Annotation of libwww/Library/src/HTTCP.c, revision 2.14
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.13 frystyk 219: return inet_ntoa(sin->sin_addr);
220: #ifdef OLD_CODE
1.1 timbl 221: static char string[16];
222: sprintf(string, "%d.%d.%d.%d",
223: (int)*((unsigned char *)(&sin->sin_addr)+0),
224: (int)*((unsigned char *)(&sin->sin_addr)+1),
225: (int)*((unsigned char *)(&sin->sin_addr)+2),
226: (int)*((unsigned char *)(&sin->sin_addr)+3));
2.13 frystyk 227: #endif
1.1 timbl 228: }
229: #endif /* Decnet */
230:
231:
2.13 frystyk 232: /* HTTCPCacheRemoveElement
233: **
234: ** Remove the element specified from the cache
235: */
236: PRIVATE void HTTCPCacheRemoveElement ARGS1(host_info *, element)
237: {
238: if (!hostcache) {
239: if (TRACE)
240: fprintf(stderr, "HostCache... Remove not done, no cache\n");
241: return;
242: }
243: if (TRACE) fprintf(stderr, "HostCache... Remove `%s' from cache\n",
244: HTAtom_name(element->hostname));
245: HTList_removeObject(hostcache, element);
246: if (element->addrlist)
247: free(element->addrlist);
248: if (element->weight)
249: free(element->weight);
250: free(element);
251: }
252:
253:
254: /* HTTCPCacheRemoveHost
255: **
256: ** Removes the corresponding entrance in the cache
257: */
258: PRIVATE void HTTCPCacheRemoveHost ARGS1(char *, host)
259: {
260: HTAtom *hostatom = HTAtom_for(host);
261: HTList *cur = hostcache;
262: host_info *pres = NULL;
263: if (!hostcache) {
264: fprintf(stderr, "HostCache... Remove host not done, no cache\n");
265: return;
266: }
267: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
268: if (pres->hostname == hostatom) {
269: break;
270: }
271: }
272: if (pres)
273: HTTCPCacheRemoveElement(pres);
274: }
275:
276:
277: /* HTTCPCacheGarbage
278: **
279: ** Remove the element with the lowest hit rate
280: */
281: PRIVATE void HTTCPCacheGarbage NOARGS
282: {
283: HTList *cur = hostcache;
284: host_info *pres, *worst_match = NULL;
285: unsigned int worst_hits = 30000; /* Should use UINT_MAX :-( */
286: if (!hostcache) {
287: if (TRACE)
288: fprintf(stderr, "HostCache... Garbage collection not done, no cache\n");
289: return;
290: }
291:
292: /* Seek for worst element */
293: while ((pres = (host_info *) HTList_nextObject(cur))) {
294: if (!worst_match || pres->hits <= worst_hits) {
295: worst_match = pres;
296: worst_hits = pres->hits;
297: }
298: }
299: if (worst_match)
300: HTTCPCacheRemoveElement(worst_match);
301: }
302:
303:
304: /* HTTCPCacheAddElement
305: **
306: ** Add an element to the cache of visited hosts. Note that this function
307: ** requires the system implemented structure hostent and not our own
308: ** host_info. If multihomed host then multihome indicates the number of
309: ** IP addresses found. If not then multihome=0
310: **
311: ** Returns new element if OK NULL if error
312: */
313: PRIVATE host_info *HTTCPCacheAddElement ARGS2(HTAtom *, host,
314: struct hostent *, element)
315: {
316: int homes; /* Number of homes on the host */
317: host_info *new;
318: if (!host || !element) {
319: if (TRACE)
320: fprintf(stderr, "HostCache... Bad argument to add to cache\n");
321: return NULL;
322: }
323: if ((new = (host_info *) calloc(1, sizeof(host_info))) == NULL ||
324: (new->addrlist = (char **)
325: calloc(1, sizeof element->h_addr_list)) == NULL)
326: outofmem(__FILE__, "HTParseInet");
327: new->hostname = host;
328:
329: if ((homes = (sizeof element->h_addr_list) / element->h_length) > 1) {
330: new->multihomed = homes;
331: if ((new->weight = (float *) calloc(homes, sizeof(float))) == NULL)
332: outofmem(__FILE__, "HTTCPCacheAddElement");
333: }
334: new->addrlength = element->h_length;
335: memcpy((void *) new->addrlist, element->h_addr_list,
336: sizeof element->h_addr_list);
337: if (!hostcache)
338: hostcache = HTList_new();
339:
340: if (TRACE) {
341: if (new->multihomed)
342: fprintf(stderr, "HostCache... Adding multihomed host `%s' having %d homes\n", HTAtom_name(host), new->multihomed);
343: else
344: fprintf(stderr, "HostCache... Adding `%s'\n", HTAtom_name(host));
345: }
346: HTList_addObject(hostcache, (void *) new);
347: HTCacheSize++; /* Update number of elements */
348: return new;
349: }
350:
351:
352: /* HTTCPAddrWeights
353: **
354: ** This function calculates the weights of the different IP addresses
355: ** on a multi homed host. Each weight is calculated as
356: **
357: ** w(n+1) = w(n)*a + (1-a) * deltatime
358: ** a = exp(-1/Neff)
359: ** Neff is the effective number of samples used
360: ** deltatime is time spend on making a connection
361: **
362: ** A short window (low Neff) gives a high sensibility, but this is
363: ** required as we can't expect a lot of data to test on.
364: **
365: */
366: PUBLIC void HTTCPAddrWeights ARGS2(char *, host, time_t, deltatime)
367: {
368: HTAtom *hostatom = HTAtom_for(host);
369: HTList *cur = hostcache;
370: host_info *pres = NULL;
371: if (!hostcache) {
372: fprintf(stderr, "HostCache... Weights not calculated, no cache\n");
373: return;
374: }
375: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
376: if (pres->hostname == hostatom) {
377: break;
378: }
379: }
380: if (pres && pres->multihomed) {
381: int cnt;
2.14 ! frystyk 382: CONST float passive = 0.9; /* Factor for all passive IP_addrs */
2.13 frystyk 383: #if 0
2.14 ! frystyk 384: CONST int Neff = 3;
! 385: CONST float alpha = exp(-1.0/Neff);
2.13 frystyk 386: #else
2.14 ! frystyk 387: CONST float alpha = 0.716531310574;
2.13 frystyk 388: #endif
389: for (cnt=0; cnt<pres->multihomed; cnt++) {
390: if (cnt == pres->offset) {
391: *(pres->weight+pres->offset) = *(pres->weight+pres->offset)*alpha + (1.0-alpha)*deltatime;
392: } else {
393: *(pres->weight+cnt) = *(pres->weight+cnt) * passive;
394: }
395: }
396: } else if (TRACE) {
397: fprintf(stderr, "HostCache... Weights not calculated, host not found in cache or is not multihomed: `%s\'\n", host);
398: }
399: }
400:
401:
402: /* HTGetHostByName
403: **
404: ** Searched first the local cache then asks the DNS for an address of
405: ** the host specified.
406: **
407: ** Returns 0 if OK else -1
408: */
409: PUBLIC int HTGetHostByName ARGS3(char *, host, SockA *, sin, BOOL *, multi)
410: {
411: HTAtom *hostatom = HTAtom_for(host);
412: host_info *pres = NULL;
413: if (!hostcache)
414: hostcache = HTList_new(); /* First time through */
415: else {
416: HTList *cur = hostcache; /* Search cache */
417: while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
418: if (pres->hostname == hostatom) {
419: if (TRACE)
420: fprintf(stderr, "ParseInet... Host `%s\' found in cache.\n", host);
421: break;
422: }
423: }
424: }
425:
426: /* If the host was not found in the cache, then do gethostbyname.
427: If cache found then find the best address if more than one. If we
428: are talking to a multi homed host then take the IP address with the
429: lowest weight */
430: if (pres) {
431: if (pres->multihomed) {
432: int cnt;
433: float best_weight = 1e30; /* Should be FLT_MAX :-( */
434: for (cnt=0; cnt<pres->multihomed; cnt++) {
435: if (*(pres->weight+cnt) < best_weight) {
436: best_weight = *(pres->weight+cnt);
437: pres->offset = cnt;
438: }
439: }
440: *multi = YES;
441: } else
442: *multi = NO;
443: pres->hits++; /* Update number of hits */
444: } else { /* Go and ask for it */
445: struct hostent *hostelement; /* see netdb.h */
446: #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */
447: if (TRACE)
448: fprintf(stderr, "HTTCP: gethostbyname(%s)\n", host);
449: #endif
450: if ((hostelement = gethostbyname(host)) == NULL) {
451: if (TRACE) fprintf(stderr, "ParseInet... Can't find internet node name `%s'.\n", host);
452: return -1;
453: }
454:
455: /* Add element to the cache and maybe do garbage collection */
456: if (HTCacheSize >= HTConCacheSize)
457: HTTCPCacheGarbage();
458: if ((pres = HTTCPCacheAddElement(hostatom, hostelement)) == NULL) {
459: return -1;
460: }
461: }
462:
463: /* Update socket structure using the element with the lowest weight. On
464: single homed hosts it means the first value */
465: memcpy(&sin->sin_addr, *(pres->addrlist+pres->offset), pres->addrlength);
466: return 0;
467: }
468:
469:
1.1 timbl 470: /* Parse a network node address and port
471: ** -------------------------------------
472: **
473: ** On entry,
474: ** str points to a string with a node name or number,
475: ** with optional trailing colon and port number.
476: ** sin points to the binary internet or decnet address field.
477: **
478: ** On exit,
479: ** *sin is filled in. If no port is specified in str, that
480: ** field is left unchanged in *sin.
2.13 frystyk 481: **
482: ** NOTE: It is assumed that any portnumber and numeric host address
483: ** is given in decimal notation. Separation character is '.'
1.1 timbl 484: */
2.13 frystyk 485: PUBLIC int HTParseInet ARGS3(SockA *,sin, CONST char *,str, BOOL *, multihome)
1.1 timbl 486: {
2.13 frystyk 487: char *host = NULL;
488: StrAllocCopy(host, str); /* Take a copy we can mutilate */
1.1 timbl 489:
2.13 frystyk 490: /* Parse port number if present. */
491: *multihome = NO;
492: {
493: char *port;
494: if ((port=strchr(host, ':'))) {
495: *port++ = 0; /* Chop off port */
496: if (isdigit(*port)) {
1.1 timbl 497: #ifdef DECNET
2.13 frystyk 498: sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
499: #else /* Internet */
500: sin->sin_port = htons(atol(port));
1.1 timbl 501: #endif
2.13 frystyk 502: } else {
503: fprintf(stderr, "ParseInet... No port indicated\n");
504: }
1.1 timbl 505: }
2.13 frystyk 506: }
1.1 timbl 507:
2.13 frystyk 508: /* Parse Internet host */
1.1 timbl 509: #ifdef DECNET
510: /* read Decnet node name. @@ Should know about DECnet addresses, but it's
511: probably worth waiting until the Phase transition from IV to V. */
512:
513: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
514: strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
515:
516: if (TRACE) fprintf(stderr,
517: "DECnet: Parsed address as object number %d on host %.6s...\n",
518: sin->sdn_objnum, host);
519:
2.13 frystyk 520: #else /* Internet */
1.1 timbl 521:
2.13 frystyk 522: /* Parse host number if present */
523: {
524: BOOL numeric = YES;
525: char *strptr = host;
526: while (*strptr) {
527: if (!isdigit(*strptr) && *strptr != '.') {
528: numeric = NO;
529: break;
530: }
531: ++strptr;
532: }
533: if (numeric) {
534: sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
535: } else {
536: if (HTGetHostByName(host, sin, multihome)) {
537: free(host);
538: return -1;
539: }
540: }
541: if (TRACE) {
542: fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
543: (int) ntohs(sin->sin_port),
544: HTInetString(sin));
1.1 timbl 545: }
546: }
547: #endif /* Internet vs. Decnet */
2.13 frystyk 548: free(host);
1.1 timbl 549: return 0; /* OK */
550: }
551:
552:
2.8 luotonen 553: /*
554: ** Get host name of the machine on the other end of a socket.
2.13 frystyk 555: ** THIS SHOULD BE CALLED HTGetHostByAddr :-(
2.8 luotonen 556: */
557: PUBLIC char * HTGetHostName ARGS1(int, soc)
558: {
559: struct sockaddr addr;
560: int len = sizeof(struct sockaddr);
561: struct in_addr *iaddr;
562: struct hostent * phost; /* Pointer to host -- See netdb.h */
563: char *name = NULL;
564:
565: #ifdef DECNET /* Decnet ain't got no damn name server 8#OO */
566: return NULL;
567: #else
568: if (getpeername(soc, &addr, &len) < 0)
569: return NULL;
570:
571: iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
572: phost=gethostbyaddr((char*)iaddr,
573: sizeof(struct in_addr),
574: AF_INET);
575: if (!phost) {
576: if (TRACE) fprintf(stderr,
2.9 luotonen 577: "TCP......... Can't find internet node name for peer!!\n");
2.8 luotonen 578: return NULL;
579: }
580: StrAllocCopy(name, phost->h_name);
2.9 luotonen 581: if (TRACE) fprintf(stderr, "TCP......... Peer name is `%s'\n", name);
2.8 luotonen 582:
583: return name;
584:
585: #endif /* not DECNET */
586: }
587:
588:
1.1 timbl 589: /* Derive the name of the host on which we are
590: ** -------------------------------------------
591: **
592: */
2.8 luotonen 593: PRIVATE void get_host_details NOARGS
1.1 timbl 594:
595: #ifndef MAXHOSTNAMELEN
596: #define MAXHOSTNAMELEN 64 /* Arbitrary limit */
597: #endif
598:
599: {
600: char name[MAXHOSTNAMELEN+1]; /* The name of this host */
601: struct hostent * phost; /* Pointer to host -- See netdb.h */
602: int namelength = sizeof(name);
603:
604: if (hostname) return; /* Already done */
605: gethostname(name, namelength); /* Without domain */
2.9 luotonen 606: CTRACE(tfp, "TCP......... Local host name is %s\n", name);
1.1 timbl 607: StrAllocCopy(hostname, name);
608:
609: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
610: phost=gethostbyname(name); /* See netdb.h */
611: if (!phost) {
612: if (TRACE) fprintf(stderr,
2.9 luotonen 613: "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1 timbl 614: name);
615: return; /* Fail! */
616: }
617: StrAllocCopy(hostname, phost->h_name);
2.9 luotonen 618: CTRACE(tfp, "TCP......... Full local host name is %s\n", hostname);
2.8 luotonen 619:
620: #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1.1 timbl 621: memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
622: if (TRACE) fprintf(stderr, " Name server says that I am `%s' = %s\n",
623: hostname, HTInetString(&HTHostAddress));
2.8 luotonen 624: #endif /* NEED_HOST_ADDRESS */
1.1 timbl 625:
626: #endif /* not Decnet */
627: }
628:
2.12 luotonen 629:
630: PUBLIC CONST char * HTHostName NOARGS
1.1 timbl 631: {
632: get_host_details();
633: return hostname;
2.13 frystyk 634: }
635:
636:
637: /* HTDoConnect()
638: **
639: ** TEMPORARY FUNCTION.
640: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
641: ** the default_port value.
642: **
643: ** Returns 0 if OK, -1 on error
644: */
645: PUBLIC int HTDoConnect ARGS5(HTRequest *, request, char *, url,
646: u_short, default_port, int *, sockfd,
647: u_long *, addr)
648: {
649: BOOL multihomed = NO;
650: time_t deltatime;
651: int status;
652: SockA sock_addr; /* SockA is defined in tcp.h */
653: char *p1 = HTParse(url, "", PARSE_HOST);
654: char *at_sign;
655: char *host;
656:
657: /* if theres an @ then use the stuff after it as a hostname */
658: if((at_sign = strchr(p1,'@')) != NULL)
659: host = at_sign+1;
660: else
661: host = p1;
662: if (TRACE) fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
663:
664: /* Set up defaults */
665: memset((void *) &sock_addr, '\0', sizeof(sock_addr));
666: #ifdef DECNET
667: sock_addr.sdn_family = AF_DECnet; /* Family = DECnet, host order */
668: sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object number */
669: #else /* Internet */
670: sock_addr.sin_family = AF_INET;
671: sock_addr.sin_port = htons(default_port);
672: #endif
673:
674: /* Get node name */
675: if (HTParseInet(&sock_addr, host, &multihomed)) {
676: if (TRACE) fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
677: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
678: (void *) host, strlen(host), "HTDoConnect");
679: free (p1);
680: *sockfd = -1;
681: return -1;
682: }
683:
684: #ifdef DECNET
685: if ((*sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
686: #else
687: if ((*sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
688: #endif
689: HTErrorSysAdd(request, ERR_FATAL, NO, "socket");
690: free (p1);
691: return -1;
692: }
693: if (addr)
694: *addr = ntohl(sock_addr.sin_addr.s_addr);
695:
696: if (TRACE)
697: fprintf(stderr, "HTDoConnect. Created socket number %d\n", *sockfd);
698:
699: if (multihomed) /* Start timer on connection */
700: deltatime = time(NULL);
701: if ((status = connect(*sockfd, (struct sockaddr *) &sock_addr,
702: sizeof(sock_addr))) < 0) {
703: HTErrorSysAdd(request, ERR_FATAL, NO, "connect");
704: HTTCPCacheRemoveHost(host); /* Remove host from cache */
705: if (NETCLOSE(*sockfd) < 0)
706: HTErrorSysAdd(request, ERR_FATAL, NO, "close");
707: free(p1);
708: *sockfd = -1;
709: return -1;
710: }
711:
712: /* Measure time to make a connection and recalculate weights */
713: if (multihomed) {
714: deltatime = time(NULL) - deltatime;
715: HTTCPAddrWeights(host, deltatime);
716: }
717: free(p1);
718: return status;
719: }
720:
721:
722: /* HTDoAccept()
723: **
724: ** This function makes a non-blocking accept on a port and polls every
725: ** second until MAX_ACCEPT_POLL or interrupted by user.
726: **
727: ** BUGS Interrupted is not yet implemented!!!
728: **
729: ** Returns 0 if OK, -1 on error
730: */
731: PUBLIC int HTDoAccept ARGS2(HTRequest *, request, int, sockfd)
732: {
733: SockA soc_address; /* SockA is defined in tcp.h */
734: int status;
735: int cnt;
736: int soc_addrlen = sizeof(soc_address);
737: if (sockfd < 0) {
738: if (TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
739: return -1;
740: }
741:
742: /* First make the socket non-blocking */
743: if((status = FCNTL(sockfd, F_GETFL, 0)) != -1) {
744: status |= FNDELAY;
745: status = FCNTL(sockfd, F_SETFL, status);
746: }
747: if (status == -1) {
748: HTErrorSysAdd(request, ERR_FATAL, NO, "fcntl");
749: return -1;
750: }
751:
752: /* Now poll every sekund */
753: for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
754: if ((status = accept(sockfd, (struct sockaddr*) &soc_address,
755: &soc_addrlen)) >= 0) {
756: if (TRACE) fprintf(stderr,
757: "HTDoAccept.. Accepted new socket %d\n",
758: status);
759: return status;
760: } else
761: HTErrorSysAdd(request, ERR_WARNING, YES, "accept");
762: sleep(1);
763: }
764:
765: /* If nothing has happened */
766: if (TRACE)
767: fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
768: HTErrorAdd(request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0, "HTDoAccept");
769: return -1;
1.1 timbl 770: }
771:
Webmaster