Ignore:
Timestamp:
Sep 25, 2006, 6:37:45 PM (15 years ago)
Author:
joshe
Message:

Merge nat-traversal branch to trunk.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/tracker.c

    r854 r920  
    4343    uint64_t       dateOk;
    4444
    45 #define TC_STATUS_IDLE    1
    46 #define TC_STATUS_RESOLVE 2
    47 #define TC_STATUS_CONNECT 4
    48 #define TC_STATUS_RECV    8
    49     char           status;
    50 
    5145#define TC_ATTEMPT_NOREACH 1
    5246#define TC_ATTEMPT_ERROR   2
     
    5448    char           lastAttempt;
    5549
    56     tr_resolve_t * resolve;
    57     int            socket;
    58     uint8_t      * buf;
    59     int            size;
    60     int            pos;
     50    tr_http_t    * http;
    6151
    6252    int            bindPort;
     
    6757};
    6858
    69 static void sendQuery  ( tr_tracker_t * tc );
    70 static void recvAnswer ( tr_tracker_t * tc );
     59static tr_http_t * getQuery   ( tr_tracker_t * tc );
     60static void        readAnswer ( tr_tracker_t * tc, const char *, int );
    7161
    7262tr_tracker_t * tr_trackerInit( tr_torrent_t * tor )
     
    8474    tc->leechers = -1;
    8575
    86     tc->status   = TC_STATUS_IDLE;
    8776    tc->lastAttempt = TC_ATTEMPT_NOREACH;
    88     tc->size     = 1024;
    89     tc->buf      = malloc( tc->size );
    9077
    9178    tc->bindPort = *(tor->bindPort);
     
    160147    tr_torrent_t * tor = tc->tor;
    161148    tr_info_t    * inf = &tor->info;
    162     uint64_t       now = tr_date();
    163 
    164     if( ( tc->status & TC_STATUS_IDLE ) && shouldConnect( tc ) )
    165     {
    166         tc->resolve = tr_netResolveInit( inf->trackerAddress );
     149    const char   * data;
     150    int            len;
     151
     152    if( ( NULL == tc->http ) && shouldConnect( tc ) )
     153    {
     154        if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
     155        {
     156            return 0;
     157        }
     158        tc->dateTry = tr_date();
     159        tc->http = getQuery( tc );
    167160
    168161        tr_inf( "Tracker: connecting to %s:%d (%s)",
     
    173166                    ( 0 < tc->newPort ? "sending 'stopped' to change port" :
    174167                      "getting peers" ) ) ) );
    175 
    176         tc->status  = TC_STATUS_RESOLVE;
    177         tc->dateTry = tr_date();
    178     }
    179 
    180     if( tc->status & TC_STATUS_RESOLVE )
    181     {
    182         int ret;
    183         struct in_addr addr;
    184 
    185         ret = tr_netResolvePulse( tc->resolve, &addr );
    186         if( ret == TR_RESOLVE_WAIT )
    187         {
    188             return 0;
    189         }
    190         else
    191         {
    192             tr_netResolveClose( tc->resolve );
    193         }
    194        
    195         if( ret == TR_RESOLVE_ERROR )
    196         {
    197             tc->status = TC_STATUS_IDLE;
    198             return 0;
    199         }
    200 
    201         if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
    202         {
    203             tc->status = TC_STATUS_IDLE;
    204             return 0;
    205         }
    206 
    207         tc->socket = tr_netOpen( addr, htons( inf->trackerPort ) );
    208         if( tc->socket < 0 )
    209         {
    210             tr_fdSocketClosed( tor->fdlimit, 1 );
    211             tc->status = TC_STATUS_IDLE;
    212             return 0;
    213         }
    214 
    215         tc->status = TC_STATUS_CONNECT;
    216     }
    217 
    218     if( tc->status & TC_STATUS_CONNECT )
    219     {
    220         /* We are connecting to the tracker. Try to send the query */
    221         sendQuery( tc );
    222     }
    223 
    224     if( tc->status & TC_STATUS_RECV )
    225     {
    226         /* Try to get something */
    227         recvAnswer( tc );
    228     }
    229 
    230     if( tc->status > TC_STATUS_IDLE && now > tc->dateTry + 60000 )
    231     {
    232         /* Give up if the request wasn't successful within 60 seconds */
    233         tr_inf( "Tracker: timeout reached (60 s)" );
    234 
    235         tr_netClose( tc->socket );
    236         tr_fdSocketClosed( tor->fdlimit, 1 );
    237 
    238         tc->status  = TC_STATUS_IDLE;
    239         tc->dateTry = tr_date();
     168    }
     169
     170    if( NULL != tc->http )
     171    {
     172        switch( tr_httpPulse( tc->http, &data, &len ) )
     173        {
     174            case TR_WAIT:
     175                return 0;
     176
     177            case TR_ERROR:
     178                tr_httpClose( tc->http );
     179                tr_fdSocketClosed( tor->fdlimit, 1 );
     180                tc->http    = NULL;
     181                tc->dateTry = tr_date();
     182                return 0;
     183
     184            case TR_OK:
     185                readAnswer( tc, data, len );
     186                tr_httpClose( tc->http );
     187                tc->http = NULL;
     188                tr_fdSocketClosed( tor->fdlimit, 1 );
     189                break;
     190        }
    240191    }
    241192
     
    254205    tr_torrent_t * tor = tc->tor;
    255206
    256     if( tc->status > TC_STATUS_CONNECT )
     207    if( NULL != tc->http )
    257208    {
    258209        /* If we are already sendy a query at the moment, we need to
    259210           reconnect */
    260         tr_netClose( tc->socket );
     211        tr_httpClose( tc->http );
     212        tc->http = NULL;
    261213        tr_fdSocketClosed( tor->fdlimit, 1 );
    262         tc->status = TC_STATUS_IDLE;
    263214    }
    264215
     
    268219
    269220    /* Even if we have connected recently, reconnect right now */
    270     if( tc->status & TC_STATUS_IDLE )
    271     {
    272         tc->dateTry = 0;
    273     }
     221    tc->dateTry = 0;
    274222}
    275223
     
    278226    tr_torrent_t * tor = tc->tor;
    279227
    280     if( tc->status == TC_STATUS_RESOLVE )
    281     {
    282         tr_netResolveClose( tc->resolve );
    283     }
    284     else if( tc->status > TC_STATUS_RESOLVE )
    285     {
    286         tr_netClose( tc->socket );
     228    if( NULL != tc->http )
     229    {
     230        tr_httpClose( tc->http );
    287231        tr_fdSocketClosed( tor->fdlimit, 1 );
    288232    }
    289     free( tc->buf );
    290233    free( tc );
    291234}
    292235
    293 static void sendQuery( tr_tracker_t * tc )
     236static tr_http_t * getQuery( tr_tracker_t * tc )
    294237{
    295238    tr_torrent_t * tor = tc->tor;
    296239    tr_info_t    * inf = &tor->info;
    297240
    298     char     * event;
    299     uint64_t   left;
    300     int        ret;
    301     uint64_t   down;
    302     uint64_t   up;
     241    char         * event;
     242    uint64_t       left;
     243    uint64_t       down;
     244    uint64_t       up;
    303245
    304246    assert( tor->downloaded >= tc->download && tor->uploaded >= tc->upload );
     
    331273    left = tr_cpLeftBytes( tor->completion );
    332274
    333     ret = snprintf( (char *) tc->buf, tc->size,
    334             "GET %s?"
    335             "info_hash=%s&"
    336             "peer_id=%s&"
    337             "port=%d&"
    338             "uploaded=%"PRIu64"&"
    339             "downloaded=%"PRIu64"&"
    340             "left=%"PRIu64"&"
    341             "compact=1&"
    342             "numwant=50&"
    343             "key=%s"
    344             "%s "
    345             "HTTP/1.1\r\n"
    346             "Host: %s\r\n"
    347             "User-Agent: Transmission/%d.%d\r\n"
    348             "Connection: close\r\n\r\n",
    349             inf->trackerAnnounce, tor->hashString, tc->id,
    350             tc->bindPort, up, down,
    351             left, tor->key, event, inf->trackerAddress,
    352             VERSION_MAJOR, VERSION_MINOR );
    353 
    354     ret = tr_netSend( tc->socket, tc->buf, ret );
    355     if( ret & TR_NET_CLOSE )
    356     {
    357         tr_inf( "Tracker: connection failed" );
    358         tr_netClose( tc->socket );
    359         tr_fdSocketClosed( tor->fdlimit, 1 );
    360         tc->status  = TC_STATUS_IDLE;
    361         tc->dateTry = tr_date();
    362     }
    363     else if( !( ret & TR_NET_BLOCK ) )
    364     {
    365         // printf( "Tracker: sent %s", tc->buf );
    366         tc->status = TC_STATUS_RECV;
    367         tc->pos    = 0;
    368     }
    369 }
    370 
    371 static void recvAnswer( tr_tracker_t * tc )
     275    return tr_httpClient( TR_HTTP_GET, inf->trackerAddress,
     276                          inf->trackerPort,
     277                          "%s?"
     278                          "info_hash=%s&"
     279                          "peer_id=%s&"
     280                          "port=%d&"
     281                          "uploaded=%"PRIu64"&"
     282                          "downloaded=%"PRIu64"&"
     283                          "left=%"PRIu64"&"
     284                          "compact=1&"
     285                          "numwant=50&"
     286                          "key=%s"
     287                          "%s ",
     288                          inf->trackerAnnounce, tor->hashString, tc->id,
     289                          tc->bindPort, up, down, left, tor->key, event );
     290}
     291
     292static void readAnswer( tr_tracker_t * tc, const char * data, int len )
    372293{
    373294    tr_torrent_t * tor = tc->tor;
    374     int ret;
    375295    int i;
     296    int code;
    376297    benc_val_t   beAll;
    377298    benc_val_t * bePeers, * beFoo;
    378     uint8_t * body;
     299    const uint8_t * body;
    379300    int bodylen;
    380301    int shouldfree;
    381302
    382     if( tc->pos == tc->size )
    383     {
    384         tc->size *= 2;
    385         tc->buf   = realloc( tc->buf, tc->size );
    386     }
    387    
    388     ret = tr_netRecv( tc->socket, &tc->buf[tc->pos],
    389                     tc->size - tc->pos );
    390 
    391     if( ret & TR_NET_BLOCK )
    392     {
    393         return;
    394     }
    395     if( !( ret & TR_NET_CLOSE ) )
    396     {
    397         // printf( "got %d bytes\n", ret );
    398         tc->pos += ret;
    399         return;
    400     }
    401 
    402     tr_netClose( tc->socket );
    403     tr_fdSocketClosed( tor->fdlimit, 1 );
    404     // printf( "connection closed, got total %d bytes\n", tc->pos );
    405 
    406     tc->status  = TC_STATUS_IDLE;
    407303    tc->dateTry = tr_date();
    408 
    409     if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) &&
    410                           0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) )
    411     {
    412         /* We don't have a complete HTTP status line */
    413         tr_inf( "Tracker: incomplete HTTP status line" );
     304    code = tr_httpResponseCode( data, len );
     305    if( 0 > code )
     306    {
     307        /* We don't have a valid HTTP status line */
     308        tr_inf( "Tracker: invalid HTTP status line" );
    414309        tc->lastAttempt = TC_ATTEMPT_NOREACH;
    415310        return;
    416311    }
    417312
    418     if( '2' != tc->buf[9] )
     313    if( !TR_HTTP_STATUS_OK( code ) )
    419314    {
    420315        /* we didn't get a 2xx status code */
    421         tr_err( "Tracker: invalid HTTP status code: %c%c%c",
    422                 tc->buf[9], tc->buf[10], tc->buf[11] );
     316        tr_err( "Tracker: invalid HTTP status code: %i", code );
    423317        tc->lastAttempt = TC_ATTEMPT_ERROR;
    424318        return;
     
    426320
    427321    /* find the end of the http headers */
    428     body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 );
    429     if( NULL != body )
    430     {
    431         body += 4;
    432     }
    433     /* hooray for trackers that violate the HTTP spec */
    434     else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) ||
    435              NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) )
    436     {
    437         body += 2;
    438     }
    439     else
     322    body = (uint8_t *) tr_httpParse( data, len, NULL );
     323    if( NULL == body )
    440324    {
    441325        tr_err( "Tracker: could not find end of HTTP headers" );
     
    443327        return;
    444328    }
    445     bodylen = tc->pos - (body - tc->buf);
     329    bodylen = len - (body - (const uint8_t*)data);
    446330
    447331    /* Find and load the dictionary */
     
    611495    tr_info_t * inf = &tor->info;
    612496
    613     int s, i, ret;
    614     uint8_t buf[1024];
    615     benc_val_t scrape, * val1, * val2;
    616     struct in_addr addr;
    617     uint64_t date;
    618     int pos, len;
    619     tr_resolve_t * resolve;
     497    tr_http_t  * http;
     498    const char * data, * body;
     499    int          datalen, bodylen;
     500    int          code, ii;
     501    benc_val_t   scrape, * val1, * val2;
    620502
    621503    if( !tor->scrape[0] )
     
    625507    }
    626508
    627     resolve = tr_netResolveInit( inf->trackerAddress );
    628     for( date = tr_date();; )
    629     {
    630         ret = tr_netResolvePulse( resolve, &addr );
    631         if( ret == TR_RESOLVE_OK )
    632         {
    633             tr_netResolveClose( resolve );
     509    http = tr_httpClient( TR_HTTP_GET, inf->trackerAddress, inf->trackerPort,
     510                          "%s?info_hash=%s", tor->scrape, tor->hashString );
     511
     512    data = NULL;
     513    while( NULL == data )
     514    {
     515        switch( tr_httpPulse( http, &data, &datalen ) )
     516        {
     517            case TR_WAIT:
     518                break;
     519
     520            case TR_ERROR:
     521                tr_httpClose( http );
     522                return 1;
     523
     524            case TR_OK:
     525                if( NULL == data || 0 >= datalen )
     526                {
     527                    tr_httpClose( http );
     528                    return 1;
     529                }
     530                break;
     531        }
     532        tr_wait( 10 );
     533    }
     534
     535    code = tr_httpResponseCode( data, datalen );
     536    if( !TR_HTTP_STATUS_OK( code ) )
     537    {
     538        tr_httpClose( http );
     539        return 1;
     540    }
     541
     542    body = tr_httpParse( data, datalen , NULL );
     543    if( NULL == body )
     544    {
     545        tr_httpClose( http );
     546        return 1;
     547    }
     548    bodylen = datalen - ( body - data );
     549
     550    for( ii = 0; ii < bodylen - 8; ii++ )
     551    {
     552        if( !memcmp( body + ii, "d5:files", 8 ) )
     553        {
    634554            break;
    635555        }
    636         if( ret == TR_RESOLVE_ERROR ||
    637             ( ret == TR_RESOLVE_WAIT && tr_date() > date + 10000 ) )
    638         {
    639             tr_err( "Could not resolve %s", inf->trackerAddress );
    640             tr_netResolveClose( resolve );
    641             return 1;
    642         }
    643         tr_wait( 10 );
    644     }
    645 
    646     s = tr_netOpen( addr, htons( inf->trackerPort ) );
    647     if( s < 0 )
    648     {
    649         return 1;
    650     }
    651 
    652     len = snprintf( (char *) buf, sizeof( buf ),
    653               "GET %s?info_hash=%s HTTP/1.1\r\n"
    654               "Host: %s\r\n"
    655               "Connection: close\r\n\r\n",
    656               tor->scrape, tor->hashString,
    657               inf->trackerAddress );
    658 
    659     for( date = tr_date();; )
    660     {
    661         ret = tr_netSend( s, buf, len );
    662         if( ret & TR_NET_CLOSE )
    663         {
    664             tr_err( "Could not connect to tracker" );
    665             tr_netClose( s );
    666             return 1;
    667         }
    668         else if( ret & TR_NET_BLOCK )
    669         {
    670             if( tr_date() > date + 10000 )
    671             {
    672                 tr_err( "Could not connect to tracker" );
    673                 tr_netClose( s );
    674                 return 1;
    675             }
    676         }
    677         else
    678         {
    679             break;
    680         }
    681         tr_wait( 10 );
    682     }
    683 
    684     pos = 0;
    685     for( date = tr_date();; )
    686     {
    687         ret = tr_netRecv( s, &buf[pos], sizeof( buf ) - pos );
    688         if( ret & TR_NET_CLOSE )
    689         {
    690             break;
    691         }
    692         else if( ret & TR_NET_BLOCK )
    693         {
    694             if( tr_date() > date + 10000 )
    695             {
    696                 tr_err( "Could not read from tracker" );
    697                 tr_netClose( s );
    698                 return 1;
    699             }
    700         }
    701         else
    702         {
    703             pos += ret;
    704         }
    705         tr_wait( 10 );
    706     }
    707 
    708     if( pos < 1 )
    709     {
    710         tr_err( "Could not read from tracker" );
    711         tr_netClose( s );
    712         return 1;
    713     }
    714 
    715     for( i = 0; i < pos - 8; i++ )
    716     {
    717         if( !memcmp( &buf[i], "d5:files", 8 ) )
    718         {
    719             break;
    720         }
    721     }
    722     if( i >= pos - 8 )
    723     {
    724         return 1;
    725     }
    726     if( tr_bencLoad( &buf[i], pos - i, &scrape, NULL ) )
    727     {
     556    }
     557    if( ii >= bodylen - 8 )
     558    {
     559        tr_httpClose( http );
     560        return 1;
     561    }
     562    if( tr_bencLoad( body + ii, bodylen - ii, &scrape, NULL ) )
     563    {
     564        tr_httpClose( http );
    728565        return 1;
    729566    }
     
    732569    if( !val1 )
    733570    {
     571        tr_bencFree( &scrape );
     572        tr_httpClose( http );
    734573        return 1;
    735574    }
     
    737576    if( !val1 )
    738577    {
     578        tr_bencFree( &scrape );
     579        tr_httpClose( http );
    739580        return 1;
    740581    }
     
    742583    if( !val2 )
    743584    {
     585        tr_bencFree( &scrape );
     586        tr_httpClose( http );
    744587        return 1;
    745588    }
     
    748591    if( !val2 )
    749592    {
     593        tr_bencFree( &scrape );
     594        tr_httpClose( http );
    750595        return 1;
    751596    }
    752597    *leechers = val2->val.i;
    753598    tr_bencFree( &scrape );
     599    tr_httpClose( http );
    754600
    755601    return 0;
Note: See TracChangeset for help on using the changeset viewer.