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