package main import ( "io" "io/ioutil" "log" "net" "os" "sync" "time" "github.com/Microsoft/go-winio" clog "github.com/containerd/containerd/log" "github.com/pkg/errors" "github.com/urfave/cli" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) func getGRPCConnection(context *cli.Context) (*grpc.ClientConn, error) { if grpcConn != nil { return grpcConn, nil } bindAddress := context.GlobalString("address") // reset the logger for grpc to log to dev/null so that it does not mess with our stdio grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags)) dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithTimeout(100 * time.Second)} dialOpts = append(dialOpts, grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { return winio.DialPipe(bindAddress, &timeout) }, )) conn, err := grpc.Dial(bindAddress, dialOpts...) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", bindAddress) } grpcConn = conn return grpcConn, nil } func prepareStdio(stdin, stdout, stderr string, console bool) (*sync.WaitGroup, error) { var wg sync.WaitGroup if stdin != "" { l, err := winio.ListenPipe(stdin, nil) if err != nil { return nil, errors.Wrapf(err, "failed to create stdin pipe %s", stdin) } defer func(l net.Listener) { if err != nil { l.Close() } }(l) go func() { c, err := l.Accept() if err != nil { clog.L.WithError(err).Errorf("failed to accept stdin connection on %s", stdin) return } io.Copy(c, os.Stdin) c.Close() l.Close() }() } if stdout != "" { l, err := winio.ListenPipe(stdout, nil) if err != nil { return nil, errors.Wrapf(err, "failed to create stdin pipe %s", stdout) } defer func(l net.Listener) { if err != nil { l.Close() } }(l) wg.Add(1) go func() { defer wg.Done() c, err := l.Accept() if err != nil { clog.L.WithError(err).Errorf("failed to accept stdout connection on %s", stdout) return } io.Copy(os.Stdout, c) c.Close() l.Close() }() } if !console && stderr != "" { l, err := winio.ListenPipe(stderr, nil) if err != nil { return nil, errors.Wrapf(err, "failed to create stderr pipe %s", stderr) } defer func(l net.Listener) { if err != nil { l.Close() } }(l) wg.Add(1) go func() { defer wg.Done() c, err := l.Accept() if err != nil { clog.L.WithError(err).Errorf("failed to accept stderr connection on %s", stderr) return } io.Copy(os.Stderr, c) c.Close() l.Close() }() } return &wg, nil }