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