static int bootstrap_af(tr_session *session) { if( bootstrap_done(session, AF_INET6) ) return AF_INET; else if ( bootstrap_done(session, AF_INET) ) return AF_INET6; else return 0; }
static int bootstrap_done( tr_session *session, int af ) { int status; if(af == 0) return bootstrap_done(session, AF_INET) && bootstrap_done(session, AF_INET6); status = tr_dhtStatus(session, af, NULL); return status == TR_DHT_STOPPED || status >= TR_DHT_FIREWALLED; }
static void bootstrap_from_name( const char *name, tr_port port, int af ) { struct addrinfo hints, *info, *infop; char pp[10]; int rc; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_DGRAM; hints.ai_family = af; /* No, just passing p + 1 to gai won't work. */ tr_snprintf(pp, sizeof(pp), "%d", (int)port); rc = getaddrinfo(name, pp, &hints, &info); if(rc != 0) { tr_nerr("DHT", "%s:%s: %s", name, pp, gai_strerror(rc)); return; } infop = info; while(infop) { dht_ping_node(infop->ai_addr, infop->ai_addrlen); nap(15); if(bootstrap_done(session, af)) break; infop = infop->ai_next; } freeaddrinfo(info); }
static void dht_bootstrap(void *closure) { struct bootstrap_closure *cl = closure; int i; int num = cl->len / 6, num6 = cl->len6 / 18; if(session != cl->session) return; if(cl->len > 0) tr_ninf( "DHT", "Bootstrapping from %d nodes", num ); if(cl->len6 > 0) tr_ninf( "DHT", "Bootstrapping from %d IPv6 nodes", num6 ); for(i = 0; i < MAX(num, num6); i++) { if( i < num && !bootstrap_done(cl->session, AF_INET) ) { tr_port port; struct tr_address addr; memset(&addr, 0, sizeof(addr)); addr.type = TR_AF_INET; memcpy(&addr.addr.addr4, &cl->nodes[i * 6], 4); memcpy(&port, &cl->nodes[i * 6 + 4], 2); port = ntohs(port); tr_dhtAddNode(cl->session, &addr, port, 1); } if( i < num6 && !bootstrap_done(cl->session, AF_INET6) ) { tr_port port; struct tr_address addr; memset(&addr, 0, sizeof(addr)); addr.type = TR_AF_INET6; memcpy(&addr.addr.addr6, &cl->nodes6[i * 18], 16); memcpy(&port, &cl->nodes6[i * 18 + 16], 2); port = ntohs(port); tr_dhtAddNode(cl->session, &addr, port, 1); } /* Our DHT code is able to take up to 9 nodes in a row without dropping any. After that, it takes some time to split buckets. So ping the first 8 nodes quickly, then slow down. */ if(i < 8) nap(2); else nap(15); if(bootstrap_done( session, 0 )) break; } if(!bootstrap_done(cl->session, 0)) { char *bootstrap_file; FILE *f = NULL; bootstrap_file = tr_buildPath(cl->session->configDir, "dht.bootstrap", NULL); if(bootstrap_file) f = fopen(bootstrap_file, "rb"); if(f != NULL) { tr_ninf("DHT", "Attempting manual bootstrap"); for(;;) { char buf[201]; char *p; int port = 0; p = fgets(buf, 200, f); if( p == NULL ) break; p = memchr(buf, ' ', strlen(buf)); if(p != NULL) port = atoi(p + 1); if(p == NULL || port <= 0 || port >= 0x10000) { tr_nerr("DHT", "Couldn't parse %s", buf); continue; } *p = '\0'; bootstrap_from_name( buf, port, bootstrap_af(session) ); if(bootstrap_done(cl->session, 0)) break; } } tr_free( bootstrap_file ); } /* We really don't want to abuse our bootstrap nodes. Be glacially slow. */ if(!bootstrap_done(cl->session, 0)) nap(30); if(!bootstrap_done(cl->session, 0)) { tr_ninf("DHT", "Attempting bootstrap from dht.transmissionbt.com"); bootstrap_from_name( "dht.transmissionbt.com", 6881, bootstrap_af(session) ); } if( cl->nodes ) tr_free( cl->nodes ); if( cl->nodes6 ) tr_free( cl->nodes6 ); tr_free( closure ); tr_ndbg( "DHT", "Finished bootstrapping" ); }
static void dht_bootstrap (void *closure) { struct bootstrap_closure *cl = closure; int i; int num = cl->len / 6, num6 = cl->len6 / 18; if (session != cl->session) return; if (cl->len > 0) tr_logAddNamedInfo ("DHT", "Bootstrapping from %d IPv4 nodes", num); if (cl->len6 > 0) tr_logAddNamedInfo ("DHT", "Bootstrapping from %d IPv6 nodes", num6); for (i = 0; i < MAX (num, num6); i++) { if (i < num && !bootstrap_done (cl->session, AF_INET)) { tr_port port; struct tr_address addr; memset (&addr, 0, sizeof (addr)); addr.type = TR_AF_INET; memcpy (&addr.addr.addr4, &cl->nodes[i * 6], 4); memcpy (&port, &cl->nodes[i * 6 + 4], 2); port = ntohs (port); tr_dhtAddNode (cl->session, &addr, port, 1); } if (i < num6 && !bootstrap_done (cl->session, AF_INET6)) { tr_port port; struct tr_address addr; memset (&addr, 0, sizeof (addr)); addr.type = TR_AF_INET6; memcpy (&addr.addr.addr6, &cl->nodes6[i * 18], 16); memcpy (&port, &cl->nodes6[i * 18 + 16], 2); port = ntohs (port); tr_dhtAddNode (cl->session, &addr, port, 1); } /* Our DHT code is able to take up to 9 nodes in a row without dropping any. After that, it takes some time to split buckets. So ping the first 8 nodes quickly, then slow down. */ if (i < 8) nap (2); else nap (15); if (bootstrap_done (session, 0)) break; } if (!bootstrap_done (cl->session, 0)) { char *bootstrap_file; tr_sys_file_t f = TR_BAD_SYS_FILE; bootstrap_file = tr_buildPath (cl->session->configDir, "dht.bootstrap", NULL); if (bootstrap_file) f = tr_sys_file_open (bootstrap_file, TR_SYS_FILE_READ, 0, NULL); if (f != TR_BAD_SYS_FILE) { tr_logAddNamedInfo ("DHT", "Attempting manual bootstrap"); for (;;) { char buf[201]; char *p; int port = 0; if (!tr_sys_file_read_line (f, buf, 200, NULL)) break; p = memchr (buf, ' ', strlen (buf)); if (p != NULL) port = atoi (p + 1); if (p == NULL || port <= 0 || port >= 0x10000) { tr_logAddNamedError ("DHT", "Couldn't parse %s", buf); continue; } *p = '\0'; bootstrap_from_name (buf, port, bootstrap_af (session)); if (bootstrap_done (cl->session, 0)) break; } tr_sys_file_close (f, NULL); } tr_free (bootstrap_file); } if (!bootstrap_done (cl->session, 0)) { for (i = 0; i < 6; i++) { /* We don't want to abuse our bootstrap nodes, so be very slow. The initial wait is to give other nodes a chance to contact us before we attempt to contact a bootstrap node, for example because we've just been restarted. */ nap (40); if (bootstrap_done (cl->session, 0)) break; if (i == 0) tr_logAddNamedInfo ("DHT", "Attempting bootstrap from dht.transmissionbt.com"); bootstrap_from_name ("dht.transmissionbt.com", 6881, bootstrap_af (session)); } } if (cl->nodes) tr_free (cl->nodes); if (cl->nodes6) tr_free (cl->nodes6); tr_free (closure); tr_logAddNamedDbg ("DHT", "Finished bootstrapping"); }