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