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