Ticket #7: transmission-dht-20090612.patch

File transmission-dht-20090612.patch, 14.6 KB (added by charles, 13 years ago)
  • cli/Makefile.am

    diff -urN transmission-1.60/cli/Makefile.am transmission-dht/cli/Makefile.am
    old new  
    2020    $(top_builddir)/third-party/libevent/libevent.la \
    2121    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    2222    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
     23    $(top_builddir)/third-party/dht/dht.o \
    2324    $(INTLLIBS) \
    2425    $(LIBCURL_LIBS) \
    2526    $(ZLIB_LIBS) \
  • daemon/Makefile.am

    diff -urN transmission-1.60/daemon/Makefile.am transmission-dht/daemon/Makefile.am
    old new  
    2222    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
    2323    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    2424    $(top_builddir)/third-party/libevent/libevent.la \
     25    $(top_builddir)/third-party/dht/dht.o \
    2526    $(INTLLIBS) \
    2627    $(LIBCURL_LIBS) \
    2728    $(ZLIB_LIBS) \
  • gtk/details.c

    diff -urN transmission-1.60/gtk/details.c transmission-dht/gtk/details.c
    old new  
    15001500                case '?': s = _( "We unchoked this peer, but they're not interested" ); break;
    15011501                case 'E': s = _( "Encrypted connection" ); break;
    15021502                case 'X': s = _( "Peer was discovered through Peer Exchange (PEX)" ); break;
     1503                case 'H': s = _( "Peer was discovered through the DHT" ); break;
    15031504                case 'I': s = _( "Peer is an incoming connection" ); break;
    15041505            }
    15051506            if( s )
  • gtk/Makefile.am

    diff -urN transmission-1.60/gtk/Makefile.am transmission-dht/gtk/Makefile.am
    old new  
    101101    $(top_builddir)/third-party/libevent/libevent.la \
    102102    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
    103103    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
     104    $(top_builddir)/third-party/dht/dht.o \
    104105    $(GTK_LIBS) \
    105106    $(GIO_LIBS) \
    106107    $(LIBNOTIFY_LIBS) \
  • libtransmission/Makefile.am

    diff -urN transmission-1.60/libtransmission/Makefile.am transmission-dht/libtransmission/Makefile.am
    old new  
    4949    torrent-ctor.c \
    5050    tr-getopt.c \
    5151    tracker.c \
     52    trdht.c \
    5253    trevent.c \
    5354    upnp.c \
    5455    utils.c \
     
    9697    tracker.h \
    9798    tr-getopt.h \
    9899    transmission.h \
     100    trdht.h \
    99101    trevent.h \
    100102    upnp.h \
    101103    utils.h \
     
    124126    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
    125127    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    126128    $(top_builddir)/third-party/libevent/libevent.la \
     129    $(top_builddir)/third-party/dht/dht.o \
    127130    $(INTLLIBS) \
    128131    $(LIBCURL_LIBS) \
    129132    $(OPENSSL_LIBS) \
  • libtransmission/peer-mgr.c

    diff -urN transmission-1.60/libtransmission/peer-mgr.c transmission-dht/libtransmission/peer-mgr.c
    old new  
    18601860        if( !stat->peerIsChoked && !stat->peerIsInterested ) *pch++ = '?';
    18611861        if( stat->isEncrypted ) *pch++ = 'E';
    18621862        if( stat->from == TR_PEER_FROM_PEX ) *pch++ = 'X';
     1863        if( stat->from == TR_PEER_FROM_DHT ) *pch++ = 'H';
    18631864        if( stat->isIncoming ) *pch++ = 'I';
    18641865        *pch = '\0';
    18651866    }
  • libtransmission/transmission.h

    diff -urN transmission-1.60/libtransmission/transmission.h transmission-dht/libtransmission/transmission.h
    old new  
    13351335    TR_PEER_FROM_TRACKER   = 1,  /* peers received from a tracker */
    13361336    TR_PEER_FROM_CACHE     = 2,  /* peers read from the peer cache */
    13371337    TR_PEER_FROM_PEX       = 3,  /* peers discovered via PEX */
     1338    TR_PEER_FROM_DHT       = 4,
    13381339    TR_PEER_FROM__MAX
    13391340};
    13401341
  • libtransmission/trdht.c

    diff -urN transmission-1.60/libtransmission/trdht.c transmission-dht/libtransmission/trdht.c
    old new  
     1/*
     2Copyright (c) 2009 by Juliusz Chroboczek
     3
     4Permission is hereby granted, free of charge, to any person obtaining a copy
     5of this software and associated documentation files (the "Software"), to deal
     6in the Software without restriction, including without limitation the rights
     7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8copies of the Software, and to permit persons to whom the Software is
     9furnished to do so, subject to the following conditions:
     10
     11The above copyright notice and this permission notice shall be included in
     12all copies or substantial portions of the Software.
     13
     14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20THE SOFTWARE.
     21*/
     22
     23#include <stdio.h>
     24#include <stdlib.h>
     25#include <errno.h>
     26#include <string.h>
     27#include <unistd.h>
     28#include <fcntl.h>
     29#include <sys/time.h>
     30#include <arpa/inet.h>
     31#include <sys/types.h>
     32#include <sys/socket.h>
     33#include <sys/signal.h>
     34
     35#include <dht/dht.h>
     36
     37#include "transmission.h"
     38#include "session.h"
     39#include "torrent.h"
     40#include "peer-mgr.h"
     41#include "crypto.h"
     42#include "platform.h"
     43
     44#include "trdht.h"
     45
     46static void trdht_main_loop(void*);
     47int s;
     48unsigned char myid[20];
     49static tr_session *session = NULL;
     50sig_atomic_t please_exit = 0;
     51
     52void
     53trdht_init(tr_session *ss)
     54{
     55    struct sockaddr_in sin;
     56    int rc;
     57    int fd;
     58
     59    if(session) {
     60        fprintf(stderr, "Multiple calls to trdht_init.\n");
     61        return;
     62    }
     63    session = ss;
     64
     65    s = socket(PF_INET, SOCK_DGRAM, 0);
     66    if(s < 0) {
     67        perror("socket");
     68        return;
     69    }
     70
     71    memset(&sin, 0, sizeof(sin));
     72    sin.sin_family = AF_INET;
     73    sin.sin_port = htons(tr_sessionGetPeerPort(session));
     74    rc = bind(s, (struct sockaddr*)&sin, sizeof(sin));
     75    if(rc < 0) {
     76        perror("bind");
     77        close(s);
     78        return;
     79    }
     80
     81    /* Note that you cannot just use your BT id -- DHT ids need to be
     82       distributed uniformly, so it should either be the SHA-1 of
     83       something, or truly random. */
     84    fd = open("/dev/urandom", O_RDONLY);
     85    read(fd, myid, 20);
     86    close(fd);
     87
     88    rc = dht_init(s, myid);
     89    if(rc < 0) {
     90        perror("dht_init");
     91        return;
     92    }
     93
     94#if 1
     95    dht_debug = stdout;
     96#endif
     97
     98    tr_threadNew(trdht_main_loop, trdht_main_loop);
     99
     100    if(session->configDir) {
     101        char buf[512];
     102        FILE *f;
     103        strncpy(buf, session->configDir, 512);
     104        strncat(buf, "/dht-bootstrap", 512);
     105        f = fopen(buf, "r");
     106        if(f) {
     107            while(1) {
     108                int port;
     109                rc = fscanf(f, "%30[0-9.]:%d\n", buf, &port);
     110                if(rc != 2 || port < 1 || port > 0xFFFF)
     111                    break;
     112                memset(&sin, 0, sizeof(sin));
     113                sin.sin_family = AF_INET;
     114                rc = inet_pton(AF_INET, buf, &sin.sin_addr);
     115                if(rc != 1) break;
     116                sin.sin_port = htons(port);
     117                printf("Bootstrapping from %s:%d.\n", buf, port);
     118                /* Happily dht_ping doesn't have any locking issues. */
     119                dht_ping_node(s, &sin);
     120                sleep(1);
     121            }
     122        }
     123    }
     124}
     125
     126void
     127trdht_uninit(tr_session *ss)
     128{
     129    if(ss != session)
     130        return;
     131
     132    please_exit = 1;
     133}
     134
     135
     136static void
     137callback(void *closure,
     138         int event,
     139         unsigned char *info_hash,
     140         void *data, size_t data_len)
     141{
     142    int i;
     143    if(event == DHT_EVENT_SEARCH_DONE)
     144        printf("Search done.\n");
     145    else if(event == DHT_EVENT_VALUES) {
     146        tr_torrent *tor;
     147        tr_pex *pex;
     148        size_t n;
     149        pex = tr_peerMgrCompactToPex(data, data_len, NULL, 0, &n);
     150        tr_globalLock(session);
     151        tor = tr_torrentFindFromHash(session, info_hash);
     152        if(tor) {
     153            for(i = 0; i < n; i++)
     154                tr_peerMgrAddPex(tor, TR_PEER_FROM_DHT, pex + i);
     155        }
     156        tr_globalUnlock(session);
     157        tr_free(pex);
     158    }
     159}
     160
     161static void
     162search_and_announce(int announce)
     163{
     164    tr_torrent * tor = NULL;
     165
     166    tr_globalLock(session);
     167    /* 'Twere better if we didn't schedule searches for all torrents at the
     168       sime time... but that will require deeper integration with the rest
     169       of Transmission. */
     170    while((tor = tr_torrentNext(session, tor)))
     171        if(tr_torrentGetActivity(tor) != TR_STATUS_STOPPED)
     172            dht_search(s, tor->info.hash,
     173                       announce ? tr_sessionGetPeerPort(session) : 0,
     174                       callback, NULL);
     175    tr_globalUnlock(session);
     176}
     177
     178static void
     179trdht_main_loop(void* ignore)
     180{
     181    int rc;
     182    time_t tosleep;
     183    time_t announce_time;
     184
     185    announce_time = 0;
     186
     187    while(!please_exit) {
     188        struct timeval tv, now;
     189        fd_set readfds;
     190        tv.tv_sec = tosleep;
     191        tv.tv_usec = random() % 1000000;
     192
     193        gettimeofday(&now, NULL);
     194        if(announce_time == 0) {
     195            int good, dubious, cached;
     196            dht_nodes(&good, &dubious, &cached);
     197            if(good >= 8 && good + dubious + cached >= 24)
     198                announce_time = now.tv_sec;
     199        } else if(now.tv_sec >= announce_time) {
     200            search_and_announce(1);
     201            /* Most peers expire data after 30 minutes, give us
     202               a chance to announce twice in this interval. */
     203            announce_time = now.tv_sec + 600 + random() % 240;
     204        }
     205
     206
     207        FD_ZERO(&readfds);
     208        FD_SET(s, &readfds);
     209        rc = select(s + 1, &readfds, NULL, NULL, &tv);
     210        if(rc < 0) {
     211            if(errno != EINTR) {
     212                perror("select");
     213                sleep(1);
     214            }
     215        }
     216       
     217        rc = dht_periodic(s, rc > 0, &tosleep, callback, NULL);
     218        if(rc < 0) {
     219            if(errno == EINTR) {
     220                continue;
     221            } else {
     222                perror("dht_periodic");
     223                if(rc == EINVAL || rc == EFAULT)
     224                    abort();
     225                tosleep = 1;
     226            }
     227        }
     228    }
     229
     230    dht_uninit(s, 0);
     231    please_exit = 0;
     232}
     233
     234void
     235dht_hash(void *hash_return, int hash_size,
     236         const void *v1, int len1,
     237         const void *v2, int len2,
     238         const void *v3, int len3)
     239{
     240    unsigned char sha1[20];
     241    tr_sha1(sha1, v1, len1, v2, len2, v3, len3, NULL);
     242    if(hash_size > 20) {
     243        memset((char*)hash_return + 20, 0, hash_size - 20);
     244    }
     245    memcpy(hash_return, sha1, hash_size > 20 ? 20 : hash_size);
     246}
  • libtransmission/trdht.h

    diff -urN transmission-1.60/libtransmission/trdht.h transmission-dht/libtransmission/trdht.h
    old new  
     1/*
     2Copyright (c) 2009 by Juliusz Chroboczek
     3
     4Permission is hereby granted, free of charge, to any person obtaining a copy
     5of this software and associated documentation files (the "Software"), to deal
     6in the Software without restriction, including without limitation the rights
     7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8copies of the Software, and to permit persons to whom the Software is
     9furnished to do so, subject to the following conditions:
     10
     11The above copyright notice and this permission notice shall be included in
     12all copies or substantial portions of the Software.
     13
     14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20THE SOFTWARE.
     21*/
     22
     23void trdht_init(tr_session *ss);
     24void trdht_uninit(tr_session *ss);
  • third-party/Makefile.am

    diff -urN transmission-1.60/third-party/Makefile.am transmission-dht/third-party/Makefile.am
    old new  
    11SUBDIRS = \
    22    libevent \
    33    libnatpmp \
    4     miniupnp
     4    miniupnp \
     5    dht
    56
    67EXTRA_DIST = \
    78    macosx-libevent-config.h
  • libtransmission/session.c

    old new  
    4444#include "version.h"
    4545#include "verify.h"
    4646#include "web.h"
     47#include "trdht.h"
    4748
    4849#define dbgmsg( ... ) \
    4950    do { \
     
    492493    while( session->isWaiting )
    493494        tr_wait( 100 );
    494495
     496    trdht_init(session);
     497
    495498    return session;
    496499}
    497500
     
    13991402
    14001403    dbgmsg( "shutting down transmission session %p", session );
    14011404
     1405    trdht_uninit(session);
     1406
    14021407    /* close the session */
    14031408    tr_runInEventThread( session, tr_closeAllConnections, session );
    14041409    while( !session->isClosed && !deadlineReached( deadline ) )
  • libtransmission/handshake.c

    old new  
    8282 #define HANDSHAKE_SET_FASTEXT( bits ) ( (void)0 )
    8383#endif
    8484
     85#define HANDSHAKE_HAS_DHT( bits ) ( ( ( bits )[7] & 0x01 ) ? 1 : 0 )
     86#define HANDSHAKE_SET_DHT( bits ) ( ( bits )[7] |= 0x01 )
     87
    8588/* http://www.azureuswiki.com/index.php/Extension_negotiation_protocol
    8689   these macros are to be used if both extended messaging and the
    8790   azureus protocol is supported, they indicate which protocol is preferred */
     
    218221    memset( walk, 0, HANDSHAKE_FLAGS_LEN );
    219222    HANDSHAKE_SET_LTEP( walk );
    220223    HANDSHAKE_SET_FASTEXT( walk );
     224    HANDSHAKE_SET_DHT( walk );
    221225
    222226    walk += HANDSHAKE_FLAGS_LEN;
    223227    memcpy( walk, torrentHash, SHA_DIGEST_LENGTH );