diff --git a/libtransmission/net.c b/libtransmission/net.c index 618e49816..78bd7eef2 100644 --- a/libtransmission/net.c +++ b/libtransmission/net.c @@ -242,33 +242,22 @@ tr_compareAddresses( const tr_address * a, const tr_address * b) return memcmp( &a->addr, &b->addr, addrlen ); } -tr_net_af_support -tr_net_getAFSupport( tr_port port ) +tr_bool +tr_net_hasIPv6( tr_port port ) { - /* Do we care if an address is in use? Probably not, since it will be - * caught later. This will only set up the list of sockets to bind. */ - static tr_bool alreadyDone = FALSE; - static tr_net_af_support support = { FALSE, FALSE }; - int s4, s6; + static tr_bool alreadyDone = FALSE; + static tr_bool result = FALSE; + int s; if( alreadyDone ) - return support; - s6 = tr_netBindTCP( &tr_in6addr_any, port, TRUE ); - if( s6 >= 0 || -s6 != EAFNOSUPPORT ) /* we support ipv6 */ + return result; + s = tr_netBindTCP( &tr_in6addr_any, port, TRUE ); + if( s >= 0 || -s != EAFNOSUPPORT ) /* we support ipv6 */ { - listen( s6, 1 ); - support.has_inet6 = TRUE; + result = TRUE; + tr_netClose( s ); } - s4 = tr_netBindTCP( &tr_inaddr_any, port, TRUE ); - if( s4 >= 0 ) /* we bound *with* the ipv6 socket bound (need both) - * or only have ipv4 */ - { - tr_netClose( s4 ); - support.needs_inet4 = TRUE; - } - if( s6 >= 0 ) - tr_netClose( s6 ); alreadyDone = TRUE; - return support; + return result; } /*********************************************************************** @@ -537,9 +526,10 @@ tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs ) struct sockaddr_storage sock; const int type = SOCK_STREAM; int addrlen; + int retval; -#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT ) - int optval; +#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT ) || defined( IPV6_V6ONLY ) + int optval = 1; #endif assert( tr_isAddress( addr ) ); @@ -549,10 +539,18 @@ tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs ) return s; #ifdef SO_REUSEADDR - optval = 1; setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) ); #endif +#ifdef IPV6_V6ONLY + if( retval = setsockopt( s, IPPROTO_IPV6, IPV6_V6ONLY, &optval, + sizeof( optval ) ) == -1 ) { + /* the kernel may not support this. if not, ignore it */ + if( errno != ENOPROTOOPT ) + return -errno; + } +#endif + addrlen = setup_sockaddr( addr, htons( port ), &sock ); if( bind( s, (struct sockaddr *) &sock, diff --git a/libtransmission/net.h b/libtransmission/net.h index d8de8c5fb..cbe57b50c 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -94,13 +94,7 @@ void tr_suspectAddress( const tr_address * a, const char * source ); static TR_INLINE tr_bool tr_isAddress( const tr_address * a ) { return ( a != NULL ) && ( a->type==TR_AF_INET || a->type==TR_AF_INET6 ); } -typedef struct tr_net_af_support -{ - tr_bool has_inet6; - tr_bool needs_inet4; -} tr_net_af_support; - -tr_net_af_support tr_net_getAFSupport( tr_port ); +tr_bool tr_net_hasIPv6( tr_port ); /*********************************************************************** * Socket list housekeeping diff --git a/libtransmission/port-forwarding.c b/libtransmission/port-forwarding.c index e014e120d..37c4faab4 100644 --- a/libtransmission/port-forwarding.c +++ b/libtransmission/port-forwarding.c @@ -224,17 +224,15 @@ sharedPulse( void * vshared ) static tr_socketList * setupBindSockets( tr_port port ) { - tr_net_af_support support = tr_net_getAFSupport( port ); + tr_bool hasIPv6 = tr_net_hasIPv6( port ); tr_socketList * socks = NULL; - if( support.has_inet6 ) + if( hasIPv6 ) socks = tr_socketListNew( &tr_in6addr_any ); - if( support.needs_inet4 ) - { - if( socks ) - tr_socketListAppend( socks, &tr_inaddr_any ); - else - socks = tr_socketListNew( &tr_inaddr_any ); - } + + if( socks ) + tr_socketListAppend( socks, &tr_inaddr_any ); + else + socks = tr_socketListNew( &tr_inaddr_any ); return socks; /* Because the dryer gremlins won't */ }