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