Annotation of libwww/Library/src/HTTCP.c, revision 2.19
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: ** THIS FUNCTION USED TO BE CALLED HTGetHostName()
! 491: */
! 492: PUBLIC char * HTGetHostBySock ARGS1(int, soc)
! 493: {
! 494: struct sockaddr addr;
! 495: int len = sizeof(struct sockaddr);
! 496: struct in_addr *iaddr;
! 497: struct hostent * phost; /* Pointer to host -- See netdb.h */
! 498: char *name = NULL;
! 499:
! 500: #ifdef DECNET /* Decnet ain't got no damn name server 8#OO */
! 501: return NULL;
! 502: #else
! 503: if (getpeername(soc, &addr, &len) < 0)
! 504: return NULL;
! 505:
! 506: iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
! 507: phost=gethostbyaddr((char*)iaddr,
! 508: sizeof(struct in_addr),
! 509: AF_INET);
! 510: if (!phost) {
! 511: if (TRACE) fprintf(stderr,
! 512: "TCP......... Can't find internet node name for peer!!\n");
! 513: return NULL;
! 514: }
! 515: StrAllocCopy(name, phost->h_name);
! 516: if (TRACE) fprintf(stderr, "TCP......... Peer name is `%s'\n", name);
! 517:
! 518: return name;
! 519:
! 520: #endif /* not DECNET */
! 521: }
! 522:
! 523:
1.1 timbl 524: /* Parse a network node address and port
525: ** -------------------------------------
526: **
527: ** On entry,
528: ** str points to a string with a node name or number,
529: ** with optional trailing colon and port number.
530: ** sin points to the binary internet or decnet address field.
531: **
532: ** On exit,
533: ** *sin is filled in. If no port is specified in str, that
534: ** field is left unchanged in *sin.
2.13 frystyk 535: **
536: ** NOTE: It is assumed that any portnumber and numeric host address
537: ** is given in decimal notation. Separation character is '.'
1.1 timbl 538: */
2.13 frystyk 539: PUBLIC int HTParseInet ARGS3(SockA *,sin, CONST char *,str, BOOL *, multihome)
1.1 timbl 540: {
2.13 frystyk 541: char *host = NULL;
542: StrAllocCopy(host, str); /* Take a copy we can mutilate */
1.1 timbl 543:
2.13 frystyk 544: /* Parse port number if present. */
545: *multihome = NO;
546: {
547: char *port;
548: if ((port=strchr(host, ':'))) {
549: *port++ = 0; /* Chop off port */
550: if (isdigit(*port)) {
1.1 timbl 551: #ifdef DECNET
2.13 frystyk 552: sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
553: #else /* Internet */
554: sin->sin_port = htons(atol(port));
1.1 timbl 555: #endif
2.13 frystyk 556: } else {
557: fprintf(stderr, "ParseInet... No port indicated\n");
558: }
1.1 timbl 559: }
2.13 frystyk 560: }
1.1 timbl 561:
2.13 frystyk 562: /* Parse Internet host */
1.1 timbl 563: #ifdef DECNET
564: /* read Decnet node name. @@ Should know about DECnet addresses, but it's
565: probably worth waiting until the Phase transition from IV to V. */
566:
567: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
568: strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
569:
570: if (TRACE) fprintf(stderr,
571: "DECnet: Parsed address as object number %d on host %.6s...\n",
572: sin->sdn_objnum, host);
573:
2.13 frystyk 574: #else /* Internet */
1.1 timbl 575:
2.13 frystyk 576: /* Parse host number if present */
577: {
578: BOOL numeric = YES;
579: char *strptr = host;
580: while (*strptr) {
581: if (!isdigit(*strptr) && *strptr != '.') {
582: numeric = NO;
583: break;
584: }
585: ++strptr;
586: }
587: if (numeric) {
588: sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
589: } else {
590: if (HTGetHostByName(host, sin, multihome)) {
591: free(host);
592: return -1;
593: }
594: }
595: if (TRACE) {
596: fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
597: (int) ntohs(sin->sin_port),
598: HTInetString(sin));
1.1 timbl 599: }
600: }
601: #endif /* Internet vs. Decnet */
2.13 frystyk 602: free(host);
1.1 timbl 603: return 0; /* OK */
604: }
605:
606:
2.16 frystyk 607: #ifdef OLD_CODE
1.1 timbl 608: /* Derive the name of the host on which we are
609: ** -------------------------------------------
610: **
611: */
2.8 luotonen 612: PRIVATE void get_host_details NOARGS
1.1 timbl 613:
614: #ifndef MAXHOSTNAMELEN
615: #define MAXHOSTNAMELEN 64 /* Arbitrary limit */
616: #endif
617:
618: {
619: char name[MAXHOSTNAMELEN+1]; /* The name of this host */
620: struct hostent * phost; /* Pointer to host -- See netdb.h */
621: int namelength = sizeof(name);
622:
623: if (hostname) return; /* Already done */
624: gethostname(name, namelength); /* Without domain */
2.18 frystyk 625: if (TRACE) fprintf(stderr, "TCP......... Local host name is %s\n", name);
1.1 timbl 626: StrAllocCopy(hostname, name);
627:
628: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
629: phost=gethostbyname(name); /* See netdb.h */
630: if (!phost) {
631: if (TRACE) fprintf(stderr,
2.9 luotonen 632: "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1 timbl 633: name);
634: return; /* Fail! */
635: }
636: StrAllocCopy(hostname, phost->h_name);
2.18 frystyk 637: if (TRACE)
638: fprintf(stderr, "TCP......... Full local host name is %s\n", hostname);
2.8 luotonen 639:
640: #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1.1 timbl 641: memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
642: if (TRACE) fprintf(stderr, " Name server says that I am `%s' = %s\n",
643: hostname, HTInetString(&HTHostAddress));
2.8 luotonen 644: #endif /* NEED_HOST_ADDRESS */
1.1 timbl 645:
646: #endif /* not Decnet */
647: }
2.16 frystyk 648: #endif /* OLD_CODE */
1.1 timbl 649:
2.19 ! frystyk 650:
! 651: /* HTSetHostName
! 652: ** Sets the current hostname inclusive domain name.
! 653: ** If this is not set then the default approach is used using
! 654: ** HTGetHostname().
! 655: */
! 656: PUBLIC void HTSetHostName ARGS1(char *, host)
! 657: {
! 658: if (host && *host)
! 659: StrAllocCopy(hostname, host);
! 660: else {
! 661: if (TRACE) fprintf(stderr, "SetHostName. Bad argument ignored\n");
! 662: }
! 663: }
! 664:
! 665:
! 666: /* HTGetHostName
2.18 frystyk 667: ** Returns the name of this host. It uses the following algoritm:
668: **
669: ** 1) gethostname()
670: ** 2) if the hostname doesn't contain any '.' try to read
671: ** /etc/resolv.conf. If there is no domain line in this file then
672: ** 3) Try getdomainname and do as the man pages say for resolv.conf (sun)
673: ** If there is no domain line in this file, then it is derived
674: ** from the domain name set by the domainname(1) command, usually
675: ** by removing the first component. For example, if the domain-
676: ** name is set to ``foo.podunk.edu'' then the default domain name
677: ** used will be ``pudunk.edu''.
678: **
679: ** This is the same procedure as used by res_init() and sendmail.
2.16 frystyk 680: **
681: ** Return: hostname on success else NULL
682: */
2.19 ! frystyk 683: PUBLIC CONST char * HTGetHostName NOARGS
1.1 timbl 684: {
2.18 frystyk 685: BOOL got_it = NO;
686: FILE *fp;
2.16 frystyk 687: char name[MAXHOSTNAMELEN+1];
2.18 frystyk 688: if (hostname) { /* If already done */
689: if (*hostname)
690: return hostname;
691: else
692: return NULL; /* We couldn't get the last time */
693: }
2.16 frystyk 694: *(name+MAXHOSTNAMELEN) = '\0';
695: if (gethostname(name, MAXHOSTNAMELEN)) { /* Maybe without domain */
696: if (TRACE)
697: fprintf(stderr, "HostName.... Can't get host name\n");
698: return NULL;
699: }
2.18 frystyk 700: if (TRACE)
701: fprintf(stderr, "HostName.... Local host name is %s\n", name);
2.16 frystyk 702: StrAllocCopy(hostname, name);
703:
2.18 frystyk 704: /* Now try the resolver config file */
705: if ((fp = fopen(RESOLV_CONF, "r")) != NULL) {
706: char buffer[80];
707: *(buffer+79) = '\0';
708: while (fgets(buffer, 79, fp)) {
709: if (!strncasecomp(buffer, "domain", 6)) {
710: char *domainstr = buffer+6;
711: char *end;
712: while (*domainstr == ' ' || *domainstr == '\t')
713: domainstr++;
714: end = domainstr;
715: while (*end && !isspace(*end))
716: end++;
717: *end = '\0';
718: if (*domainstr) {
719: StrAllocCat(hostname, ".");
720: StrAllocCat(hostname, domainstr);
721: got_it = YES;
722: break;
723: }
724: }
725: }
726: fclose(fp);
2.16 frystyk 727: }
728:
2.18 frystyk 729: /* If everything else has failed then try getdomainname */
730: if (!got_it) {
731: if (getdomainname(name, MAXHOSTNAMELEN)) {
732: if (TRACE)
733: fprintf(stderr, "HostName.... Can't get domain name\n");
734: *hostname = '\0';
735: return NULL;
736: }
737:
738: /* If the host name and the first part of the domain name are different
739: then use the former as it is more exact (I guess) */
740: if (strncmp(name, hostname, (int) strlen(hostname))) {
741: char *domain = strchr(name, '.');
742: if (!domain)
743: domain = name;
744: StrAllocCat(hostname, domain);
745: }
2.16 frystyk 746: }
2.18 frystyk 747: if (TRACE)
748: fprintf(stderr, "HostName.... Full local host name is %s\n", hostname);
749: return hostname;
750:
751: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
752: #ifdef OLD_CODE
753: /* Now we try to get information on the domain */
2.16 frystyk 754: {
755: struct hostent *hostelement;
756: if ((hostelement = gethostbyname(hostname)) == NULL) {
757: if (TRACE)
758: fprintf(stderr, "HostName.... Can't find host name on DNS\n");
759: FREE(hostname);
760: return NULL;
761: }
2.17 frystyk 762: StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16 frystyk 763: }
2.18 frystyk 764: #endif /* OLD_CODE */
2.16 frystyk 765: #endif /* not Decnet */
2.13 frystyk 766: }
767:
2.19 ! frystyk 768:
! 769: /* HTSetMailAddress
! 770: ** Sets the current mail address plus host name and domain name.
! 771: ** If this is not set then the default approach is used using
! 772: ** HTGetMailAddress().
! 773: */
! 774: PUBLIC void HTSetMailAddress ARGS1(char *, address)
! 775: {
! 776: if (address && *address)
! 777: StrAllocCopy(mailaddress, address);
! 778: else {
! 779: if (TRACE) fprintf(stderr, "SetMailAddress. Bad argument ignored\n");
! 780: }
! 781: }
! 782:
! 783:
! 784: /* HTGetMailAddress
! 785: **
! 786: ** Get the mail address of the current user on the current host. The
! 787: ** domain name used is the one initialized in HTSetHostName or
! 788: ** HTGetHostName. The login name is determined using (ordered):
! 789: **
! 790: ** getlogin
! 791: ** getpwuid(getuid())
! 792: **
! 793: ** The weakness about the last attempt is if the user has multiple
! 794: ** login names each with the same user ID. If this fails as well then:
! 795: **
! 796: ** LOGNAME environment variable
! 797: ** USER environment variable
! 798: **
! 799: ** Returns NULL if error else pointer to static string
! 800: */
! 801: PUBLIC CONST char * HTGetMailAddress NOARGS
! 802: {
! 803: char *login;
! 804: CONST char *domain;
! 805: struct passwd *pw_info;
! 806: if (mailaddress)
! 807: return mailaddress;
! 808: if ((login = (char *) getlogin()) == NULL) {
! 809: if (TRACE) fprintf(stderr, "MailAddress. getlogin returns NULL\n");
! 810: if ((pw_info = getpwuid(getuid())) == NULL) {
! 811: if (TRACE) fprintf(stderr, "MailAddress. getpwid returns NULL\n");
! 812: if ((login = getenv("LOGNAME")) == NULL) {
! 813: if (TRACE) fprintf(stderr, "MailAddress. LOGNAME not found\n");
! 814: if ((login = getenv("USER")) == NULL) {
! 815: if (TRACE) fprintf(stderr,"MailAddress. USER not found\n");
! 816: return NULL; /* I GIVE UP */
! 817: }
! 818: }
! 819: } else
! 820: login = pw_info->pw_name;
! 821: }
! 822: if (login) {
! 823: StrAllocCopy(mailaddress, login);
! 824: StrAllocCat(mailaddress, "@");
! 825: if ((domain = HTGetHostName()) != NULL)
! 826: StrAllocCat(mailaddress, domain);
! 827: return mailaddress;
! 828: }
! 829: return NULL;
! 830: }
! 831:
! 832: /* ------------------------------------------------------------------------- */
! 833: /* CONNECTION ESTABLISHMENT MANAGEMENT */
! 834: /* ------------------------------------------------------------------------- */
2.13 frystyk 835:
836: /* HTDoConnect()
837: **
838: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
839: ** the default_port value.
840: **
841: ** Returns 0 if OK, -1 on error
842: */
2.15 frystyk 843: PUBLIC int HTDoConnect ARGS4(HTNetInfo *, net, char *, url,
844: u_short, default_port, u_long *, addr)
2.13 frystyk 845: {
846: BOOL multihomed = NO;
847: time_t deltatime;
848: int status;
849: SockA sock_addr; /* SockA is defined in tcp.h */
850: char *p1 = HTParse(url, "", PARSE_HOST);
851: char *at_sign;
852: char *host;
853:
854: /* if theres an @ then use the stuff after it as a hostname */
855: if((at_sign = strchr(p1,'@')) != NULL)
856: host = at_sign+1;
857: else
858: host = p1;
859: if (TRACE) fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
860:
861: /* Set up defaults */
862: memset((void *) &sock_addr, '\0', sizeof(sock_addr));
863: #ifdef DECNET
864: sock_addr.sdn_family = AF_DECnet; /* Family = DECnet, host order */
865: sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object number */
866: #else /* Internet */
867: sock_addr.sin_family = AF_INET;
868: sock_addr.sin_port = htons(default_port);
869: #endif
870:
871: /* Get node name */
872: if (HTParseInet(&sock_addr, host, &multihomed)) {
873: if (TRACE) fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
2.15 frystyk 874: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
2.13 frystyk 875: (void *) host, strlen(host), "HTDoConnect");
876: free (p1);
2.15 frystyk 877: net->sockfd = -1;
2.13 frystyk 878: return -1;
879: }
880:
881: #ifdef DECNET
2.15 frystyk 882: if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
2.13 frystyk 883: #else
2.15 frystyk 884: if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2.13 frystyk 885: #endif
2.15 frystyk 886: HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
2.13 frystyk 887: free (p1);
888: return -1;
889: }
890: if (addr)
891: *addr = ntohl(sock_addr.sin_addr.s_addr);
892:
893: if (TRACE)
2.15 frystyk 894: fprintf(stderr, "HTDoConnect. Created socket number %d\n",
895: net->sockfd);
2.13 frystyk 896:
897: if (multihomed) /* Start timer on connection */
898: deltatime = time(NULL);
2.15 frystyk 899: if ((status = connect(net->sockfd, (struct sockaddr *) &sock_addr,
2.13 frystyk 900: sizeof(sock_addr))) < 0) {
2.15 frystyk 901: HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
2.13 frystyk 902: HTTCPCacheRemoveHost(host); /* Remove host from cache */
2.15 frystyk 903: if (NETCLOSE(net->sockfd) < 0)
904: HTErrorSysAdd(net->request, ERR_FATAL, NO, "close");
2.13 frystyk 905: free(p1);
2.15 frystyk 906: net->sockfd = -1;
2.13 frystyk 907: return -1;
908: }
909:
910: /* Measure time to make a connection and recalculate weights */
911: if (multihomed) {
912: deltatime = time(NULL) - deltatime;
913: HTTCPAddrWeights(host, deltatime);
914: }
915: free(p1);
916: return status;
917: }
918:
919:
920: /* HTDoAccept()
921: **
922: ** This function makes a non-blocking accept on a port and polls every
923: ** second until MAX_ACCEPT_POLL or interrupted by user.
924: **
925: ** BUGS Interrupted is not yet implemented!!!
926: **
927: ** Returns 0 if OK, -1 on error
928: */
2.15 frystyk 929: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13 frystyk 930: {
931: SockA soc_address; /* SockA is defined in tcp.h */
932: int status;
933: int cnt;
934: int soc_addrlen = sizeof(soc_address);
2.15 frystyk 935: if (net->sockfd < 0) {
2.13 frystyk 936: if (TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
937: return -1;
938: }
939:
940: /* First make the socket non-blocking */
2.15 frystyk 941: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.13 frystyk 942: status |= FNDELAY;
2.15 frystyk 943: status = FCNTL(net->sockfd, F_SETFL, status);
2.13 frystyk 944: }
945: if (status == -1) {
2.15 frystyk 946: HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13 frystyk 947: return -1;
948: }
949:
950: /* Now poll every sekund */
951: for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15 frystyk 952: if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13 frystyk 953: &soc_addrlen)) >= 0) {
954: if (TRACE) fprintf(stderr,
955: "HTDoAccept.. Accepted new socket %d\n",
956: status);
957: return status;
958: } else
2.15 frystyk 959: HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13 frystyk 960: sleep(1);
961: }
962:
963: /* If nothing has happened */
964: if (TRACE)
965: fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15 frystyk 966: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
967: "HTDoAccept");
2.13 frystyk 968: return -1;
1.1 timbl 969: }
970:
Webmaster