Changeset 6907


Ignore:
Timestamp:
Oct 15, 2008, 4:43:51 PM (13 years ago)
Author:
charles
Message:

(libT) try again to get the libevent+libcurl code working

Location:
trunk/libtransmission
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/tracker.c

    r6893 r6907  
    3232enum
    3333{
     34    /* the announceAt fields are set to this when the action is disabled */
     35    TR_TRACKER_STOPPED = 0,
     36
     37    /* the announceAt fields are set to this when the action is in progress */
     38    TR_TRACKER_BUSY = 1,
     39
    3440    HTTP_OK = 200,
    3541
     
    316322                   void *                       torrent_hash  )
    317323{
     324    tr_tracker * t = findTracker( session, torrent_hash );
     325    if( t )
     326    {
     327        const time_t now = time( NULL );
     328
     329        t->reannounceAt = TR_TRACKER_STOPPED;
     330        t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
     331
     332        if( t->scrapeAt <= now )
     333            t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
     334    }
     335
    318336    dbgmsg( NULL, "got a response to some `stop' message" );
     337    onReqDone( session );
    319338    tr_free( torrent_hash );
    320     onReqDone( session );
    321339}
    322340
     
    455473        publishErrorMessageAndStop( t, _( "Tracker returned a 4xx message" ) );
    456474        t->manualAnnounceAllowedAt = ~(time_t)0;
    457         t->reannounceAt = 0;
     475        t->reannounceAt = TR_TRACKER_STOPPED;
    458476    }
    459477    else if( 500 <= responseCode && responseCode <= 599 )
     
    761779        {
    762780            t->lastScrapeTime = now;
    763             t->scrapeAt = 1;
     781            t->scrapeAt = TR_TRACKER_BUSY;
    764782        }
    765783        else
    766784        {
    767785            t->lastAnnounceTime = now;
    768             t->reannounceAt = 1;
    769             t->manualAnnounceAllowedAt = 1;
     786            t->reannounceAt = TR_TRACKER_BUSY;
     787            t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
    770788        }
    771789    }
     
    823841          && ( trackerSupportsScrape( t, tor ) ) )
    824842        {
    825             t->scrapeAt = 1;
     843            t->scrapeAt = TR_TRACKER_BUSY;
    826844            enqueueScrape( session, t );
    827845        }
     
    831849          && ( t->isRunning ) )
    832850        {
    833             t->reannounceAt = 1;
    834             t->manualAnnounceAllowedAt = 1;
     851            t->reannounceAt = TR_TRACKER_BUSY;
     852            t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
    835853            enqueueRequest( session, t, TR_REQ_REANNOUNCE );
    836854        }
     
    10511069    {
    10521070        t->isRunning = 0;
    1053         t->reannounceAt = t->manualAnnounceAllowedAt = 0;
     1071        t->reannounceAt = TR_TRACKER_STOPPED;
     1072        t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
    10541073        enqueueRequest( t->session, t, TR_REQ_STOPPED );
    10551074    }
  • trunk/libtransmission/trevent.c

    r6904 r6907  
    332332    tr_timer * timer = tr_new0( tr_timer, 1 );
    333333
    334     timer->tv = tr_timevalMsec( interval_milliseconds );
     334    tr_timevalMsec( interval_milliseconds, &timer->tv );
    335335    timer->func = func;
    336336    timer->user_data = user_data;
  • trunk/libtransmission/utils.c

    r6905 r6907  
    393393**/
    394394
    395 struct timeval
    396 tr_timevalMsec( uint64_t milliseconds )
    397 {
    398     struct timeval ret;
     395void
     396tr_timevalMsec( uint64_t milliseconds, struct timeval * setme )
     397{
    399398    const uint64_t microseconds = milliseconds * 1000;
    400 
    401     ret.tv_sec  = microseconds / 1000000;
    402     ret.tv_usec = microseconds % 1000000;
    403     return ret;
     399    setme->tv_sec  = microseconds / 1000000;
     400    setme->tv_usec = microseconds % 1000000;
    404401}
    405402
  • trunk/libtransmission/utils.h

    r6897 r6907  
    184184                                              TR_GNUC_MALLOC;
    185185
    186 struct timeval tr_timevalMsec( uint64_t milliseconds );
     186struct timeval;
     187
     188void tr_timevalMsec( uint64_t           milliseconds,
     189                     struct timeval   * setme );
    187190
    188191
  • trunk/libtransmission/web.c

    r6893 r6907  
    44 * This file is licensed by the GPL version 2.  Works owned by the
    55 * Transmission project are granted a special exemption to clause 2(b)
    6  * so that the bulk of its code can remain under the MIT license.
     6 * so that the bulk of its code can remain under the MIT license. 
    77 * This exemption does not extend to derived works not owned by
    88 * the Transmission project.
     
    1818
    1919#include "transmission.h"
     20#include "list.h"
    2021#include "trevent.h"
    2122#include "utils.h"
    2223#include "web.h"
    2324
    24 #define CURL_CHECK_VERSION( major, minor, micro )    \
    25     ( LIBCURL_VERSION_MAJOR > ( major )    \
    26     || ( LIBCURL_VERSION_MAJOR == ( major ) && LIBCURL_VERSION_MINOR >\
    27         ( minor ) )    \
    28     || ( LIBCURL_VERSION_MAJOR == ( major ) && LIBCURL_VERSION_MINOR ==\
    29         ( minor )    \
    30        && LIBCURL_VERSION_PATCH >= ( micro ) ) )
    31 
    32 #define PULSE_MSEC 100
    33 
    34 #define dbgmsg( ... ) tr_deepLog( __FILE__, __LINE__, "web", __VA_ARGS__ )
     25#define dbgmsg( ... )  tr_deepLog( __FILE__, __LINE__, "web", __VA_ARGS__ )
    3526
    3627struct tr_web
    3728{
    38     unsigned int    dying  : 1;
    39     unsigned int    running : 1;
    40     int             remain;
    41     CURLM *         cm;
    42     tr_session *    session;
    43     struct event    timer;
     29    unsigned int dying : 1;
     30    int prev_running;
     31    int still_running;
     32    CURLM * multi;
     33    tr_session * session;
     34    struct event timer_event;
    4435};
    4536
     37/***
     38****
     39***/
     40
    4641struct tr_web_task
    4742{
    48     unsigned long       tag;
    49     struct evbuffer *   response;
    50     char *              url;
    51     char *              range;
    52     tr_session *        session;
    53     tr_web_done_func *  done_func;
    54     void *              done_func_user_data;
     43    unsigned long tag;
     44    struct evbuffer * response;
     45    char * url;
     46    char * range;
     47    tr_session * session;
     48    tr_web_done_func * done_func;
     49    void * done_func_user_data;
    5550};
    5651
    57 static void
    58 processCompletedTasks( tr_web * web )
    59 {
    60     CURL *    easy;
    61     CURLMsg * msg;
    62 
    63     do
    64     {
    65         /* this convoluted loop is from the "hiperinfo.c" sample which
    66          * hints that removing an easy handle in curl_multi_info_read's
    67          * loop may be unsafe */
    68         int more;
    69         easy = NULL;
    70         while( ( msg = curl_multi_info_read( web->cm, &more ) ) )
    71         {
    72             if( msg->msg == CURLMSG_DONE )
    73             {
    74                 easy = msg->easy_handle;
    75                 break;
    76             }
    77         }
    78 
    79         if( easy )
    80         {
    81             struct tr_web_task * task;
    82             long                 response_code;
    83             curl_easy_getinfo( easy, CURLINFO_PRIVATE, (void*)&task );
    84             curl_easy_getinfo( easy, CURLINFO_RESPONSE_CODE, &response_code );
    85             --web->remain;
    86             dbgmsg( "task #%lu done (%d remain)", task->tag, web->remain );
    87             task->done_func( web->session,
    88                              response_code,
    89                              EVBUFFER_DATA( task->response ),
    90                              EVBUFFER_LENGTH( task->response ),
    91                              task->done_func_user_data );
    92             curl_multi_remove_handle( web->cm, easy );
    93             curl_easy_cleanup( easy );
    94             evbuffer_free( task->response );
    95             tr_free( task->range );
    96             tr_free( task->url );
    97             tr_free( task );
    98         }
    99     }
    100     while( easy );
    101 }
    102 
    103 static void
    104 pump( tr_web * web )
    105 {
    106     int       unused;
    107     CURLMcode rc;
    108 
    109     do
    110     {
    111         rc = curl_multi_perform( web->cm, &unused );
    112     }
    113     while( rc == CURLM_CALL_MULTI_PERFORM );
    114 
    115     if( rc == CURLM_OK  )
    116         processCompletedTasks( web );
    117     else
    118         tr_err( "%s", curl_multi_strerror( rc ) );
    119 }
    120 
    12152static size_t
    122 writeFunc( void * ptr,
    123            size_t size,
    124            size_t nmemb,
    125            void * task )
     53writeFunc( void * ptr, size_t size, size_t nmemb, void * task )
    12654{
    12755    const size_t byteCount = size * nmemb;
    128 
    129     evbuffer_add( ( (struct tr_web_task*)task )->response, ptr, byteCount );
     56    evbuffer_add( ((struct tr_web_task*)task)->response, ptr, byteCount );
    13057    return byteCount;
    131 }
    132 
    133 static void
    134 ensureTimerIsRunning( tr_web * web )
    135 {
    136     if( !web->running )
    137     {
    138         struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    139         dbgmsg( "starting web timer" );
    140         web->running = 1;
    141         evtimer_add( &web->timer, &tv );
    142     }
    14358}
    14459
     
    14863    switch( t )
    14964    {
    150         case TR_PROXY_SOCKS4:
    151             return CURLPROXY_SOCKS4;
    152 
    153         case TR_PROXY_SOCKS5:
    154             return CURLPROXY_SOCKS5;
    155 
    156         default:
    157             return CURLPROXY_HTTP;
     65        case TR_PROXY_SOCKS4: return CURLPROXY_SOCKS4;
     66        case TR_PROXY_SOCKS5: return CURLPROXY_SOCKS5;
     67        default:              return CURLPROXY_HTTP;
    15868    }
    15969}
     
    16373{
    16474    struct tr_web_task * task = vtask;
    165     const tr_handle *    session = task->session;
     75    const tr_handle * session = task->session;
    16676
    16777    if( session && session->web )
    16878    {
    16979        struct tr_web * web = session->web;
    170         CURL *          ch;
    171 
    172         ensureTimerIsRunning( web );
    173 
    174         ++web->remain;
    175         dbgmsg( "adding task #%lu [%s] (%d remain)", task->tag, task->url,
    176                 web->remain );
     80        CURL * ch;
     81        CURLMcode rc;
     82
     83        dbgmsg( "adding task #%lu [%s]", task->tag, task->url );
    17784
    17885        ch = curl_easy_init( );
    17986
    180         if( !task->range && session->isProxyEnabled )
    181         {
     87        if( !task->range && session->isProxyEnabled ) {
    18288            curl_easy_setopt( ch, CURLOPT_PROXY, session->proxy );
    18389            curl_easy_setopt( ch, CURLOPT_PROXYPORT, session->proxyPort );
    184             curl_easy_setopt( ch, CURLOPT_PROXYTYPE,
    185                              getCurlProxyType( session->proxyType ) );
     90            curl_easy_setopt( ch, CURLOPT_PROXYTYPE, getCurlProxyType( session->proxyType ) );
    18691            curl_easy_setopt( ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
    18792        }
    188         if( !task->range && session->isProxyAuthEnabled )
    189         {
    190             char * str = tr_strdup_printf( "%s:%s", session->proxyUsername,
    191                                            session->proxyPassword );
     93        if( !task->range && session->isProxyAuthEnabled ) {
     94            char * str = tr_strdup_printf( "%s:%s", session->proxyUsername, session->proxyPassword );
    19295            curl_easy_setopt( ch, CURLOPT_PROXYUSERPWD, str );
    19396            tr_free( str );
     
    198101        curl_easy_setopt( ch, CURLOPT_WRITEFUNCTION, writeFunc );
    199102        curl_easy_setopt( ch, CURLOPT_WRITEDATA, task );
    200         curl_easy_setopt( ch, CURLOPT_USERAGENT,
    201                           TR_NAME "/" LONG_VERSION_STRING );
     103        curl_easy_setopt( ch, CURLOPT_USERAGENT, TR_NAME "/" LONG_VERSION_STRING );
    202104        curl_easy_setopt( ch, CURLOPT_SSL_VERIFYHOST, 0 );
    203105        curl_easy_setopt( ch, CURLOPT_SSL_VERIFYPEER, 0 );
     
    207109        curl_easy_setopt( ch, CURLOPT_MAXREDIRS, 5 );
    208110        curl_easy_setopt( ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
    209         curl_easy_setopt( ch, CURLOPT_VERBOSE, getenv(
    210                               "TR_CURL_VERBOSE" ) != NULL );
     111        curl_easy_setopt( ch, CURLOPT_VERBOSE, getenv( "TR_CURL_VERBOSE" ) != NULL );
    211112        if( task->range )
    212113            curl_easy_setopt( ch, CURLOPT_RANGE, task->range );
    213114        else /* don't set encoding if range is sent; it messes up binary data */
    214115            curl_easy_setopt( ch, CURLOPT_ENCODING, "" );
    215         curl_multi_add_handle( web->cm, ch );
    216     }
    217 }
     116
     117        rc = curl_multi_add_handle( web->multi, ch );
     118        if( rc != CURLM_OK )
     119            tr_err( "%s", curl_multi_strerror( rc ) );
     120    }
     121}
     122
     123/***
     124****
     125***/
     126
     127struct tr_web_sockinfo
     128{
     129    struct event ev;
     130    int evset;
     131};
     132
     133static void
     134finish_task( struct tr_web_task * task, long response_code )
     135{
     136    dbgmsg( "finished a web task... response code is %ld", response_code );
     137    dbgmsg( "===================================================" );
     138    task->done_func( task->session,
     139                     response_code,
     140                     EVBUFFER_DATA( task->response ),
     141                     EVBUFFER_LENGTH( task->response ),
     142                     task->done_func_user_data );
     143    evbuffer_free( task->response );
     144    tr_free( task->range );
     145    tr_free( task->url );
     146    tr_free( task );
     147}
     148
     149static void
     150webDestroy( tr_web * web )
     151{
     152    timeout_del( &web->timer_event );
     153    curl_multi_cleanup( web->multi );
     154    tr_free( web );
     155}
     156
     157/* note: this function can free the tr_web if it's been flagged for deletion
     158   and there are no more tasks remaining.  so, callers need to make sure to
     159   not reference their g pointer after calling this function */
     160static void
     161check_run_count( tr_web * g )
     162{
     163    dbgmsg( "check_run_count: prev_running %d, still_running %d",
     164            g->prev_running, g->still_running );
     165
     166    if( g->prev_running > g->still_running )
     167    {
     168        CURLMsg * msg;
     169        int msgs_left;
     170        CURL * easy;
     171        CURLcode res;
     172
     173        do{
     174            easy = NULL;
     175            while(( msg = curl_multi_info_read( g->multi, &msgs_left ))) {
     176                if( msg->msg == CURLMSG_DONE ) {
     177                    easy = msg->easy_handle;
     178                    res = msg->data.result;
     179                    break;
     180                }
     181            }
     182            if( easy ) {
     183                long code;
     184                struct tr_web_task * task;
     185                curl_easy_getinfo( easy, CURLINFO_PRIVATE, (void*)&task );
     186                curl_easy_getinfo( easy, CURLINFO_RESPONSE_CODE, &code );
     187                curl_multi_remove_handle( g->multi, easy );
     188                curl_easy_cleanup( easy );
     189                finish_task( task, code );
     190            }
     191        } while ( easy );
     192    }
     193
     194    g->prev_running = g->still_running;
     195
     196    if( g->still_running <= 0 ) {
     197        if( evtimer_pending( &g->timer_event, NULL ) ) {
     198            dbgmsg( "deleting the pending global timer" );
     199            evtimer_del( &g->timer_event );
     200        }
     201    }
     202
     203    if( g->dying && ( g->still_running < 1 ) ) {
     204        dbgmsg( "destroying the web global now that all the tasks are done" );
     205        webDestroy( g );
     206    }
     207}
     208
     209/* libevent says that sock is ready to be processed, so wake up libcurl */
     210static void
     211event_cb( int fd, short kind, void * vg )
     212{
     213    tr_web * g = vg;
     214    CURLMcode rc;
     215    int error = 0;
     216    int mask;
     217    socklen_t errsz = sizeof( error );
     218
     219    getsockopt( fd, SOL_SOCKET, SO_ERROR, &error, &errsz );
     220    if( error )
     221        mask = CURL_CSELECT_ERR;
     222    else {
     223        mask = 0;
     224        if( kind & EV_READ  ) mask |= CURL_CSELECT_IN;
     225        if( kind & EV_WRITE ) mask |= CURL_CSELECT_OUT;
     226    }
     227
     228    do {
     229        dbgmsg( stderr, "event_cb calling socket_action fd %d, mask %d", fd, mask );
     230        rc = curl_multi_socket_action( g->multi, fd, mask, &g->still_running );
     231    } while( rc == CURLM_CALL_MULTI_PERFORM );
     232    if( rc != CURLM_OK )
     233        tr_err( "%s", curl_multi_strerror( rc ) );
     234
     235    check_run_count( g );
     236}
     237
     238/* libevent says that timeout_ms have passed, so wake up libcurl */
     239static void
     240timer_cb( int socket UNUSED, short action UNUSED, void * vg )
     241{
     242    tr_web * g = vg;
     243    CURLMcode rc;
     244    dbgmsg( "libevent timer is done" );
     245
     246    do {
     247        dbgmsg( "timer_cb calling CURL_SOCKET_TIMEOUT" );
     248        rc = curl_multi_socket_action( g->multi, 0, CURL_SOCKET_TIMEOUT,
     249                                       &g->still_running );
     250    } while( rc == CURLM_CALL_MULTI_PERFORM );
     251
     252    if( rc != CURLM_OK )
     253        tr_err( "%s", curl_multi_strerror( rc ) );
     254
     255    check_run_count( g );
     256}
     257
     258static void
     259remsock( struct tr_web_sockinfo * f )
     260{
     261    if( f ) {
     262        dbgmsg( "deleting sockinfo %p", f );
     263        if( f->evset )
     264            event_del( &f->ev );
     265        tr_free( f );
     266    }
     267}
     268
     269static void
     270setsock( curl_socket_t            sockfd,
     271         int                      action,
     272         struct tr_web          * g,
     273         struct tr_web_sockinfo * f )
     274{
     275    const int kind = (action & CURL_POLL_IN ? EV_READ : 0)
     276                   | (action & CURL_POLL_OUT ? EV_WRITE : 0);
     277    dbgmsg( "setsock: fd is %d, curl action is %d, libevent action is %d", sockfd, action, kind );
     278    if( f->evset )
     279        event_del( &f->ev );
     280    event_set( &f->ev, sockfd, kind, event_cb, g );
     281    f->evset = 1;
     282    event_add( &f->ev, NULL );
     283}
     284
     285static void
     286addsock( curl_socket_t    sockfd,
     287         int              action,
     288         struct tr_web  * g )
     289{
     290    struct tr_web_sockinfo * f = tr_new0( struct tr_web_sockinfo, 1 );
     291    dbgmsg( "creating a sockinfo %p for fd %d", f, sockfd );
     292    setsock( sockfd, action, g, f );
     293    curl_multi_assign( g->multi, sockfd, f );
     294}
     295
     296/* CURLMOPT_SOCKETFUNCTION */
     297static int
     298sock_cb( CURL            * e UNUSED,
     299         curl_socket_t     s,
     300         int               what,
     301         void            * vg,
     302         void            * vf)
     303{
     304    struct tr_web * g = vg;
     305    struct tr_web_sockinfo * f = vf;
     306    dbgmsg( "sock_cb: what is %d, sockinfo is %p", what, f );
     307
     308    if( what == CURL_POLL_REMOVE )
     309        remsock( f );
     310    else if( !f )
     311        addsock( s, what, g );
     312    else
     313        setsock( s, what, g, f );
     314
     315    return 0;
     316}
     317
     318
     319/* libcurl wants us to tell it when timeout_ms have passed */
     320static void
     321multi_timer_cb( CURLM *multi UNUSED, long timeout_ms, void * vweb )
     322{
     323    tr_web * web = vweb;
     324    struct timeval timeout;
     325    dbgmsg( "adding a timeout for %ld seconds from now", timeout_ms/1000l );
     326    tr_timevalMsec( timeout_ms, &timeout );
     327    timeout_add( &web->timer_event, &timeout );
     328}
     329
     330/****
     331*****
     332****/
    218333
    219334void
    220 tr_webRun( tr_session *      session,
    221            const char *      url,
    222            const char *      range,
    223            tr_web_done_func   done_func,
    224            void *            done_func_user_data )
     335tr_webRun( tr_session         * session,
     336           const char         * url,
     337           const char         * range,
     338           tr_web_done_func     done_func,
     339           void               * done_func_user_data )
    225340{
    226341    if( session->web )
     
    242357}
    243358
    244 static void
    245 webDestroy( tr_web * web )
    246 {
    247     dbgmsg( "deleting web timer" );
    248     assert( !web->running );
    249     evtimer_del( &web->timer );
    250     curl_multi_cleanup( web->cm );
    251     tr_free( web );
    252 }
    253 
    254 static void
    255 pulse( int socket   UNUSED,
    256        short action UNUSED,
    257        void *       vweb )
    258 {
    259     tr_web * web = vweb;
    260 
    261     assert( web->running );
    262 
    263     pump( web );
    264 
    265     evtimer_del( &web->timer );
    266 
    267     web->running = web->remain > 0;
    268 
    269     if( web->running )
    270     {
    271         struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    272         evtimer_add( &web->timer, &tv );
    273     }
    274     else if( web->dying )
    275     {
    276         webDestroy( web );
    277     }
    278     else
    279     {
    280         dbgmsg( "stopping web timer" );
    281     }
    282 }
    283 
    284359tr_web*
    285360tr_webInit( tr_session * session )
    286361{
    287362    static int curlInited = FALSE;
    288     tr_web *   web;
     363    tr_web * web;
    289364
    290365    /* call curl_global_init if we haven't done it already.
    291366     * try to enable ssl for https support; but if that fails,
    292      * try a plain vanilla init */
    293     if( curlInited == FALSE )
    294     {
     367     * try a plain vanilla init */
     368    if( curlInited == FALSE ) {
    295369        curlInited = TRUE;
    296370        if( curl_global_init( CURL_GLOBAL_SSL ) )
    297371            curl_global_init( 0 );
    298372    }
    299 
     373   
    300374    web = tr_new0( struct tr_web, 1 );
    301     web->cm = curl_multi_init( );
     375    web->multi = curl_multi_init( );
    302376    web->session = session;
    303377
    304     evtimer_set( &web->timer, pulse, web );
    305 #if CURL_CHECK_VERSION( 7, 16, 3 )
    306     curl_multi_setopt( web->cm, CURLMOPT_MAXCONNECTS, 10 );
    307 #endif
    308     pump( web );
     378    timeout_set( &web->timer_event, timer_cb, web );
     379    curl_multi_setopt( web->multi, CURLMOPT_SOCKETDATA, web );
     380    curl_multi_setopt( web->multi, CURLMOPT_SOCKETFUNCTION, sock_cb );
     381    curl_multi_setopt( web->multi, CURLMOPT_TIMERDATA, web );
     382    curl_multi_setopt( web->multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb );
    309383
    310384    return web;
     
    315389{
    316390    tr_web * web = *web_in;
    317 
    318391    *web_in = NULL;
    319 
    320     if( !web->running )
     392    if( web->still_running < 1 )
    321393        webDestroy( web );
    322394    else
     
    324396}
    325397
    326 /***
    327 ****
    328 ***/
    329 
    330 static struct http_msg
    331 {
    332     long          code;
    333     const char *  text;
     398/*****
     399******
     400******
     401*****/
     402
     403static struct http_msg {
     404    long code;
     405    const char * text;
    334406} http_msg[] = {
    335     { 101, "Switching Protocols"             },
    336     { 200, "OK"                              },
    337     { 201, "Created"                         },
    338     { 202, "Accepted"                        },
    339     { 203, "Non-Authoritative Information"   },
    340     { 204, "No Content"                      },
    341     { 205, "Reset Content"                   },
    342     { 206, "Partial Content"                 },
    343     { 300, "Multiple Choices"                },
    344     { 301, "Moved Permanently"               },
    345     { 302, "Found"                           },
    346     { 303, "See Other"                       },
    347     { 304, "Not Modified"                    },
    348     { 305, "Use Proxy"                       },
    349     { 306, "(Unused)"                        },
    350     { 307, "Temporary Redirect"              },
    351     { 400, "Bad Request"                     },
    352     { 401, "Unauthorized"                    },
    353     { 402, "Payment Required"                },
    354     { 403, "Forbidden"                       },
    355     { 404, "Not Found"                       },
    356     { 405, "Method Not Allowed"              },
    357     { 406, "Not Acceptable"                  },
    358     { 407, "Proxy Authentication Required"   },
    359     { 408, "Request Timeout"                 },
    360     { 409, "Conflict"                        },
    361     { 410, "Gone"                            },
    362     { 411, "Length Required"                 },
    363     { 412, "Precondition Failed"             },
    364     { 413, "Request Entity Too Large"        },
    365     { 414, "Request-URI Too Long"            },
    366     { 415, "Unsupported Media Type"          },
     407    { 101, "Switching Protocols" },
     408    { 200, "OK" },
     409    { 201, "Created" },
     410    { 202, "Accepted" },
     411    { 203, "Non-Authoritative Information" },
     412    { 204, "No Content" },
     413    { 205, "Reset Content" },
     414    { 206, "Partial Content" },
     415    { 300, "Multiple Choices" },
     416    { 301, "Moved Permanently" },
     417    { 302, "Found" },
     418    { 303, "See Other" },
     419    { 304, "Not Modified" },
     420    { 305, "Use Proxy" },
     421    { 306, "(Unused)" },
     422    { 307, "Temporary Redirect" },
     423    { 400, "Bad Request" },
     424    { 401, "Unauthorized" },
     425    { 402, "Payment Required" },
     426    { 403, "Forbidden" },
     427    { 404, "Not Found" },
     428    { 405, "Method Not Allowed" },
     429    { 406, "Not Acceptable" },
     430    { 407, "Proxy Authentication Required" },
     431    { 408, "Request Timeout" },
     432    { 409, "Conflict" },
     433    { 410, "Gone" },
     434    { 411, "Length Required" },
     435    { 412, "Precondition Failed" },
     436    { 413, "Request Entity Too Large" },
     437    { 414, "Request-URI Too Long" },
     438    { 415, "Unsupported Media Type" },
    367439    { 416, "Requested Range Not Satisfiable" },
    368     { 417, "Expectation Failed"              },
    369     { 500, "Internal Server Error"           },
    370     { 501, "Not Implemented"                 },
    371     { 502, "Bad Gateway"                     },
    372     { 503, "Service Unavailable"             },
    373     { 504, "Gateway Timeout"                 },
    374     { 505, "HTTP Version Not Supported"      },
    375     {   0, NULL                              }
     440    { 417, "Expectation Failed" },
     441    { 500, "Internal Server Error" },
     442    { 501, "Not Implemented" },
     443    { 502, "Bad Gateway" },
     444    { 503, "Service Unavailable" },
     445    { 504, "Gateway Timeout" },
     446    { 505, "HTTP Version Not Supported" },
     447    { 0, NULL }
    376448};
    377449
    378450static int
    379 compareResponseCodes( const void * va,
    380                       const void * vb )
    381 {
    382     const long              a = *(const long*) va;
     451compareResponseCodes( const void * va, const void * vb )
     452{
     453    const long a = *(const long*) va;
    383454    const struct http_msg * b = vb;
    384 
    385455    return a - b->code;
    386456}
     
    390460{
    391461    struct http_msg * msg = bsearch( &code,
    392                                      http_msg,
    393                                      sizeof( http_msg ) /
    394                                      sizeof( http_msg[0] ),
     462                                     http_msg,
     463                                     sizeof( http_msg ) / sizeof( http_msg[0] ),
    395464                                     sizeof( http_msg[0] ),
    396465                                     compareResponseCodes );
    397 
    398466    return msg ? msg->text : "Unknown Error";
    399467}
    400 
Note: See TracChangeset for help on using the changeset viewer.