github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/cmd/proxy/tcp_proxy.go (about) 1 package main 2 3 import ( 4 "io" 5 "log" 6 "net" 7 "sync" 8 "syscall" 9 ) 10 11 // TCPProxy is a proxy for TCP connections. It implements the Proxy interface to 12 // handle TCP traffic forwarding between the frontend and backend addresses. 13 type TCPProxy struct { 14 listener *net.TCPListener 15 frontendAddr *net.TCPAddr 16 backendAddr *net.TCPAddr 17 } 18 19 // NewTCPProxy creates a new TCPProxy. 20 func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) { 21 listener, err := net.ListenTCP("tcp", frontendAddr) 22 if err != nil { 23 return nil, err 24 } 25 // If the port in frontendAddr was 0 then ListenTCP will have a picked 26 // a port to listen on, hence the call to Addr to get that actual port: 27 return &TCPProxy{ 28 listener: listener, 29 frontendAddr: listener.Addr().(*net.TCPAddr), 30 backendAddr: backendAddr, 31 }, nil 32 } 33 34 func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { 35 backend, err := net.DialTCP("tcp", nil, proxy.backendAddr) 36 if err != nil { 37 log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) 38 client.Close() 39 return 40 } 41 42 var wg sync.WaitGroup 43 var broker = func(to, from *net.TCPConn) { 44 if _, err := io.Copy(to, from); err != nil { 45 // If the socket we are writing to is shutdown with 46 // SHUT_WR, forward it to the other end of the pipe: 47 if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE { 48 from.CloseWrite() 49 } 50 } 51 to.CloseRead() 52 wg.Done() 53 } 54 55 wg.Add(2) 56 go broker(client, backend) 57 go broker(backend, client) 58 59 finish := make(chan struct{}) 60 go func() { 61 wg.Wait() 62 close(finish) 63 }() 64 65 select { 66 case <-quit: 67 case <-finish: 68 } 69 client.Close() 70 backend.Close() 71 <-finish 72 } 73 74 // Run starts forwarding the traffic using TCP. 75 func (proxy *TCPProxy) Run() { 76 quit := make(chan bool) 77 defer close(quit) 78 for { 79 client, err := proxy.listener.Accept() 80 if err != nil { 81 log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) 82 return 83 } 84 go proxy.clientLoop(client.(*net.TCPConn), quit) 85 } 86 } 87 88 // Close stops forwarding the traffic. 89 func (proxy *TCPProxy) Close() { proxy.listener.Close() } 90 91 // FrontendAddr returns the TCP address on which the proxy is listening. 92 func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr } 93 94 // BackendAddr returns the TCP proxied address. 95 func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }