(trunk libT) #2035: Transmission causes wakeups by unnecessary polling.
This commit is contained in:
parent
3973659162
commit
da42fe8a7c
|
@ -38,6 +38,7 @@
|
|||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#include <evutil.h>
|
||||
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include "net.h"
|
||||
#include "peer-io.h"
|
||||
#include "platform.h"
|
||||
#include "session.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef IN_MULTICAST
|
||||
|
@ -54,31 +56,30 @@
|
|||
#endif
|
||||
|
||||
const tr_address tr_in6addr_any = { TR_AF_INET6, { IN6ADDR_ANY_INIT } };
|
||||
const tr_address tr_inaddr_any = { TR_AF_INET,
|
||||
{ { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } };
|
||||
const tr_address tr_inaddr_any = { TR_AF_INET, { { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } };
|
||||
|
||||
#ifdef WIN32
|
||||
static const char *
|
||||
inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
|
||||
inet_ntop( int af, const void *src, char *dst, socklen_t cnt )
|
||||
{
|
||||
if (af == AF_INET)
|
||||
{
|
||||
struct sockaddr_in in;
|
||||
memset(&in, 0, sizeof(in));
|
||||
memset( &in, 0, sizeof( in ) );
|
||||
in.sin_family = AF_INET;
|
||||
memcpy(&in.sin_addr, src, sizeof(struct in_addr));
|
||||
getnameinfo((struct sockaddr *)&in, sizeof(struct
|
||||
sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
|
||||
memcpy( &in.sin_addr, src, sizeof( struct in_addr ) );
|
||||
getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in),
|
||||
dst, cnt, NULL, 0, NI_NUMERICHOST);
|
||||
return dst;
|
||||
}
|
||||
else if (af == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 in;
|
||||
memset(&in, 0, sizeof(in));
|
||||
memset( &in, 0, sizeof( in ) );
|
||||
in.sin6_family = AF_INET6;
|
||||
memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
|
||||
getnameinfo((struct sockaddr *)&in, sizeof(struct
|
||||
sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
|
||||
memcpy( &in.sin6_addr, src, sizeof( struct in_addr6 ) );
|
||||
getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6),
|
||||
dst, cnt, NULL, 0, NI_NUMERICHOST);
|
||||
return dst;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -196,140 +197,22 @@ tr_compareAddresses( const tr_address * a, const tr_address * b)
|
|||
tr_bool
|
||||
tr_net_hasIPv6( tr_port port )
|
||||
{
|
||||
static tr_bool result = FALSE;
|
||||
static tr_bool alreadyDone = FALSE;
|
||||
static tr_bool result = FALSE;
|
||||
int s;
|
||||
if( alreadyDone )
|
||||
return result;
|
||||
s = tr_netBindTCP( &tr_in6addr_any, port, TRUE );
|
||||
if( s >= 0 || -s != EAFNOSUPPORT ) /* we support ipv6 */
|
||||
|
||||
if( !alreadyDone )
|
||||
{
|
||||
result = TRUE;
|
||||
tr_netClose( s );
|
||||
int fd = tr_netBindTCP( &tr_in6addr_any, port, TRUE );
|
||||
if( fd >= 0 || -fd != EAFNOSUPPORT ) /* we support ipv6 */
|
||||
result = TRUE;
|
||||
if( fd >= 0 )
|
||||
EVUTIL_CLOSESOCKET( fd );
|
||||
alreadyDone = TRUE;
|
||||
}
|
||||
alreadyDone = TRUE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Socket list housekeeping
|
||||
**********************************************************************/
|
||||
struct tr_socketList
|
||||
{
|
||||
int socket;
|
||||
tr_address addr;
|
||||
tr_socketList * next;
|
||||
};
|
||||
|
||||
tr_socketList *
|
||||
tr_socketListAppend( tr_socketList * const head,
|
||||
const tr_address * const addr )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
|
||||
assert( head );
|
||||
assert( tr_isAddress( addr ) );
|
||||
|
||||
for( tmp = head; tmp->next; tmp = tmp->next );
|
||||
tmp->next = tr_socketListNew( addr );
|
||||
return tmp->next;
|
||||
}
|
||||
|
||||
tr_socketList *
|
||||
tr_socketListNew( const tr_address * const addr )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
|
||||
assert( tr_isAddress( addr ) );
|
||||
|
||||
tmp = tr_new( tr_socketList, 1 );
|
||||
tmp->socket = -1;
|
||||
tmp->addr = *addr;
|
||||
tmp->next = NULL;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListFree( tr_socketList * const head )
|
||||
{
|
||||
assert( head );
|
||||
|
||||
if( head->next )
|
||||
tr_socketListFree( head->next );
|
||||
tr_free( head );
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListRemove( tr_socketList * const head,
|
||||
tr_socketList * const el)
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
|
||||
assert( head );
|
||||
assert( el );
|
||||
|
||||
for( tmp = head; tmp->next && tmp->next != el; tmp = tmp->next );
|
||||
tmp->next = el->next;
|
||||
el->next = NULL;
|
||||
tr_socketListFree(el);
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListTruncate( tr_socketList * const head,
|
||||
tr_socketList * const start )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
|
||||
assert( head );
|
||||
assert( start );
|
||||
|
||||
for( tmp = head; tmp->next && tmp->next != start; tmp = tmp->next );
|
||||
tr_socketListFree( start );
|
||||
tmp->next = NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
tr_socketListGetSocket( const tr_socketList * const el )
|
||||
{
|
||||
assert( el );
|
||||
|
||||
return el->socket;
|
||||
}
|
||||
|
||||
const tr_address *
|
||||
tr_socketListGetAddress( const tr_socketList * const el )
|
||||
{
|
||||
assert( el );
|
||||
return &el->addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tr_socketListForEach( tr_socketList * const head,
|
||||
void ( * cb ) ( int * const,
|
||||
tr_address * const,
|
||||
void * const),
|
||||
void * const userData )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
for( tmp = head; tmp; tmp = tmp->next )
|
||||
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
|
||||
**********************************************************************/
|
||||
|
@ -344,57 +227,16 @@ tr_netSetTOS( int s, int tos )
|
|||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
makeSocketNonBlocking( int fd )
|
||||
{
|
||||
if( fd >= 0 )
|
||||
{
|
||||
if( evutil_make_socket_nonblocking( fd ) )
|
||||
{
|
||||
int tmperrno;
|
||||
tr_err( _( "Couldn't create socket: %s" ),
|
||||
tr_strerror( sockerrno ) );
|
||||
tmperrno = sockerrno;
|
||||
tr_netClose( fd );
|
||||
fd = -tmperrno;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
createSocket( int domain, int type )
|
||||
{
|
||||
return makeSocketNonBlocking( tr_fdSocketCreate( domain, type ) );
|
||||
}
|
||||
|
||||
static void
|
||||
setSndBuf( tr_session * session UNUSED, int fd UNUSED )
|
||||
{
|
||||
#if 0
|
||||
if( fd >= 0 )
|
||||
{
|
||||
const int sndbuf = session->so_sndbuf;
|
||||
const int rcvbuf = session->so_rcvbuf;
|
||||
setsockopt( fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof( sndbuf ) );
|
||||
setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof( rcvbuf ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static socklen_t
|
||||
setup_sockaddr( const tr_address * addr,
|
||||
tr_port port,
|
||||
struct sockaddr_storage * sockaddr)
|
||||
{
|
||||
struct sockaddr_in sock4;
|
||||
struct sockaddr_in6 sock6;
|
||||
|
||||
assert( tr_isAddress( addr ) );
|
||||
|
||||
if( addr->type == TR_AF_INET )
|
||||
{
|
||||
struct sockaddr_in sock4;
|
||||
memset( &sock4, 0, sizeof( sock4 ) );
|
||||
sock4.sin_family = AF_INET;
|
||||
sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
|
||||
|
@ -404,11 +246,12 @@ setup_sockaddr( const tr_address * addr,
|
|||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in6 sock6;
|
||||
memset( &sock6, 0, sizeof( sock6 ) );
|
||||
sock6.sin6_family = AF_INET6;
|
||||
sock6.sin6_port = port;
|
||||
sock6.sin6_family = AF_INET6;
|
||||
sock6.sin6_port = port;
|
||||
sock6.sin6_flowinfo = 0;
|
||||
sock6.sin6_addr = addr->addr.addr6;
|
||||
sock6.sin6_addr = addr->addr.addr6;
|
||||
memcpy( sockaddr, &sock6, sizeof( sock6 ) );
|
||||
return sizeof( struct sockaddr_in6 );
|
||||
}
|
||||
|
@ -460,16 +303,14 @@ 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,
|
||||
tr_port port )
|
||||
{
|
||||
static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
|
||||
int s;
|
||||
struct sockaddr_storage sock;
|
||||
const int type = SOCK_STREAM;
|
||||
socklen_t addrlen;
|
||||
const tr_address * source_addr;
|
||||
socklen_t sourcelen;
|
||||
|
@ -480,16 +321,19 @@ tr_netOpenTCP( tr_session * session,
|
|||
if( isMulticastAddress( addr ) || isIPv6LinkLocalAddress( addr ) )
|
||||
return -EINVAL;
|
||||
|
||||
if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ), type ) ) < 0 )
|
||||
return s;
|
||||
s = tr_fdSocketCreate( domains[addr->type], SOCK_STREAM );
|
||||
if( s < 0 )
|
||||
return -1;
|
||||
|
||||
setSndBuf( session, s );
|
||||
if( evutil_make_socket_nonblocking( s ) < 0 ) {
|
||||
EVUTIL_CLOSESOCKET( s );
|
||||
return -1;
|
||||
}
|
||||
|
||||
addrlen = setup_sockaddr( addr, port, &sock );
|
||||
|
||||
/* set source address */
|
||||
source_addr = tr_socketListGetType( tr_getSessionBindSockets( session ),
|
||||
addr->type );
|
||||
source_addr = tr_sessionGetPublicAddress( session, addr->type );
|
||||
assert( source_addr );
|
||||
sourcelen = setup_sockaddr( source_addr, 0, &source_sock );
|
||||
if( bind( s, ( struct sockaddr * ) &source_sock, sourcelen ) )
|
||||
|
@ -526,64 +370,68 @@ tr_netOpenTCP( tr_session * session,
|
|||
int
|
||||
tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
|
||||
{
|
||||
int s;
|
||||
static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
|
||||
struct sockaddr_storage sock;
|
||||
const int type = SOCK_STREAM;
|
||||
int addrlen;
|
||||
|
||||
#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT ) || defined( IPV6_V6ONLY )
|
||||
int optval = 1;
|
||||
#endif
|
||||
int fd;
|
||||
int addrlen;
|
||||
int optval;
|
||||
|
||||
assert( tr_isAddress( addr ) );
|
||||
|
||||
if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
|
||||
type ) ) < 0 )
|
||||
return s;
|
||||
fd = socket( domains[addr->type], SOCK_STREAM, 0 );
|
||||
if( fd < 0 )
|
||||
return -1;
|
||||
|
||||
#ifdef SO_REUSEADDR
|
||||
setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
|
||||
#endif
|
||||
if( evutil_make_socket_nonblocking( fd ) < 0 ) {
|
||||
EVUTIL_CLOSESOCKET( fd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
optval = 1;
|
||||
setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) );
|
||||
setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if( addr->type == TR_AF_INET6 &&
|
||||
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;
|
||||
}
|
||||
if( addr->type == TR_AF_INET6 )
|
||||
if( setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof( optval ) ) == -1 )
|
||||
if( EVUTIL_SOCKET_ERROR( ) != ENOPROTOOPT ) /* if the kernel doesn't support it, ignore it */
|
||||
return -EVUTIL_SOCKET_ERROR( );
|
||||
#endif
|
||||
|
||||
addrlen = setup_sockaddr( addr, htons( port ), &sock );
|
||||
|
||||
if( bind( s, (struct sockaddr *) &sock,
|
||||
addrlen ) )
|
||||
{
|
||||
int tmperrno;
|
||||
if( bind( fd, (struct sockaddr *) &sock, addrlen ) ) {
|
||||
const int err = EVUTIL_SOCKET_ERROR( );
|
||||
if( !suppressMsgs )
|
||||
tr_err( _( "Couldn't bind port %d on %s: %s" ), port,
|
||||
tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) );
|
||||
tmperrno = sockerrno;
|
||||
tr_netClose( s );
|
||||
return -tmperrno;
|
||||
tr_err( _( "Couldn't bind port %d on %s: %s" ),
|
||||
port, tr_ntop_non_ts( addr ), tr_strerror( err ) );
|
||||
tr_netClose( fd );
|
||||
return -err;
|
||||
}
|
||||
|
||||
if( !suppressMsgs )
|
||||
tr_dbg( "Bound socket %d to port %d on %s",
|
||||
s, port, tr_ntop_non_ts( addr ) );
|
||||
return s;
|
||||
tr_dbg( "Bound socket %d to port %d on %s", fd, port, tr_ntop_non_ts( addr ) );
|
||||
|
||||
if( listen( fd, 128 ) == -1 ) {
|
||||
EVUTIL_CLOSESOCKET( fd );
|
||||
return -EVUTIL_SOCKET_ERROR( );
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
tr_netAccept( tr_session * session,
|
||||
tr_netAccept( tr_session * session UNUSED,
|
||||
int b,
|
||||
tr_address * addr,
|
||||
tr_port * port )
|
||||
{
|
||||
int fd;
|
||||
int fd = tr_fdSocketAccept( b, addr, port );
|
||||
|
||||
if( fd>=0 && evutil_make_socket_nonblocking(fd)<0 ) {
|
||||
EVUTIL_CLOSESOCKET( fd );
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
fd = makeSocketNonBlocking( tr_fdSocketAccept( b, addr, port ) );
|
||||
setSndBuf( session, fd );
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,10 @@ struct tr_session;
|
|||
typedef enum tr_address_type
|
||||
{
|
||||
TR_AF_INET,
|
||||
TR_AF_INET6
|
||||
} tr_address_type;
|
||||
TR_AF_INET6,
|
||||
NUM_TR_AF_INET_TYPES
|
||||
}
|
||||
tr_address_type;
|
||||
|
||||
typedef struct tr_address
|
||||
{
|
||||
|
@ -93,28 +95,6 @@ static TR_INLINE tr_bool tr_isAddress( const tr_address * a ) { return ( a != NU
|
|||
|
||||
tr_bool tr_net_hasIPv6( tr_port );
|
||||
|
||||
/***********************************************************************
|
||||
* Socket list housekeeping
|
||||
**********************************************************************/
|
||||
typedef struct tr_socketList tr_socketList;
|
||||
tr_socketList *tr_socketListAppend( tr_socketList * const head,
|
||||
const tr_address * const addr );
|
||||
tr_socketList *tr_socketListNew( const tr_address * const addr );
|
||||
void tr_socketListFree( tr_socketList * const head );
|
||||
void tr_socketListRemove( tr_socketList * const head,
|
||||
tr_socketList * const el);
|
||||
void tr_socketListTruncate( tr_socketList * const head,
|
||||
tr_socketList * const start );
|
||||
int tr_socketListGetSocket( const tr_socketList * const el );
|
||||
const tr_address *tr_socketListGetAddress( const tr_socketList * const el );
|
||||
void tr_socketListForEach( tr_socketList * const head,
|
||||
void ( * cb ) ( int * const,
|
||||
tr_address * const,
|
||||
void * const ),
|
||||
void * const userData);
|
||||
const tr_address *tr_socketListGetType( const tr_socketList * const el,
|
||||
tr_address_type type );
|
||||
|
||||
/***********************************************************************
|
||||
* Sockets
|
||||
**********************************************************************/
|
||||
|
|
|
@ -35,20 +35,16 @@ struct tr_shared
|
|||
{
|
||||
tr_bool isEnabled;
|
||||
tr_bool isShuttingDown;
|
||||
tr_bool doPortCheck;
|
||||
|
||||
tr_port_forwarding natpmpStatus;
|
||||
tr_port_forwarding upnpStatus;
|
||||
|
||||
tr_bool shouldChange;
|
||||
tr_socketList * bindSockets;
|
||||
tr_port publicPort;
|
||||
|
||||
tr_timer * pulseTimer;
|
||||
tr_timer * recheckTimer;
|
||||
|
||||
tr_upnp * upnp;
|
||||
tr_natpmp * natpmp;
|
||||
tr_session * session;
|
||||
|
||||
struct event * timer;
|
||||
};
|
||||
|
||||
/***
|
||||
|
@ -60,36 +56,21 @@ getNatStateStr( int state )
|
|||
{
|
||||
switch( state )
|
||||
{
|
||||
/* we're in the process of trying to set up port forwarding */
|
||||
case TR_PORT_MAPPING:
|
||||
return _( "Starting" );
|
||||
|
||||
/* we've successfully forwarded the port */
|
||||
case TR_PORT_MAPPED:
|
||||
return _( "Forwarded" );
|
||||
|
||||
/* we're cancelling the port forwarding */
|
||||
case TR_PORT_UNMAPPING:
|
||||
return _( "Stopping" );
|
||||
|
||||
/* the port isn't forwarded */
|
||||
case TR_PORT_UNMAPPED:
|
||||
return _( "Not forwarded" );
|
||||
|
||||
case TR_PORT_ERROR:
|
||||
return "???";
|
||||
case TR_PORT_MAPPING: return _( "Starting" );
|
||||
case TR_PORT_MAPPED: return _( "Forwarded" );
|
||||
case TR_PORT_UNMAPPING: return _( "Stopping" );
|
||||
case TR_PORT_UNMAPPED: return _( "Not forwarded" );
|
||||
default: return "???";
|
||||
}
|
||||
|
||||
return "notfound";
|
||||
}
|
||||
|
||||
static void
|
||||
natPulse( tr_shared * s, tr_bool doPortCheck )
|
||||
{
|
||||
const tr_port port = s->publicPort;
|
||||
const int isEnabled = s->isEnabled && !s->isShuttingDown;
|
||||
int oldStatus;
|
||||
int newStatus;
|
||||
const tr_port port = s->session->peerPort;
|
||||
const int isEnabled = s->isEnabled && !s->isShuttingDown;
|
||||
int oldStatus;
|
||||
int newStatus;
|
||||
|
||||
oldStatus = tr_sharedTraversalStatus( s );
|
||||
s->natpmpStatus = tr_natpmpPulse( s->natpmp, port, isEnabled );
|
||||
|
@ -102,187 +83,125 @@ natPulse( tr_shared * s, tr_bool doPortCheck )
|
|||
getNatStateStr( newStatus ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Callbacks for socket list
|
||||
*/
|
||||
static void
|
||||
closeCb( int * const socket,
|
||||
tr_address * const addr,
|
||||
void * const userData )
|
||||
onTimer( int fd UNUSED, short what UNUSED, void * vshared )
|
||||
{
|
||||
tr_shared * s = ( tr_shared * )userData;
|
||||
if( *socket >= 0 )
|
||||
{
|
||||
tr_ninf( getKey( ), _( "Closing port %d on %s" ), s->publicPort,
|
||||
tr_ntop_non_ts( addr ) );
|
||||
tr_netClose( *socket );
|
||||
}
|
||||
}
|
||||
tr_shared * s = vshared;
|
||||
struct timeval interval;
|
||||
|
||||
static void
|
||||
acceptCb( int * const socket,
|
||||
tr_address * const addr UNUSED,
|
||||
void * const userData )
|
||||
{
|
||||
tr_shared * s = ( tr_shared * )userData;
|
||||
tr_address clientAddr;
|
||||
tr_port clientPort;
|
||||
int clientSocket;
|
||||
clientSocket = tr_netAccept( s->session, *socket, &clientAddr, &clientPort );
|
||||
if( clientSocket > 0 )
|
||||
{
|
||||
tr_deepLog( __FILE__, __LINE__, NULL,
|
||||
"New INCOMING connection %d (%s)",
|
||||
clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
|
||||
|
||||
tr_peerMgrAddIncoming( s->session->peerMgr, &clientAddr, clientPort,
|
||||
clientSocket );
|
||||
}
|
||||
}
|
||||
assert( s );
|
||||
assert( s->timer );
|
||||
|
||||
static void
|
||||
bindCb( int * const socket,
|
||||
tr_address * const addr,
|
||||
void * const userData )
|
||||
{
|
||||
tr_shared * s = ( tr_shared * )userData;
|
||||
*socket = tr_netBindTCP( addr, s->publicPort, FALSE );
|
||||
if( *socket >= 0 )
|
||||
{
|
||||
tr_ninf( getKey( ),
|
||||
_( "Opened port %d on %s to listen for incoming peer connections" ),
|
||||
s->publicPort, tr_ntop_non_ts( addr ) );
|
||||
listen( *socket, 10 );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_nerr( getKey( ),
|
||||
_(
|
||||
"Couldn't open port %d on %s to listen for incoming peer connections (errno %d - %s)" ),
|
||||
s->publicPort, tr_ntop_non_ts( addr ), errno, tr_strerror( errno ) );
|
||||
}
|
||||
}
|
||||
/* do something */
|
||||
natPulse( s, s->doPortCheck );
|
||||
s->doPortCheck = FALSE;
|
||||
|
||||
static void
|
||||
incomingPeersPulse( tr_shared * s )
|
||||
{
|
||||
if( s->shouldChange )
|
||||
/* when to wake up again */
|
||||
switch( tr_sharedTraversalStatus( s ) )
|
||||
{
|
||||
tr_socketListForEach( s->bindSockets, &closeCb, s );
|
||||
s->shouldChange = FALSE;
|
||||
if( s->publicPort > 0 )
|
||||
tr_socketListForEach( s->bindSockets, &bindCb, s );
|
||||
}
|
||||
|
||||
/* (jhujhiti):
|
||||
* This has been changed from a loop that will end when the listener queue
|
||||
* is exhausted to one that will only check for one connection at a time.
|
||||
* I think it unlikely that we get many more than one connection in the
|
||||
* time between pulses (currently one second). However, just to be safe,
|
||||
* I have increased the length of the listener queue from 5 to 10
|
||||
* (see acceptCb() above). */
|
||||
tr_socketListForEach( s->bindSockets, &acceptCb, s );
|
||||
}
|
||||
case TR_PORT_MAPPED:
|
||||
/* if we're mapped, everything is fine... check back in 20 minutes
|
||||
* to renew the port forwarding if it's expired */
|
||||
s->doPortCheck = TRUE;
|
||||
interval.tv_sec = 60*20;
|
||||
break;
|
||||
|
||||
static int
|
||||
sharedPulse( void * vshared )
|
||||
{
|
||||
tr_bool keepPulsing = TRUE;
|
||||
tr_shared * shared = vshared;
|
||||
case TR_PORT_ERROR:
|
||||
/* some kind of an error. wait 60 seconds and retry */
|
||||
interval.tv_sec = 60;
|
||||
break;
|
||||
|
||||
natPulse( shared, FALSE );
|
||||
|
||||
if( !shared->isShuttingDown )
|
||||
{
|
||||
incomingPeersPulse( shared );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_ninf( getKey( ), _( "Stopped" ) );
|
||||
tr_timerFree( &shared->pulseTimer );
|
||||
tr_timerFree( &shared->recheckTimer );
|
||||
tr_socketListForEach( shared->bindSockets, &closeCb, shared );
|
||||
tr_socketListFree( shared->bindSockets );
|
||||
tr_natpmpClose( shared->natpmp );
|
||||
tr_upnpClose( shared->upnp );
|
||||
shared->session->shared = NULL;
|
||||
tr_free( shared );
|
||||
keepPulsing = FALSE;
|
||||
default:
|
||||
/* in progress. pulse frequently. */
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_usec = 333000;
|
||||
break;
|
||||
}
|
||||
|
||||
return keepPulsing;
|
||||
}
|
||||
|
||||
static int
|
||||
recheckPulse( void * vshared )
|
||||
{
|
||||
tr_bool keepPulsing = TRUE;
|
||||
tr_shared * shared = vshared;
|
||||
|
||||
tr_ninf( getKey( ), _( "Checking to see if port %d is still open" ), shared->publicPort );
|
||||
natPulse( shared, TRUE );
|
||||
|
||||
if( shared->isShuttingDown )
|
||||
keepPulsing = FALSE;
|
||||
|
||||
return keepPulsing;
|
||||
evtimer_add( s->timer, &interval );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static void
|
||||
start_timer( tr_shared * s )
|
||||
{
|
||||
s->timer = tr_new0( struct event, 1 );
|
||||
evtimer_set( s->timer, onTimer, s );
|
||||
onTimer( 0, 0, s );
|
||||
}
|
||||
|
||||
tr_shared *
|
||||
tr_sharedInit( tr_session * session,
|
||||
tr_bool isEnabled,
|
||||
tr_port publicPort,
|
||||
tr_socketList * socks )
|
||||
tr_sharedInit( tr_session * session, tr_bool isEnabled )
|
||||
{
|
||||
tr_shared * s = tr_new0( tr_shared, 1 );
|
||||
|
||||
s->session = session;
|
||||
s->publicPort = publicPort;
|
||||
s->bindSockets = socks;
|
||||
s->shouldChange = TRUE;
|
||||
s->natpmp = tr_natpmpInit( );
|
||||
s->upnp = tr_upnpInit( );
|
||||
s->pulseTimer = tr_timerNew( session, sharedPulse, s, 1000 );
|
||||
s->recheckTimer = tr_timerNew( session, recheckPulse, s, 1000*60*20 ); /* 20 minutes */
|
||||
s->isEnabled = isEnabled;
|
||||
s->upnpStatus = TR_PORT_UNMAPPED;
|
||||
s->natpmpStatus = TR_PORT_UNMAPPED;
|
||||
|
||||
if( isEnabled )
|
||||
start_timer( s );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
tr_sharedShuttingDown( tr_shared * s )
|
||||
static void
|
||||
stop_timer( tr_shared * s )
|
||||
{
|
||||
s->isShuttingDown = 1;
|
||||
if( s->timer != NULL )
|
||||
{
|
||||
evtimer_del( s->timer );
|
||||
tr_free( s->timer );
|
||||
s->timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_forwarding( tr_shared * s )
|
||||
{
|
||||
tr_ninf( getKey( ), _( "Stopped" ) );
|
||||
natPulse( s, FALSE );
|
||||
tr_natpmpClose( s->natpmp );
|
||||
tr_upnpClose( s->upnp );
|
||||
stop_timer( s );
|
||||
}
|
||||
|
||||
void
|
||||
tr_sharedSetPort( tr_shared * s, tr_port port )
|
||||
tr_sharedClose( tr_session * session )
|
||||
{
|
||||
tr_torrent * tor = NULL;
|
||||
tr_shared * s = session->shared;
|
||||
|
||||
s->publicPort = port;
|
||||
s->shouldChange = TRUE;
|
||||
|
||||
while( ( tor = tr_torrentNext( s->session, tor ) ) )
|
||||
tr_torrentChangeMyPort( tor );
|
||||
}
|
||||
|
||||
tr_port
|
||||
tr_sharedGetPeerPort( const tr_shared * s )
|
||||
{
|
||||
return s->publicPort;
|
||||
s->isShuttingDown = TRUE;
|
||||
stop_forwarding( s );
|
||||
s->session->shared = NULL;
|
||||
tr_free( s );
|
||||
}
|
||||
|
||||
void
|
||||
tr_sharedTraversalEnable( tr_shared * s, tr_bool isEnabled )
|
||||
{
|
||||
s->isEnabled = isEnabled;
|
||||
if(( s->isEnabled = isEnabled ))
|
||||
start_timer( s );
|
||||
else
|
||||
stop_forwarding( s );
|
||||
}
|
||||
|
||||
void
|
||||
tr_sharedPortChanged( tr_session * session )
|
||||
{
|
||||
tr_shared * s = session->shared;
|
||||
|
||||
if( s->isEnabled )
|
||||
{
|
||||
stop_timer( s );
|
||||
start_timer( s );
|
||||
}
|
||||
}
|
||||
|
||||
tr_bool
|
||||
|
@ -296,9 +215,3 @@ tr_sharedTraversalStatus( const tr_shared * s )
|
|||
{
|
||||
return MAX( s->natpmpStatus, s->upnpStatus );
|
||||
}
|
||||
|
||||
const tr_socketList *
|
||||
tr_sharedGetBindSockets( const tr_shared * shared )
|
||||
{
|
||||
return shared->bindSockets;
|
||||
}
|
||||
|
|
|
@ -32,14 +32,15 @@
|
|||
#include "transmission.h"
|
||||
#include "net.h"
|
||||
|
||||
struct tr_bindsockets;
|
||||
|
||||
typedef struct tr_shared tr_shared;
|
||||
|
||||
tr_shared* tr_sharedInit( tr_session*, tr_bool isEnabled, tr_port publicPort,
|
||||
tr_socketList * socks);
|
||||
tr_shared* tr_sharedInit( tr_session*, tr_bool isEnabled );
|
||||
|
||||
void tr_sharedShuttingDown( tr_shared * );
|
||||
void tr_sharedClose( tr_session * );
|
||||
|
||||
void tr_sharedSetPort( tr_shared *, tr_port publicPort );
|
||||
void tr_sharedPortChanged( tr_session * );
|
||||
|
||||
void tr_sharedTraversalEnable( tr_shared *, tr_bool isEnabled );
|
||||
|
||||
|
@ -49,5 +50,4 @@ tr_bool tr_sharedTraversalIsEnabled( const tr_shared * s );
|
|||
|
||||
int tr_sharedTraversalStatus( const tr_shared * );
|
||||
|
||||
const tr_socketList *tr_sharedGetBindSockets( const tr_shared * shared );
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "list.h"
|
||||
#include "metainfo.h" /* tr_metainfoFree */
|
||||
#include "net.h"
|
||||
#include "peer-io.h"
|
||||
#include "peer-mgr.h"
|
||||
#include "platform.h" /* tr_lock */
|
||||
#include "port-forwarding.h"
|
||||
|
@ -125,9 +126,100 @@ tr_sessionSetEncryption( tr_session * session,
|
|||
****
|
||||
***/
|
||||
|
||||
struct tr_bindinfo
|
||||
{
|
||||
int socket;
|
||||
tr_address addr;
|
||||
struct event ev;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
close_bindinfo( struct tr_bindinfo * b )
|
||||
{
|
||||
if( b->socket >=0 )
|
||||
{
|
||||
event_del( &b->ev );
|
||||
EVUTIL_CLOSESOCKET( b->socket );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
close_incoming_peer_port( tr_session * session )
|
||||
{
|
||||
close_bindinfo( session->public_ipv4 );
|
||||
close_bindinfo( session->public_ipv6 );
|
||||
}
|
||||
|
||||
static void
|
||||
free_incoming_peer_port( tr_session * session )
|
||||
{
|
||||
close_bindinfo( session->public_ipv4 );
|
||||
tr_free( session->public_ipv4 );
|
||||
session->public_ipv4 = NULL;
|
||||
|
||||
close_bindinfo( session->public_ipv6 );
|
||||
tr_free( session->public_ipv6 );
|
||||
session->public_ipv6 = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
accept_incoming_peer( int fd, short what UNUSED, void * vsession )
|
||||
{
|
||||
int clientSocket;
|
||||
tr_port clientPort;
|
||||
tr_address clientAddr;
|
||||
tr_session * session = vsession;
|
||||
|
||||
clientSocket = tr_netAccept( session, fd, &clientAddr, &clientPort );
|
||||
if( clientSocket > 0 ) {
|
||||
tr_deepLog( __FILE__, __LINE__, NULL, "new incoming connection %d (%s)",
|
||||
clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
|
||||
tr_peerMgrAddIncoming( session->peerMgr, &clientAddr, clientPort, clientSocket );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
open_incoming_peer_port( tr_session * session )
|
||||
{
|
||||
struct tr_bindinfo * b;
|
||||
|
||||
/* bind an ipv4 port to listen for incoming peers... */
|
||||
b = session->public_ipv4;
|
||||
b->socket = tr_netBindTCP( &b->addr, session->peerPort, FALSE );
|
||||
if( b->socket >= 0 ) {
|
||||
event_set( &b->ev, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
|
||||
event_add( &b->ev, NULL );
|
||||
}
|
||||
|
||||
/* and do the exact same thing for ipv6, if it's supported... */
|
||||
if( tr_net_hasIPv6( session->peerPort ) ) {
|
||||
b = session->public_ipv6;
|
||||
b->socket = tr_netBindTCP( &b->addr, session->peerPort, FALSE );
|
||||
if( b->socket >= 0 ) {
|
||||
event_set( &b->ev, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
|
||||
event_add( &b->ev, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tr_address*
|
||||
tr_sessionGetPublicAddress( const tr_session * session, int tr_af_type )
|
||||
{
|
||||
switch( tr_af_type )
|
||||
{
|
||||
case TR_AF_INET: return &session->public_ipv4->addr;
|
||||
case TR_AF_INET6: return &session->public_ipv6->addr; break;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static int
|
||||
tr_stringEndsWith( const char * str,
|
||||
const char * end )
|
||||
tr_stringEndsWith( const char * str, const char * end )
|
||||
{
|
||||
const size_t slen = strlen( str );
|
||||
const size_t elen = strlen( end );
|
||||
|
@ -303,14 +395,9 @@ tr_sessionGetDefaultSettings( tr_benc * d )
|
|||
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 )
|
||||
{
|
||||
const char * val;
|
||||
const tr_address * addr;
|
||||
|
||||
assert( tr_bencIsDict( d ) );
|
||||
|
||||
tr_bencDictReserve( d, 30 );
|
||||
|
@ -359,14 +446,8 @@ 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 );
|
||||
|
||||
addr = tr_socketListGetType( tr_getSessionBindSockets( s ), TR_AF_INET );
|
||||
val = addr ? tr_ntop_non_ts( addr ) : TR_DEFAULT_BIND_ADDRESS_IPV4;
|
||||
tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, val );
|
||||
|
||||
addr = tr_socketListGetType( tr_getSessionBindSockets( s ), TR_AF_INET6 );
|
||||
val = addr ? tr_ntop_non_ts( addr ) : TR_DEFAULT_BIND_ADDRESS_IPV6;
|
||||
tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, val );
|
||||
tr_bencDictAddStr ( d, TR_DEFAULT_BIND_ADDRESS_IPV4, tr_ntop_non_ts( &s->public_ipv4->addr ) );
|
||||
tr_bencDictAddStr ( d, TR_DEFAULT_BIND_ADDRESS_IPV6, tr_ntop_non_ts( &s->public_ipv6->addr ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -512,8 +593,6 @@ 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 ) );
|
||||
|
@ -633,39 +712,30 @@ tr_sessionInitImpl( void * vdata )
|
|||
assert( found );
|
||||
session->peerPort = session->isPortRandom ? getRandomPort( session ) : j;
|
||||
|
||||
/* bind addresses */
|
||||
/* public 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 );
|
||||
{
|
||||
struct tr_bindinfo b;
|
||||
const char * str;
|
||||
|
||||
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;
|
||||
str = TR_PREFS_KEY_BIND_ADDRESS_IPV4;
|
||||
tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, &str );
|
||||
if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET ) )
|
||||
b.addr = tr_inaddr_any;
|
||||
b.socket = -1;
|
||||
session->public_ipv4 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
|
||||
|
||||
str = TR_PREFS_KEY_BIND_ADDRESS_IPV6;
|
||||
tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, &str );
|
||||
if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET6 ) )
|
||||
b.addr = tr_in6addr_any;
|
||||
b.socket = -1;
|
||||
session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
|
||||
|
||||
open_incoming_peer_port( session );
|
||||
}
|
||||
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;
|
||||
session->shared = tr_sharedInit( session, boolVal );
|
||||
|
||||
/**
|
||||
**/
|
||||
|
@ -818,36 +888,19 @@ tr_globalIsLocked( const tr_session * session )
|
|||
*
|
||||
**********************************************************************/
|
||||
|
||||
struct bind_port_data
|
||||
{
|
||||
tr_session * session;
|
||||
tr_port port;
|
||||
};
|
||||
|
||||
static void
|
||||
tr_setBindPortImpl( void * vdata )
|
||||
setPeerPort( void * session )
|
||||
{
|
||||
struct bind_port_data * data = vdata;
|
||||
tr_session * session = data->session;
|
||||
const tr_port port = data->port;
|
||||
|
||||
session->isPortSet = 1;
|
||||
tr_sharedSetPort( session->shared, port );
|
||||
|
||||
tr_free( data );
|
||||
}
|
||||
|
||||
static void
|
||||
setPortImpl( tr_session * session, tr_port port )
|
||||
{
|
||||
struct bind_port_data * data;
|
||||
tr_torrent * tor = NULL;
|
||||
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
data = tr_new( struct bind_port_data, 1 );
|
||||
data->session = session;
|
||||
data->port = port;
|
||||
tr_runInEventThread( session, tr_setBindPortImpl, data );
|
||||
close_incoming_peer_port( session );
|
||||
open_incoming_peer_port( session );
|
||||
tr_sharedPortChanged( session );
|
||||
|
||||
while(( tor = tr_torrentNext( session, tor )))
|
||||
tr_torrentChangeMyPort( tor );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -857,7 +910,8 @@ tr_sessionSetPeerPort( tr_session * session,
|
|||
assert( tr_isSession( session ) );
|
||||
|
||||
session->peerPort = port;
|
||||
setPortImpl( session, session->peerPort );
|
||||
|
||||
tr_runInEventThread( session, setPeerPort, session );
|
||||
}
|
||||
|
||||
tr_port
|
||||
|
@ -873,8 +927,7 @@ tr_sessionSetPeerPortRandom( tr_session * session )
|
|||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
session->peerPort = getRandomPort( session );
|
||||
setPortImpl( session, session->peerPort );
|
||||
tr_sessionSetPeerPort( session, getRandomPort( session ) );
|
||||
return session->peerPort;
|
||||
}
|
||||
|
||||
|
@ -1348,13 +1401,15 @@ tr_closeAllConnections( void * vsession )
|
|||
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
free_incoming_peer_port( session );
|
||||
|
||||
evtimer_del( session->altTimer );
|
||||
tr_free( session->altTimer );
|
||||
session->altTimer = NULL;
|
||||
|
||||
tr_verifyClose( session );
|
||||
tr_statsClose( session );
|
||||
tr_sharedShuttingDown( session->shared );
|
||||
tr_sharedClose( session );
|
||||
tr_rpcClose( &session->rpcServer );
|
||||
|
||||
/* close the torrents. get the most active ones first so that
|
||||
|
@ -2093,9 +2148,3 @@ tr_sessionGetActiveTorrentCount( tr_session * session )
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const tr_socketList *
|
||||
tr_getSessionBindSockets( const tr_session * session )
|
||||
{
|
||||
return tr_sharedGetBindSockets( session->shared );
|
||||
}
|
||||
|
|
|
@ -55,10 +55,10 @@ struct tr_metainfo_lookup
|
|||
|
||||
struct tr_address;
|
||||
struct tr_bandwidth;
|
||||
struct tr_bindsockets;
|
||||
|
||||
struct tr_session
|
||||
{
|
||||
tr_bool isPortSet;
|
||||
tr_bool isPortRandom;
|
||||
tr_bool isPexEnabled;
|
||||
tr_bool isBlocklistEnabled;
|
||||
|
@ -151,6 +151,9 @@ struct tr_session
|
|||
struct tr_bandwidth * bandwidth;
|
||||
|
||||
double desiredRatio;
|
||||
|
||||
struct tr_bindinfo * public_ipv4;
|
||||
struct tr_bindinfo * public_ipv6;
|
||||
};
|
||||
|
||||
tr_bool tr_sessionGetActiveSpeedLimit( const tr_session * session,
|
||||
|
@ -173,6 +176,10 @@ void tr_globalUnlock( tr_session * );
|
|||
|
||||
tr_bool tr_globalIsLocked( const tr_session * );
|
||||
|
||||
const struct tr_address* tr_sessionGetPublicAddress( const tr_session *, int tr_af_type );
|
||||
|
||||
struct tr_bindsockets * tr_sessionGetBindSockets( tr_session * );
|
||||
|
||||
enum
|
||||
{
|
||||
SESSION_MAGIC_NUMBER = 3845
|
||||
|
|
|
@ -596,7 +596,6 @@ torrentRealInit( tr_torrent * tor, const tr_ctor * ctor )
|
|||
|
||||
tr_peerMgrAddTorrent( session->peerMgr, tor );
|
||||
|
||||
assert( session->isPortSet );
|
||||
assert( !tor->downloadedCur );
|
||||
assert( !tor->uploadedCur );
|
||||
|
||||
|
|
Loading…
Reference in New Issue