From bd1b98fa441e30685538ea79fbf75a0479418f6c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 3 Apr 2019 19:29:38 -0700 Subject: [PATCH] set linger to 0 for both inbound and outbound connections This causes us to send RST packets instead of FIN packets when closing connections and means connections immediately enter the "reset" state instead of entering the TIME-WAIT state. Importantly, this means we can immediately reuse the 5-tuple and reconnect. --- tcp.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tcp.go b/tcp.go index 18e119e..5f7fec8 100644 --- a/tcp.go +++ b/tcp.go @@ -2,6 +2,7 @@ package tcp import ( "context" + "net" "time" logging "github.com/ipfs/go-log" @@ -20,6 +21,29 @@ var DefaultConnectTimeout = 5 * time.Second var log = logging.Logger("tcp-tpt") +// try to set linger on the connection, if possible. +func tryLinger(conn net.Conn, sec int) { + if lingerConn, ok := conn.(interface { + SetLinger(int) error + }); ok { + _ = lingerConn.SetLinger(sec) + } +} + +type lingerListener struct { + manet.Listener + sec int +} + +func (ll *lingerListener) Accept() (manet.Conn, error) { + c, err := ll.Listener.Accept() + if err != nil { + return nil, err + } + tryLinger(c, ll.sec) + return c, nil +} + // TcpTransport is the TCP transport. type TcpTransport struct { // Connection upgrader for upgrading insecure stream connections to @@ -73,6 +97,10 @@ func (t *TcpTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) if err != nil { return nil, err } + // Set linger to 0 so we never get stuck in the TIME-WAIT state. When + // linger is 0, connections are _reset_ instead of closed with a FIN. + // This means we can immediately reuse the 5-tuple and reconnect. + tryLinger(conn, 0) return t.Upgrader.UpgradeOutbound(ctx, t, conn, p) } @@ -94,6 +122,7 @@ func (t *TcpTransport) Listen(laddr ma.Multiaddr) (tpt.Listener, error) { if err != nil { return nil, err } + list = &lingerListener{list, 0} return t.Upgrader.UpgradeListener(t, list), nil }