github.com/rootless-containers/rootlesskit/v2@v2.3.4/pkg/port/builtin/parent/tcp/tcp.go (about) 1 package tcp 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "os" 8 "strconv" 9 "sync" 10 11 "github.com/rootless-containers/rootlesskit/v2/pkg/port" 12 "github.com/rootless-containers/rootlesskit/v2/pkg/port/builtin/msg" 13 ) 14 15 func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, stoppedCh chan error, logWriter io.Writer) error { 16 ln, err := net.Listen(spec.Proto, net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort))) 17 if err != nil { 18 fmt.Fprintf(logWriter, "listen: %v\n", err) 19 return err 20 } 21 newConns := make(chan net.Conn) 22 go func() { 23 for { 24 c, err := ln.Accept() 25 if err != nil { 26 fmt.Fprintf(logWriter, "accept: %v\n", err) 27 close(newConns) 28 return 29 } 30 newConns <- c 31 } 32 }() 33 go func() { 34 defer func() { 35 stoppedCh <- ln.Close() 36 close(stoppedCh) 37 }() 38 for { 39 select { 40 case c, ok := <-newConns: 41 if !ok { 42 return 43 } 44 go func() { 45 if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil { 46 fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err) 47 return 48 } 49 }() 50 case <-stopCh: 51 return 52 } 53 } 54 }() 55 // no wait 56 return nil 57 } 58 59 func copyConnToChild(c net.Conn, socketPath string, spec port.Spec, stopCh <-chan struct{}) error { 60 defer c.Close() 61 // get fd from the child as an SCM_RIGHTS cmsg 62 fd, err := msg.ConnectToChildWithRetry(socketPath, spec, 10) 63 if err != nil { 64 return err 65 } 66 f := os.NewFile(uintptr(fd), "") 67 defer f.Close() 68 fc, err := net.FileConn(f) 69 if err != nil { 70 return err 71 } 72 defer fc.Close() 73 bicopy(c, fc, stopCh) 74 return nil 75 } 76 77 // bicopy is based on libnetwork/cmd/proxy/tcp_proxy.go . 78 // NOTE: sendfile(2) cannot be used for sockets 79 func bicopy(x, y net.Conn, quit <-chan struct{}) { 80 var wg sync.WaitGroup 81 var broker = func(to, from net.Conn) { 82 io.Copy(to, from) 83 if fromTCP, ok := from.(*net.TCPConn); ok { 84 fromTCP.CloseRead() 85 } 86 if toTCP, ok := to.(*net.TCPConn); ok { 87 toTCP.CloseWrite() 88 } 89 wg.Done() 90 } 91 92 wg.Add(2) 93 go broker(x, y) 94 go broker(y, x) 95 finish := make(chan struct{}) 96 go func() { 97 wg.Wait() 98 close(finish) 99 }() 100 101 select { 102 case <-quit: 103 case <-finish: 104 } 105 x.Close() 106 y.Close() 107 <-finish 108 }