github.com/kobeld/docker@v1.12.0-rc1/api/client/hijack.go (about) 1 package client 2 3 import ( 4 "io" 5 "sync" 6 7 "golang.org/x/net/context" 8 9 "github.com/Sirupsen/logrus" 10 "github.com/docker/docker/pkg/stdcopy" 11 "github.com/docker/engine-api/types" 12 ) 13 14 // HoldHijackedConnection handles copying input to and output from streams to the 15 // connection 16 func (cli *DockerCli) HoldHijackedConnection(ctx context.Context, tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error { 17 var ( 18 err error 19 restoreOnce sync.Once 20 ) 21 if inputStream != nil && tty { 22 if err := cli.setRawTerminal(); err != nil { 23 return err 24 } 25 defer func() { 26 restoreOnce.Do(func() { 27 cli.restoreTerminal(inputStream) 28 }) 29 }() 30 } 31 32 receiveStdout := make(chan error, 1) 33 if outputStream != nil || errorStream != nil { 34 go func() { 35 // When TTY is ON, use regular copy 36 if tty && outputStream != nil { 37 _, err = io.Copy(outputStream, resp.Reader) 38 // we should restore the terminal as soon as possible once connection end 39 // so any following print messages will be in normal type. 40 if inputStream != nil { 41 restoreOnce.Do(func() { 42 cli.restoreTerminal(inputStream) 43 }) 44 } 45 } else { 46 _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader) 47 } 48 49 logrus.Debug("[hijack] End of stdout") 50 receiveStdout <- err 51 }() 52 } 53 54 stdinDone := make(chan struct{}) 55 go func() { 56 if inputStream != nil { 57 io.Copy(resp.Conn, inputStream) 58 // we should restore the terminal as soon as possible once connection end 59 // so any following print messages will be in normal type. 60 if tty { 61 restoreOnce.Do(func() { 62 cli.restoreTerminal(inputStream) 63 }) 64 } 65 logrus.Debug("[hijack] End of stdin") 66 } 67 68 if err := resp.CloseWrite(); err != nil { 69 logrus.Debugf("Couldn't send EOF: %s", err) 70 } 71 close(stdinDone) 72 }() 73 74 select { 75 case err := <-receiveStdout: 76 if err != nil { 77 logrus.Debugf("Error receiveStdout: %s", err) 78 return err 79 } 80 case <-stdinDone: 81 if outputStream != nil || errorStream != nil { 82 select { 83 case err := <-receiveStdout: 84 if err != nil { 85 logrus.Debugf("Error receiveStdout: %s", err) 86 return err 87 } 88 case <-ctx.Done(): 89 } 90 } 91 case <-ctx.Done(): 92 } 93 94 return nil 95 }