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  }