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 12543 2011-07-12 12:26:24Z jordan $
29 #include <string.h> /* memcpy(), memset(), memchr(), strlen() */
30 #include <stdlib.h> /* atoi() */
33 #include <signal.h> /* sig_atomic_t */
35 #include <unistd.h> /* close() */
38 #define _WIN32_WINNT 0x0501 /* freeaddrinfo(),getaddrinfo(),getnameinfo() */
41 #include <sys/types.h>
42 #include <sys/socket.h> /* socket(), bind() */
44 #include <netinet/in.h> /* sockaddr_in */
48 #include <event2/event.h>
52 #include "transmission.h"
56 #include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
57 #include "platform.h" /* tr_threadNew() */
59 #include "torrent.h" /* tr_torrentFindFromHash() */
61 #include "trevent.h" /* tr_runInEventThread() */
64 static struct event
*dht_timer
= NULL
;
65 static unsigned char myid
[20];
66 static tr_session
*session
= NULL
;
68 static void timer_callback(int s
, short type
, void *ignore
);
70 struct bootstrap_closure
{
78 bootstrap_done( tr_session
*session
, int af
)
84 bootstrap_done(session
, AF_INET
) &&
85 bootstrap_done(session
, AF_INET6
);
87 status
= tr_dhtStatus(session
, af
, NULL
);
88 return status
== TR_DHT_STOPPED
|| status
>= TR_DHT_FIREWALLED
;
92 nap( int roughly_sec
)
94 const int roughly_msec
= roughly_sec
* 1000;
95 const int msec
= roughly_msec
/2 + tr_cryptoWeakRandInt(roughly_msec
);
100 bootstrap_af(tr_session
*session
)
102 if( bootstrap_done(session
, AF_INET6
) )
104 else if ( bootstrap_done(session
, AF_INET
) )
111 bootstrap_from_name( const char *name
, tr_port port
, int af
)
113 struct addrinfo hints
, *info
, *infop
;
117 memset(&hints
, 0, sizeof(hints
));
118 hints
.ai_socktype
= SOCK_DGRAM
;
119 hints
.ai_family
= af
;
120 /* No, just passing p + 1 to gai won't work. */
121 tr_snprintf(pp
, sizeof(pp
), "%d", (int)port
);
123 rc
= getaddrinfo(name
, pp
, &hints
, &info
);
125 tr_nerr("DHT", "%s:%s: %s", name
, pp
, gai_strerror(rc
));
131 dht_ping_node(infop
->ai_addr
, infop
->ai_addrlen
);
135 if(bootstrap_done(session
, af
))
137 infop
= infop
->ai_next
;
143 dht_bootstrap(void *closure
)
145 struct bootstrap_closure
*cl
= closure
;
147 int num
= cl
->len
/ 6, num6
= cl
->len6
/ 18;
149 if(session
!= cl
->session
)
153 tr_ninf( "DHT", "Bootstrapping from %d nodes", num
);
156 tr_ninf( "DHT", "Bootstrapping from %d IPv6 nodes", num6
);
159 for(i
= 0; i
< MAX(num
, num6
); i
++) {
160 if( i
< num
&& !bootstrap_done(cl
->session
, AF_INET
) ) {
162 struct tr_address addr
;
164 memset(&addr
, 0, sizeof(addr
));
165 addr
.type
= TR_AF_INET
;
166 memcpy(&addr
.addr
.addr4
, &cl
->nodes
[i
* 6], 4);
167 memcpy(&port
, &cl
->nodes
[i
* 6 + 4], 2);
169 tr_dhtAddNode(cl
->session
, &addr
, port
, 1);
171 if( i
< num6
&& !bootstrap_done(cl
->session
, AF_INET6
) ) {
173 struct tr_address addr
;
175 memset(&addr
, 0, sizeof(addr
));
176 addr
.type
= TR_AF_INET6
;
177 memcpy(&addr
.addr
.addr6
, &cl
->nodes6
[i
* 18], 16);
178 memcpy(&port
, &cl
->nodes6
[i
* 18 + 16], 2);
180 tr_dhtAddNode(cl
->session
, &addr
, port
, 1);
183 /* Our DHT code is able to take up to 9 nodes in a row without
184 dropping any. After that, it takes some time to split buckets.
185 So ping the first 8 nodes quickly, then slow down. */
191 if(bootstrap_done( session
, 0 ))
195 if(!bootstrap_done(cl
->session
, 0)) {
196 char *bootstrap_file
;
200 tr_buildPath(cl
->session
->configDir
, "dht.bootstrap", NULL
);
203 f
= fopen(bootstrap_file
, "rb");
205 tr_ninf("DHT", "Attempting manual bootstrap");
211 p
= fgets(buf
, 200, f
);
215 p
= memchr(buf
, ' ', strlen(buf
));
218 if(p
== NULL
|| port
<= 0 || port
>= 0x10000) {
219 tr_nerr("DHT", "Couldn't parse %s", buf
);
225 bootstrap_from_name( buf
, port
, bootstrap_af(session
) );
227 if(bootstrap_done(cl
->session
, 0))
233 tr_free( bootstrap_file
);
236 if(!bootstrap_done(cl
->session
, 0)) {
237 for(i
= 0; i
< 6; i
++) {
238 /* We don't want to abuse our bootstrap nodes, so be very
239 slow. The initial wait is to give other nodes a chance
240 to contact us before we attempt to contact a bootstrap
241 node, for example because we've just been restarted. */
243 if(bootstrap_done(cl
->session
, 0))
247 "Attempting bootstrap from dht.transmissionbt.com");
248 bootstrap_from_name( "dht.transmissionbt.com", 6881,
249 bootstrap_af(session
) );
254 tr_free( cl
->nodes
);
256 tr_free( cl
->nodes6
);
258 tr_ndbg( "DHT", "Finished bootstrapping" );
262 tr_dhtInit(tr_session
*ss
)
266 bool have_id
= false;
268 uint8_t * nodes
= NULL
, * nodes6
= NULL
;
271 struct bootstrap_closure
* cl
;
273 if( session
) /* already initialized */
276 tr_ndbg( "DHT", "Initializing DHT" );
278 if( getenv( "TR_DHT_VERBOSE" ) != NULL
)
281 dat_file
= tr_buildPath( ss
->configDir
, "dht.dat", NULL
);
282 rc
= tr_bencLoadFile( &benc
, TR_FMT_BENC
, dat_file
);
285 have_id
= tr_bencDictFindRaw(&benc
, "id", &raw
, &len
);
286 if( have_id
&& len
==20 )
287 memcpy( myid
, raw
, len
);
288 if( ss
->udp_socket
>= 0 &&
289 tr_bencDictFindRaw( &benc
, "nodes", &raw
, &len
) && !(len
%6) ) {
290 nodes
= tr_memdup( raw
, len
);
292 if( ss
->udp6_socket
> 0 &&
293 tr_bencDictFindRaw( &benc
, "nodes6", &raw
, &len6
) && !(len6
%18) ) {
294 nodes6
= tr_memdup( raw
, len6
);
296 tr_bencFree( &benc
);
305 tr_ninf( "DHT", "Reusing old id" );
307 /* Note that DHT ids need to be distributed uniformly,
308 * so it should be something truly random. */
309 tr_ninf( "DHT", "Generating new id" );
310 tr_cryptoRandBuf( myid
, 20 );
313 rc
= dht_init( ss
->udp_socket
, ss
->udp6_socket
, myid
, NULL
);
319 cl
= tr_new( struct bootstrap_closure
, 1 );
320 cl
->session
= session
;
325 tr_threadNew( dht_bootstrap
, cl
);
327 dht_timer
= evtimer_new( session
->event_base
, timer_callback
, session
);
328 tr_timerAdd( dht_timer
, 0, tr_cryptoWeakRandInt( 1000000 ) );
330 tr_ndbg( "DHT", "DHT initialized" );
335 tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", errno
);
341 tr_dhtUninit(tr_session
*ss
)
346 tr_ndbg( "DHT", "Uninitializing DHT" );
348 if( dht_timer
!= NULL
) {
349 event_free( dht_timer
);
353 /* Since we only save known good nodes, avoid erasing older data if we
354 don't know enough nodes. */
355 if(tr_dhtStatus(ss
, AF_INET
, NULL
) < TR_DHT_FIREWALLED
)
356 tr_ninf( "DHT", "Not saving nodes, DHT not ready" );
359 struct sockaddr_in sins
[300];
360 struct sockaddr_in6 sins6
[300];
361 char compact
[300 * 6], compact6
[300 * 18];
363 int i
, j
, num
= 300, num6
= 300;
364 int n
= dht_get_nodes(sins
, &num
, sins6
, &num6
);
366 tr_ninf( "DHT", "Saving %d (%d + %d) nodes", n
, num
, num6
);
369 for( i
=0; i
<num
; ++i
) {
370 memcpy( compact
+ j
, &sins
[i
].sin_addr
, 4 );
371 memcpy( compact
+ j
+ 4, &sins
[i
].sin_port
, 2 );
375 for( i
=0; i
<num6
; ++i
) {
376 memcpy( compact6
+ j
, &sins6
[i
].sin6_addr
, 16 );
377 memcpy( compact6
+ j
+ 16, &sins6
[i
].sin6_port
, 2 );
380 tr_bencInitDict( &benc
, 3 );
381 tr_bencDictAddRaw( &benc
, "id", myid
, 20 );
383 tr_bencDictAddRaw( &benc
, "nodes", compact
, num
* 6 );
385 tr_bencDictAddRaw( &benc
, "nodes6", compact6
, num6
* 18 );
386 dat_file
= tr_buildPath( ss
->configDir
, "dht.dat", NULL
);
387 tr_bencToFile( &benc
, TR_FMT_BENC
, dat_file
);
388 tr_bencFree( &benc
);
393 tr_ndbg("DHT", "Done uninitializing DHT");
399 tr_dhtEnabled( const tr_session
* ss
)
401 return ss
&& ( ss
== session
);
404 struct getstatus_closure
412 getstatus( void * cl
)
414 struct getstatus_closure
* closure
= cl
;
415 int good
, dubious
, incoming
;
417 dht_nodes( closure
->af
, &good
, &dubious
, NULL
, &incoming
);
419 closure
->count
= good
+ dubious
;
421 if( good
< 4 || good
+ dubious
<= 8 )
422 closure
->status
= TR_DHT_BROKEN
;
424 closure
->status
= TR_DHT_POOR
;
425 else if( incoming
< 8 )
426 closure
->status
= TR_DHT_FIREWALLED
;
428 closure
->status
= TR_DHT_GOOD
;
432 tr_dhtStatus( tr_session
* session
, int af
, int * nodes_return
)
434 struct getstatus_closure closure
= { af
, -1, -1 };
436 if( !tr_dhtEnabled( session
) ||
437 (af
== AF_INET
&& session
->udp_socket
< 0) ||
438 (af
== AF_INET6
&& session
->udp6_socket
< 0) ) {
441 return TR_DHT_STOPPED
;
444 tr_runInEventThread( session
, getstatus
, &closure
);
445 while( closure
.status
< 0 )
446 tr_wait_msec( 50 /*msec*/ );
449 *nodes_return
= closure
.count
;
451 return closure
.status
;
455 tr_dhtPort( tr_session
*ss
)
457 return tr_dhtEnabled( ss
) ? ss
->udp_port
: 0;
461 tr_dhtAddNode( tr_session
* ss
,
462 const tr_address
* address
,
466 int af
= address
->type
== TR_AF_INET
? AF_INET
: AF_INET6
;
468 if( !tr_dhtEnabled( ss
) )
471 /* Since we don't want to abuse our bootstrap nodes,
472 * we don't ping them if the DHT is in a good state. */
475 if(tr_dhtStatus(ss
, af
, NULL
) >= TR_DHT_FIREWALLED
)
479 if( address
->type
== TR_AF_INET
) {
480 struct sockaddr_in sin
;
481 memset(&sin
, 0, sizeof(sin
));
482 sin
.sin_family
= AF_INET
;
483 memcpy(&sin
.sin_addr
, &address
->addr
.addr4
, 4);
484 sin
.sin_port
= htons(port
);
485 dht_ping_node((struct sockaddr
*)&sin
, sizeof(sin
));
487 } else if( address
->type
== TR_AF_INET6
) {
488 struct sockaddr_in6 sin6
;
489 memset(&sin6
, 0, sizeof(sin6
));
490 sin6
.sin6_family
= AF_INET6
;
491 memcpy(&sin6
.sin6_addr
, &address
->addr
.addr6
, 16);
492 sin6
.sin6_port
= htons(port
);
493 dht_ping_node((struct sockaddr
*)&sin6
, sizeof(sin6
));
501 tr_dhtPrintableStatus(int status
)
504 case TR_DHT_STOPPED
: return "stopped";
505 case TR_DHT_BROKEN
: return "broken";
506 case TR_DHT_POOR
: return "poor";
507 case TR_DHT_FIREWALLED
: return "firewalled";
508 case TR_DHT_GOOD
: return "good";
509 default: return "???";
514 callback( void *ignore UNUSED
, int event
,
515 unsigned char *info_hash
, void *data
, size_t data_len
)
517 if( event
== DHT_EVENT_VALUES
|| event
== DHT_EVENT_VALUES6
) {
519 tr_sessionLock( session
);
520 tor
= tr_torrentFindFromHash( session
, info_hash
);
521 if( tor
&& tr_torrentAllowsDHT( tor
))
525 if( event
== DHT_EVENT_VALUES
)
526 pex
= tr_peerMgrCompactToPex(data
, data_len
, NULL
, 0, &n
);
528 pex
= tr_peerMgrCompact6ToPex(data
, data_len
, NULL
, 0, &n
);
530 tr_peerMgrAddPex( tor
, TR_PEER_FROM_DHT
, pex
+i
, -1 );
532 tr_tordbg(tor
, "Learned %d%s peers from DHT",
534 event
== DHT_EVENT_VALUES6
? " IPv6" : "");
536 tr_sessionUnlock( session
);
537 } else if( event
== DHT_EVENT_SEARCH_DONE
||
538 event
== DHT_EVENT_SEARCH_DONE6
) {
539 tr_torrent
* tor
= tr_torrentFindFromHash( session
, info_hash
);
541 if( event
== DHT_EVENT_SEARCH_DONE
) {
542 tr_torinf(tor
, "DHT announce done");
543 tor
->dhtAnnounceInProgress
= 0;
545 tr_torinf(tor
, "IPv6 DHT announce done");
546 tor
->dhtAnnounce6InProgress
= 0;
553 tr_dhtAnnounce(tr_torrent
*tor
, int af
, bool announce
)
555 int rc
, status
, numnodes
, ret
= 0;
557 if( !tr_torrentAllowsDHT( tor
) )
560 status
= tr_dhtStatus( tor
->session
, af
, &numnodes
);
562 if( status
== TR_DHT_STOPPED
) {
563 /* Let the caller believe everything is all right. */
567 if(status
>= TR_DHT_POOR
) {
568 rc
= dht_search( tor
->info
.hash
,
569 announce
? tr_sessionGetPeerPort(session
) : 0,
572 tr_torinf(tor
, "Starting%s DHT announce (%s, %d nodes)",
573 af
== AF_INET6
? " IPv6" : "",
574 tr_dhtPrintableStatus(status
), numnodes
);
576 tor
->dhtAnnounceInProgress
= true;
578 tor
->dhtAnnounce6InProgress
= true;
581 tr_torerr(tor
, "%sDHT announce failed (%s, %d nodes): %s",
582 af
== AF_INET6
? "IPv6 " : "",
583 tr_dhtPrintableStatus(status
), numnodes
,
584 tr_strerror( errno
) );
587 tr_tordbg(tor
, "%sDHT not ready (%s, %d nodes)",
588 af
== AF_INET6
? "IPv6 " : "",
589 tr_dhtPrintableStatus(status
), numnodes
);
596 tr_dhtUpkeep( tr_session
* session
)
598 tr_torrent
* tor
= NULL
;
599 const time_t now
= tr_time( );
601 while(( tor
= tr_torrentNext( session
, tor
)))
603 if( !tor
->isRunning
|| !tr_torrentAllowsDHT( tor
) )
606 if( tor
->dhtAnnounceAt
<= now
)
608 const int rc
= tr_dhtAnnounce(tor
, AF_INET
, 1);
610 tor
->dhtAnnounceAt
= now
+ ((rc
== 0)
611 ? 5 + tr_cryptoWeakRandInt( 5 )
612 : 25 * 60 + tr_cryptoWeakRandInt( 3*60 ));
615 if( tor
->dhtAnnounce6At
<= now
)
617 const int rc
= tr_dhtAnnounce(tor
, AF_INET6
, 1);
619 tor
->dhtAnnounce6At
= now
+ ((rc
== 0)
620 ? 5 + tr_cryptoWeakRandInt( 5 )
621 : 25 * 60 + tr_cryptoWeakRandInt( 3*60 ));
627 tr_dhtCallback(unsigned char *buf
, int buflen
,
628 struct sockaddr
*from
, socklen_t fromlen
,
634 assert(tr_isSession(sv
));
639 rc
= dht_periodic( buf
, buflen
, from
, fromlen
,
640 &tosleep
, callback
, NULL
);
645 tr_nerr( "DHT", "dht_periodic failed: %s", tr_strerror( errno
) );
646 if(errno
== EINVAL
|| errno
== EFAULT
)
652 /* Being slightly late is fine,
653 and has the added benefit of adding some jitter. */
654 tr_timerAdd( dht_timer
, tosleep
, tr_cryptoWeakRandInt( 1000000 ) );
658 timer_callback(int s UNUSED
, short type UNUSED
, void *session
)
660 tr_dhtCallback(NULL
, 0, NULL
, 0, session
);
665 dht_hash(void *hash_return
, int hash_size
,
666 const void *v1
, int len1
,
667 const void *v2
, int len2
,
668 const void *v3
, int len3
)
670 unsigned char sha1
[SHA_DIGEST_LENGTH
];
671 tr_sha1( sha1
, v1
, len1
, v2
, len2
, v3
, len3
, NULL
);
672 memset( hash_return
, 0, hash_size
);
673 memcpy( hash_return
, sha1
, MIN( hash_size
, SHA_DIGEST_LENGTH
) );
677 dht_random_bytes( void * buf
, size_t size
)
679 tr_cryptoRandBuf( buf
, size
);