Changeset 8398


Ignore:
Timestamp:
May 14, 2009, 1:42:29 PM (12 years ago)
Author:
charles
Message:

(trunk libT) #2035: Transmission causes wakeups by unnecessary polling.

Location:
trunk/libtransmission
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/net.c

    r8391 r8398  
    3939 #include <fcntl.h>
    4040#endif
     41#include <unistd.h>
    4142
    4243#include <evutil.h>
     
    4849#include "peer-io.h"
    4950#include "platform.h"
     51#include "session.h"
    5052#include "utils.h"
    5153
     
    5557
    5658const tr_address tr_in6addr_any = { TR_AF_INET6, { IN6ADDR_ANY_INIT } };
    57 const tr_address tr_inaddr_any = { TR_AF_INET,
    58     { { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } };
     59const tr_address tr_inaddr_any = { TR_AF_INET, { { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } };
    5960
    6061#ifdef WIN32
    6162static const char *
    62 inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
     63inet_ntop( int af, const void *src, char *dst, socklen_t cnt )
    6364{
    6465    if (af == AF_INET)
    6566    {
    6667        struct sockaddr_in in;
    67         memset(&in, 0, sizeof(in));
     68        memset( &in, 0, sizeof( in ) );
    6869        in.sin_family = AF_INET;
    69         memcpy(&in.sin_addr, src, sizeof(struct in_addr));
    70         getnameinfo((struct sockaddr *)&in, sizeof(struct
    71             sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
     70        memcpy( &in.sin_addr, src, sizeof( struct in_addr ) );
     71        getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in),
     72                    dst, cnt, NULL, 0, NI_NUMERICHOST);
    7273        return dst;
    7374    }
     
    7576    {
    7677        struct sockaddr_in6 in;
    77         memset(&in, 0, sizeof(in));
     78        memset( &in, 0, sizeof( in ) );
    7879        in.sin6_family = AF_INET6;
    79         memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
    80         getnameinfo((struct sockaddr *)&in, sizeof(struct
    81             sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
     80        memcpy( &in.sin6_addr, src, sizeof( struct in_addr6 ) );
     81        getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6),
     82                    dst, cnt, NULL, 0, NI_NUMERICHOST);
    8283        return dst;
    8384    }
     
    197198tr_net_hasIPv6( tr_port port )
    198199{
     200    static tr_bool result = FALSE;
    199201    static tr_bool alreadyDone = FALSE;
    200     static tr_bool result      = FALSE;
    201     int s;
    202     if( alreadyDone )
    203         return result;
    204     s = tr_netBindTCP( &tr_in6addr_any, port, TRUE );
    205     if( s >= 0 || -s != EAFNOSUPPORT ) /* we support ipv6 */
    206     {
    207         result = TRUE;
    208         tr_netClose( s );
    209     }
    210     alreadyDone = TRUE;
     202
     203    if( !alreadyDone )
     204    {
     205        int fd = tr_netBindTCP( &tr_in6addr_any, port, TRUE );
     206        if( fd >= 0 || -fd != EAFNOSUPPORT ) /* we support ipv6 */
     207            result = TRUE;
     208        if( fd >= 0 )
     209            EVUTIL_CLOSESOCKET( fd );
     210        alreadyDone = TRUE;
     211    }
     212
    211213    return result;
    212 }
    213 
    214 /***********************************************************************
    215  * Socket list housekeeping
    216  **********************************************************************/
    217 struct tr_socketList
    218 {
    219     int             socket;
    220     tr_address      addr;
    221     tr_socketList * next;
    222 };
    223 
    224 tr_socketList *
    225 tr_socketListAppend( tr_socketList * const head,
    226                      const tr_address * const addr )
    227 {
    228     tr_socketList * tmp;
    229 
    230     assert( head );
    231     assert( tr_isAddress( addr ) );
    232 
    233     for( tmp = head; tmp->next; tmp = tmp->next );
    234     tmp->next = tr_socketListNew( addr );
    235     return tmp->next;
    236 }
    237 
    238 tr_socketList *
    239 tr_socketListNew( const tr_address * const addr )
    240 {
    241     tr_socketList * tmp;
    242 
    243     assert( tr_isAddress( addr ) );
    244 
    245     tmp = tr_new( tr_socketList, 1 );
    246     tmp->socket = -1;
    247     tmp->addr = *addr;
    248     tmp->next = NULL;
    249     return tmp;
    250 }
    251 
    252 void
    253 tr_socketListFree( tr_socketList * const head )
    254 {
    255     assert( head );
    256 
    257     if( head->next )
    258         tr_socketListFree( head->next );
    259     tr_free( head );
    260 }
    261 
    262 void
    263 tr_socketListRemove( tr_socketList * const head,
    264                      tr_socketList * const el)
    265 {
    266     tr_socketList * tmp;
    267 
    268     assert( head );
    269     assert( el );
    270 
    271     for( tmp = head; tmp->next && tmp->next != el; tmp = tmp->next );
    272     tmp->next = el->next;
    273     el->next = NULL;
    274     tr_socketListFree(el);
    275 }
    276 
    277 void
    278 tr_socketListTruncate( tr_socketList * const head,
    279                        tr_socketList * const start )
    280 {
    281     tr_socketList * tmp;
    282 
    283     assert( head );
    284     assert( start );
    285 
    286     for( tmp = head; tmp->next && tmp->next != start; tmp = tmp->next );
    287     tr_socketListFree( start );
    288     tmp->next = NULL;
    289 }
    290 
    291 #if 0
    292 int
    293 tr_socketListGetSocket( const tr_socketList * const el )
    294 {
    295     assert( el );
    296 
    297     return el->socket;
    298 }
    299 
    300 const tr_address *
    301 tr_socketListGetAddress( const tr_socketList * const el )
    302 {
    303     assert( el );
    304     return &el->addr;
    305 }
    306 #endif
    307 
    308 void
    309 tr_socketListForEach( tr_socketList * const head,
    310                       void ( * cb ) ( int * const,
    311                                       tr_address * const,
    312                                       void * const),
    313                       void * const userData )
    314 {
    315     tr_socketList * tmp;
    316     for( tmp = head; tmp; tmp = tmp->next )
    317         cb( &tmp->socket, &tmp->addr, userData );
    318 }
    319 
    320 const tr_address *
    321 tr_socketListGetType( const tr_socketList * const el, tr_address_type type )
    322 {
    323     const tr_socketList * tmp = el;
    324     while( tmp )
    325     {
    326         if( tmp->addr.type == type )
    327             return &tmp->addr;
    328         tmp = tmp->next;
    329     }
    330     return NULL;
    331214}
    332215
     
    345228}
    346229
    347 static int
    348 makeSocketNonBlocking( int fd )
    349 {
    350     if( fd >= 0 )
    351     {
    352         if( evutil_make_socket_nonblocking( fd ) )
    353         {
    354             int tmperrno;
    355             tr_err( _( "Couldn't create socket: %s" ),
    356                    tr_strerror( sockerrno ) );
    357             tmperrno = sockerrno;
    358             tr_netClose( fd );
    359             fd = -tmperrno;
    360         }
    361     }
    362 
    363     return fd;
    364 }
    365 
    366 static int
    367 createSocket( int domain, int type )
    368 {
    369     return makeSocketNonBlocking( tr_fdSocketCreate( domain, type ) );
    370 }
    371 
    372 static void
    373 setSndBuf( tr_session * session UNUSED, int fd UNUSED )
    374 {
    375 #if 0
    376     if( fd >= 0 )
    377     {
    378         const int sndbuf = session->so_sndbuf;
    379         const int rcvbuf = session->so_rcvbuf;
    380         setsockopt( fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof( sndbuf ) );
    381         setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof( rcvbuf ) );
    382     }
    383 #endif
    384 }
    385 
    386230static socklen_t
    387231setup_sockaddr( const tr_address        * addr,
     
    389233                struct sockaddr_storage * sockaddr)
    390234{
    391     struct sockaddr_in  sock4;
    392     struct sockaddr_in6 sock6;
    393 
    394235    assert( tr_isAddress( addr ) );
    395236
    396237    if( addr->type == TR_AF_INET )
    397238    {
     239        struct sockaddr_in  sock4;
    398240        memset( &sock4, 0, sizeof( sock4 ) );
    399241        sock4.sin_family      = AF_INET;
     
    405247    else
    406248    {
     249        struct sockaddr_in6 sock6;
    407250        memset( &sock6, 0, sizeof( sock6 ) );
    408         sock6.sin6_family = AF_INET6;
    409         sock6.sin6_port = port;
     251        sock6.sin6_family   = AF_INET6;
     252        sock6.sin6_port     = port;
    410253        sock6.sin6_flowinfo = 0;
    411         sock6.sin6_addr = addr->addr.addr6;
     254        sock6.sin6_addr     = addr->addr.addr6;
    412255        memcpy( sockaddr, &sock6, sizeof( sock6 ) );
    413256        return sizeof( struct sockaddr_in6 );
     
    461304}
    462305
    463 const tr_socketList * tr_getSessionBindSockets( const tr_session * session );
    464 
    465306int
    466307tr_netOpenTCP( tr_session        * session,
     
    468309               tr_port             port )
    469310{
     311    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
    470312    int                     s;
    471313    struct sockaddr_storage sock;
    472     const int               type = SOCK_STREAM;
    473314    socklen_t               addrlen;
    474315    const tr_address      * source_addr;
     
    481322        return -EINVAL;
    482323
    483     if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ), type ) ) < 0 )
    484         return s;
    485 
    486     setSndBuf( session, s );
     324    s = tr_fdSocketCreate( domains[addr->type], SOCK_STREAM );
     325    if( s < 0 )
     326        return -1;
     327
     328    if( evutil_make_socket_nonblocking( s ) < 0 ) {
     329        EVUTIL_CLOSESOCKET( s );
     330        return -1;
     331    }
    487332
    488333    addrlen = setup_sockaddr( addr, port, &sock );
    489334   
    490335    /* set source address */
    491     source_addr = tr_socketListGetType( tr_getSessionBindSockets( session ),
    492                                         addr->type );
     336    source_addr = tr_sessionGetPublicAddress( session, addr->type );
    493337    assert( source_addr );
    494338    sourcelen = setup_sockaddr( source_addr, 0, &source_sock );
     
    527371tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
    528372{
    529     int                     s;
     373    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
    530374    struct sockaddr_storage sock;
    531     const int               type = SOCK_STREAM;
    532     int                     addrlen;
    533 
    534 #if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT ) || defined( IPV6_V6ONLY )
    535     int                optval = 1;
    536 #endif
     375    int fd;
     376    int addrlen;
     377    int optval;
    537378
    538379    assert( tr_isAddress( addr ) );
    539380
    540     if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
    541                             type ) ) < 0 )
    542         return s;
    543 
    544 #ifdef SO_REUSEADDR
    545     setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
    546 #endif
     381    fd = socket( domains[addr->type], SOCK_STREAM, 0 );
     382    if( fd < 0 )
     383        return -1;
     384
     385    if( evutil_make_socket_nonblocking( fd ) < 0 ) {
     386        EVUTIL_CLOSESOCKET( fd );
     387        return -1;
     388    }
     389
     390    optval = 1;
     391    setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) );
     392    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
    547393
    548394#ifdef IPV6_V6ONLY
    549     if( addr->type == TR_AF_INET6 &&
    550         setsockopt( s, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
    551                              sizeof( optval ) ) == -1 ) {
    552         /* the kernel may not support this. if not, ignore it */
    553         if( errno != ENOPROTOOPT )
    554             return -errno;
    555     }
     395    if( addr->type == TR_AF_INET6 )
     396        if( setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof( optval ) ) == -1 )
     397            if( EVUTIL_SOCKET_ERROR( ) != ENOPROTOOPT ) /* if the kernel doesn't support it, ignore it */
     398                return -EVUTIL_SOCKET_ERROR( );
    556399#endif
    557400
    558401    addrlen = setup_sockaddr( addr, htons( port ), &sock );
    559 
    560     if( bind( s, (struct sockaddr *) &sock,
    561              addrlen ) )
    562     {
    563         int tmperrno;
     402    if( bind( fd, (struct sockaddr *) &sock, addrlen ) ) {
     403        const int err = EVUTIL_SOCKET_ERROR( );
    564404        if( !suppressMsgs )
    565             tr_err( _( "Couldn't bind port %d on %s: %s" ), port,
    566                     tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) );
    567         tmperrno = sockerrno;
    568         tr_netClose( s );
    569         return -tmperrno;
    570     }
     405            tr_err( _( "Couldn't bind port %d on %s: %s" ),
     406                    port, tr_ntop_non_ts( addr ), tr_strerror( err ) );
     407        tr_netClose( fd );
     408        return -err;
     409    }
     410
    571411    if( !suppressMsgs )
    572         tr_dbg(  "Bound socket %d to port %d on %s",
    573                  s, port, tr_ntop_non_ts( addr ) );
    574     return s;
     412        tr_dbg( "Bound socket %d to port %d on %s", fd, port, tr_ntop_non_ts( addr ) );
     413
     414    if( listen( fd, 128 ) == -1 ) {
     415        EVUTIL_CLOSESOCKET( fd );
     416        return -EVUTIL_SOCKET_ERROR( );
     417    }
     418
     419    return fd;
    575420}
    576421
    577422int
    578 tr_netAccept( tr_session  * session,
     423tr_netAccept( tr_session  * session UNUSED,
    579424              int           b,
    580425              tr_address  * addr,
    581426              tr_port     * port )
    582427{
    583     int fd;
    584 
    585     fd = makeSocketNonBlocking( tr_fdSocketAccept( b, addr, port ) );
    586     setSndBuf( session, fd );
     428    int fd = tr_fdSocketAccept( b, addr, port );
     429
     430    if( fd>=0 && evutil_make_socket_nonblocking(fd)<0 ) {
     431        EVUTIL_CLOSESOCKET( fd );
     432        fd = -1;
     433    }
     434
    587435    return fd;
    588436}
  • trunk/libtransmission/net.h

    r8242 r8398  
    6262{
    6363    TR_AF_INET,
    64     TR_AF_INET6
    65 } tr_address_type;
     64    TR_AF_INET6,
     65    NUM_TR_AF_INET_TYPES
     66}
     67tr_address_type;
    6668
    6769typedef struct tr_address
     
    9597
    9698/***********************************************************************
    97  * Socket list housekeeping
    98  **********************************************************************/
    99 typedef struct tr_socketList tr_socketList;
    100 tr_socketList *tr_socketListAppend( tr_socketList * const head,
    101                                     const tr_address * const addr );
    102 tr_socketList *tr_socketListNew( const tr_address * const addr );
    103 void tr_socketListFree( tr_socketList * const head );
    104 void tr_socketListRemove( tr_socketList * const head,
    105                           tr_socketList * const el);
    106 void tr_socketListTruncate( tr_socketList * const head,
    107                             tr_socketList * const start );
    108 int tr_socketListGetSocket( const tr_socketList * const el );
    109 const tr_address *tr_socketListGetAddress( const tr_socketList * const el );
    110 void tr_socketListForEach( tr_socketList * const head,
    111                            void ( * cb ) ( int * const,
    112                                            tr_address * const,
    113                                            void * const ),
    114                            void * const userData);
    115 const tr_address *tr_socketListGetType( const tr_socketList * const el,
    116                                         tr_address_type type );
    117 
    118 /***********************************************************************
    11999 * Sockets
    120100 **********************************************************************/
  • trunk/libtransmission/port-forwarding.c

    r8271 r8398  
    3636    tr_bool               isEnabled;
    3737    tr_bool               isShuttingDown;
     38    tr_bool               doPortCheck;
    3839
    3940    tr_port_forwarding    natpmpStatus;
    4041    tr_port_forwarding    upnpStatus;
    41 
    42     tr_bool               shouldChange;
    43     tr_socketList       * bindSockets;
    44     tr_port               publicPort;
    45 
    46     tr_timer            * pulseTimer;
    47     tr_timer            * recheckTimer;
    4842
    4943    tr_upnp             * upnp;
    5044    tr_natpmp           * natpmp;
    5145    tr_session          * session;
     46
     47    struct event        * timer;
    5248};
    5349
     
    6157    switch( state )
    6258    {
    63         /* we're in the process of trying to set up port forwarding */
    64         case TR_PORT_MAPPING:
    65             return _( "Starting" );
    66 
    67         /* we've successfully forwarded the port */
    68         case TR_PORT_MAPPED:
    69             return _( "Forwarded" );
    70 
    71         /* we're cancelling the port forwarding */
    72         case TR_PORT_UNMAPPING:
    73             return _( "Stopping" );
    74 
    75         /* the port isn't forwarded */
    76         case TR_PORT_UNMAPPED:
    77             return _( "Not forwarded" );
    78 
    79         case TR_PORT_ERROR:
    80             return "???";
    81     }
    82 
    83     return "notfound";
     59        case TR_PORT_MAPPING:   return _( "Starting" );
     60        case TR_PORT_MAPPED:    return _( "Forwarded" );
     61        case TR_PORT_UNMAPPING: return _( "Stopping" );
     62        case TR_PORT_UNMAPPED:  return _( "Not forwarded" );
     63        default:                return "???";
     64    }
    8465}
    8566
     
    8768natPulse( tr_shared * s, tr_bool doPortCheck )
    8869{
    89     const tr_port port = s->publicPort;
    90     const int     isEnabled = s->isEnabled && !s->isShuttingDown;
    91     int           oldStatus;
    92     int           newStatus;
     70    const tr_port port = s->session->peerPort;
     71    const int isEnabled = s->isEnabled && !s->isShuttingDown;
     72    int oldStatus;
     73    int newStatus;
    9374
    9475    oldStatus = tr_sharedTraversalStatus( s );
     
    10384}
    10485
    105 /*
    106  * Callbacks for socket list
    107  */
    108 static void
    109 closeCb( int * const socket,
    110          tr_address * const addr,
    111          void * const userData )
    112 {
    113     tr_shared * s = ( tr_shared * )userData;
    114     if( *socket >= 0 )
    115     {
    116         tr_ninf( getKey( ), _( "Closing port %d on %s" ), s->publicPort,
    117                 tr_ntop_non_ts( addr ) );
    118         tr_netClose( *socket );
    119     }
    120 }
    121 
    122 static void
    123 acceptCb( int        * const socket,
    124           tr_address * const addr UNUSED,
    125           void       * const userData )
    126 {
    127     tr_shared * s = ( tr_shared * )userData;
    128     tr_address clientAddr;
    129     tr_port clientPort;
    130     int clientSocket;
    131     clientSocket = tr_netAccept( s->session, *socket, &clientAddr, &clientPort );
    132     if( clientSocket > 0 )
    133     {
    134         tr_deepLog( __FILE__, __LINE__, NULL,
    135                    "New INCOMING connection %d (%s)",
    136                    clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
    137        
    138         tr_peerMgrAddIncoming( s->session->peerMgr, &clientAddr, clientPort,
    139                               clientSocket );
    140     }
    141 }
    142 
    143 static void
    144 bindCb( int * const socket,
    145         tr_address * const addr,
    146         void * const userData )
    147 {
    148     tr_shared * s = ( tr_shared * )userData;
    149     *socket = tr_netBindTCP( addr, s->publicPort, FALSE );
    150     if( *socket >= 0 )
    151     {
    152         tr_ninf( getKey( ),
    153                 _( "Opened port %d on %s to listen for incoming peer connections" ),
    154                 s->publicPort, tr_ntop_non_ts( addr ) );
    155         listen( *socket, 10 );
    156     }
    157     else
    158     {
    159         tr_nerr( getKey( ),
    160                 _(
    161                   "Couldn't open port %d on %s to listen for incoming peer connections (errno %d - %s)" ),
    162                 s->publicPort, tr_ntop_non_ts( addr ), errno, tr_strerror( errno ) );
    163     }
    164 }
    165 
    166 static void
    167 incomingPeersPulse( tr_shared * s )
    168 {
    169     if( s->shouldChange )
    170     {
    171         tr_socketListForEach( s->bindSockets, &closeCb, s );
    172         s->shouldChange = FALSE;
    173         if( s->publicPort > 0 )
    174             tr_socketListForEach( s->bindSockets, &bindCb, s );
    175     }
    176    
    177     /* (jhujhiti):
    178      * This has been changed from a loop that will end when the listener queue
    179      * is exhausted to one that will only check for one connection at a time.
    180      * I think it unlikely that we get many more than one connection in the
    181      * time between pulses (currently one second). However, just to be safe,
    182      * I have increased the length of the listener queue from 5 to 10
    183      * (see acceptCb() above). */
    184     tr_socketListForEach( s->bindSockets, &acceptCb, s );
    185 }
    186 
    187 static int
    188 sharedPulse( void * vshared )
    189 {
    190     tr_bool keepPulsing = TRUE;
    191     tr_shared * shared = vshared;
    192 
    193     natPulse( shared, FALSE );
    194 
    195     if( !shared->isShuttingDown )
    196     {
    197         incomingPeersPulse( shared );
    198     }
    199     else
    200     {
    201         tr_ninf( getKey( ), _( "Stopped" ) );
    202         tr_timerFree( &shared->pulseTimer );
    203         tr_timerFree( &shared->recheckTimer );
    204         tr_socketListForEach( shared->bindSockets, &closeCb, shared );
    205         tr_socketListFree( shared->bindSockets );
    206         tr_natpmpClose( shared->natpmp );
    207         tr_upnpClose( shared->upnp );
    208         shared->session->shared = NULL;
    209         tr_free( shared );
    210         keepPulsing = FALSE;
    211     }
    212 
    213     return keepPulsing;
    214 }
    215 
    216 static int
    217 recheckPulse( void * vshared )
    218 {
    219     tr_bool keepPulsing = TRUE;
    220     tr_shared * shared = vshared;
    221 
    222     tr_ninf( getKey( ), _( "Checking to see if port %d is still open" ), shared->publicPort );
    223     natPulse( shared, TRUE );
    224 
    225     if( shared->isShuttingDown )
    226         keepPulsing = FALSE;
    227 
    228     return keepPulsing;
     86static void
     87onTimer( int fd UNUSED, short what UNUSED, void * vshared )
     88{
     89    tr_shared * s = vshared;
     90    struct timeval interval;
     91
     92    assert( s );
     93    assert( s->timer );
     94
     95    /* do something */
     96    natPulse( s, s->doPortCheck );
     97    s->doPortCheck = FALSE;
     98
     99    /* when to wake up again */
     100    switch( tr_sharedTraversalStatus( s ) )
     101    {
     102        case TR_PORT_MAPPED:
     103            /* if we're mapped, everything is fine... check back in 20 minutes
     104             * to renew the port forwarding if it's expired */
     105            s->doPortCheck = TRUE;
     106            interval.tv_sec = 60*20;
     107            break;
     108
     109        case TR_PORT_ERROR:
     110            /* some kind of an error.  wait 60 seconds and retry */
     111            interval.tv_sec = 60;
     112            break;
     113
     114        default:
     115            /* in progress.  pulse frequently. */
     116            interval.tv_sec = 0;
     117            interval.tv_usec = 333000;
     118            break;
     119    }
     120
     121    evtimer_add( s->timer, &interval );
    229122}
    230123
     
    233126***/
    234127
     128static void
     129start_timer( tr_shared * s )
     130{
     131    s->timer = tr_new0( struct event, 1 );
     132    evtimer_set( s->timer, onTimer, s );
     133    onTimer( 0, 0, s );
     134}
     135
    235136tr_shared *
    236 tr_sharedInit( tr_session  * session,
    237                tr_bool       isEnabled,
    238                tr_port       publicPort,
    239                tr_socketList * socks )
     137tr_sharedInit( tr_session  * session, tr_bool isEnabled )
    240138{
    241139    tr_shared * s = tr_new0( tr_shared, 1 );
    242140
    243141    s->session      = session;
    244     s->publicPort   = publicPort;
    245     s->bindSockets  = socks;
    246     s->shouldChange = TRUE;
    247142    s->natpmp       = tr_natpmpInit( );
    248143    s->upnp         = tr_upnpInit( );
    249     s->pulseTimer   = tr_timerNew( session, sharedPulse, s, 1000 );
    250     s->recheckTimer = tr_timerNew( session, recheckPulse, s, 1000*60*20 ); /* 20 minutes */
    251144    s->isEnabled    = isEnabled;
    252145    s->upnpStatus   = TR_PORT_UNMAPPED;
    253146    s->natpmpStatus = TR_PORT_UNMAPPED;
    254147
     148    if( isEnabled )
     149        start_timer( s );
     150
    255151    return s;
    256152}
    257153
     154static void
     155stop_timer( tr_shared * s )
     156{
     157    if( s->timer != NULL )
     158    {
     159        evtimer_del( s->timer );
     160        tr_free( s->timer );
     161        s->timer = NULL;
     162    }
     163}
     164
     165static void
     166stop_forwarding( tr_shared * s )
     167{
     168    tr_ninf( getKey( ), _( "Stopped" ) );
     169    natPulse( s, FALSE );
     170    tr_natpmpClose( s->natpmp );
     171    tr_upnpClose( s->upnp );
     172    stop_timer( s );
     173}
     174
    258175void
    259 tr_sharedShuttingDown( tr_shared * s )
    260 {
    261     s->isShuttingDown = 1;
    262 }
    263 
    264 void
    265 tr_sharedSetPort( tr_shared * s, tr_port  port )
    266 {
    267     tr_torrent * tor = NULL;
    268 
    269     s->publicPort   = port;
    270     s->shouldChange = TRUE;
    271 
    272     while( ( tor = tr_torrentNext( s->session, tor ) ) )
    273         tr_torrentChangeMyPort( tor );
    274 }
    275 
    276 tr_port
    277 tr_sharedGetPeerPort( const tr_shared * s )
    278 {
    279     return s->publicPort;
     176tr_sharedClose( tr_session * session )
     177{
     178    tr_shared * s = session->shared;
     179
     180    s->isShuttingDown = TRUE;
     181    stop_forwarding( s );
     182    s->session->shared = NULL;
     183    tr_free( s );
    280184}
    281185
     
    283187tr_sharedTraversalEnable( tr_shared * s, tr_bool isEnabled )
    284188{
    285     s->isEnabled = isEnabled;
     189    if(( s->isEnabled = isEnabled ))
     190        start_timer( s );
     191    else
     192        stop_forwarding( s );
     193}
     194
     195void
     196tr_sharedPortChanged( tr_session * session )
     197{
     198    tr_shared * s = session->shared;
     199
     200    if( s->isEnabled )
     201    {
     202        stop_timer( s );
     203        start_timer( s );
     204    }
    286205}
    287206
     
    297216    return MAX( s->natpmpStatus, s->upnpStatus );
    298217}
    299 
    300 const tr_socketList *
    301 tr_sharedGetBindSockets( const tr_shared * shared )
    302 {
    303     return shared->bindSockets;
    304 }
  • trunk/libtransmission/port-forwarding.h

    r8242 r8398  
    3333#include "net.h"
    3434
     35struct tr_bindsockets;
     36
    3537typedef struct tr_shared tr_shared;
    3638
    37 tr_shared* tr_sharedInit( tr_session*, tr_bool isEnabled, tr_port publicPort,
    38                           tr_socketList * socks);
     39tr_shared* tr_sharedInit( tr_session*, tr_bool isEnabled );
    3940
    40 void       tr_sharedShuttingDown( tr_shared * );
     41void       tr_sharedClose( tr_session * );
    4142
    42 void       tr_sharedSetPort( tr_shared *, tr_port publicPort );
     43void       tr_sharedPortChanged( tr_session * );
    4344
    4445void       tr_sharedTraversalEnable( tr_shared *, tr_bool isEnabled );
     
    5051int        tr_sharedTraversalStatus( const tr_shared * );
    5152
    52 const tr_socketList *tr_sharedGetBindSockets( const tr_shared * shared );
    5353#endif
  • trunk/libtransmission/session.c

    r8389 r8398  
    3333#include "metainfo.h" /* tr_metainfoFree */
    3434#include "net.h"
     35#include "peer-io.h"
    3536#include "peer-mgr.h"
    3637#include "platform.h" /* tr_lock */
     
    126127***/
    127128
     129struct tr_bindinfo
     130{
     131    int socket;
     132    tr_address addr;
     133    struct event ev;
     134};
     135
     136
     137static void
     138close_bindinfo( struct tr_bindinfo * b )
     139{
     140    if( b->socket >=0 )
     141    {
     142        event_del( &b->ev );
     143        EVUTIL_CLOSESOCKET( b->socket );
     144    }
     145}
     146
     147static void
     148close_incoming_peer_port( tr_session * session )
     149{
     150    close_bindinfo( session->public_ipv4 );
     151    close_bindinfo( session->public_ipv6 );
     152}
     153
     154static void
     155free_incoming_peer_port( tr_session * session )
     156{
     157    close_bindinfo( session->public_ipv4 );
     158    tr_free( session->public_ipv4 );
     159    session->public_ipv4 = NULL;
     160
     161    close_bindinfo( session->public_ipv6 );
     162    tr_free( session->public_ipv6 );
     163    session->public_ipv6 = NULL;
     164}
     165
     166static void
     167accept_incoming_peer( int fd, short what UNUSED, void * vsession )
     168{
     169    int clientSocket;
     170    tr_port clientPort;
     171    tr_address clientAddr;
     172    tr_session * session = vsession;
     173
     174    clientSocket = tr_netAccept( session, fd, &clientAddr, &clientPort );
     175    if( clientSocket > 0 ) {
     176        tr_deepLog( __FILE__, __LINE__, NULL, "new incoming connection %d (%s)",
     177                   clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
     178        tr_peerMgrAddIncoming( session->peerMgr, &clientAddr, clientPort, clientSocket );
     179    }
     180}
     181
     182static void
     183open_incoming_peer_port( tr_session * session )
     184{
     185    struct tr_bindinfo * b;
     186
     187    /* bind an ipv4 port to listen for incoming peers... */
     188    b = session->public_ipv4;
     189    b->socket = tr_netBindTCP( &b->addr, session->peerPort, FALSE );
     190    if( b->socket >= 0 ) {
     191        event_set( &b->ev, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
     192        event_add( &b->ev, NULL );
     193    }
     194
     195    /* and do the exact same thing for ipv6, if it's supported... */
     196    if( tr_net_hasIPv6( session->peerPort ) ) {
     197        b = session->public_ipv6;
     198        b->socket = tr_netBindTCP( &b->addr, session->peerPort, FALSE );
     199        if( b->socket >= 0 ) {
     200            event_set( &b->ev, b->socket, EV_READ | EV_PERSIST, accept_incoming_peer, session );
     201            event_add( &b->ev, NULL );
     202        }
     203    }
     204}
     205
     206const tr_address*
     207tr_sessionGetPublicAddress( const tr_session * session, int tr_af_type )
     208{
     209    switch( tr_af_type )
     210    {
     211        case TR_AF_INET: return &session->public_ipv4->addr;
     212        case TR_AF_INET6: return &session->public_ipv6->addr; break;
     213        default: return NULL;
     214    }
     215}
     216
     217/***
     218****
     219***/
     220
    128221static int
    129 tr_stringEndsWith( const char * str,
    130                    const char * end )
     222tr_stringEndsWith( const char * str, const char * end )
    131223{
    132224    const size_t slen = strlen( str );
     
    304396}
    305397
    306 const tr_socketList * tr_getSessionBindSockets( const tr_session * session );
    307 
    308398void
    309399tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
    310400{
    311     const char * val;
    312     const tr_address * addr;
    313 
    314401    assert( tr_bencIsDict( d ) );
    315402
     
    360447    tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED,           tr_sessionIsSpeedLimited( s, TR_UP ) );
    361448    tr_bencDictAddInt ( d, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, s->uploadSlotsPerTorrent );
    362 
    363     addr = tr_socketListGetType( tr_getSessionBindSockets( s ), TR_AF_INET );
    364     val = addr ? tr_ntop_non_ts( addr ) : TR_DEFAULT_BIND_ADDRESS_IPV4;
    365     tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4, val );
    366 
    367     addr = tr_socketListGetType( tr_getSessionBindSockets( s ), TR_AF_INET6 );
    368     val = addr ? tr_ntop_non_ts( addr ) : TR_DEFAULT_BIND_ADDRESS_IPV6;
    369     tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6, val );
     449    tr_bencDictAddStr ( d, TR_DEFAULT_BIND_ADDRESS_IPV4,          tr_ntop_non_ts( &s->public_ipv4->addr ) );
     450    tr_bencDictAddStr ( d, TR_DEFAULT_BIND_ADDRESS_IPV6,          tr_ntop_non_ts( &s->public_ipv6->addr ) );
    370451}
    371452
     
    513594    tr_benc * clientSettings = data->clientSettings;
    514595    tr_session * session = data->session;
    515     tr_address address;
    516     tr_socketList * socketList;
    517596
    518597    assert( tr_amInEventThread( session ) );
     
    634713    session->peerPort = session->isPortRandom ? getRandomPort( session ) : j;
    635714
    636     /* bind addresses */
    637 
    638     found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4,
    639                                 &str );
    640     assert( found );
    641     if( tr_pton( str, &address ) == NULL ) {
    642         tr_err( _( "%s is not a valid address" ), str );
    643         socketList = tr_socketListNew( &tr_inaddr_any );
    644     } else if( address.type != TR_AF_INET ) {
    645         tr_err( _( "%s is not an IPv4 address" ), str );
    646         socketList = tr_socketListNew( &tr_inaddr_any );
    647     } else
    648         socketList = tr_socketListNew( &address );
    649 
    650     found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6,
    651                                 &str );
    652     assert( found );
    653     if( tr_pton( str, &address ) == NULL ) {
    654         tr_err( _( "%s is not a valid address" ), str );
    655         address = tr_in6addr_any;
    656     } else if( address.type != TR_AF_INET6 ) {
    657         tr_err( _( "%s is not an IPv6 address" ), str );
    658         address = tr_in6addr_any;
    659     }
    660     if( tr_net_hasIPv6( session->peerPort ) )
    661         tr_socketListAppend( socketList, &address );
    662     else
    663         tr_inf( _( "System does not seem to support IPv6. Not listening on"
    664                    " an IPv6 address" ) );
    665 
    666     session->shared = tr_sharedInit( session, boolVal, session->peerPort,
    667                                      socketList );
    668     session->isPortSet = session->peerPort > 0;
     715    /* public addresses */
     716
     717    {
     718        struct tr_bindinfo b;
     719        const char * str;
     720
     721        str = TR_PREFS_KEY_BIND_ADDRESS_IPV4;
     722        tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, &str );
     723        if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET ) )
     724            b.addr = tr_inaddr_any;
     725        b.socket = -1;
     726        session->public_ipv4 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
     727
     728        str = TR_PREFS_KEY_BIND_ADDRESS_IPV6;
     729        tr_bencDictFindStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, &str );
     730        if( !tr_pton( str, &b.addr ) || ( b.addr.type != TR_AF_INET6 ) )
     731            b.addr = tr_in6addr_any;
     732        b.socket = -1;
     733        session->public_ipv6 = tr_memdup( &b, sizeof( struct tr_bindinfo ) );
     734
     735        open_incoming_peer_port( session );
     736    }
     737
     738    session->shared = tr_sharedInit( session, boolVal );
    669739
    670740    /**
     
    819889 **********************************************************************/
    820890
    821 struct bind_port_data
    822 {
    823     tr_session * session;
    824     tr_port      port;
    825 };
    826 
    827891static void
    828 tr_setBindPortImpl( void * vdata )
    829 {
    830     struct bind_port_data * data = vdata;
    831     tr_session * session = data->session;
    832     const tr_port port = data->port;
    833 
    834     session->isPortSet = 1;
    835     tr_sharedSetPort( session->shared, port );
    836 
    837     tr_free( data );
    838 }
    839 
    840 static void
    841 setPortImpl( tr_session * session, tr_port port )
    842 {
    843     struct bind_port_data * data;
    844 
    845     assert( tr_isSession( session ) );
    846 
    847     data = tr_new( struct bind_port_data, 1 );
    848     data->session = session;
    849     data->port = port;
    850     tr_runInEventThread( session, tr_setBindPortImpl, data );
     892setPeerPort( void * session )
     893{
     894    tr_torrent * tor = NULL;
     895
     896    assert( tr_isSession( session ) );
     897
     898    close_incoming_peer_port( session );
     899    open_incoming_peer_port( session );
     900    tr_sharedPortChanged( session );
     901
     902    while(( tor = tr_torrentNext( session, tor )))
     903        tr_torrentChangeMyPort( tor );
    851904}
    852905
     
    858911
    859912    session->peerPort = port;
    860     setPortImpl( session, session->peerPort );
     913
     914    tr_runInEventThread( session, setPeerPort, session );
    861915}
    862916
     
    874928    assert( tr_isSession( session ) );
    875929
    876     session->peerPort = getRandomPort( session );
    877     setPortImpl( session, session->peerPort );
     930    tr_sessionSetPeerPort( session, getRandomPort( session ) );
    878931    return session->peerPort;
    879932}
     
    13491402    assert( tr_isSession( session ) );
    13501403
     1404    free_incoming_peer_port( session );
     1405
    13511406    evtimer_del( session->altTimer );
    13521407    tr_free( session->altTimer );
     
    13551410    tr_verifyClose( session );
    13561411    tr_statsClose( session );
    1357     tr_sharedShuttingDown( session->shared );
     1412    tr_sharedClose( session );
    13581413    tr_rpcClose( &session->rpcServer );
    13591414
     
    20942149    return ret;
    20952150}
    2096 
    2097 const tr_socketList *
    2098 tr_getSessionBindSockets( const tr_session * session )
    2099 {
    2100     return tr_sharedGetBindSockets( session->shared );
    2101 }
  • trunk/libtransmission/session.h

    r8243 r8398  
    5656struct tr_address;
    5757struct tr_bandwidth;
     58struct tr_bindsockets;
    5859
    5960struct tr_session
    6061{
    61     tr_bool                      isPortSet;
    6262    tr_bool                      isPortRandom;
    6363    tr_bool                      isPexEnabled;
     
    152152
    153153    double                       desiredRatio;
     154
     155    struct tr_bindinfo         * public_ipv4;
     156    struct tr_bindinfo         * public_ipv6;
    154157};
    155158
     
    174177tr_bool      tr_globalIsLocked( const tr_session * );
    175178
     179const struct tr_address*  tr_sessionGetPublicAddress( const tr_session *, int tr_af_type );
     180
     181struct tr_bindsockets * tr_sessionGetBindSockets( tr_session * );
     182
    176183enum
    177184{
  • trunk/libtransmission/torrent.c

    r8389 r8398  
    597597    tr_peerMgrAddTorrent( session->peerMgr, tor );
    598598
    599     assert( session->isPortSet );
    600599    assert( !tor->downloadedCur );
    601600    assert( !tor->uploadedCur );
Note: See TracChangeset for help on using the changeset viewer.