示例#1
0
int
tr_ctorSetMetainfo( tr_ctor *       ctor,
                    const uint8_t * metainfo,
                    size_t          len )
{
    int err;

    clearMetainfo( ctor );
    err = tr_bencLoad( metainfo, len, &ctor->metainfo, NULL );
    ctor->isSet_metainfo = !err;
    return err;
}
示例#2
0
static int
testJSONSnippet( const char * benc_str,
                 const char * expected )
{
    tr_benc top;
    char *  serialized;

    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
    serialized = tr_bencSaveAsJSON( &top, NULL );
    stripWhitespace( serialized );
#if 0
    fprintf( stderr, "benc: %s\n", benc_str );
    fprintf( stderr, "json: %s\n", serialized );
    fprintf( stderr, "want: %s\n", expected );
#endif
    check( !strcmp( serialized, expected ) );
    tr_free( serialized );
    tr_bencFree( &top );
    return 0;
}
示例#3
0
static int
testJSONSnippet( const char * benc_str,
                 const char * expected )
{
    tr_benc top;
    char * serialized;
    struct evbuffer * buf;

    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
    buf = tr_bencToBuf( &top, TR_FMT_JSON );
    serialized = (char*) evbuffer_pullup( buf, -1 );
    stripWhitespace( serialized );
#if 0
    fprintf( stderr, "benc: %s\n", benc_str );
    fprintf( stderr, "json: %s\n", serialized );
    fprintf( stderr, "want: %s\n", expected );
#endif
    check_streq (expected, serialized);
    tr_bencFree( &top );
    evbuffer_free( buf );
    return 0;
}
示例#4
0
static void
on_scrape_done( tr_session   * session,
                bool           did_connect,
                bool           did_timeout,
                long           response_code,
                const void   * msg,
                size_t         msglen,
                void         * vdata )
{
    tr_scrape_response * response;
    struct scrape_data * data = vdata;

    response = &data->response;
    response->did_connect = did_connect;
    response->did_timeout = did_timeout;
    dbgmsg( data->log_name, "Got scrape response for \"%s\"", response->url );

    if( response_code != HTTP_OK )
    {
        const char * fmt = _( "Tracker gave HTTP response code %1$ld (%2$s)" );
        const char * response_str = tr_webGetResponseStr( response_code );
        response->errmsg = tr_strdup_printf( fmt, response_code, response_str );
    }
    else
    {
        tr_benc top;
        int64_t intVal;
        tr_benc * files;
        const char * str;
        const int benc_loaded = !tr_bencLoad( msg, msglen, &top, NULL );
        if( benc_loaded )
        {
            if( tr_bencDictFindStr( &top, "failure reason", &str ) )
                response->errmsg = tr_strdup( str );

            if( tr_bencDictFindInt( &top, "min_request_interval", &intVal ) )
                response->min_request_interval = intVal;

            if( tr_bencDictFindDict( &top, "files", &files ) )
            {
                int i = 0;

                for( ;; )
                {
                    int j;
                    tr_benc * val;
                    const char * key;

                    /* get the next "file" */
                    if( !tr_bencDictChild( files, i++, &key, &val ) )
                        break;

                    /* populate the corresponding row in our response array */
                    for( j=0; j<response->row_count; ++j )
                    {
                        struct tr_scrape_response_row * row = &response->rows[j];
                        if( !memcmp( key, row->info_hash, SHA_DIGEST_LENGTH ) )
                        {
                            if( tr_bencDictFindInt( val, "complete", &intVal ) )
                                row->seeders = intVal;
                            if( tr_bencDictFindInt( val, "incomplete", &intVal ) )
                                row->leechers = intVal;
                            if( tr_bencDictFindInt( val, "downloaded", &intVal ) )
                                row->downloads = intVal;
                            if( tr_bencDictFindInt( val, "downloaders", &intVal ) )
                                row->downloaders = intVal;
                            break;
                        }
                    }
                }
            }

            tr_bencFree( &top );
        }
    }

    tr_runInEventThread( session, on_scrape_done_eventthread, data );
}
示例#5
0
static void
on_announce_done( tr_session   * session,
                  bool           did_connect,
                  bool           did_timeout,
                  long           response_code,
                  const void   * msg,
                  size_t         msglen,
                  void         * vdata )
{
    tr_announce_response * response;
    struct announce_data * data = vdata;

    response = &data->response;
    response->did_connect = did_connect;
    response->did_timeout = did_timeout;
    dbgmsg( data->log_name, "Got announce response" );

    if( response_code != HTTP_OK )
    {
        const char * fmt = _( "Tracker gave HTTP response code %1$ld (%2$s)" );
        const char * response_str = tr_webGetResponseStr( response_code );
        response->errmsg = tr_strdup_printf( fmt, response_code, response_str );
    }
    else
    {
        tr_benc benc;
        const int benc_loaded = !tr_bencLoad( msg, msglen, &benc, NULL );

        if( getenv( "TR_CURL_VERBOSE" ) != NULL )
        {
            struct evbuffer * buf = tr_bencToBuf( &benc, TR_FMT_JSON );
            fprintf( stderr, "Announce response:\n< %s\n", evbuffer_pullup( buf, -1 ) );
            tr_free( buf );
        }

        if( benc_loaded && tr_bencIsDict( &benc ) )
        {
            int64_t i;
            size_t rawlen;
            tr_benc * tmp;
            const char * str;
            const uint8_t * raw;

            if( tr_bencDictFindStr( &benc, "failure reason", &str ) )
                response->errmsg = tr_strdup( str );

            if( tr_bencDictFindStr( &benc, "warning message", &str ) )
                response->warning = tr_strdup( str );

            if( tr_bencDictFindInt( &benc, "interval", &i ) )
                response->interval = i;

            if( tr_bencDictFindInt( &benc, "min interval", &i ) )
                response->min_interval = i;

            if( tr_bencDictFindStr( &benc, "tracker id", &str ) )
                response->tracker_id_str = tr_strdup( str );

            if( tr_bencDictFindInt( &benc, "complete", &i ) )
                response->seeders = i;

            if( tr_bencDictFindInt( &benc, "incomplete", &i ) )
                response->leechers = i;

            if( tr_bencDictFindInt( &benc, "downloaded", &i ) )
                response->downloads = i;

            if( tr_bencDictFindRaw( &benc, "peers6", &raw, &rawlen ) ) {
                dbgmsg( data->log_name, "got a peers6 length of %zu", rawlen );
                response->pex6 = tr_peerMgrCompact6ToPex( raw, rawlen,
                                              NULL, 0, &response->pex6_count );
            }

            if( tr_bencDictFindRaw( &benc, "peers", &raw, &rawlen ) ) {
                dbgmsg( data->log_name, "got a compact peers length of %zu", rawlen );
                response->pex = tr_peerMgrCompactToPex( raw, rawlen,
                                               NULL, 0, &response->pex_count );
            } else if( tr_bencDictFindList( &benc, "peers", &tmp ) ) {
                response->pex = listToPex( tmp, &response->pex_count );
                dbgmsg( data->log_name, "got a peers list with %zu entries",
                        response->pex_count );
            }
        }

        if( benc_loaded )
            tr_bencFree( &benc );
    }

    tr_runInEventThread( session, on_announce_done_eventthread, data );
}
示例#6
0
int tr_trackerScrape( tr_torrent_t * tor, int * seeders, int * leechers )
{
    tr_info_t * inf = &tor->info;

    int s, i, ret;
    uint8_t buf[1024];
    benc_val_t scrape, * val1, * val2;
    struct in_addr addr;
    uint64_t date;
    int pos, len;
    tr_resolve_t * resolve;

    if( !tor->scrape[0] )
    {
        /* scrape not supported */
        return 1;
    }

    resolve = tr_netResolveInit( inf->trackerAddress );
    for( date = tr_date();; )
    {
        ret = tr_netResolvePulse( resolve, &addr );
        if( ret == TR_RESOLVE_OK )
        {
            tr_netResolveClose( resolve );
            break;
        }
        if( ret == TR_RESOLVE_ERROR ||
                ( ret == TR_RESOLVE_WAIT && tr_date() > date + 10000 ) )
        {
            fprintf( stderr, "Could not resolve %s\n", inf->trackerAddress );
            tr_netResolveClose( resolve );
            return 1;
        }
        tr_wait( 10 );
    }

    s = tr_netOpen( addr, htons( inf->trackerPort ) );
    if( s < 0 )
    {
        return 1;
    }

    len = snprintf( (char *) buf, sizeof( buf ),
                    "GET %s?info_hash=%s HTTP/1.1\r\n"
                    "Host: %s\r\n"
                    "Connection: close\r\n\r\n",
                    tor->scrape, tor->hashString,
                    inf->trackerAddress );

    for( date = tr_date();; )
    {
        ret = tr_netSend( s, buf, len );
        if( ret & TR_NET_CLOSE )
        {
            fprintf( stderr, "Could not connect to tracker\n" );
            tr_netClose( s );
            return 1;
        }
        else if( ret & TR_NET_BLOCK )
        {
            if( tr_date() > date + 10000 )
            {
                fprintf( stderr, "Could not connect to tracker\n" );
                tr_netClose( s );
                return 1;
            }
        }
        else
        {
            break;
        }
        tr_wait( 10 );
    }

    pos = 0;
    for( date = tr_date();; )
    {
        ret = tr_netRecv( s, &buf[pos], sizeof( buf ) - pos );
        if( ret & TR_NET_CLOSE )
        {
            break;
        }
        else if( ret & TR_NET_BLOCK )
        {
            if( tr_date() > date + 10000 )
            {
                fprintf( stderr, "Could not read from tracker\n" );
                tr_netClose( s );
                return 1;
            }
        }
        else
        {
            pos += ret;
        }
        tr_wait( 10 );
    }

    if( pos < 1 )
    {
        fprintf( stderr, "Could not read from tracker\n" );
        tr_netClose( s );
        return 1;
    }

    for( i = 0; i < pos - 8; i++ )
    {
        if( !memcmp( &buf[i], "d5:files", 8 ) )
        {
            break;
        }
    }
    if( i >= pos - 8 )
    {
        return 1;
    }
    if( tr_bencLoad( &buf[i], pos - i, &scrape, NULL ) )
    {
        return 1;
    }

    val1 = tr_bencDictFind( &scrape, "files" );
    if( !val1 )
    {
        return 1;
    }
    val1 = &val1->val.l.vals[1];
    if( !val1 )
    {
        return 1;
    }
    val2 = tr_bencDictFind( val1, "complete" );
    if( !val2 )
    {
        return 1;
    }
    *seeders = val2->val.i;
    val2 = tr_bencDictFind( val1, "incomplete" );
    if( !val2 )
    {
        return 1;
    }
    *leechers = val2->val.i;
    tr_bencFree( &scrape );

    return 0;
}
示例#7
0
static void recvAnswer( tr_tracker_t * tc )
{
    tr_torrent_t * tor = tc->tor;
    int ret;
    int i;
    benc_val_t   beAll;
    benc_val_t * bePeers, * beFoo;
    uint8_t * body;
    int bodylen;

    if( tc->pos == tc->size )
    {
        tc->size *= 2;
        tc->buf   = realloc( tc->buf, tc->size );
    }

    ret = tr_netRecv( tc->socket, &tc->buf[tc->pos],
                      tc->size - tc->pos );

    if( ret & TR_NET_BLOCK )
    {
        return;
    }
    if( !( ret & TR_NET_CLOSE ) )
    {
        // printf( "got %d bytes\n", ret );
        tc->pos += ret;
        return;
    }

    tr_netClose( tc->socket );
    tr_fdSocketClosed( tor->fdlimit, 1 );
    // printf( "connection closed, got total %d bytes\n", tc->pos );

    tc->status  = TC_STATUS_IDLE;
    tc->dateTry = tr_date();

    if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) &&
                          0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) )
    {
        /* We don't have a complete HTTP status line */
        tr_inf( "Tracker: incomplete HTTP status line" );
        tc->lastAttempt = TC_ATTEMPT_NOREACH;
        return;
    }

    if( '2' != tc->buf[9] )
    {
        /* we didn't get a 2xx status code */
        tr_err( "Tracker: invalid HTTP status code: %c%c%c",
                tc->buf[9], tc->buf[10], tc->buf[11] );
        tc->lastAttempt = TC_ATTEMPT_ERROR;
        return;
    }

    /* find the end of the http headers */
    body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 );
    if( NULL != body )
    {
        body += 4;
    }
    /* hooray for trackers that violate the HTTP spec */
    else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) ||
             NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) )
    {
        body += 2;
    }
    else
    {
        tr_err( "Tracker: could not find end of HTTP headers" );
        tc->lastAttempt = TC_ATTEMPT_NOREACH;
        return;
    }
    bodylen = tc->pos - (body - tc->buf);

    /* Find and load the dictionary */
    for( i = 0; i < bodylen; i++ )
    {
        if( !tr_bencLoad( &body[i], bodylen - i, &beAll, NULL ) )
        {
            break;
        }
    }

    if( i >= bodylen )
    {
        if( tc->stopped || 0 < tc->newPort )
        {
            tc->lastAttempt = TC_ATTEMPT_OK;
            goto nodict;
        }
        tr_err( "Tracker: no valid dictionary found in answer" );
        tc->lastAttempt = TC_ATTEMPT_ERROR;
        return;
    }

    // tr_bencPrint( &beAll );

    if( ( bePeers = tr_bencDictFind( &beAll, "failure reason" ) ) )
    {
        tr_err( "Tracker: %s", bePeers->val.s.s );
        tor->error |= TR_ETRACKER;
        snprintf( tor->trackerError, sizeof( tor->trackerError ),
                  "%s", bePeers->val.s.s );
        tc->lastAttempt = TC_ATTEMPT_ERROR;
        goto cleanup;
    }

    tor->error &= ~TR_ETRACKER;
    tc->lastAttempt = TC_ATTEMPT_OK;

    if( !tc->interval )
    {
        /* Get the tracker interval, ignore it if it is not between
           10 sec and 5 mins */
        if( !( beFoo = tr_bencDictFind( &beAll, "interval" ) ) ||
                !( beFoo->type & TYPE_INT ) )
        {
            tr_err( "Tracker: no 'interval' field" );
            goto cleanup;
        }

        tc->interval = beFoo->val.i;
        tc->interval = MIN( tc->interval, 300 );
        tc->interval = MAX( 10, tc->interval );

        tr_inf( "Tracker: interval = %d seconds", tc->interval );
    }

    if( ( beFoo = tr_bencDictFind( &beAll, "complete" ) ) &&
            ( beFoo->type & TYPE_INT ) )
    {
        tc->seeders = beFoo->val.i;
    }
    if( ( beFoo = tr_bencDictFind( &beAll, "incomplete" ) ) &&
            ( beFoo->type & TYPE_INT ) )
    {
        tc->leechers = beFoo->val.i;
    }
    if( tc->seeders + tc->leechers >= 50 )
    {
        tc->hasManyPeers = 1;
    }

    if( !( bePeers = tr_bencDictFind( &beAll, "peers" ) ) )
    {
        if( tc->stopped || 0 < tc->newPort )
        {
            goto nodict;
        }
        tr_err( "Tracker: no \"peers\" field" );
        goto cleanup;
    }

    if( bePeers->type & TYPE_LIST )
    {
        char * ip;
        int    port;

        /* Original protocol */
        tr_inf( "Tracker: got %d peers", bePeers->val.l.count );

        for( i = 0; i < bePeers->val.l.count; i++ )
        {
            beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "ip" );
            if( !beFoo )
                continue;
            ip = beFoo->val.s.s;
            beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "port" );
            if( !beFoo )
                continue;
            port = beFoo->val.i;

            tr_peerAddOld( tor, ip, port );
        }

        if( bePeers->val.l.count >= 50 )
        {
            tc->hasManyPeers = 1;
        }
    }
    else if( bePeers->type & TYPE_STR )
    {
        struct in_addr addr;
        in_port_t      port;

        /* "Compact" extension */
        if( bePeers->val.s.i % 6 )
        {
            tr_err( "Tracker: \"peers\" of size %d",
                    bePeers->val.s.i );
            tr_lockUnlock( &tor->lock );
            goto cleanup;
        }

        tr_inf( "Tracker: got %d peers", bePeers->val.s.i / 6 );
        for( i = 0; i < bePeers->val.s.i / 6; i++ )
        {
            memcpy( &addr, &bePeers->val.s.s[6*i],   4 );
            memcpy( &port, &bePeers->val.s.s[6*i+4], 2 );

            tr_peerAddCompact( tor, addr, port );
        }

        if( bePeers->val.s.i / 6 >= 50 )
        {
            tc->hasManyPeers = 1;
        }
    }

nodict:
    /* Success */
    tc->started   = 0;
    tc->completed = 0;
    tc->dateOk    = tr_date();

    if( tc->stopped )
    {
        tor->status = TR_STATUS_STOPPED;
        tc->stopped = 0;
    }
    else if( 0 < tc->newPort )
    {
        tc->started  = 1;
        tc->download = tor->downloaded;
        tc->upload   = tor->uploaded;
    }

cleanup:
    tr_bencFree( &beAll );
}
示例#8
0
int _tr_bencLoad( char * buf, size_t len, benc_val_t * val, char ** end )
{
    char * p, * e, * foo;

    if( 1 >= len )
    {
        return 1;
    }

    if( !end )
    {
        /* So we only have to check once */
        end = &foo;
    }

    val->begin = buf;

    if( buf[0] == 'i' )
    {
        e = memchr( &buf[1], 'e', len - 1 );
        if( NULL == e )
        {
            return 1;
        }

        /* Integer: i1242e */
        val->type  = TYPE_INT;
        *e         = '\0';
        val->val.i = strtoll( &buf[1], &p, 10 );
        *e         = 'e';

        if( p != e )
        {
            return 1;
        }

        val->end = p + 1;
    }
    else if( buf[0] == 'l' || buf[0] == 'd' )
    {
        /* List: l<item1><item2>e
           Dict: d<string1><item1><string2><item2>e
           A dictionary is just a special kind of list with an even
           count of items, and where even items are strings. */
        char * cur;
        char   is_dict;
        char   str_expected;

        is_dict          = ( buf[0] == 'd' );
        val->type        = is_dict ? TYPE_DICT : TYPE_LIST;
        val->val.l.alloc = LIST_SIZE;
        val->val.l.count = 0;
        val->val.l.vals  = malloc( LIST_SIZE * sizeof( benc_val_t ) );
        cur              = &buf[1];
        str_expected     = 1;
        while( (size_t)(cur - buf) < len && cur[0] != 'e' )
        {
            if( val->val.l.count == val->val.l.alloc )
            {
                /* We need a bigger boat */
                val->val.l.alloc += LIST_SIZE;
                val->val.l.vals   =  realloc( val->val.l.vals,
                        val->val.l.alloc  * sizeof( benc_val_t ) );
            }
            if( tr_bencLoad( cur, len - (cur - buf),
                             &val->val.l.vals[val->val.l.count], &p ) )
            {
                return 1;
            }
            if( is_dict && str_expected &&
                val->val.l.vals[val->val.l.count].type != TYPE_STR )
            {
                return 1;
            }
            str_expected = !str_expected;

            val->val.l.count++;
            cur = p;
        }

        if( is_dict && ( val->val.l.count & 1 ) )
        {
            return 1;
        }

        val->end = cur + 1;
    }
    else
    {
        e = memchr( buf, ':', len );
        if( NULL == e )
        {
            return 1;
        }

        /* String: 12:whateverword */
        val->type    = TYPE_STR;
        e[0]         = '\0';
        val->val.s.i = strtol( buf, &p, 10 );
        e[0]         = ':';

        if( p != e || 0 > val->val.s.i ||
            (size_t)(val->val.s.i) > len - ((p + 1) - buf) )
        {
            return 1;
        }

        val->val.s.s               = malloc( val->val.s.i + 1 );
        val->val.s.s[val->val.s.i] = 0;
        memcpy( val->val.s.s, p + 1, val->val.s.i );

        val->end = p + 1 + val->val.s.i;
    }

    *end = val->end;

    return 0;
}