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