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