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