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;
}
Beispiel #4
0
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;
    }
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}