From f73a6b3845a498107cfb22e4d962f0a30870e7c6 Mon Sep 17 00:00:00 2001 From: Phil Estes Date: Fri, 30 Jan 2015 10:50:27 -0500 Subject: [PATCH] Setup TCP keep-alive on hijacked HTTP(S) client <--> daemon sessions Fixes #10387 Without TCP keep-alive set on socket connections to the daemon, any long-running container with std{out,err,in} attached that doesn't read/write for a minute or longer will end in ECONNTIMEDOUT (depending on network settings/OS defaults, etc.), leaving the docker client side believing it is still waiting on data with no actual underlying socket connection. This patch turns on TCP keep-alive for the underlying TCP connection for both TLS and standard HTTP hijacked daemon connections from the docker client, with a keep-alive timeout of 30 seconds. Docker-DCO-1.1-Signed-off-by: Phil Estes --- api/client/hijack.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/api/client/hijack.go b/api/client/hijack.go index 987f2d23fa..bb902405c0 100644 --- a/api/client/hijack.go +++ b/api/client/hijack.go @@ -72,6 +72,15 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con if err != nil { return nil, err } + // When we set up a TCP connection for hijack, there could be long periods + // of inactivity (a long running command with no output) that in certain + // network setups may cause ECONNTIMEOUT, leaving the client in an unknown + // state. Setting TCP KeepAlive on the socket connection will prohibit + // ECONNTIMEOUT unless the socket connection truly is broken + if tcpConn, ok := rawConn.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(30 * time.Second) + } colonPos := strings.LastIndex(addr, ":") if colonPos == -1 { @@ -140,6 +149,15 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea req.Host = cli.addr dial, err := cli.dial() + // When we set up a TCP connection for hijack, there could be long periods + // of inactivity (a long running command with no output) that in certain + // network setups may cause ECONNTIMEOUT, leaving the client in an unknown + // state. Setting TCP KeepAlive on the socket connection will prohibit + // ECONNTIMEOUT unless the socket connection truly is broken + if tcpConn, ok := dial.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(30 * time.Second) + } if err != nil { if strings.Contains(err.Error(), "connection refused") { return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")