Annotation of libwww/Library/src/HTTCP.c, revision 2.18
1.1 timbl 1: /* Generic Communication Code HTTCP.c
2: ** ==========================
3: **
4: ** This code is in common between client and server sides.
5: **
6: ** 16 Jan 92 TBL Fix strtol() undefined on CMU Mach.
7: ** 25 Jun 92 JFG Added DECNET option through TCP socket emulation.
2.7 duns 8: ** 13 Sep 93 MD Added correct return of vmserrorno for HTInetStatus.
9: ** Added decoding of vms error message for MULTINET.
2.13 frystyk 10: ** 31 May 94 HF Added cache on host id's; now use inet_ntoa() to
11: ** HTInetString and some other fixes. Added HTDoConnect
12: ** and HTDoAccept
1.1 timbl 13: */
14:
2.13 frystyk 15: #include "tcp.h" /* Defines SHORT_NAMES if necessary */
16: #include "HTUtils.h"
17: #include "HTAtom.h"
18: #include "HTList.h"
19: #include "HTParse.h"
20: #include "HTAccess.h"
21: #include "HTError.h"
1.1 timbl 22:
23: #ifdef SHORT_NAMES
24: #define HTInetStatus HTInStat
2.12 luotonen 25: #define HTErrnoString HTErrnoS
1.1 timbl 26: #define HTInetString HTInStri
27: #define HTParseInet HTPaInet
28: #endif
29:
2.8 luotonen 30:
2.11 duns 31: /* VMS stuff */
32: #ifdef VMS
33: #ifndef MULTINET
34: #define FD_SETSIZE 32
35: #else /* Multinet */
36: #define FD_SETSIZE 256
37: #endif /* Multinet */
38: #endif /* VMS */
39:
2.13 frystyk 40: /* Macros and other defines */
41: #define MAX_ACCEPT_POLL 30
42: #define FCNTL(r, s, t) fcntl(r, s, t)
43:
2.18 ! frystyk 44: #ifndef RESOLV_CONF
! 45: #define RESOLV_CONF "/etc/resolv.conf"
! 46: #endif
! 47:
2.13 frystyk 48: /* Globals */
49: PUBLIC unsigned int HTConCacheSize = 512; /* Number of cached servers */
50:
51: /* Type definitions and global variables etc. local to this module */
52:
53: /* This structure is a cache of hosts to whom we have connected over time.
54: The structure contains the necessary parts from hostent. For Internet host
55: hostent->h_addr_list is not an array of char pointers but an array of
56: pointers of type in_addr. */
57: typedef struct _host_info {
58: HTAtom * hostname; /* Official name of host */
59: int hits; /* Total number of hits on this host */
60: int addrlength; /* Length of address in bytes */
61: int multihomed; /* Number of IP addresses on the host */
62: int offset; /* Offset value of active IP address */
63: char ** addrlist; /* List of addresses from name server */
64: float * weight; /* Weight on each address */
65: } host_info;
66:
67: PRIVATE char *hostname = NULL; /* The name of this host */
68: PRIVATE HTList *hostcache = NULL; /* List of servers that we have talked to */
69: PRIVATE unsigned int HTCacheSize = 0; /* Current size of cache */
2.11 duns 70:
2.13 frystyk 71: /* ------------------------------------------------------------------------- */
1.1 timbl 72:
73: /* Encode INET status (as in sys/errno.h) inet_status()
74: ** ------------------
75: **
76: ** On entry,
77: ** where gives a description of what caused the error
78: ** global errno gives the error number in the unix way.
79: **
80: ** On return,
81: ** returns a negative status in the unix way.
82: */
83: #ifndef PCNFS
2.7 duns 84: #ifdef VMS
2.10 duns 85: #ifndef __DECC
1.1 timbl 86: extern int uerrno; /* Deposit of error info (as per errno.h) */
2.7 duns 87: extern volatile noshare int socket_errno; /* socket VMS error info
88: (used for translation of vmserrno) */
1.1 timbl 89: extern volatile noshare int vmserrno; /* Deposit of VMS error info */
90: extern volatile noshare int errno; /* noshare to avoid PSECT conflict */
2.10 duns 91: #endif /* not DECC */
2.11 duns 92: #endif /* VMS */
93:
1.1 timbl 94: #ifndef errno
95: extern int errno;
96: #endif /* errno */
97:
98: #ifndef VM
2.7 duns 99: #ifndef VMS
1.1 timbl 100: #ifndef NeXT
101: #ifndef THINK_C
102: extern char *sys_errlist[]; /* see man perror on cernvax */
103: extern int sys_nerr;
104: #endif /* think c */
105: #endif /* NeXT */
2.7 duns 106: #endif /* VMS */
1.1 timbl 107: #endif /* VM */
108:
109: #endif /* PCNFS */
110:
2.12 luotonen 111:
112: /*
113: * Returns the string equivalent of the current errno.
114: */
115: PUBLIC CONST char * HTErrnoString NOARGS
1.1 timbl 116: {
2.11 duns 117: #ifndef VMS
2.7 duns 118:
1.1 timbl 119: #ifdef VM
2.12 luotonen 120: return "(Error number not translated)"; /* What Is the VM equiv? */
1.1 timbl 121: #define ER_NO_TRANS_DONE
122: #endif
2.12 luotonen 123:
124: #if defined(NeXT) || defined(THINK_C)
125: return strerror(errno);
1.1 timbl 126: #define ER_NO_TRANS_DONE
127: #endif
2.12 luotonen 128:
129: #ifndef ER_NO_TRANS_DONE
130: return (errno < sys_nerr ? sys_errlist[errno] : "Unknown error");
1.1 timbl 131: #endif
132:
2.12 luotonen 133: #else /* VMS */
134:
135: static char buf[60];
136: sprintf(buf,"Unix errno = %ld dec, VMS error = %lx hex",errno,vaxc$errno);
137: return buf;
138:
1.1 timbl 139: #endif
2.12 luotonen 140: }
141:
142:
143: /* Report Internet Error
144: ** ---------------------
145: */
146: PUBLIC int HTInetStatus ARGS1(char *, where)
147: {
148: #ifndef VMS
149:
150: CTRACE(tfp,
151: "TCP errno... %d after call to %s() failed.\n............ %s\n",
152: errno, where, HTErrnoString());
1.1 timbl 153:
2.11 duns 154: #else /* VMS */
2.12 luotonen 155:
2.11 duns 156: CTRACE(tfp, " Unix error number = %ld dec\n", errno);
157: CTRACE(tfp, " VMS error = %lx hex\n", vaxc$errno);
2.12 luotonen 158:
2.11 duns 159: #ifdef MULTINET
160: CTRACE(tfp, " Multinet error = %lx hex\n", socket_errno);
161: #endif /* MULTINET */
2.12 luotonen 162:
2.11 duns 163: #endif /* VMS */
2.7 duns 164:
165: #ifdef VMS
2.11 duns 166: /* errno happen to be zero if vaxc$errno <> 0 */
167: return -vaxc$errno;
2.7 duns 168: #else
1.1 timbl 169: return -errno;
2.7 duns 170: #endif
1.1 timbl 171: }
172:
173:
174: /* Parse a cardinal value parse_cardinal()
175: ** ----------------------
176: **
177: ** On entry,
178: ** *pp points to first character to be interpreted, terminated by
179: ** non 0:9 character.
180: ** *pstatus points to status already valid
181: ** maxvalue gives the largest allowable value.
182: **
183: ** On exit,
184: ** *pp points to first unread character
185: ** *pstatus points to status updated iff bad
186: */
187:
188: PUBLIC unsigned int HTCardinal ARGS3
189: (int *, pstatus,
190: char **, pp,
191: unsigned int, max_value)
192: {
193: int n;
194: if ( (**pp<'0') || (**pp>'9')) { /* Null string is error */
195: *pstatus = -3; /* No number where one expeceted */
196: return 0;
197: }
198:
199: n=0;
200: while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
201:
202: if (n>max_value) {
203: *pstatus = -4; /* Cardinal outside range */
204: return 0;
205: }
206:
207: return n;
208: }
209:
210:
211: #ifndef DECNET /* Function only used below for a trace message */
212:
213: /* Produce a string for an Internet address
214: ** ----------------------------------------
215: **
216: ** On exit,
217: ** returns a pointer to a static string which must be copied if
218: ** it is to be kept.
219: */
220:
2.13 frystyk 221: PUBLIC CONST char * HTInetString ARGS1(SockA *, sin)
1.1 timbl 222: {
2.15 frystyk 223: #if 0
224: /* This dumps core on some Sun systems :-(. Yhe problem is now, that
225: the current implememtation only works for IP-addresses and not in
226: other address spaces. */
2.13 frystyk 227: return inet_ntoa(sin->sin_addr);
2.15 frystyk 228: #endif
1.1 timbl 229: static char string[16];
230: sprintf(string, "%d.%d.%d.%d",
231: (int)*((unsigned char *)(&sin->sin_addr)+0),
232: (int)*((unsigned char *)(&sin->sin_addr)+1),
233: (int)*((unsigned char *)(&sin->sin_addr)+2),
234: (int)*((unsigned char *)(&sin->sin_addr)+3));
2.15 frystyk 235: return string;
1.1 timbl 236: }
237: #endif /* Decnet */
238:
239:
2.13 frystyk 240: /* HTTCPCacheRemoveElement
241: **
242: ** Remove the element specified from the cache
243: */
244: PRIVATE void HTTCPCacheRemoveElement ARGS1(host_info *, element)
245: {
246: if (!hostcache) {
247: if (TRACE)
248: fprintf(stderr, "HostCache... Remove not done, no cache\n");
249: return;
250: }
251: if (TRACE) fprintf(stderr, "HostCache... Remove `%s' from cache\n",
252: HTAtom_name(element->hostname));
253: HTList_removeObject(hostcache, element);
254: if (element->addrlist)
255: free(element->addrlist);
256: if (element->weight)
257: free(element->weight);
258: free(element);
259: }
260:
261:
262: /* HTTCPCacheRemoveHost
263: **
264: ** Removes the corresponding entrance in the cache
265: */
266: PRIVATE void HTTCPCacheRemoveHost ARGS1(char *, host)
267: {
268: HTAtom *hostatom = HTAtom_for(host);
269: HTList *cur = hostcache;
270: host_info *pres = NULL;
271: if (!hostcache) {
272: fprintf(stderr, "HostCache... Remove host not done, no cache\n");
273: return;
274: }
275: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
276: if (pres->hostname == hostatom) {
277: break;
278: }
279: }
280: if (pres)
281: HTTCPCacheRemoveElement(pres);
282: }
283:
284:
285: /* HTTCPCacheGarbage
286: **
287: ** Remove the element with the lowest hit rate
288: */
289: PRIVATE void HTTCPCacheGarbage NOARGS
290: {
291: HTList *cur = hostcache;
292: host_info *pres, *worst_match = NULL;
293: unsigned int worst_hits = 30000; /* Should use UINT_MAX :-( */
294: if (!hostcache) {
295: if (TRACE)
296: fprintf(stderr, "HostCache... Garbage collection not done, no cache\n");
297: return;
298: }
299:
300: /* Seek for worst element */
301: while ((pres = (host_info *) HTList_nextObject(cur))) {
302: if (!worst_match || pres->hits <= worst_hits) {
303: worst_match = pres;
304: worst_hits = pres->hits;
305: }
306: }
307: if (worst_match)
308: HTTCPCacheRemoveElement(worst_match);
309: }
310:
311:
312: /* HTTCPCacheAddElement
313: **
314: ** Add an element to the cache of visited hosts. Note that this function
315: ** requires the system implemented structure hostent and not our own
316: ** host_info. If multihomed host then multihome indicates the number of
317: ** IP addresses found. If not then multihome=0
318: **
319: ** Returns new element if OK NULL if error
320: */
321: PRIVATE host_info *HTTCPCacheAddElement ARGS2(HTAtom *, host,
322: struct hostent *, element)
323: {
324: int homes; /* Number of homes on the host */
325: host_info *new;
326: if (!host || !element) {
327: if (TRACE)
328: fprintf(stderr, "HostCache... Bad argument to add to cache\n");
329: return NULL;
330: }
331: if ((new = (host_info *) calloc(1, sizeof(host_info))) == NULL ||
332: (new->addrlist = (char **)
333: calloc(1, sizeof element->h_addr_list)) == NULL)
2.18 ! frystyk 334: outofmem(__FILE__, "HTTCPCacheAddElement");
2.13 frystyk 335: new->hostname = host;
336:
337: if ((homes = (sizeof element->h_addr_list) / element->h_length) > 1) {
338: new->multihomed = homes;
339: if ((new->weight = (float *) calloc(homes, sizeof(float))) == NULL)
340: outofmem(__FILE__, "HTTCPCacheAddElement");
341: }
342: new->addrlength = element->h_length;
343: memcpy((void *) new->addrlist, element->h_addr_list,
344: sizeof element->h_addr_list);
345: if (!hostcache)
346: hostcache = HTList_new();
347:
348: if (TRACE) {
349: if (new->multihomed)
350: fprintf(stderr, "HostCache... Adding multihomed host `%s' having %d homes\n", HTAtom_name(host), new->multihomed);
351: else
352: fprintf(stderr, "HostCache... Adding `%s'\n", HTAtom_name(host));
353: }
354: HTList_addObject(hostcache, (void *) new);
355: HTCacheSize++; /* Update number of elements */
356: return new;
357: }
358:
359:
360: /* HTTCPAddrWeights
361: **
362: ** This function calculates the weights of the different IP addresses
363: ** on a multi homed host. Each weight is calculated as
364: **
365: ** w(n+1) = w(n)*a + (1-a) * deltatime
366: ** a = exp(-1/Neff)
367: ** Neff is the effective number of samples used
368: ** deltatime is time spend on making a connection
369: **
370: ** A short window (low Neff) gives a high sensibility, but this is
371: ** required as we can't expect a lot of data to test on.
372: **
373: */
374: PUBLIC void HTTCPAddrWeights ARGS2(char *, host, time_t, deltatime)
375: {
376: HTAtom *hostatom = HTAtom_for(host);
377: HTList *cur = hostcache;
378: host_info *pres = NULL;
379: if (!hostcache) {
380: fprintf(stderr, "HostCache... Weights not calculated, no cache\n");
381: return;
382: }
383: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
384: if (pres->hostname == hostatom) {
385: break;
386: }
387: }
388: if (pres && pres->multihomed) {
389: int cnt;
2.14 frystyk 390: CONST float passive = 0.9; /* Factor for all passive IP_addrs */
2.13 frystyk 391: #if 0
2.14 frystyk 392: CONST int Neff = 3;
393: CONST float alpha = exp(-1.0/Neff);
2.13 frystyk 394: #else
2.14 frystyk 395: CONST float alpha = 0.716531310574;
2.13 frystyk 396: #endif
397: for (cnt=0; cnt<pres->multihomed; cnt++) {
398: if (cnt == pres->offset) {
399: *(pres->weight+pres->offset) = *(pres->weight+pres->offset)*alpha + (1.0-alpha)*deltatime;
400: } else {
401: *(pres->weight+cnt) = *(pres->weight+cnt) * passive;
402: }
403: }
404: } else if (TRACE) {
405: fprintf(stderr, "HostCache... Weights not calculated, host not found in cache or is not multihomed: `%s\'\n", host);
406: }
407: }
408:
409:
410: /* HTGetHostByName
411: **
412: ** Searched first the local cache then asks the DNS for an address of
413: ** the host specified.
414: **
415: ** Returns 0 if OK else -1
416: */
417: PUBLIC int HTGetHostByName ARGS3(char *, host, SockA *, sin, BOOL *, multi)
418: {
419: HTAtom *hostatom = HTAtom_for(host);
420: host_info *pres = NULL;
421: if (!hostcache)
422: hostcache = HTList_new(); /* First time through */
423: else {
424: HTList *cur = hostcache; /* Search cache */
425: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
426: if (pres->hostname == hostatom) {
427: if (TRACE)
2.18 ! frystyk 428: fprintf(stderr, "HostByName.. Host `%s\' found in cache.\n", host);
2.13 frystyk 429: break;
430: }
431: }
432: }
433:
434: /* If the host was not found in the cache, then do gethostbyname.
435: If cache found then find the best address if more than one. If we
436: are talking to a multi homed host then take the IP address with the
437: lowest weight */
438: if (pres) {
439: if (pres->multihomed) {
440: int cnt;
441: float best_weight = 1e30; /* Should be FLT_MAX :-( */
442: for (cnt=0; cnt<pres->multihomed; cnt++) {
443: if (*(pres->weight+cnt) < best_weight) {
444: best_weight = *(pres->weight+cnt);
445: pres->offset = cnt;
446: }
447: }
448: *multi = YES;
449: } else
450: *multi = NO;
451: pres->hits++; /* Update number of hits */
452: } else { /* Go and ask for it */
453: struct hostent *hostelement; /* see netdb.h */
454: #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */
455: if (TRACE)
456: fprintf(stderr, "HTTCP: gethostbyname(%s)\n", host);
457: #endif
458: if ((hostelement = gethostbyname(host)) == NULL) {
2.18 ! frystyk 459: if (TRACE) fprintf(stderr, "HostByName.. Can't find internet node name `%s'.\n", host);
2.13 frystyk 460: return -1;
461: }
462:
463: /* Add element to the cache and maybe do garbage collection */
464: if (HTCacheSize >= HTConCacheSize)
465: HTTCPCacheGarbage();
466: if ((pres = HTTCPCacheAddElement(hostatom, hostelement)) == NULL) {
467: return -1;
468: }
469: }
470:
471: /* Update socket structure using the element with the lowest weight. On
472: single homed hosts it means the first value */
473: memcpy(&sin->sin_addr, *(pres->addrlist+pres->offset), pres->addrlength);
474: return 0;
475: }
476:
477:
1.1 timbl 478: /* Parse a network node address and port
479: ** -------------------------------------
480: **
481: ** On entry,
482: ** str points to a string with a node name or number,
483: ** with optional trailing colon and port number.
484: ** sin points to the binary internet or decnet address field.
485: **
486: ** On exit,
487: ** *sin is filled in. If no port is specified in str, that
488: ** field is left unchanged in *sin.
2.13 frystyk 489: **
490: ** NOTE: It is assumed that any portnumber and numeric host address
491: ** is given in decimal notation. Separation character is '.'
1.1 timbl 492: */
2.13 frystyk 493: PUBLIC int HTParseInet ARGS3(SockA *,sin, CONST char *,str, BOOL *, multihome)
1.1 timbl 494: {
2.13 frystyk 495: char *host = NULL;
496: StrAllocCopy(host, str); /* Take a copy we can mutilate */
1.1 timbl 497:
2.13 frystyk 498: /* Parse port number if present. */
499: *multihome = NO;
500: {
501: char *port;
502: if ((port=strchr(host, ':'))) {
503: *port++ = 0; /* Chop off port */
504: if (isdigit(*port)) {
1.1 timbl 505: #ifdef DECNET
2.13 frystyk 506: sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
507: #else /* Internet */
508: sin->sin_port = htons(atol(port));
1.1 timbl 509: #endif
2.13 frystyk 510: } else {
511: fprintf(stderr, "ParseInet... No port indicated\n");
512: }
1.1 timbl 513: }
2.13 frystyk 514: }
1.1 timbl 515:
2.13 frystyk 516: /* Parse Internet host */
1.1 timbl 517: #ifdef DECNET
518: /* read Decnet node name. @@ Should know about DECnet addresses, but it's
519: probably worth waiting until the Phase transition from IV to V. */
520:
521: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
522: strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
523:
524: if (TRACE) fprintf(stderr,
525: "DECnet: Parsed address as object number %d on host %.6s...\n",
526: sin->sdn_objnum, host);
527:
2.13 frystyk 528: #else /* Internet */
1.1 timbl 529:
2.13 frystyk 530: /* Parse host number if present */
531: {
532: BOOL numeric = YES;
533: char *strptr = host;
534: while (*strptr) {
535: if (!isdigit(*strptr) && *strptr != '.') {
536: numeric = NO;
537: break;
538: }
539: ++strptr;
540: }
541: if (numeric) {
542: sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
543: } else {
544: if (HTGetHostByName(host, sin, multihome)) {
545: free(host);
546: return -1;
547: }
548: }
549: if (TRACE) {
550: fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
551: (int) ntohs(sin->sin_port),
552: HTInetString(sin));
1.1 timbl 553: }
554: }
555: #endif /* Internet vs. Decnet */
2.13 frystyk 556: free(host);
1.1 timbl 557: return 0; /* OK */
558: }
559:
560:
2.8 luotonen 561: /*
562: ** Get host name of the machine on the other end of a socket.
2.13 frystyk 563: ** THIS SHOULD BE CALLED HTGetHostByAddr :-(
2.8 luotonen 564: */
565: PUBLIC char * HTGetHostName ARGS1(int, soc)
566: {
567: struct sockaddr addr;
568: int len = sizeof(struct sockaddr);
569: struct in_addr *iaddr;
570: struct hostent * phost; /* Pointer to host -- See netdb.h */
571: char *name = NULL;
572:
573: #ifdef DECNET /* Decnet ain't got no damn name server 8#OO */
574: return NULL;
575: #else
576: if (getpeername(soc, &addr, &len) < 0)
577: return NULL;
578:
579: iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
580: phost=gethostbyaddr((char*)iaddr,
581: sizeof(struct in_addr),
582: AF_INET);
583: if (!phost) {
584: if (TRACE) fprintf(stderr,
2.9 luotonen 585: "TCP......... Can't find internet node name for peer!!\n");
2.8 luotonen 586: return NULL;
587: }
588: StrAllocCopy(name, phost->h_name);
2.9 luotonen 589: if (TRACE) fprintf(stderr, "TCP......... Peer name is `%s'\n", name);
2.8 luotonen 590:
591: return name;
592:
593: #endif /* not DECNET */
594: }
595:
596:
2.16 frystyk 597: #ifdef OLD_CODE
1.1 timbl 598: /* Derive the name of the host on which we are
599: ** -------------------------------------------
600: **
601: */
2.8 luotonen 602: PRIVATE void get_host_details NOARGS
1.1 timbl 603:
604: #ifndef MAXHOSTNAMELEN
605: #define MAXHOSTNAMELEN 64 /* Arbitrary limit */
606: #endif
607:
608: {
609: char name[MAXHOSTNAMELEN+1]; /* The name of this host */
610: struct hostent * phost; /* Pointer to host -- See netdb.h */
611: int namelength = sizeof(name);
612:
613: if (hostname) return; /* Already done */
614: gethostname(name, namelength); /* Without domain */
2.18 ! frystyk 615: if (TRACE) fprintf(stderr, "TCP......... Local host name is %s\n", name);
1.1 timbl 616: StrAllocCopy(hostname, name);
617:
618: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
619: phost=gethostbyname(name); /* See netdb.h */
620: if (!phost) {
621: if (TRACE) fprintf(stderr,
2.9 luotonen 622: "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1 timbl 623: name);
624: return; /* Fail! */
625: }
626: StrAllocCopy(hostname, phost->h_name);
2.18 ! frystyk 627: if (TRACE)
! 628: fprintf(stderr, "TCP......... Full local host name is %s\n", hostname);
2.8 luotonen 629:
630: #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1.1 timbl 631: memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
632: if (TRACE) fprintf(stderr, " Name server says that I am `%s' = %s\n",
633: hostname, HTInetString(&HTHostAddress));
2.8 luotonen 634: #endif /* NEED_HOST_ADDRESS */
1.1 timbl 635:
636: #endif /* not Decnet */
637: }
2.16 frystyk 638: #endif /* OLD_CODE */
1.1 timbl 639:
2.16 frystyk 640: /* HTHostName
2.18 ! frystyk 641: ** Returns the name of this host. It uses the following algoritm:
! 642: **
! 643: ** 1) gethostname()
! 644: ** 2) if the hostname doesn't contain any '.' try to read
! 645: ** /etc/resolv.conf. If there is no domain line in this file then
! 646: ** 3) Try getdomainname and do as the man pages say for resolv.conf (sun)
! 647: ** If there is no domain line in this file, then it is derived
! 648: ** from the domain name set by the domainname(1) command, usually
! 649: ** by removing the first component. For example, if the domain-
! 650: ** name is set to ``foo.podunk.edu'' then the default domain name
! 651: ** used will be ``pudunk.edu''.
! 652: **
! 653: ** This is the same procedure as used by res_init() and sendmail.
2.16 frystyk 654: **
655: ** Return: hostname on success else NULL
656: */
2.12 luotonen 657: PUBLIC CONST char * HTHostName NOARGS
1.1 timbl 658: {
2.18 ! frystyk 659: BOOL got_it = NO;
! 660: FILE *fp;
2.16 frystyk 661: char name[MAXHOSTNAMELEN+1];
2.18 ! frystyk 662: if (hostname) { /* If already done */
! 663: if (*hostname)
! 664: return hostname;
! 665: else
! 666: return NULL; /* We couldn't get the last time */
! 667: }
2.16 frystyk 668: *(name+MAXHOSTNAMELEN) = '\0';
669: if (gethostname(name, MAXHOSTNAMELEN)) { /* Maybe without domain */
670: if (TRACE)
671: fprintf(stderr, "HostName.... Can't get host name\n");
672: return NULL;
673: }
2.18 ! frystyk 674: if (TRACE)
! 675: fprintf(stderr, "HostName.... Local host name is %s\n", name);
2.16 frystyk 676: StrAllocCopy(hostname, name);
677:
2.18 ! frystyk 678: /* Now try the resolver config file */
! 679: if ((fp = fopen(RESOLV_CONF, "r")) != NULL) {
! 680: char buffer[80];
! 681: *(buffer+79) = '\0';
! 682: while (fgets(buffer, 79, fp)) {
! 683: if (!strncasecomp(buffer, "domain", 6)) {
! 684: char *domainstr = buffer+6;
! 685: char *end;
! 686: while (*domainstr == ' ' || *domainstr == '\t')
! 687: domainstr++;
! 688: end = domainstr;
! 689: while (*end && !isspace(*end))
! 690: end++;
! 691: *end = '\0';
! 692: if (*domainstr) {
! 693: StrAllocCat(hostname, ".");
! 694: StrAllocCat(hostname, domainstr);
! 695: got_it = YES;
! 696: break;
! 697: }
! 698: }
! 699: }
! 700: fclose(fp);
2.16 frystyk 701: }
702:
2.18 ! frystyk 703: /* If everything else has failed then try getdomainname */
! 704: if (!got_it) {
! 705: if (getdomainname(name, MAXHOSTNAMELEN)) {
! 706: if (TRACE)
! 707: fprintf(stderr, "HostName.... Can't get domain name\n");
! 708: *hostname = '\0';
! 709: return NULL;
! 710: }
! 711:
! 712: /* If the host name and the first part of the domain name are different
! 713: then use the former as it is more exact (I guess) */
! 714: if (strncmp(name, hostname, (int) strlen(hostname))) {
! 715: char *domain = strchr(name, '.');
! 716: if (!domain)
! 717: domain = name;
! 718: StrAllocCat(hostname, domain);
! 719: }
2.16 frystyk 720: }
2.18 ! frystyk 721: if (TRACE)
! 722: fprintf(stderr, "HostName.... Full local host name is %s\n", hostname);
! 723: return hostname;
! 724:
! 725: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
! 726: #ifdef OLD_CODE
! 727: /* Now we try to get information on the domain */
2.16 frystyk 728: {
729: struct hostent *hostelement;
730: if ((hostelement = gethostbyname(hostname)) == NULL) {
731: if (TRACE)
732: fprintf(stderr, "HostName.... Can't find host name on DNS\n");
733: FREE(hostname);
734: return NULL;
735: }
2.17 frystyk 736: StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16 frystyk 737: }
2.18 ! frystyk 738: #endif /* OLD_CODE */
2.16 frystyk 739: #endif /* not Decnet */
2.13 frystyk 740: }
741:
742:
743: /* HTDoConnect()
744: **
745: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
746: ** the default_port value.
747: **
748: ** Returns 0 if OK, -1 on error
749: */
2.15 frystyk 750: PUBLIC int HTDoConnect ARGS4(HTNetInfo *, net, char *, url,
751: u_short, default_port, u_long *, addr)
2.13 frystyk 752: {
753: BOOL multihomed = NO;
754: time_t deltatime;
755: int status;
756: SockA sock_addr; /* SockA is defined in tcp.h */
757: char *p1 = HTParse(url, "", PARSE_HOST);
758: char *at_sign;
759: char *host;
760:
761: /* if theres an @ then use the stuff after it as a hostname */
762: if((at_sign = strchr(p1,'@')) != NULL)
763: host = at_sign+1;
764: else
765: host = p1;
766: if (TRACE) fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
767:
768: /* Set up defaults */
769: memset((void *) &sock_addr, '\0', sizeof(sock_addr));
770: #ifdef DECNET
771: sock_addr.sdn_family = AF_DECnet; /* Family = DECnet, host order */
772: sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object number */
773: #else /* Internet */
774: sock_addr.sin_family = AF_INET;
775: sock_addr.sin_port = htons(default_port);
776: #endif
777:
778: /* Get node name */
779: if (HTParseInet(&sock_addr, host, &multihomed)) {
780: if (TRACE) fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
2.15 frystyk 781: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
2.13 frystyk 782: (void *) host, strlen(host), "HTDoConnect");
783: free (p1);
2.15 frystyk 784: net->sockfd = -1;
2.13 frystyk 785: return -1;
786: }
787:
788: #ifdef DECNET
2.15 frystyk 789: if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
2.13 frystyk 790: #else
2.15 frystyk 791: if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2.13 frystyk 792: #endif
2.15 frystyk 793: HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
2.13 frystyk 794: free (p1);
795: return -1;
796: }
797: if (addr)
798: *addr = ntohl(sock_addr.sin_addr.s_addr);
799:
800: if (TRACE)
2.15 frystyk 801: fprintf(stderr, "HTDoConnect. Created socket number %d\n",
802: net->sockfd);
2.13 frystyk 803:
804: if (multihomed) /* Start timer on connection */
805: deltatime = time(NULL);
2.15 frystyk 806: if ((status = connect(net->sockfd, (struct sockaddr *) &sock_addr,
2.13 frystyk 807: sizeof(sock_addr))) < 0) {
2.15 frystyk 808: HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
2.13 frystyk 809: HTTCPCacheRemoveHost(host); /* Remove host from cache */
2.15 frystyk 810: if (NETCLOSE(net->sockfd) < 0)
811: HTErrorSysAdd(net->request, ERR_FATAL, NO, "close");
2.13 frystyk 812: free(p1);
2.15 frystyk 813: net->sockfd = -1;
2.13 frystyk 814: return -1;
815: }
816:
817: /* Measure time to make a connection and recalculate weights */
818: if (multihomed) {
819: deltatime = time(NULL) - deltatime;
820: HTTCPAddrWeights(host, deltatime);
821: }
822: free(p1);
823: return status;
824: }
825:
826:
827: /* HTDoAccept()
828: **
829: ** This function makes a non-blocking accept on a port and polls every
830: ** second until MAX_ACCEPT_POLL or interrupted by user.
831: **
832: ** BUGS Interrupted is not yet implemented!!!
833: **
834: ** Returns 0 if OK, -1 on error
835: */
2.15 frystyk 836: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13 frystyk 837: {
838: SockA soc_address; /* SockA is defined in tcp.h */
839: int status;
840: int cnt;
841: int soc_addrlen = sizeof(soc_address);
2.15 frystyk 842: if (net->sockfd < 0) {
2.13 frystyk 843: if (TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
844: return -1;
845: }
846:
847: /* First make the socket non-blocking */
2.15 frystyk 848: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.13 frystyk 849: status |= FNDELAY;
2.15 frystyk 850: status = FCNTL(net->sockfd, F_SETFL, status);
2.13 frystyk 851: }
852: if (status == -1) {
2.15 frystyk 853: HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13 frystyk 854: return -1;
855: }
856:
857: /* Now poll every sekund */
858: for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15 frystyk 859: if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13 frystyk 860: &soc_addrlen)) >= 0) {
861: if (TRACE) fprintf(stderr,
862: "HTDoAccept.. Accepted new socket %d\n",
863: status);
864: return status;
865: } else
2.15 frystyk 866: HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13 frystyk 867: sleep(1);
868: }
869:
870: /* If nothing has happened */
871: if (TRACE)
872: fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15 frystyk 873: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
874: "HTDoAccept");
2.13 frystyk 875: return -1;
1.1 timbl 876: }
877:
Webmaster