static void set_evtimer_from_status( tr_shared * s ) { int sec=0, msec=0; /* when to wake up again */ switch( tr_sharedTraversalStatus( s ) ) { case TR_PORT_MAPPED: /* if we're mapped, everything is fine... check back in 20 minutes * to renew the port forwarding if it's expired */ s->doPortCheck = TRUE; sec = 60 * 20; break; case TR_PORT_ERROR: /* some kind of an error. wait 60 seconds and retry */ sec = 60; break; default: /* in progress. pulse frequently. */ msec = 333000; break; } if( s->timer != NULL ) tr_timerAdd( s->timer, sec, msec ); }
tr_handshake* tr_handshakeNew (tr_peerIo * io, tr_encryption_mode encryptionMode, handshakeDoneCB doneCB, void * doneUserData) { tr_handshake * handshake; tr_session * session = tr_peerIoGetSession (io); handshake = tr_new0 (tr_handshake, 1); handshake->io = io; handshake->crypto = tr_peerIoGetCrypto (io); handshake->encryptionMode = encryptionMode; handshake->doneCB = doneCB; handshake->doneUserData = doneUserData; handshake->session = session; handshake->timeout_timer = evtimer_new (session->event_base, handshakeTimeout, handshake); tr_timerAdd (handshake->timeout_timer, HANDSHAKE_TIMEOUT_SEC, 0); tr_peerIoRef (io); /* balanced by the unref in tr_handshakeFree */ tr_peerIoSetIOFuncs (handshake->io, canRead, NULL, gotError, handshake); tr_peerIoSetEncryption (io, PEER_ENCRYPTION_NONE); if (tr_peerIoIsIncoming (handshake->io)) { setReadState (handshake, AWAITING_HANDSHAKE); } else if (encryptionMode != TR_CLEAR_PREFERRED) { sendYa (handshake); } else { uint8_t msg[HANDSHAKE_SIZE]; buildHandshakeMessage (handshake, msg); handshake->haveSentBitTorrentHandshake = 1; setReadState (handshake, AWAITING_HANDSHAKE); tr_peerIoWriteBytes (handshake->io, msg, sizeof (msg), false); } return handshake; }
tr_shared * tr_sharedInit( tr_session * session ) { tr_shared * s = tr_new0( tr_shared, 1 ); s->session = session; s->isEnabled = FALSE; s->upnpStatus = TR_PORT_UNMAPPED; s->natpmpStatus = TR_PORT_UNMAPPED; #if 0 if( isEnabled ) { s->timer = tr_new0( struct event, 1 ); evtimer_set( s->timer, onTimer, s ); tr_timerAdd( s->timer, 0, 333000 ); } #endif return s; }
static void addTask( void * vtask ) { struct tr_web_task * task = vtask; const tr_session * session = task->session; if( ( session == NULL ) || ( session->web == NULL ) ) return; if( !task->resolved_host ) { dbgmsg( "couldn't resolve host for \"%s\"... task failed", task->url ); task_finish( task, 0 ); } else { CURL * e = curl_easy_init( ); struct tr_web * web = session->web; const int timeout = getTimeoutFromURL( task->url ); const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; const char * user_agent = TR_NAME "/" SHORT_VERSION_STRING; /* insert the resolved host into the URL s.t. curl's DNS won't block * even if -- like on most OSes -- it wasn't built with C-Ares :( * "http://www.craptrackular.org/announce?key=val&key2=..." becomes * "http://127.0.0.1/announce?key=val&key2=..." */ { char * host; struct evbuffer * buf = evbuffer_new( ); char * pch = strstr( task->url, task->host ); char * tail = pch + strlen( task->host ); evbuffer_add( buf, task->url, pch - task->url ); evbuffer_add_printf( buf, "%s", task->resolved_host ); evbuffer_add_printf( buf, "%s", tail ); task->resolved_url = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) ); dbgmsg( "old url: \"%s\" -- new url: \"%s\"", task->url, task->resolved_url ); evbuffer_free( buf ); /* Manually add a Host: argument that refers to the true URL */ if( ( ( task->port <= 0 ) ) || ( ( task->port == 80 ) && !strncmp( task->url, "http://", 7 ) ) || ( ( task->port == 443 ) && !strncmp( task->url, "https://", 8 ) ) ) host = tr_strdup_printf( "Host: %s", task->host ); else host = tr_strdup_printf( "Host: %s:%d", task->host, task->port ); task->slist = curl_slist_append( NULL, host ); task->slist = curl_slist_append( task->slist, "Accept:" ); curl_easy_setopt( e, CURLOPT_HTTPHEADER, task->slist ); tr_free( host ); } dbgmsg( "adding task #%lu [%s]", task->tag, task->resolved_url ? task->resolved_url : task->url ); if( !task->range && session->isProxyEnabled ) { curl_easy_setopt( e, CURLOPT_PROXY, session->proxy ); curl_easy_setopt( e, CURLOPT_PROXYAUTH, CURLAUTH_ANY ); curl_easy_setopt( e, CURLOPT_PROXYPORT, session->proxyPort ); curl_easy_setopt( e, CURLOPT_PROXYTYPE, getCurlProxyType( session->proxyType ) ); } if( !task->range && session->isProxyAuthEnabled ) { char * str = tr_strdup_printf( "%s:%s", session->proxyUsername, session->proxyPassword ); curl_easy_setopt( e, CURLOPT_PROXYUSERPWD, str ); tr_free( str ); } task->easy = e; task->multi = web->multi; /* use our own timeout instead of CURLOPT_TIMEOUT because the latter * doesn't play nicely with curl_multi. See curl bug #2501457 */ task->timer_event_isSet = TRUE; evtimer_set( &task->timer_event, task_timeout_cb, task ); tr_timerAdd( &task->timer_event, timeout, 0 ); curl_easy_setopt( e, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction ); curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc ); curl_easy_setopt( e, CURLOPT_DNS_CACHE_TIMEOUT, MIN_DNS_CACHE_TIME ); curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L ); curl_easy_setopt( e, CURLOPT_FORBID_REUSE, 1L ); curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L ); curl_easy_setopt( e, CURLOPT_PRIVATE, task ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L ); curl_easy_setopt( e, CURLOPT_URL, task->resolved_url ? task->resolved_url : task->url ); curl_easy_setopt( e, CURLOPT_USERAGENT, user_agent ); curl_easy_setopt( e, CURLOPT_VERBOSE, verbose ); if( web->haveAddr ) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( &web->addr ) ); if( task->range ) curl_easy_setopt( e, CURLOPT_RANGE, task->range ); if( curl_multi_add_handle( web->multi, e ) == CURLM_OK ) ++web->taskCount; } }
int tr_dhtInit(tr_session *ss, const tr_address * tr_addr) { struct sockaddr_in sin; tr_benc benc; int rc; tr_bool have_id = FALSE; char * dat_file; uint8_t * nodes = NULL, * nodes6 = NULL; const uint8_t * raw; size_t len, len6; struct bootstrap_closure * cl; if( session ) /* already initialized */ return -1; dht_port = tr_sessionGetPeerPort(ss); if(dht_port <= 0) return -1; tr_ndbg( "DHT", "Initializing DHT" ); dht_socket = socket(PF_INET, SOCK_DGRAM, 0); if(dht_socket < 0) goto fail; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; memcpy(&sin.sin_addr, &tr_addr->addr.addr4, sizeof (struct in_addr)); sin.sin_port = htons(dht_port); rc = bind(dht_socket, (struct sockaddr*)&sin, sizeof(sin)); if(rc < 0) goto fail; if(tr_globalIPv6()) rebind_ipv6(TRUE); if( getenv( "TR_DHT_VERBOSE" ) != NULL ) dht_debug = stderr; dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL ); rc = tr_bencLoadFile( &benc, TR_FMT_BENC, dat_file ); tr_free( dat_file ); if(rc == 0) { have_id = tr_bencDictFindRaw(&benc, "id", &raw, &len); if( have_id && len==20 ) memcpy( myid, raw, len ); if( dht_socket >= 0 && tr_bencDictFindRaw( &benc, "nodes", &raw, &len ) && !(len%6) ) { nodes = tr_memdup( raw, len ); } if( dht6_socket > 0 && tr_bencDictFindRaw( &benc, "nodes6", &raw, &len6 ) && !(len6%18) ) { nodes6 = tr_memdup( raw, len6 ); } tr_bencFree( &benc ); } if(nodes == NULL) len = 0; if(nodes6 == NULL) len6 = 0; if( have_id ) tr_ninf( "DHT", "Reusing old id" ); else { /* Note that DHT ids need to be distributed uniformly, * so it should be something truly random. */ tr_ninf( "DHT", "Generating new id" ); tr_cryptoRandBuf( myid, 20 ); } rc = dht_init( dht_socket, dht6_socket, myid, NULL ); if( rc < 0 ) goto fail; session = ss; cl = tr_new( struct bootstrap_closure, 1 ); cl->session = session; cl->nodes = nodes; cl->nodes6 = nodes6; cl->len = len; cl->len6 = len6; tr_threadNew( dht_bootstrap, cl ); dht_event = event_new( session->event_base, dht_socket, EV_READ, event_callback, NULL ); tr_timerAdd( dht_event, 0, tr_cryptoWeakRandInt( 1000000 ) ); if( dht6_socket >= 0 ) { dht6_event = event_new( session->event_base, dht6_socket, EV_READ, event_callback, NULL ); tr_timerAdd( dht6_event, 0, tr_cryptoWeakRandInt( 1000000 ) ); } tr_ndbg( "DHT", "DHT initialized" ); return 1; fail: { const int save = errno; close(dht_socket); if( dht6_socket >= 0 ) close(dht6_socket); dht_socket = dht6_socket = -1; session = NULL; tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", save ); errno = save; } return -1; }
int tr_dhtInit(tr_session *ss) { tr_benc benc; int rc; bool have_id = false; char * dat_file; uint8_t * nodes = NULL, * nodes6 = NULL; const uint8_t * raw; size_t len, len6; struct bootstrap_closure * cl; if( session ) /* already initialized */ return -1; tr_ndbg( "DHT", "Initializing DHT" ); if( getenv( "TR_DHT_VERBOSE" ) != NULL ) dht_debug = stderr; dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL ); rc = tr_bencLoadFile( &benc, TR_FMT_BENC, dat_file ); tr_free( dat_file ); if(rc == 0) { have_id = tr_bencDictFindRaw(&benc, "id", &raw, &len); if( have_id && len==20 ) memcpy( myid, raw, len ); if( ss->udp_socket >= 0 && tr_bencDictFindRaw( &benc, "nodes", &raw, &len ) && !(len%6) ) { nodes = tr_memdup( raw, len ); } if( ss->udp6_socket > 0 && tr_bencDictFindRaw( &benc, "nodes6", &raw, &len6 ) && !(len6%18) ) { nodes6 = tr_memdup( raw, len6 ); } tr_bencFree( &benc ); } if(nodes == NULL) len = 0; if(nodes6 == NULL) len6 = 0; if( have_id ) tr_ninf( "DHT", "Reusing old id" ); else { /* Note that DHT ids need to be distributed uniformly, * so it should be something truly random. */ tr_ninf( "DHT", "Generating new id" ); tr_cryptoRandBuf( myid, 20 ); } rc = dht_init( ss->udp_socket, ss->udp6_socket, myid, NULL ); if( rc < 0 ) goto fail; session = ss; cl = tr_new( struct bootstrap_closure, 1 ); cl->session = session; cl->nodes = nodes; cl->nodes6 = nodes6; cl->len = len; cl->len6 = len6; tr_threadNew( dht_bootstrap, cl ); dht_timer = evtimer_new( session->event_base, timer_callback, session ); tr_timerAdd( dht_timer, 0, tr_cryptoWeakRandInt( 1000000 ) ); tr_ndbg( "DHT", "DHT initialized" ); return 1; fail: tr_ndbg( "DHT", "DHT initialization failed (errno = %d)", errno ); session = NULL; return -1; }
int tr_dhtInit (tr_session *ss) { tr_variant benc; int rc; bool have_id = false; char * dat_file; uint8_t * nodes = NULL, * nodes6 = NULL; const uint8_t * raw; size_t len, len6; struct bootstrap_closure * cl; if (session) /* already initialized */ return -1; tr_logAddNamedDbg ("DHT", "Initializing DHT"); if (tr_env_key_exists ("TR_DHT_VERBOSE")) dht_debug = stderr; dat_file = tr_buildPath (ss->configDir, "dht.dat", NULL); rc = tr_variantFromFile (&benc, TR_VARIANT_FMT_BENC, dat_file, NULL) ? 0 : -1; tr_free (dat_file); if (rc == 0) { have_id = tr_variantDictFindRaw (&benc, TR_KEY_id, &raw, &len); if (have_id && len==20) memcpy (myid, raw, len); if (ss->udp_socket != TR_BAD_SOCKET && tr_variantDictFindRaw (&benc, TR_KEY_nodes, &raw, &len) && ! (len%6)) { nodes = tr_memdup (raw, len); } if (ss->udp6_socket != TR_BAD_SOCKET && tr_variantDictFindRaw (&benc, TR_KEY_nodes6, &raw, &len6) && ! (len6%18)) { nodes6 = tr_memdup (raw, len6); } tr_variantFree (&benc); } if (nodes == NULL) len = 0; if (nodes6 == NULL) len6 = 0; if (have_id) tr_logAddNamedInfo ("DHT", "Reusing old id"); else { /* Note that DHT ids need to be distributed uniformly, * so it should be something truly random. */ tr_logAddNamedInfo ("DHT", "Generating new id"); tr_rand_buffer (myid, 20); } rc = dht_init (ss->udp_socket, ss->udp6_socket, myid, NULL); if (rc < 0) goto fail; session = ss; cl = tr_new (struct bootstrap_closure, 1); cl->session = session; cl->nodes = nodes; cl->nodes6 = nodes6; cl->len = len; cl->len6 = len6; tr_threadNew (dht_bootstrap, cl); dht_timer = evtimer_new (session->event_base, timer_callback, session); tr_timerAdd (dht_timer, 0, tr_rand_int_weak (1000000)); tr_logAddNamedDbg ("DHT", "DHT initialized"); return 1; fail: tr_logAddNamedDbg ("DHT", "DHT initialization failed (errno = %d)", errno); session = NULL; return -1; }