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