Skip to content

Commit

Permalink
net: add KeepAlive field to ListenConfig
Browse files Browse the repository at this point in the history
This commit adds a KeepAlive field to ListenConfig and uses it
analogously to Dialer.KeepAlive to set TCP KeepAlives per default on
Accept()

Fixes #23378

Change-Id: I57eaf9508c979e7f0e2b8c5dd8e8901f6eb27fd6
GitHub-Last-Rev: e9e035d
GitHub-Pull-Request: #31242
Reviewed-on: https://go-review.googlesource.com/c/go/+/170678
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information
costela authored and bradfitz committed Apr 4, 2019
1 parent 964fe4b commit 1abf3aa
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 26 deletions.
8 changes: 8 additions & 0 deletions src/net/dial.go
Expand Up @@ -596,6 +596,14 @@ type ListenConfig struct {
// necessarily the ones passed to Listen. For example, passing "tcp" to
// Listen will cause the Control function to be called with "tcp4" or "tcp6".
Control func(network, address string, c syscall.RawConn) error

// KeepAlive specifies the keep-alive period for network
// connections accepted by this listener.
// If zero, keep-alives are enabled if supported by the protocol
// and operating system. Network protocols or operating systems
// that do not support keep-alives ignore this field.
// If negative, keep-alives are disabled.
KeepAlive time.Duration
}

// Listen announces on the local network address.
Expand Down
2 changes: 1 addition & 1 deletion src/net/file_plan9.go
Expand Up @@ -127,7 +127,7 @@ func fileListener(f *os.File) (Listener, error) {
return nil, errors.New("file does not represent a listener")
}

return &TCPListener{fd}, nil
return &TCPListener{fd: fd}, nil
}

func filePacketConn(f *os.File) (PacketConn, error) {
Expand Down
2 changes: 1 addition & 1 deletion src/net/file_unix.go
Expand Up @@ -93,7 +93,7 @@ func fileListener(f *os.File) (Listener, error) {
}
switch laddr := fd.laddr.(type) {
case *TCPAddr:
return &TCPListener{fd}, nil
return &TCPListener{fd: fd}, nil
case *UnixAddr:
return &UnixListener{fd: fd, path: laddr.Name, unlink: false}, nil
}
Expand Down
22 changes: 2 additions & 20 deletions src/net/http/server.go
Expand Up @@ -2792,7 +2792,7 @@ func (srv *Server) ListenAndServe() error {
if err != nil {
return err
}
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
return srv.Serve(ln)
}

var testHookServerServe func(*Server, net.Listener) // used if non-nil
Expand Down Expand Up @@ -3076,7 +3076,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {

defer ln.Close()

return srv.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, certFile, keyFile)
return srv.ServeTLS(ln, certFile, keyFile)
}

// setupHTTP2_ServeTLS conditionally configures HTTP/2 on
Expand Down Expand Up @@ -3269,24 +3269,6 @@ func (tw *timeoutWriter) writeHeader(code int) {
tw.code = code
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
tc, err := ln.AcceptTCP()
if err != nil {
return nil, err
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}

// onceCloseListener wraps a net.Listener, protecting it from
// multiple Close calls.
type onceCloseListener struct {
Expand Down
1 change: 1 addition & 0 deletions src/net/tcpsock.go
Expand Up @@ -224,6 +224,7 @@ func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
// use variables of type Listener instead of assuming TCP.
type TCPListener struct {
fd *netFD
lc ListenConfig
}

// SyscallConn returns a raw network connection.
Expand Down
14 changes: 12 additions & 2 deletions src/net/tcpsock_plan9.go
Expand Up @@ -8,6 +8,7 @@ import (
"context"
"io"
"os"
"time"
)

func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
Expand Down Expand Up @@ -44,7 +45,16 @@ func (ln *TCPListener) accept() (*TCPConn, error) {
if err != nil {
return nil, err
}
return newTCPConn(fd), nil
tc := newTCPConn(fd)
if ln.lc.KeepAlive >= 0 {
setKeepAlive(fd, true)
ka := ln.lc.KeepAlive
if ln.lc.KeepAlive == 0 {
ka = 3 * time.Minute
}
setKeepAlivePeriod(fd, ka)
}
return tc, nil
}

func (ln *TCPListener) close() error {
Expand Down Expand Up @@ -74,5 +84,5 @@ func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListe
if err != nil {
return nil, err
}
return &TCPListener{fd}, nil
return &TCPListener{fd: fd, lc: sl.ListenConfig}, nil
}
14 changes: 12 additions & 2 deletions src/net/tcpsock_posix.go
Expand Up @@ -11,6 +11,7 @@ import (
"io"
"os"
"syscall"
"time"
)

func sockaddrToTCP(sa syscall.Sockaddr) Addr {
Expand Down Expand Up @@ -140,7 +141,16 @@ func (ln *TCPListener) accept() (*TCPConn, error) {
if err != nil {
return nil, err
}
return newTCPConn(fd), nil
tc := newTCPConn(fd)
if ln.lc.KeepAlive >= 0 {
setKeepAlive(fd, true)
ka := ln.lc.KeepAlive
if ln.lc.KeepAlive == 0 {
ka = 3 * time.Minute
}
setKeepAlivePeriod(fd, ka)
}
return tc, nil
}

func (ln *TCPListener) close() error {
Expand All @@ -160,5 +170,5 @@ func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListe
if err != nil {
return nil, err
}
return &TCPListener{fd}, nil
return &TCPListener{fd: fd, lc: sl.ListenConfig}, nil
}

0 comments on commit 1abf3aa

Please sign in to comment.