(trunk) #1497 Options to listen on specific network sockets

This commit is contained in:
Erick Turnquist 2009-04-15 21:05:58 +00:00
parent b9ad8b290f
commit 2719372bc6
11 changed files with 160 additions and 22 deletions

View File

@ -84,6 +84,9 @@ static const struct tr_option options[] =
{ 910, "encryption-required", "Encrypt all peer connections", "er", 0, NULL },
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", 0, NULL },
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", 0, NULL },
{ 'i', "bind-address-ipv4", "Where to listen for peer connections", "i", 1, "<ipv4 address>" },
{ 'I', "bind-address-ipv6", "Where to listen for peer connections", "I", 1, "<ipv6 address" },
{ 'r', "rpc-bind-address", "Where to listen for RPC connections", "r", 1, "<ipv4 address>" },
{ 0, NULL, NULL, NULL, 0, NULL }
};
@ -276,6 +279,15 @@ main( int argc, char ** argv )
break;
case 912: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_CLEAR_PREFERRED );
break;
case 'i':
tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, optarg );
break;
case 'I':
tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, optarg );
break;
case 'r':
tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_BIND_ADDRESS, optarg );
break;
default: showUsage( );
break;
}

View File

@ -74,6 +74,13 @@ Prefer unencrypted peer connections.
.It Fl h Fl -help
Print command-line option descriptions.
.It Fl i Fl -bind-address-ipv4
Listen for IPv4 BitTorrent connections on a specific address. Only one IPv4 listening address is allowed. Default: 0.0.0.0 (All addresses)
.It Fl I Fl -bind-address-ipv6
Listen for IPv6 BitTorrent connections on a specific address. Only one IPv6 listening address is allowed. Default: :: (All addresses)
.It Fl r Fl -rpc-bind-address
Listen for RPC connections on a specific address. This must be an IPv4 address. Only one RPC listening address is allowed. Default: 0.0.0.0 (All addresses)
.It Fl L Fl -peerlimit-global Ar limit
Overall peer limit. Useful on embedded systems where the default might be unsuitable. Default: 240
.It Fl l Fl -peerlimit-torrent Ar limit

View File

@ -154,6 +154,7 @@ tr_address *
tr_pton( const char * src, tr_address * dst )
{
int retval = inet_pton( AF_INET, src, &dst->addr );
assert( dst );
if( retval < 0 )
return NULL;
else if( retval == 0 )
@ -316,6 +317,19 @@ tr_socketListForEach( tr_socketList * const head,
cb( &tmp->socket, &tmp->addr, userData );
}
const tr_address *
tr_socketListGetType( const tr_socketList * const el, tr_address_type type )
{
const tr_socketList * tmp = el;
while( tmp )
{
if( tmp->addr.type == type )
return &tmp->addr;
tmp = tmp->next;
}
return NULL;
}
/***********************************************************************
* TCP sockets
**********************************************************************/
@ -446,6 +460,8 @@ tr_isValidPeerAddress( const tr_address * addr, tr_port port )
return TRUE;
}
const tr_socketList * tr_getSessionBindSockets( const tr_session * session );
int
tr_netOpenTCP( tr_session * session,
const tr_address * addr,
@ -455,6 +471,9 @@ tr_netOpenTCP( tr_session * session,
struct sockaddr_storage sock;
const int type = SOCK_STREAM;
socklen_t addrlen;
const tr_address * source_addr;
socklen_t sourcelen;
struct sockaddr_storage source_sock;
assert( tr_isAddress( addr ) );
@ -467,6 +486,18 @@ tr_netOpenTCP( tr_session * session,
setSndBuf( session, s );
addrlen = setup_sockaddr( addr, port, &sock );
/* set source address */
source_addr = tr_socketListGetType( tr_getSessionBindSockets( session ),
addr->type );
assert( source_addr );
sourcelen = setup_sockaddr( source_addr, 0, &source_sock );
if( bind( s, ( struct sockaddr * ) &source_sock, sourcelen ) )
{
tr_err( _( "Couldn't set source address %s on %d: %s" ),
tr_ntop_non_ts( source_addr ), s, tr_strerror( errno ) );
return -errno;
}
if( ( connect( s, (struct sockaddr *) &sock,
addrlen ) < 0 )

View File

@ -112,6 +112,8 @@ void tr_socketListForEach( tr_socketList * const head,
tr_address * const,
void * const ),
void * const userData);
const tr_address *tr_socketListGetType( const tr_socketList * const el,
tr_address_type type );
/***********************************************************************
* Sockets

View File

@ -215,32 +215,18 @@ sharedPulse( void * vshared )
****
***/
static tr_socketList *
setupBindSockets( tr_port port )
{
tr_bool hasIPv6 = tr_net_hasIPv6( port );
tr_socketList * socks = NULL;
if( hasIPv6 )
socks = tr_socketListNew( &tr_in6addr_any );
if( socks )
tr_socketListAppend( socks, &tr_inaddr_any );
else
socks = tr_socketListNew( &tr_inaddr_any );
return socks; /* Because the dryer gremlins won't */
}
tr_shared *
tr_sharedInit( tr_session * session,
tr_bool isEnabled,
tr_port publicPort )
tr_port publicPort,
tr_socketList * socks )
{
tr_shared * s = tr_new0( tr_shared, 1 );
s->session = session;
s->publicPort = publicPort;
s->shouldChange = TRUE;
s->bindSockets = setupBindSockets( publicPort );
s->bindSockets = socks;
s->shouldChange = TRUE;
s->natpmp = tr_natpmpInit( );
s->upnp = tr_upnpInit( );
@ -294,3 +280,8 @@ tr_sharedTraversalStatus( const tr_shared * s )
return MAX( s->natpmpStatus, s->upnpStatus );
}
const tr_socketList *
tr_sharedGetBindSockets( const tr_shared * shared )
{
return shared->bindSockets;
}

View File

@ -30,10 +30,12 @@
#define SHARED_H 1
#include "transmission.h"
#include "net.h"
typedef struct tr_shared tr_shared;
tr_shared* tr_sharedInit( tr_session*, tr_bool isEnabled, tr_port publicPort );
tr_shared* tr_sharedInit( tr_session*, tr_bool isEnabled, tr_port publicPort,
tr_socketList * socks);
void tr_sharedShuttingDown( tr_shared * );
@ -47,4 +49,5 @@ tr_bool tr_sharedTraversalIsEnabled( const tr_shared * s );
int tr_sharedTraversalStatus( const tr_shared * );
const tr_socketList *tr_sharedGetBindSockets( const tr_shared * shared );
#endif

View File

@ -37,6 +37,7 @@
#include "trevent.h"
#include "utils.h"
#include "web.h"
#include "net.h"
#define MY_NAME "RPC Server"
#define MY_REALM "Transmission"
@ -52,6 +53,7 @@ struct tr_rpc_server
tr_bool isPasswordEnabled;
tr_bool isWhitelistEnabled;
tr_port port;
struct in_addr bindAddress;
struct evhttp * httpd;
tr_session * session;
char * username;
@ -528,11 +530,15 @@ static void
startServer( void * vserver )
{
tr_rpc_server * server = vserver;
tr_address addr;
if( !server->httpd )
{
addr.type = TR_AF_INET;
addr.addr.addr4 = server->bindAddress;
server->httpd = evhttp_new( tr_eventGetBase( server->session ) );
evhttp_bind_socket( server->httpd, "0.0.0.0", server->port );
evhttp_bind_socket( server->httpd, tr_ntop_non_ts( &addr ),
server->port );
evhttp_set_gencb( server->httpd, handle_request, server );
}
@ -707,6 +713,15 @@ tr_rpcIsPasswordEnabled( const tr_rpc_server * server )
return server->isPasswordEnabled;
}
const char *
tr_rpcGetBindAddress( const tr_rpc_server * server )
{
tr_address addr;
addr.type = TR_AF_INET;
addr.addr.addr4 = server->bindAddress;
return tr_ntop_non_ts( &addr );
}
/****
***** LIFE CYCLE
****/
@ -745,6 +760,7 @@ tr_rpcInit( tr_session * session,
tr_bool boolVal;
int64_t i;
const char *str;
tr_address address;
s = tr_new0( tr_rpc_server, 1 );
s->session = session;
@ -780,6 +796,18 @@ tr_rpcInit( tr_session * session,
else
s->password = strdup( str );
found = tr_bencDictFindStr( settings, TR_PREFS_KEY_RPC_BIND_ADDRESS, &str );
assert( found );
if( tr_pton( str, &address ) == NULL ) {
tr_err( _( "%s is not a valid address" ), str );
address = tr_inaddr_any;
} else if( address.type != TR_AF_INET ) {
tr_err( _( "%s is not an IPv4 address. RPC listeners must be IPv4" ),
str );
address = tr_inaddr_any;
}
s->bindAddress = address.addr.addr4;
#ifdef HAVE_ZLIB
s->stream.zalloc = (alloc_func) Z_NULL;
s->stream.zfree = (free_func) Z_NULL;

View File

@ -63,5 +63,6 @@ void tr_rpcSetPasswordEnabled( tr_rpc_server * server,
tr_bool tr_rpcIsPasswordEnabled( const tr_rpc_server * session );
const char* tr_rpcGetBindAddress( const tr_rpc_server * server );
#endif

View File

@ -281,6 +281,7 @@ tr_sessionGetDefaultSettings( tr_benc * d )
tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO, 2.0 );
tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED, FALSE );
tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED, FALSE );
tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_BIND_ADDRESS, "0.0.0.0" );
tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED, TRUE );
tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD, "" );
tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME, "" );
@ -297,8 +298,12 @@ tr_sessionGetDefaultSettings( tr_benc * d )
tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED, 100 );
tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, FALSE );
tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, 14 );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, TR_DEFAULT_BIND_ADDRESS_IPV4 );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, TR_DEFAULT_BIND_ADDRESS_IPV6 );
}
const tr_socketList * tr_getSessionBindSockets( const tr_session * session );
void
tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
{
@ -336,6 +341,7 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
tr_bencDictAddReal( d, TR_PREFS_KEY_RATIO, s->desiredRatio );
tr_bencDictAddBool( d, TR_PREFS_KEY_RATIO_ENABLED, s->isRatioLimited );
tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED, tr_sessionIsRPCPasswordEnabled( s ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_BIND_ADDRESS, tr_sessionGetRPCBindAddress( s ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_ENABLED, tr_sessionIsRPCEnabled( s ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_PASSWORD, freeme[n++] = tr_sessionGetRPCPassword( s ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT, tr_sessionGetRPCPort( s ) );
@ -352,6 +358,10 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
tr_bencDictAddInt ( d, TR_PREFS_KEY_USPEED, tr_sessionGetSpeedLimit( s, TR_UP ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, tr_sessionIsSpeedLimited( s, TR_UP ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4,
tr_ntop_non_ts( tr_socketListGetType( tr_getSessionBindSockets( s ), TR_AF_INET ) ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6,
tr_ntop_non_ts( tr_socketListGetType( tr_getSessionBindSockets( s ), TR_AF_INET6 ) ) );
for( i=0; i<n; ++i )
tr_free( freeme[i] );
@ -500,6 +510,8 @@ tr_sessionInitImpl( void * vdata )
struct init_data * data = vdata;
tr_benc * clientSettings = data->clientSettings;
tr_session * session = data->session;
tr_address address;
tr_socketList * socketList;
assert( tr_amInEventThread( session ) );
assert( tr_bencIsDict( clientSettings ) );
@ -618,7 +630,39 @@ tr_sessionInitImpl( void * vdata )
&& tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j );
assert( found );
session->peerPort = session->isPortRandom ? getRandomPort( session ) : j;
session->shared = tr_sharedInit( session, boolVal, session->peerPort );
/* bind addresses */
found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4,
&str );
assert( found );
if( tr_pton( str, &address ) == NULL ) {
tr_err( _( "%s is not a valid address" ), str );
socketList = tr_socketListNew( &tr_inaddr_any );
} else if( address.type != TR_AF_INET ) {
tr_err( _( "%s is not an IPv4 address" ), str );
socketList = tr_socketListNew( &tr_inaddr_any );
} else
socketList = tr_socketListNew( &address );
found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6,
&str );
assert( found );
if( tr_pton( str, &address ) == NULL ) {
tr_err( _( "%s is not a valid address" ), str );
address = tr_in6addr_any;
} else if( address.type != TR_AF_INET6 ) {
tr_err( _( "%s is not an IPv6 address" ), str );
address = tr_in6addr_any;
}
if( tr_net_hasIPv6( session->peerPort ) )
tr_socketListAppend( socketList, &address );
else
tr_inf( _( "System does not seem to support IPv6. Not listening on"
"an IPv6 address" ) );
session->shared = tr_sharedInit( session, boolVal, session->peerPort,
socketList );
session->isPortSet = session->peerPort > 0;
/**
@ -1889,6 +1933,14 @@ tr_sessionIsRPCPasswordEnabled( const tr_session * session )
return tr_rpcIsPasswordEnabled( session->rpcServer );
}
const char *
tr_sessionGetRPCBindAddress( const tr_session * session )
{
assert( tr_isSession( session ) );
return tr_rpcGetBindAddress( session->rpcServer );
}
/***
****
***/
@ -2038,3 +2090,9 @@ tr_sessionGetActiveTorrentCount( tr_session * session )
return ret;
}
const tr_socketList *
tr_getSessionBindSockets( const tr_session * session )
{
return tr_sharedGetBindSockets( session->shared );
}

View File

@ -171,8 +171,6 @@ void tr_globalLock( tr_session * );
void tr_globalUnlock( tr_session * );
tr_bool tr_globalIsLocked( const tr_session * );
enum
{
SESSION_MAGIC_NUMBER = 3845

View File

@ -150,6 +150,8 @@ static TR_INLINE tr_bool tr_isEncryptionMode( tr_encryption_mode m )
}
#define TR_DEFAULT_BIND_ADDRESS_IPV4 "0.0.0.0"
#define TR_DEFAULT_BIND_ADDRESS_IPV6 "::"
#define TR_DEFAULT_OPEN_FILE_LIMIT_STR "32"
#define TR_DEFAULT_RPC_WHITELIST "127.0.0.1"
#define TR_DEFAULT_RPC_PORT_STR "9091"
@ -165,6 +167,8 @@ static TR_INLINE tr_bool tr_isEncryptionMode( tr_encryption_mode m )
#define TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED "alt-speed-time-enabled"
#define TR_PREFS_KEY_ALT_SPEED_TIME_END "alt-speed-time-end"
#define TR_PREFS_KEY_ALT_SPEED_TIME_DAY "alt-speed-time-day"
#define TR_PREFS_KEY_BIND_ADDRESS_IPV4 "bind-address-ipv4"
#define TR_PREFS_KEY_BIND_ADDRESS_IPV6 "bind-address-ipv6"
#define TR_PREFS_KEY_BLOCKLIST_ENABLED "blocklist-enabled"
#define TR_PREFS_KEY_DOWNLOAD_DIR "download-dir"
#define TR_PREFS_KEY_ENCRYPTION "encryption"
@ -191,6 +195,7 @@ static TR_INLINE tr_bool tr_isEncryptionMode( tr_encryption_mode m )
#define TR_PREFS_KEY_RATIO "ratio-limit"
#define TR_PREFS_KEY_RATIO_ENABLED "ratio-limit-enabled"
#define TR_PREFS_KEY_RPC_AUTH_REQUIRED "rpc-authentication-required"
#define TR_PREFS_KEY_RPC_BIND_ADDRESS "rpc-bind-address"
#define TR_PREFS_KEY_RPC_ENABLED "rpc-enabled"
#define TR_PREFS_KEY_RPC_PASSWORD "rpc-password"
#define TR_PREFS_KEY_RPC_PORT "rpc-port"
@ -397,6 +402,8 @@ void tr_sessionSetRPCPasswordEnabled( tr_session * session,
tr_bool tr_sessionIsRPCPasswordEnabled( const tr_session * session );
const char* tr_sessionGetRPCBindAddress( const tr_session * session );
typedef enum
{