Changeset 5673


Ignore:
Timestamp:
Apr 24, 2008, 1:42:53 AM (14 years ago)
Author:
charles
Message:

#377: preliminary https support. this commit probably breaks mac and cli and is not for the faint of heart.

Location:
trunk
Files:
2 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/cli/Makefile.am

    r5500 r5673  
    11AM_CPPFLAGS = -I$(top_srcdir) $(LIBEVENT_CPPFLAGS)
    2 AM_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
     2AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
    33
    44bin_PROGRAMS = transmissioncli
     
    99
    1010transmissioncli_LDADD = \
    11     $(top_builddir)/libtransmission/libtransmission.a \
    12     $(top_builddir)/third-party/libevent/libevent.la \
    13     $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    14     $(top_builddir)/third-party/miniupnp/libminiupnp.a \
    15     $(INTLLIBS) $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
     11  $(top_builddir)/libtransmission/libtransmission.a \
     12  $(top_builddir)/third-party/libevent/libevent.la \
     13  $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
     14  $(top_builddir)/third-party/miniupnp/libminiupnp.a \
     15  $(INTLLIBS) \
     16  $(OPENSSL_LIBS) \
     17  $(LIBCURL_LIBS) \
     18  $(PTHREAD_LIBS) \
     19  -lm
    1620
  • trunk/configure.ac

    r5653 r5673  
    1111AC_PROG_LIBTOOL
    1212
     13CURL_MINIMUM=7.16.0
    1314GIO_MINIMUM=2.15.5
    1415GLIB_MINIMUM=2.6.0
     
    1718LIBNOTIFY_MINIMUM=0.4.4
    1819DBUS_GLIB_MINIMUM=0.70
     20AC_SUBST(CURL_MINIMUM)
    1921AC_SUBST(GIO_MINIMUM)
    2022AC_SUBST(GLIB_MINIMUM)
     
    4244AC_SEARCH_LIBS([gethostbyname], [nsl bind])
    4345PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.4])
     46PKG_CHECK_MODULES(LIBCURL, [libcurl >= 0.9.4])
    4447
    4548AC_SYS_LARGEFILE
  • trunk/daemon/Makefile.am

    r5500 r5673  
    11AM_CPPFLAGS = -I@top_srcdir@ $(LIBEVENT_CPPFLAGS)
    2 AM_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
     2AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
    33
    44noinst_LIBRARIES = libdaemon.a
     
    3333    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    3434    $(top_builddir)/third-party/libevent/libevent.la \
    35     $(INTLLIBS) $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
     35    $(INTLLIBS) \
     36    $(OPENSSL_LIBS) \
     37    $(LIBCURL_LIBS) \
     38    $(PTHREAD_LIBS) -lm
    3639
    3740transmission_daemon_SOURCES = daemon.c server.c torrents.c
  • trunk/gtk/Makefile.am

    r5605 r5673  
    1010    $(GTK_CFLAGS) \
    1111    $(OPENSSL_CFLAGS) \
     12    $(LIBCURL_CFLAGS) \
    1213    $(PTHREAD_CFLAGS) \
    1314    $(GIO_CFLAGS) \
     
    7980    $(DBUS_GLIB_LIBS) \
    8081    $(OPENSSL_LIBS) \
     82    $(LIBCURL_LIBS) \
    8183    $(PTHREAD_LIBS) -lm
    8284
  • trunk/gtk/details.c

    r5595 r5673  
    11201120    int row = 0;
    11211121    const char * s;
    1122     char * tmp;
    11231122    struct tracker_page * page = g_new0( struct tracker_page, 1 );
    1124     const tr_tracker_info * track;
    11251123    const tr_info * info = tr_torrent_info (gtor);
    11261124
     
    11481146    hig_workarea_add_section_title( t, &row, _( "Announce" ) );
    11491147
    1150         track = info->trackerList->list;
    1151         tmp = track->port==80
    1152           ? g_strdup_printf( "http://%s%s", track->address, track->announce )
    1153           : g_strdup_printf( "http://%s:%d%s", track->address, track->port, track->announce );
    1154         l = gtk_label_new( tmp );
     1148        l = gtk_label_new( info->trackers[0].announce );
    11551149        gtk_label_set_ellipsize( GTK_LABEL( l ), PANGO_ELLIPSIZE_END );
    11561150        hig_workarea_add_row (t, &row, _( "Tracker:" ), l, NULL);
    1157         g_free( tmp );
    11581151
    11591152        s = _( "Last announce at:" );
  • trunk/gtk/tr-core.c

    r5646 r5673  
    284284    gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
    285285    gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
    286     return strcmp( tr_torrentInfo(ta)->primaryAddress,
    287                    tr_torrentInfo(tb)->primaryAddress );
     286    return strcmp( tr_torrentInfo(ta)->trackers[0].announce,
     287                   tr_torrentInfo(tb)->trackers[0].announce );
    288288}
    289289
  • trunk/gtk/tr-window.c

    r5662 r5673  
    275275
    276276        case FILTER_TEXT_MODE_TRACKER:
    277             pch = g_ascii_strdown( torInfo->primaryAddress, -1 );
     277            pch = g_ascii_strdown( torInfo->trackers[0].announce, -1 );
    278278            ret = !text || ( strstr( pch, text ) != NULL );
    279279            g_free( pch );
  • trunk/libtransmission/Makefile.am

    r5606 r5673  
    11AM_CPPFLAGS = -I. -I$(top_srcdir) -I$(top_srcdir)/third-party/ -D__TRANSMISSION__ $(LIBEVENT_CPPFLAGS)
    2 AM_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
     2AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
    33
    44noinst_LIBRARIES = libtransmission.a
     
    3838    upnp.c \
    3939    utils.c \
    40     verify.c
     40    verify.c \
     41    web.c
    4142
    4243noinst_HEADERS = \
     
    7677    upnp.h \
    7778    utils.h \
    78     verify.h
     79    verify.h \
     80    web.h
    7981
    8082bin_PROGRAMS = benc2php
     
    9395    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    9496    $(top_builddir)/third-party/libevent/libevent.la \
    95     $(INTLLIBS) $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
     97    $(INTLLIBS) \
     98    $(OPENSSL_LIBS) \
     99    $(LIBCURL_LIBS) \
     100    $(PTHREAD_LIBS) \
     101    -lm
    96102
    97103benc2php_SOURCES = benc2php.c
  • trunk/libtransmission/ipcparse.c

    r5643 r5673  
    532532{
    533533    tr_bencInitDict( val, 4 );
    534     tr_bencDictAddStr( val, "address",  tk->address );
    535     tr_bencDictAddInt( val, "port",     tk->port );
    536534    tr_bencDictAddStr( val, "announce", tk->announce );
    537535    if( tk->scrape )
     
    555553{
    556554    tr_benc * dict;
    557     int          ii, jj, kk;
     555    int          ii, jj;
    558556    tr_file_index_t ff;
    559557    const tr_info * inf = tr_torrentInfo( tor );
     
    629627                tr_bencInitInt( item, inf->totalSize );
    630628                break;
    631             case IPC_INF_TRACKERS:
    632                 tr_bencInitList( item, inf->trackerTiers );
    633                 for( jj = 0; inf->trackerTiers > jj; jj++ )
    634                 {
    635                     tr_benc * tier = tr_bencListAdd( item );
    636                     tr_bencInitList( tier, inf->trackerList[jj].count );
    637                     for( kk = 0; inf->trackerList[jj].count > kk; kk++ )
    638                         filltracker( tr_bencListAdd( tier ),
    639                                      &inf->trackerList[jj].list[kk] );
    640                 }
    641                 break;
     629            case IPC_INF_TRACKERS: {
     630                int prevTier = -1;
     631                tr_benc * tier = NULL;
     632                tr_bencInitList( item, 0 );
     633                for( jj=0; jj<inf->trackerCount; ++jj ) {
     634                    if( prevTier != inf->trackers[jj].tier ) {
     635                        prevTier = inf->trackers[jj].tier;
     636                        tier = tr_bencListAddList( item, 0 );
     637                    }
     638                    filltracker( tr_bencListAdd( tier ), &inf->trackers[jj] );
     639                }
     640                break;
     641            }
    642642            default:
    643643                assert( 0 );
  • trunk/libtransmission/metainfo.c

    r5613 r5673  
    3232#include <sys/stat.h>
    3333#include <unistd.h> /* unlink, stat */
     34
     35#include <event.h> /* struct evbuffer */
    3436
    3537#include "transmission.h"
     
    331333{
    332334    tr_file_index_t ff;
    333     int i, j;
     335    int i;
    334336
    335337    for( ff=0; ff<inf->fileCount; ++ff )
     
    342344    tr_free( inf->torrent );
    343345    tr_free( inf->name );
    344     tr_free( inf->primaryAddress );
    345346   
    346     for( i=0; i<inf->trackerTiers; ++i ) {
    347         for( j=0; j<inf->trackerList[i].count; ++j )
    348             tr_trackerInfoClear( &inf->trackerList[i].list[j] );
    349         tr_free( inf->trackerList[i].list );
    350     }
    351     tr_free( inf->trackerList );
     347    for( i=0; i<inf->trackerCount; ++i ) {
     348        tr_free( inf->trackers[i].announce );
     349        tr_free( inf->trackers[i].scrape );
     350    }
     351    tr_free( inf->trackers );
    352352
    353353    memset( inf, '\0', sizeof(tr_info) );
     
    412412static int getannounce( tr_info * inf, tr_benc * meta )
    413413{
    414     tr_benc           * val, * urlval;
    415     char              * address, * announce;
    416     int                 ii, jj, port, random;
    417     tr_tracker_info   * sublist;
    418     void * swapping;
     414    const char * str;
     415    tr_tracker_info * trackers = NULL;
     416    int trackerCount = 0;
     417    tr_benc * tiers;
    419418
    420419    /* Announce-list */
    421     val = tr_bencDictFind( meta, "announce-list" );
    422     if( tr_bencIsList(val) && 0 < val->val.l.count )
    423     {
    424         inf->trackerTiers = 0;
    425         inf->trackerList = calloc( val->val.l.count,
    426                                    sizeof( inf->trackerList[0] ) );
    427 
    428         /* iterate through the announce-list's tiers */
    429         for( ii = 0; ii < val->val.l.count; ii++ )
    430         {
    431             int subcount = 0;
    432             tr_benc * subval = &val->val.l.vals[ii];
    433 
    434             if( !tr_bencIsList(subval) || 0 >= subval->val.l.count )
    435                 continue;
    436 
    437             sublist = calloc( subval->val.l.count, sizeof( sublist[0] ) );
    438 
    439             /* iterate through the tier's items */
    440             for( jj = 0; jj < subval->val.l.count; jj++ )
    441             {
    442                 tr_tracker_info tmp;
    443 
    444                 urlval = &subval->val.l.vals[jj];
    445                 if( TYPE_STR != urlval->type ||
    446                     tr_trackerInfoInit( &tmp, urlval->val.s.s, urlval->val.s.i ) )
    447                 {
    448                     continue;
     420    if( tr_bencDictFindList( meta, "announce-list", &tiers ) )
     421    {
     422        int n;
     423        int i, j;
     424
     425        n = 0;
     426        for( i=0; i<tiers->val.l.count; ++i )
     427            n += tiers->val.l.vals[i].val.l.count;
     428
     429        trackers = tr_new0( tr_tracker_info, n );
     430        trackerCount = 0;
     431
     432        for( i=0; i<tiers->val.l.count; ++i ) {
     433            const tr_benc * tier = &tiers->val.l.vals[i];
     434            for( j=0; tr_bencIsList(tier) && j<tier->val.l.count; ++j ) {
     435                const tr_benc * address = &tier->val.l.vals[j];
     436                if( tr_bencIsString( address ) && tr_httpIsValidURL( address->val.s.s ) ) {
     437                    trackers[trackerCount].tier = i;
     438                    trackers[trackerCount].announce = tr_strndup( address->val.s.s, address->val.s.i );
     439                    trackers[trackerCount++].scrape = announceToScrape( address->val.s.s );
     440                    /*fprintf( stderr, "tier %d: %s\n", i, address->val.s.s );*/
    449441                }
    450 
    451                 if( !inf->primaryAddress ) {
    452                      char buf[1024];
    453                      snprintf( buf, sizeof(buf), "%s:%d", tmp.address, tmp.port );
    454                      inf->primaryAddress = tr_strdup( buf );
    455                 }
    456 
    457                 /* place the item info in a random location in the sublist */
    458                 random = tr_rand( subcount + 1 );
    459                 if( random != subcount )
    460                     sublist[subcount] = sublist[random];
    461                 sublist[random] = tmp;
    462                 subcount++;
    463442            }
    464 
    465             /* just use sublist as-is if it's full */
    466             if( subcount == subval->val.l.count )
    467             {
    468                 inf->trackerList[inf->trackerTiers].list = sublist;
    469                 inf->trackerList[inf->trackerTiers].count = subcount;
    470                 inf->trackerTiers++;
    471             }
    472             /* if we skipped some of the tier's items then trim the sublist */
    473             else if( 0 < subcount )
    474             {
    475                 inf->trackerList[inf->trackerTiers].list = calloc( subcount, sizeof( sublist[0] ) );
    476                 memcpy( inf->trackerList[inf->trackerTiers].list, sublist,
    477                         sizeof( sublist[0] ) * subcount );
    478                 inf->trackerList[inf->trackerTiers].count = subcount;
    479                 inf->trackerTiers++;
    480                 free( sublist );
    481             }
    482             /* drop the whole sublist if we didn't use any items at all */
    483             else
    484             {
    485                 free( sublist );
    486             }
    487443        }
    488444
    489445        /* did we use any of the tiers? */
    490         if( 0 == inf->trackerTiers )
    491         {
     446        if( !trackerCount ) {
    492447            tr_inf( _( "Invalid metadata entry \"%s\"" ), "announce-list" );
    493             free( inf->trackerList );
    494             inf->trackerList = NULL;
    495         }
    496         /* trim unused sublist pointers */
    497         else if( inf->trackerTiers < val->val.l.count )
    498         {
    499             swapping = inf->trackerList;
    500             inf->trackerList = calloc( inf->trackerTiers,
    501                                        sizeof( inf->trackerList[0] ) );
    502             memcpy( inf->trackerList, swapping,
    503                     sizeof( inf->trackerList[0] ) * inf->trackerTiers );
    504             free( swapping );
     448            tr_free( trackers );
     449            trackers = NULL;
    505450        }
    506451    }
    507452
    508453    /* Regular announce value */
    509     val = tr_bencDictFind( meta, "announce" );
    510     if( !tr_bencIsString( val ) )
    511     {
    512         tr_err( _( "Missing metadata entry \"%s\"" ), "announce" );
    513         return TR_EINVALID;
    514     }
    515 
    516     if( !inf->trackerTiers )
    517     {
    518         char buf[4096], *pch;
    519         strlcpy( buf, val->val.s.s, sizeof( buf ) );
    520         pch = buf;
    521         while( isspace( *pch ) )
    522             ++pch;
    523 
    524         if( tr_httpParseURL( pch, -1, &address, &port, &announce ) )
    525         {
    526             tr_err( _( "Invalid announce URL \"%s\"" ), val->val.s.s );
    527             return TR_EINVALID;
    528         }
    529         sublist                   = calloc( 1, sizeof( sublist[0] ) );
    530         sublist[0].address        = address;
    531         sublist[0].port           = port;
    532         sublist[0].announce       = announce;
    533         sublist[0].scrape         = announceToScrape( announce );
    534         inf->trackerList          = calloc( 1, sizeof( inf->trackerList[0] ) );
    535         inf->trackerList[0].list  = sublist;
    536         inf->trackerList[0].count = 1;
    537         inf->trackerTiers         = 1;
    538 
    539         if( !inf->primaryAddress ) {
    540             char buf[1024];
    541             snprintf( buf, sizeof(buf), "%s:%d", sublist[0].address, sublist[0].port );
    542             inf->primaryAddress = tr_strdup( buf );
    543         }
    544 
    545     }
    546 
     454    if( !trackerCount
     455        && tr_bencDictFindStr( meta, "announce", &str )
     456        && tr_httpIsValidURL( str ) )
     457    {
     458        trackers = tr_new0( tr_tracker_info, 1 );
     459        trackers[trackerCount].tier = 0;
     460        trackers[trackerCount].announce = tr_strdup( str );
     461        trackers[trackerCount++].scrape = announceToScrape( str );
     462        /*fprintf( stderr, "single announce: [%s]\n", str );*/
     463    }
     464
     465    inf->trackers = trackers;
     466    inf->trackerCount = trackerCount;
    547467    return TR_OK;
    548468}
    549469
    550 static char * announceToScrape( const char * announce )
    551 {
    552     char old[]  = "announce";
    553     int  oldlen = 8;
    554     char new[]  = "scrape";
    555     int  newlen = 6;
    556     char * slash, * scrape;
    557     size_t scrapelen, used;
    558 
     470static char *
     471announceToScrape( const char * announce )
     472{
     473    char * scrape = NULL;
     474    const char * slash;
     475    struct evbuffer * buf;
     476
     477    /* To derive the scrape URL use the following steps:
     478     * Begin with the announce URL. Find the last '/' in it.
     479     * If the text immediately following that '/' isn't 'announce'
     480     * it will be taken as a sign that that tracker doesn't support
     481     * the scrape convention. If it does, substitute 'scrape' for
     482     * 'announce' to find the scrape page.  */
     483
     484    /* is the last slash followed by "announce"? */
    559485    slash = strrchr( announce, '/' );
    560     if( NULL == slash )
    561     {
     486    if( !slash )
    562487        return NULL;
    563     }
    564     slash++;
    565    
    566     if( 0 != strncmp( slash, old, oldlen ) )
    567     {
     488    ++slash;
     489    if( strncmp( slash, "announce", 8 ) )
    568490        return NULL;
    569     }
    570 
    571     scrapelen = strlen( announce ) - oldlen + newlen;
    572     scrape = calloc( scrapelen + 1, 1 );
    573     if( NULL == scrape )
    574     {
    575         return NULL;
    576     }
    577     assert( ( size_t )( slash - announce ) < scrapelen );
    578     memcpy( scrape, announce, slash - announce );
    579     used = slash - announce;
    580     strncat( scrape, new, scrapelen - used );
    581     used += newlen;
    582     assert( strlen( scrape ) == used );
    583     if( used < scrapelen )
    584     {
    585         assert( strlen( slash + oldlen ) == scrapelen - used );
    586         strncat( scrape, slash + oldlen, scrapelen - used );
    587     }
     491
     492    /* build the scrape url */
     493    buf = evbuffer_new( );
     494    evbuffer_add( buf, announce, slash-announce );
     495    evbuffer_add( buf, "scrape", 6 );
     496    evbuffer_add_printf( buf, "%s", slash+8 );
     497    scrape = tr_strdup( ( char * ) EVBUFFER_DATA( buf ) );
     498    evbuffer_free( buf );
    588499
    589500    return scrape;
    590 }
    591 
    592 int
    593 tr_trackerInfoInit( tr_tracker_info  * info,
    594                     const char       * address,
    595                     int                address_len )
    596 {
    597     int ret = tr_httpParseURL( address, address_len,
    598                                &info->address,
    599                                &info->port,
    600                                &info->announce );
    601     if( !ret )
    602         info->scrape = announceToScrape( info->announce );
    603 
    604     return ret;
    605 }
    606 
    607 void
    608 tr_trackerInfoClear( tr_tracker_info * info )
    609 {
    610     tr_free( info->address );
    611     tr_free( info->announce );
    612     tr_free( info->scrape );
    613     memset( info, '\0', sizeof(tr_tracker_info) );
    614501}
    615502
  • trunk/libtransmission/session.c

    r5637 r5673  
    4848#include "trevent.h"
    4949#include "utils.h"
     50#include "web.h"
    5051
    5152/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
     
    9394
    9495tr_encryption_mode
    95 tr_getEncryptionMode( tr_handle * handle )
    96 {
    97     assert( handle != NULL );
    98 
    99     return handle->encryptionMode;
    100 }
    101 
    102 void
    103 tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode )
    104 {
    105     assert( handle != NULL );
     96tr_getEncryptionMode( tr_session * session )
     97{
     98    assert( session != NULL );
     99
     100    return session->encryptionMode;
     101}
     102
     103void
     104tr_setEncryptionMode( tr_session * session, tr_encryption_mode mode )
     105{
     106    assert( session != NULL );
    106107    assert( mode==TR_ENCRYPTION_PREFERRED
    107108         || mode==TR_ENCRYPTION_REQUIRED
    108109         || mode==TR_PLAINTEXT_PREFERRED );
    109110
    110     handle->encryptionMode = mode;
     111    session->encryptionMode = mode;
    111112}
    112113
     
    191192
    192193    tr_statsInit( h );
     194
     195    h->web = tr_webInit( h );
    193196
    194197    metainfoLookupRescan( h );
  • trunk/libtransmission/session.h

    r5613 r5673  
    4444#endif
    4545
    46 int tr_trackerInfoInit( struct tr_tracker_info  * info,
    47                         const char              * address,
    48                         int                       address_len );
    49 
    50 void tr_trackerInfoClear( struct tr_tracker_info * info );
    51 
    5246uint8_t* tr_peerIdNew( void );
    5347
     
    5953    char * filename;
    6054};
    61 
    62 const char * tr_sessionFindTorrentFile( const tr_handle  * h,
    63                                         const char       * hashString );
    64 
    65 void tr_sessionSetTorrentFile( tr_handle    * h,
    66                                const char   * hashString,
    67                                const char   * filename );
    6855
    6956struct tr_handle
     
    9986    struct tr_lock             * lock;
    10087
     88    struct tr_web              * web;
     89
    10190    tr_handle_status             stats[2];
    10291    int                          statCur;
     
    10998};
    11099
    111 void tr_globalLock       ( struct tr_handle * );
    112 void tr_globalUnlock     ( struct tr_handle * );
    113 int  tr_globalIsLocked   ( const struct tr_handle * );
     100typedef struct tr_handle tr_session;
     101
     102const char * tr_sessionFindTorrentFile( const tr_session * session,
     103                                        const char       * hashString );
     104
     105void tr_sessionSetTorrentFile( tr_session   * session,
     106                               const char   * hashString,
     107                               const char   * filename );
     108
     109void tr_globalLock       ( tr_session * );
     110void tr_globalUnlock     ( tr_session * );
     111int  tr_globalIsLocked   ( const tr_session * );
    114112
    115113#endif
  • trunk/libtransmission/tracker.c

    r5654 r5673  
    1818
    1919#include <event.h>
    20 #include <evhttp.h>
    2120
    2221#include "transmission.h"
    2322#include "bencode.h"
    2423#include "completion.h"
    25 #include "list.h"
    2624#include "net.h"
    2725#include "port-forwarding.h"
     
    3230#include "trevent.h"
    3331#include "utils.h"
     32#include "web.h"
    3433
    3534enum
    3635{
     36    HTTP_OK = 200,
     37
    3738    /* seconds between tracker pulses */
    3839    PULSE_INTERVAL_MSEC = 1000,
     
    6364
    6465    /* the value of the 'numwant' argument passed in tracker requests. */
    65     NUMWANT = 200,
     66    NUMWANT = 150,
    6667
    6768    /* the length of the 'key' argument passed in tracker requests */
     
    7576struct tr_tracker
    7677{
    77     tr_handle * handle;
     78    unsigned int isRunning     : 1;
     79
     80    uint8_t randOffset;
     81
     82    tr_session * session;
    7883
    7984    /* these are set from the latest scrape or tracker response */
     
    8388    int retryScrapeIntervalSec;
    8489
    85     tr_tracker_info * redirect;
    86     tr_tracker_info * addresses;
    87     int addressIndex;
    88     int addressCount;
    89     int * tierFronts;
     90    /* index into the torrent's tr_info.trackers array */
     91    int trackerIndex;
    9092
    9193    /* sent as the "key" argument in tracker requests
     
    98100    /* torrent hash string */
    99101    uint8_t hash[SHA_DIGEST_LENGTH];
    100     char escaped[SHA_DIGEST_LENGTH * 3 + 1];
     102    char escaped[SHA_DIGEST_LENGTH*3 + 1];
    101103    char * name;
    102104
     
    119121
    120122    time_t lastScrapeTime;
    121     char lastScrapeResponse[512];
     123    long lastScrapeResponse;
    122124
    123125    time_t lastAnnounceTime;
    124     char lastAnnounceResponse[512];
    125 
    126     int randOffset;
    127 
    128     unsigned int isRunning     : 1;
     126    long lastAnnounceResponse;
    129127};
    130128
     
    145143
    146144        evbuffer_add_printf( buf, "[%s] ", tr_getLogTimeStr( timestr, sizeof(timestr) ) );
    147         if( t != NULL )
     145        if( t )
    148146            evbuffer_add_printf( buf, "%s ", t->name );
    149147        va_start( args, fmt );
     
    165163
    166164static const tr_tracker_info *
     165getCurrentAddressFromTorrent( const tr_tracker * t, const tr_torrent * tor )
     166{
     167    assert( t->trackerIndex >= 0 );
     168    assert( t->trackerIndex < tor->info.trackerCount );
     169    return tor->info.trackers + t->trackerIndex;
     170}
     171   
     172static const tr_tracker_info *
    167173getCurrentAddress( const tr_tracker * t )
    168174{
    169     assert( t->addresses != NULL );
    170     assert( t->addressIndex >= 0 );
    171     assert( t->addressIndex < t->addressCount );
    172 
    173     return t->redirect ? t->redirect
    174                        : t->addresses + t->addressIndex;
     175    const tr_torrent * torrent;
     176    if(( torrent = tr_torrentFindFromHash( t->session, t->hash )))
     177        return getCurrentAddressFromTorrent( t, torrent );
     178    return NULL;
    175179}
    176180
    177181static int
    178 trackerSupportsScrape( const tr_tracker * t )
    179 {
    180     const tr_tracker_info * info = getCurrentAddress( t );
    181 
    182     return ( info != NULL )
    183         && ( info->scrape != NULL )
    184         && ( info->scrape[0] != '\0' );
     182trackerSupportsScrape( const tr_tracker * t, const tr_torrent * tor )
     183{
     184    const tr_tracker_info * info = getCurrentAddressFromTorrent( t, tor );
     185    return info && info->scrape;
    185186}
    186187
     
    189190***/
    190191
    191 struct torrent_hash
    192 {
    193     tr_handle * handle;
    194     uint8_t hash[SHA_DIGEST_LENGTH];
    195 };
    196 
    197 static struct torrent_hash*
    198 torrentHashNew( tr_handle * handle, const tr_tracker * t )
    199 {
    200     struct torrent_hash * data = tr_new( struct torrent_hash, 1 );
    201     data->handle = handle;
    202     memcpy( data->hash, t->hash, SHA_DIGEST_LENGTH );
    203     return data;
    204 }
    205 
    206192tr_tracker *
    207 findTrackerFromHash( struct torrent_hash * data )
    208 {
    209     tr_torrent * torrent = tr_torrentFindFromHash( data->handle, data->hash );
    210     return torrent ? torrent->tracker : NULL;
    211 }
    212 
    213 tr_tracker *
    214 findTracker( tr_handle * handle, const uint8_t * hash )
    215 {
    216     tr_torrent * torrent = tr_torrentFindFromHash( handle, hash );
     193findTracker( tr_session * session, const uint8_t * hash )
     194{
     195    tr_torrent * torrent = tr_torrentFindFromHash( session, hash );
    217196    return torrent ? torrent->tracker : NULL;
    218197}
     
    227206publishMessage( tr_tracker * t, const char * msg, int type )
    228207{
    229     if( t != NULL )
     208    if( t )
    230209    {
    231210        tr_tracker_event event = emptyEvent;
     
    257236
    258237static void
    259 publishNewPeers( tr_tracker * t, int allAreSeeds, void * compact, int compactLen )
     238publishNewPeers( tr_tracker * t, int allAreSeeds,
     239                 void * compact, int compactLen )
    260240{
    261241    tr_tracker_event event = emptyEvent;
     
    273253***/
    274254
    275 static void onReqDone( tr_handle * handle );
    276 
    277 static void
    278 onStoppedResponse( struct evhttp_request * req UNUSED, void * handle )
    279 {
    280     dbgmsg( NULL, "got a response to some `stop' message" );
    281     onReqDone( handle );
    282 }
    283 
    284 static int
    285 parseBencResponse( struct evhttp_request * req, tr_benc * setme )
    286 {
    287     const unsigned char * body = EVBUFFER_DATA( req->input_buffer );
    288     const int bodylen = EVBUFFER_LENGTH( req->input_buffer );
    289     return tr_bencLoad( body, bodylen, setme, NULL );
    290 }
    291 
    292 static void
    293 updateAddresses( tr_tracker * t, const struct evhttp_request * req, int * tryAgain )
     255static void onReqDone( tr_session * session );
     256
     257static void
     258updateAddresses( tr_tracker * t, long response_code, int * tryAgain )
    294259{
    295260    int moveToNextAddress = FALSE;
    296 
    297     if( !req ) /* tracker didn't respond */
     261    tr_torrent * torrent = tr_torrentFindFromHash( t->session, t->hash );
     262
     263    if( !response_code ) /* tracker didn't respond */
    298264    {
    299265        tr_ninf( t->name, _( "Tracker hasn't responded yet.  Retrying..." ) );
    300266        moveToNextAddress = TRUE;
    301267    }
    302     else if( req->response_code == HTTP_OK )
    303     {
    304         if( t->redirect != NULL )
    305         {
    306             /* multitracker spec: "if a connection with a tracker is
    307                successful, it will be moved to the front of the tier." */
    308             const int i = t->addressIndex;
    309             const int j = t->tierFronts[i];
    310             const tr_tracker_info swap = t->addresses[i];
    311             t->addresses[i] = t->addresses[j];
    312             t->addresses[j] = swap;
    313         }
    314     }
    315     else if(    ( req->response_code == HTTP_MOVEPERM )
    316              || ( req->response_code == HTTP_MOVETEMP ) )
    317     {
    318         const char * loc = evhttp_find_header( req->input_headers, "Location" );
    319         tr_tracker_info tmp;
    320         if( tr_trackerInfoInit( &tmp, loc, -1 ) ) /* a bad redirect? */
    321         {
    322             moveToNextAddress = TRUE;
    323         }
    324         else if( req->response_code == HTTP_MOVEPERM )
    325         {
    326             tr_tracker_info * cur = &t->addresses[t->addressIndex];
    327             tr_trackerInfoClear( cur );
    328             *cur = tmp;
    329         }
    330         else if( req->response_code == HTTP_MOVETEMP )
    331         {
    332             if( t->redirect == NULL )
    333                 t->redirect = tr_new0( tr_tracker_info, 1 );
    334             else
    335                 tr_trackerInfoClear( t->redirect );
    336             *t->redirect = tmp;
    337         }
     268    else if( response_code == HTTP_OK )
     269    {
     270#if 0
     271/* FIXME */
     272        /* multitracker spec: "if a connection with a tracker is
     273           successful, it will be moved to the front of the tier." */
     274        const int i = t->addressIndex;
     275        const int j = t->tierFronts[i];
     276        const tr_tracker_info swap = t->addresses[i];
     277        t->addresses[i] = t->addresses[j];
     278        t->addresses[j] = swap;
     279#endif
    338280    }
    339281    else
     
    346288    if( moveToNextAddress )
    347289    {
    348         if ( ++t->addressIndex >= t->addressCount ) /* we've tried them all */
     290        if ( ++t->trackerIndex >= torrent->info.trackerCount ) /* we've tried them all */
    349291        {
    350292            *tryAgain = FALSE;
    351             t->addressIndex = 0;
     293            t->trackerIndex = 0;
    352294        }
    353295        else
    354296        {
    355             const tr_tracker_info * n = getCurrentAddress( t );
    356             tr_ninf( t->name, _( "Trying next tracker \"%s:%d\"" ), n->address, n->port );
     297            const tr_tracker_info * n = getCurrentAddressFromTorrent( t, torrent );
     298            tr_ninf( t->name, _( "Trying tracker \"%s\"" ), n->announce );
    357299        }
    358300    }
     
    373315    for( i=0, walk=compact; i<peerCount; ++i )
    374316    {
     317        const char * s;
     318        int64_t itmp;
    375319        struct in_addr addr;
    376320        tr_port_t port;
    377         tr_benc * val;
    378321        tr_benc * peer = &bePeers->val.l.vals[i];
    379322
    380         val = tr_bencDictFind( peer, "ip" );
    381         if( !val || val->type!=TYPE_STR || tr_netResolve(val->val.s.s, &addr) )
     323        if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) )
    382324            continue;
    383325
     
    385327        walk += 4;
    386328
    387         val = tr_bencDictFind( peer, "port" );
    388         if( !val || val->type!=TYPE_INT || val->val.i<0 || val->val.i>0xffff )
     329        if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp<0 || itmp>0xffff )
    389330            continue;
    390331
    391         port = htons( val->val.i );
     332        port = htons( itmp );
    392333        memcpy( walk, &port, 2 );
    393334        walk += 2;
     
    399340
    400341static void
    401 onTrackerResponse( struct evhttp_request * req, void * vhash )
     342onStoppedResponse( tr_session    * session,
     343                   long            responseCode  UNUSED,
     344                   const void    * response      UNUSED,
     345                   size_t          responseLen   UNUSED,
     346                   void          * torrent_hash  UNUSED )
     347{
     348    dbgmsg( NULL, "got a response to some `stop' message" );
     349    onReqDone( session );
     350}
     351
     352static void
     353onTrackerResponse( tr_session    * session,
     354                   long            responseCode,
     355                   const void    * response,
     356                   size_t          responseLen,
     357                   void          * torrent_hash )
    402358{
    403359    int tryAgain;
    404     int responseCode;
    405     struct torrent_hash * torrent_hash = (struct torrent_hash*) vhash;
    406     tr_tracker * t = findTrackerFromHash( torrent_hash );
    407 
    408     onReqDone( torrent_hash->handle );
     360    tr_tracker * t;
     361
     362    onReqDone( session );
     363    t = findTracker( session, torrent_hash );
    409364    tr_free( torrent_hash );
    410 
    411     if( t == NULL ) /* tracker has been closed */
     365    if( !t ) /* tracker's been closed */
    412366        return;
    413367
    414     dbgmsg( t, "got response from tracker: \"%s\"",
    415             ( req && req->response_code_line ) ?  req->response_code_line
    416                                                : "(null)" );
    417 
    418     *t->lastAnnounceResponse = '\0';
    419     if( req && req->response_code_line )
    420         strlcpy( t->lastAnnounceResponse, req->response_code_line, sizeof( t->lastAnnounceResponse ) );
    421 
    422     tr_ndbg( t->name, "tracker response: %s",
    423              ( req ? req->response_code_line : "(null)") );
    424 
    425     if( req && ( req->response_code == HTTP_OK ) )
     368    dbgmsg( t, "tracker response: %d", responseCode );
     369    tr_ndbg( t->name, "tracker response: %d", responseCode );
     370    t->lastAnnounceResponse = responseCode;
     371
     372    if( responseCode == HTTP_OK )
    426373    {
    427374        tr_benc benc;
    428         const int bencLoaded = !parseBencResponse( req, &benc );
    429 
     375        const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
    430376        publishErrorClear( t );
    431 
    432         if( bencLoaded && benc.type==TYPE_DICT )
     377        if( bencLoaded && tr_bencIsDict( &benc ) )
    433378        {
    434379            tr_benc * tmp;
     380            int64_t i;
    435381            int incomplete = -1;
    436 
    437             if(( tmp = tr_bencDictFind( &benc, "failure reason" ))) {
    438                 dbgmsg( t, "got failure message [%s]", tmp->val.s.s );
    439                 publishErrorMessageAndStop( t, tmp->val.s.s );
     382            const char * str;
     383
     384            if(( tr_bencDictFindStr( &benc, "failure reason", &str )))
     385                publishErrorMessageAndStop( t, str );
     386
     387            if(( tr_bencDictFindStr( &benc, "warning message", &str )))
     388                publishWarning( t, str );
     389
     390            if(( tr_bencDictFindInt( &benc, "interval", &i ))) {
     391                dbgmsg( t, "setting interval to %d", (int)i );
     392                t->announceIntervalSec = i;
    440393            }
    441394
    442             if(( tmp = tr_bencDictFind( &benc, "warning message" ))) {
    443                 dbgmsg( t, "got warning message [%s]", tmp->val.s.s );
    444                 publishWarning( t, tmp->val.s.s );
     395            if(( tr_bencDictFindInt( &benc, "min interval", &i ))) {
     396                dbgmsg( t, "setting min interval to %d", (int)i );
     397                t->announceMinIntervalSec = i;
    445398            }
    446399
    447             if(( tmp = tr_bencDictFind( &benc, "interval" ))) {
    448                 dbgmsg( t, "setting interval to %d", tmp->val.i );
    449                 t->announceIntervalSec = tmp->val.i;
    450             }
    451 
    452             if(( tmp = tr_bencDictFind( &benc, "min interval" ))) {
    453                 dbgmsg( t, "setting min interval to %d", tmp->val.i );
    454                 t->announceMinIntervalSec = tmp->val.i;
    455             }
    456 
    457             if(( tmp = tr_bencDictFind( &benc, "tracker id" )))
    458                 t->trackerID = tr_strndup( tmp->val.s.s, tmp->val.s.i );
    459 
    460             if(( tmp = tr_bencDictFind( &benc, "complete" )))
    461                 t->seederCount = tmp->val.i;
    462 
    463             if(( tmp = tr_bencDictFind( &benc, "incomplete" )))
    464                 t->leecherCount = incomplete = tmp->val.i;
     400            if(( tr_bencDictFindStr( &benc, "tracker id", &str )))
     401                t->trackerID = tr_strdup( str );
     402
     403            if(( tr_bencDictFindInt( &benc, "complete", &i )))
     404                t->seederCount = i;
     405
     406            if(( tr_bencDictFindInt( &benc, "incomplete", &i )))
     407                t->leecherCount = incomplete = i;
    465408
    466409            if(( tmp = tr_bencDictFind( &benc, "peers" )))
     
    486429    }
    487430
    488     updateAddresses( t, req, &tryAgain );
     431    updateAddresses( t, responseCode, &tryAgain );
    489432
    490433    /**
     
    494437    if( tryAgain )
    495438        responseCode = 300;
    496     else if( req )
    497         responseCode = req->response_code;
    498     else
    499         responseCode = 503;
    500439
    501440    if( 200<=responseCode && responseCode<=299 )
    502441    {
    503         dbgmsg( t, "request succeeded. reannouncing in %d seconds",
    504                    t->announceIntervalSec );
    505         t->reannounceAt = time( NULL ) + t->randOffset + t->announceIntervalSec;
     442        const int interval = t->announceIntervalSec + t->randOffset;
     443        dbgmsg( t, "request succeeded. reannouncing in %d seconds", interval );
     444        t->reannounceAt = time( NULL ) + interval;
    506445        t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
    507446    }
    508447    else if( 300<=responseCode && responseCode<=399 )
    509448    {
     449        /* it's a redirect... updateAddresses() has already
     450         * parsed the redirect, all that's left is to retry */
    510451        const int interval = 5;
    511452        dbgmsg( t, "got a redirect. retrying in %d seconds", interval );
    512 
    513         /* it's a redirect... updateAddresses() has already
    514          * parsed the redirect, all that's left is to retry */
    515453        t->reannounceAt = time( NULL ) + interval;
    516454        t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
     
    518456    else if( 400<=responseCode && responseCode<=499 )
    519457    {
    520         const char * err = req && req->response_code_line
    521             ? req->response_code_line
    522             : "Unspecified 4xx error from tracker.";
    523         dbgmsg( t, err );
    524 
    525458        /* The request could not be understood by the server due to
    526459         * malformed syntax. The client SHOULD NOT repeat the
    527460         * request without modifications. */
    528         publishErrorMessageAndStop( t, err );
     461        publishErrorMessageAndStop( t, _( "Tracker returned a 4xx message" ) );
    529462        t->manualAnnounceAllowedAt = ~(time_t)0;
    530463        t->reannounceAt = 0;
     
    532465    else if( 500<=responseCode && responseCode<=599 )
    533466    {
    534         dbgmsg( t, "Got a 5xx error... retrying in one minute." );
    535 
    536467        /* Response status codes beginning with the digit "5" indicate
    537468         * cases in which the server is aware that it has erred or is
    538469         * incapable of performing the request.  So we pause a bit and
    539470         * try again. */
    540         if( req && req->response_code_line )
    541             publishWarning( t, req->response_code_line );
    542471        t->manualAnnounceAllowedAt = ~(time_t)0;
    543472        t->reannounceAt = time( NULL ) + 60;
     
    545474    else
    546475    {
     476        /* WTF did we get?? */
    547477        dbgmsg( t, "Invalid response from tracker... retrying in two minutes." );
    548 
    549         /* WTF did we get?? */
    550         if( req && req->response_code_line )
    551             publishWarning( t, req->response_code_line );
    552478        t->manualAnnounceAllowedAt = ~(time_t)0;
    553479        t->reannounceAt = time( NULL ) + t->randOffset + 120;
     
    556482
    557483static void
    558 onScrapeResponse( struct evhttp_request * req, void * vhash )
     484onScrapeResponse( tr_session   * session,
     485                  long           responseCode,
     486                  const void   * response,
     487                  size_t         responseLen,
     488                  void         * torrent_hash )
    559489{
    560490    int tryAgain;
    561     int responseCode;
    562     struct torrent_hash * torrent_hash = (struct torrent_hash*) vhash;
    563     tr_tracker * t = findTrackerFromHash( torrent_hash );
    564 
    565     onReqDone( torrent_hash->handle );
     491    tr_tracker * t;
     492
     493    onReqDone( session );
     494    t = findTracker( session, torrent_hash );
    566495    tr_free( torrent_hash );
    567 
    568     dbgmsg( t, "Got scrape response for '%s': %s (%d)", (t ? t->name : "(null)"), (req ? req->response_code_line : "(no line)"), (req ? req->response_code : -1) );
    569 
    570     if( t == NULL ) /* tracker's been closed... */
     496    if( !t ) /* tracker's been closed... */
    571497        return;
    572498
    573     *t->lastScrapeResponse = '\0';
    574     if( req && req->response_code_line )
    575         strlcpy( t->lastScrapeResponse, req->response_code_line, sizeof( t->lastScrapeResponse ) );
    576 
    577     tr_ndbg( t->name, "Got scrape response: \"%s\"",
    578             ( ( req && req->response_code_line ) ? req->response_code_line : "(null)") );
    579 
    580     if( req && ( req->response_code == HTTP_OK ) )
     499    dbgmsg( t, "scrape response: %ld\n", responseCode );
     500    tr_ndbg( t->name, "scrape response: %d", responseCode );
     501    t->lastScrapeResponse = responseCode;
     502
     503    if( responseCode == HTTP_OK )
    581504    {
    582505        tr_benc benc, *files;
    583         const int bencLoaded = !parseBencResponse( req, &benc );
    584 
    585         if( bencLoaded
    586             && (( files = tr_bencDictFind( &benc, "files" ) ))
    587             && ( files->type == TYPE_DICT ) )
     506        const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
     507        if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) )
    588508        {
    589509            int i;
    590510            for( i=0; i<files->val.l.count; i+=2 )
    591511            {
     512                int64_t itmp;
    592513                const uint8_t* hash =
    593                         (const uint8_t*) files->val.l.vals[i].val.s.s;
    594                 tr_benc *tmp, *flags;
    595                 tr_benc *tordict = &files->val.l.vals[i+1];
     514                    (const uint8_t*) files->val.l.vals[i].val.s.s;
     515                tr_benc * flags;
     516                tr_benc * tordict = &files->val.l.vals[i+1];
    596517                if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
    597518                    continue;
     
    599520                publishErrorClear( t );
    600521
    601                 if(( tmp = tr_bencDictFind( tordict, "complete" )))
    602                     t->seederCount = tmp->val.i;
    603 
    604                 if(( tmp = tr_bencDictFind( tordict, "incomplete" )))
    605                     t->leecherCount = tmp->val.i;
    606 
    607                 if(( tmp = tr_bencDictFind( tordict, "downloaded" )))
    608                     t->timesDownloaded = tmp->val.i;
    609 
    610                 if(( flags = tr_bencDictFind( tordict, "flags" )))
    611                     if(( tmp = tr_bencDictFind( flags, "min_request_interval")))
    612                         t->scrapeIntervalSec = tmp->val.i;
     522                if(( tr_bencDictFindInt( tordict, "complete", &itmp )))
     523                    t->seederCount = itmp;
     524
     525                if(( tr_bencDictFindInt( tordict, "incomplete", &itmp )))
     526                    t->leecherCount = itmp;
     527
     528                if(( tr_bencDictFindInt( tordict, "downloaded", &itmp )))
     529                    t->timesDownloaded = itmp;
     530
     531                if( tr_bencDictFindDict( tordict, "flags", &flags ))
     532                    if(( tr_bencDictFindInt( flags, "min_request_interval", &itmp )))
     533                        t->scrapeIntervalSec = i;
    613534
    614535                tr_ndbg( t->name, "Scrape successful.  Rescraping in %d seconds.",
     
    623544    }
    624545
    625     updateAddresses( t, req, &tryAgain );
     546    updateAddresses( t, responseCode, &tryAgain );
    626547
    627548    /**
     
    631552    if( tryAgain )
    632553        responseCode = 300;
    633     else if( req )
    634         responseCode = req->response_code;
    635     else
    636         responseCode = 503;
    637554
    638555    if( 200<=responseCode && responseCode<=299 )
     
    652569    {
    653570        const int interval = t->retryScrapeIntervalSec + t->randOffset;
    654         dbgmsg( t, "Tracker responded to scrape with %d.  Retrying in %d seconds.", responseCode,  interval );
     571        dbgmsg( t, "Tracker responded to scrape with %d.  Retrying in %d seconds.",
     572                   responseCode,  interval );
    655573        t->retryScrapeIntervalSec *= 2;
    656574        t->scrapeAt = time( NULL ) + interval;
     
    674592struct tr_tracker_request
    675593{
    676     int port;
    677     int timeout;
     594    char * url;
    678595    int reqtype; /* TR_REQ_* */
    679     char * address;
    680     char * uri;
    681     struct evhttp_request * req;
    682596    uint8_t torrent_hash[SHA_DIGEST_LENGTH];
     597    tr_web_done_func * done_func;
     598    tr_session * session;
    683599};
    684600
     
    686602freeRequest( struct tr_tracker_request * req )
    687603{
    688     tr_free( req->address );
    689     tr_free( req->uri );
     604    tr_free( req->url );
    690605    tr_free( req );
    691606}
    692607
    693608static void
    694 addCommonHeaders( const tr_tracker * t,
    695                   struct evhttp_request * req )
    696 {
    697     char buf[1024];
    698     const tr_tracker_info * address = getCurrentAddress( t );
    699     snprintf( buf, sizeof(buf), "%s:%d", address->address, address->port );
    700     evhttp_add_header( req->output_headers, "Host", buf );
    701     evhttp_add_header( req->output_headers, "Connection", "close" );
    702     evhttp_add_header( req->output_headers, "User-Agent",
    703                                          TR_NAME "/" LONG_VERSION_STRING );
    704 }
    705 
    706 static char*
    707609buildTrackerRequestURI( const tr_tracker  * t,
    708610                        const tr_torrent  * torrent,
    709                         const char        * eventName )
     611                        const char        * eventName,
     612                        struct evbuffer   * buf )
    710613{
    711614    const int isStopping = !strcmp( eventName, "stopped" );
    712615    const int numwant = isStopping ? 0 : NUMWANT;
    713     struct evbuffer * buf = evbuffer_new( );
    714     char * ret;
    715 
    716     const char * ann = getCurrentAddress(t)->announce;
     616    const char * ann = getCurrentAddressFromTorrent(t,torrent)->announce;
    717617   
    718     evbuffer_add_printf( buf, "%s"
    719                               "%cinfo_hash=%s"
     618    evbuffer_add_printf( buf, "%cinfo_hash=%s"
    720619                              "&peer_id=%s"
    721620                              "&port=%d"
     
    727626                              "&numwant=%d"
    728627                              "&key=%s"
    729                               "&supportcrypto=1"
    730                               "&requirecrypto=%d"
    731628                              "%s%s"
    732629                              "%s%s",
    733         ann,
    734630        strchr(ann, '?') ? '&' : '?',
    735631        t->escaped,
    736632        t->peer_id,
    737         tr_sharedGetPublicPort( t->handle->shared ),
     633        tr_sharedGetPublicPort( t->session->shared ),
    738634        torrent->uploadedCur,
    739635        torrent->downloadedCur,
     
    742638        numwant,
    743639        t->key_param,
    744         ( t->handle->encryptionMode==TR_ENCRYPTION_REQUIRED ? 1 : 0 ),
    745640        ( ( eventName && *eventName ) ? "&event=" : "" ),
    746641        ( ( eventName && *eventName ) ? eventName : "" ),
    747642        ( ( t->trackerID && *t->trackerID ) ? "&trackerid=" : "" ),
    748643        ( ( t->trackerID && *t->trackerID ) ? t->trackerID : "" ) );
    749 
    750     ret = tr_strdup( (char*) EVBUFFER_DATA( buf ) );
    751     evbuffer_free( buf );
    752     return ret;
    753644}
    754645
    755646static struct tr_tracker_request*
    756 createRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
    757 {
    758     static const char* strings[TR_REQ_COUNT] = { "started", "completed", "stopped", "", "err" };
    759     const tr_torrent * torrent = tr_torrentFindFromHash( handle, tracker->hash );
    760     const tr_tracker_info * address = getCurrentAddress( tracker );
     647createRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
     648{
     649    static const char* strings[] = { "started", "completed", "stopped", "", "err" };
     650    const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
     651    const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
    761652    const int isStopping = reqtype == TR_REQ_STOPPED;
    762     const char * eventName = strings[reqtype];
    763653    struct tr_tracker_request * req;
     654    struct evbuffer * url;
     655
     656    url = evbuffer_new( );
     657    evbuffer_add_printf( url, "%s", address->announce );
     658    buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
    764659
    765660    req = tr_new0( struct tr_tracker_request, 1 );
    766     req->address = tr_strdup( address->address );
    767     req->port = address->port;
    768     req->uri = buildTrackerRequestURI( tracker, torrent, eventName );
    769     req->timeout = isStopping ? STOP_TIMEOUT_INTERVAL_SEC : TIMEOUT_INTERVAL_SEC;
     661    req->session = session;
    770662    req->reqtype = reqtype;
    771     req->req = isStopping
    772         ? evhttp_request_new( onStoppedResponse, handle )
    773         : evhttp_request_new( onTrackerResponse, torrentHashNew(handle, tracker) );
     663    req->done_func =  isStopping ? onStoppedResponse : onTrackerResponse;
     664    req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
    774665    memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
    775     addCommonHeaders( tracker, req->req );
    776 
     666
     667    evbuffer_free( url );
    777668    return req;
    778669}
    779670
    780671static struct tr_tracker_request*
    781 createScrape( tr_handle * handle, const tr_tracker * tracker )
     672createScrape( tr_session * session, const tr_tracker * tracker )
    782673{
    783674    const tr_tracker_info * a = getCurrentAddress( tracker );
    784675    struct tr_tracker_request * req;
     676    struct evbuffer * url = evbuffer_new( );
     677
     678    evbuffer_add_printf( url, "%s%cinfo_hash=%s",
     679                         a->scrape, strchr(a->scrape,'?')?'&':'?',
     680                         tracker->escaped );
    785681
    786682    req = tr_new0( struct tr_tracker_request, 1 );
    787     req->address = tr_strdup( a->address );
    788     req->port = a->port;
    789     req->timeout = TIMEOUT_INTERVAL_SEC;
    790     req->req = evhttp_request_new( onScrapeResponse, torrentHashNew( handle, tracker ) );
     683    req->session = session;
    791684    req->reqtype = TR_REQ_SCRAPE;
    792     tr_asprintf( &req->uri, "%s%cinfo_hash=%s", a->scrape, strchr(a->scrape,'?')?'&':'?', tracker->escaped );
     685    req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
     686    req->done_func = onScrapeResponse;
    793687    memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
    794     addCommonHeaders( tracker, req->req );
    795 
     688
     689    evbuffer_free( url );
    796690    return req;
    797691}
     
    799693struct tr_tracker_handle
    800694{
    801     int socketCount;
    802695    unsigned int isShuttingDown : 1;
     696    int runningCount;
    803697    tr_timer * pulseTimer;
    804     tr_list * requestQueue;
    805     tr_list * scrapeQueue;
    806698};
    807699
    808 static int pulse( void * vhandle );
    809 
    810 static void
    811 ensureGlobalsExist( tr_handle * handle )
    812 {
    813     if( handle->tracker == NULL )
    814     {
    815         handle->tracker = tr_new0( struct tr_tracker_handle, 1 );
    816         handle->tracker->pulseTimer = tr_timerNew( handle, pulse, handle, PULSE_INTERVAL_MSEC );
     700static int pulse( void * vsession );
     701
     702static void
     703ensureGlobalsExist( tr_session * session )
     704{
     705    if( session->tracker == NULL )
     706    {
     707        session->tracker = tr_new0( struct tr_tracker_handle, 1 );
     708        session->tracker->pulseTimer = tr_timerNew( session, pulse, session, PULSE_INTERVAL_MSEC );
    817709        dbgmsg( NULL, "creating tracker timer" );
    818710    }
    819711}
    820712
    821 static void
    822 freeRequest2( void * req )
    823 {
    824     freeRequest( req );
    825 }
    826 
    827713void
    828 tr_trackerShuttingDown( tr_handle * handle )
    829 {
    830     if( handle->tracker )
    831     {
    832         /* since we're shutting down, we don't need to scrape anymore... */
    833         tr_list_free( &handle->tracker->scrapeQueue, freeRequest2 );
    834 
    835         handle->tracker->isShuttingDown = 1;
    836     }
     714tr_trackerShuttingDown( tr_session * session )
     715{
     716    if( session->tracker )
     717        session->tracker->isShuttingDown = 1;
    837718}
    838719
    839720static int
    840 maybeFreeGlobals( tr_handle * handle )
    841 {
    842     int globalsExist = handle->tracker != NULL;
     721maybeFreeGlobals( tr_session * session )
     722{
     723    int globalsExist = session->tracker != NULL;
    843724
    844725    if( globalsExist
    845         && ( handle->tracker->socketCount < 1 )
    846         && ( handle->tracker->requestQueue == NULL )
    847         && ( handle->tracker->scrapeQueue == NULL )
    848         && ( handle->torrentList== NULL ) )
     726        && ( session->tracker->runningCount < 1 )
     727        && ( session->torrentList== NULL ) )
    849728    {
    850729        dbgmsg( NULL, "freeing tracker timer" );
    851         tr_timerFree( &handle->tracker->pulseTimer );
    852         tr_free( handle->tracker );
    853         handle->tracker = NULL;
     730        tr_timerFree( &session->tracker->pulseTimer );
     731        tr_free( session->tracker );
     732        session->tracker = NULL;
    854733        globalsExist = FALSE;
    855734    }
     
    862741***/
    863742
    864 static int
    865 freeConnection( void * evcon )
    866 {
    867     evhttp_connection_free( evcon );
    868     return FALSE;
    869 }
    870 static void
    871 connectionClosedCB( struct evhttp_connection * evcon, void * vhandle )
    872 {
    873     tr_handle * handle = vhandle;
    874 
    875     /* libevent references evcon right after calling this function,
    876        so we can't free it yet... defer it to after this call chain
    877        has played out */
    878     tr_timerNew( handle, freeConnection, evcon, 100 );
    879 }
    880 
    881 static struct evhttp_connection*
    882 getConnection( tr_handle * handle, const char * address, int port )
    883 {
    884     struct evhttp_connection * c = evhttp_connection_new( address, port );
    885     evhttp_connection_set_closecb( c, connectionClosedCB, handle );
    886     return c;
    887 }
    888 
    889 static void
    890 invokeRequest( tr_handle * handle, const struct tr_tracker_request * req )
    891 {
    892     const time_t now = time( NULL );
    893     struct evhttp_connection * evcon = getConnection( handle, req->address, req->port );
    894     tr_tracker * t = findTracker( handle, req->torrent_hash );
    895     dbgmsg( t, "sending '%s' to tracker %s:%d, timeout is %d", req->uri, req->address, req->port, (int)req->timeout );
    896     evhttp_connection_set_timeout( evcon, req->timeout );
    897     ++handle->tracker->socketCount;
    898 
    899     if( t != NULL )
     743static void
     744invokeRequest( void * vreq )
     745{
     746    struct tr_tracker_request * req = vreq;
     747    uint8_t * hash;
     748    tr_tracker * t = findTracker( req->session, req->torrent_hash );
     749
     750    if( t )
    900751    {
    901752        if( req->reqtype == TR_REQ_SCRAPE )
    902753        {
    903             t->lastScrapeTime = now;
     754            t->lastScrapeTime = time( NULL );
    904755            t->scrapeAt = 0;
    905756        }
    906757        else
    907758        {
    908             t->lastAnnounceTime = now;
     759            t->lastAnnounceTime = time( NULL );
    909760            t->reannounceAt = 0;
    910             t->manualAnnounceAllowedAt = 0;
     761            t->manualAnnounceAllowedAt = ~(time_t)0;
    911762        }
    912763    }
    913764
    914     if( evhttp_make_request( evcon, req->req, EVHTTP_REQ_GET, req->uri ))
    915         (*req->req->cb)(req->req, req->req->cb_arg);
    916     else
    917         dbgmsg( t, "incremented socket count to %d", handle->tracker->socketCount );
    918 }
    919 
    920 static void
    921 invokeNextInQueue( tr_handle * handle, tr_list ** list )
    922 {
    923     struct tr_tracker_request * req = tr_list_pop_front( list );
    924     invokeRequest( handle, req );
     765    ++req->session->tracker->runningCount;
     766
     767    hash = tr_new0( uint8_t, SHA_DIGEST_LENGTH );
     768    memcpy( hash, req->torrent_hash, SHA_DIGEST_LENGTH );
     769    tr_webRun( req->session, req->url, req->done_func, hash );
     770
    925771    freeRequest( req );
    926772}
    927773
     774static void ensureGlobalsExist( tr_session * );
     775
     776static void
     777enqueueScrape( tr_session * session, const tr_tracker * tracker )
     778{
     779    struct tr_tracker_request * req;
     780    ensureGlobalsExist( session );
     781    req = createScrape( session, tracker );
     782    tr_runInEventThread( session, invokeRequest, req );
     783}
     784
     785static void
     786enqueueRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
     787{
     788    struct tr_tracker_request * req;
     789    ensureGlobalsExist( session );
     790    req = createRequest( session, tracker, reqtype );
     791    tr_runInEventThread( session, invokeRequest, req );
     792}
     793
    928794static int
    929 socketIsAvailable( tr_handle * handle )
    930 {
    931     const int max = handle->tracker->isShuttingDown
    932                       ? MAX_TRACKER_SOCKETS_DURING_SHUTDOWN
    933                       : MAX_TRACKER_SOCKETS;
    934     return handle->tracker->socketCount < max;
    935 }
    936 
    937 static void ensureGlobalsExist( tr_handle * );
    938 
    939 static void
    940 enqueueScrape( tr_handle * handle, const tr_tracker * tracker )
    941 {
    942     struct tr_tracker_request * req;
    943     ensureGlobalsExist( handle );
    944     req = createScrape( handle, tracker );
    945     tr_list_append( &handle->tracker->scrapeQueue, req );
    946 }
    947 
    948 static void
    949 enqueueRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
    950 {
    951     struct tr_tracker_request * req;
    952     ensureGlobalsExist( handle );
    953     req = createRequest( handle, tracker, reqtype );
    954     tr_list_append( &handle->tracker->requestQueue, req );
    955 }
    956 
    957 static void
    958 scrapeSoon( tr_tracker * t )
    959 {
    960     if( trackerSupportsScrape( t ) )
    961         t->scrapeAt = time( NULL ) + t->randOffset;
    962 }
    963 
    964 static int
    965 pulse( void * vhandle )
    966 {
    967     tr_handle * handle = vhandle;
    968     struct tr_tracker_handle * th = handle->tracker;
     795pulse( void * vsession )
     796{
     797    tr_session * session = vsession;
     798    struct tr_tracker_handle * th = session->tracker;
    969799    tr_torrent * tor;
    970800    const time_t now = time( NULL );
    971801
    972     if( handle->tracker == NULL )
     802    if( !session->tracker )
    973803        return FALSE;
    974804
    975     if( handle->tracker->socketCount || tr_list_size(th->requestQueue) || tr_list_size(th->scrapeQueue) )
    976         dbgmsg( NULL, "tracker pulse... %d sockets, %d reqs left, %d scrapes left", handle->tracker->socketCount, tr_list_size(th->requestQueue), tr_list_size(th->scrapeQueue) );
     805    if( th->runningCount )
     806        dbgmsg( NULL, "tracker pulse... %d running", th->runningCount );
    977807
    978808    /* upkeep: queue periodic rescrape / reannounce */
    979     for( tor=handle->torrentList; tor; tor=tor->next )
     809    for( tor=session->torrentList; tor; tor=tor->next )
    980810    {
    981811        tr_tracker * t = tor->tracker;
    982812
    983         if( t->scrapeAt && trackerSupportsScrape( t ) && ( now >= t->scrapeAt ) ) {
     813        if( t->scrapeAt && trackerSupportsScrape( t, tor ) && ( now >= t->scrapeAt ) ) {
    984814            t->scrapeAt = 0;
    985             enqueueScrape( handle, t );
     815            enqueueScrape( session, t );
    986816        }
    987817
    988818        if( t->reannounceAt && t->isRunning && ( now >= t->reannounceAt ) ) {
    989819            t->reannounceAt = 0;
    990             enqueueRequest( handle, t, TR_REQ_REANNOUNCE );
     820            enqueueRequest( session, t, TR_REQ_REANNOUNCE );
    991821        }
    992822    }
    993823
    994     if( handle->tracker->socketCount || tr_list_size(th->requestQueue) || tr_list_size(th->scrapeQueue) )
    995         dbgmsg( NULL, "tracker pulse after upkeep... %d sockets, %d reqs left, %d scrapes left", handle->tracker->socketCount, tr_list_size(th->requestQueue), tr_list_size(th->scrapeQueue) );
    996 
    997     /* look for things to do... process all the requests, then process all the scrapes */
    998     while( th->requestQueue && socketIsAvailable( handle ) )
    999         invokeNextInQueue( handle, &th->requestQueue );
    1000     while( th->scrapeQueue && socketIsAvailable( handle ) )
    1001         invokeNextInQueue( handle, &th->scrapeQueue );
    1002 
    1003     if( handle->tracker->socketCount || tr_list_size(th->requestQueue) || tr_list_size(th->scrapeQueue) )
    1004         dbgmsg( NULL, "tracker pulse done... %d sockets, %d reqs left, %d scrapes left", handle->tracker->socketCount, tr_list_size(th->requestQueue), tr_list_size(th->scrapeQueue) );
    1005 
    1006     return maybeFreeGlobals( handle );
    1007 }
    1008 
    1009 static void
    1010 onReqDone( tr_handle * handle )
    1011 {
    1012     if( handle->tracker )
    1013     {
    1014         pulse( handle );
    1015         --handle->tracker->socketCount;
    1016         dbgmsg( NULL, "decrementing socket count to %d", handle->tracker->socketCount );
     824    if( th->runningCount )
     825        dbgmsg( NULL, "tracker pulse after upkeep... %d running", th->runningCount );
     826
     827    return maybeFreeGlobals( session );
     828}
     829
     830static void
     831onReqDone( tr_session * session )
     832{
     833    if( session->tracker )
     834    {
     835        --session->tracker->runningCount;
     836        dbgmsg( NULL, "decrementing runningCount to %d", session->tracker->runningCount );
     837        pulse( session );
    1017838    }
    1018839}
     
    1057878{
    1058879    const tr_info * info = &torrent->info;
    1059     int i, j, sum, *iwalk;
    1060     tr_tracker_info * nwalk;
    1061880    tr_tracker * t;
    1062881
    1063882    t = tr_new0( tr_tracker, 1 );
    1064     t->handle = torrent->handle;
    1065     t->scrapeIntervalSec       = DEFAULT_SCRAPE_INTERVAL_SEC;
    1066     t->retryScrapeIntervalSec  = 60;
    1067     t->announceIntervalSec     = DEFAULT_ANNOUNCE_INTERVAL_SEC;
    1068     t->announceMinIntervalSec  = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
    1069     generateKeyParam( t->key_param, KEYLEN );
    1070 
    1071883    t->publisher = tr_publisherNew( );
    1072     t->timesDownloaded = -1;
    1073     t->seederCount = -1;
    1074     t->leecherCount = -1;
    1075     t->manualAnnounceAllowedAt = ~(time_t)0;
     884    t->session                  = torrent->handle;
     885    t->scrapeIntervalSec        = DEFAULT_SCRAPE_INTERVAL_SEC;
     886    t->retryScrapeIntervalSec   = 60;
     887    t->announceIntervalSec      = DEFAULT_ANNOUNCE_INTERVAL_SEC;
     888    t->announceMinIntervalSec   = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
     889    t->timesDownloaded          = -1;
     890    t->seederCount              = -1;
     891    t->leecherCount             = -1;
     892    t->manualAnnounceAllowedAt  = ~(time_t)0;
    1076893    t->name = tr_strdup( info->name );
    1077894    t->randOffset = tr_rand( 120 );
    1078895    memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
    1079896    escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
    1080 
    1081     for( sum=i=0; i<info->trackerTiers; ++i )
    1082          sum += info->trackerList[i].count;
    1083     t->addresses = nwalk = tr_new0( tr_tracker_info, sum );
    1084     t->addressIndex = 0;
    1085     t->addressCount = sum;
    1086     t->tierFronts = iwalk = tr_new0( int, sum );
    1087 
    1088     for( i=0; i<info->trackerTiers; ++i )
    1089     {
    1090         const int tierFront = nwalk - t->addresses;
    1091 
    1092         for( j=0; j<info->trackerList[i].count; ++j )
    1093         {
    1094             const tr_tracker_info * src = &info->trackerList[i].list[j];
    1095             nwalk->address = tr_strdup( src->address );
    1096             nwalk->port = src->port;
    1097             nwalk->announce = tr_strdup( src->announce );
    1098             nwalk->scrape = tr_strdup( src->scrape );
    1099             ++nwalk;
    1100 
    1101             *iwalk++ = tierFront;
    1102         }
    1103     }
    1104 
    1105     assert( nwalk - t->addresses == sum );
    1106     assert( iwalk - t->tierFronts == sum );
    1107 
    1108     scrapeSoon( t );
     897    generateKeyParam( t->key_param, KEYLEN );
     898
     899    t->trackerIndex = 0;
     900
     901    if( trackerSupportsScrape( t, torrent ) )
     902        t->scrapeAt = time( NULL ) + t->randOffset;
    1109903
    1110904    return t;
     
    1114908onTrackerFreeNow( void * vt )
    1115909{
    1116     int i;
    1117910    tr_tracker * t = vt;
    1118911
     
    1122915    tr_free( t->peer_id );
    1123916
    1124     /* addresses... */
    1125     for( i=0; i<t->addressCount; ++i )
    1126         tr_trackerInfoClear( &t->addresses[i] );
    1127     tr_free( t->addresses );
    1128     tr_free( t->tierFronts );
    1129 
    1130     /* redirect... */
    1131     if( t->redirect ) {
    1132         tr_trackerInfoClear( t->redirect );
    1133         tr_free( t->redirect );
    1134     }
    1135 
    1136917    tr_free( t );
    1137918}
     
    1145926{
    1146927    if( t )
    1147         tr_runInEventThread( t->handle, onTrackerFreeNow, t );
     928        tr_runInEventThread( t->session, onTrackerFreeNow, t );
    1148929}
    1149930
     
    1203984tr_trackerStart( tr_tracker * t )
    1204985{
    1205     if( t )
     986    if( t && !t->isRunning )
    1206987    {
    1207988        tr_free( t->peer_id );
    1208989        t->peer_id = tr_peerIdNew( );
    1209990
    1210         if( t->isRunning == 0 ) {
    1211             t->isRunning = 1;
    1212             enqueueRequest( t->handle, t, TR_REQ_STARTED );
    1213         }
     991        t->isRunning = 1;
     992        enqueueRequest( t->session, t, TR_REQ_STARTED );
    1214993    }
    1215994}
     
    1218997tr_trackerReannounce( tr_tracker * t )
    1219998{
    1220     enqueueRequest( t->handle, t, TR_REQ_REANNOUNCE );
     999    enqueueRequest( t->session, t, TR_REQ_REANNOUNCE );
    12211000}
    12221001
     
    12241003tr_trackerCompleted( tr_tracker * t )
    12251004{
    1226     enqueueRequest( t->handle, t, TR_REQ_COMPLETED );
     1005    enqueueRequest( t->session, t, TR_REQ_COMPLETED );
    12271006}
    12281007
     
    12301009tr_trackerStop( tr_tracker * t )
    12311010{
     1011fprintf( stderr, "trackerStop... isRunning %d\n", (int)t->isRunning );
    12321012    if( t && t->isRunning ) {
    12331013        t->isRunning = 0;
    12341014        t->reannounceAt = t->manualAnnounceAllowedAt = 0;
    1235         enqueueRequest( t->handle, t, TR_REQ_STOPPED );
     1015        enqueueRequest( t->session, t, TR_REQ_STOPPED );
    12361016    }
    12371017}
     
    12451025
    12461026void
    1247 tr_trackerStat( const tr_tracker * t,
     1027tr_trackerStat( const tr_tracker       * t,
    12481028                struct tr_tracker_stat * setme)
    12491029{
     
    12511031    assert( setme != NULL );
    12521032
    1253     strlcpy( setme->scrapeResponse,
    1254              t->lastScrapeResponse,
    1255              sizeof( setme->scrapeResponse ) );
     1033    snprintf( setme->scrapeResponse,
     1034              sizeof( setme->scrapeResponse ),
     1035              "%ld", t->lastScrapeResponse );
    12561036    setme->lastScrapeTime = t->lastScrapeTime;
    12571037    setme->nextScrapeTime = t->scrapeAt;
    12581038
    1259     strlcpy( setme->announceResponse,
    1260              t->lastAnnounceResponse,
    1261              sizeof( setme->announceResponse ) );
     1039    snprintf( setme->announceResponse,
     1040              sizeof( setme->announceResponse ),
     1041              "%ld", t->lastAnnounceResponse );
     1042
    12621043    setme->lastAnnounceTime = t->lastAnnounceTime;
    12631044    setme->nextAnnounceTime = t->reannounceAt;
  • trunk/libtransmission/transmission.h

    r5666 r5673  
    703703typedef struct tr_tracker_info
    704704{
    705     char * address;
    706     int    port;
     705    int    tier;
    707706    char * announce;
    708707    char * scrape;
     
    724723    unsigned int isMultifile : 1;
    725724
    726     /* Tracker info */
    727     struct
    728     {
    729         tr_tracker_info  * list;
    730         int                 count;
    731     }                  * trackerList;
    732     int                  trackerTiers;
    733     char               * primaryAddress;
     725    /* these trackers are sorted by tier */
     726    tr_tracker_info    * trackers;
     727    int                  trackerCount;
    734728
    735729    /* Torrent info */
  • trunk/libtransmission/trevent.c

    r5280 r5673  
    191191    eh->lock = tr_lockNew( );
    192192    eh->h = handle;
    193     eh->pulseInterval = timevalMsec( 100 );
     193    eh->pulseInterval = tr_timevalMsec( 100 );
    194194    eh->thread = tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
    195195}
     
    290290{
    291291    tr_timer * timer = tr_new0( tr_timer, 1 );
    292     timer->tv = timevalMsec( timeout_milliseconds );
     292    timer->tv = tr_timevalMsec( timeout_milliseconds );
    293293    timer->func = func;
    294294    timer->user_data = user_data;
  • trunk/libtransmission/utils.c

    r5526 r5673  
    4444#endif
    4545
    46 #include <miniupnp/miniwget.h> /* parseURL */
    47 
    4846#include "transmission.h"
    4947#include "trcompat.h"
     
    353351
    354352struct timeval
    355 timevalMsec( uint64_t milliseconds )
     353tr_timevalMsec( uint64_t milliseconds )
    356354{
    357355    struct timeval ret;
     
    956954
    957955int
     956tr_httpIsValidURL( const char * url )
     957{
     958    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
     959}
     960
     961int
    958962tr_httpParseURL( const char * url_in, int len,
    959963                 char ** setme_host,
     
    961965                 char ** setme_path )
    962966{
    963     char * url = tr_strndup( url_in, len );
    964     char * path;
    965     char host[4096+1];
    966     unsigned short port;
    967     int success;
    968 
    969     success = parseURL( url, host, &port, &path );
    970 
    971     if( success ) {
    972         if( setme_host ) *setme_host = tr_strdup( host );
    973         if( setme_port ) *setme_port = port;
    974         if( setme_path ) *setme_path = tr_strdup( path );
    975     }
    976 
    977     tr_free( url );
    978 
    979     return !success;
    980 }
    981 
     967    int err;
     968    int port = 0;
     969    int n;
     970    char * tmp;
     971    char * pch;
     972    const char * protocol = NULL;
     973    const char * host = NULL;
     974    const char * path = NULL;
     975
     976    tmp = tr_strndup( url_in, len );
     977    if(( pch = strstr( tmp, "://" )))
     978    {
     979       *pch = '\0';
     980       protocol = tmp;
     981       pch += 3;
     982/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch );*/
     983       if(( n = strcspn( pch, ":/" )))
     984       {
     985           const int havePort = pch[n] == ':';
     986           host = pch;
     987           pch += n;
     988           *pch++ = '\0';
     989/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
     990           if( havePort )
     991           {
     992               char * end;
     993               port = strtol( pch, &end, 10 );
     994               pch = end;
     995/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
     996           }
     997           path = pch;
     998/*fprintf( stderr, "path is [%s]\n", path );*/
     999       }
     1000    }
     1001
     1002    err = !host || !path || !protocol || ( strcmp(protocol,"http") && strcmp(protocol,"https") );
     1003
     1004    if( !err && !port ) {
     1005        if( !strcmp(protocol,"http") ) port = 80;
     1006        if( !strcmp(protocol,"https") ) port = 443;
     1007    }
     1008
     1009    if( !err ) {
     1010        if( setme_host) { ((char*)host)[-3]=':'; *setme_host = tr_strdup( protocol ); }
     1011        if( setme_path) { ((char*)path)[-1]='/'; *setme_path = tr_strdup( path-1 ); }
     1012        if( setme_port) *setme_port = port;
     1013    }
     1014
     1015
     1016    tr_free( tmp );
     1017    return err;
     1018}
  • trunk/libtransmission/utils.h

    r5526 r5673  
    9393                   const char * first_element, ... );
    9494
    95 struct timeval timevalMsec( uint64_t milliseconds );
     95struct timeval tr_timevalMsec( uint64_t milliseconds );
    9696
    9797
     
    161161
    162162
     163int tr_httpIsValidURL( const char * url );
     164
    163165int tr_httpParseURL( const char * url,
    164166                     int          url_len,
Note: See TracChangeset for help on using the changeset viewer.