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