transmission: update from 2.13 to 2.22
[tomato.git] / release / src / router / transmission / libtransmission / tr-dht.c
blob4d78c52ac46a9323f6fd98719093efcc3815e0d4
1 /*
2 * Copyright (c) 2009-2010 by Juliusz Chroboczek
3 *
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
20 * THE SOFTWARE.
22 * $Id: tr-dht.c 12033 2011-02-24 15:42:04Z jordan $
26 /* ansi */
27 #include <errno.h>
28 #include <stdio.h>
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
45 /* third party */
46 #include <event2/event.h>
47 #include <dht/dht.h>
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"
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 {
69 tr_session *session;
70 uint8_t *nodes;
71 uint8_t *nodes6;
72 size_t len, len6;
75 static int
76 bootstrap_done( tr_session *session, int af )
78 int status;
80 if(af == 0)
81 return
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;
89 static void
90 nap( int roughly_sec )
92 const int roughly_msec = roughly_sec * 1000;
93 const int msec = roughly_msec/2 + tr_cryptoWeakRandInt(roughly_msec);
94 tr_wait_msec( msec );
97 static int
98 bootstrap_af(tr_session *session)
100 if( bootstrap_done(session, AF_INET6) )
101 return AF_INET;
102 else if ( bootstrap_done(session, AF_INET) )
103 return AF_INET6;
104 else
105 return 0;
108 static void
109 bootstrap_from_name( const char *name, tr_port port, int af )
111 struct addrinfo hints, *info, *infop;
112 char pp[10];
113 int rc;
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);
122 if(rc != 0) {
123 tr_nerr("DHT", "%s:%s: %s", name, pp, gai_strerror(rc));
124 return;
127 infop = info;
128 while(infop) {
129 dht_ping_node(infop->ai_addr, infop->ai_addrlen);
131 nap(15);
133 if(bootstrap_done(session, af))
134 break;
135 infop = infop->ai_next;
137 freeaddrinfo(info);
140 static void
141 dht_bootstrap(void *closure)
143 struct bootstrap_closure *cl = closure;
144 int i;
145 int num = cl->len / 6, num6 = cl->len6 / 18;
147 if(session != cl->session)
148 return;
150 if(cl->len > 0)
151 tr_ninf( "DHT", "Bootstrapping from %d nodes", num );
153 if(cl->len6 > 0)
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) ) {
159 tr_port port;
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);
166 port = ntohs(port);
167 tr_dhtAddNode(cl->session, &addr, port, 1);
169 if( i < num6 && !bootstrap_done(cl->session, AF_INET6) ) {
170 tr_port port;
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);
177 port = ntohs(port);
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. */
184 if(i < 8)
185 nap(2);
186 else
187 nap(15);
189 if(bootstrap_done( session, 0 ))
190 break;
193 if(!bootstrap_done(cl->session, 0)) {
194 char *bootstrap_file;
195 FILE *f = NULL;
197 bootstrap_file =
198 tr_buildPath(cl->session->configDir, "dht.bootstrap", NULL);
200 if(bootstrap_file)
201 f = fopen(bootstrap_file, "rb");
202 if(f != NULL) {
203 tr_ninf("DHT", "Attempting manual bootstrap");
204 for(;;) {
205 char buf[201];
206 char *p;
207 int port = 0;
209 p = fgets(buf, 200, f);
210 if( p == NULL )
211 break;
213 p = memchr(buf, ' ', strlen(buf));
214 if(p != NULL)
215 port = atoi(p + 1);
216 if(p == NULL || port <= 0 || port >= 0x10000) {
217 tr_nerr("DHT", "Couldn't parse %s", buf);
218 continue;
221 *p = '\0';
223 bootstrap_from_name( buf, port, bootstrap_af(session) );
225 if(bootstrap_done(cl->session, 0))
226 break;
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. */
239 nap(40);
240 if(bootstrap_done(cl->session, 0))
241 break;
242 if(i == 0)
243 tr_ninf("DHT",
244 "Attempting bootstrap from dht.transmissionbt.com");
245 bootstrap_from_name( "dht.transmissionbt.com", 6881,
246 bootstrap_af(session) );
250 if( cl->nodes )
251 tr_free( cl->nodes );
252 if( cl->nodes6 )
253 tr_free( cl->nodes6 );
254 tr_free( closure );
255 tr_ndbg( "DHT", "Finished bootstrapping" );
259 tr_dhtInit(tr_session *ss)
261 tr_benc benc;
262 int rc;
263 tr_bool have_id = FALSE;
264 char * dat_file;
265 uint8_t * nodes = NULL, * nodes6 = NULL;
266 const uint8_t * raw;
267 size_t len, len6;
268 struct bootstrap_closure * cl;
270 if( session ) /* already initialized */
271 return -1;
273 tr_ndbg( "DHT", "Initializing DHT" );
275 if( getenv( "TR_DHT_VERBOSE" ) != NULL )
276 dht_debug = stderr;
278 dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL );
279 rc = tr_bencLoadFile( &benc, TR_FMT_BENC, dat_file );
280 tr_free( dat_file );
281 if(rc == 0) {
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 );
296 if(nodes == NULL)
297 len = 0;
298 if(nodes6 == NULL)
299 len6 = 0;
301 if( have_id )
302 tr_ninf( "DHT", "Reusing old id" );
303 else {
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 );
311 if( rc < 0 )
312 goto fail;
314 session = ss;
316 cl = tr_new( struct bootstrap_closure, 1 );
317 cl->session = session;
318 cl->nodes = nodes;
319 cl->nodes6 = nodes6;
320 cl->len = len;
321 cl->len6 = len6;
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" );
329 return 1;
331 fail:
332 tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", errno );
333 session = NULL;
334 return -1;
337 void
338 tr_dhtUninit(tr_session *ss)
340 if(session != ss)
341 return;
343 tr_ndbg( "DHT", "Uninitializing DHT" );
345 event_free( dht_timer );
346 dht_timer = NULL;
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" );
352 else {
353 tr_benc benc;
354 struct sockaddr_in sins[300];
355 struct sockaddr_in6 sins6[300];
356 char compact[300 * 6], compact6[300 * 18];
357 char *dat_file;
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 );
363 j = 0;
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 );
367 j += 6;
369 j = 0;
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 );
373 j += 18;
375 tr_bencInitDict( &benc, 3 );
376 tr_bencDictAddRaw( &benc, "id", myid, 20 );
377 if(num > 0)
378 tr_bencDictAddRaw( &benc, "nodes", compact, num * 6 );
379 if(num6 > 0)
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 );
384 tr_free( dat_file );
387 dht_uninit();
388 tr_ndbg("DHT", "Done uninitializing DHT");
390 session = NULL;
393 tr_bool
394 tr_dhtEnabled( const tr_session * ss )
396 return ss && ( ss == session );
399 struct getstatus_closure
401 int af;
402 sig_atomic_t status;
403 sig_atomic_t count;
406 static void
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;
418 else if( good < 40 )
419 closure->status = TR_DHT_POOR;
420 else if( incoming < 8 )
421 closure->status = TR_DHT_FIREWALLED;
422 else
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) ) {
434 if( nodes_return )
435 *nodes_return = 0;
436 return TR_DHT_STOPPED;
439 tr_runInEventThread( session, getstatus, &closure );
440 while( closure.status < 0 )
441 tr_wait_msec( 50 /*msec*/ );
443 if( nodes_return )
444 *nodes_return = closure.count;
446 return closure.status;
449 tr_port
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,
458 tr_port port,
459 tr_bool bootstrap )
461 int af = address->type == TR_AF_INET ? AF_INET : AF_INET6;
463 if( !tr_dhtEnabled( ss ) )
464 return 0;
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. */
469 if(bootstrap) {
470 if(tr_dhtStatus(ss, af, NULL) >= TR_DHT_FIREWALLED)
471 return 0;
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));
481 return 1;
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));
489 return 1;
492 return 0;
495 const char *
496 tr_dhtPrintableStatus(int status)
498 switch(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 "???";
508 static void
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 ) {
513 tr_torrent *tor;
514 tr_sessionLock( session );
515 tor = tr_torrentFindFromHash( session, info_hash );
516 if( tor && tr_torrentAllowsDHT( tor ))
518 size_t i, n;
519 tr_pex * pex;
520 if( event == DHT_EVENT_VALUES )
521 pex = tr_peerMgrCompactToPex(data, data_len, NULL, 0, &n);
522 else
523 pex = tr_peerMgrCompact6ToPex(data, data_len, NULL, 0, &n);
524 for( i=0; i<n; ++i )
525 tr_peerMgrAddPex( tor, TR_PEER_FROM_DHT, pex+i, -1 );
526 tr_free(pex);
527 tr_tordbg(tor, "Learned %d%s peers from DHT",
528 (int)n,
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 );
535 if( tor ) {
536 if( event == DHT_EVENT_SEARCH_DONE ) {
537 tr_torinf(tor, "DHT announce done");
538 tor->dhtAnnounceInProgress = 0;
539 } else {
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 ) )
553 return -1;
555 status = tr_dhtStatus( tor->session, af, &numnodes );
557 if( status == TR_DHT_STOPPED ) {
558 /* Let the caller believe everything is all right. */
559 return 1;
562 if(status >= TR_DHT_POOR ) {
563 rc = dht_search( tor->info.hash,
564 announce ? tr_sessionGetPeerPort(session) : 0,
565 af, callback, NULL);
566 if( rc >= 1 ) {
567 tr_torinf(tor, "Starting%s DHT announce (%s, %d nodes)",
568 af == AF_INET6 ? " IPv6" : "",
569 tr_dhtPrintableStatus(status), numnodes);
570 if(af == AF_INET)
571 tor->dhtAnnounceInProgress = TRUE;
572 else
573 tor->dhtAnnounce6InProgress = TRUE;
574 ret = 1;
575 } else {
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 ) );
581 } else {
582 tr_tordbg(tor, "%sDHT not ready (%s, %d nodes)",
583 af == AF_INET6 ? "IPv6 " : "",
584 tr_dhtPrintableStatus(status), numnodes);
587 return ret;
590 void
591 tr_dhtCallback(unsigned char *buf, int buflen,
592 struct sockaddr *from, socklen_t fromlen,
593 void *sv )
595 time_t tosleep;
596 int rc;
598 assert(tr_isSession(sv));
600 if(sv != session)
601 return;
603 rc = dht_periodic( buf, buflen, from, fromlen,
604 &tosleep, callback, NULL);
605 if(rc < 0) {
606 if(errno == EINTR) {
607 tosleep = 0;
608 } else {
609 tr_nerr( "DHT", "dht_periodic failed: %s", tr_strerror( errno ) );
610 if(errno == EINVAL || errno == EFAULT)
611 abort();
612 tosleep = 1;
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 ) );
621 static void
622 timer_callback(int s UNUSED, short type UNUSED, void *session )
624 tr_dhtCallback(NULL, 0, NULL, 0, session);
628 void
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 );
644 return size;