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