mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
139 lines
2.3 KiB
Go
139 lines
2.3 KiB
Go
|
package libcontainerd
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"io"
|
||
|
"net"
|
||
|
"sync"
|
||
|
|
||
|
winio "github.com/Microsoft/go-winio"
|
||
|
"github.com/containerd/containerd"
|
||
|
"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 *containerd.FIFOSet) (*IOPipe, error) {
|
||
|
var (
|
||
|
err error
|
||
|
ctx, cancel = context.WithCancel(context.Background())
|
||
|
p io.ReadWriteCloser
|
||
|
iop = &IOPipe{
|
||
|
Terminal: fifos.Terminal,
|
||
|
cancel: cancel,
|
||
|
config: containerd.IOConfig{
|
||
|
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
|
||
|
}
|