Changeset 5696


Ignore:
Timestamp:
Apr 25, 2008, 4:07:06 PM (14 years ago)
Author:
charles
Message:

more hacking on the curl code, based on libcurl's "hiperfifo.c" sample code

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/web.c

    r5690 r5696  
    3131static void pulse( int socket UNUSED, short action UNUSED, void * vweb );
    3232#endif
     33static void processCompletedTasks( tr_web * );
    3334
    3435#define dbgmsg(fmt...) tr_deepLog( __FILE__, __LINE__, "web", ##fmt )
     
    6162pump( tr_web * web )
    6263{
     64    int unused;
    6365    CURLMcode rc;
    6466    do
    6567#ifdef USE_CURL_MULTI_SOCKET
    66         rc = curl_multi_socket_all( web->cm, &web->remain );
     68        rc = curl_multi_socket_all( web->cm, &unused );
    6769#else
    68         rc = curl_multi_perform( web->cm, &web->remain );
     70        rc = curl_multi_perform( web->cm, &unused );
    6971#endif
    7072    while( rc == CURLM_CALL_MULTI_PERFORM );
    71     dbgmsg( "%d tasks remain", web->remain );
    72     if ( rc != CURLM_OK  )
     73    if ( rc == CURLM_OK  )
     74        processCompletedTasks( web );
     75    else
    7376        tr_err( "%s", curl_multi_strerror(rc) );
    7477}
     
    101104    curl_easy_setopt( ch, CURLOPT_USERAGENT, TR_NAME "/" LONG_VERSION_STRING );
    102105    curl_easy_setopt( ch, CURLOPT_SSL_VERIFYPEER, 0 );
    103     curl_easy_setopt( ch, CURLOPT_TIMEOUT, 30 );
    104 
    105106    curl_multi_add_handle( web->cm, ch );
    106107
    107 #ifdef USE_CURL_MULTI_SOCKET
    108108    pump( web );
    109 #else
    110     if( !evtimer_initialized( &web->timer ) )
    111         evtimer_set( &web->timer, pulse, web );
    112     if( !evtimer_pending( &web->timer, NULL ) ) {
    113         struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    114         evtimer_add( &web->timer, &tv );
    115     }
    116 #endif
    117109}
    118110
     
    121113{
    122114    int more = 0;
     115    CURL * easy;
     116    CURLMsg * msg;
     117    CURLcode res;
    123118
    124119    do {
    125         CURLMsg * msg = curl_multi_info_read( web->cm, &more );
    126         if( msg && ( msg->msg == CURLMSG_DONE ) )
    127         {
    128             CURL * ch;
     120        /* find a completed task.  this idea is from the "hiperinfo.c"
     121         * sample that questions the safety of removing an easy handle
     122         * inside the curl_multi_info_read loop */
     123        easy = NULL;
     124        while(( msg = curl_multi_info_read( web->cm, &more ))) {
     125            if( msg->msg == CURLMSG_DONE ) {
     126                easy = msg->easy_handle;
     127                res = msg->data.result;
     128                break;
     129            }
     130        }
     131        if( easy ) {
    129132            struct tr_web_task * task;
    130             long response_code;
    131 
    132             if( msg->data.result != CURLE_OK )
    133                 tr_err( "%s", curl_easy_strerror( msg->data.result ) );
    134            
    135             ch = msg->easy_handle;
    136             curl_easy_getinfo( ch, CURLINFO_PRIVATE, &task );
    137             curl_easy_getinfo( ch, CURLINFO_RESPONSE_CODE, &response_code );
    138 
    139             dbgmsg( "task #%lu done", task->tag );
     133            int response_code;
     134            curl_easy_getinfo( easy, CURLINFO_PRIVATE, &task );
     135            curl_easy_getinfo( easy, CURLINFO_RESPONSE_CODE, &response_code );
     136
     137            --web->remain;
     138            dbgmsg( "task #%lu done (%d tasks remain)", task->tag, web->remain );
    140139            task->done_func( web->session,
    141140                             response_code,
     
    144143                             task->done_func_user_data );
    145144
    146             curl_multi_remove_handle( web->cm, ch );
    147             curl_easy_cleanup( ch );
    148 
     145            curl_multi_remove_handle( web->cm, easy );
     146            curl_easy_cleanup( easy );
    149147            evbuffer_free( task->response );
    150148            tr_free( task );
    151149        }
    152     }
    153     while( more );
    154 
    155     /* remove timeout if there are no transfers left */
    156     if( !web->remain && evtimer_initialized( &web->timer ) )
    157         evtimer_del( &web->timer );
     150    } while( easy );
    158151}
    159152
    160153#ifdef USE_CURL_MULTI_SOCKET
     154
    161155/* libevent says that sock is ready to be processed, so tell libcurl */
    162156static void
     
    165159    tr_web * web = vweb;
    166160    CURLMcode rc;
    167     int mask;
     161    int mask, unused;
    168162
    169163    switch (action & (EV_READ|EV_WRITE)) {
     
    174168    }
    175169
    176     do
    177         rc = curl_multi_socket_action( web->cm, sock, mask, &web->remain );
     170    do rc = curl_multi_socket_action( web->cm, sock, mask, &unused );
    178171    while( rc == CURLM_CALL_MULTI_PERFORM );
    179172
     
    184177}
    185178
     179/* CURLMPOPT_SOCKETFUNCTION */
    186180/* libcurl wants us to tell it when sock is ready to be processed */
    187 static int
    188 socket_callback( CURL            * easy UNUSED,
    189                  curl_socket_t     sock,
    190                  int               action,
    191                  void            * vweb,
    192                  void            * assigndata )
    193 {
    194     tr_web * web = vweb;
    195     int events = EV_PERSIST;
     181static void
     182multi_sock_cb( CURL            * easy UNUSED,
     183               curl_socket_t     sock,
     184               int               action,
     185               void            * vweb,
     186               void            * assigndata )
     187{
     188    tr_web * web = vweb;
    196189    struct event * ev = assigndata;
    197190
    198     if( ev )
    199         event_del( ev );
    200     else {
    201         ev = tr_new0( struct event, 1 );
    202         curl_multi_assign( web->cm, sock, ev );
     191    if( action == CURL_POLL_REMOVE ) {
     192        if( ev ) {
     193            event_del( ev );
     194            tr_free( ev );
     195            curl_multi_assign( web->cm, sock, NULL );
     196        }
     197    } else {
     198        int kind;
     199        if( ev ) {
     200            event_del( ev );
     201        } else {
     202            ev = tr_new0( struct event, 1 );
     203            curl_multi_assign( web->cm, sock, ev );
     204        }
     205        kind = EV_PERSIST;
     206        if( action & CURL_POLL_IN ) kind |= EV_READ;
     207        if( action & CURL_POLL_OUT ) kind |= EV_WRITE;
     208        event_set( ev, sock, kind, event_callback, web );
     209        event_add( ev, NULL );
    203210    }
    204 
    205     switch (action) {
    206         case CURL_POLL_IN: events |= EV_READ; break;
    207         case CURL_POLL_OUT: events |= EV_WRITE; break;
    208         case CURL_POLL_INOUT: events |= EV_READ|EV_WRITE; break;
    209         case CURL_POLL_REMOVE: tr_free( ev ); /* fallthrough */
    210         case CURL_POLL_NONE: return 0;
    211         default: tr_err( "Unknown socket action %d", action ); return -1;
    212     }
    213 
    214     event_set( ev, sock, events, event_callback, web );
    215     event_add( ev, NULL );
    216     return 0;
    217211}
    218212
    219213/* libevent says that timeout_ms have passed, so tell libcurl */
    220214static void
    221 timeout_callback( int socket UNUSED, short action UNUSED, void * vweb )
    222 {
    223     tr_web * web = vweb;
     215event_timer_cb( int socket UNUSED, short action UNUSED, void * vweb )
     216{
     217    int unused;
    224218    CURLMcode rc;
    225 
    226     do rc = curl_multi_socket( web->cm, CURL_SOCKET_TIMEOUT, &web->remain );
    227     while( rc == CURLM_CALL_MULTI_PERFORM );
    228     if( rc != CURLM_OK )
    229         tr_err( "%s", curl_multi_strerror( rc ) );
    230 }
    231 
    232 /* libcurl wants us to tell it when timeout_ms have passed */
    233 static void
    234 timer_callback( CURLM *multi UNUSED, long timeout_ms, void * vweb )
     219    tr_web * web = vweb;
     220
     221    do {
     222        rc = curl_multi_socket( web->cm, CURL_SOCKET_TIMEOUT, &unused );
     223    } while( rc == CURLM_CALL_MULTI_PERFORM );
     224    if ( rc == CURLM_OK  )
     225        processCompletedTasks( web );
     226    else
     227        tr_err( "%s", curl_multi_strerror(rc) );
     228}
     229
     230/* CURLMPOPT_TIMERFUNCTION */
     231static void
     232multi_timer_cb( CURLM *multi UNUSED, long timeout_ms, void * vweb )
    235233{
    236234    tr_web * web = vweb;
    237235    struct timeval tv = tr_timevalMsec( timeout_ms );
    238 
    239     if( evtimer_initialized( &web->timer ) )
    240         evtimer_del( &web->timer );
    241 
    242     evtimer_set( &web->timer, timeout_callback, vweb );
    243236    evtimer_add( &web->timer, &tv );
    244237}
     238
    245239#else
    246240
     
    249243{
    250244    tr_web * web = vweb;
     245    struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    251246
    252247    pump( web );
    253248    processCompletedTasks( web );
    254249
    255     if( web->remain > 0 ) {
    256         struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    257         evtimer_add( &web->timer, &tv );
    258     }
     250    evtimer_del( &web->timer );
     251    evtimer_add( &web->timer, &tv );
    259252}
    260253
     
    264257tr_webInit( tr_session * session )
    265258{
     259#ifndef USE_CURL_MULTI_SOCKET
     260    struct timeval tv = tr_timevalMsec( PULSE_MSEC );
     261#endif
    266262    static int curlInited = FALSE;
    267263    tr_web * web;
     
    281277
    282278#ifdef USE_CURL_MULTI_SOCKET
     279    evtimer_set( &web->timer, event_timer_cb, web );
    283280    curl_multi_setopt( web->cm, CURLMOPT_SOCKETDATA, web );
    284     curl_multi_setopt( web->cm, CURLMOPT_SOCKETFUNCTION, socket_callback );
     281    curl_multi_setopt( web->cm, CURLMOPT_SOCKETFUNCTION, multi_sock_cb );
    285282    curl_multi_setopt( web->cm, CURLMOPT_TIMERDATA, web );
    286     curl_multi_setopt( web->cm, CURLMOPT_TIMERFUNCTION, timer_callback );
     283    curl_multi_setopt( web->cm, CURLMOPT_TIMERFUNCTION, multi_timer_cb );
     284#else
     285    evtimer_set( &web->timer, pulse, web );
     286    evtimer_add( &web->timer, &tv );
    287287#endif
    288288#if CURL_CHECK_VERSION(7,16,3)
    289     curl_multi_setopt( web->cm, CURLMOPT_MAXCONNECTS, 20 );
     289    curl_multi_setopt( web->cm, CURLMOPT_MAXCONNECTS, 10 );
    290290#endif
    291291#if CURL_CHECK_VERSION(7,16,0)
    292292    curl_multi_setopt( web->cm, CURLMOPT_PIPELINING, 1 );
    293293#endif
     294    pump( web );
    294295
    295296    return web;
Note: See TracChangeset for help on using the changeset viewer.