From 15c9dbaee09876eb54267c5b6a83e9ff0ace2e5a Mon Sep 17 00:00:00 2001 From: Dong Chen Date: Thu, 14 Jan 2016 15:52:11 -0800 Subject: [PATCH] Support TCP_USER_TIMEOUT for Linux and its equivalent in Mac Signed-off-by: Dong Chen --- cluster/engine.go | 2 +- cluster/utils_darwin.go | 22 ++++++++++++++++++++++ cluster/utils_unix.go | 28 ++++++++++++++++++++++++++++ cluster/utils_windows.go | 16 ++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 cluster/utils_darwin.go create mode 100644 cluster/utils_unix.go create mode 100644 cluster/utils_windows.go diff --git a/cluster/engine.go b/cluster/engine.go index df307011f1..1d56b0fdb9 100644 --- a/cluster/engine.go +++ b/cluster/engine.go @@ -145,7 +145,7 @@ func (e *Engine) Connect(config *tls.Config) error { } e.IP = addr.IP.String() - c, err := dockerclient.NewDockerClientTimeout("tcp://"+e.Addr, config, time.Duration(requestTimeout), nil) + c, err := dockerclient.NewDockerClientTimeout("tcp://"+e.Addr, config, time.Duration(requestTimeout), setTCPUserTimeout) if err != nil { return err } diff --git a/cluster/utils_darwin.go b/cluster/utils_darwin.go new file mode 100644 index 0000000000..f501fe5052 --- /dev/null +++ b/cluster/utils_darwin.go @@ -0,0 +1,22 @@ +// +build darwin + +package dockerclient + +import ( + "net" + "os" + "syscall" + "time" +) + +// setTCPUserTimeout sets TCP_RXT_CONNDROPTIME on darwin +func setTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error { + f, err := conn.File() + if err != nil { + return err + } + defer f.Close() + + secs := int(uto.Nanoseconds() / 1e9) + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(f.Fd()), syscall.IPPROTO_TCP, unix.TCP_RXT_CONNDROPTIME, secs)) +} diff --git a/cluster/utils_unix.go b/cluster/utils_unix.go new file mode 100644 index 0000000000..f085d3425a --- /dev/null +++ b/cluster/utils_unix.go @@ -0,0 +1,28 @@ +// +build linux + +package cluster + +import ( + "net" + "os" + "syscall" + "time" +) + +// setTCPUserTimeout sets TCP_USER_TIMEOUT according to RFC5842 +func setTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error { + f, err := conn.File() + if err != nil { + return err + } + defer f.Close() + + msecs := int(uto.Nanoseconds() / 1e6) + // TCP_USER_TIMEOUT is a relatively new feature to detect dead peer from sender side. + // Linux supports it since kernel 2.6.37. It's among Golang experimental under + // golang.org/x/sys/unix but it doesn't support all Linux platforms yet. + // we explicitly define it here until it becomes official in golang. + // TODO: replace it with proper package when TCP_USER_TIMEOUT is supported in golang. + const tcpUserTimeout = 0x12 + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(f.Fd()), syscall.IPPROTO_TCP, tcpUserTimeout, msecs)) +} diff --git a/cluster/utils_windows.go b/cluster/utils_windows.go new file mode 100644 index 0000000000..49de656bab --- /dev/null +++ b/cluster/utils_windows.go @@ -0,0 +1,16 @@ +// +build !linux,!darwin + +package cluster + +import ( + "errors" + "net" + "time" +) + +// setTCPUserTimeout doesn't work under Windows because Go doesn't support +// the option and swarm doesn't support cgo +// This is a usability enhancement. Service shouldn't fail on this error. +func setTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error { + return errors.New("Go doesn't have native support for TCP_USER_TIMEOUT for this platform") +}