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  }