github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/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 func (cli *DockerCli) holdHijackedConnection(ctx context.Context, tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error { 15 var ( 16 err error 17 restoreOnce sync.Once 18 ) 19 if inputStream != nil && tty { 20 if err := cli.setRawTerminal(); err != nil { 21 return err 22 } 23 defer func() { 24 restoreOnce.Do(func() { 25 cli.restoreTerminal(inputStream) 26 }) 27 }() 28 } 29 30 receiveStdout := make(chan error, 1) 31 if outputStream != nil || errorStream != nil { 32 go func() { 33 // When TTY is ON, use regular copy 34 if tty && outputStream != nil { 35 _, err = io.Copy(outputStream, resp.Reader) 36 // we should restore the terminal as soon as possible once connection end 37 // so any following print messages will be in normal type. 38 if inputStream != nil { 39 restoreOnce.Do(func() { 40 cli.restoreTerminal(inputStream) 41 }) 42 } 43 } else { 44 _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader) 45 } 46 47 logrus.Debugf("[hijack] End of stdout") 48 receiveStdout <- err 49 }() 50 } 51 52 stdinDone := make(chan struct{}) 53 go func() { 54 if inputStream != nil { 55 io.Copy(resp.Conn, inputStream) 56 // we should restore the terminal as soon as possible once connection end 57 // so any following print messages will be in normal type. 58 if tty { 59 restoreOnce.Do(func() { 60 cli.restoreTerminal(inputStream) 61 }) 62 } 63 logrus.Debugf("[hijack] End of stdin") 64 } 65 66 if err := resp.CloseWrite(); err != nil { 67 logrus.Debugf("Couldn't send EOF: %s", err) 68 } 69 close(stdinDone) 70 }() 71 72 select { 73 case err := <-receiveStdout: 74 if err != nil { 75 logrus.Debugf("Error receiveStdout: %s", err) 76 return err 77 } 78 case <-stdinDone: 79 if outputStream != nil || errorStream != nil { 80 select { 81 case err := <-receiveStdout: 82 if err != nil { 83 logrus.Debugf("Error receiveStdout: %s", err) 84 return err 85 } 86 case <-ctx.Done(): 87 } 88 } 89 case <-ctx.Done(): 90 } 91 92 return nil 93 }