2018-04-12 11:41:07 +10:00
package torrent
import (
"context"
"net"
"strconv"
2023-05-01 10:15:34 +10:00
"syscall"
2018-04-12 11:41:07 +10:00
2022-02-14 21:18:32 -08:00
"github.com/anacrolix/log"
2018-06-15 22:42:05 +10:00
"github.com/anacrolix/missinggo/perf"
2021-06-23 17:24:50 +10:00
"github.com/anacrolix/missinggo/v2"
2018-11-19 20:35:21 +11:00
"github.com/pkg/errors"
2018-04-12 11:41:07 +10:00
)
2020-02-20 16:47:37 +11:00
type Listener interface {
2020-11-09 10:56:27 +11:00
// Accept waits for and returns the next connection to the listener.
Accept ( ) ( net . Conn , error )
// Addr returns the listener's network address.
Addr ( ) net . Addr
2018-04-12 11:41:07 +10:00
}
2020-02-20 10:57:02 +11:00
type socket interface {
2020-02-20 16:47:37 +11:00
Listener
Dialer
2020-11-09 10:56:27 +11:00
Close ( ) error
2018-06-08 13:52:36 +03:00
}
2022-02-14 21:18:32 -08:00
func listen ( n network , addr string , f firewallCallback , logger log . Logger ) ( socket , error ) {
2018-11-28 10:30:21 +11:00
switch {
case n . Tcp :
2020-02-20 10:57:02 +11:00
return listenTcp ( n . String ( ) , addr )
2018-11-28 10:30:21 +11:00
case n . Udp :
2022-02-14 21:18:32 -08:00
return listenUtp ( n . String ( ) , addr , f , logger )
2018-11-28 10:30:21 +11:00
default :
panic ( n )
2018-04-12 11:41:07 +10:00
}
}
2023-05-01 10:15:34 +10:00
var tcpListenConfig = net . ListenConfig {
Control : func ( network , address string , c syscall . RawConn ) ( err error ) {
controlErr := c . Control ( func ( fd uintptr ) {
err = setReusePortSockOpts ( fd )
} )
if err != nil {
return
}
err = controlErr
return
} ,
// BitTorrent connections manage their own keep-alives.
KeepAlive : - 1 ,
}
2020-02-20 10:57:02 +11:00
func listenTcp ( network , address string ) ( s socket , err error ) {
2023-05-01 10:15:34 +10:00
l , err := tcpListenConfig . Listen ( context . Background ( ) , network , address )
2020-02-20 10:57:02 +11:00
return tcpSocket {
Listener : l ,
2021-06-21 13:29:26 +10:00
NetworkDialer : NetworkDialer {
2020-02-20 16:47:37 +11:00
Network : network ,
2023-05-01 10:15:34 +10:00
Dialer : & net . Dialer {
2023-04-29 14:53:03 +10:00
// 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(),
2023-05-01 10:15:34 +10:00
// 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
} ,
} ,
2020-02-20 16:47:37 +11:00
} ,
2020-02-20 10:57:02 +11:00
} , err
2018-04-12 11:41:07 +10:00
}
2020-02-20 10:57:02 +11:00
type tcpSocket struct {
2019-12-22 03:19:16 -05:00
net . Listener
2021-06-21 13:29:26 +10:00
NetworkDialer
2019-12-22 03:19:16 -05:00
}
2022-02-14 21:18:32 -08:00
func listenAll ( networks [ ] network , getHost func ( string ) string , port int , f firewallCallback , logger log . Logger ) ( [ ] socket , error ) {
2018-04-12 11:41:07 +10:00
if len ( networks ) == 0 {
return nil , nil
}
2018-04-12 15:06:53 +10:00
var nahs [ ] networkAndHost
for _ , n := range networks {
2018-11-28 10:30:21 +11:00
nahs = append ( nahs , networkAndHost { n , getHost ( n . String ( ) ) } )
2018-04-12 15:06:53 +10:00
}
2018-04-12 11:41:07 +10:00
for {
2022-02-14 21:18:32 -08:00
ss , retry , err := listenAllRetry ( nahs , port , f , logger )
2018-04-12 11:41:07 +10:00
if ! retry {
return ss , err
}
}
}
2018-04-12 15:06:53 +10:00
type networkAndHost struct {
2018-11-28 10:30:21 +11:00
Network network
2018-04-12 15:06:53 +10:00
Host string
}
2022-02-14 21:18:32 -08:00
func listenAllRetry ( nahs [ ] networkAndHost , port int , f firewallCallback , logger log . Logger ) ( ss [ ] socket , retry bool , err error ) {
2018-04-12 15:06:53 +10:00
ss = make ( [ ] socket , 1 , len ( nahs ) )
portStr := strconv . FormatInt ( int64 ( port ) , 10 )
2022-02-14 21:18:32 -08:00
ss [ 0 ] , err = listen ( nahs [ 0 ] . Network , net . JoinHostPort ( nahs [ 0 ] . Host , portStr ) , f , logger )
2018-04-12 11:41:07 +10:00
if err != nil {
2018-11-19 20:35:21 +11:00
return nil , false , errors . Wrap ( err , "first listen" )
2018-04-12 11:41:07 +10:00
}
defer func ( ) {
if err != nil || retry {
for _ , s := range ss {
s . Close ( )
}
ss = nil
}
} ( )
2018-04-12 15:06:53 +10:00
portStr = strconv . FormatInt ( int64 ( missinggo . AddrPort ( ss [ 0 ] . Addr ( ) ) ) , 10 )
for _ , nah := range nahs [ 1 : ] {
2022-02-14 21:18:32 -08:00
s , err := listen ( nah . Network , net . JoinHostPort ( nah . Host , portStr ) , f , logger )
2018-04-12 11:41:07 +10:00
if err != nil {
return ss ,
missinggo . IsAddrInUse ( err ) && port == 0 ,
2018-11-19 20:35:21 +11:00
errors . Wrap ( err , "subsequent listen" )
2018-04-12 11:41:07 +10:00
}
ss = append ( ss , s )
}
return
}
2021-12-16 09:44:59 +11:00
// This isn't aliased from go-libutp since that assumes CGO.
type firewallCallback func ( net . Addr ) bool
2018-07-25 17:11:09 +10:00
2022-02-14 21:18:32 -08:00
func listenUtp ( network , addr string , fc firewallCallback , logger log . Logger ) ( socket , error ) {
us , err := NewUtpSocket ( network , addr , fc , logger )
2020-02-20 10:57:02 +11:00
return utpSocketSocket { us , network } , err
2019-12-22 03:19:16 -05:00
}
2021-06-21 12:54:57 +10:00
// utpSocket wrapper, additionally wrapped for the torrent package's socket interface.
2018-04-12 11:41:07 +10:00
type utpSocketSocket struct {
utpSocket
network string
}
2021-06-21 12:54:57 +10:00
func ( me utpSocketSocket ) DialerNetwork ( ) string {
return me . network
}
2020-02-20 16:47:37 +11:00
func ( me utpSocketSocket ) Dial ( ctx context . Context , addr string ) ( conn net . Conn , err error ) {
2018-06-15 22:42:05 +10:00
defer perf . ScopeTimerErr ( & err ) ( )
2018-04-12 11:41:07 +10:00
return me . utpSocket . DialContext ( ctx , me . network , addr )
}