github.com/rentongzhang/docker@v1.8.2-rc1/daemon/execdriver/windows/namedpipes.go (about)

     1  // +build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"io"
     7  
     8  	"github.com/Sirupsen/logrus"
     9  	"github.com/natefinch/npipe"
    10  )
    11  
    12  // stdinAccept runs as a go function. It waits for the container system
    13  // to accept our offer of a named pipe for stdin. Once accepted, if we are
    14  // running "attached" to the container (eg docker run -i), then we spin up
    15  // a further thread to copy anything from the client into the container.
    16  //
    17  // Important design note. This function is run as a go function for a very
    18  // good reason. The named pipe Accept call is blocking until one of two things
    19  // happen. Either someone connects to it, or it is forcibly closed. Let's
    20  // assume that no-one connects to it, the only way otherwise the Run()
    21  // method would continue is by closing it. However, as that would be the same
    22  // thread, it can't close it. Hence we run as another thread allowing Run()
    23  // to close the named pipe.
    24  func stdinAccept(inListen *npipe.PipeListener, pipeName string, copyfrom io.ReadCloser) {
    25  
    26  	// Wait for the pipe to be connected to by the shim
    27  	logrus.Debugln("stdinAccept: Waiting on ", pipeName)
    28  	stdinConn, err := inListen.Accept()
    29  	if err != nil {
    30  		logrus.Errorf("Failed to accept on pipe %s %s", pipeName, err)
    31  		return
    32  	}
    33  	logrus.Debugln("Connected to ", stdinConn.RemoteAddr())
    34  
    35  	// Anything that comes from the client stdin should be copied
    36  	// across to the stdin named pipe of the container.
    37  	if copyfrom != nil {
    38  		go func() {
    39  			defer stdinConn.Close()
    40  			logrus.Debugln("Calling io.Copy on stdin")
    41  			bytes, err := io.Copy(stdinConn, copyfrom)
    42  			logrus.Debugf("Finished io.Copy on stdin bytes=%d err=%s pipe=%s", bytes, err, stdinConn.RemoteAddr())
    43  		}()
    44  	} else {
    45  		defer stdinConn.Close()
    46  	}
    47  }
    48  
    49  // stdouterrAccept runs as a go function. It waits for the container system to
    50  // accept our offer of a named pipe - in fact two of them - one for stdout
    51  // and one for stderr (we are called twice). Once the named pipe is accepted,
    52  // if we are running "attached" to the container (eg docker run -i), then we
    53  // spin up a further thread to copy anything from the containers output channels
    54  // to the client.
    55  func stdouterrAccept(outerrListen *npipe.PipeListener, pipeName string, copyto io.Writer) {
    56  
    57  	// Wait for the pipe to be connected to by the shim
    58  	logrus.Debugln("out/err: Waiting on ", pipeName)
    59  	outerrConn, err := outerrListen.Accept()
    60  	if err != nil {
    61  		logrus.Errorf("Failed to accept on pipe %s %s", pipeName, err)
    62  		return
    63  	}
    64  	logrus.Debugln("Connected to ", outerrConn.RemoteAddr())
    65  
    66  	// Anything that comes from the container named pipe stdout/err should be copied
    67  	// across to the stdout/err of the client
    68  	if copyto != nil {
    69  		go func() {
    70  			defer outerrConn.Close()
    71  			logrus.Debugln("Calling io.Copy on ", pipeName)
    72  			bytes, err := io.Copy(copyto, outerrConn)
    73  			logrus.Debugf("Copied %d bytes from pipe=%s", bytes, outerrConn.RemoteAddr())
    74  			if err != nil {
    75  				// Not fatal, just debug log it
    76  				logrus.Debugf("Error hit during copy %s", err)
    77  			}
    78  		}()
    79  	} else {
    80  		defer outerrConn.Close()
    81  	}
    82  }