Ignore:
Timestamp:
Feb 9, 2009, 5:34:43 PM (13 years ago)
Author:
charles
Message:

(1.5x libT) backport #1671, #1798

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/1.5x/libtransmission/web.c

    r7813 r7855  
    5050#endif
    5151
     52struct tr_web_sockinfo
     53{
     54    int fd;
     55    tr_bool evset;
     56    struct event ev;
     57};
     58
    5259struct tr_web
    5360{
     
    5865    CURLM * multi;
    5966    tr_session * session;
    60 #if 0
    61     tr_list * easy_queue;
    62 #endif
    6367    struct event timer_event;
     68    tr_list * fds;
    6469};
     70
     71/***
     72****
     73***/
     74
     75static struct tr_web_sockinfo *
     76getSockinfo( tr_web * web, int fd, tr_bool createIfMissing )
     77{
     78    tr_list * l = web->fds;
     79
     80    for( l=web->fds; l!=NULL; l=l->next ) {
     81        struct tr_web_sockinfo * s =  l->data;
     82        if( s->fd == fd ) {
     83            dbgmsg( "looked up sockinfo %p for fd %d", s, fd );
     84            return s;
     85        }
     86    }
     87
     88    if( createIfMissing ) {
     89        struct tr_web_sockinfo * s =  tr_new0( struct tr_web_sockinfo, 1 );
     90        s->fd = fd;
     91        tr_list_prepend( &web->fds, s );
     92        dbgmsg( "created sockinfo %p for fd %d... we now have %d sockinfos", s, fd, tr_list_size(web->fds) );
     93        return s;
     94    }
     95
     96    return NULL;
     97}
     98
     99static void
     100clearSockinfoEvent( struct tr_web_sockinfo * s )
     101{
     102    if( s && s->evset )
     103    {
     104        dbgmsg( "clearing libevent polling for sockinfo %p, fd %d", s, s->fd );
     105        event_del( &s->ev );
     106        s->evset = FALSE;
     107    }
     108}
     109
     110static void
     111purgeSockinfo( tr_web * web, int fd )
     112{
     113    struct tr_web_sockinfo * s = getSockinfo( web, fd, FALSE );
     114
     115    if( s != NULL )
     116    {
     117        tr_list_remove_data( &web->fds, s );
     118        clearSockinfoEvent( s );
     119        dbgmsg( "freeing sockinfo %p, fd %d", s, s->fd );
     120        tr_free( s );
     121    }
     122}
    65123
    66124/***
     
    128186        }
    129187
     188        curl_easy_setopt( easy, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
    130189        curl_easy_setopt( easy, CURLOPT_DNS_CACHE_TIMEOUT, 360L );
    131190        curl_easy_setopt( easy, CURLOPT_CONNECTTIMEOUT, 60L );
     
    149208            curl_easy_setopt( easy, CURLOPT_ENCODING, "" );
    150209
    151 #if 0
    152         if( web->still_running >= MAX_CONCURRENT_TASKS )
    153210        {
    154             tr_list_append( &web->easy_queue, easy );
    155             dbgmsg( " >> enqueueing a task ... size is now %d",
    156                                            tr_list_size( web->easy_queue ) );
    157         }
    158         else
    159 #endif
    160         {
    161             const CURLMcode rc = curl_multi_add_handle( web->multi, easy );
    162             if( rc == CURLM_OK )
     211            const CURLMcode mcode = curl_multi_add_handle( web->multi, easy );
     212            tr_assert( mcode == CURLM_OK, "curl_multi_add_handle() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
     213            if( mcode == CURLM_OK )
    163214                ++web->still_running;
    164215            else
    165                 tr_err( "%s", curl_multi_strerror( rc ) );
     216                tr_err( "%s", curl_multi_strerror( mcode ) );
    166217        }
    167218    }
     
    171222****
    172223***/
    173 
    174 struct tr_web_sockinfo
    175 {
    176     struct event ev;
    177     int evset;
    178 };
    179224
    180225static void
     
    220265        if( easy ) {
    221266            long code;
     267            long fd;
    222268            struct tr_web_task * task;
    223             curl_easy_getinfo( easy, CURLINFO_PRIVATE, (void*)&task );
    224             curl_easy_getinfo( easy, CURLINFO_RESPONSE_CODE, &code );
    225             curl_multi_remove_handle( g->multi, easy );
     269            CURLcode ecode;
     270            CURLMcode mcode;
     271
     272            ecode = curl_easy_getinfo( easy, CURLINFO_PRIVATE, (void*)&task );
     273            tr_assert( ecode == CURLE_OK, "curl_easy_getinfo() failed: %d (%s)", ecode, curl_easy_strerror( ecode ) );
     274
     275            ecode = curl_easy_getinfo( easy, CURLINFO_RESPONSE_CODE, &code );
     276            tr_assert( ecode == CURLE_OK, "curl_easy_getinfo() failed: %d (%s)", ecode, curl_easy_strerror( ecode ) );
     277
     278            ecode = curl_easy_getinfo( easy, CURLINFO_LASTSOCKET, &fd );
     279            tr_assert( ecode == CURLE_OK, "curl_easy_getinfo() failed: %d (%s)", ecode, curl_easy_strerror( ecode ) );
     280            if( fd != -1L )
     281                purgeSockinfo( g, fd );
     282
     283            mcode = curl_multi_remove_handle( g->multi, easy );
     284            tr_assert( mcode == CURLM_OK, "curl_multi_socket_action() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
     285
    226286            curl_easy_cleanup( easy );
    227287            task_finish( task, code );
     
    258318}
    259319
    260 #if 0
    261 static void
    262 add_tasks_from_queue( tr_web * g )
    263 {
    264     while( ( g->still_running < MAX_CONCURRENT_TASKS )
    265         && ( tr_list_size( g->easy_queue ) > 0 ) )
    266     {
    267         CURL * easy = tr_list_pop_front( &g->easy_queue );
    268         if( easy )
    269         {
    270             const CURLMcode rc = curl_multi_add_handle( g->multi, easy );
    271             if( rc != CURLM_OK )
    272                 tr_err( "%s", curl_multi_strerror( rc ) );
    273             else {
    274                 dbgmsg( "pumped the task queue, %d remain",
    275                         tr_list_size( g->easy_queue ) );
    276                 ++g->still_running;
    277             }
    278         }
    279     }
    280 }
    281 #endif
    282 
    283320static void
    284321web_close( tr_web * g )
    285322{
     323    CURLMcode mcode;
     324
    286325    stop_timer( g );
    287     curl_multi_cleanup( g->multi );
     326
     327    mcode = curl_multi_cleanup( g->multi );
     328    tr_assert( mcode == CURLM_OK, "curl_multi_cleanup() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
     329    if( mcode != CURLM_OK )
     330        tr_err( "%s", curl_multi_strerror( mcode ) );
     331
    288332    tr_free( g );
    289333}
     
    296340{
    297341    int closed = FALSE;
    298     CURLMcode rc;
     342    CURLMcode mcode;
    299343
    300344    dbgmsg( "check_run_count: prev_running %d, still_running %d",
     
    303347    /* invoke libcurl's processing */
    304348    do {
    305         rc = curl_multi_socket_action( g->multi, fd, 0, &g->still_running );
    306         dbgmsg( "event_cb(): fd %d, still_running is %d",
    307                 fd, g->still_running );
    308     } while( rc == CURLM_CALL_MULTI_PERFORM );
    309     if( rc != CURLM_OK )
    310         tr_err( "%s", curl_multi_strerror( rc ) );
     349        mcode = curl_multi_socket_action( g->multi, fd, 0, &g->still_running );
     350        dbgmsg( "event_cb(): fd %d, still_running is %d", fd, g->still_running );
     351    } while( mcode == CURLM_CALL_MULTI_PERFORM );
     352    if( ( mcode == CURLM_BAD_SOCKET ) && ( fd != CURL_SOCKET_TIMEOUT ) )
     353        purgeSockinfo( g, fd );
     354    else {
     355        tr_assert( mcode == CURLM_OK, "curl_multi_socket_action() failed on fd %d: %d (%s)", fd, mcode, curl_multi_strerror( mcode ) );
     356        if( mcode != CURLM_OK )
     357            tr_err( "%s", curl_multi_strerror( mcode ) );
     358    }
    311359
    312360    remove_finished_tasks( g );
    313361
    314 #if 0
    315     add_tasks_from_queue( g );
    316 #endif
    317 
    318362    if( !g->still_running ) {
     363        assert( tr_list_size( g->fds ) == 0 );
    319364        stop_timer( g );
    320365        if( g->closing ) {
     
    343388}
    344389
    345 static void
    346 remsock( struct tr_web_sockinfo * f )
    347 {
    348     if( f ) {
    349         dbgmsg( "deleting sockinfo %p", f );
    350         if( f->evset )
    351             event_del( &f->ev );
    352         tr_free( f );
    353     }
    354 }
    355 
    356 static void
    357 setsock( curl_socket_t            sockfd,
    358          int                      action,
    359          struct tr_web          * g,
    360          struct tr_web_sockinfo * f )
    361 {
    362     const int kind = EV_PERSIST
    363                    | (( action & CURL_POLL_IN ) ? EV_READ : 0 )
    364                    | (( action & CURL_POLL_OUT ) ? EV_WRITE : 0 );
    365 
    366     assert( tr_amInEventThread( g->session ) );
    367     assert( g->session != NULL );
    368     assert( g->session->events != NULL );
    369 
    370     dbgmsg( "setsock: fd is %d, curl action is %d, libevent action is %d",
    371             sockfd, action, kind );
    372     if( f->evset )
    373         event_del( &f->ev );
    374     event_set( &f->ev, sockfd, kind, event_cb, g );
    375     f->evset = 1;
    376     event_add( &f->ev, NULL );
    377 }
    378 
    379 static void
    380 addsock( curl_socket_t    sockfd,
    381          int              action,
    382          struct tr_web  * g )
    383 {
    384     struct tr_web_sockinfo * f = tr_new0( struct tr_web_sockinfo, 1 );
    385     dbgmsg( "creating a sockinfo %p for fd %d", f, sockfd );
    386     setsock( sockfd, action, g, f );
    387     curl_multi_assign( g->multi, sockfd, f );
    388 }
    389 
    390390/* CURLMOPT_SOCKETFUNCTION */
    391391static int
    392392sock_cb( CURL            * e UNUSED,
    393          curl_socket_t     s,
    394          int               what,
    395          void            * vg,
    396          void            * vf)
    397 {
    398     struct tr_web * g = vg;
    399     struct tr_web_sockinfo * f = vf;
    400     dbgmsg( "sock_cb: what is %d, sockinfo is %p", what, f );
    401 
    402     if( what == CURL_POLL_REMOVE )
    403         remsock( f );
    404     else if( !f )
    405         addsock( s, what, g );
     393         curl_socket_t     fd,
     394         int               action,
     395         void            * vweb,
     396         void            * unused UNUSED)
     397{
     398    struct tr_web * web = vweb;
     399    dbgmsg( "sock_cb: action is %d, fd is %d", action, (int)fd );
     400
     401    if( action == CURL_POLL_REMOVE )
     402    {
     403        purgeSockinfo( web, fd );
     404    }
    406405    else
    407         setsock( s, what, g, f );
     406    {
     407        struct tr_web_sockinfo * sockinfo = getSockinfo( web, fd, TRUE );
     408        const int kind = EV_PERSIST
     409                       | (( action & CURL_POLL_IN ) ? EV_READ : 0 )
     410                       | (( action & CURL_POLL_OUT ) ? EV_WRITE : 0 );
     411        dbgmsg( "setsock: fd is %d, curl action is %d, libevent action is %d", fd, action, kind );
     412        assert( tr_amInEventThread( web->session ) );
     413        assert( kind != EV_PERSIST );
     414
     415        /* clear any old polling on this fd */
     416        clearSockinfoEvent( sockinfo );
     417
     418        /* set the new polling on this fd */
     419        dbgmsg( "enabling (libevent %d, libcurl %d) polling on sockinfo %p, fd %d", action, kind, sockinfo, fd );
     420        event_set( &sockinfo->ev, fd, kind, event_cb, web );
     421        event_add( &sockinfo->ev, NULL );
     422        sockinfo->evset = TRUE;
     423    }
    408424
    409425    return 0;
     
    462478tr_webInit( tr_session * session )
    463479{
     480    CURLMcode mcode;
    464481    static int curlInited = FALSE;
    465482    tr_web * web;
     
    480497
    481498    evtimer_set( &web->timer_event, timer_cb, web );
    482     curl_multi_setopt( web->multi, CURLMOPT_SOCKETDATA, web );
    483     curl_multi_setopt( web->multi, CURLMOPT_SOCKETFUNCTION, sock_cb );
    484     curl_multi_setopt( web->multi, CURLMOPT_TIMERDATA, web );
    485     curl_multi_setopt( web->multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb );
     499    mcode = curl_multi_setopt( web->multi, CURLMOPT_SOCKETDATA, web );
     500    tr_assert( mcode == CURLM_OK, "curl_mutli_setopt() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
     501    mcode = curl_multi_setopt( web->multi, CURLMOPT_SOCKETFUNCTION, sock_cb );
     502    tr_assert( mcode == CURLM_OK, "curl_mutli_setopt() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
     503    mcode = curl_multi_setopt( web->multi, CURLMOPT_TIMERDATA, web );
     504    tr_assert( mcode == CURLM_OK, "curl_mutli_setopt() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
     505    mcode = curl_multi_setopt( web->multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb );
     506    tr_assert( mcode == CURLM_OK, "curl_mutli_setopt() failed: %d (%s)", mcode, curl_multi_strerror( mcode ) );
    486507
    487508    return web;
Note: See TracChangeset for help on using the changeset viewer.