github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libcontainerd/remote/client_io_windows.go (about) 1 package remote // import "github.com/Prakhar-Agarwal-byte/moby/libcontainerd/remote" 2 3 import ( 4 "io" 5 "net" 6 "sync" 7 8 winio "github.com/Microsoft/go-winio" 9 "github.com/containerd/containerd/cio" 10 "github.com/containerd/log" 11 "github.com/pkg/errors" 12 ) 13 14 type delayedConnection struct { 15 l net.Listener 16 con net.Conn 17 wg sync.WaitGroup 18 once sync.Once 19 } 20 21 func (dc *delayedConnection) Write(p []byte) (int, error) { 22 dc.wg.Wait() 23 if dc.con != nil { 24 return dc.con.Write(p) 25 } 26 return 0, errors.New("use of closed network connection") 27 } 28 29 func (dc *delayedConnection) Read(p []byte) (int, error) { 30 dc.wg.Wait() 31 if dc.con != nil { 32 return dc.con.Read(p) 33 } 34 return 0, errors.New("use of closed network connection") 35 } 36 37 func (dc *delayedConnection) unblockConnectionWaiters() { 38 defer dc.once.Do(func() { 39 dc.wg.Done() 40 }) 41 } 42 43 func (dc *delayedConnection) Close() error { 44 dc.l.Close() 45 if dc.con != nil { 46 return dc.con.Close() 47 } 48 dc.unblockConnectionWaiters() 49 return nil 50 } 51 52 type stdioPipes struct { 53 stdin io.WriteCloser 54 stdout io.ReadCloser 55 stderr io.ReadCloser 56 } 57 58 // newStdioPipes creates actual fifos for stdio. 59 func (c *client) newStdioPipes(fifos *cio.FIFOSet) (_ *stdioPipes, err error) { 60 p := &stdioPipes{} 61 if fifos.Stdin != "" { 62 c.logger.WithField("stdin", fifos.Stdin).Debug("listen") 63 l, err := winio.ListenPipe(fifos.Stdin, nil) 64 if err != nil { 65 return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdin) 66 } 67 dc := &delayedConnection{ 68 l: l, 69 } 70 dc.wg.Add(1) 71 defer func() { 72 if err != nil { 73 dc.Close() 74 } 75 }() 76 p.stdin = dc 77 78 go func() { 79 c.logger.WithField("stdin", fifos.Stdin).Debug("accept") 80 conn, err := l.Accept() 81 if err != nil { 82 dc.Close() 83 if err != winio.ErrPipeListenerClosed { 84 c.logger.WithError(err).Errorf("failed to accept stdin connection on %s", fifos.Stdin) 85 } 86 return 87 } 88 c.logger.WithField("stdin", fifos.Stdin).Debug("connected") 89 dc.con = conn 90 dc.unblockConnectionWaiters() 91 }() 92 } 93 94 if fifos.Stdout != "" { 95 c.logger.WithField("stdout", fifos.Stdout).Debug("listen") 96 l, err := winio.ListenPipe(fifos.Stdout, nil) 97 if err != nil { 98 return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout) 99 } 100 dc := &delayedConnection{ 101 l: l, 102 } 103 dc.wg.Add(1) 104 defer func() { 105 if err != nil { 106 dc.Close() 107 } 108 }() 109 p.stdout = dc 110 111 go func() { 112 c.logger.WithField("stdout", fifos.Stdout).Debug("accept") 113 conn, err := l.Accept() 114 if err != nil { 115 dc.Close() 116 if err != winio.ErrPipeListenerClosed { 117 c.logger.WithFields(log.Fields{"error": err, "stdout": fifos.Stdout}).Error("failed to accept stdout connection") 118 } 119 return 120 } 121 c.logger.WithField("stdout", fifos.Stdout).Debug("connected") 122 dc.con = conn 123 dc.unblockConnectionWaiters() 124 }() 125 } 126 127 if fifos.Stderr != "" { 128 c.logger.WithField("stderr", fifos.Stderr).Debug("listen") 129 l, err := winio.ListenPipe(fifos.Stderr, nil) 130 if err != nil { 131 return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr) 132 } 133 dc := &delayedConnection{ 134 l: l, 135 } 136 dc.wg.Add(1) 137 defer func() { 138 if err != nil { 139 dc.Close() 140 } 141 }() 142 p.stderr = dc 143 144 go func() { 145 c.logger.WithField("stderr", fifos.Stderr).Debug("accept") 146 conn, err := l.Accept() 147 if err != nil { 148 dc.Close() 149 if err != winio.ErrPipeListenerClosed { 150 c.logger.WithError(err).Errorf("failed to accept stderr connection on %s", fifos.Stderr) 151 } 152 return 153 } 154 c.logger.WithField("stderr", fifos.Stderr).Debug("connected") 155 dc.con = conn 156 dc.unblockConnectionWaiters() 157 }() 158 } 159 return p, nil 160 }