package gost import ( "io" "net" "sync" "time" "github.com/go-log/log" ) // Server is a proxy server. type Server struct { Listener Listener } // Addr returns the address of the server func (s *Server) Addr() net.Addr { return s.Listener.Addr() } // Close closes the server func (s *Server) Close() error { return s.Listener.Close() } // Serve serves as a proxy server. func (s *Server) Serve(h Handler) error { if s.Listener == nil { ln, err := TCPListener("") if err != nil { return err } s.Listener = ln } if h == nil { h = HTTPHandler() } l := s.Listener var tempDelay time.Duration for { conn, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } log.Logf("server: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 go h.Handle(conn) } } // Listener is a proxy server listener, just like a net.Listener. type Listener interface { net.Listener } type tcpListener struct { net.Listener } // TCPListener creates a Listener for TCP proxy server. func TCPListener(addr string) (Listener, error) { laddr, err := net.ResolveTCPAddr("tcp", addr) if err != nil { return nil, err } ln, err := net.ListenTCP("tcp", laddr) if err != nil { return nil, err } return &tcpListener{Listener: tcpKeepAliveListener{ln}}, nil } type tcpKeepAliveListener struct { *net.TCPListener } func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { tc, err := ln.AcceptTCP() if err != nil { return } tc.SetKeepAlive(true) tc.SetKeepAlivePeriod(KeepAliveTime) return tc, nil } func transport(rw1, rw2 io.ReadWriter) error { var err1 error var err2 error wg := sync.WaitGroup{} wg.Add(2) go func() { _, err1 = io.Copy(rw1, rw2) wg.Done() }() go func() { _, err2 = io.Copy(rw2, rw1) wg.Done() }() // wait for both direction complete wg.Wait() if err1 != nil { return err1 } return err2 }