2017-09-22 13:52:41 +00:00
|
|
|
package libcontainerd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
winio "github.com/Microsoft/go-winio"
|
2017-11-30 00:15:20 +00:00
|
|
|
"github.com/containerd/containerd/cio"
|
2017-09-22 13:52:41 +00:00
|
|
|
"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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-30 00:15:20 +00:00
|
|
|
func newIOPipe(fifos *cio.FIFOSet) (*IOPipe, error) {
|
2017-09-22 13:52:41 +00:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
ctx, cancel = context.WithCancel(context.Background())
|
|
|
|
p io.ReadWriteCloser
|
|
|
|
iop = &IOPipe{
|
|
|
|
Terminal: fifos.Terminal,
|
|
|
|
cancel: cancel,
|
2017-11-30 00:15:20 +00:00
|
|
|
config: cio.Config{
|
2017-09-22 13:52:41 +00:00
|
|
|
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
|
|
|
|
}
|