Ignore:
Timestamp:
Jan 27, 2010, 6:40:12 AM (12 years ago)
Author:
charles
Message:

(trunk libT) web.c: add a cache for unresolvable hostnames

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/web.c

    r10019 r10024  
    2020#include "list.h"
    2121#include "net.h"
     22#include "ptrarray.h"
    2223#include "session.h"
    2324#include "trevent.h"
     
    6263    tr_session * session;
    6364    tr_address addr;
    64     tr_list * dns_cache;
     65    tr_ptrArray dns_cache;
    6566    struct event timer_event;
    6667};
     
    7576    curl_multi_cleanup( g->multi );
    7677    evtimer_del( &g->timer_event );
    77     tr_list_free( &g->dns_cache, (TrListForeachFunc)dns_cache_item_free );
     78    tr_ptrArrayDestruct( &g->dns_cache, (TrListForeachFunc)dns_cache_item_free );
    7879    memset( g, TR_MEMORY_TRASH, sizeof( struct tr_web ) );
    7980    tr_free( g );
     
    127128    char * resolved_host;
    128129    time_t expiration;
     130    tr_bool success;
    129131};
    130132
     
    137139}
    138140
    139 static const char *
    140 dns_get_cached_host( struct tr_web_task * task, const char * host )
    141 {
    142     tr_list * l;
    143     tr_web * g = task->session->web;
    144     struct dns_cache_item * item = NULL;
    145 
    146     if( g != NULL )
    147     {
    148         /* do we have it cached? */
    149         for( l=g->dns_cache; l!=NULL; l=l->next ) {
    150             struct dns_cache_item * tmp = l->data;
    151             if( !strcmp( host, tmp->host ) ) {
    152                 item = tmp;
    153                 break;
    154             }
    155         }
     141static int
     142dns_cache_compare( const void * va, const void * vb )
     143{
     144    const struct dns_cache_item * a = va;
     145    const struct dns_cache_item * b = vb;
     146    return strcmp( a->host, b->host );
     147}
     148
     149static int
     150dns_cache_compare_key( const void * va, const void * key )
     151{
     152    const struct dns_cache_item * a = va;
     153    return strcmp( a->host, key );
     154}
     155
     156typedef enum
     157{
     158    TR_DNS_OK,
     159    TR_DNS_FAIL,
     160    TR_DNS_UNTESTED
     161}
     162tr_dns_result;
     163
     164static tr_dns_result
     165dns_cache_lookup( struct tr_web_task * task, const char * host, const char ** resolved )
     166{
     167    tr_dns_result result = TR_DNS_UNTESTED;
     168
     169    if( task->session->web != NULL )
     170    {
     171        tr_ptrArray * cache = &task->session->web->dns_cache;
     172
     173        struct dns_cache_item * item = tr_ptrArrayFindSorted( cache, host,
     174                                                              dns_cache_compare_key );
    156175
    157176        /* has the ttl expired? */
    158         if( ( item != NULL ) && ( item->expiration <= tr_time( ) ) ) {
    159             tr_list_remove_data( &g->dns_cache, item );
     177        if( ( item != NULL ) && ( item->expiration <= tr_time( ) ) )
     178        {
     179            tr_ptrArrayRemoveSorted( cache, host, dns_cache_compare_key );
    160180            dns_cache_item_free( item );
    161181            item = NULL;
    162182        }
    163     }
    164 
    165     if( item != NULL )
    166         dbgmsg( "found cached dns entry for \"%s\": %s",
    167                 host, item->resolved_host );
    168 
    169     return item ? item->resolved_host : NULL;
     183
     184        if( item != NULL )
     185        {
     186            result = item->success ? TR_DNS_OK : TR_DNS_FAIL;
     187
     188            if( result == TR_DNS_OK )
     189            {
     190                *resolved = item->resolved_host;
     191           
     192                dbgmsg( "found cached dns entry for \"%s\": %s", host, *resolved );
     193            }
     194        }
     195    }
     196
     197    return result;
     198}
     199
     200static void
     201dns_cache_set_fail( struct tr_web_task * task, const char * host )
     202{
     203    if( task->session->web != NULL )
     204    {
     205        struct dns_cache_item * item = tr_new( struct dns_cache_item, 1 );
     206        item->host = tr_strdup( host );
     207        item->resolved_host = NULL;
     208        item->expiration = tr_time( ) + MIN_DNS_CACHE_TIME;
     209        item->success = FALSE;
     210        tr_ptrArrayInsertSorted( &task->session->web->dns_cache, item, dns_cache_compare );
     211    }
    170212}
    171213
    172214static const char*
    173 dns_set_cached_host( struct tr_web_task * task, const char * host,
    174                      const char * resolved, int ttl )
     215dns_cache_set_name( struct tr_web_task * task, const char * host,
     216                   const char * resolved, int ttl )
    175217{
    176218    char * ret = NULL;
    177     tr_web * g;
    178 
    179     assert( task != NULL );
    180     assert( host != NULL );
    181     assert( resolved != NULL );
    182     assert( ttl >= 0 );
    183219
    184220    ttl = MAX( MIN_DNS_CACHE_TIME, ttl );
    185221
    186     g = task->session->web;
    187     if( g != NULL )
     222    if( task->session->web != NULL )
    188223    {
    189224        struct dns_cache_item * item = tr_new( struct dns_cache_item, 1 );
     
    191226        item->resolved_host = tr_strdup( resolved );
    192227        item->expiration = tr_time( ) + ttl;
    193         tr_list_append( &g->dns_cache, item );
     228        item->success = TRUE;
     229        tr_ptrArrayInsertSorted( &task->session->web->dns_cache, item, dns_cache_compare );
    194230        ret = item->resolved_host;
    195231        dbgmsg( "adding dns cache entry for \"%s\": %s", host, resolved );
     
    260296        return;
    261297
    262     if( task->resolved_host == NULL )
     298    if( !task->resolved_host )
    263299    {
    264300        dbgmsg( "couldn't resolve host for \"%s\"... task failed", task->url );
     
    362398    struct tr_web_task * task = vtask;
    363399
    364     if( !err && ( task->host != NULL ) && ( count > 0 ) && ( ttl >= 0 ) && ( type == DNS_IPv6_AAAA ) )
     400    if( !err && task->host && ( count>0 ) && ( ttl>=0 ) && ( type==DNS_IPv6_AAAA ) )
    365401    {
    366402        int i;
     
    372408            if( b != NULL ) {
    373409                /* FIXME: is there a better way to tell which one to use if count > 1? */
    374                 task->resolved_host = dns_set_cached_host( task, task->host, b, ttl );
     410                task->resolved_host = dns_cache_set_name( task, task->host, b, ttl );
    375411                break;
    376412            }
     
    378414    }
    379415
     416    if( task->resolved_host == NULL )
     417        dns_cache_set_fail( task, task->host );
     418
    380419    addTask( task );
    381420}
     
    386425    struct tr_web_task * task = vtask;
    387426
    388     if( !err && ( task->host != NULL ) && ( count > 0 ) && ( ttl >= 0 ) && ( type == DNS_IPv4_A ) )
     427    if( !err && task->host && ( count>0 ) && ( ttl>=0 ) && ( type==DNS_IPv4_A ) )
    389428    {
    390429        struct in_addr * in_addrs = addresses;
    391430        const char * resolved = inet_ntoa( in_addrs[0] );
    392         task->resolved_host = dns_set_cached_host( task, task->host, resolved, ttl );
     431        task->resolved_host = dns_cache_set_name( task, task->host, resolved, ttl );
    393432        /* FIXME: if count > 1, is there a way to decide which is best to use? */
    394433    }
     
    406445    char * host = NULL;
    407446    struct tr_web_task * task = vtask;
     447    tr_dns_result lookup_result = TR_DNS_UNTESTED;
    408448
    409449    assert( task->resolved_host == NULL );
    410450
    411     if( !tr_httpParseURL( task->url, -1, &host, &port, NULL ) ) {
     451    if( !tr_httpParseURL( task->url, -1, &host, &port, NULL ) )
     452    {
    412453        task->port = port;
    413454        task->host = host;
    414         task->resolved_host = dns_get_cached_host( task, host );
    415     }
    416 
    417     if( ( task->resolved_host != NULL )
    418             || ( host == NULL )
    419             || evdns_resolve_ipv4( host, 0, dns_ipv4_done_cb, task ) )
     455        lookup_result = dns_cache_lookup( task, host, &task->resolved_host );
     456    }
     457
     458    if( lookup_result != TR_DNS_UNTESTED )
     459    {
     460        addTask( task );
     461    }
     462    else if( !host || evdns_resolve_ipv4( host, 0, dns_ipv4_done_cb, task ) )
     463    {
    420464        dns_ipv4_done_cb( DNS_ERR_UNKNOWN, DNS_IPv4_A, 0, 0, NULL, task );
     465    }
    421466}
    422467
     
    623668
    624669    web = tr_new0( struct tr_web, 1 );
     670    web->dns_cache = TR_PTR_ARRAY_INIT;
    625671    web->session = session;
    626672    web->timer_msec = DEFAULT_TIMER_MSEC; /* overwritten by multi_timer_cb() */
Note: See TracChangeset for help on using the changeset viewer.