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