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