Changeset 11632


Ignore:
Timestamp:
Jan 6, 2011, 1:00:21 AM (12 years ago)
Author:
jordan
Message:

(trunk libT) #3519 "webseeds don't work" -- fixed.

Location:
trunk/libtransmission
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/peer-common.h

    r11599 r11632  
    8686struct tr_peer;
    8787
    88 typedef void tr_peer_callback( struct tr_peer      * peer,
    89                               const tr_peer_event  * event,
    90                               void                 * client_data );
     88typedef void tr_peer_callback( struct tr_peer       * peer,
     89                               const tr_peer_event  * event,
     90                               void                 * client_data );
    9191
    9292#ifdef WIN32
  • trunk/libtransmission/peer-mgr.c

    r11599 r11632  
    161161tr_atomAddrStr( const struct peer_atom * atom )
    162162{
    163     return tr_peerIoAddrStr( &atom->addr, atom->port );
     163    return atom ? tr_peerIoAddrStr( &atom->addr, atom->port ) : "[no atom]";
    164164}
    165165
     
    12001200            for( it=t->requests, end=it+n; it!=end; ++it )
    12011201            {
    1202                 if( ( it->sentAt <= too_old ) && !tr_peerMsgsIsReadingBlock( it->peer->msgs, it->block ) )
     1202                if( ( it->sentAt <= too_old ) && it->peer->msgs && !tr_peerMsgsIsReadingBlock( it->peer->msgs, it->block ) )
    12031203                    cancel[cancelCount++] = *it;
    12041204                else
     
    14081408
    14091409            /* update our atom */
    1410             if( peer && e->wasPieceData )
     1410            if( peer && peer->atom && e->wasPieceData )
    14111411                peer->atom->piece_data_time = now;
    14121412
     
    14351435            pieceListRemoveRequest( t, block );
    14361436
    1437             if( peer != NULL )
     1437            if( peer && peer->blocksSentToClient )
    14381438                tr_historyAdd( peer->blocksSentToClient, tr_time( ), 1 );
    14391439
     
    14831483                         * to manage the swarms, not the web server and does not fit
    14841484                         * into the jurisdiction of the tracker." */
    1485                         if( peer != NULL ) {
     1485                        if( peer->msgs != NULL ) {
    14861486                            const uint32_t n = tr_torPieceCountBytes( tor, p );
    14871487                            tr_announcerAddBytes( tor, TR_ANN_DOWN, n );
  • trunk/libtransmission/ratecontrol.c

    r10998 r11632  
    7474
    7575void
    76 tr_rcTransferred( tr_ratecontrol * r,
    77                   size_t           size )
     76tr_rcTransferred( tr_ratecontrol * r, size_t size )
    7877{
    7978    const uint64_t now = tr_time_msec ( );
  • trunk/libtransmission/web.c

    r11610 r11632  
    7474    long code;
    7575    struct evbuffer * response;
     76    struct evbuffer * freebuf;
    7677    char * url;
    7778    char * range;
     
    8485task_free( struct tr_web_task * task )
    8586{
    86     evbuffer_free( task->response );
     87    if( task->freebuf )
     88        evbuffer_free( task->freebuf );
    8789    tr_free( task->range );
    8890    tr_free( task->url );
     
    215217           void               * done_func_user_data )
    216218{
     219    tr_webRunWithBuffer( session, url, range,
     220                         done_func, done_func_user_data,
     221                         NULL );
     222}
     223
     224void
     225tr_webRunWithBuffer( tr_session         * session,
     226                     const char         * url,
     227                     const char         * range,
     228                     tr_web_done_func     done_func,
     229                     void               * done_func_user_data,
     230                     struct evbuffer    * buffer )
     231{
    217232    struct tr_web * web = session->web;
    218233
     
    226241        task->done_func = done_func;
    227242        task->done_func_user_data = done_func_user_data;
    228         task->response = evbuffer_new( );
     243        task->response = buffer ? buffer : evbuffer_new( );
     244        task->freebuf = buffer ? NULL : task->response;
    229245
    230246        tr_lockLock( web->taskLock );
  • trunk/libtransmission/web.h

    r11599 r11632  
    5151const char * tr_webGetResponseStr( long response_code );
    5252
    53 void         tr_webRun( tr_session        * session,
    54                         const char        * url,
    55                         const char        * range,
    56                         tr_web_done_func    done_func,
    57                         void              * done_func_user_data );
     53void tr_webRun( tr_session        * session,
     54                const char        * url,
     55                const char        * range,
     56                tr_web_done_func    done_func,
     57                void              * done_func_user_data );
    5858
    5959struct evbuffer;
     60
     61void tr_webRunWithBuffer( tr_session         * session,
     62                          const char         * url,
     63                          const char         * range,
     64                          tr_web_done_func     done_func,
     65                          void               * done_func_user_data,
     66                          struct evbuffer    * buffer );
    6067
    6168void tr_http_escape( struct evbuffer *out, const char *str, int len, tr_bool escape_slashes );
  • trunk/libtransmission/webseed.c

    r11599 r11632  
    1111 */
    1212
    13 #include <string.h> /* strlen */
     13#include <string.h> /* strlen() */
    1414
    1515#include <event2/buffer.h>
     16#include <event2/event.h>
    1617
    1718#include "transmission.h"
    18 #include "inout.h"
     19#include "cache.h"
     20#include "inout.h" /* tr_ioFindFileLocation() */
     21#include "list.h"
    1922#include "ratecontrol.h"
     23#include "peer-mgr.h"
    2024#include "torrent.h"
    2125#include "utils.h"
     
    2327#include "webseed.h"
    2428
     29struct tr_webseed_task
     30{
     31    tr_session         * session;
     32    struct evbuffer    * content;
     33    struct tr_webseed  * webseed;
     34    tr_block_index_t     block;
     35    tr_piece_index_t     piece_index;
     36    uint32_t             piece_offset;
     37    uint32_t             length;
     38    int                  torrent_id;
     39};
     40
    2541struct tr_webseed
    2642{
    27     tr_bool             busy;
    28     tr_bool             dead;
    29 
    30     uint8_t             hash[SHA_DIGEST_LENGTH];
    31 
    32     char              * url;
    33 
    34     tr_peer_callback  * callback;
    35     void              * callback_data;
    36 
    37     tr_piece_index_t    pieceIndex;
    38     uint32_t            pieceOffset;
    39     uint32_t            byteCount;
    40 
    41     tr_ratecontrol      rateDown;
    42 
    43     tr_session        * session;
    44 
    45     struct evbuffer   * content;
     43    tr_peer              parent;
     44    tr_ratecontrol       download_rate;
     45    tr_session         * session;
     46    tr_peer_callback   * callback;
     47    void               * callback_data;
     48    tr_list            * tasks;
     49    struct event       * timer;
     50    char               * base_url;
     51    size_t               base_url_len;
     52    int                  torrent_id;
     53    tr_bool              is_stopping;
    4654};
     55
     56static void
     57webseed_free( struct tr_webseed * w )
     58{
     59    tr_bitsetDestructor( &w->parent.have );
     60    tr_free( w->parent.client );
     61
     62    event_free( w->timer );
     63    tr_rcDestruct( &w->download_rate );
     64    tr_free( w->base_url );
     65    tr_free( w );
     66}
    4767
    4868/***
     
    5676{
    5777    if( w->callback != NULL )
    58         w->callback( NULL, e, w->callback_data );
    59 }
    60 
    61 static void
    62 fireNeedReq( tr_webseed * w )
    63 {
    64 #if 0
     78        w->callback( &w->parent, e, w->callback_data );
     79}
     80
     81static void
     82fireClientGotBlock( tr_torrent * tor, tr_webseed * w, tr_block_index_t block )
     83{
    6584    tr_peer_event e = blankEvent;
    66     e.eventType = TR_PEER_NEED_REQ;
    67     publish( w, &e );
    68 #endif
    69 }
    70 
    71 static void
    72 fireClientGotBlock( tr_webseed * w, uint32_t pieceIndex, uint32_t offset, uint32_t length )
    73 {
    74     tr_peer_event e = blankEvent;
     85    e.pieceIndex = tr_torBlockPiece( tor, block );
     86    e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
     87    e.length = tr_torBlockCountBytes( tor, block );
    7588    e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
    76     e.pieceIndex = pieceIndex;
    77     e.offset = offset;
    78     e.length = length;
    7989    publish( w, &e );
    8090}
     
    94104***/
    95105
     106static void
     107on_content_changed( struct evbuffer                * buf UNUSED,
     108                    const struct evbuffer_cb_info  * info,
     109                    void                           * vw )
     110{
     111    tr_webseed * w = vw;
     112
     113    if( ( info->n_added > 0 ) && !w->is_stopping )
     114    {
     115        tr_rcTransferred( &w->download_rate, info->n_added );
     116        fireClientGotData( w, info->n_added );
     117    }
     118}
     119
     120static void task_request_next_chunk( struct tr_webseed_task * task );
     121
     122static void
     123on_idle( tr_webseed * w )
     124{
     125    tr_torrent * tor = tr_torrentFindFromId( w->session, w->torrent_id );
     126
     127    if( w->is_stopping && !tr_webseedIsActive( w ) )
     128    {
     129        webseed_free( w );
     130    }
     131    else if( !w->is_stopping && tor && tor->isRunning && !tr_torrentIsSeed( tor ) )
     132    {
     133        int i;
     134        int got = 0;
     135        const int max = tor->blockCountInPiece;
     136        const int want = max - tr_list_size( w->tasks );
     137        tr_block_index_t * blocks = NULL;
     138
     139        if( want > 0 )
     140        {
     141            blocks = tr_new( tr_block_index_t, want );
     142            tr_peerMgrGetNextRequests( tor, &w->parent, want, blocks, &got );
     143        }
     144
     145        for( i=0; i<got; ++i )
     146        {
     147            const tr_block_index_t b = blocks[i];
     148            struct tr_webseed_task * task = tr_new( struct tr_webseed_task, 1 );
     149            task->webseed = w;
     150            task->session = w->session;
     151            task->torrent_id = w->torrent_id;
     152            task->block = b;
     153            task->piece_index = tr_torBlockPiece( tor, b );
     154            task->piece_offset = ( tor->blockSize * b )
     155                                   - ( tor->info.pieceSize * task->piece_index );
     156            task->length = tr_torBlockCountBytes( tor, b );
     157            task->content = evbuffer_new( );
     158            evbuffer_add_cb( task->content, on_content_changed, w );
     159            tr_list_append( &w->tasks, task );
     160            task_request_next_chunk( task );
     161        }
     162
     163        tr_free( blocks );
     164    }
     165}
     166
     167
     168static void
     169web_response_func( tr_session    * session,
     170                   long            response_code,
     171                   const void    * response UNUSED,
     172                   size_t          response_byte_count UNUSED,
     173                   void          * vtask )
     174{
     175    struct tr_webseed_task * t = vtask;
     176    tr_torrent * tor = tr_torrentFindFromId( session, t->torrent_id );
     177    const int success = ( response_code == 206 );
     178
     179    if( success && tor )
     180    {
     181        if( evbuffer_get_length( t->content ) < t->length )
     182        {
     183            task_request_next_chunk( t );
     184        }
     185        else
     186        {
     187            tr_webseed * w = t->webseed;
     188
     189            tr_cacheWriteBlock( session->cache, tor,
     190                                t->piece_index, t->piece_offset, t->length,
     191                                evbuffer_pullup( t->content, -1 ) );
     192            fireClientGotBlock( tor, w, t->block );
     193
     194            tr_list_remove_data( &w->tasks, t );
     195            evbuffer_free( t->content );
     196            tr_free( t );
     197
     198            on_idle( w );
     199        }
     200    }
     201}
     202
    96203static char*
    97 makeURL( tr_webseed *    w,
    98          const tr_file * file )
     204make_url( tr_webseed * w, const tr_file * file )
    99205{
    100206    struct evbuffer * out = evbuffer_new( );
    101     const char *      url = w->url;
    102     const size_t      url_len = strlen( url );
    103 
    104     evbuffer_add( out, url, url_len );
     207
     208    evbuffer_add( out, w->base_url, w->base_url_len );
    105209
    106210    /* if url ends with a '/', add the torrent name */
    107     if( url[url_len - 1] == '/' && file->name )
     211    if( w->base_url[w->base_url_len - 1] == '/' && file->name )
    108212        tr_http_escape( out, file->name, strlen(file->name), FALSE );
    109213
     
    111215}
    112216
    113 static void requestNextChunk( tr_webseed * w );
    114 
    115 static void
    116 webResponseFunc( tr_session    * session,
    117                  long            response_code,
    118                  const void    * response,
    119                  size_t          response_byte_count,
    120                  void          * vw )
    121 {
    122     tr_webseed * w = vw;
    123     tr_torrent * tor = tr_torrentFindFromHash( session, w->hash );
    124     const int    success = ( response_code == 206 );
    125 
    126 /*fprintf( stderr, "server responded with code %ld and %lu bytes\n",
    127   response_code, (unsigned long)response_byte_count );*/
    128     if( !success )
    129     {
    130         /* FIXME */
    131     }
    132     else if( tor != NULL )
    133     {
    134         evbuffer_add( w->content, response, response_byte_count );
    135         if( !w->dead )
    136         {
    137             fireClientGotData( w, response_byte_count );
    138             tr_rcTransferred( &w->rateDown, response_byte_count );
    139         }
    140 
    141         if( evbuffer_get_length( w->content ) < w->byteCount )
    142             requestNextChunk( w );
    143         else {
    144             tr_ioWrite( tor, w->pieceIndex, w->pieceOffset, w->byteCount, evbuffer_pullup( w->content, -1 ) );
    145             evbuffer_drain( w->content, evbuffer_get_length( w->content ) );
    146             w->busy = 0;
    147             if( w->dead )
    148                 tr_webseedFree( w );
    149             else  {
    150                 fireClientGotBlock( w, w->pieceIndex, w->pieceOffset, w->byteCount );
    151                 fireNeedReq( w );
    152             }
    153         }
    154     }
    155 }
    156 
    157 static void
    158 requestNextChunk( tr_webseed * w )
    159 {
    160     tr_torrent * tor = tr_torrentFindFromHash( w->session, w->hash );
    161 
     217static void
     218task_request_next_chunk( struct tr_webseed_task * t )
     219{
     220    tr_torrent * tor = tr_torrentFindFromId( t->session, t->torrent_id );
    162221    if( tor != NULL )
    163222    {
     223        char * url;
     224        char range[64];
     225
    164226        const tr_info * inf = tr_torrentInfo( tor );
    165         const uint32_t have = evbuffer_get_length( w->content );
    166         const uint32_t left = w->byteCount - have;
    167         const uint32_t pieceOffset = w->pieceOffset + have;
    168         tr_file_index_t fileIndex;
    169         uint64_t fileOffset;
    170         uint32_t thisPass;
    171         char * url;
    172         char * range;
    173 
    174         tr_ioFindFileLocation( tor, w->pieceIndex, pieceOffset,
    175                                &fileIndex, &fileOffset );
    176         thisPass = MIN( left, inf->files[fileIndex].length - fileOffset );
    177 
    178         url = makeURL( w, &inf->files[fileIndex] );
    179 /*fprintf( stderr, "url is [%s]\n", url );*/
    180         range = tr_strdup_printf( "%"PRIu64"-%"PRIu64, fileOffset, fileOffset + thisPass - 1 );
    181 /*fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are left, and we're asking for %lu this time\n", range, (unsigned long)w->byteCount, (unsigned long)have, (unsigned long)left, (unsigned long)thisPass );*/
    182         tr_webRun( w->session, url, range, webResponseFunc, w );
    183         tr_free( range );
     227        const uint32_t remain = t->length - evbuffer_get_length( t->content );
     228
     229        const uint64_t total_offset = inf->pieceSize * t->piece_index
     230                                    + t->piece_offset
     231                                    + evbuffer_get_length( t->content );
     232        const tr_piece_index_t step_piece = total_offset / inf->pieceSize;
     233        const uint32_t step_piece_offset = total_offset - ( inf->pieceSize * step_piece );
     234
     235        tr_file_index_t file_index;
     236        uint64_t file_offset;
     237        const tr_file * file;
     238        uint32_t this_pass;
     239
     240        tr_ioFindFileLocation( tor, step_piece, step_piece_offset,
     241                                    &file_index, &file_offset );
     242        file = &inf->files[file_index];
     243        this_pass = MIN( remain, file->length - file_offset );
     244
     245        url = make_url( t->webseed, file );
     246        tr_snprintf( range, sizeof range, "%"PRIu64"-%"PRIu64,
     247                     file_offset, file_offset + this_pass - 1 );
     248        tr_webRunWithBuffer( t->session, url, range,
     249                             web_response_func, t, t->content );
    184250        tr_free( url );
    185251    }
    186252}
    187253
    188 tr_addreq_t
    189 tr_webseedAddRequest( tr_webseed  * w,
    190                       uint32_t      pieceIndex,
    191                       uint32_t      pieceOffset,
    192                       uint32_t      byteCount )
    193 {
    194     int ret;
    195 
    196     if( w->busy || w->dead )
    197     {
    198         ret = TR_ADDREQ_FULL;
    199     }
    200     else
    201     {
    202         w->busy = 1;
    203         w->pieceIndex = pieceIndex;
    204         w->pieceOffset = pieceOffset;
    205         w->byteCount = byteCount;
    206         evbuffer_drain( w->content, evbuffer_get_length( w->content ) );
    207         requestNextChunk( w );
    208         ret = TR_ADDREQ_OK;
    209     }
    210 
    211     return ret;
    212 }
    213 
    214 int
     254tr_bool
    215255tr_webseedIsActive( const tr_webseed * w )
    216256{
    217     return w->busy != 0;
    218 }
    219 
    220 int
     257    return w->tasks != NULL;
     258}
     259
     260tr_bool
    221261tr_webseedGetSpeed_Bps( const tr_webseed * w, uint64_t now, int * setme_Bps )
    222262{
    223     const int isActive = tr_webseedIsActive( w );
    224     *setme_Bps = isActive ? tr_rcRate_Bps( &w->rateDown, now ) : 0;
    225     return isActive;
     263    const tr_bool is_active = tr_webseedIsActive( w );
     264    *setme_Bps = is_active ? tr_rcRate_Bps( &w->download_rate, now ) : 0;
     265    return is_active;
    226266}
    227267
     
    230270***/
    231271
     272static void
     273webseed_timer_func( evutil_socket_t foo UNUSED, short bar UNUSED, void * vw )
     274{
     275    tr_webseed * w = vw;
     276    on_idle( w );
     277    tr_timerAddMsec( w->timer, 1000 );
     278}
     279
    232280tr_webseed*
    233 tr_webseedNew( struct tr_torrent * torrent,
     281tr_webseedNew( struct tr_torrent * tor,
    234282               const char        * url,
    235283               tr_peer_callback  * callback,
     
    237285{
    238286    tr_webseed * w = tr_new0( tr_webseed, 1 );
    239 
    240     memcpy( w->hash, torrent->info.hash, SHA_DIGEST_LENGTH );
    241     w->session = torrent->session;
    242     w->content = evbuffer_new( );
    243     w->url = tr_strdup( url );
     287    tr_peer * peer = &w->parent;
     288
     289    peer->peerIsChoked = TRUE;
     290    peer->peerIsInterested = FALSE;
     291    peer->clientIsChoked = FALSE;
     292    peer->clientIsChoked = FALSE;
     293    peer->clientIsInterested = !tr_torrentIsSeed( tor );
     294    tr_bitsetConstructor( &peer->have, tor->info.pieceCount );
     295    tr_bitsetSetHaveAll( &peer->have );
     296    peer->progress = 1.0;
     297    peer->client = tr_strdup( "webseed" );
     298
     299    w->torrent_id = tr_torrentId( tor );
     300    w->session = tor->session;
     301
     302    w->base_url_len = strlen( url );
     303    w->base_url = tr_strndup( url, w->base_url_len );
    244304    w->callback = callback;
    245305    w->callback_data = callback_data;
    246     tr_rcConstruct( &w->rateDown );
     306    tr_rcConstruct( &w->download_rate );
     307    w->timer = evtimer_new( w->session->event_base, webseed_timer_func, w );
     308    tr_timerAddMsec( w->timer, 1000 );
    247309    return w;
    248310}
     
    253315    if( w )
    254316    {
    255         if( w->busy )
    256         {
    257             w->dead = 1;
    258         }
     317        if( tr_webseedIsActive( w ) )
     318            w->is_stopping = TRUE;
    259319        else
    260         {
    261             evbuffer_free( w->content );
    262             tr_rcDestruct( &w->rateDown );
    263             tr_free( w->url );
    264             tr_free( w );
    265         }
    266     }
    267 }
     320            webseed_free( w );
     321    }
     322}
  • trunk/libtransmission/webseed.h

    r11599 r11632  
    2929void        tr_webseedFree( tr_webseed * );
    3030
    31 tr_addreq_t tr_webseedAddRequest( tr_webseed *     w,
    32                                   uint32_t         index,
    33                                   uint32_t         offset,
    34                                   uint32_t         length );
    35 
    3631/** @return true if a request is being processed, or false if idle */
    37 int         tr_webseedGetSpeed_Bps( const tr_webseed * w,
     32tr_bool     tr_webseedGetSpeed_Bps( const tr_webseed * w,
    3833                                    uint64_t           now,
    3934                                    int              * setme_Bps );
    4035
    4136/** @return true if a request is being processed, or false if idle */
    42 int         tr_webseedIsActive( const tr_webseed * w );
     37tr_bool     tr_webseedIsActive( const tr_webseed * w );
    4338
    4439
Note: See TracChangeset for help on using the changeset viewer.