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 }