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