Annotation of libwww/Library/src/HTDNS.c, revision 2.29

2.1       frystyk     1: /*                                                                     HTDNS.c
                      2: **     DOMAIN NAME SERVICE MANAGER
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.29    ! frystyk     6: **     @(#) $Id: HTDNS.c,v 2.28 1999/02/03 17:37:42 frystyk Exp $
2.1       frystyk     7: **
                      8: **     This object manages a cache of hosts we have looked up vis DNS.
                      9: **     The object contains the necessary parts from hostent. For Internet host
                     10: **     hostent->h_addr_list is not an array of char pointers but an array of 
                     11: **     pointers of type in_addr.
                     12: **
                     13: **     13 Sep 95  HFN  Spawned from HTTCP.c and rewritten
                     14: */
                     15: 
                     16: /* Library include files */
2.26      frystyk    17: #include "wwwsys.h"
2.21      frystyk    18: #include "WWWUtil.h"
2.1       frystyk    19: #include "HTParse.h"
                     20: #include "HTAlert.h"
                     21: #include "HTError.h"
2.21      frystyk    22: #include "HTTrans.h"
2.23      frystyk    23: #include "HTHstMan.h"
2.1       frystyk    24: #include "HTDNS.h"                                      /* Implemented here */
                     25: 
2.25      frystyk    26: #define DNS_TIMEOUT            1800L        /* Default DNS timeout is 30 mn */
2.1       frystyk    27: 
                     28: /* Type definitions and global variables etc. local to this module */
                     29: struct _HTdns {
2.21      frystyk    30:     char *             hostname;                            /* name of host */
2.1       frystyk    31:     time_t             ntime;                              /* Creation time */
                     32:     int                        addrlength;            /* Length of address in bytes */
                     33:     int                        homes;         /* Number of IP addresses on the host */
                     34:     char **            addrlist;      /* List of addresses from name server */
                     35:     double *           weight;                    /* Weight on each address */
                     36: };
                     37: 
2.2       frystyk    38: PRIVATE HTList **CacheTable = NULL;
                     39: PRIVATE time_t DNSTimeout = DNS_TIMEOUT;          /* Timeout on DNS entries */
2.1       frystyk    40: 
                     41: /* ------------------------------------------------------------------------- */
                     42: 
2.20      frystyk    43: PRIVATE void free_object (HTdns * me)
2.1       frystyk    44: {
                     45:     if (me) {
2.17      frystyk    46:        HT_FREE(me->hostname);
2.1       frystyk    47:        if (*me->addrlist)
2.17      frystyk    48:            HT_FREE(*me->addrlist);
                     49:        HT_FREE(me->addrlist);
                     50:        HT_FREE(me->weight);
                     51:        HT_FREE(me);
2.1       frystyk    52:     }
                     53: }
                     54: 
2.21      frystyk    55: PRIVATE BOOL delete_object (HTList * list, HTdns * me)
2.1       frystyk    56: {
                     57:     if (PROT_TRACE)
2.18      eric       58:        HTTrace("DNS Delete.. object %p from list %p\n", me, list);
2.1       frystyk    59:     HTList_removeObject(list, (void *) me);
2.20      frystyk    60:     free_object(me);
2.1       frystyk    61:     return YES;
                     62: }
                     63: 
                     64: /*     HTDNS_setTimeout
                     65: **     ----------------
                     66: **     Set the cache timeout for DNS entries. Default is DNS_TIMEOUT
                     67: */
                     68: PUBLIC void HTDNS_setTimeout (time_t timeout)
                     69: {
                     70:     DNSTimeout = timeout;
                     71: }
                     72: 
                     73: /*     HTDNS_timeout
                     74: **     -------------
                     75: **     Get the cache timeout 
                     76: */
                     77: PUBLIC time_t HTDNS_timeout (time_t timeout)
                     78: {
                     79:     return DNSTimeout;
                     80: }
                     81: 
                     82: /*     HTDNS_add
                     83: **     ---------
                     84: **     Add an element to the cache of visited hosts. Note that this function
                     85: **     requires the system implemented structure hostent and not our own
2.21      frystyk    86: **     host_info. The homes variable indicates the number of IP addresses 
                     87: **     found. A host name must NOT contain a port number.
                     88: **     Returns address of new HTdns object
2.1       frystyk    89: */
2.22      frystyk    90: PUBLIC HTdns * HTDNS_add (HTList * list, struct hostent * element,
                     91:                          char *host, int *homes)
2.1       frystyk    92: {
                     93:     HTdns *me;
2.21      frystyk    94:     char *addr = NULL;
2.1       frystyk    95:     char **index = element->h_addr_list;
                     96:     int cnt = 1;
                     97: 
                     98:     while(*index++) cnt++;
2.17      frystyk    99:     if ((me = (HTdns *) HT_CALLOC(1, sizeof(HTdns))) == NULL ||
                    100:        (me->addrlist = (char **) HT_CALLOC(1, cnt*sizeof(char*))) == NULL ||
                    101:        (addr = (char *) HT_CALLOC(1, cnt*element->h_length)) == NULL)
                    102:        HT_OUTOFMEM("HTDNS_add");
2.1       frystyk   103:     StrAllocCopy(me->hostname, host);
                    104:     me->ntime = time(NULL);
                    105:     index = element->h_addr_list;
                    106:     cnt = 0;
                    107:     while (*index) {
                    108:        *(me->addrlist+cnt) = addr+cnt*element->h_length;
                    109:        memcpy((void *) *(me->addrlist+cnt++), *index++, element->h_length);
                    110:     }
                    111:     me->homes = cnt;
                    112:     *homes = cnt;
2.17      frystyk   113:     if ((me->weight = (double *) HT_CALLOC(me->homes, sizeof(double))) == NULL)
                    114:         HT_OUTOFMEM("HTDNS_add");
2.1       frystyk   115:     me->addrlength = element->h_length;
                    116:     if (PROT_TRACE)
2.18      eric      117:        HTTrace("DNS Add..... `%s\' with %d home(s) to %p\n",
2.1       frystyk   118:                host, *homes, list);
                    119:     HTList_addObject(list, (void *) me);
                    120:     return me;
                    121: }
                    122: 
                    123: 
                    124: /*     HTDNS_updateWeights
                    125: **     -------------------
                    126: **     This function calculates the weights of the different IP addresses
                    127: **     on a multi homed host. Each weight is calculated as
                    128: **
                    129: **             w(n+1) = w(n)*a + (1-a) * deltatime
                    130: **             a = exp(-1/Neff)
                    131: **             Neff is the effective number of samples used
                    132: **             deltatime is time spend on making a connection
                    133: **
                    134: **     A short window (low Neff) gives a high sensibility, but this is
                    135: **     required as we can't expect a lot of data to test on.
2.21      frystyk   136: **     "current" is the index returned by HTGetHostByName()
2.1       frystyk   137: */
2.24      frystyk   138: PUBLIC BOOL HTDNS_updateWeigths(HTdns *dns, int current, ms_t deltatime)
2.1       frystyk   139: {
                    140:     if (dns) {
                    141:        int cnt;
2.19      frystyk   142:        const double passive = 0.9;       /* Factor for all passive IP_addrs */
2.1       frystyk   143: #if 0
2.19      frystyk   144:        const int Neff = 3;
                    145:        const double alpha = exp(-1.0/Neff);
2.1       frystyk   146: #else
2.19      frystyk   147:        const double alpha = 0.716531310574;    /* Doesn't need the math lib */
2.1       frystyk   148: #endif
                    149:        for (cnt=0; cnt<dns->homes; cnt++) {
                    150:            if (cnt == current) {
                    151:                *(dns->weight+current) = *(dns->weight+current)*alpha + (1.0-alpha)*deltatime;
2.16      frystyk   152:                if (*(dns->weight+current) < 0.0) *(dns->weight+current) = 0.0;
2.1       frystyk   153:            } else {
                    154:                *(dns->weight+cnt) = *(dns->weight+cnt) * passive;
                    155:            }
                    156:            if (PROT_TRACE)
2.28      frystyk   157:                HTTrace("DNS weight.. Home %d has weight %4.2f\n", cnt,
2.1       frystyk   158:                        *(dns->weight+cnt));
                    159:        }
                    160:        return YES;
                    161:     }
                    162:     if (PROT_TRACE)
2.28      frystyk   163:        HTTrace("DNS weight.. Object %p not found'\n", dns);
2.1       frystyk   164:     return NO;
                    165: }
                    166: 
                    167: /*     HTDNS_delete
                    168: **     ------------
                    169: **     Remove an element from the cache
                    170: */
2.19      frystyk   171: PUBLIC BOOL HTDNS_delete (const char * host)
2.1       frystyk   172: {
                    173:     HTList *list;
                    174:     int hash = 0;
2.19      frystyk   175:     const char *ptr;
2.1       frystyk   176:     if (!host || !CacheTable) return NO;
                    177:     for(ptr=host; *ptr; ptr++)
2.29    ! frystyk   178:        hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HT_M_HASH_SIZE);
2.1       frystyk   179:     if ((list = CacheTable[hash])) {    /* We have the list, find the entry */
                    180:        HTdns *pres;
                    181:        while ((pres = (HTdns *) HTList_nextObject(list))) {
                    182:            if (!strcmp(pres->hostname, host)) {
                    183:                delete_object(CacheTable[hash], pres);
                    184:                break;
                    185:            }
                    186:        }
                    187:     }
                    188:     return YES;
                    189: }
                    190: 
                    191: /*     HTDNS_deleteAll
                    192: **     ---------------
                    193: **     Destroys the cache completely
                    194: */
                    195: PUBLIC BOOL HTDNS_deleteAll (void)
                    196: {
                    197:     int cnt;
                    198:     HTList *cur;
                    199:     if (!CacheTable) return NO;
2.29    ! frystyk   200:     for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
2.1       frystyk   201:        if ((cur = CacheTable[cnt])) { 
                    202:            HTdns *pres;
                    203:            while ((pres = (HTdns *) HTList_nextObject(cur)) != NULL)
2.20      frystyk   204:                free_object(pres);
2.1       frystyk   205:        }
                    206:        HTList_delete(CacheTable[cnt]);
                    207:        CacheTable[cnt] = NULL;
2.2       frystyk   208:     }
2.21      frystyk   209:     HT_FREE(CacheTable);
2.2       frystyk   210:     return YES;
                    211: }
2.1       frystyk   212: 
                    213: /*     HTGetHostByName
                    214: **     ---------------
                    215: **     Resolve the host name using internal DNS cache. As we want to refer   
                    216: **     a specific host when timing the connection the weight function must
                    217: **     use the 'current' value as returned.
                    218: **      Returns:
                    219: **             >0      Number of homes
                    220: **             -1      Error
                    221: */
2.23      frystyk   222: PUBLIC int HTGetHostByName (HTHost * host, char *hostname, HTRequest* request)
2.1       frystyk   223: {
2.23      frystyk   224:     SockA *sin = HTHost_getSockAddr(host);
2.1       frystyk   225:     int homes = -1;
                    226:     HTList *list;                                  /* Current list in cache */
                    227:     HTdns *pres = NULL;
2.23      frystyk   228:     if (!host || !hostname) {
2.1       frystyk   229:        if (PROT_TRACE)
2.18      eric      230:            HTTrace("HostByName.. Bad argument\n");
2.1       frystyk   231:        return -1;
                    232:     }
2.23      frystyk   233:     HTHost_setHome(host, 0);
2.1       frystyk   234:     
                    235:     /* Find a hash for this host */
                    236:     {
                    237:        int hash = 0;
                    238:        char *ptr;
2.23      frystyk   239:        for(ptr=hostname; *ptr; ptr++)
2.29    ! frystyk   240:            hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HT_M_HASH_SIZE);
2.1       frystyk   241:        if (!CacheTable) {
2.29    ! frystyk   242:            if ((CacheTable = (HTList* *) HT_CALLOC(HT_M_HASH_SIZE, sizeof(HTList *))) == NULL)
2.17      frystyk   243:                HT_OUTOFMEM("HTDNS_init");
2.1       frystyk   244:        }
                    245:        if (!CacheTable[hash]) CacheTable[hash] = HTList_new();
                    246:        list = CacheTable[hash];
                    247:     }
                    248: 
                    249:     /* Search the cache */
                    250:     {
                    251:        HTList *cur = list;
                    252:        while ((pres = (HTdns *) HTList_nextObject(cur))) {
2.23      frystyk   253:            if (!strcmp(pres->hostname, hostname)) {
2.1       frystyk   254:                if (time(NULL) > pres->ntime + DNSTimeout) {
                    255:                    if (PROT_TRACE)
2.18      eric      256:                        HTTrace("HostByName.. Refreshing cache\n");
2.1       frystyk   257:                    delete_object(list, pres);
                    258:                    pres = NULL;
                    259:                }
                    260:                break;
                    261:            }
                    262:        }
                    263:     }
                    264:     if (pres) {
                    265:        /*
                    266:        ** Find the best home. We still want to do this as we use it as a
                    267:        ** fall back for persistent connections
                    268:        */
                    269:        homes = pres->homes;
                    270:        if (pres->homes > 1) {
                    271:            int cnt = 0;
2.28      frystyk   272:            double best_weight = 1e30;                        /* Pretty bad */
2.1       frystyk   273:            while (cnt < pres->homes) {
                    274:                if (*(pres->weight+cnt) < best_weight) {
                    275:                    best_weight = *(pres->weight+cnt);
2.23      frystyk   276:                    HTHost_setHome(host, cnt);
2.1       frystyk   277:                }
                    278:                cnt++;
                    279:            }
                    280:        }
2.23      frystyk   281:        host->dns = pres;
                    282:        memcpy((void *) &sin->sin_addr, *(pres->addrlist+HTHost_home(host)),
2.14      frystyk   283:               pres->addrlength);
2.1       frystyk   284:     } else {
                    285:        struct hostent *hostelement;                          /* see netdb.h */
2.10      frystyk   286:        HTAlertCallback *cbf = HTAlert_find(HT_PROG_DNS);
2.1       frystyk   287: #ifdef HT_REENTRANT
                    288:        int thd_errno;
                    289:        char buffer[HOSTENT_MAX];
                    290:        struct hostent result;                        /* For gethostbyname_r */
2.23      frystyk   291:        if (cbf) (*cbf)(request, HT_PROG_DNS, HT_MSG_NULL,NULL,hostname,NULL);
                    292:        hostelement = gethostbyname_r(hostname, &result, buffer,
2.1       frystyk   293:                                      HOSTENT_MAX, &thd_errno);
                    294: #else
2.23      frystyk   295:        if (cbf) (*cbf)(request, HT_PROG_DNS, HT_MSG_NULL,NULL,hostname,NULL);
                    296:        hostelement = gethostbyname(hostname);
2.1       frystyk   297: #endif
                    298:        if (!hostelement) {
2.27      frystyk   299:             HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO,
                    300:                                     "gethostbyname");
2.1       frystyk   301:            return -1;
                    302:        }       
2.23      frystyk   303:        host->dns = HTDNS_add(list, hostelement, hostname, &homes);
2.14      frystyk   304:        memcpy((void *) &sin->sin_addr, *hostelement->h_addr_list,
                    305:               hostelement->h_length);
2.1       frystyk   306:     }
                    307:     return homes;
                    308: }
                    309: 
                    310: 
                    311: /*
                    312: **     Get host name of the machine on the other end of a socket.
                    313: **
                    314: */
2.9       frystyk   315: PUBLIC char * HTGetHostBySock (int soc)
2.1       frystyk   316: {
                    317:     struct sockaddr addr;
                    318:     int len = sizeof(struct sockaddr);
                    319:     struct in_addr *iaddr;
                    320:     char *name = NULL;
                    321:     struct hostent * phost;            /* Pointer to host -- See netdb.h */
                    322: #ifdef HT_REENTRANT
                    323:     int thd_errno;
                    324:     char buffer[HOSTENT_MAX];
                    325:     struct hostent result;                           /* For gethostbyaddr_r */
                    326: #endif
                    327: 
                    328: #ifdef DECNET  /* Decnet ain't got no damn name server 8#OO */
                    329:     return NULL;
                    330: #else
                    331:     if (getpeername(soc, &addr, &len) < 0)
                    332:        return NULL;
                    333:     iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
                    334: 
                    335: #ifdef HT_REENTRANT
                    336:     phost = gethostbyaddr_r((char *) iaddr, sizeof(struct in_addr), AF_INET,
                    337:                            &result, buffer, HOSTENT_MAX, &thd_errno);
                    338: #else
                    339:     phost = gethostbyaddr((char *) iaddr, sizeof(struct in_addr), AF_INET);
                    340: #endif
                    341:     if (!phost) {
                    342:        if (PROT_TRACE)
2.18      eric      343:            HTTrace("TCP......... Can't find internet node name for peer!!\n");
2.1       frystyk   344:        return NULL;
                    345:     }
                    346:     StrAllocCopy(name, phost->h_name);
2.18      eric      347:     if (PROT_TRACE) HTTrace("TCP......... Peer name is `%s'\n", name);
2.1       frystyk   348:     return name;
                    349: 
                    350: #endif /* not DECNET */
                    351: }

Webmaster