1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- package client
- import (
- "io"
- "sync"
- "golang.org/x/net/context"
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/pkg/stdcopy"
- "github.com/docker/engine-api/types"
- )
- // HoldHijackedConnection handles copying input to and output from streams to the
- // connection
- func (cli *DockerCli) HoldHijackedConnection(ctx context.Context, tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
- var (
- err error
- restoreOnce sync.Once
- )
- if inputStream != nil && tty {
- if err := cli.setRawTerminal(); err != nil {
- return err
- }
- defer func() {
- restoreOnce.Do(func() {
- cli.restoreTerminal(inputStream)
- })
- }()
- }
- receiveStdout := make(chan error, 1)
- if outputStream != nil || errorStream != nil {
- go func() {
- // When TTY is ON, use regular copy
- if tty && outputStream != nil {
- _, err = io.Copy(outputStream, resp.Reader)
- // we should restore the terminal as soon as possible once connection end
- // so any following print messages will be in normal type.
- if inputStream != nil {
- restoreOnce.Do(func() {
- cli.restoreTerminal(inputStream)
- })
- }
- } else {
- _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
- }
- logrus.Debug("[hijack] End of stdout")
- receiveStdout <- err
- }()
- }
- stdinDone := make(chan struct{})
- go func() {
- if inputStream != nil {
- io.Copy(resp.Conn, inputStream)
- // we should restore the terminal as soon as possible once connection end
- // so any following print messages will be in normal type.
- if tty {
- restoreOnce.Do(func() {
- cli.restoreTerminal(inputStream)
- })
- }
- logrus.Debug("[hijack] End of stdin")
- }
- if err := resp.CloseWrite(); err != nil {
- logrus.Debugf("Couldn't send EOF: %s", err)
- }
- close(stdinDone)
- }()
- select {
- case err := <-receiveStdout:
- if err != nil {
- logrus.Debugf("Error receiveStdout: %s", err)
- return err
- }
- case <-stdinDone:
- if outputStream != nil || errorStream != nil {
- select {
- case err := <-receiveStdout:
- if err != nil {
- logrus.Debugf("Error receiveStdout: %s", err)
- return err
- }
- case <-ctx.Done():
- }
- }
- case <-ctx.Done():
- }
- return nil
- }
|