Annotation of libwww/Library/src/HTTCP.c, revision 2.27
1.1 timbl 1: /* Generic Communication Code HTTCP.c
2: ** ==========================
3: **
4: ** This code is in common between client and server sides.
5: **
6: ** 16 Jan 92 TBL Fix strtol() undefined on CMU Mach.
7: ** 25 Jun 92 JFG Added DECNET option through TCP socket emulation.
2.7 duns 8: ** 13 Sep 93 MD Added correct return of vmserrorno for HTInetStatus.
9: ** Added decoding of vms error message for MULTINET.
2.13 frystyk 10: ** 31 May 94 HF Added cache on host id's; now use inet_ntoa() to
11: ** HTInetString and some other fixes. Added HTDoConnect
12: ** and HTDoAccept
1.1 timbl 13: */
14:
2.23 duns 15: #ifndef VMS
2.19 frystyk 16: #include <pwd.h>
2.23 duns 17: #endif /* not VMS */
18:
2.13 frystyk 19: #include "tcp.h" /* Defines SHORT_NAMES if necessary */
2.19 frystyk 20:
2.13 frystyk 21: #include "HTUtils.h"
22: #include "HTAtom.h"
23: #include "HTList.h"
24: #include "HTParse.h"
25: #include "HTAccess.h"
26: #include "HTError.h"
2.27 ! frystyk 27: #include "HTThread.h"
2.24 frystyk 28: #include "HTTCP.h" /* Implemented here */
1.1 timbl 29:
2.23 duns 30: #ifdef VMS
31: #include "HTVMSUtils.h"
32: #endif /* VMS */
33:
1.1 timbl 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.8 luotonen 41:
2.11 duns 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.18 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 */
82: float * weight; /* Weight on each address */
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: /* ------------------------------------------------------------------------- */
2.27 ! frystyk 91: /* TEMPORARY STUFF */
! 92: #define IOCTL ioctl
! 93: /* ------------------------------------------------------------------------- */
1.1 timbl 94:
95: /* Encode INET status (as in sys/errno.h) inet_status()
96: ** ------------------
97: **
98: ** On entry,
99: ** where gives a description of what caused the error
100: ** global errno gives the error number in the unix way.
101: **
102: ** On return,
103: ** returns a negative status in the unix way.
104: */
105: #ifndef PCNFS
2.7 duns 106: #ifdef VMS
2.10 duns 107: #ifndef __DECC
1.1 timbl 108: extern int uerrno; /* Deposit of error info (as per errno.h) */
2.7 duns 109: extern volatile noshare int socket_errno; /* socket VMS error info
110: (used for translation of vmserrno) */
1.1 timbl 111: extern volatile noshare int vmserrno; /* Deposit of VMS error info */
112: extern volatile noshare int errno; /* noshare to avoid PSECT conflict */
2.10 duns 113: #endif /* not DECC */
2.11 duns 114: #endif /* VMS */
115:
1.1 timbl 116: #ifndef errno
117: extern int errno;
118: #endif /* errno */
119:
120: #ifndef VM
2.7 duns 121: #ifndef VMS
1.1 timbl 122: #ifndef NeXT
123: #ifndef THINK_C
124: extern char *sys_errlist[]; /* see man perror on cernvax */
125: extern int sys_nerr;
126: #endif /* think c */
127: #endif /* NeXT */
2.7 duns 128: #endif /* VMS */
1.1 timbl 129: #endif /* VM */
130:
131: #endif /* PCNFS */
132:
2.12 luotonen 133:
134: /*
135: * Returns the string equivalent of the current errno.
136: */
137: PUBLIC CONST char * HTErrnoString NOARGS
1.1 timbl 138: {
2.11 duns 139: #ifndef VMS
2.7 duns 140:
1.1 timbl 141: #ifdef VM
2.12 luotonen 142: return "(Error number not translated)"; /* What Is the VM equiv? */
1.1 timbl 143: #define ER_NO_TRANS_DONE
144: #endif
2.12 luotonen 145:
146: #if defined(NeXT) || defined(THINK_C)
147: return strerror(errno);
1.1 timbl 148: #define ER_NO_TRANS_DONE
149: #endif
2.12 luotonen 150:
151: #ifndef ER_NO_TRANS_DONE
152: return (errno < sys_nerr ? sys_errlist[errno] : "Unknown error");
1.1 timbl 153: #endif
154:
2.12 luotonen 155: #else /* VMS */
156:
157: static char buf[60];
158: sprintf(buf,"Unix errno = %ld dec, VMS error = %lx hex",errno,vaxc$errno);
159: return buf;
160:
1.1 timbl 161: #endif
2.12 luotonen 162: }
163:
164:
165: /* Report Internet Error
166: ** ---------------------
167: */
168: PUBLIC int HTInetStatus ARGS1(char *, where)
169: {
170: #ifndef VMS
171:
2.27 ! frystyk 172: if (PROT_TRACE)
! 173: fprintf(stderr, "TCP errno... %d after call to %s() failed.\n............ %s\n", errno, where, HTErrnoString());
1.1 timbl 174:
2.11 duns 175: #else /* VMS */
2.12 luotonen 176:
2.27 ! frystyk 177: if (PROT_TRACE) fprintf(stderr, " Unix error number = %ld dec\n", errno);
! 178: if (PROT_TRACE) fprintf(stderr, " VMS error = %lx hex\n", vaxc$errno);
2.12 luotonen 179:
2.11 duns 180: #ifdef MULTINET
2.27 ! frystyk 181: if (PROT_TRACE) fprintf(stderr, " Multinet error = %lx hex\n", socket_errno);
! 182: if (PROT_TRACE) fprintf(stderr, " Error String = %s\n", vms_errno_string());
2.11 duns 183: #endif /* MULTINET */
2.12 luotonen 184:
2.11 duns 185: #endif /* VMS */
2.7 duns 186:
187: #ifdef VMS
2.11 duns 188: /* errno happen to be zero if vaxc$errno <> 0 */
189: return -vaxc$errno;
2.7 duns 190: #else
1.1 timbl 191: return -errno;
2.7 duns 192: #endif
1.1 timbl 193: }
194:
195:
196: /* Parse a cardinal value parse_cardinal()
197: ** ----------------------
198: **
199: ** On entry,
200: ** *pp points to first character to be interpreted, terminated by
201: ** non 0:9 character.
202: ** *pstatus points to status already valid
203: ** maxvalue gives the largest allowable value.
204: **
205: ** On exit,
206: ** *pp points to first unread character
207: ** *pstatus points to status updated iff bad
208: */
209:
210: PUBLIC unsigned int HTCardinal ARGS3
211: (int *, pstatus,
212: char **, pp,
213: unsigned int, max_value)
214: {
215: int n;
216: if ( (**pp<'0') || (**pp>'9')) { /* Null string is error */
217: *pstatus = -3; /* No number where one expeceted */
218: return 0;
219: }
220:
221: n=0;
222: while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
223:
224: if (n>max_value) {
225: *pstatus = -4; /* Cardinal outside range */
226: return 0;
227: }
228:
229: return n;
230: }
231:
2.19 frystyk 232: /* ------------------------------------------------------------------------- */
2.27 ! frystyk 233: /* SIGNAL HANDLING */
! 234: /* ------------------------------------------------------------------------- */
! 235:
! 236: #ifdef WWWLIB_SIG
! 237: /* HTSetSignal
! 238: ** This function sets up signal handlers. This might not be necessary to
! 239: ** call if the application has its own handlers.
! 240: */
! 241: #include <signal.h>
! 242: PUBLIC void HTSetSignal NOARGS
! 243: {
! 244: /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
! 245: ** when attemting to connect to a remote host where you normally should
! 246: ** get `connection refused' back
! 247: */
! 248: if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
! 249: if (PROT_TRACE) fprintf(stderr, "HTSignal.... Can't catch SIGPIPE\n");
! 250: } else {
! 251: if (PROT_TRACE) fprintf(stderr, "HTSignal.... Ignoring SIGPIPE\n");
! 252: }
! 253: }
! 254: #endif /* WWWLIB_SIG */
! 255:
! 256: /* ------------------------------------------------------------------------- */
2.19 frystyk 257: /* HOST CACHE MANAGEMENT */
258: /* ------------------------------------------------------------------------- */
1.1 timbl 259:
2.27 ! frystyk 260: /* HTTCPCacheRemoveElement
2.13 frystyk 261: **
262: ** Remove the element specified from the cache
263: */
264: PRIVATE void HTTCPCacheRemoveElement ARGS1(host_info *, element)
265: {
266: if (!hostcache) {
2.27 ! frystyk 267: if (PROT_TRACE)
2.13 frystyk 268: fprintf(stderr, "HostCache... Remove not done, no cache\n");
269: return;
270: }
2.27 ! frystyk 271: if (PROT_TRACE) fprintf(stderr, "HostCache... Remove `%s' from cache\n",
! 272: HTAtom_name(element->hostname));
! 273: HTList_removeObject(hostcache, (void *) element);
2.22 frystyk 274: if (*element->addrlist)
275: free(*element->addrlist);
2.13 frystyk 276: if (element->addrlist)
277: free(element->addrlist);
278: if (element->weight)
279: free(element->weight);
280: free(element);
281: }
282:
283:
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: if (TRACE) fprintf(stderr, "TESTTESTTEST `%s\'\n", host);
! 623:
1.1 timbl 624: #ifdef DECNET
2.13 frystyk 625: sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
626: #else /* Internet */
627: sin->sin_port = htons(atol(port));
1.1 timbl 628: #endif
2.13 frystyk 629: } else {
2.24 frystyk 630: if (PROT_TRACE)
631: fprintf(stderr, "ParseInet... No port indicated\n");
632: free(host);
633: return -1;
2.13 frystyk 634: }
1.1 timbl 635: }
2.13 frystyk 636: }
1.1 timbl 637:
2.13 frystyk 638: /* Parse Internet host */
1.1 timbl 639: #ifdef DECNET
640: /* read Decnet node name. @@ Should know about DECnet addresses, but it's
641: probably worth waiting until the Phase transition from IV to V. */
642:
643: sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */
644: strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
645:
2.27 ! frystyk 646: if (PROT_TRACE) fprintf(stderr,
1.1 timbl 647: "DECnet: Parsed address as object number %d on host %.6s...\n",
648: sin->sdn_objnum, host);
649:
2.13 frystyk 650: #else /* Internet */
1.1 timbl 651:
2.13 frystyk 652: /* Parse host number if present */
653: {
654: BOOL numeric = YES;
655: char *strptr = host;
656: while (*strptr) {
657: if (!isdigit(*strptr) && *strptr != '.') {
658: numeric = NO;
659: break;
660: }
661: ++strptr;
662: }
663: if (numeric) {
664: sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
665: } else {
2.24 frystyk 666: if ((status = HTGetHostByName(host, sin, use_cur)) < 0) {
2.13 frystyk 667: free(host);
668: return -1;
669: }
670: }
2.27 ! frystyk 671: if (PROT_TRACE) {
2.13 frystyk 672: fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
673: (int) ntohs(sin->sin_port),
674: HTInetString(sin));
1.1 timbl 675: }
676: }
677: #endif /* Internet vs. Decnet */
2.13 frystyk 678: free(host);
2.24 frystyk 679: return status;
1.1 timbl 680: }
681:
682:
2.16 frystyk 683: #ifdef OLD_CODE
1.1 timbl 684: /* Derive the name of the host on which we are
685: ** -------------------------------------------
686: **
687: */
2.8 luotonen 688: PRIVATE void get_host_details NOARGS
1.1 timbl 689:
690: #ifndef MAXHOSTNAMELEN
691: #define MAXHOSTNAMELEN 64 /* Arbitrary limit */
692: #endif
693:
694: {
695: char name[MAXHOSTNAMELEN+1]; /* The name of this host */
696: struct hostent * phost; /* Pointer to host -- See netdb.h */
697: int namelength = sizeof(name);
698:
699: if (hostname) return; /* Already done */
700: gethostname(name, namelength); /* Without domain */
2.27 ! frystyk 701: if (PROT_TRACE) fprintf(stderr, "TCP......... Local host name is %s\n", name);
1.1 timbl 702: StrAllocCopy(hostname, name);
703:
704: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
705: phost=gethostbyname(name); /* See netdb.h */
706: if (!phost) {
2.27 ! frystyk 707: if (PROT_TRACE) fprintf(stderr,
2.9 luotonen 708: "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1 timbl 709: name);
710: return; /* Fail! */
711: }
712: StrAllocCopy(hostname, phost->h_name);
2.27 ! frystyk 713: if (PROT_TRACE)
2.18 frystyk 714: fprintf(stderr, "TCP......... Full local host name is %s\n", hostname);
2.8 luotonen 715:
716: #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
1.1 timbl 717: memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
2.27 ! frystyk 718: if (PROT_TRACE) fprintf(stderr, " Name server says that I am `%s' = %s\n",
1.1 timbl 719: hostname, HTInetString(&HTHostAddress));
2.8 luotonen 720: #endif /* NEED_HOST_ADDRESS */
1.1 timbl 721:
722: #endif /* not Decnet */
723: }
2.16 frystyk 724: #endif /* OLD_CODE */
1.1 timbl 725:
2.19 frystyk 726:
2.24 frystyk 727: /* HTGetDomainName
728: ** Returns the current domain name without the local host name.
729: ** The response is pointing to a static area that might be changed
730: ** using HTSetHostName(). Returns NULL on error
731: */
732: PUBLIC CONST char *HTGetDomainName NOARGS
733: {
734: CONST char *host = HTGetHostName();
735: char *domain;
736: if (host && *host) {
737: if ((domain = strchr(host, '.')) != NULL)
738: return ++domain;
739: else
740: return host;
741: } else
742: return NULL;
743: }
744:
745:
746:
2.19 frystyk 747: /* HTSetHostName
748: ** Sets the current hostname inclusive domain name.
749: ** If this is not set then the default approach is used using
750: ** HTGetHostname().
751: */
752: PUBLIC void HTSetHostName ARGS1(char *, host)
753: {
2.24 frystyk 754: if (host && *host) {
755: char *strptr;
2.19 frystyk 756: StrAllocCopy(hostname, host);
2.24 frystyk 757: strptr = hostname;
758: while (*strptr) {
759: *strptr = TOLOWER(*strptr);
760: strptr++;
761: }
762: if (*(hostname+strlen(hostname)-1) == '.') /* Remove trailing dot */
763: *(hostname+strlen(hostname)-1) = '\0';
764: } else {
2.27 ! frystyk 765: if (PROT_TRACE) fprintf(stderr, "SetHostName. Bad argument ignored\n");
2.19 frystyk 766: }
767: }
768:
769:
770: /* HTGetHostName
2.18 frystyk 771: ** Returns the name of this host. It uses the following algoritm:
772: **
773: ** 1) gethostname()
774: ** 2) if the hostname doesn't contain any '.' try to read
775: ** /etc/resolv.conf. If there is no domain line in this file then
776: ** 3) Try getdomainname and do as the man pages say for resolv.conf (sun)
777: ** If there is no domain line in this file, then it is derived
778: ** from the domain name set by the domainname(1) command, usually
779: ** by removing the first component. For example, if the domain-
780: ** name is set to ``foo.podunk.edu'' then the default domain name
781: ** used will be ``pudunk.edu''.
782: **
783: ** This is the same procedure as used by res_init() and sendmail.
2.16 frystyk 784: **
785: ** Return: hostname on success else NULL
786: */
2.19 frystyk 787: PUBLIC CONST char * HTGetHostName NOARGS
1.1 timbl 788: {
2.18 frystyk 789: BOOL got_it = NO;
790: FILE *fp;
2.16 frystyk 791: char name[MAXHOSTNAMELEN+1];
2.18 frystyk 792: if (hostname) { /* If already done */
793: if (*hostname)
794: return hostname;
795: else
796: return NULL; /* We couldn't get the last time */
797: }
2.16 frystyk 798: *(name+MAXHOSTNAMELEN) = '\0';
799: if (gethostname(name, MAXHOSTNAMELEN)) { /* Maybe without domain */
2.27 ! frystyk 800: if (PROT_TRACE)
2.16 frystyk 801: fprintf(stderr, "HostName.... Can't get host name\n");
802: return NULL;
803: }
2.27 ! frystyk 804: if (PROT_TRACE)
2.24 frystyk 805: fprintf(stderr, "HostName.... Local host name is `%s\'\n", name);
2.16 frystyk 806: StrAllocCopy(hostname, name);
2.24 frystyk 807: {
808: char *strptr = strchr(hostname, '.');
809: if (strptr != NULL) /* We have it all */
810: got_it = YES;
811: }
2.16 frystyk 812:
2.23 duns 813: #ifndef VMS
2.18 frystyk 814: /* Now try the resolver config file */
2.24 frystyk 815: if (!got_it && (fp = fopen(RESOLV_CONF, "r")) != NULL) {
2.18 frystyk 816: char buffer[80];
817: *(buffer+79) = '\0';
818: while (fgets(buffer, 79, fp)) {
819: if (!strncasecomp(buffer, "domain", 6)) {
820: char *domainstr = buffer+6;
821: char *end;
822: while (*domainstr == ' ' || *domainstr == '\t')
823: domainstr++;
824: end = domainstr;
825: while (*end && !isspace(*end))
826: end++;
827: *end = '\0';
828: if (*domainstr) {
829: StrAllocCat(hostname, ".");
830: StrAllocCat(hostname, domainstr);
831: got_it = YES;
832: break;
833: }
834: }
835: }
836: fclose(fp);
2.16 frystyk 837: }
838:
2.18 frystyk 839: /* If everything else has failed then try getdomainname */
2.26 frystyk 840: #ifndef sco
2.18 frystyk 841: if (!got_it) {
842: if (getdomainname(name, MAXHOSTNAMELEN)) {
2.27 ! frystyk 843: if (PROT_TRACE)
2.18 frystyk 844: fprintf(stderr, "HostName.... Can't get domain name\n");
2.24 frystyk 845: StrAllocCopy(hostname, "");
2.18 frystyk 846: return NULL;
847: }
848:
849: /* If the host name and the first part of the domain name are different
850: then use the former as it is more exact (I guess) */
851: if (strncmp(name, hostname, (int) strlen(hostname))) {
852: char *domain = strchr(name, '.');
853: if (!domain)
854: domain = name;
2.26 frystyk 855: StrAllocCat(hostname, ".");
2.18 frystyk 856: StrAllocCat(hostname, domain);
857: }
2.16 frystyk 858: }
2.26 frystyk 859: #endif /* not sco */
2.23 duns 860: #endif /* not VMS */
861:
2.24 frystyk 862: {
863: char *strptr = hostname;
864: while (*strptr) {
865: *strptr = TOLOWER(*strptr);
866: strptr++;
867: }
868: if (*(hostname+strlen(hostname)-1) == '.') /* Remove trailing dot */
869: *(hostname+strlen(hostname)-1) = '\0';
870: }
2.27 ! frystyk 871: if (PROT_TRACE)
2.24 frystyk 872: fprintf(stderr, "HostName.... Full host name is `%s\'\n", hostname);
2.18 frystyk 873: return hostname;
874:
875: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
876: #ifdef OLD_CODE
877: /* Now we try to get information on the domain */
2.16 frystyk 878: {
879: struct hostent *hostelement;
880: if ((hostelement = gethostbyname(hostname)) == NULL) {
2.27 ! frystyk 881: if (PROT_TRACE)
2.16 frystyk 882: fprintf(stderr, "HostName.... Can't find host name on DNS\n");
883: FREE(hostname);
884: return NULL;
885: }
2.17 frystyk 886: StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16 frystyk 887: }
2.18 frystyk 888: #endif /* OLD_CODE */
2.16 frystyk 889: #endif /* not Decnet */
2.13 frystyk 890: }
891:
2.19 frystyk 892:
893: /* HTSetMailAddress
894: ** Sets the current mail address plus host name and domain name.
895: ** If this is not set then the default approach is used using
2.27 ! frystyk 896: ** HTGetMailAddress(). If the argument is NULL or "" then HTGetMailAddress
! 897: ** returns NULL on a succeding request.
2.19 frystyk 898: */
899: PUBLIC void HTSetMailAddress ARGS1(char *, address)
900: {
2.27 ! frystyk 901: if (!address || !*address)
! 902: StrAllocCopy(mailaddress, "");
! 903: else
2.19 frystyk 904: StrAllocCopy(mailaddress, address);
2.27 ! frystyk 905: if (TRACE)
! 906: fprintf(stderr, "SetMailAdr.. Set mail address to `%s\'\n",
! 907: mailaddress);
2.19 frystyk 908: }
909:
910:
911: /* HTGetMailAddress
912: **
913: ** Get the mail address of the current user on the current host. The
914: ** domain name used is the one initialized in HTSetHostName or
915: ** HTGetHostName. The login name is determined using (ordered):
916: **
917: ** getlogin
918: ** getpwuid(getuid())
919: **
920: ** The weakness about the last attempt is if the user has multiple
921: ** login names each with the same user ID. If this fails as well then:
922: **
923: ** LOGNAME environment variable
924: ** USER environment variable
925: **
926: ** Returns NULL if error else pointer to static string
927: */
928: PUBLIC CONST char * HTGetMailAddress NOARGS
929: {
930: char *login;
931: CONST char *domain;
932: struct passwd *pw_info;
2.21 frystyk 933: if (mailaddress) {
934: if (*mailaddress)
935: return mailaddress;
936: else
937: return NULL; /* No luck the last time so we wont try again */
938: }
2.23 duns 939:
940: #ifdef VMS
941: if ((login = (char *) cuserid(NULL)) == NULL) {
2.27 ! frystyk 942: if (PROT_TRACE) fprintf(stderr, "MailAddress. cuserid returns NULL\n");
2.23 duns 943: }
944:
945: #else /* not VMS */
2.19 frystyk 946: if ((login = (char *) getlogin()) == NULL) {
2.27 ! frystyk 947: if (PROT_TRACE)
! 948: fprintf(stderr, "MailAddress. getlogin returns NULL\n");
2.19 frystyk 949: if ((pw_info = getpwuid(getuid())) == NULL) {
2.27 ! frystyk 950: if (PROT_TRACE)
! 951: fprintf(stderr, "MailAddress. getpwid returns NULL\n");
2.19 frystyk 952: if ((login = getenv("LOGNAME")) == NULL) {
2.27 ! frystyk 953: if (PROT_TRACE)
! 954: fprintf(stderr, "MailAddress. LOGNAME not found\n");
2.19 frystyk 955: if ((login = getenv("USER")) == NULL) {
2.27 ! frystyk 956: if (PROT_TRACE)
! 957: fprintf(stderr,"MailAddress. USER not found\n");
2.19 frystyk 958: return NULL; /* I GIVE UP */
959: }
960: }
961: } else
962: login = pw_info->pw_name;
963: }
2.23 duns 964: #endif /* not VMS */
965:
2.19 frystyk 966: if (login) {
967: StrAllocCopy(mailaddress, login);
968: StrAllocCat(mailaddress, "@");
969: if ((domain = HTGetHostName()) != NULL)
970: StrAllocCat(mailaddress, domain);
2.21 frystyk 971: else {
972: *mailaddress = '\0';
973: return NULL; /* Domain name not available */
974: }
2.19 frystyk 975: return mailaddress;
976: }
977: return NULL;
978: }
979:
980: /* ------------------------------------------------------------------------- */
981: /* CONNECTION ESTABLISHMENT MANAGEMENT */
982: /* ------------------------------------------------------------------------- */
2.13 frystyk 983:
984: /* HTDoConnect()
985: **
986: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
987: ** the default_port value.
988: **
989: ** Returns 0 if OK, -1 on error
990: */
2.24 frystyk 991: PUBLIC int HTDoConnect ARGS5(HTNetInfo *, net, char *, url,
992: u_short, default_port, u_long *, addr,
993: BOOL, use_cur)
2.13 frystyk 994: {
995: int status;
996: char *p1 = HTParse(url, "", PARSE_HOST);
997: char *at_sign;
998: char *host;
999:
1000: /* if theres an @ then use the stuff after it as a hostname */
2.27 ! frystyk 1001: if((at_sign = strchr(p1, '@')) != NULL)
2.13 frystyk 1002: host = at_sign+1;
1003: else
1004: host = p1;
2.24 frystyk 1005: if (!*host) {
1006: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_HOST,
1007: NULL, 0, "HTDoConnect");
1008: free(p1);
1009: return -1;
2.27 ! frystyk 1010: } else {
! 1011: if (PROT_TRACE)
! 1012: fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
! 1013: }
2.13 frystyk 1014:
1015: /* Set up defaults */
2.27 ! frystyk 1016: if (net->sockfd < 0) {
! 1017: memset((void *) &net->sock_addr, '\0', sizeof(net->sock_addr));
2.13 frystyk 1018: #ifdef DECNET
2.27 ! frystyk 1019: net->sock_addr.sdn_family = AF_DECnet;/* Family = DECnet, host order */
! 1020: net->sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object number */
2.13 frystyk 1021: #else /* Internet */
2.27 ! frystyk 1022: net->sock_addr.sin_family = AF_INET;
! 1023: net->sock_addr.sin_port = htons(default_port);
2.13 frystyk 1024: #endif
2.27 ! frystyk 1025: }
2.13 frystyk 1026:
2.24 frystyk 1027: /* If we are trying to connect to a multi-homed host then loop here until
1028: success or we have tried all IP-addresses */
1029: do {
2.27 ! frystyk 1030: if (net->sockfd < 0) {
! 1031: int hosts;
! 1032: if ((hosts = HTParseInet(&net->sock_addr, host, use_cur)) < 0) {
! 1033: if (PROT_TRACE)
! 1034: fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
! 1035: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
! 1036: (void *) host, strlen(host), "HTDoConnect");
! 1037: break;
! 1038: };
! 1039: if (!net->addressCount && hosts > 1)
! 1040: net->addressCount = hosts;
! 1041: #ifdef DECNET
! 1042: if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0)
! 1043: #else
! 1044: if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
! 1045: #endif
! 1046: {
! 1047: HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
! 1048: break;
! 1049: }
! 1050: if (addr)
! 1051: *addr = ntohl(net->sock_addr.sin_addr.s_addr);
! 1052: if (PROT_TRACE)
! 1053: fprintf(stderr, "HTDoConnect. Created socket number %d\n",
! 1054: net->sockfd);
! 1055:
! 1056: /* If non-blocking protocol then change socket status */
! 1057: /* I use FCNTL so that I can ask the status before I set it */
! 1058: if (!HTProtocolBlocking(net->request)) {
! 1059: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
! 1060: status |= FNDELAY;
! 1061: status = FCNTL(net->sockfd, F_SETFL, status);
! 1062: }
! 1063: if (status == -1) {
! 1064: if (PROT_TRACE)
! 1065: fprintf(stderr, "HTDoConnect. Can NOT make socket non-blocking\n");
! 1066: }
! 1067: }
! 1068:
! 1069: /* If multi-homed host then start timer on connection */
! 1070: if (net->addressCount >= 1)
! 1071: net->connecttime = time(NULL);
2.24 frystyk 1072: }
2.13 frystyk 1073:
2.27 ! frystyk 1074: /* Check for interrupt */
! 1075: if (HTThreadIntr(net->sockfd)) {
! 1076: if (NETCLOSE(net->sockfd) < 0)
! 1077: HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
! 1078: HTThreadState(net->sockfd, THD_CLOSE);
! 1079: net->sockfd = -1;
! 1080: free(p1);
! 1081: return HT_INTERRUPTED;
! 1082: }
! 1083:
! 1084: /* Do a connect */
! 1085: status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr,
! 1086: sizeof(net->sock_addr));
! 1087: /*
! 1088: * According to the Sun man page for connect:
! 1089: * EINPROGRESS The socket is non-blocking and the con-
! 1090: * nection cannot be completed immediately.
! 1091: * It is possible to select(2) for comple-
! 1092: * tion by selecting the socket for writ-
! 1093: * ing.
! 1094: * According to the Motorola SVR4 man page for connect:
! 1095: * EAGAIN The socket is non-blocking and the con-
! 1096: * nection cannot be completed immediately.
! 1097: * It is possible to select for completion
! 1098: * by selecting the socket for writing.
! 1099: * However, this is only possible if the
! 1100: * socket STREAMS module is the topmost
! 1101: * module on the protocol stack with a
! 1102: * write service procedure. This will be
! 1103: * the normal case.
! 1104: */
! 1105: #ifdef EAGAIN
! 1106: if ((status < 0) && ((errno == EINPROGRESS) || (errno == EAGAIN)))
2.13 frystyk 1107: #else
2.27 ! frystyk 1108: if ((status < 0) && (errno == EINPROGRESS))
! 1109: #endif /* EAGAIN */
2.24 frystyk 1110: {
2.27 ! frystyk 1111: if (PROT_TRACE)
! 1112: fprintf(stderr, "HTDoConnect. WOULD BLOCK `%s'\n", host);
! 1113: HTThreadState(net->sockfd, THD_SET_WRITE);
! 1114: free(p1);
! 1115: return HT_WOULD_BLOCK;
2.24 frystyk 1116: }
2.27 ! frystyk 1117: if (net->addressCount >= 1) {
! 1118: net->connecttime = time(NULL) - net->connecttime;
2.24 frystyk 1119: if (status < 0) {
2.27 ! frystyk 1120: if (errno == EISCONN) { /* connect multi after would block */
! 1121: HTThreadState(net->sockfd, THD_CLR_WRITE);
! 1122: HTTCPAddrWeights(host, net->connecttime);
! 1123: free(p1);
! 1124: net->addressCount = 0;
! 1125: return 0;
! 1126: }
2.24 frystyk 1127: HTErrorSysAdd(net->request, ERR_NON_FATAL, NO, "connect");
2.27 ! frystyk 1128:
! 1129: /* I have added EINVAL `invalid argument' as this is what I
! 1130: get back from a non-blocking connect where I should
! 1131: get `connection refused' */
2.24 frystyk 1132: if (errno==ECONNREFUSED || errno==ETIMEDOUT ||
1133: errno==ENETUNREACH || errno==EHOSTUNREACH ||
2.27 ! frystyk 1134: errno==EHOSTDOWN || errno==EINVAL)
! 1135: net->connecttime += TCP_DELAY;
2.24 frystyk 1136: else
2.27 ! frystyk 1137: net->connecttime += TCP_PENALTY;
2.24 frystyk 1138: if (NETCLOSE(net->sockfd) < 0)
2.27 ! frystyk 1139: HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
! 1140: HTThreadState(net->sockfd, THD_CLOSE);
! 1141: net->sockfd = -1;
! 1142: HTTCPAddrWeights(host, net->connecttime);
! 1143: } else { /* Connect on multi-homed */
! 1144: HTTCPAddrWeights(host, net->connecttime);
! 1145: free(p1);
! 1146: net->addressCount = 0;
! 1147: return 0;
! 1148: }
! 1149: } else if (status < 0) {
! 1150: if (errno == EISCONN) { /* Connect single after would block */
! 1151: HTThreadState(net->sockfd, THD_CLR_WRITE);
! 1152: net->addressCount = 0;
! 1153: free(p1);
! 1154: return 0;
2.24 frystyk 1155: } else {
2.27 ! frystyk 1156: HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
! 1157: HTTCPCacheRemoveHost(host);
! 1158: if (NETCLOSE(net->sockfd) < 0)
! 1159: HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
! 1160: HTThreadState(net->sockfd, THD_CLOSE);
2.24 frystyk 1161: break;
1162: }
2.27 ! frystyk 1163: } else { /* Connect on single homed */
! 1164: free(p1);
! 1165: net->addressCount = 0;
! 1166: return 0;
2.24 frystyk 1167: }
2.27 ! frystyk 1168: } while (--net->addressCount);
2.13 frystyk 1169:
2.27 ! frystyk 1170: if (PROT_TRACE)
! 1171: fprintf(stderr, "HTDoConnect. Connect failed\n");
2.24 frystyk 1172: free (p1);
1173: net->addressCount = 0;
1174: net->sockfd = -1;
1175: return -1;
2.13 frystyk 1176: }
1177:
1178:
1179: /* HTDoAccept()
1180: **
1181: ** This function makes a non-blocking accept on a port and polls every
1182: ** second until MAX_ACCEPT_POLL or interrupted by user.
1183: **
1184: ** BUGS Interrupted is not yet implemented!!!
1185: **
2.27 ! frystyk 1186: ** Returns HT_WOULD_BLOCK if waiting
! 1187: ** 0 if OK,
! 1188: ** -1 on error
2.13 frystyk 1189: */
2.15 frystyk 1190: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13 frystyk 1191: {
1192: SockA soc_address; /* SockA is defined in tcp.h */
1193: int status;
1194: int cnt;
1195: int soc_addrlen = sizeof(soc_address);
2.15 frystyk 1196: if (net->sockfd < 0) {
2.27 ! frystyk 1197: if (PROT_TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
2.13 frystyk 1198: return -1;
1199: }
2.27 ! frystyk 1200:
2.13 frystyk 1201: /* First make the socket non-blocking */
2.23 duns 1202: #ifdef VMS
1203: #ifdef MULTINET
1204: {
1205: int enable = 1;
1206: status = socket_ioctl(net->sockfd, FIONBIO, &enable);
1207: }
1208: #endif /* MULTINET */
1209: #else /* not VMS */
2.15 frystyk 1210: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.23 duns 1211: status |= FNDELAY; /* O_NDELAY; */
2.15 frystyk 1212: status = FCNTL(net->sockfd, F_SETFL, status);
2.13 frystyk 1213: }
2.23 duns 1214: #endif /* not VMS */
2.13 frystyk 1215: if (status == -1) {
2.15 frystyk 1216: HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13 frystyk 1217: return -1;
1218: }
1219:
1220: /* Now poll every sekund */
1221: for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15 frystyk 1222: if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13 frystyk 1223: &soc_addrlen)) >= 0) {
2.27 ! frystyk 1224: if (PROT_TRACE) fprintf(stderr,
2.13 frystyk 1225: "HTDoAccept.. Accepted new socket %d\n",
1226: status);
1227: return status;
1228: } else
2.15 frystyk 1229: HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13 frystyk 1230: sleep(1);
1231: }
1232:
1233: /* If nothing has happened */
2.27 ! frystyk 1234: if (PROT_TRACE)
2.13 frystyk 1235: fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15 frystyk 1236: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
1237: "HTDoAccept");
2.13 frystyk 1238: return -1;
1.1 timbl 1239: }
2.27 ! frystyk 1240:
1.1 timbl 1241:
Webmaster