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