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

Last change on this file since 11588 was 11588, checked in by charles, 11 years ago

(trunk libT) #3836 "libevent2 support" -- finish moving to the libevent2 API mode. don't include the backwards-compatable API headers.

  • 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 11588 2010-12-24 08:58:41Z 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 <event2/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
62static int dht_socket = -1, dht6_socket = -1;
63static struct event * dht_event = NULL;
64static struct event * dht6_event = NULL;
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    struct bootstrap_closure * cl;
329
330    if( session ) /* already initialized */
331        return -1;
332
333    dht_port = tr_sessionGetPeerPort(ss);
334    if(dht_port <= 0)
335        return -1;
336
337    tr_ndbg( "DHT", "Initializing DHT" );
338
339    dht_socket = socket(PF_INET, SOCK_DGRAM, 0);
340    if(dht_socket < 0)
341        goto fail;
342
343    memset(&sin, 0, sizeof(sin));
344    sin.sin_family = AF_INET;
345    memcpy(&sin.sin_addr, &tr_addr->addr.addr4, sizeof (struct in_addr));
346    sin.sin_port = htons(dht_port);
347    rc = bind(dht_socket, (struct sockaddr*)&sin, sizeof(sin));
348    if(rc < 0)
349        goto fail;
350
351    if(tr_globalIPv6())
352        rebind_ipv6(TRUE);
353
354    if( getenv( "TR_DHT_VERBOSE" ) != NULL )
355        dht_debug = stderr;
356
357    dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL );
358    rc = tr_bencLoadFile( &benc, TR_FMT_BENC, dat_file );
359    tr_free( dat_file );
360    if(rc == 0) {
361        have_id = tr_bencDictFindRaw(&benc, "id", &raw, &len);
362        if( have_id && len==20 )
363            memcpy( myid, raw, len );
364        if( dht_socket >= 0 &&
365            tr_bencDictFindRaw( &benc, "nodes", &raw, &len ) && !(len%6) ) {
366                nodes = tr_memdup( raw, len );
367        }
368        if( dht6_socket > 0 &&
369            tr_bencDictFindRaw( &benc, "nodes6", &raw, &len6 ) && !(len6%18) ) {
370            nodes6 = tr_memdup( raw, len6 );
371        }
372        tr_bencFree( &benc );
373    }
374
375    if(nodes == NULL)
376        len = 0;
377    if(nodes6 == NULL)
378        len6 = 0;
379
380    if( have_id )
381        tr_ninf( "DHT", "Reusing old id" );
382    else {
383        /* Note that DHT ids need to be distributed uniformly,
384         * so it should be something truly random. */
385        tr_ninf( "DHT", "Generating new id" );
386        tr_cryptoRandBuf( myid, 20 );
387    }
388
389    rc = dht_init( dht_socket, dht6_socket, myid, NULL );
390    if( rc < 0 )
391        goto fail;
392
393    session = ss;
394
395    cl = tr_new( struct bootstrap_closure, 1 );
396    cl->session = session;
397    cl->nodes = nodes;
398    cl->nodes6 = nodes6;
399    cl->len = len;
400    cl->len6 = len6;
401    tr_threadNew( dht_bootstrap, cl );
402
403    dht_event = event_new( session->event_base, dht_socket, EV_READ, event_callback, NULL );
404    tr_timerAdd( dht_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
405
406    if( dht6_socket >= 0 )
407    {
408        dht6_event = event_new( session->event_base, dht6_socket, EV_READ, event_callback, NULL );
409        tr_timerAdd( dht6_event, 0, tr_cryptoWeakRandInt( 1000000 ) );
410    }
411
412    tr_ndbg( "DHT", "DHT initialized" );
413
414    return 1;
415
416    fail:
417    {
418        const int save = errno;
419        close(dht_socket);
420        if( dht6_socket >= 0 )
421            close(dht6_socket);
422        dht_socket = dht6_socket = -1;
423        session = NULL;
424        tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", save );
425        errno = save;
426    }
427
428    return -1;
429}
430
431void
432tr_dhtUninit(tr_session *ss)
433{
434    if(session != ss)
435        return;
436
437    tr_ndbg( "DHT", "Uninitializing DHT" );
438
439    event_free( dht_event );
440    dht_event = NULL;
441
442    if( dht6_event ) {
443        event_free( dht6_event );
444        dht6_event = NULL;
445    }
446
447    /* Since we only save known good nodes, avoid erasing older data if we
448       don't know enough nodes. */
449    if(tr_dhtStatus(ss, AF_INET, NULL) < TR_DHT_FIREWALLED)
450        tr_ninf( "DHT", "Not saving nodes, DHT not ready" );
451    else {
452        tr_benc benc;
453        struct sockaddr_in sins[300];
454        struct sockaddr_in6 sins6[300];
455        char compact[300 * 6], compact6[300 * 18];
456        char *dat_file;
457        int i, j, num = 300, num6 = 300;
458        int n = dht_get_nodes(sins, &num, sins6, &num6);
459
460        tr_ninf( "DHT", "Saving %d (%d + %d) nodes", n, num, num6 );
461
462        j = 0;
463        for( i=0; i<num; ++i ) {
464            memcpy( compact + j, &sins[i].sin_addr, 4 );
465            memcpy( compact + j + 4, &sins[i].sin_port, 2 );
466            j += 6;
467        }
468        j = 0;
469        for( i=0; i<num6; ++i ) {
470            memcpy( compact6 + j, &sins6[i].sin6_addr, 16 );
471            memcpy( compact6 + j + 16, &sins6[i].sin6_port, 2 );
472            j += 18;
473        }
474        tr_bencInitDict( &benc, 3 );
475        tr_bencDictAddRaw( &benc, "id", myid, 20 );
476        if(num > 0)
477            tr_bencDictAddRaw( &benc, "nodes", compact, num * 6 );
478        if(num6 > 0)
479            tr_bencDictAddRaw( &benc, "nodes6", compact6, num6 * 18 );
480        dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL );
481        tr_bencToFile( &benc, TR_FMT_BENC, dat_file );
482        tr_bencFree( &benc );
483        tr_free( dat_file );
484    }
485
486    dht_uninit( 1 );
487    tr_netCloseSocket( dht_socket );
488    dht_socket = -1;
489    if(dht6_socket > 0) {
490        tr_netCloseSocket( dht6_socket );
491        dht6_socket = -1;
492    }
493
494    tr_ndbg("DHT", "Done uninitializing DHT");
495
496    session = NULL;
497}
498
499tr_bool
500tr_dhtEnabled( const tr_session * ss )
501{
502    return ss && ( ss == session );
503}
504
505struct getstatus_closure
506{
507    int af;
508    sig_atomic_t status;
509    sig_atomic_t count;
510};
511
512static void
513getstatus( void * cl )
514{
515    struct getstatus_closure * closure = cl;
516    int good, dubious, incoming;
517
518    dht_nodes( closure->af, &good, &dubious, NULL, &incoming );
519
520    closure->count = good + dubious;
521
522    if( good < 4 || good + dubious <= 8 )
523        closure->status = TR_DHT_BROKEN;
524    else if( good < 40 )
525        closure->status = TR_DHT_POOR;
526    else if( incoming < 8 )
527        closure->status = TR_DHT_FIREWALLED;
528    else
529        closure->status = TR_DHT_GOOD;
530}
531
532int
533tr_dhtStatus( tr_session * session, int af, int * nodes_return )
534{
535    struct getstatus_closure closure = { af, -1, -1 };
536
537    if( !tr_dhtEnabled( session ) ||
538        (af == AF_INET && dht_socket < 0) ||
539        (af == AF_INET6 && dht6_socket < 0) ) {
540        if( nodes_return )
541            *nodes_return = 0;
542        return TR_DHT_STOPPED;
543    }
544
545    tr_runInEventThread( session, getstatus, &closure );
546    while( closure.status < 0 )
547        tr_wait_msec( 50 /*msec*/ );
548
549    if( nodes_return )
550        *nodes_return = closure.count;
551
552    return closure.status;
553}
554
555tr_port
556tr_dhtPort( tr_session *ss )
557{
558    return tr_dhtEnabled( ss ) ? dht_port : 0;
559}
560
561int
562tr_dhtAddNode( tr_session       * ss,
563               const tr_address * address,
564               tr_port            port,
565               tr_bool            bootstrap )
566{
567    int af = address->type == TR_AF_INET ? AF_INET : AF_INET6;
568
569    if( !tr_dhtEnabled( ss ) )
570        return 0;
571
572    /* Since we don't want to abuse our bootstrap nodes,
573     * we don't ping them if the DHT is in a good state. */
574
575    if(bootstrap) {
576        if(tr_dhtStatus(ss, af, NULL) >= TR_DHT_FIREWALLED)
577            return 0;
578    }
579
580    if( address->type == TR_AF_INET ) {
581        struct sockaddr_in sin;
582        memset(&sin, 0, sizeof(sin));
583        sin.sin_family = AF_INET;
584        memcpy(&sin.sin_addr, &address->addr.addr4, 4);
585        sin.sin_port = htons(port);
586        dht_ping_node((struct sockaddr*)&sin, sizeof(sin));
587        return 1;
588    } else if( address->type == TR_AF_INET6 ) {
589        struct sockaddr_in6 sin6;
590        memset(&sin6, 0, sizeof(sin6));
591        sin6.sin6_family = AF_INET6;
592        memcpy(&sin6.sin6_addr, &address->addr.addr6, 16);
593        sin6.sin6_port = htons(port);
594        dht_ping_node((struct sockaddr*)&sin6, sizeof(sin6));
595        return 1;
596    }
597
598    return 0;
599}
600
601const char *
602tr_dhtPrintableStatus(int status)
603{
604    switch(status) {
605    case TR_DHT_STOPPED: return "stopped";
606    case TR_DHT_BROKEN: return "broken";
607    case TR_DHT_POOR: return "poor";
608    case TR_DHT_FIREWALLED: return "firewalled";
609    case TR_DHT_GOOD: return "good";
610    default: return "???";
611    }
612}
613
614static void
615callback( void *ignore UNUSED, int event,
616          unsigned char *info_hash, void *data, size_t data_len )
617{
618    if( event == DHT_EVENT_VALUES || event == DHT_EVENT_VALUES6 ) {
619        tr_torrent *tor;
620        tr_sessionLock( session );
621        tor = tr_torrentFindFromHash( session, info_hash );
622        if( tor && tr_torrentAllowsDHT( tor ))
623        {
624            size_t i, n;
625            tr_pex * pex;
626            if( event == DHT_EVENT_VALUES )
627                pex = tr_peerMgrCompactToPex(data, data_len, NULL, 0, &n);
628            else
629                pex = tr_peerMgrCompact6ToPex(data, data_len, NULL, 0, &n);
630            for( i=0; i<n; ++i )
631                tr_peerMgrAddPex( tor, TR_PEER_FROM_DHT, pex+i, -1 );
632            tr_free(pex);
633            tr_tordbg(tor, "Learned %d%s peers from DHT",
634                      (int)n,
635                      event == DHT_EVENT_VALUES6 ? " IPv6" : "");
636        }
637        tr_sessionUnlock( session );
638    } else if( event == DHT_EVENT_SEARCH_DONE ||
639               event == DHT_EVENT_SEARCH_DONE6) {
640        tr_torrent * tor = tr_torrentFindFromHash( session, info_hash );
641        if( tor ) {
642            if( event == DHT_EVENT_SEARCH_DONE ) {
643                tr_torinf(tor, "DHT announce done");
644                tor->dhtAnnounceInProgress = 0;
645            } else {
646                tr_torinf(tor, "IPv6 DHT announce done");
647                tor->dhtAnnounce6InProgress = 0;
648            }
649        }
650    }
651}
652
653int
654tr_dhtAnnounce(tr_torrent *tor, int af, tr_bool announce)
655{
656    int rc, status, numnodes, ret = 0;
657
658    if( !tr_torrentAllowsDHT( tor ) )
659        return -1;
660
661    status = tr_dhtStatus( tor->session, af, &numnodes );
662
663    if( status == TR_DHT_STOPPED ) {
664        /* Let the caller believe everything is all right. */
665        return 1;
666    }
667
668    if(status >= TR_DHT_POOR ) {
669        rc = dht_search( tor->info.hash,
670                         announce ? tr_sessionGetPeerPort(session) : 0,
671                         af, callback, NULL);
672        if( rc >= 1 ) {
673            tr_torinf(tor, "Starting%s DHT announce (%s, %d nodes)",
674                      af == AF_INET6 ? " IPv6" : "",
675                      tr_dhtPrintableStatus(status), numnodes);
676            if(af == AF_INET)
677                tor->dhtAnnounceInProgress = TRUE;
678            else
679                tor->dhtAnnounce6InProgress = TRUE;
680            ret = 1;
681        } else {
682            tr_torerr(tor, "%sDHT announce failed, errno = %d (%s, %d nodes)",
683                      af == AF_INET6 ? "IPv6 " : "",
684                      errno, tr_dhtPrintableStatus(status), numnodes);
685        }
686    } else {
687        tr_tordbg(tor, "%sDHT not ready (%s, %d nodes)",
688                  af == AF_INET6 ? "IPv6 " : "",
689                  tr_dhtPrintableStatus(status), numnodes);
690    }
691
692    return ret;
693}
694
695static void
696event_callback(int s, short type, void *ignore UNUSED )
697{
698    struct event *event = (s == dht_socket) ? dht_event : dht6_event;
699    time_t tosleep;
700    static int count = 0;
701
702    if( dht_periodic( type == EV_READ, &tosleep, callback, NULL) < 0 ) {
703        if(errno == EINTR) {
704            tosleep = 0;
705        } else {
706            tr_nerr("DHT", "dht_periodic failed (errno = %d)", errno);
707            if(errno == EINVAL || errno == EFAULT)
708                    abort();
709            tosleep = 1;
710        }
711    }
712
713    /* Only do this once in a while.  Counting rather than measuring time
714       avoids a system call. */
715    count++;
716    if(count >= 20) {
717        rebind_ipv6(FALSE);
718        count = 0;
719    }
720
721    /* Being slightly late is fine,
722       and has the added benefit of adding some jitter. */
723    tr_timerAdd( event, tosleep, tr_cryptoWeakRandInt( 1000000 ) );
724}
725
726void
727dht_hash(void *hash_return, int hash_size,
728         const void *v1, int len1,
729         const void *v2, int len2,
730         const void *v3, int len3)
731{
732    unsigned char sha1[SHA_DIGEST_LENGTH];
733    tr_sha1( sha1, v1, len1, v2, len2, v3, len3, NULL );
734    memset( hash_return, 0, hash_size );
735    memcpy( hash_return, sha1, MIN( hash_size, SHA_DIGEST_LENGTH ) );
736}
737
738int
739dht_random_bytes( void * buf, size_t size )
740{
741    tr_cryptoRandBuf( buf, size );
742    return size;
743}
Note: See TracBrowser for help on using the repository browser.