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