client_test.go | 2 +- fs/go.mod | 2 +- fs/go.sum | 2 ++ socket.go | 76 +++++++++++++++++++++++++++++++++-------------------- diff --git a/client_test.go b/client_test.go index 22281efd6cde9bf0eaa6a0b03d7f48150ee5a500..d2a88e9e7a769abcd1871092c006e37b33573a51 100644 --- a/client_test.go +++ b/client_test.go @@ -897,7 +897,7 @@ } // https://github.com/anacrolix/torrent/issues/837 func TestClientConfigSetHandlerNotIgnored(t *testing.T) { - cfg := NewDefaultClientConfig() + cfg := TestingConfig(t) cfg.Logger.SetHandlers(log.DiscardHandler) c := qt.New(t) cl, err := NewClient(cfg) diff --git a/fs/go.mod b/fs/go.mod index 67c01ef0816e5696836f70acd3e0d8c2b2b28e1f..004cee727d24a2c813c4d48454ce34e4455d191a 100644 --- a/fs/go.mod +++ b/fs/go.mod @@ -5,7 +5,7 @@ require ( github.com/anacrolix/envpprof v1.2.1 github.com/anacrolix/fuse v0.2.0 - github.com/anacrolix/log v0.14.0 + github.com/anacrolix/log v0.14.1 github.com/anacrolix/missinggo/v2 v2.7.2-0.20230527121029-a582b4f397b9 github.com/anacrolix/tagflag v1.3.0 github.com/anacrolix/torrent v1.47.1-0.20221102120345-c63f7e1bd720 diff --git a/fs/go.sum b/fs/go.sum index 3f7daed35a0c57c667b5022357a3b3f3bc22001c..b32d6e438e0023a31b3619824bc2139a5beeb178 100644 --- a/fs/go.sum +++ b/fs/go.sum @@ -46,6 +46,8 @@ github.com/anacrolix/log v0.10.1-0.20220123034749-3920702c17f8/go.mod h1:GmnE2c0nvz8pOIPUSC9Rawgefy1sDXqposC2wgtBZE4= github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68= github.com/anacrolix/log v0.14.0 h1:mYhTSemILe/Z8tIxbGdTIWWpPspI8W/fhZHpoFbDaL0= github.com/anacrolix/log v0.14.0/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY= +github.com/anacrolix/log v0.14.1 h1:j2FcIpYZ5FbANetUcm5JNu+zUBGADSp/VbjhUPrAY0k= +github.com/anacrolix/log v0.14.1/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY= github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM= github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM= github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s= diff --git a/socket.go b/socket.go index c1fb97fdbcbee17728d530da76a9fe5a6f5ab094..2d4ea863ac292f39e4d97effd297fe2b98afcfa5 100644 --- a/socket.go +++ b/socket.go @@ -37,10 +37,17 @@ panic(n) } } +// Dialing TCP from a local port limits us to a single outgoing TCP connection to each remote +// client. Instead, this should be a last resort if we need to use holepunching, and only then to +// connect to other clients that actually try to holepunch TCP. +const dialTcpFromListenPort = false + var tcpListenConfig = net.ListenConfig{ Control: func(network, address string, c syscall.RawConn) (err error) { controlErr := c.Control(func(fd uintptr) { - err = setReusePortSockOpts(fd) + if dialTcpFromListenPort { + err = setReusePortSockOpts(fd) + } }) if err != nil { return @@ -54,38 +61,49 @@ } func listenTcp(network, address string) (s socket, err error) { l, err := tcpListenConfig.Listen(context.Background(), network, address) - return tcpSocket{ + if err != nil { + return + } + netDialer := net.Dialer{ + // We don't want fallback, as we explicitly manage the IPv4/IPv6 distinction ourselves, + // although it's probably not triggered as I think the network is already constrained to + // tcp4 or tcp6 at this point. + FallbackDelay: -1, + // BitTorrent connections manage their own keepalives. + KeepAlive: tcpListenConfig.KeepAlive, + Control: func(network, address string, c syscall.RawConn) (err error) { + controlErr := c.Control(func(fd uintptr) { + err = setSockNoLinger(fd) + if err != nil { + // Failing to disable linger is undesirable, but not fatal. + log.Levelf(log.Debug, "error setting linger socket option on tcp socket: %v", err) + err = nil + } + // This is no longer required I think, see + // https://github.com/anacrolix/torrent/discussions/856. I added this originally to + // allow dialling out from the client's listen port, but that doesn't really work. I + // think Linux older than ~2013 doesn't support SO_REUSEPORT. + if dialTcpFromListenPort { + err = setReusePortSockOpts(fd) + } + }) + if err == nil { + err = controlErr + } + return + }, + } + if dialTcpFromListenPort { + netDialer.LocalAddr = l.Addr() + } + s = tcpSocket{ Listener: l, NetworkDialer: NetworkDialer{ Network: network, - Dialer: &net.Dialer{ - // Dialling TCP from a local port limits us to a single outgoing TCP connection to - // each remote client. Instead this should be a last resort if we need to use holepunching, and only then to connect to other clients that actually try to holepunch TCP. - //LocalAddr: l.Addr(), - - // We don't want fallback, as we explicitly manage the IPv4/IPv6 distinction - // ourselves, although it's probably not triggered as I think the network is already - // constrained to tcp4 or tcp6 at this point. - FallbackDelay: -1, - // BitTorrent connections manage their own keep-alives. - KeepAlive: tcpListenConfig.KeepAlive, - Control: func(network, address string, c syscall.RawConn) (err error) { - controlErr := c.Control(func(fd uintptr) { - err = setSockNoLinger(fd) - if err != nil { - // Failing to disable linger is undesirable, but not fatal. - log.Printf("error setting linger socket option on tcp socket: %v", err) - } - err = setReusePortSockOpts(fd) - }) - if err == nil { - err = controlErr - } - return - }, - }, + Dialer: &netDialer, }, - }, err + } + return } type tcpSocket struct {