package libcontainerd import ( "context" "io" "net" "sync" winio "github.com/Microsoft/go-winio" "github.com/containerd/containerd/cio" "github.com/pkg/errors" ) type winpipe struct { sync.Mutex ctx context.Context listener net.Listener readyCh chan struct{} readyErr error client net.Conn } func newWinpipe(ctx context.Context, pipe string) (*winpipe, error) { l, err := winio.ListenPipe(pipe, nil) if err != nil { return nil, errors.Wrapf(err, "%q pipe creation failed", pipe) } wp := &winpipe{ ctx: ctx, listener: l, readyCh: make(chan struct{}), } go func() { go func() { defer close(wp.readyCh) defer wp.listener.Close() c, err := wp.listener.Accept() if err != nil { wp.Lock() if wp.readyErr == nil { wp.readyErr = err } wp.Unlock() return } wp.client = c }() select { case <-wp.readyCh: case <-ctx.Done(): wp.Lock() if wp.readyErr == nil { wp.listener.Close() wp.readyErr = ctx.Err() } wp.Unlock() } }() return wp, nil } func (wp *winpipe) Read(b []byte) (int, error) { select { case <-wp.ctx.Done(): return 0, wp.ctx.Err() case <-wp.readyCh: return wp.client.Read(b) } } func (wp *winpipe) Write(b []byte) (int, error) { select { case <-wp.ctx.Done(): return 0, wp.ctx.Err() case <-wp.readyCh: return wp.client.Write(b) } } func (wp *winpipe) Close() error { select { case <-wp.readyCh: return wp.client.Close() default: return nil } } func newIOPipe(fifos *cio.FIFOSet) (*IOPipe, error) { var ( err error ctx, cancel = context.WithCancel(context.Background()) p io.ReadWriteCloser iop = &IOPipe{ Terminal: fifos.Terminal, cancel: cancel, config: cio.Config{ Terminal: fifos.Terminal, Stdin: fifos.In, Stdout: fifos.Out, Stderr: fifos.Err, }, } ) defer func() { if err != nil { cancel() iop.Close() } }() if fifos.In != "" { if p, err = newWinpipe(ctx, fifos.In); err != nil { return nil, err } iop.Stdin = p } if fifos.Out != "" { if p, err = newWinpipe(ctx, fifos.Out); err != nil { return nil, err } iop.Stdout = p } if fifos.Err != "" { if p, err = newWinpipe(ctx, fifos.Err); err != nil { return nil, err } iop.Stderr = p } return iop, nil }