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