github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/libcontainerd/remote/client_io_windows.go (about)

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