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