Annotation of libwww/Library/src/HTTCP.c, revision 2.33.2.1
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, '.');
880: if (!domain)
881: domain = name;
2.26 frystyk 882: StrAllocCat(hostname, ".");
2.18 frystyk 883: StrAllocCat(hostname, domain);
884: }
2.16 frystyk 885: }
2.26 frystyk 886: #endif /* not sco */
2.23 duns 887: #endif /* not VMS */
888:
2.24 frystyk 889: {
890: char *strptr = hostname;
891: while (*strptr) {
892: *strptr = TOLOWER(*strptr);
893: strptr++;
894: }
895: if (*(hostname+strlen(hostname)-1) == '.') /* Remove trailing dot */
896: *(hostname+strlen(hostname)-1) = '\0';
897: }
2.27 frystyk 898: if (PROT_TRACE)
2.24 frystyk 899: fprintf(stderr, "HostName.... Full host name is `%s\'\n", hostname);
2.18 frystyk 900: return hostname;
901:
902: #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */
903: #ifdef OLD_CODE
904: /* Now we try to get information on the domain */
2.16 frystyk 905: {
906: struct hostent *hostelement;
907: if ((hostelement = gethostbyname(hostname)) == NULL) {
2.27 frystyk 908: if (PROT_TRACE)
2.16 frystyk 909: fprintf(stderr, "HostName.... Can't find host name on DNS\n");
910: FREE(hostname);
911: return NULL;
912: }
2.17 frystyk 913: StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16 frystyk 914: }
2.18 frystyk 915: #endif /* OLD_CODE */
2.16 frystyk 916: #endif /* not Decnet */
2.13 frystyk 917: }
918:
2.19 frystyk 919:
2.32 frystyk 920: /*
921: ** Free the host name. Called from HTLibTerminate
922: */
923: PUBLIC void HTFreeHostName NOARGS
924: {
925: FREE(hostname);
926: }
927:
928:
2.19 frystyk 929: /* HTSetMailAddress
930: ** Sets the current mail address plus host name and domain name.
931: ** If this is not set then the default approach is used using
2.27 frystyk 932: ** HTGetMailAddress(). If the argument is NULL or "" then HTGetMailAddress
933: ** returns NULL on a succeding request.
2.19 frystyk 934: */
935: PUBLIC void HTSetMailAddress ARGS1(char *, address)
936: {
2.27 frystyk 937: if (!address || !*address)
938: StrAllocCopy(mailaddress, "");
939: else
2.19 frystyk 940: StrAllocCopy(mailaddress, address);
2.27 frystyk 941: if (TRACE)
942: fprintf(stderr, "SetMailAdr.. Set mail address to `%s\'\n",
943: mailaddress);
2.19 frystyk 944: }
945:
946:
947: /* HTGetMailAddress
948: **
949: ** Get the mail address of the current user on the current host. The
950: ** domain name used is the one initialized in HTSetHostName or
951: ** HTGetHostName. The login name is determined using (ordered):
952: **
953: ** getlogin
954: ** getpwuid(getuid())
955: **
956: ** The weakness about the last attempt is if the user has multiple
957: ** login names each with the same user ID. If this fails as well then:
958: **
959: ** LOGNAME environment variable
960: ** USER environment variable
961: **
962: ** Returns NULL if error else pointer to static string
963: */
964: PUBLIC CONST char * HTGetMailAddress NOARGS
965: {
966: char *login;
967: CONST char *domain;
968: struct passwd *pw_info;
2.21 frystyk 969: if (mailaddress) {
970: if (*mailaddress)
971: return mailaddress;
972: else
973: return NULL; /* No luck the last time so we wont try again */
974: }
2.23 duns 975:
976: #ifdef VMS
977: if ((login = (char *) cuserid(NULL)) == NULL) {
2.27 frystyk 978: if (PROT_TRACE) fprintf(stderr, "MailAddress. cuserid returns NULL\n");
2.23 duns 979: }
980:
981: #else /* not VMS */
2.19 frystyk 982: if ((login = (char *) getlogin()) == NULL) {
2.27 frystyk 983: if (PROT_TRACE)
984: fprintf(stderr, "MailAddress. getlogin returns NULL\n");
2.19 frystyk 985: if ((pw_info = getpwuid(getuid())) == NULL) {
2.27 frystyk 986: if (PROT_TRACE)
987: fprintf(stderr, "MailAddress. getpwid returns NULL\n");
2.19 frystyk 988: if ((login = getenv("LOGNAME")) == NULL) {
2.27 frystyk 989: if (PROT_TRACE)
990: fprintf(stderr, "MailAddress. LOGNAME not found\n");
2.19 frystyk 991: if ((login = getenv("USER")) == NULL) {
2.27 frystyk 992: if (PROT_TRACE)
993: fprintf(stderr,"MailAddress. USER not found\n");
2.19 frystyk 994: return NULL; /* I GIVE UP */
995: }
996: }
997: } else
998: login = pw_info->pw_name;
999: }
2.23 duns 1000: #endif /* not VMS */
1001:
2.19 frystyk 1002: if (login) {
1003: StrAllocCopy(mailaddress, login);
1004: StrAllocCat(mailaddress, "@");
1005: if ((domain = HTGetHostName()) != NULL)
1006: StrAllocCat(mailaddress, domain);
2.21 frystyk 1007: else {
1008: *mailaddress = '\0';
1009: return NULL; /* Domain name not available */
1010: }
2.19 frystyk 1011: return mailaddress;
1012: }
1013: return NULL;
1014: }
2.32 frystyk 1015:
1016:
1017: /*
1018: ** Free the mail address. Called from HTLibTerminate
1019: */
1020: PUBLIC void HTFreeMailAddress NOARGS
1021: {
1022: FREE(mailaddress);
1023: }
1024:
2.19 frystyk 1025:
1026: /* ------------------------------------------------------------------------- */
1027: /* CONNECTION ESTABLISHMENT MANAGEMENT */
1028: /* ------------------------------------------------------------------------- */
2.13 frystyk 1029:
1030: /* HTDoConnect()
1031: **
1032: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
1033: ** the default_port value.
1034: **
1035: ** Returns 0 if OK, -1 on error
1036: */
2.24 frystyk 1037: PUBLIC int HTDoConnect ARGS5(HTNetInfo *, net, char *, url,
1038: u_short, default_port, u_long *, addr,
1039: BOOL, use_cur)
2.13 frystyk 1040: {
1041: int status;
1042: char *p1 = HTParse(url, "", PARSE_HOST);
1043: char *at_sign;
1044: char *host;
1045:
1046: /* if theres an @ then use the stuff after it as a hostname */
2.27 frystyk 1047: if((at_sign = strchr(p1, '@')) != NULL)
2.13 frystyk 1048: host = at_sign+1;
1049: else
1050: host = p1;
2.24 frystyk 1051: if (!*host) {
1052: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_HOST,
1053: NULL, 0, "HTDoConnect");
1054: free(p1);
1055: return -1;
2.27 frystyk 1056: } else {
1057: if (PROT_TRACE)
1058: fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
1059: }
2.13 frystyk 1060:
1061: /* Set up defaults */
2.27 frystyk 1062: if (net->sockfd < 0) {
1063: memset((void *) &net->sock_addr, '\0', sizeof(net->sock_addr));
2.13 frystyk 1064: #ifdef DECNET
2.27 frystyk 1065: net->sock_addr.sdn_family = AF_DECnet;/* Family = DECnet, host order */
1066: net->sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object number */
2.13 frystyk 1067: #else /* Internet */
2.27 frystyk 1068: net->sock_addr.sin_family = AF_INET;
1069: net->sock_addr.sin_port = htons(default_port);
2.13 frystyk 1070: #endif
2.27 frystyk 1071: }
2.13 frystyk 1072:
2.24 frystyk 1073: /* If we are trying to connect to a multi-homed host then loop here until
1074: success or we have tried all IP-addresses */
1075: do {
2.27 frystyk 1076: if (net->sockfd < 0) {
1077: int hosts;
1078: if ((hosts = HTParseInet(&net->sock_addr, host, use_cur)) < 0) {
1079: if (PROT_TRACE)
1080: fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
1081: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
1082: (void *) host, strlen(host), "HTDoConnect");
1083: break;
1084: };
1085: if (!net->addressCount && hosts > 1)
1086: net->addressCount = hosts;
1087: #ifdef DECNET
1088: if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0)
1089: #else
1090: if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
1091: #endif
1092: {
1093: HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
1094: break;
1095: }
1096: if (addr)
1097: *addr = ntohl(net->sock_addr.sin_addr.s_addr);
1098: if (PROT_TRACE)
1099: fprintf(stderr, "HTDoConnect. Created socket number %d\n",
1100: net->sockfd);
1101:
2.28 frystyk 1102: /* If non-blocking protocol then change socket status
1103: ** I use FCNTL so that I can ask the status before I set it.
1104: ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
1105: ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
1106: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
1107: ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
1108: */
2.27 frystyk 1109: if (!HTProtocolBlocking(net->request)) {
1110: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.28 frystyk 1111: status |= O_NONBLOCK; /* POSIX */
2.27 frystyk 1112: status = FCNTL(net->sockfd, F_SETFL, status);
1113: }
1114: if (status == -1) {
1115: if (PROT_TRACE)
1116: fprintf(stderr, "HTDoConnect. Can NOT make socket non-blocking\n");
2.33 frystyk 1117: } else if (PROT_TRACE)
1118: fprintf(stderr, "HTDoConnect. Using NON_BLOCKING I/O\n");
2.27 frystyk 1119: }
1120:
1121: /* If multi-homed host then start timer on connection */
1122: if (net->addressCount >= 1)
1123: net->connecttime = time(NULL);
2.24 frystyk 1124: }
2.13 frystyk 1125:
2.27 frystyk 1126: /* Check for interrupt */
1127: if (HTThreadIntr(net->sockfd)) {
1128: if (NETCLOSE(net->sockfd) < 0)
1129: HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
1130: HTThreadState(net->sockfd, THD_CLOSE);
1131: net->sockfd = -1;
1132: free(p1);
1133: return HT_INTERRUPTED;
1134: }
1135:
1136: /* Do a connect */
1137: status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr,
1138: sizeof(net->sock_addr));
1139: /*
1140: * According to the Sun man page for connect:
1141: * EINPROGRESS The socket is non-blocking and the con-
1142: * nection cannot be completed immediately.
1143: * It is possible to select(2) for comple-
1144: * tion by selecting the socket for writ-
1145: * ing.
1146: * According to the Motorola SVR4 man page for connect:
1147: * EAGAIN The socket is non-blocking and the con-
1148: * nection cannot be completed immediately.
1149: * It is possible to select for completion
1150: * by selecting the socket for writing.
1151: * However, this is only possible if the
1152: * socket STREAMS module is the topmost
1153: * module on the protocol stack with a
1154: * write service procedure. This will be
1155: * the normal case.
1156: */
1157: #ifdef EAGAIN
1158: if ((status < 0) && ((errno == EINPROGRESS) || (errno == EAGAIN)))
2.13 frystyk 1159: #else
2.27 frystyk 1160: if ((status < 0) && (errno == EINPROGRESS))
1161: #endif /* EAGAIN */
2.24 frystyk 1162: {
2.27 frystyk 1163: if (PROT_TRACE)
1164: fprintf(stderr, "HTDoConnect. WOULD BLOCK `%s'\n", host);
1165: HTThreadState(net->sockfd, THD_SET_WRITE);
1166: free(p1);
1167: return HT_WOULD_BLOCK;
2.24 frystyk 1168: }
2.27 frystyk 1169: if (net->addressCount >= 1) {
1170: net->connecttime = time(NULL) - net->connecttime;
2.24 frystyk 1171: if (status < 0) {
2.27 frystyk 1172: if (errno == EISCONN) { /* connect multi after would block */
1173: HTThreadState(net->sockfd, THD_CLR_WRITE);
1174: HTTCPAddrWeights(host, net->connecttime);
1175: free(p1);
1176: net->addressCount = 0;
1177: return 0;
1178: }
2.24 frystyk 1179: HTErrorSysAdd(net->request, ERR_NON_FATAL, NO, "connect");
2.27 frystyk 1180:
1181: /* I have added EINVAL `invalid argument' as this is what I
1182: get back from a non-blocking connect where I should
1183: get `connection refused' */
2.24 frystyk 1184: if (errno==ECONNREFUSED || errno==ETIMEDOUT ||
1185: errno==ENETUNREACH || errno==EHOSTUNREACH ||
2.27 frystyk 1186: errno==EHOSTDOWN || errno==EINVAL)
1187: net->connecttime += TCP_DELAY;
2.24 frystyk 1188: else
2.27 frystyk 1189: net->connecttime += TCP_PENALTY;
2.24 frystyk 1190: if (NETCLOSE(net->sockfd) < 0)
2.27 frystyk 1191: HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
1192: HTThreadState(net->sockfd, THD_CLOSE);
1193: net->sockfd = -1;
1194: HTTCPAddrWeights(host, net->connecttime);
1195: } else { /* Connect on multi-homed */
1196: HTTCPAddrWeights(host, net->connecttime);
1197: free(p1);
1198: net->addressCount = 0;
1199: return 0;
1200: }
1201: } else if (status < 0) {
1202: if (errno == EISCONN) { /* Connect single after would block */
1203: HTThreadState(net->sockfd, THD_CLR_WRITE);
1204: net->addressCount = 0;
1205: free(p1);
1206: return 0;
2.24 frystyk 1207: } else {
2.27 frystyk 1208: HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
1209: HTTCPCacheRemoveHost(host);
1210: if (NETCLOSE(net->sockfd) < 0)
1211: HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
1212: HTThreadState(net->sockfd, THD_CLOSE);
2.24 frystyk 1213: break;
1214: }
2.27 frystyk 1215: } else { /* Connect on single homed */
1216: free(p1);
1217: net->addressCount = 0;
1218: return 0;
2.24 frystyk 1219: }
2.27 frystyk 1220: } while (--net->addressCount);
2.13 frystyk 1221:
2.27 frystyk 1222: if (PROT_TRACE)
1223: fprintf(stderr, "HTDoConnect. Connect failed\n");
2.24 frystyk 1224: free (p1);
1225: net->addressCount = 0;
1226: net->sockfd = -1;
1227: return -1;
2.13 frystyk 1228: }
1229:
1230:
1231: /* HTDoAccept()
1232: **
1233: ** This function makes a non-blocking accept on a port and polls every
1234: ** second until MAX_ACCEPT_POLL or interrupted by user.
1235: **
1236: ** BUGS Interrupted is not yet implemented!!!
1237: **
2.27 frystyk 1238: ** Returns HT_WOULD_BLOCK if waiting
1239: ** 0 if OK,
1240: ** -1 on error
2.13 frystyk 1241: */
2.15 frystyk 1242: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13 frystyk 1243: {
1244: SockA soc_address; /* SockA is defined in tcp.h */
1245: int status;
1246: int cnt;
1247: int soc_addrlen = sizeof(soc_address);
2.15 frystyk 1248: if (net->sockfd < 0) {
2.27 frystyk 1249: if (PROT_TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
2.13 frystyk 1250: return -1;
1251: }
2.27 frystyk 1252:
2.13 frystyk 1253: /* First make the socket non-blocking */
2.23 duns 1254: #ifdef VMS
1255: #ifdef MULTINET
1256: {
1257: int enable = 1;
1258: status = socket_ioctl(net->sockfd, FIONBIO, &enable);
1259: }
1260: #endif /* MULTINET */
1261: #else /* not VMS */
2.15 frystyk 1262: if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.23 duns 1263: status |= FNDELAY; /* O_NDELAY; */
2.15 frystyk 1264: status = FCNTL(net->sockfd, F_SETFL, status);
2.13 frystyk 1265: }
2.23 duns 1266: #endif /* not VMS */
2.13 frystyk 1267: if (status == -1) {
2.15 frystyk 1268: HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13 frystyk 1269: return -1;
1270: }
1271:
1272: /* Now poll every sekund */
1273: for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15 frystyk 1274: if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13 frystyk 1275: &soc_addrlen)) >= 0) {
2.27 frystyk 1276: if (PROT_TRACE) fprintf(stderr,
2.13 frystyk 1277: "HTDoAccept.. Accepted new socket %d\n",
1278: status);
1279: return status;
1280: } else
2.15 frystyk 1281: HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13 frystyk 1282: sleep(1);
1283: }
1284:
1285: /* If nothing has happened */
2.27 frystyk 1286: if (PROT_TRACE)
2.13 frystyk 1287: fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15 frystyk 1288: HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
1289: "HTDoAccept");
2.13 frystyk 1290: return -1;
1.1 timbl 1291: }
2.27 frystyk 1292:
1.1 timbl 1293:
Webmaster