]> granicus.if.org Git - transmission/commitdiff
Move creation of the UDP sockets to tr-udp.c.
authorJuliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Sun, 9 Jan 2011 21:48:36 +0000 (21:48 +0000)
committerJuliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Sun, 9 Jan 2011 21:48:36 +0000 (21:48 +0000)
libtransmission/session.c
libtransmission/session.h
libtransmission/tr-dht.c
libtransmission/tr-dht.h
libtransmission/tr-udp.c

index 55241c8707f4c965c12d3ccef823a320cb3b95d7..76b16c2126d66ebdd811397f8d214275d7041486 100644 (file)
@@ -523,6 +523,8 @@ tr_sessionInit( const char  * tag,
 
     /* initialize the bare skeleton of the session object */
     session = tr_new0( tr_session, 1 );
+    session->udp_socket = -1;
+    session->udp6_socket = -1;
     session->bandwidth = tr_bandwidthNew( session, NULL );
     session->lock = tr_lockNew( );
     session->cache = tr_cacheNew( 1024*1024*2 );
index 4b12a53b2cd03821c62d57b3269c2b2c21e925e6..16acba4e92aa095bf28e7760a1b738372cbe9ff9 100644 (file)
@@ -125,6 +125,12 @@ struct tr_session
 
     int                          uploadSlotsPerTorrent;
 
+    /* The UDP sockets used for the DHT and uTP. */
+    tr_port                      udp_port;
+    int                          udp_socket;
+    int                          udp6_socket;
+    unsigned char *              udp6_bound;
+
     /* The open port on the local machine for incoming peer requests */
     tr_port                      private_peer_port;
 
index dd8e80d6993203fab7be9f1aa7592a768ee189fa..36ab694906e81285517d8a3f0dc0154d966efabe 100644 (file)
@@ -59,10 +59,7 @@ THE SOFTWARE.
 #include "trevent.h" /* tr_runInEventThread() */
 #include "utils.h"
 
-static int dht_socket = -1, dht6_socket = -1;
-static struct event * dht_event = NULL;
-static struct event * dht6_event = NULL;
-static tr_port dht_port;
+static struct event dht_event, dht6_event;
 static unsigned char myid[20];
 static tr_session *session = NULL;
 
@@ -252,77 +249,9 @@ dht_bootstrap(void *closure)
     tr_ndbg( "DHT", "Finished bootstrapping" );
 }
 
-/* BEP-32 has a rather nice explanation of why we need to bind to one
-   IPv6 address, if I may say so myself. */
-
-static int
-rebind_ipv6(tr_bool force)
-{
-    struct sockaddr_in6 sin6;
-    const unsigned char *ipv6 = tr_globalIPv6();
-    static unsigned char *last_bound = NULL;
-    int s, rc;
-    int one = 1;
-
-    /* We currently have no way to enable or disable IPv6 once the DHT has
-       been initialised. Oh, well. */
-    if(ipv6 == NULL || (!force && dht6_socket < 0)) {
-        if(last_bound) {
-            free(last_bound);
-            last_bound = NULL;
-        }
-        return 0;
-    }
-
-    if(last_bound != NULL && memcmp(ipv6, last_bound, 16) == 0)
-        return 0;
-
-    s = socket(PF_INET6, SOCK_DGRAM, 0);
-    if(s < 0) {
-        tr_ndbg( "DHT", "dht6_socket: %s", tr_strerror( errno ) );
-        return -1;
-    }
-
-#ifdef IPV6_V6ONLY
-        /* Since we always open an IPv4 socket on the same port, this
-           shouldn't matter. But I'm superstitious. */
-        setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
-#endif
-
-    memset(&sin6, 0, sizeof(sin6));
-    sin6.sin6_family = AF_INET6;
-    if(ipv6)
-        memcpy(&sin6.sin6_addr, ipv6, 16);
-    sin6.sin6_port = htons(dht_port);
-    rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
-
-    if(rc < 0) {
-        tr_nerr( "DHT", "bind(dht6_socket): %s", tr_strerror( errno ) );
-        close(s);
-        return -1;
-    }
-
-    if(dht6_socket < 0) {
-        dht6_socket = s;
-    } else {
-        rc = dup2(s, dht6_socket);
-        close(s);
-        if(rc < 0)
-            return -1;
-    }
-
-    if(last_bound == NULL)
-        last_bound = malloc(16);
-    if(last_bound)
-        memcpy(last_bound, ipv6, 16);
-
-    return 1;
-}
-
 int
-tr_dhtInit(tr_session *ss, const tr_address * tr_addr)
+tr_dhtInit(tr_session *ss)
 {
-    struct sockaddr_in sin;
     tr_benc benc;
     int rc;
     tr_bool have_id = FALSE;
@@ -333,29 +262,10 @@ tr_dhtInit(tr_session *ss, const tr_address * tr_addr)
     struct bootstrap_closure * cl;
 
     if( session ) /* already initialized */
-        return -1;
-
-    dht_port = tr_sessionGetPeerPort(ss);
-    if(dht_port <= 0)
-        return -1;
+        return -1;    
 
     tr_ndbg( "DHT", "Initializing DHT" );
 
-    dht_socket = socket(PF_INET, SOCK_DGRAM, 0);
-    if(dht_socket < 0)
-        goto fail;
-
-    memset(&sin, 0, sizeof(sin));
-    sin.sin_family = AF_INET;
-    memcpy(&sin.sin_addr, &tr_addr->addr.addr4, sizeof (struct in_addr));
-    sin.sin_port = htons(dht_port);
-    rc = bind(dht_socket, (struct sockaddr*)&sin, sizeof(sin));
-    if(rc < 0)
-        goto fail;
-
-    if(tr_globalIPv6())
-        rebind_ipv6(TRUE);
-
     if( getenv( "TR_DHT_VERBOSE" ) != NULL )
         dht_debug = stderr;
 
@@ -366,11 +276,11 @@ tr_dhtInit(tr_session *ss, const tr_address * tr_addr)
         have_id = tr_bencDictFindRaw(&benc, "id", &raw, &len);
         if( have_id && len==20 )
             memcpy( myid, raw, len );
-        if( dht_socket >= 0 &&
+        if( ss->udp_socket >= 0 &&
             tr_bencDictFindRaw( &benc, "nodes", &raw, &len ) && !(len%6) ) {
                 nodes = tr_memdup( raw, len );
         }
-        if( dht6_socket > 0 &&
+        if( ss->udp6_socket > 0 &&
             tr_bencDictFindRaw( &benc, "nodes6", &raw, &len6 ) && !(len6%18) ) {
             nodes6 = tr_memdup( raw, len6 );
         }
@@ -391,7 +301,7 @@ tr_dhtInit(tr_session *ss, const tr_address * tr_addr)
         tr_cryptoRandBuf( myid, 20 );
     }
 
-    rc = dht_init( dht_socket, dht6_socket, myid, NULL );
+    rc = dht_init( ss->udp_socket, ss->udp6_socket, myid, NULL );
     if( rc < 0 )
         goto fail;
 
@@ -405,31 +315,22 @@ tr_dhtInit(tr_session *ss, const tr_address * tr_addr)
     cl->len6 = len6;
     tr_threadNew( dht_bootstrap, cl );
 
-    dht_event = event_new( session->event_base, dht_socket, EV_READ, event_callback, NULL );
-    tr_timerAdd( dht_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
+    event_set( &dht_event, ss->udp_socket, EV_READ, event_callback, NULL );
+    tr_timerAdd( &dht_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
 
-    if( dht6_socket >= 0 )
+    if( ss->udp6_socket >= 0 )
     {
-        dht6_event = event_new( session->event_base, dht6_socket, EV_READ, event_callback, NULL );
-        tr_timerAdd( dht6_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
+        event_set( &dht6_event, ss->udp6_socket, EV_READ, event_callback, NULL );
+        tr_timerAdd( &dht6_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
     }
 
     tr_ndbg( "DHT", "DHT initialized" );
 
     return 1;
 
-    fail:
-    {
-        const int save = errno;
-        close(dht_socket);
-        if( dht6_socket >= 0 )
-            close(dht6_socket);
-        dht_socket = dht6_socket = -1;
-        session = NULL;
-        tr_ndbg( "DHT", "DHT initialization failed: %s", tr_strerror( save ) );
-        errno = save;
-    }
-
+ fail:
+    tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", errno );
+    session = NULL;
     return -1;
 }
 
@@ -444,10 +345,8 @@ tr_dhtUninit(tr_session *ss)
     event_free( dht_event );
     dht_event = NULL;
 
-    if( dht6_event ) {
-        event_free( dht6_event );
-        dht6_event = NULL;
-    }
+    if( ss->udp6_socket >= 0 )
+        event_del( &dht6_event );
 
     /* Since we only save known good nodes, avoid erasing older data if we
        don't know enough nodes. */
@@ -489,13 +388,6 @@ tr_dhtUninit(tr_session *ss)
     }
 
     dht_uninit( 1 );
-    tr_netCloseSocket( dht_socket );
-    dht_socket = -1;
-    if(dht6_socket > 0) {
-        tr_netCloseSocket( dht6_socket );
-        dht6_socket = -1;
-    }
-
     tr_ndbg("DHT", "Done uninitializing DHT");
 
     session = NULL;
@@ -540,8 +432,8 @@ tr_dhtStatus( tr_session * session, int af, int * nodes_return )
     struct getstatus_closure closure = { af, -1, -1 };
 
     if( !tr_dhtEnabled( session ) ||
-        (af == AF_INET && dht_socket < 0) ||
-        (af == AF_INET6 && dht6_socket < 0) ) {
+        (af == AF_INET && session->udp_socket < 0) ||
+        (af == AF_INET6 && session->udp6_socket < 0) ) {
         if( nodes_return )
             *nodes_return = 0;
         return TR_DHT_STOPPED;
@@ -560,7 +452,7 @@ tr_dhtStatus( tr_session * session, int af, int * nodes_return )
 tr_port
 tr_dhtPort( tr_session *ss )
 {
-    return tr_dhtEnabled( ss ) ? dht_port : 0;
+    return tr_dhtEnabled( ss ) ? ss->udp_port : 0;
 }
 
 int
@@ -701,9 +593,17 @@ tr_dhtAnnounce(tr_torrent *tor, int af, tr_bool announce)
 static void
 event_callback(int s, short type, void *ignore UNUSED )
 {
-    struct event *event = (s == dht_socket) ? dht_event : dht6_event;
+    struct event *event;
     time_t tosleep;
-    static int count = 0;
+
+    if (s == session->udp_socket)
+        event =  &dht_event;
+    else if(s == session->udp6_socket)
+        event = &dht6_event;
+    else {
+        tr_nerr("DHT", "Event on unexpected socket");
+        event = NULL;
+    }
 
     if( dht_periodic( type == EV_READ, &tosleep, callback, NULL) < 0 ) {
         if(errno == EINTR) {
@@ -716,17 +616,21 @@ event_callback(int s, short type, void *ignore UNUSED )
         }
     }
 
-    /* Only do this once in a while. Counting rather than measuring time
+#ifdef NOTYET
+    /* Only do this once in a while.  Counting rather than measuring time
        avoids a system call. */
     count++;
     if(count >= 20) {
         rebind_ipv6(FALSE);
         count = 0;
     }
+#endif
 
-    /* Being slightly late is fine,
-       and has the added benefit of adding some jitter. */
-    tr_timerAdd( event, tosleep, tr_cryptoWeakRandInt( 1000000 ) );
+    if(event) {
+        /* Being slightly late is fine,
+           and has the added benefit of adding some jitter. */
+        tr_timerAdd( event, tosleep, tr_cryptoWeakRandInt( 1000000 ) );
+    }
 }
 
 void
index 386073216a00c4b164d765420ce7fb01851fa6e9..ff4729e47f6bb7bd74e537ac863dd5b714a19509 100644 (file)
@@ -36,7 +36,7 @@ enum
     TR_DHT_GOOD         = 4
 };
 
-int  tr_dhtInit( tr_session *, const tr_address * );
+int  tr_dhtInit( tr_session * );
 void tr_dhtUninit( tr_session * );
 tr_bool tr_dhtEnabled( const tr_session * );
 tr_port tr_dhtPort ( tr_session * );
index eb091106ac53a915a4b741f7313e7ea3667c1e3a..b765902794c61ac4170903279724c61ec64645d3 100644 (file)
@@ -21,22 +21,144 @@ THE SOFTWARE.
 
 */
 
+#include <unistd.h>
+#include <assert.h>
+
 #include "transmission.h"
 #include "net.h"
 #include "session.h"
 #include "tr-dht.h"
 #include "tr-udp.h"
 
+/* BEP-32 has a rather nice explanation of why we need to bind to one
+   IPv6 address, if I may say so myself. */
+
+static void
+rebind_ipv6(tr_session *ss, tr_bool force)
+{
+    struct sockaddr_in6 sin6;
+    const unsigned char *ipv6 = tr_globalIPv6();
+    int s = -1, rc;
+    int one = 1;
+
+    /* We currently have no way to enable or disable IPv6 after initialisation.
+       No way to fix that without some surgery to the DHT code itself. */
+    if(ipv6 == NULL || (!force && ss->udp6_socket < 0)) {
+        if(ss->udp6_bound) {
+            free(ss->udp6_bound);
+            ss->udp6_bound = NULL;
+        }
+        return;
+    }
+
+    if(ss->udp6_bound != NULL && memcmp(ipv6, ss->udp6_bound, 16) == 0)
+        return;
+
+    s = socket(PF_INET6, SOCK_DGRAM, 0);
+    if(s < 0)
+        goto fail;
+
+#ifdef IPV6_V6ONLY
+        /* Since we always open an IPv4 socket on the same port, this
+           shouldn't matter.  But I'm superstitious. */
+        setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
+#endif
+
+    memset(&sin6, 0, sizeof(sin6));
+    sin6.sin6_family = AF_INET6;
+    if(ipv6)
+        memcpy(&sin6.sin6_addr, ipv6, 16);
+    sin6.sin6_port = htons(ss->udp_port);
+    rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
+    if(rc < 0)
+        goto fail;
+
+    if(ss->udp6_socket < 0) {
+        ss->udp6_socket = s;
+        s = -1;
+    } else {
+        rc = dup2(s, ss->udp6_socket);
+        if(rc < 0)
+            goto fail;
+        close(s);
+        s = -1;
+    }
+
+    if(ss->udp6_bound == NULL)
+        ss->udp6_bound = malloc(16);
+    if(ss->udp6_bound)
+        memcpy(ss->udp6_bound, ipv6, 16);
+
+    return;
+
+ fail:
+    /* Something went wrong.  It's difficult to recover, so let's simply
+       set things up so that we try again next time. */
+    tr_nerr("UDP", "Couldn't rebind IPv6 socket");
+    if(s >= 0)
+        close(s);
+    if(ss->udp6_bound) {
+        free(ss->udp6_bound);
+        ss->udp6_bound = NULL;
+    }
+}
 
 void
 tr_udpInit(tr_session *ss, const tr_address * addr)
 {
-    if( ss->isDHTEnabled )
-        tr_dhtInit(ss, addr);
+    struct sockaddr_in sin;
+    int rc;
+
+    assert(ss->udp_socket < 0);
+    assert(ss->udp6_socket < 0);
+
+    ss->udp_port = tr_sessionGetPeerPort(ss);
+    if(ss->udp_port <= 0)
+        return;
+
+    ss->udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
+    if(ss->udp_socket < 0) {
+        tr_nerr("UDP", "Couldn't create IPv4 socket");
+        goto ipv6;
+    }
+
+    memset(&sin, 0, sizeof(sin));
+    sin.sin_family = AF_INET;
+    memcpy(&sin.sin_addr, &addr->addr.addr4, sizeof (struct in_addr));
+    sin.sin_port = htons(ss->udp_port);
+    rc = bind(ss->udp_socket, (struct sockaddr*)&sin, sizeof(sin));
+    if(rc < 0) {
+        tr_nerr("UDP", "Couldn't bind IPv4 socket");
+        close(ss->udp_socket);
+        ss->udp_socket = -1;
+        goto ipv6;
+    }
+
+ ipv6:
+    if(tr_globalIPv6())
+        rebind_ipv6(ss, TRUE);
+
+    if(ss->isDHTEnabled)
+        tr_dhtInit(ss);
 }
 
 void
 tr_udpUninit(tr_session *ss)
 {
-    return tr_dhtUninit(ss);
+    tr_dhtUninit(ss);
+
+    if(ss->udp_socket >= 0) {
+        tr_netCloseSocket( ss->udp_socket );
+        ss->udp_socket = -1;
+    }
+
+    if(ss->udp6_socket >= 0) {
+        tr_netCloseSocket( ss->udp6_socket );
+        ss->udp6_socket = -1;
+    }
+
+    if(ss->udp6_bound) {
+        free(ss->udp6_bound);
+        ss->udp6_bound = NULL;
+    }
 }