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:
e9e035d53ee8aa3d899d12db08b293f599daecb6
GitHub-Pull-Request: golang/go#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>
// 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.
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) {
}
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
}
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
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
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 {
// use variables of type Listener instead of assuming TCP.
type TCPListener struct {
fd *netFD
+ lc ListenConfig
}
// SyscallConn returns a raw network connection.
"context"
"io"
"os"
+ "time"
)
func (c *TCPConn) readFrom(r io.Reader) (int64, 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 {
if err != nil {
return nil, err
}
- return &TCPListener{fd}, nil
+ return &TCPListener{fd: fd, lc: sl.ListenConfig}, nil
}
"io"
"os"
"syscall"
+ "time"
)
func sockaddrToTCP(sa syscall.Sockaddr) Addr {
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 {
if err != nil {
return nil, err
}
- return &TCPListener{fd}, nil
+ return &TCPListener{fd: fd, lc: sl.ListenConfig}, nil
}