2 * Copyright (c) 2009-2010 by Juliusz Chroboczek
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * $Id: tr-dht.c 12033 2011-02-24 15:42:04Z jordan $
31 #include <signal.h> /* sig_atomic_t */
33 #include <unistd.h> /* close() */
36 #define _WIN32_WINNT 0x0501 /* freeaddrinfo(),getaddrinfo(),getnameinfo() */
39 #include <sys/types.h>
40 #include <sys/socket.h> /* socket(), bind() */
42 #include <netinet/in.h> /* sockaddr_in */
46 #include <event2/event.h>
50 #include "transmission.h"
54 #include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
55 #include "platform.h" /* tr_threadNew() */
57 #include "torrent.h" /* tr_torrentFindFromHash() */
59 #include "trevent.h" /* tr_runInEventThread() */
62 static struct event
*dht_timer
= NULL
;
63 static unsigned char myid
[20];
64 static tr_session
*session
= NULL
;
66 static void timer_callback(int s
, short type
, void *ignore
);
68 struct bootstrap_closure
{
76 bootstrap_done( tr_session
*session
, int af
)
82 bootstrap_done(session
, AF_INET
) &&
83 bootstrap_done(session
, AF_INET6
);
85 status
= tr_dhtStatus(session
, af
, NULL
);
86 return status
== TR_DHT_STOPPED
|| status
>= TR_DHT_FIREWALLED
;
90 nap( int roughly_sec
)
92 const int roughly_msec
= roughly_sec
* 1000;
93 const int msec
= roughly_msec
/2 + tr_cryptoWeakRandInt(roughly_msec
);
98 bootstrap_af(tr_session
*session
)
100 if( bootstrap_done(session
, AF_INET6
) )
102 else if ( bootstrap_done(session
, AF_INET
) )
109 bootstrap_from_name( const char *name
, tr_port port
, int af
)
111 struct addrinfo hints
, *info
, *infop
;
115 memset(&hints
, 0, sizeof(hints
));
116 hints
.ai_socktype
= SOCK_DGRAM
;
117 hints
.ai_family
= af
;
118 /* No, just passing p + 1 to gai won't work. */
119 tr_snprintf(pp
, sizeof(pp
), "%d", (int)port
);
121 rc
= getaddrinfo(name
, pp
, &hints
, &info
);
123 tr_nerr("DHT", "%s:%s: %s", name
, pp
, gai_strerror(rc
));
129 dht_ping_node(infop
->ai_addr
, infop
->ai_addrlen
);
133 if(bootstrap_done(session
, af
))
135 infop
= infop
->ai_next
;
141 dht_bootstrap(void *closure
)
143 struct bootstrap_closure
*cl
= closure
;
145 int num
= cl
->len
/ 6, num6
= cl
->len6
/ 18;
147 if(session
!= cl
->session
)
151 tr_ninf( "DHT", "Bootstrapping from %d nodes", num
);
154 tr_ninf( "DHT", "Bootstrapping from %d IPv6 nodes", num6
);
157 for(i
= 0; i
< MAX(num
, num6
); i
++) {
158 if( i
< num
&& !bootstrap_done(cl
->session
, AF_INET
) ) {
160 struct tr_address addr
;
162 memset(&addr
, 0, sizeof(addr
));
163 addr
.type
= TR_AF_INET
;
164 memcpy(&addr
.addr
.addr4
, &cl
->nodes
[i
* 6], 4);
165 memcpy(&port
, &cl
->nodes
[i
* 6 + 4], 2);
167 tr_dhtAddNode(cl
->session
, &addr
, port
, 1);
169 if( i
< num6
&& !bootstrap_done(cl
->session
, AF_INET6
) ) {
171 struct tr_address addr
;
173 memset(&addr
, 0, sizeof(addr
));
174 addr
.type
= TR_AF_INET6
;
175 memcpy(&addr
.addr
.addr6
, &cl
->nodes6
[i
* 18], 16);
176 memcpy(&port
, &cl
->nodes6
[i
* 18 + 16], 2);
178 tr_dhtAddNode(cl
->session
, &addr
, port
, 1);
181 /* Our DHT code is able to take up to 9 nodes in a row without
182 dropping any. After that, it takes some time to split buckets.
183 So ping the first 8 nodes quickly, then slow down. */
189 if(bootstrap_done( session
, 0 ))
193 if(!bootstrap_done(cl
->session
, 0)) {
194 char *bootstrap_file
;
198 tr_buildPath(cl
->session
->configDir
, "dht.bootstrap", NULL
);
201 f
= fopen(bootstrap_file
, "rb");
203 tr_ninf("DHT", "Attempting manual bootstrap");
209 p
= fgets(buf
, 200, f
);
213 p
= memchr(buf
, ' ', strlen(buf
));
216 if(p
== NULL
|| port
<= 0 || port
>= 0x10000) {
217 tr_nerr("DHT", "Couldn't parse %s", buf
);
223 bootstrap_from_name( buf
, port
, bootstrap_af(session
) );
225 if(bootstrap_done(cl
->session
, 0))
230 tr_free( bootstrap_file
);
233 if(!bootstrap_done(cl
->session
, 0)) {
234 for(i
= 0; i
< 6; i
++) {
235 /* We don't want to abuse our bootstrap nodes, so be very
236 slow. The initial wait is to give other nodes a chance
237 to contact us before we attempt to contact a bootstrap
238 node, for example because we've just been restarted. */
240 if(bootstrap_done(cl
->session
, 0))
244 "Attempting bootstrap from dht.transmissionbt.com");
245 bootstrap_from_name( "dht.transmissionbt.com", 6881,
246 bootstrap_af(session
) );
251 tr_free( cl
->nodes
);
253 tr_free( cl
->nodes6
);
255 tr_ndbg( "DHT", "Finished bootstrapping" );
259 tr_dhtInit(tr_session
*ss
)
263 tr_bool have_id
= FALSE
;
265 uint8_t * nodes
= NULL
, * nodes6
= NULL
;
268 struct bootstrap_closure
* cl
;
270 if( session
) /* already initialized */
273 tr_ndbg( "DHT", "Initializing DHT" );
275 if( getenv( "TR_DHT_VERBOSE" ) != NULL
)
278 dat_file
= tr_buildPath( ss
->configDir
, "dht.dat", NULL
);
279 rc
= tr_bencLoadFile( &benc
, TR_FMT_BENC
, dat_file
);
282 have_id
= tr_bencDictFindRaw(&benc
, "id", &raw
, &len
);
283 if( have_id
&& len
==20 )
284 memcpy( myid
, raw
, len
);
285 if( ss
->udp_socket
>= 0 &&
286 tr_bencDictFindRaw( &benc
, "nodes", &raw
, &len
) && !(len
%6) ) {
287 nodes
= tr_memdup( raw
, len
);
289 if( ss
->udp6_socket
> 0 &&
290 tr_bencDictFindRaw( &benc
, "nodes6", &raw
, &len6
) && !(len6
%18) ) {
291 nodes6
= tr_memdup( raw
, len6
);
293 tr_bencFree( &benc
);
302 tr_ninf( "DHT", "Reusing old id" );
304 /* Note that DHT ids need to be distributed uniformly,
305 * so it should be something truly random. */
306 tr_ninf( "DHT", "Generating new id" );
307 tr_cryptoRandBuf( myid
, 20 );
310 rc
= dht_init( ss
->udp_socket
, ss
->udp6_socket
, myid
, NULL
);
316 cl
= tr_new( struct bootstrap_closure
, 1 );
317 cl
->session
= session
;
322 tr_threadNew( dht_bootstrap
, cl
);
324 dht_timer
= evtimer_new( session
->event_base
, timer_callback
, session
);
325 tr_timerAdd( dht_timer
, 0, tr_cryptoWeakRandInt( 1000000 ) );
327 tr_ndbg( "DHT", "DHT initialized" );
332 tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", errno
);
338 tr_dhtUninit(tr_session
*ss
)
343 tr_ndbg( "DHT", "Uninitializing DHT" );
345 event_free( dht_timer
);
348 /* Since we only save known good nodes, avoid erasing older data if we
349 don't know enough nodes. */
350 if(tr_dhtStatus(ss
, AF_INET
, NULL
) < TR_DHT_FIREWALLED
)
351 tr_ninf( "DHT", "Not saving nodes, DHT not ready" );
354 struct sockaddr_in sins
[300];
355 struct sockaddr_in6 sins6
[300];
356 char compact
[300 * 6], compact6
[300 * 18];
358 int i
, j
, num
= 300, num6
= 300;
359 int n
= dht_get_nodes(sins
, &num
, sins6
, &num6
);
361 tr_ninf( "DHT", "Saving %d (%d + %d) nodes", n
, num
, num6
);
364 for( i
=0; i
<num
; ++i
) {
365 memcpy( compact
+ j
, &sins
[i
].sin_addr
, 4 );
366 memcpy( compact
+ j
+ 4, &sins
[i
].sin_port
, 2 );
370 for( i
=0; i
<num6
; ++i
) {
371 memcpy( compact6
+ j
, &sins6
[i
].sin6_addr
, 16 );
372 memcpy( compact6
+ j
+ 16, &sins6
[i
].sin6_port
, 2 );
375 tr_bencInitDict( &benc
, 3 );
376 tr_bencDictAddRaw( &benc
, "id", myid
, 20 );
378 tr_bencDictAddRaw( &benc
, "nodes", compact
, num
* 6 );
380 tr_bencDictAddRaw( &benc
, "nodes6", compact6
, num6
* 18 );
381 dat_file
= tr_buildPath( ss
->configDir
, "dht.dat", NULL
);
382 tr_bencToFile( &benc
, TR_FMT_BENC
, dat_file
);
383 tr_bencFree( &benc
);
388 tr_ndbg("DHT", "Done uninitializing DHT");
394 tr_dhtEnabled( const tr_session
* ss
)
396 return ss
&& ( ss
== session
);
399 struct getstatus_closure
407 getstatus( void * cl
)
409 struct getstatus_closure
* closure
= cl
;
410 int good
, dubious
, incoming
;
412 dht_nodes( closure
->af
, &good
, &dubious
, NULL
, &incoming
);
414 closure
->count
= good
+ dubious
;
416 if( good
< 4 || good
+ dubious
<= 8 )
417 closure
->status
= TR_DHT_BROKEN
;
419 closure
->status
= TR_DHT_POOR
;
420 else if( incoming
< 8 )
421 closure
->status
= TR_DHT_FIREWALLED
;
423 closure
->status
= TR_DHT_GOOD
;
427 tr_dhtStatus( tr_session
* session
, int af
, int * nodes_return
)
429 struct getstatus_closure closure
= { af
, -1, -1 };
431 if( !tr_dhtEnabled( session
) ||
432 (af
== AF_INET
&& session
->udp_socket
< 0) ||
433 (af
== AF_INET6
&& session
->udp6_socket
< 0) ) {
436 return TR_DHT_STOPPED
;
439 tr_runInEventThread( session
, getstatus
, &closure
);
440 while( closure
.status
< 0 )
441 tr_wait_msec( 50 /*msec*/ );
444 *nodes_return
= closure
.count
;
446 return closure
.status
;
450 tr_dhtPort( tr_session
*ss
)
452 return tr_dhtEnabled( ss
) ? ss
->udp_port
: 0;
456 tr_dhtAddNode( tr_session
* ss
,
457 const tr_address
* address
,
461 int af
= address
->type
== TR_AF_INET
? AF_INET
: AF_INET6
;
463 if( !tr_dhtEnabled( ss
) )
466 /* Since we don't want to abuse our bootstrap nodes,
467 * we don't ping them if the DHT is in a good state. */
470 if(tr_dhtStatus(ss
, af
, NULL
) >= TR_DHT_FIREWALLED
)
474 if( address
->type
== TR_AF_INET
) {
475 struct sockaddr_in sin
;
476 memset(&sin
, 0, sizeof(sin
));
477 sin
.sin_family
= AF_INET
;
478 memcpy(&sin
.sin_addr
, &address
->addr
.addr4
, 4);
479 sin
.sin_port
= htons(port
);
480 dht_ping_node((struct sockaddr
*)&sin
, sizeof(sin
));
482 } else if( address
->type
== TR_AF_INET6
) {
483 struct sockaddr_in6 sin6
;
484 memset(&sin6
, 0, sizeof(sin6
));
485 sin6
.sin6_family
= AF_INET6
;
486 memcpy(&sin6
.sin6_addr
, &address
->addr
.addr6
, 16);
487 sin6
.sin6_port
= htons(port
);
488 dht_ping_node((struct sockaddr
*)&sin6
, sizeof(sin6
));
496 tr_dhtPrintableStatus(int status
)
499 case TR_DHT_STOPPED
: return "stopped";
500 case TR_DHT_BROKEN
: return "broken";
501 case TR_DHT_POOR
: return "poor";
502 case TR_DHT_FIREWALLED
: return "firewalled";
503 case TR_DHT_GOOD
: return "good";
504 default: return "???";
509 callback( void *ignore UNUSED
, int event
,
510 unsigned char *info_hash
, void *data
, size_t data_len
)
512 if( event
== DHT_EVENT_VALUES
|| event
== DHT_EVENT_VALUES6
) {
514 tr_sessionLock( session
);
515 tor
= tr_torrentFindFromHash( session
, info_hash
);
516 if( tor
&& tr_torrentAllowsDHT( tor
))
520 if( event
== DHT_EVENT_VALUES
)
521 pex
= tr_peerMgrCompactToPex(data
, data_len
, NULL
, 0, &n
);
523 pex
= tr_peerMgrCompact6ToPex(data
, data_len
, NULL
, 0, &n
);
525 tr_peerMgrAddPex( tor
, TR_PEER_FROM_DHT
, pex
+i
, -1 );
527 tr_tordbg(tor
, "Learned %d%s peers from DHT",
529 event
== DHT_EVENT_VALUES6
? " IPv6" : "");
531 tr_sessionUnlock( session
);
532 } else if( event
== DHT_EVENT_SEARCH_DONE
||
533 event
== DHT_EVENT_SEARCH_DONE6
) {
534 tr_torrent
* tor
= tr_torrentFindFromHash( session
, info_hash
);
536 if( event
== DHT_EVENT_SEARCH_DONE
) {
537 tr_torinf(tor
, "DHT announce done");
538 tor
->dhtAnnounceInProgress
= 0;
540 tr_torinf(tor
, "IPv6 DHT announce done");
541 tor
->dhtAnnounce6InProgress
= 0;
548 tr_dhtAnnounce(tr_torrent
*tor
, int af
, tr_bool announce
)
550 int rc
, status
, numnodes
, ret
= 0;
552 if( !tr_torrentAllowsDHT( tor
) )
555 status
= tr_dhtStatus( tor
->session
, af
, &numnodes
);
557 if( status
== TR_DHT_STOPPED
) {
558 /* Let the caller believe everything is all right. */
562 if(status
>= TR_DHT_POOR
) {
563 rc
= dht_search( tor
->info
.hash
,
564 announce
? tr_sessionGetPeerPort(session
) : 0,
567 tr_torinf(tor
, "Starting%s DHT announce (%s, %d nodes)",
568 af
== AF_INET6
? " IPv6" : "",
569 tr_dhtPrintableStatus(status
), numnodes
);
571 tor
->dhtAnnounceInProgress
= TRUE
;
573 tor
->dhtAnnounce6InProgress
= TRUE
;
576 tr_torerr(tor
, "%sDHT announce failed (%s, %d nodes): %s",
577 af
== AF_INET6
? "IPv6 " : "",
578 tr_dhtPrintableStatus(status
), numnodes
,
579 tr_strerror( errno
) );
582 tr_tordbg(tor
, "%sDHT not ready (%s, %d nodes)",
583 af
== AF_INET6
? "IPv6 " : "",
584 tr_dhtPrintableStatus(status
), numnodes
);
591 tr_dhtCallback(unsigned char *buf
, int buflen
,
592 struct sockaddr
*from
, socklen_t fromlen
,
598 assert(tr_isSession(sv
));
603 rc
= dht_periodic( buf
, buflen
, from
, fromlen
,
604 &tosleep
, callback
, NULL
);
609 tr_nerr( "DHT", "dht_periodic failed: %s", tr_strerror( errno
) );
610 if(errno
== EINVAL
|| errno
== EFAULT
)
616 /* Being slightly late is fine,
617 and has the added benefit of adding some jitter. */
618 tr_timerAdd( dht_timer
, tosleep
, tr_cryptoWeakRandInt( 1000000 ) );
622 timer_callback(int s UNUSED
, short type UNUSED
, void *session
)
624 tr_dhtCallback(NULL
, 0, NULL
, 0, session
);
629 dht_hash(void *hash_return
, int hash_size
,
630 const void *v1
, int len1
,
631 const void *v2
, int len2
,
632 const void *v3
, int len3
)
634 unsigned char sha1
[SHA_DIGEST_LENGTH
];
635 tr_sha1( sha1
, v1
, len1
, v2
, len2
, v3
, len3
, NULL
);
636 memset( hash_return
, 0, hash_size
);
637 memcpy( hash_return
, sha1
, MIN( hash_size
, SHA_DIGEST_LENGTH
) );
641 dht_random_bytes( void * buf
, size_t size
)
643 tr_cryptoRandBuf( buf
, size
);