Annotation of libwww/Library/src/HTTCP.c, revision 2.21
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);
231: if (element->addrlist)
232: free(element->addrlist);
233: if (element->weight)
234: free(element->weight);
235: free(element);
236: }
237:
238:
239: /* HTTCPCacheRemoveHost
240: **
241: ** Removes the corresponding entrance in the cache
242: */
243: PRIVATE void HTTCPCacheRemoveHost ARGS1(char *, host)
244: {
245: HTAtom *hostatom = HTAtom_for(host);
246: HTList *cur = hostcache;
247: host_info *pres = NULL;
248: if (!hostcache) {
249: fprintf(stderr, "HostCache... Remove host not done, no cache\n");
250: return;
251: }
252: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
253: if (pres->hostname == hostatom) {
254: break;
255: }
256: }
257: if (pres)
258: HTTCPCacheRemoveElement(pres);
259: }
260:
261:
262: /* HTTCPCacheGarbage
263: **
264: ** Remove the element with the lowest hit rate
265: */
266: PRIVATE void HTTCPCacheGarbage NOARGS
267: {
268: HTList *cur = hostcache;
269: host_info *pres, *worst_match = NULL;
270: unsigned int worst_hits = 30000; /* Should use UINT_MAX :-( */
271: if (!hostcache) {
272: if (TRACE)
273: fprintf(stderr, "HostCache... Garbage collection not done, no cache\n");
274: return;
275: }
276:
277: /* Seek for worst element */
278: while ((pres = (host_info *) HTList_nextObject(cur))) {
279: if (!worst_match || pres->hits <= worst_hits) {
280: worst_match = pres;
281: worst_hits = pres->hits;
282: }
283: }
284: if (worst_match)
285: HTTCPCacheRemoveElement(worst_match);
286: }
287:
288:
289: /* HTTCPCacheAddElement
290: **
291: ** Add an element to the cache of visited hosts. Note that this function
292: ** requires the system implemented structure hostent and not our own
293: ** host_info. If multihomed host then multihome indicates the number of
294: ** IP addresses found. If not then multihome=0
295: **
296: ** Returns new element if OK NULL if error
297: */
298: PRIVATE host_info *HTTCPCacheAddElement ARGS2(HTAtom *, host,
299: struct hostent *, element)
300: {
301: int homes; /* Number of homes on the host */
302: host_info *new;
303: if (!host || !element) {
304: if (TRACE)
305: fprintf(stderr, "HostCache... Bad argument to add to cache\n");
306: return NULL;
307: }
308: if ((new = (host_info *) calloc(1, sizeof(host_info))) == NULL ||
309: (new->addrlist = (char **)
310: calloc(1, sizeof element->h_addr_list)) == NULL)
2.18 frystyk 311: outofmem(__FILE__, "HTTCPCacheAddElement");
2.13 frystyk 312: new->hostname = host;
313:
314: if ((homes = (sizeof element->h_addr_list) / element->h_length) > 1) {
315: new->multihomed = homes;
316: if ((new->weight = (float *) calloc(homes, sizeof(float))) == NULL)
317: outofmem(__FILE__, "HTTCPCacheAddElement");
318: }
319: new->addrlength = element->h_length;
320: memcpy((void *) new->addrlist, element->h_addr_list,
321: sizeof element->h_addr_list);
322: if (!hostcache)
323: hostcache = HTList_new();
324:
325: if (TRACE) {
326: if (new->multihomed)
327: fprintf(stderr, "HostCache... Adding multihomed host `%s' having %d homes\n", HTAtom_name(host), new->multihomed);
328: else
329: fprintf(stderr, "HostCache... Adding `%s'\n", HTAtom_name(host));
330: }
331: HTList_addObject(hostcache, (void *) new);
332: HTCacheSize++; /* Update number of elements */
333: return new;
334: }
335:
336:
337: /* HTTCPAddrWeights
338: **
339: ** This function calculates the weights of the different IP addresses
340: ** on a multi homed host. Each weight is calculated as
341: **
342: ** w(n+1) = w(n)*a + (1-a) * deltatime
343: ** a = exp(-1/Neff)
344: ** Neff is the effective number of samples used
345: ** deltatime is time spend on making a connection
346: **
347: ** A short window (low Neff) gives a high sensibility, but this is
348: ** required as we can't expect a lot of data to test on.
349: **
350: */
351: PUBLIC void HTTCPAddrWeights ARGS2(char *, host, time_t, deltatime)
352: {
353: HTAtom *hostatom = HTAtom_for(host);
354: HTList *cur = hostcache;
355: host_info *pres = NULL;
356: if (!hostcache) {
357: fprintf(stderr, "HostCache... Weights not calculated, no cache\n");
358: return;
359: }
360: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
361: if (pres->hostname == hostatom) {
362: break;
363: }
364: }
365: if (pres && pres->multihomed) {
366: int cnt;
2.14 frystyk 367: CONST float passive = 0.9; /* Factor for all passive IP_addrs */
2.13 frystyk 368: #if 0
2.14 frystyk 369: CONST int Neff = 3;
370: CONST float alpha = exp(-1.0/Neff);
2.13 frystyk 371: #else
2.14 frystyk 372: CONST float alpha = 0.716531310574;
2.13 frystyk 373: #endif
374: for (cnt=0; cnt<pres->multihomed; cnt++) {
375: if (cnt == pres->offset) {
376: *(pres->weight+pres->offset) = *(pres->weight+pres->offset)*alpha + (1.0-alpha)*deltatime;
377: } else {
378: *(pres->weight+cnt) = *(pres->weight+cnt) * passive;
379: }
380: }
381: } else if (TRACE) {
382: fprintf(stderr, "HostCache... Weights not calculated, host not found in cache or is not multihomed: `%s\'\n", host);
383: }
384: }
385:
2.19 frystyk 386: /* ------------------------------------------------------------------------- */
387: /* HOST NAME FUNCTIONS */
388: /* ------------------------------------------------------------------------- */
389:
390: #ifndef DECNET /* Function only used below for a trace message */
391:
392: /* Produce a string for an Internet address
393: ** ----------------------------------------
394: **
395: ** On exit,
396: ** returns a pointer to a static string which must be copied if
397: ** it is to be kept.
398: */
399:
400: PUBLIC CONST char * HTInetString ARGS1(SockA *, sin)
401: {
402: #if 0
403: /* This dumps core on some Sun systems :-(. Yhe problem is now, that
404: the current implememtation only works for IP-addresses and not in
405: other address spaces. */
406: return inet_ntoa(sin->sin_addr);
407: #endif
408: static char string[16];
409: sprintf(string, "%d.%d.%d.%d",
410: (int)*((unsigned char *)(&sin->sin_addr)+0),
411: (int)*((unsigned char *)(&sin->sin_addr)+1),
412: (int)*((unsigned char *)(&sin->sin_addr)+2),
413: (int)*((unsigned char *)(&sin->sin_addr)+3));
414: return string;
415: }
416: #endif /* Decnet */
417:
2.13 frystyk 418:
419: /* HTGetHostByName
420: **
421: ** Searched first the local cache then asks the DNS for an address of
422: ** the host specified.
423: **
424: ** Returns 0 if OK else -1
425: */
426: PUBLIC int HTGetHostByName ARGS3(char *, host, SockA *, sin, BOOL *, multi)
427: {
428: HTAtom *hostatom = HTAtom_for(host);
429: host_info *pres = NULL;
430: if (!hostcache)
431: hostcache = HTList_new(); /* First time through */
432: else {
433: HTList *cur = hostcache; /* Search cache */
434: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
435: if (pres->hostname == hostatom) {
436: if (TRACE)
2.18 frystyk 437: fprintf(stderr, "HostByName.. Host `%s\' found in cache.\n", host);
2.13 frystyk 438: break;
439: }
440: }
441: }
442:
443: /* If the host was not found in the cache, then do gethostbyname.
444: If cache found then find the best address if more than one. If we
445: are talking to a multi homed host then take the IP address with the
446: lowest weight */
447: if (pres) {
448: if (pres->multihomed) {
449: int cnt;
450: float best_weight = 1e30; /* Should be FLT_MAX :-( */
451: for (cnt=0; cnt<pres->multihomed; cnt++) {
452: if (*(pres->weight+cnt) < best_weight) {
453: best_weight = *(pres->weight+cnt);
454: pres->offset = cnt;
455: }
456: }
457: *multi = YES;
458: } else
459: *multi = NO;
460: pres->hits++; /* Update number of hits */
461: } else { /* Go and ask for it */
462: struct hostent *hostelement; /* see netdb.h */
463: #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */
464: if (TRACE)
465: fprintf(stderr, "HTTCP: gethostbyname(%s)\n", host);
466: #endif
467: if ((hostelement = gethostbyname(host)) == NULL) {
2.18 frystyk 468: if (TRACE) fprintf(stderr, "HostByName.. Can't find internet node name `%s'.\n", host);
2.13 frystyk 469: return -1;
470: }
471:
472: /* Add element to the cache and maybe do garbage collection */
473: if (HTCacheSize >= HTConCacheSize)
474: HTTCPCacheGarbage();
475: if ((pres = HTTCPCacheAddElement(hostatom, hostelement)) == NULL) {
476: return -1;
477: }
478: }
479:
480: /* Update socket structure using the element with the lowest weight. On
481: single homed hosts it means the first value */
482: memcpy(&sin->sin_addr, *(pres->addrlist+pres->offset), pres->addrlength);
483: return 0;
484: }
485:
486:
2.19 frystyk 487: /*
488: ** Get host name of the machine on the other end of a socket.
489: **
490: */
491: PUBLIC char * HTGetHostBySock ARGS1(int, soc)
492: {
493: struct sockaddr addr;
494: int len = sizeof(struct sockaddr);
495: struct in_addr *iaddr;
496: struct hostent * phost; /* Pointer to host -- See netdb.h */
497: char *name = NULL;
498:
499: #ifdef DECNET /* Decnet ain't got no damn name server 8#OO */
500: return NULL;
501: #else
502: if (getpeername(soc, &addr, &len) < 0)
503: return NULL;
504:
505: iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
506: phost=gethostbyaddr((char*)iaddr,
507: sizeof(struct in_addr),
508: AF_INET);
509: if (!phost) {
510: if (TRACE) fprintf(stderr,
511: "TCP......... Can't find internet node name for peer!!\n");
512: return NULL;
513: }
514: StrAllocCopy(name, phost->h_name);
515: if (TRACE) fprintf(stderr, "TCP......... Peer name is `%s'\n", name);
516:
517: return name;
518:
519: #endif /* not DECNET */
520: }
521:
522:
1.1 timbl 523: /* Parse a network node address and port
524: ** -------------------------------------
525: **
526: ** On entry,
527: ** str points to a string with a node name or number,
528: ** with optional trailing colon and port number.
529: ** sin points to the binary internet or decnet address field.
530: **
531: ** On exit,
532: ** *sin is filled in. If no port is specified in str, that
533: ** field is left unchanged in *sin.
2.13 frystyk 534: **
535: ** NOTE: It is assumed that any portnumber and numeric host address
536: ** is given in decimal notation. Separation character is '.'
1.1 timbl 537: */
2.13 frystyk 538: PUBLIC int HTParseInet ARGS3(SockA *,sin, CONST char *,str, BOOL *, multihome)
1.1 timbl 539: {
2.13 frystyk 540: char *host = NULL;
541: StrAllocCopy(host, str); /* Take a copy we can mutilate */
1.1 timbl 542:
2.13 frystyk 543: /* Parse port number if present. */
544: *multihome = NO;
545: {
546: char *port;
547: if ((port=strchr(host, ':'))) {
548: *port++ = 0; /* Chop off port */
549: if (isdigit(*port)) {
1.1 timbl 550: #ifdef DECNET
2.13 frystyk 551: sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
552: #else /* Internet */
553: sin->sin_port = htons(atol(port));
1.1 timbl 554: #endif
2.13 frystyk 555: } else {
556: fprintf(stderr, "ParseInet... No port indicated\n");
557: }
1.1 timbl 558: }
2.13 frystyk 559: }
1.1 timbl 560:
2.13 frystyk 561: /* Parse Internet host */
1.1 timbl 562: #ifdef DECNET
563: /* read Decnet node name. @@ Should know about DECnet addresses, but it's
564: probably worth waiting until the Phase transition from IV to V. */
565:
566: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
567: strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
568:
569: if (TRACE) fprintf(stderr,
570: "DECnet: Parsed address as object number %d on host %.6s...\n",
571: sin->sdn_objnum, host);
572:
2.13 frystyk 573: #else /* Internet */
1.1 timbl 574:
2.13 frystyk 575: /* Parse host number if present */
576: {
577: BOOL numeric = YES;
578: char *strptr = host;
579: while (*strptr) {
580: if (!isdigit(*strptr) && *strptr != '.') {
581: numeric = NO;
582: break;
583: }
584: ++strptr;
585: }
586: if (numeric) {
587: sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
588: } else {
589: if (HTGetHostByName(host, sin, multihome)) {
590: free(host);
591: return -1;
592: }
593: }
594: if (TRACE) {
595: fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
596: (int) ntohs(sin->sin_port),
597: HTInetString(sin));
1.1 timbl 598: }
599: }
600: #endif /* Internet vs. Decnet */
2.13 frystyk 601: free(host);
1.1 timbl 602: return 0; /* OK */
603: }
604:
605:
2.16 frystyk 606: #ifdef OLD_CODE
1.1 timbl 607: /* Derive the name of the host on which we are
608: ** -------------------------------------------
609: **
610: */
2.8 luotonen 611: PRIVATE void get_host_details NOARGS
1.1 timbl 612:
613: #ifndef MAXHOSTNAMELEN
614: #define MAXHOSTNAMELEN 64 /* Arbitrary limit */
615: #endif
616:
617: {
618: char name[MAXHOSTNAMELEN+1]; /* The name of this host */
619: struct hostent * phost; /* Pointer to host -- See netdb.h */
620: int namelength = sizeof(name);
621:
622: if (hostname) return; /* Already done */
623: gethostname(name, namelength); /* Without domain */
2.18 frystyk 624: if (TRACE) fprintf(stderr, "TCP......... Local host name is %s\n", name);
1.1 timbl 625: StrAllocCopy(hostname, name);
626:
627: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
628: phost=gethostbyname(name); /* See netdb.h */
629: if (!phost) {
630: if (TRACE) fprintf(stderr,
2.9 luotonen 631: "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1 timbl 632: name);
633: return; /* Fail! */
634: }
635: StrAllocCopy(hostname, phost->h_name);
2.18 frystyk 636: if (TRACE)
637: fprintf(stderr, "TCP......... Full local host name is %s\n", hostname);
2.8 luotonen 638:
639: #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1.1 timbl 640: memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
641: if (TRACE) fprintf(stderr, " Name server says that I am `%s' = %s\n",
642: hostname, HTInetString(&HTHostAddress));
2.8 luotonen 643: #endif /* NEED_HOST_ADDRESS */
1.1 timbl 644:
645: #endif /* not Decnet */
646: }
2.16 frystyk 647: #endif /* OLD_CODE */
1.1 timbl 648:
2.19 frystyk 649:
650: /* HTSetHostName
651: ** Sets the current hostname inclusive domain name.
652: ** If this is not set then the default approach is used using
653: ** HTGetHostname().
654: */
655: PUBLIC void HTSetHostName ARGS1(char *, host)
656: {
657: if (host && *host)
658: StrAllocCopy(hostname, host);
659: else {
660: if (TRACE) fprintf(stderr, "SetHostName. Bad argument ignored\n");
661: }
662: }
663:
664:
665: /* HTGetHostName
2.18 frystyk 666: ** Returns the name of this host. It uses the following algoritm:
667: **
668: ** 1) gethostname()
669: ** 2) if the hostname doesn't contain any '.' try to read
670: ** /etc/resolv.conf. If there is no domain line in this file then
671: ** 3) Try getdomainname and do as the man pages say for resolv.conf (sun)
672: ** If there is no domain line in this file, then it is derived
673: ** from the domain name set by the domainname(1) command, usually
674: ** by removing the first component. For example, if the domain-
675: ** name is set to ``foo.podunk.edu'' then the default domain name
676: ** used will be ``pudunk.edu''.
677: **
678: ** This is the same procedure as used by res_init() and sendmail.
2.16 frystyk 679: **
680: ** Return: hostname on success else NULL
681: */
2.19 frystyk 682: PUBLIC CONST char * HTGetHostName NOARGS
1.1 timbl 683: {
2.18 frystyk 684: BOOL got_it = NO;
685: FILE *fp;
2.16 frystyk 686: char name[MAXHOSTNAMELEN+1];
2.18 frystyk 687: if (hostname) { /* If already done */
688: if (*hostname)
689: return hostname;
690: else
691: return NULL; /* We couldn't get the last time */
692: }
2.16 frystyk 693: *(name+MAXHOSTNAMELEN) = '\0';
694: if (gethostname(name, MAXHOSTNAMELEN)) { /* Maybe without domain */
695: if (TRACE)
696: fprintf(stderr, "HostName.... Can't get host name\n");
697: return NULL;
698: }
2.18 frystyk 699: if (TRACE)
700: fprintf(stderr, "HostName.... Local host name is %s\n", name);
2.16 frystyk 701: StrAllocCopy(hostname, name);
702:
2.18 frystyk 703: /* Now try the resolver config file */
704: if ((fp = fopen(RESOLV_CONF, "r")) != NULL) {
705: char buffer[80];
706: *(buffer+79) = '\0';
707: while (fgets(buffer, 79, fp)) {
708: if (!strncasecomp(buffer, "domain", 6)) {
709: char *domainstr = buffer+6;
710: char *end;
711: while (*domainstr == ' ' || *domainstr == '\t')
712: domainstr++;
713: end = domainstr;
714: while (*end && !isspace(*end))
715: end++;
716: *end = '\0';
717: if (*domainstr) {
718: StrAllocCat(hostname, ".");
719: StrAllocCat(hostname, domainstr);
720: got_it = YES;
721: break;
722: }
723: }
724: }
725: fclose(fp);
2.16 frystyk 726: }
727:
2.18 frystyk 728: /* If everything else has failed then try getdomainname */
729: if (!got_it) {
730: if (getdomainname(name, MAXHOSTNAMELEN)) {
731: if (TRACE)
732: fprintf(stderr, "HostName.... Can't get domain name\n");
733: *hostname = '\0';
734: return NULL;
735: }
736:
737: /* If the host name and the first part of the domain name are different
738: then use the former as it is more exact (I guess) */
739: if (strncmp(name, hostname, (int) strlen(hostname))) {
740: char *domain = strchr(name, '.');
741: if (!domain)
742: domain = name;
743: StrAllocCat(hostname, domain);
744: }
2.16 frystyk 745: }
2.18 frystyk 746: if (TRACE)
747: fprintf(stderr, "HostName.... Full local host name is %s\n", hostname);
748: return hostname;
749:
750: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
751: #ifdef OLD_CODE
752: /* Now we try to get information on the domain */
2.16 frystyk 753: {
754: struct hostent *hostelement;
755: if ((hostelement = gethostbyname(hostname)) == NULL) {
756: if (TRACE)
757: fprintf(stderr, "HostName.... Can't find host name on DNS\n");
758: FREE(hostname);
759: return NULL;
760: }
2.17 frystyk 761: StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16 frystyk 762: }
2.18 frystyk 763: #endif /* OLD_CODE */
2.16 frystyk 764: #endif /* not Decnet */
2.13 frystyk 765: }
766:
2.19 frystyk 767:
768: /* HTSetMailAddress
769: ** Sets the current mail address plus host name and domain name.
770: ** If this is not set then the default approach is used using
771: ** HTGetMailAddress().
772: */
773: PUBLIC void HTSetMailAddress ARGS1(char *, address)
774: {
775: if (address && *address)
776: StrAllocCopy(mailaddress, address);
777: else {
778: if (TRACE) fprintf(stderr, "SetMailAddress. Bad argument ignored\n");
779: }
780: }
781:
782:
783: /* HTGetMailAddress
784: **
785: ** Get the mail address of the current user on the current host. The
786: ** domain name used is the one initialized in HTSetHostName or
787: ** HTGetHostName. The login name is determined using (ordered):
788: **
789: ** getlogin
790: ** getpwuid(getuid())
791: **
792: ** The weakness about the last attempt is if the user has multiple
793: ** login names each with the same user ID. If this fails as well then:
794: **
795: ** LOGNAME environment variable
796: ** USER environment variable
797: **
798: ** Returns NULL if error else pointer to static string
799: */
800: PUBLIC CONST char * HTGetMailAddress NOARGS
801: {
802: char *login;
803: CONST char *domain;
804: struct passwd *pw_info;
2.21 ! frystyk 805: if (mailaddress) {
! 806: if (*mailaddress)
! 807: return mailaddress;
! 808: else
! 809: return NULL; /* No luck the last time so we wont try again */
! 810: }
2.19 frystyk 811: if ((login = (char *) getlogin()) == NULL) {
812: if (TRACE) fprintf(stderr, "MailAddress. getlogin returns NULL\n");
813: if ((pw_info = getpwuid(getuid())) == NULL) {
814: if (TRACE) fprintf(stderr, "MailAddress. getpwid returns NULL\n");
815: if ((login = getenv("LOGNAME")) == NULL) {
816: if (TRACE) fprintf(stderr, "MailAddress. LOGNAME not found\n");
817: if ((login = getenv("USER")) == NULL) {
818: if (TRACE) fprintf(stderr,"MailAddress. USER not found\n");
819: return NULL; /* I GIVE UP */
820: }
821: }
822: } else
823: login = pw_info->pw_name;
824: }
825: if (login) {
826: StrAllocCopy(mailaddress, login);
827: StrAllocCat(mailaddress, "@");
828: if ((domain = HTGetHostName()) != NULL)
829: StrAllocCat(mailaddress, domain);
2.21 ! frystyk 830: else {
! 831: *mailaddress = '\0';
! 832: return NULL; /* Domain name not available */
! 833: }
2.19 frystyk 834: return mailaddress;
835: }
836: return NULL;
837: }
838:
839: /* ------------------------------------------------------------------------- */
840: /* CONNECTION ESTABLISHMENT MANAGEMENT */
841: /* ------------------------------------------------------------------------- */
2.13 frystyk 842:
843: /* HTDoConnect()
844: **
845: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
846: ** the default_port value.
847: **
848: ** Returns 0 if OK, -1 on error
849: */
2.15 frystyk 850: PUBLIC int HTDoConnect ARGS4(HTNetInfo *, net, char *, url,
851: u_short, default_port, u_long *, addr)
2.13 frystyk 852: {
853: BOOL multihomed = NO;
854: time_t deltatime;
855: int status;
856: SockA sock_addr; /* SockA is defined in tcp.h */
857: char *p1 = HTParse(url, "", PARSE_HOST);
858: char *at_sign;
859: char *host;
860:
861: /* if theres an @ then use the stuff after it as a hostname */
862: if((at_sign = strchr(p1,'@')) != NULL)
863: host = at_sign+1;
864: else
865: host = p1;
866: if (TRACE) fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
867:
868: /* Set up defaults */
869: memset((void *) &sock_addr, '\0', sizeof(sock_addr));
870: #ifdef DECNET
871: sock_addr.sdn_family = AF_DECnet; /* Family = DECnet, host order */
872: sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object number */
873: #else /* Internet */
874: sock_addr.sin_family = AF_INET;
875: sock_addr.sin_port = htons(default_port);
876: #endif
877:
878: /* Get node name */
879: if (HTParseInet(&sock_addr, host, &multihomed)) {
880: if (TRACE) fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
2.15 frystyk 881: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
2.13 frystyk 882: (void *) host, strlen(host), "HTDoConnect");
883: free (p1);
2.15 frystyk 884: net->sockfd = -1;
2.13 frystyk 885: return -1;
886: }
887:
888: #ifdef DECNET
2.15 frystyk 889: if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
2.13 frystyk 890: #else
2.15 frystyk 891: if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2.13 frystyk 892: #endif
2.15 frystyk 893: HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
2.13 frystyk 894: free (p1);
895: return -1;
896: }
897: if (addr)
898: *addr = ntohl(sock_addr.sin_addr.s_addr);
899:
900: if (TRACE)
2.15 frystyk 901: fprintf(stderr, "HTDoConnect. Created socket number %d\n",
902: net->sockfd);
2.13 frystyk 903:
904: if (multihomed) /* Start timer on connection */
905: deltatime = time(NULL);
2.15 frystyk 906: if ((status = connect(net->sockfd, (struct sockaddr *) &sock_addr,
2.13 frystyk 907: sizeof(sock_addr))) < 0) {
2.15 frystyk 908: HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
2.13 frystyk 909: HTTCPCacheRemoveHost(host); /* Remove host from cache */
2.15 frystyk 910: if (NETCLOSE(net->sockfd) < 0)
911: HTErrorSysAdd(net->request, ERR_FATAL, NO, "close");
2.13 frystyk 912: free(p1);
2.15 frystyk 913: net->sockfd = -1;
2.13 frystyk 914: return -1;
915: }
916:
917: /* Measure time to make a connection and recalculate weights */
918: if (multihomed) {
919: deltatime = time(NULL) - deltatime;
920: HTTCPAddrWeights(host, deltatime);
921: }
922: free(p1);
923: return status;
924: }
925:
926:
927: /* HTDoAccept()
928: **
929: ** This function makes a non-blocking accept on a port and polls every
930: ** second until MAX_ACCEPT_POLL or interrupted by user.
931: **
932: ** BUGS Interrupted is not yet implemented!!!
933: **
934: ** Returns 0 if OK, -1 on error
935: */
2.15 frystyk 936: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13 frystyk 937: {
938: SockA soc_address; /* SockA is defined in tcp.h */
939: int status;
940: int cnt;
941: int soc_addrlen = sizeof(soc_address);
2.15 frystyk 942: if (net->sockfd < 0) {
2.13 frystyk 943: if (TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
944: return -1;
945: }
946:
947: /* First make the socket non-blocking */
2.15 frystyk 948: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.13 frystyk 949: status |= FNDELAY;
2.15 frystyk 950: status = FCNTL(net->sockfd, F_SETFL, status);
2.13 frystyk 951: }
952: if (status == -1) {
2.15 frystyk 953: HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13 frystyk 954: return -1;
955: }
956:
957: /* Now poll every sekund */
958: for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15 frystyk 959: if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13 frystyk 960: &soc_addrlen)) >= 0) {
961: if (TRACE) fprintf(stderr,
962: "HTDoAccept.. Accepted new socket %d\n",
963: status);
964: return status;
965: } else
2.15 frystyk 966: HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13 frystyk 967: sleep(1);
968: }
969:
970: /* If nothing has happened */
971: if (TRACE)
972: fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15 frystyk 973: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
974: "HTDoAccept");
2.13 frystyk 975: return -1;
1.1 timbl 976: }
977:
Webmaster