source: trunk/libtransmission/tr-dht.c @ 11284

Last change on this file since 11284 was 11284, checked in by charles, 12 years ago

(trunk) more "svn propset" tweaks for $Id$

  • Property svn:keywords set to Date Rev Author Id
File size: 20.2 KB
Line 
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 $Id: tr-dht.c 11284 2010-10-01 20:22:51Z charles $
23
24*/
25
26/* ansi */
27#include <errno.h>
28#include <stdio.h>
29
30/* posix */
31#include <signal.h> /* sig_atomic_t */
32#include <sys/time.h>
33#include <unistd.h> /* close() */
34#ifdef WIN32
35  #include <inttypes.h>
36  #define _WIN32_WINNT  0x0501  /* freeaddrinfo(),getaddrinfo(),getnameinfo() */
37  #include <ws2tcpip.h>
38#else
39  #include <sys/types.h>
40  #include <sys/socket.h> /* socket(), bind() */
41  #include <netdb.h>
42  #include <netinet/in.h> /* sockaddr_in */
43#endif
44
45/* third party */
46#include <event.h>
47#include <dht/dht.h>
48
49/* libT */
50#include "transmission.h"
51#include "bencode.h"
52#include "crypto.h"
53#include "net.h"
54#include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
55#include "platform.h" /* tr_threadNew() */
56#include "session.h"
57#include "torrent.h" /* tr_torrentFindFromHash() */
58#include "tr-dht.h"
59#include "trevent.h" /* tr_runInEventThread() */
60#include "utils.h"
61#include "version.h"
62
63static int dht_socket = -1, dht6_socket = -1;
64static struct event dht_event, dht6_event;
65static tr_port dht_port;
66static unsigned char myid[20];
67static tr_session *session = NULL;
68
69static void event_callback(int s, short type, void *ignore);
70
71struct bootstrap_closure {
72    tr_session *session;
73    uint8_t *nodes;
74    uint8_t *nodes6;
75    size_t len, len6;
76};
77
78static int
79bootstrap_done( tr_session *session, int af )
80{
81    int status;
82
83    if(af == 0)
84        return
85            bootstrap_done(session, AF_INET) &&
86            bootstrap_done(session, AF_INET6);
87
88    status = tr_dhtStatus(session, af, NULL);
89    return status == TR_DHT_STOPPED || status >= TR_DHT_FIREWALLED;
90}
91
92static void
93nap( int roughly_sec )
94{
95    const int roughly_msec = roughly_sec * 1000;
96    const int msec = roughly_msec/2 + tr_cryptoWeakRandInt(roughly_msec);
97    tr_wait_msec( msec );
98}
99
100static int
101bootstrap_af(tr_session *session)
102{
103    if( bootstrap_done(session, AF_INET6) )
104        return AF_INET;
105    else if ( bootstrap_done(session, AF_INET) )
106        return AF_INET6;
107    else
108        return 0;
109}
110
111static void
112bootstrap_from_name( const char *name, tr_port port, int af )
113{
114    struct addrinfo hints, *info, *infop;
115    char pp[10];
116    int rc;
117
118    memset(&hints, 0, sizeof(hints));
119    hints.ai_socktype = SOCK_DGRAM;
120    hints.ai_family = af;
121    /* No, just passing p + 1 to gai won't work. */
122    tr_snprintf(pp, sizeof(pp), "%d", (int)port);
123
124    rc = getaddrinfo(name, pp, &hints, &info);
125    if(rc != 0) {
126        tr_nerr("DHT", "%s:%s: %s", name, pp, gai_strerror(rc));
127        return;
128    }
129
130    infop = info;
131    while(infop) {
132        dht_ping_node(infop->ai_addr, infop->ai_addrlen);
133
134        nap(15);
135
136        if(bootstrap_done(session, af))
137            break;
138        infop = infop->ai_next;
139    }
140    freeaddrinfo(info);
141}
142
143static void
144dht_bootstrap(void *closure)
145{
146    struct bootstrap_closure *cl = closure;
147    int i;
148    int num = cl->len / 6, num6 = cl->len6 / 18;
149
150    if(session != cl->session)
151        return;
152
153    if(cl->len > 0)
154        tr_ninf( "DHT", "Bootstrapping from %d nodes", num );
155
156    if(cl->len6 > 0)
157        tr_ninf( "DHT", "Bootstrapping from %d IPv6 nodes", num6 );
158
159
160    for(i = 0; i < MAX(num, num6); i++) {
161        if( i < num && !bootstrap_done(cl->session, AF_INET) ) {
162            tr_port port;
163            struct tr_address addr;
164
165            memset(&addr, 0, sizeof(addr));
166            addr.type = TR_AF_INET;
167            memcpy(&addr.addr.addr4, &cl->nodes[i * 6], 4);
168            memcpy(&port, &cl->nodes[i * 6 + 4], 2);
169            port = ntohs(port);
170            tr_dhtAddNode(cl->session, &addr, port, 1);
171        }
172        if( i < num6 && !bootstrap_done(cl->session, AF_INET6) ) {
173            tr_port port;
174            struct tr_address addr;
175
176            memset(&addr, 0, sizeof(addr));
177            addr.type = TR_AF_INET6;
178            memcpy(&addr.addr.addr6, &cl->nodes6[i * 18], 16);
179            memcpy(&port, &cl->nodes6[i * 18 + 16], 2);
180            port = ntohs(port);
181            tr_dhtAddNode(cl->session, &addr, port, 1);
182        }
183
184        /* Our DHT code is able to take up to 9 nodes in a row without
185           dropping any.  After that, it takes some time to split buckets.
186           So ping the first 8 nodes quickly, then slow down. */
187        if(i < 8)
188            nap(2);
189        else
190            nap(15);
191
192        if(bootstrap_done( session, 0 ))
193            break;
194    }
195
196    if(!bootstrap_done(cl->session, 0)) {
197        char *bootstrap_file;
198        FILE *f = NULL;
199
200        bootstrap_file =
201            tr_buildPath(cl->session->configDir, "dht.bootstrap", NULL);
202
203        if(bootstrap_file)
204            f = fopen(bootstrap_file, "rb");
205        if(f != NULL) {
206            tr_ninf("DHT", "Attempting manual bootstrap");
207            for(;;) {
208                char buf[201];
209                char *p;
210                int port = 0;
211
212                p = fgets(buf, 200, f);
213                if( p == NULL )
214                    break;
215
216                p = memchr(buf, ' ', strlen(buf));
217                if(p != NULL)
218                    port = atoi(p + 1);
219                if(p == NULL || port <= 0 || port >= 0x10000) {
220                    tr_nerr("DHT", "Couldn't parse %s", buf);
221                    continue;
222                }
223
224                *p = '\0';
225
226                bootstrap_from_name( buf, port, bootstrap_af(session) );
227
228                if(bootstrap_done(cl->session, 0))
229                    break;
230            }
231        }
232
233        tr_free( bootstrap_file );
234    }
235
236    /* We really don't want to abuse our bootstrap nodes.
237       Be glacially slow. */
238    if(!bootstrap_done(cl->session, 0))
239        nap(30);
240
241    if(!bootstrap_done(cl->session, 0)) {
242        tr_ninf("DHT", "Attempting bootstrap from dht.transmissionbt.com");
243        bootstrap_from_name( "dht.transmissionbt.com", 6881,
244                             bootstrap_af(session) );
245    }
246
247    if( cl->nodes )
248        tr_free( cl->nodes );
249    if( cl->nodes6 )
250        tr_free( cl->nodes6 );
251    tr_free( closure );
252    tr_ndbg( "DHT", "Finished bootstrapping" );
253}
254
255/* BEP-32 has a rather nice explanation of why we need to bind to one
256   IPv6 address, if I may say so myself. */
257
258static int
259rebind_ipv6(tr_bool force)
260{
261    struct sockaddr_in6 sin6;
262    const unsigned char *ipv6 = tr_globalIPv6();
263    static unsigned char *last_bound = NULL;
264    int s, rc;
265    int one = 1;
266
267    /* We currently have no way to enable or disable IPv6 once the DHT has
268       been initialised.  Oh, well. */
269    if(ipv6 == NULL || (!force && dht6_socket < 0)) {
270        if(last_bound) {
271            free(last_bound);
272            last_bound = NULL;
273        }
274        return 0;
275    }
276
277    if(last_bound != NULL && memcmp(ipv6, last_bound, 16) == 0)
278        return 0;
279
280    s = socket(PF_INET6, SOCK_DGRAM, 0);
281    if(s < 0)
282        return -1;
283
284#ifdef IPV6_V6ONLY
285        /* Since we always open an IPv4 socket on the same port, this
286           shouldn't matter.  But I'm superstitious. */
287        setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
288#endif
289
290    memset(&sin6, 0, sizeof(sin6));
291    sin6.sin6_family = AF_INET6;
292    if(ipv6)
293        memcpy(&sin6.sin6_addr, ipv6, 16);
294    sin6.sin6_port = htons(dht_port);
295    rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
296
297    if(rc < 0)
298        return -1;
299
300    if(dht6_socket < 0) {
301        dht6_socket = s;
302    } else {
303        rc = dup2(s, dht6_socket);
304        close(s);
305        if(rc < 0)
306            return -1;
307    }
308
309    if(last_bound == NULL)
310        last_bound = malloc(16);
311    if(last_bound)
312        memcpy(last_bound, ipv6, 16);
313
314    return 1;
315}
316
317int
318tr_dhtInit(tr_session *ss, const tr_address * tr_addr)
319{
320    struct sockaddr_in sin;
321    tr_benc benc;
322    int rc;
323    tr_bool have_id = FALSE;
324    char * dat_file;
325    uint8_t * nodes = NULL, * nodes6 = NULL;
326    const uint8_t * raw;
327    size_t len, len6;
328    char v[5];
329    struct bootstrap_closure * cl;
330
331    if( session ) /* already initialized */
332        return -1;
333
334    dht_port = tr_sessionGetPeerPort(ss);
335    if(dht_port <= 0)
336        return -1;
337
338    tr_ndbg( "DHT", "Initializing DHT" );
339
340    dht_socket = socket(PF_INET, SOCK_DGRAM, 0);
341    if(dht_socket < 0)
342        goto fail;
343
344    memset(&sin, 0, sizeof(sin));
345    sin.sin_family = AF_INET;
346    memcpy(&sin.sin_addr, &tr_addr->addr.addr4, sizeof (struct in_addr));
347    sin.sin_port = htons(dht_port);
348    rc = bind(dht_socket, (struct sockaddr*)&sin, sizeof(sin));
349    if(rc < 0)
350        goto fail;
351
352    if(tr_globalIPv6())
353        rebind_ipv6(TRUE);
354
355    if( getenv( "TR_DHT_VERBOSE" ) != NULL )
356        dht_debug = stderr;
357
358    dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL );
359    rc = tr_bencLoadFile( &benc, TR_FMT_BENC, dat_file );
360    tr_free( dat_file );
361    if(rc == 0) {
362        have_id = tr_bencDictFindRaw(&benc, "id", &raw, &len);
363        if( have_id && len==20 )
364            memcpy( myid, raw, len );
365        if( dht_socket >= 0 &&
366            tr_bencDictFindRaw( &benc, "nodes", &raw, &len ) && !(len%6) ) {
367                nodes = tr_memdup( raw, len );
368        }
369        if( dht6_socket > 0 &&
370            tr_bencDictFindRaw( &benc, "nodes6", &raw, &len6 ) && !(len6%18) ) {
371            nodes6 = tr_memdup( raw, len6 );
372        }
373        tr_bencFree( &benc );
374    }
375
376    if(nodes == NULL)
377        len = 0;
378    if(nodes6 == NULL)
379        len6 = 0;
380
381    if( have_id )
382        tr_ninf( "DHT", "Reusing old id" );
383    else {
384        /* Note that DHT ids need to be distributed uniformly,
385         * so it should be something truly random. */
386        tr_ninf( "DHT", "Generating new id" );
387        tr_cryptoRandBuf( myid, 20 );
388    }
389
390    v[0] = 'T';
391    v[1] = 'R';
392    v[2] = (SVN_REVISION_NUM >> 8) & 0xFF;
393    v[3] = SVN_REVISION_NUM & 0xFF;
394    rc = dht_init( dht_socket, dht6_socket, myid, (const unsigned char*)v );
395    if(rc < 0)
396        goto fail;
397
398    session = ss;
399
400    cl = tr_new( struct bootstrap_closure, 1 );
401    cl->session = session;
402    cl->nodes = nodes;
403    cl->nodes6 = nodes6;
404    cl->len = len;
405    cl->len6 = len6;
406    tr_threadNew( dht_bootstrap, cl );
407
408    event_set( &dht_event, dht_socket, EV_READ, event_callback, NULL );
409    tr_timerAdd( &dht_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
410
411    if( dht6_socket >= 0 )
412    {
413        event_set( &dht6_event, dht6_socket, EV_READ, event_callback, NULL );
414        tr_timerAdd( &dht6_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
415    }
416
417    tr_ndbg( "DHT", "DHT initialized" );
418
419    return 1;
420
421    fail:
422    {
423        const int save = errno;
424        close(dht_socket);
425        if( dht6_socket >= 0 )
426            close(dht6_socket);
427        dht_socket = dht6_socket = -1;
428        session = NULL;
429        tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", save );
430        errno = save;
431    }
432
433    return -1;
434}
435
436void
437tr_dhtUninit(tr_session *ss)
438{
439    if(session != ss)
440        return;
441
442    tr_ndbg( "DHT", "Uninitializing DHT" );
443
444    event_del( &dht_event );
445
446    if( dht6_socket >= 0 )
447        event_del( &dht6_event );
448
449    /* Since we only save known good nodes, avoid erasing older data if we
450       don't know enough nodes. */
451    if(tr_dhtStatus(ss, AF_INET, NULL) < TR_DHT_FIREWALLED)
452        tr_ninf( "DHT", "Not saving nodes, DHT not ready" );
453    else {
454        tr_benc benc;
455        struct sockaddr_in sins[300];
456        struct sockaddr_in6 sins6[300];
457        char compact[300 * 6], compact6[300 * 18];
458        char *dat_file;
459        int i, j, num = 300, num6 = 300;
460        int n = dht_get_nodes(sins, &num, sins6, &num6);
461
462        tr_ninf( "DHT", "Saving %d (%d + %d) nodes", n, num, num6 );
463
464        j = 0;
465        for( i=0; i<num; ++i ) {
466            memcpy( compact + j, &sins[i].sin_addr, 4 );
467            memcpy( compact + j + 4, &sins[i].sin_port, 2 );
468            j += 6;
469        }
470        j = 0;
471        for( i=0; i<num6; ++i ) {
472            memcpy( compact6 + j, &sins6[i].sin6_addr, 16 );
473            memcpy( compact6 + j + 16, &sins6[i].sin6_port, 2 );
474            j += 18;
475        }
476        tr_bencInitDict( &benc, 3 );
477        tr_bencDictAddRaw( &benc, "id", myid, 20 );
478        if(num > 0)
479            tr_bencDictAddRaw( &benc, "nodes", compact, num * 6 );
480        if(num6 > 0)
481            tr_bencDictAddRaw( &benc, "nodes6", compact6, num6 * 18 );
482        dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL );
483        tr_bencToFile( &benc, TR_FMT_BENC, dat_file );
484        tr_bencFree( &benc );
485        tr_free( dat_file );
486    }
487
488    dht_uninit( 1 );
489    tr_netCloseSocket( dht_socket );
490    dht_socket = -1;
491    if(dht6_socket > 0) {
492        tr_netCloseSocket( dht6_socket );
493        dht6_socket = -1;
494    }
495
496    tr_ndbg("DHT", "Done uninitializing DHT");
497
498    session = NULL;
499}
500
501tr_bool
502tr_dhtEnabled( const tr_session * ss )
503{
504    return ss && ( ss == session );
505}
506
507struct getstatus_closure
508{
509    int af;
510    sig_atomic_t status;
511    sig_atomic_t count;
512};
513
514static void
515getstatus( void * cl )
516{
517    struct getstatus_closure * closure = cl;
518    int good, dubious, incoming;
519
520    dht_nodes( closure->af, &good, &dubious, NULL, &incoming );
521
522    closure->count = good + dubious;
523
524    if( good < 4 || good + dubious <= 8 )
525        closure->status = TR_DHT_BROKEN;
526    else if( good < 40 )
527        closure->status = TR_DHT_POOR;
528    else if( incoming < 8 )
529        closure->status = TR_DHT_FIREWALLED;
530    else
531        closure->status = TR_DHT_GOOD;
532}
533
534int
535tr_dhtStatus( tr_session * session, int af, int * nodes_return )
536{
537    struct getstatus_closure closure = { af, -1, -1 };
538
539    if( !tr_dhtEnabled( session ) ||
540        (af == AF_INET && dht_socket < 0) ||
541        (af == AF_INET6 && dht6_socket < 0) ) {
542        if( nodes_return )
543            *nodes_return = 0;
544        return TR_DHT_STOPPED;
545    }
546
547    tr_runInEventThread( session, getstatus, &closure );
548    while( closure.status < 0 )
549        tr_wait_msec( 50 /*msec*/ );
550
551    if( nodes_return )
552        *nodes_return = closure.count;
553
554    return closure.status;
555}
556
557tr_port
558tr_dhtPort( tr_session *ss )
559{
560    return tr_dhtEnabled( ss ) ? dht_port : 0;
561}
562
563int
564tr_dhtAddNode( tr_session       * ss,
565               const tr_address * address,
566               tr_port            port,
567               tr_bool            bootstrap )
568{
569    int af = address->type == TR_AF_INET ? AF_INET : AF_INET6;
570
571    if( !tr_dhtEnabled( ss ) )
572        return 0;
573
574    /* Since we don't want to abuse our bootstrap nodes,
575     * we don't ping them if the DHT is in a good state. */
576
577    if(bootstrap) {
578        if(tr_dhtStatus(ss, af, NULL) >= TR_DHT_FIREWALLED)
579            return 0;
580    }
581
582    if( address->type == TR_AF_INET ) {
583        struct sockaddr_in sin;
584        memset(&sin, 0, sizeof(sin));
585        sin.sin_family = AF_INET;
586        memcpy(&sin.sin_addr, &address->addr.addr4, 4);
587        sin.sin_port = htons(port);
588        dht_ping_node((struct sockaddr*)&sin, sizeof(sin));
589        return 1;
590    } else if( address->type == TR_AF_INET6 ) {
591        struct sockaddr_in6 sin6;
592        memset(&sin6, 0, sizeof(sin6));
593        sin6.sin6_family = AF_INET6;
594        memcpy(&sin6.sin6_addr, &address->addr.addr6, 16);
595        sin6.sin6_port = htons(port);
596        dht_ping_node((struct sockaddr*)&sin6, sizeof(sin6));
597        return 1;
598    }
599
600    return 0;
601}
602
603const char *
604tr_dhtPrintableStatus(int status)
605{
606    switch(status) {
607    case TR_DHT_STOPPED: return "stopped";
608    case TR_DHT_BROKEN: return "broken";
609    case TR_DHT_POOR: return "poor";
610    case TR_DHT_FIREWALLED: return "firewalled";
611    case TR_DHT_GOOD: return "good";
612    default: return "???";
613    }
614}
615
616static void
617callback( void *ignore UNUSED, int event,
618          unsigned char *info_hash, void *data, size_t data_len )
619{
620    if( event == DHT_EVENT_VALUES || event == DHT_EVENT_VALUES6 ) {
621        tr_torrent *tor;
622        tr_sessionLock( session );
623        tor = tr_torrentFindFromHash( session, info_hash );
624        if( tor && tr_torrentAllowsDHT( tor ))
625        {
626            size_t i, n;
627            tr_pex * pex;
628            if( event == DHT_EVENT_VALUES )
629                pex = tr_peerMgrCompactToPex(data, data_len, NULL, 0, &n);
630            else
631                pex = tr_peerMgrCompact6ToPex(data, data_len, NULL, 0, &n);
632            for( i=0; i<n; ++i )
633                tr_peerMgrAddPex( tor, TR_PEER_FROM_DHT, pex+i, -1 );
634            tr_free(pex);
635            tr_tordbg(tor, "Learned %d%s peers from DHT",
636                      (int)n,
637                      event == DHT_EVENT_VALUES6 ? " IPv6" : "");
638        }
639        tr_sessionUnlock( session );
640    } else if( event == DHT_EVENT_SEARCH_DONE ||
641               event == DHT_EVENT_SEARCH_DONE6) {
642        tr_torrent * tor = tr_torrentFindFromHash( session, info_hash );
643        if( tor ) {
644            if( event == DHT_EVENT_SEARCH_DONE ) {
645                tr_torinf(tor, "DHT announce done");
646                tor->dhtAnnounceInProgress = 0;
647            } else {
648                tr_torinf(tor, "IPv6 DHT announce done");
649                tor->dhtAnnounce6InProgress = 0;
650            }
651        }
652    }
653}
654
655int
656tr_dhtAnnounce(tr_torrent *tor, int af, tr_bool announce)
657{
658    int rc, status, numnodes, ret = 0;
659
660    if( !tr_torrentAllowsDHT( tor ) )
661        return -1;
662
663    status = tr_dhtStatus( tor->session, af, &numnodes );
664
665    if( status == TR_DHT_STOPPED ) {
666        /* Let the caller believe everything is all right. */
667        return 1;
668    }
669
670    if(status >= TR_DHT_POOR ) {
671        rc = dht_search( tor->info.hash,
672                         announce ? tr_sessionGetPeerPort(session) : 0,
673                         af, callback, NULL);
674        if( rc >= 1 ) {
675            tr_torinf(tor, "Starting%s DHT announce (%s, %d nodes)",
676                      af == AF_INET6 ? " IPv6" : "",
677                      tr_dhtPrintableStatus(status), numnodes);
678            if(af == AF_INET)
679                tor->dhtAnnounceInProgress = TRUE;
680            else
681                tor->dhtAnnounce6InProgress = TRUE;
682            ret = 1;
683        } else {
684            tr_torerr(tor, "%sDHT announce failed, errno = %d (%s, %d nodes)",
685                      af == AF_INET6 ? "IPv6 " : "",
686                      errno, tr_dhtPrintableStatus(status), numnodes);
687        }
688    } else {
689        tr_tordbg(tor, "%sDHT not ready (%s, %d nodes)",
690                  af == AF_INET6 ? "IPv6 " : "",
691                  tr_dhtPrintableStatus(status), numnodes);
692    }
693
694    return ret;
695}
696
697static void
698event_callback(int s, short type, void *ignore UNUSED )
699{
700    struct event *event = (s == dht_socket) ? &dht_event : &dht6_event;
701    time_t tosleep;
702    static int count = 0;
703
704    if( dht_periodic( type == EV_READ, &tosleep, callback, NULL) < 0 ) {
705        if(errno == EINTR) {
706            tosleep = 0;
707        } else {
708            tr_nerr("DHT", "dht_periodic failed (errno = %d)", errno);
709            if(errno == EINVAL || errno == EFAULT)
710                    abort();
711            tosleep = 1;
712        }
713    }
714
715    /* Only do this once in a while.  Counting rather than measuring time
716       avoids a system call. */
717    count++;
718    if(count >= 20) {
719        rebind_ipv6(FALSE);
720        count = 0;
721    }
722
723    /* Being slightly late is fine,
724       and has the added benefit of adding some jitter. */
725    tr_timerAdd( event, tosleep, tr_cryptoWeakRandInt( 1000000 ) );
726}
727
728void
729dht_hash(void *hash_return, int hash_size,
730         const void *v1, int len1,
731         const void *v2, int len2,
732         const void *v3, int len3)
733{
734    unsigned char sha1[SHA_DIGEST_LENGTH];
735    tr_sha1( sha1, v1, len1, v2, len2, v3, len3, NULL );
736    memset( hash_return, 0, hash_size );
737    memcpy( hash_return, sha1, MIN( hash_size, SHA_DIGEST_LENGTH ) );
738}
739
740int
741dht_random_bytes( void * buf, size_t size )
742{
743    tr_cryptoRandBuf( buf, size );
744    return size;
745}
Note: See TracBrowser for help on using the repository browser.