diff options
author | Thomas E. Dickey <dickey@invisible-island.net> | 1999-02-08 10:50:02 -0500 |
---|---|---|
committer | Thomas E. Dickey <dickey@invisible-island.net> | 1999-02-08 10:50:02 -0500 |
commit | 8ce6b560f4fb325be3d34266c54c70eb8668e8e1 (patch) | |
tree | d227c501d100ee0c5f1c72601d9ea5a487c1e2ca /WWW/Library/Implementation/HTTCP.c | |
parent | 87434eaa074d789f65bac589b03df341e76e7a4e (diff) | |
download | lynx-snapshots-8ce6b560f4fb325be3d34266c54c70eb8668e8e1.tar.gz |
snapshot of project "lynx", label v2-8-2dev_16
Diffstat (limited to 'WWW/Library/Implementation/HTTCP.c')
-rw-r--r-- | WWW/Library/Implementation/HTTCP.c | 961 |
1 files changed, 685 insertions, 276 deletions
diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c index d58b86d4..f34e0fbf 100644 --- a/WWW/Library/Implementation/HTTCP.c +++ b/WWW/Library/Implementation/HTTCP.c @@ -28,7 +28,11 @@ #include <sys/wait.h> #endif /* NSL_FORK */ -#define OK_HOST(p) ((p) != 0 && (p->h_length) != 0) +#ifdef HAVE_RESOLV_H +#include <resolv.h> +#endif + +#define OK_HOST(p) ((p) != 0 && ((p)->h_length) != 0) #ifdef SVR4_BSDSELECT PUBLIC int BSDselect PARAMS(( @@ -368,152 +372,337 @@ PRIVATE void quench ARGS1( } #endif /* NSL_FORK */ -/* Parse a network node address and port -** ------------------------------------- -** -** On entry, -** str points to a string with a node name or number, -** with optional trailing colon and port number. -** soc_in points to the binary internet or decnet address field. +PUBLIC int lynx_nsl_status = HT_OK; + +#ifndef DJGPP /* much excluded! */ + +#define DEBUG_HOSTENT /* disable in case of problems */ +#define DEBUG_HOSTENT_CHILD /* for NSL_FORK, may screw up trace file */ + +/* +** Two auxiliary functions for name lookup and struct hostent. ** -** On exit, -** *soc_in is filled in. If no port is specified in str, that -** field is left unchanged in *soc_in. +** dump_hostent - dumps the contents of a struct hostent to the +** trace log or stderr, including all pointer values, strings, and +** addresses, in a format inspired by gdb's print format. - kw */ -PUBLIC int HTParseInet ARGS2( - SockA *, soc_in, - CONST char *, str) +PRIVATE void dump_hostent ARGS2( + CONST char *, msgprefix, + CONST struct hostent *, phost) { - char *port; - int dotcount_ip = 0; /* for dotted decimal IP addr */ -#ifndef _WINDOWS_NSL - char *host = NULL; -#endif /* _WINDOWS_NSL */ - - if (!str) { - CTRACE(tfp, "HTParseInet: Can't parse `NULL'.\n"); - return -1; + if (TRACE) { + int i; + char **pcnt; + CTRACE(tfp,"%s: %p ", msgprefix, phost); + if (phost) { + CTRACE(tfp,"{ h_name = %p", phost->h_name); + if (phost->h_name) { + CTRACE(tfp, " \"%s\",", phost->h_name); + } else { + CTRACE(tfp, ","); + } + CTRACE(tfp,"\n\t h_aliases = %p", phost->h_aliases); + if (phost->h_aliases) { + CTRACE(tfp, " {"); + for (pcnt = phost->h_aliases; *pcnt; pcnt++) { + CTRACE(tfp,"%s %p \"%s\"", + (pcnt == phost->h_aliases ? " " : ", "), + *pcnt, *pcnt); + } + CTRACE(tfp, "%s0x0 },\n\t", + (*phost->h_aliases ? ", " : " ")); + } else { + CTRACE(tfp, ",\n\t"); + } + CTRACE(tfp," h_addrtype = %d,", phost->h_addrtype); + CTRACE(tfp," h_length = %d,\n\t", phost->h_length); + CTRACE(tfp," h_addr_list = %p", phost->h_addr_list); + if (phost->h_addr_list) { + CTRACE(tfp, " {"); + for (pcnt = phost->h_addr_list; *pcnt; pcnt++) { + CTRACE(tfp,"%s %p", + (pcnt == phost->h_addr_list ? "" : ","), + *pcnt); + for (i = 0; i < phost->h_length; i++) { + CTRACE(tfp, "%s%d%s", (i==0 ? " \"" : "."), + (int)*((unsigned char *)(*pcnt)+i), + (i+1 == phost->h_length ? "\"" : "")); + } + } + if (*phost->h_addr_list) { + CTRACE(tfp, ", 0x0 } }"); + } else { + CTRACE(tfp, " 0x0 } }"); + } + } else { + CTRACE(tfp, "}"); + } + } + CTRACE(tfp,"\n"); + fflush(tfp); } - CTRACE(tfp, "HTParseInet: parsing `%s'.\n", str); - if (HTCheckForInterrupt()) { - CTRACE (tfp, "HTParseInet: INTERRUPTED for '%s'.\n", str); - return -1; +} + +/* +** fill_rehostent - copies as much as possible relevant content from +** the struct hostent pointed to by phost to the char buffer given +** by rehostent, subject to maximum output length rehostentsize, +** following pointers and building self-contained output which can be +** cast to a struct hostent. - kw +** See also description of LYGetHostByName. +*/ +PRIVATE size_t fill_rehostent ARGS3( + char *, rehostent, + size_t, rehostentsize, + CONST struct hostent *, phost) +{ + int num_addrs = 0; + int num_aliases = 0; + char **pcnt; + char *p_next_char; + char **p_next_charptr; + size_t name_len = 0; + size_t required_per_addr; + size_t curlen = sizeof(struct hostent); + size_t available = rehostentsize - curlen; + size_t chk_available, mem_this_alias, required_this_alias; + int i_addr, i_alias; + + if (!phost) + return 0; + required_per_addr = phost->h_length + sizeof(char *); + if (phost->h_addr_list) + available -= sizeof(phost->h_addr_list[0]); + if (phost->h_aliases) + available -= sizeof(phost->h_aliases[0]); + if (phost->h_name) + available--; + if (phost->h_addr_list) { + if (phost->h_addr_list[0]) { + if (available >= required_per_addr) { + num_addrs++; + available -= required_per_addr; + } + } } -#ifdef _WINDOWS_NSL - strncpy(host, str, (size_t)512); -#else - StrAllocCopy(host, str); /* Make a copy we can mutilate */ -#endif /* _WINDOWS_NSL */ - /* - ** Parse port number if present. - */ - if ((port = strchr(host, ':')) != NULL) { - *port++ = 0; /* Chop off port */ - if (port[0] >= '0' && port[0] <= '9') { -#ifdef unix - soc_in->sin_port = htons(atol(port)); -#else /* VMS: */ -#ifdef DECNET - soc_in->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10)); -#else - soc_in->sin_port = htons((unsigned short)strtol(port,(char**)0,10)); -#endif /* Decnet */ -#endif /* Unix vs. VMS */ -#ifdef SUPPRESS /* 1. crashes!?!. 2. Not recommended */ + if (phost->h_name) { + name_len = strlen(phost->h_name); + if (available >= name_len) { + available -= name_len; } else { - struct servent * serv = getservbyname(port, (char*)0); - if (serv) { - soc_in->sin_port = serv->s_port; + name_len = 0; + } + } + if (num_addrs) { + for (pcnt=phost->h_addr_list+1; *pcnt; pcnt++) { + if (available >= required_per_addr) { + num_addrs++; + available -= required_per_addr; } else { - CTRACE(tfp, "TCP: Unknown service %s\n", port); + break; } -#endif /* SUPPRESS */ } } - -#ifdef DECNET - /* - ** Read Decnet node name. @@ Should know about DECnet addresses, but - ** it's probably worth waiting until the Phase transition from IV to V. - */ - soc_in->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */ - strncpy(soc_in->sdn_nam.n_name, host, soc_in->sdn_nam.n_len + 1); - CTRACE(tfp, "DECnet: Parsed address as object number %d on host %.6s...\n", - soc_in->sdn_objnum, host); -#else /* parse Internet host: */ - - if (*host >= '0' && *host <= '9') { /* Test for numeric node address: */ - char *strptr = host; - while (*strptr) { - if (*strptr == '.') { - dotcount_ip++; - } else if (!isdigit(*strptr)) { - break; + chk_available = available; + if (phost->h_aliases) { + for (pcnt=phost->h_aliases; *pcnt; pcnt++) { + required_this_alias = sizeof(phost->h_aliases[0]) + + strlen(*pcnt) + 1; + if (chk_available >= required_this_alias) { + num_aliases++; + chk_available -= required_this_alias; } - strptr++; } - if (*strptr) { /* found non-numeric, assume domain name */ - dotcount_ip = 0; + } + + ((struct hostent *)rehostent)->h_addrtype = phost->h_addrtype; + ((struct hostent *)rehostent)->h_length = phost->h_length; + p_next_charptr = (char **)(rehostent + curlen); + p_next_char = rehostent + curlen; + if (phost->h_addr_list) + p_next_char += (num_addrs+1) * sizeof(phost->h_addr_list[0]); + if (phost->h_aliases) + p_next_char += (num_aliases+1) * sizeof(phost->h_aliases[0]); + + if (phost->h_addr_list) { + ((struct hostent *)rehostent)->h_addr_list = p_next_charptr; + for (pcnt=phost->h_addr_list, i_addr = 0; + i_addr < num_addrs; + pcnt++, i_addr++) { + memcpy(p_next_char, *pcnt, sizeof(phost->h_addr_list[0])); + *p_next_charptr++ = p_next_char; + p_next_char += sizeof(phost->h_addr_list[0]); } + *p_next_charptr++ = NULL; + } else { + ((struct hostent *)rehostent)->h_addr_list = NULL; } - /* - ** Parse host number if present. - */ - if (dotcount_ip == 3) { /* Numeric node address: */ + if (phost->h_name) { + ((struct hostent *)rehostent)->h_name = p_next_char; + if (name_len) { + strcpy(p_next_char, phost->h_name); + p_next_char += name_len + 1; + } else { + *p_next_char++ = '\0'; + } + } else { + ((struct hostent *)rehostent)->h_name = NULL; + } -#ifdef DJGPP - soc_in->sin_addr.s_addr = htonl(aton(host)); -#else -#ifdef DGUX_OLD - soc_in->sin_addr.s_addr = inet_addr(host).s_addr; /* See arpa/inet.h */ -#else -#ifdef GUSI - soc_in->sin_addr = inet_addr(host); /* See netinet/in.h */ -#else -#ifdef HAVE_INET_ATON - if (!inet_aton(host, &(soc_in->sin_addr))) { - CTRACE(tfp, "inet_aton(%s) returns error\n", host); - return -1; + if (phost->h_aliases) { + ((struct hostent *)rehostent)->h_aliases = p_next_charptr; + for (pcnt=phost->h_aliases, i_alias = 0; + (*pcnt && i_alias < num_addrs); + pcnt++, i_alias++) { + mem_this_alias = strlen(*pcnt) + 1; + required_this_alias = sizeof(phost->h_aliases[0]) + + mem_this_alias; + if (available >= required_this_alias) { + i_alias++; + available -= required_this_alias; + strcpy(p_next_char, *pcnt); + *p_next_charptr++ = p_next_char; + p_next_char += mem_this_alias; + } + p_next_char += sizeof(phost->h_aliases[0]); } -#else - soc_in->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */ -#endif /* HAVE_INET_ATON */ -#endif /* GUSI */ -#endif /* DGUX_OLD */ -#endif /* DJGPP */ -#ifndef _WINDOWS_NSL - FREE(host); -#endif /* _WINDOWS_NSL */ - } else { /* Alphanumeric node name: */ - if (!valid_hostname(host)) { + *p_next_charptr++ = NULL; + } else { + ((struct hostent *)rehostent)->h_aliases = NULL; + } + curlen = p_next_char - (char *)rehostent; + return curlen; +} + +#define REHOSTENT_SIZE 128 /* not bigger than pipe buffer! */ + +/* Resolve an internet hostname, like gethostbyname +** ------------------------------------------------ +** +** On entry, +** str points to the given host name, not numeric address, +** without colon or port number. +** +** On exit, +** returns a pointer to a struct hostent in static storage, +** or NULL in case of error or user interruption. +** +** The interface is intended to be exactly the same as for (Unix) +** gethostbyname(), except for the following: +** +** If NSL_FORK is not used, the result of gethostbyname is returned +** directly. Otherwise: +** All lists, addresses, and strings referred to by pointers in the +** returned struct are located, together with the returned struct +** itself, in a buffer of size REHOSTENT_SIZE. If not everything fits, +** some info is omitted, but the function is careful to still return +** a valid structure, without truncating strings; it tries to return, +** in order of decreasing priority, the first address (h_addr), the +** official name (h_name), the additional addresses, then alias names. +** +** If NULL is returned, the reason is made available in the global +** variable lynx_nsl_status, with one of the following values: +** HT_INTERRUPTED Interrupted by user +** HT_NOT_ACCEPTABLE Hostname detected as invalid +** (also sets h_errno) +** HT_H_ERRNO_VALID An error occurred, and h_errno holds +** an appropriate value +** HT_ERROR Resolver error, reason not known +** HT_INTERNAL Internal error +*/ +PUBLIC struct hostent * LYGetHostByName ARGS1( + CONST char *, str) +{ #ifndef _WINDOWS_NSL - FREE(host); + CONST char *host = str; #endif /* _WINDOWS_NSL */ - return HT_NOT_ACCEPTABLE; /* only HTDoConnect checks this. */ - } +#ifdef NSL_FORK + /* for transfer of result between from child to parent: */ + static struct { + struct hostent h; + char rest[REHOSTENT_SIZE]; + } aligned_full_rehostent; + /* + * We could define rehosten directly as a + * static char rehostent[REHOSTENT_SIZE], + * but the indirect approach via the above struct + * should automatically take care of alignment requirements. + * Note that, in addition, + * - this must be static, as we shall return a pointer to it + * which must remain valid, and + * - we have to use the same rehostent in the child process as + * in the parent (its address in the parent's address space + * must be the same as in the child's, otherwise the internal + * pointers built by the child's call to fill_rehostent would + * be invalid when seen by the parent). - kw + */ + char *rehostent = (char *)&aligned_full_rehostent; + + /* for transfer of status from child to parent: */ + struct _statuses { + size_t rehostentlen; + int h_length; + int child_errno; /* maybe not very useful */ + int child_h_errno; + BOOL h_errno_valid; + } statuses; + + size_t rehostentlen = 0; +#endif /* NSL_FORK */ + + struct hostent *result_phost = NULL; + + if (!str) { + CTRACE(tfp, "LYGetHostByName: Can't parse `NULL'.\n"); + lynx_nsl_status = HT_INTERNAL; + return NULL; + } + CTRACE(tfp, "LYGetHostByName: parsing `%s'.\n", str); + + /* Could disable this if all our callers already check - kw */ + if (HTCheckForInterrupt()) { + CTRACE (tfp, "LYGetHostByName: INTERRUPTED for '%s'.\n", str); + lynx_nsl_status = HT_INTERRUPTED; + return NULL; + } + + if (!valid_hostname(host)) { + lynx_nsl_status = HT_NOT_ACCEPTABLE; + h_errno = NO_RECOVERY; + return NULL; + } + +#ifdef _WINDOWS_NSL + strncpy(host, str, (size_t)512); +#else + host = str; +#endif /* _WINDOWS_NSL */ #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */ - CTRACE(tfp, "HTParseInet: Calling gethostbyname(%s)\n", host); + CTRACE(tfp, "LYGetHostByName: Calling gethostbyname(%s)\n", host); #endif /* MVS */ + lynx_nsl_status = HT_INTERNAL; /* should be set to something else below */ + #ifdef NSL_FORK + statuses.h_errno_valid = NO; /* ** Start block for fork-based gethostbyname() with ** checks for interrupts. - Tom Zerucha (tz@execpc.com) & FM */ - { - int success = 0; - /* - ** Pipe, child pid, status buffers, cycle count, select() - ** control variables. + { + int got_rehostent = 0; + /* + ** Pipe, child pid, status buffers, cycle count, select() + ** control variables. */ - pid_t fpid, waitret; - int pfd[2], h_length, selret, readret, waitstat = 0, cycle = 0; - fd_set readfds; - struct timeval timeout; - int dns_patience = 30; /* how many seconds will we wait for DNS? */ - int child_exited = 0; + pid_t fpid, waitret; + int pfd[2], selret, readret, waitstat = 0, cycle = 0; + fd_set readfds; + struct timeval timeout; + int dns_patience = 30; /* how many seconds will we wait for DNS? */ + int child_exited = 0; /* ** Reap any children that have terminated since last time @@ -524,113 +713,135 @@ PUBLIC int HTParseInet ARGS2( ** returns 0 when children exist but none have exited; -1 ** with errno == ECHILD when no children.) -BL */ - do { - waitret = waitpid(-1, 0, WNOHANG); - } while (waitret > 0 || (waitret == -1 && errno == EINTR)); - waitret = 0; + do { + waitret = waitpid(-1, 0, WNOHANG); + } while (waitret > 0 || (waitret == -1 && errno == EINTR)); + waitret = 0; - pipe(pfd); + pipe(pfd); - if ((fpid = fork()) == 0 ) { - struct hostent *phost; /* Pointer to host - See netdb.h */ - /* - ** Child - for the long call. + if ((fpid = fork()) == 0 ) { + struct hostent *phost; /* Pointer to host - See netdb.h */ + /* + ** Child - for the long call. ** ** Make sure parent can kill us at will. -BL */ - (void) signal(SIGTERM, quench); + (void) signal(SIGTERM, quench); - /* + /* ** Also make sure the child does not run one of the ** signal handlers that may have been installed by ** Lynx if one of those signals occurs. For example ** we don't want the child to remove temp files on ** ^C, let the parent deal with that. - kw */ - (void) signal(SIGINT, quench); + (void) signal(SIGINT, quench); #ifndef NOSIGHUP - (void) signal(SIGHUP, quench); + (void) signal(SIGHUP, quench); #endif /* NOSIGHUP */ #ifdef SIGTSTP - if (no_suspend) - (void) signal(SIGTSTP, SIG_IGN); - else - (void) signal(SIGTSTP, SIG_DFL); + if (no_suspend) + (void) signal(SIGTSTP, SIG_IGN); + else + (void) signal(SIGTSTP, SIG_DFL); #endif /* SIGTSTP */ #ifdef SIGWINCH - (void) signal(SIGWINCH, SIG_IGN); + (void) signal(SIGWINCH, SIG_IGN); #endif /* SIGWINCH */ #ifndef __linux__ #ifndef DOSPATH - signal(SIGBUS, SIG_DFL); + signal(SIGBUS, SIG_DFL); #endif /* DOSPATH */ #endif /* !__linux__ */ - signal(SIGSEGV, SIG_DFL); - signal(SIGILL, SIG_DFL); + signal(SIGSEGV, SIG_DFL); + signal(SIGILL, SIG_DFL); - /* + /* ** Child won't use read side. -BL */ - close(pfd[0]); - phost = gethostbyname(host); + close(pfd[0]); + phost = gethostbyname(host); + statuses.child_h_errno = h_errno; + statuses.h_errno_valid = YES; #ifdef MVS - CTRACE(tfp, "HTParseInet: gethostbyname() returned %d\n", phost); + CTRACE(tfp, "LYGetHostByName: gethostbyname() returned %d\n", phost); #endif /* MVS */ - /* - ** Send length of subsequent value to parent (as a - ** native int). - */ - if (OK_HOST(phost)) - h_length = phost->h_length; - else - h_length = 0; - write(pfd[1], &h_length, sizeof h_length); - - if (h_length) { - /* - ** Return value through pipe... - */ - write(pfd[1], phost->h_addr, phost->h_length); - _exit(0); - } else { - /* - ** ... or return error as exit code. - */ - _exit(1); - } +#ifdef DEBUG_HOSTENT_CHILD + dump_hostent("CHILD gethostbyname", phost); +#endif + if (OK_HOST(phost)) { + rehostentlen = fill_rehostent(rehostent, REHOSTENT_SIZE, phost); +#ifdef DEBUG_HOSTENT_CHILD + dump_hostent("CHILD fill_rehostent", (struct hostent *)rehostent); +#endif + } + if (rehostentlen <= sizeof(struct hostent) || + !OK_HOST((struct hostent *)rehostent)) { + rehostentlen = 0; + statuses.h_length = 0; + } else { + statuses.h_length = ((struct hostent *)rehostent)->h_length; } - /* - ** (parent) Wait until lookup finishes, or interrupt, - ** or cycled too many times (just in case) -BL + ** Send variables indicating status of lookup to parent. + ** That includes rehostentlen, which the parent will use + ** as the size for the second read (if > 0). */ + statuses.child_errno = errno; + statuses.rehostentlen = rehostentlen; + write(pfd[1], &statuses, sizeof(statuses)); - close(pfd[1]); /* parent won't use write side -BL */ - while (cycle < dns_patience) { + if (rehostentlen) { /* - ** Avoid infinite loop in the face of the unexpected. -BL + ** Return our resulting rehostent through pipe... */ - cycle++; - - FD_ZERO(&readfds); -#ifndef USE_SLANG + write(pfd[1], rehostent, rehostentlen); + _exit(0); + } else { /* - ** This allows us to abort immediately, not after 1-second - ** timeout, when user hits abort key. Can't do this when - ** using SLANG (or at least I don't know how), so SLANG - ** users must live with up-to-1s timeout. -BL - ** - ** Whoops -- we need to make sure stdin is actually - ** selectable! /dev/null isn't, on some systems, which - ** makes some useful Lynx invocations fail. -BL + ** ... or return error as exit code. + */ + _exit(1); + } + } + + /* + ** (parent) Wait until lookup finishes, or interrupt, + ** or cycled too many times (just in case) -BL + */ + + close(pfd[1]); /* parent won't use write side -BL */ + + while (cycle < dns_patience) { + /* + ** Avoid infinite loop in the face of the unexpected. -BL */ - if (isatty(fileno(stdin))) FD_SET(fileno(stdin), &readfds); -#endif /* USE_SLANG */ - timeout.tv_sec = 1; - timeout.tv_usec = 0; - FD_SET(pfd[0], &readfds); + cycle++; + + FD_ZERO(&readfds); + /* + ** This allows us to abort immediately, not after 1-second + ** timeout, when user hits abort key. Can't do this when + ** using SLANG (or at least I don't know how), so SLANG + ** users must live with up-to-1s timeout. -BL + ** + ** Whoops -- we need to make sure stdin is actually + ** selectable! /dev/null isn't, on some systems, which + ** makes some useful Lynx invocations fail. -BL + */ + { + int kbd_fd = LYConsoleInputFD(TRUE); + if (kbd_fd != INVSOC) { + FD_SET(kbd_fd, &readfds); + } + } + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + FD_SET(pfd[0], &readfds); /* ** Return when data received, interrupted, or failed. @@ -638,107 +849,117 @@ PUBLIC int HTParseInet ARGS2( ** select(), to be nice to the system. -BL */ #ifdef SOCKS - if (socks_flag) - selret = Rselect(pfd[0] + 1, (void *)&readfds, NULL, NULL, &timeout); - else + if (socks_flag) + selret = Rselect(pfd[0] + 1, (void *)&readfds, NULL, NULL, &timeout); + else #endif /* SOCKS */ - selret = select(pfd[0] + 1, (void *)&readfds, NULL, NULL, &timeout); + selret = select(pfd[0] + 1, (void *)&readfds, NULL, NULL, &timeout); - if ((selret > 0) && FD_ISSET(pfd[0], &readfds)) { - /* - ** First get length of address. -BL - */ - readret = read(pfd[0], (void *)&h_length, sizeof h_length); - if (readret == sizeof h_length && - h_length == sizeof soc_in->sin_addr) { + if ((selret > 0) && FD_ISSET(pfd[0], &readfds)) { + /* + ** First get status, including length of address. -BL, kw + */ + readret = read(pfd[0], &statuses, sizeof(statuses)); + if (readret == sizeof(statuses)) { + h_errno = statuses.child_h_errno; + errno = statuses.child_errno; + if (statuses.h_errno_valid) + lynx_nsl_status = HT_H_ERRNO_VALID; + if (statuses.rehostentlen > sizeof(struct hostent)) { /* - ** Then get address itself. -BL + ** Then get the full reorganized hostent. -BL, kw */ - readret = read(pfd[0], (void *)&soc_in->sin_addr, h_length); - if (readret == h_length) success = 1; + readret = read(pfd[0], rehostent, statuses.rehostentlen); +#ifdef DEBUG_HOSTENT + dump_hostent("Read from pipe", (struct hostent *)rehostent); +#endif + if (readret == (int) statuses.rehostentlen) { + got_rehostent = 1; + result_phost = (struct hostent *)rehostent; + lynx_nsl_status = HT_OK; + } else if (!statuses.h_errno_valid) { + lynx_nsl_status = HT_INTERNAL; + } } - /* + } else { + lynx_nsl_status = HT_ERROR; + } + /* ** Make sure child is cleaned up. -BL */ - if (!child_exited) - waitret = waitpid(fpid, &waitstat, WNOHANG); - if (!WIFEXITED(waitstat) && !WIFSIGNALED(waitstat)) { - kill(fpid, SIGTERM); - waitret = waitpid(fpid, &waitstat, WNOHANG); - } - break; - } + if (!child_exited) + waitret = waitpid(fpid, &waitstat, WNOHANG); + if (!WIFEXITED(waitstat) && !WIFSIGNALED(waitstat)) { + kill(fpid, SIGTERM); + waitret = waitpid(fpid, &waitstat, WNOHANG); + } + break; + } - /* + /* ** Clean up if child exited before & no data received. -BL */ - if (child_exited) { - waitret = waitpid(fpid, &waitstat, WNOHANG); - break; - } - /* + if (child_exited) { + waitret = waitpid(fpid, &waitstat, WNOHANG); + break; + } + /* ** If child exited, loop once more looking for data. -BL */ - if ((waitret = waitpid(fpid, &waitstat, WNOHANG)) > 0) { - /* - ** Data will be arriving right now, so make sure we - ** don't short-circuit out for too many loops, and - ** skip the interrupt check. -BL - */ - child_exited = 1; - cycle--; - continue; - } - + if ((waitret = waitpid(fpid, &waitstat, WNOHANG)) > 0) { /* - ** Abort if interrupt key pressed. + ** Data will be arriving right now, so make sure we + ** don't short-circuit out for too many loops, and + ** skip the interrupt check. -BL */ - if (HTCheckForInterrupt()) { - CTRACE(tfp, "HTParseInet: INTERRUPTED gethostbyname.\n"); - kill(fpid, SIGTERM); - waitpid(fpid, NULL, WNOHANG); - FREE(host); - close(pfd[0]); - return HT_INTERRUPTED; - } + child_exited = 1; + cycle--; + continue; } - close(pfd[0]); - if (waitret <= 0) { + + /* + ** Abort if interrupt key pressed. + */ + if (HTCheckForInterrupt()) { + CTRACE(tfp, "LYGetHostByName: INTERRUPTED gethostbyname.\n"); kill(fpid, SIGTERM); - waitret = waitpid(fpid, &waitstat, WNOHANG); + waitpid(fpid, NULL, WNOHANG); + close(pfd[0]); + lynx_nsl_status = HT_INTERRUPTED; + return NULL; } - if (waitret > 0) { - if (WIFEXITED(waitstat)) { - CTRACE(tfp, "HTParseInet: NSL_FORK child %d exited, status 0x%x.\n", - (int)waitret, waitstat); - } else if (WIFSIGNALED(waitstat)) { - CTRACE(tfp, "HTParseInet: NSL_FORK child %d got signal, status 0x%x!\n", - (int)waitret, waitstat); + } + close(pfd[0]); + if (waitret <= 0) { + kill(fpid, SIGTERM); + waitret = waitpid(fpid, &waitstat, WNOHANG); + } + if (waitret > 0) { + if (WIFEXITED(waitstat)) { + CTRACE(tfp, "LYGetHostByName: NSL_FORK child %d exited, status 0x%x.\n", + (int)waitret, waitstat); + } else if (WIFSIGNALED(waitstat)) { + CTRACE(tfp, "LYGetHostByName: NSL_FORK child %d got signal, status 0x%x!\n", + (int)waitret, waitstat); #ifdef WCOREDUMP - if (WCOREDUMP(waitstat)) { - CTRACE(tfp, "HTParseInet: NSL_FORK child %d dumped core!\n", - (int)waitret); - } -#endif /* WCOREDUMP */ - } else if (WIFSTOPPED(waitstat)) { - CTRACE(tfp, "HTParseInet: NSL_FORK child %d is stopped, status 0x%x!\n", - (int)waitret, waitstat); + if (WCOREDUMP(waitstat)) { + CTRACE(tfp, "LYGetHostByName: NSL_FORK child %d dumped core!\n", + (int)waitret); } - } - if (!success) { - memset((void *)&soc_in->sin_addr, 0, sizeof(soc_in->sin_addr)); - goto failed; +#endif /* WCOREDUMP */ + } else if (WIFSTOPPED(waitstat)) { + CTRACE(tfp, "LYGetHostByName: NSL_FORK child %d is stopped, status 0x%x!\n", + (int)waitret, waitstat); } } -#else /* Not NSL_FORK: */ -#ifdef DJGPP - soc_in->sin_addr.s_addr = htonl(resolve(host)); - if (soc_in->sin_addr.s_addr == 0) { + if (!got_rehostent) { goto failed; } -#else /* !NSL_FORK, !DJGPP: */ + } +#else /* Not NSL_FORK: */ + #ifdef _WINDOWS_NSL - { + { #ifdef __BORLANDC__ HANDLE hThread, dwThreadID; #else @@ -765,18 +986,197 @@ PUBLIC int HTParseInet ARGS2( if (!CloseHandle(hThread)) MessageBox((void *)NULL, "CloseHandle","CloseHandle Failed", 0L); - return HT_INTERRUPTED; + lynx_nsl_status = HT_INTERRUPTED; + return NULL; }; - }; + if (phost) { + lynx_nsl_status = HT_OK; + result_phost = phost; + } else { + lynx_nsl_status = HT_ERROR; + goto failed; + } + }; + +#else /* !NSL_FORK, !_WINDOWS_NSL: */ + { + struct hostent *phost; + phost = gethostbyname(host); /* See netdb.h */ +#ifdef MVS + CTRACE(tfp, "LYGetHostByName: gethostbyname() returned %d\n", phost); +#endif /* MVS */ + if (phost) { + lynx_nsl_status = HT_OK; + result_phost = phost; + } else { + lynx_nsl_status = HT_H_ERRNO_VALID; + goto failed; + } + } +#endif /* !NSL_FORK, !_WINDOWS_NSL */ +#endif /* !NSL_FORK */ + +#ifdef DEBUG_HOSTENT + dump_hostent("End of LYGetHostByName", result_phost); + CTRACE(tfp, "LYGetHostByName: Resolved name to a hostent.\n"); +#endif + + return result_phost; /* OK */ + +failed: + CTRACE(tfp, "LYGetHostByName: Can't find internet node name `%s'.\n", + host); + return NULL; +} + +#endif /* from here on DJGPP joins us again. */ + + +/* Parse a network node address and port +** ------------------------------------- +** +** On entry, +** str points to a string with a node name or number, +** with optional trailing colon and port number. +** soc_in points to the binary internet or decnet address field. +** +** On exit, +** *soc_in is filled in. If no port is specified in str, that +** field is left unchanged in *soc_in. +*/ +PUBLIC int HTParseInet ARGS2( + SockA *, soc_in, + CONST char *, str) +{ + char *port; + int dotcount_ip = 0; /* for dotted decimal IP addr */ +#ifndef _WINDOWS_NSL + char *host = NULL; +#endif /* _WINDOWS_NSL */ + + if (!str) { + CTRACE(tfp, "HTParseInet: Can't parse `NULL'.\n"); + return -1; + } + CTRACE(tfp, "HTParseInet: parsing `%s'.\n", str); + if (HTCheckForInterrupt()) { + CTRACE (tfp, "HTParseInet: INTERRUPTED for '%s'.\n", str); + return -1; + } +#ifdef _WINDOWS_NSL + strncpy(host, str, (size_t)512); +#else + StrAllocCopy(host, str); /* Make a copy we can mutilate */ +#endif /* _WINDOWS_NSL */ + /* + ** Parse port number if present. + */ + if ((port = strchr(host, ':')) != NULL) { + *port++ = 0; /* Chop off port */ + if (port[0] >= '0' && port[0] <= '9') { +#ifdef unix + soc_in->sin_port = htons(atol(port)); +#else /* VMS: */ +#ifdef DECNET + soc_in->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10)); +#else + soc_in->sin_port = htons((unsigned short)strtol(port,(char**)0,10)); +#endif /* Decnet */ +#endif /* Unix vs. VMS */ +#ifdef SUPPRESS /* 1. crashes!?!. 2. Not recommended */ + } else { + struct servent * serv = getservbyname(port, (char*)0); + if (serv) { + soc_in->sin_port = serv->s_port; + } else { + CTRACE(tfp, "TCP: Unknown service %s\n", port); + } +#endif /* SUPPRESS */ + } + } + +#ifdef DECNET + /* + ** Read Decnet node name. @@ Should know about DECnet addresses, but + ** it's probably worth waiting until the Phase transition from IV to V. + */ + soc_in->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */ + strncpy(soc_in->sdn_nam.n_name, host, soc_in->sdn_nam.n_len + 1); + CTRACE(tfp, "DECnet: Parsed address as object number %d on host %.6s...\n", + soc_in->sdn_objnum, host); +#else /* parse Internet host: */ + + if (*host >= '0' && *host <= '9') { /* Test for numeric node address: */ + char *strptr = host; + while (*strptr) { + if (*strptr == '.') { + dotcount_ip++; + } else if (!isdigit(*strptr)) { + break; + } + strptr++; + } + if (*strptr) { /* found non-numeric, assume domain name */ + dotcount_ip = 0; + } + } + + /* + ** Parse host number if present. + */ + if (dotcount_ip == 3) { /* Numeric node address: */ + +#ifdef DJGPP + soc_in->sin_addr.s_addr = htonl(aton(host)); +#else +#ifdef DGUX_OLD + soc_in->sin_addr.s_addr = inet_addr(host).s_addr; /* See arpa/inet.h */ +#else +#ifdef GUSI + soc_in->sin_addr = inet_addr(host); /* See netinet/in.h */ +#else +#ifdef HAVE_INET_ATON + if (!inet_aton(host, &(soc_in->sin_addr))) { + CTRACE(tfp, "inet_aton(%s) returns error\n", host); +#ifndef _WINDOWS_NSL + FREE(host); +#endif /* _WINDOWS_NSL */ + return -1; + } +#else + soc_in->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */ +#endif /* HAVE_INET_ATON */ +#endif /* GUSI */ +#endif /* DGUX_OLD */ +#endif /* DJGPP */ +#ifndef _WINDOWS_NSL + FREE(host); +#endif /* _WINDOWS_NSL */ + } else { /* Alphanumeric node name: */ + +#ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */ + CTRACE(tfp, "HTParseInet: Calling LYGetHostByName(%s)\n", host); +#endif /* MVS */ + +#ifdef DJGPP + if (!valid_hostname(host)) { + FREE(host); + return HT_NOT_ACCEPTABLE; /* only HTDoConnect checks this. */ + } + soc_in->sin_addr.s_addr = htonl(resolve(host)); + if (soc_in->sin_addr.s_addr == 0) { + goto failed; + } +#else /* !DJGPP: */ +#ifdef _WINDOWS_NSL + phost = LYGetHostByName(host); /* See above */ if (!phost) goto failed; memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length); -#else /* !NSL_FORK, !DJGPP, !_WINDOWS_NSL: */ +#else /* !DJGPP, !_WINDOWS_NSL: */ { struct hostent *phost; - phost = gethostbyname(host); /* See netdb.h */ -#ifdef MVS - CTRACE(tfp, "HTParseInet: gethostbyname() returned %d\n", phost); -#endif /* MVS */ + phost = LYGetHostByName(host); /* See above */ + if (!phost) goto failed; #if defined(VMS) && defined(CMU_TCP) /* @@ -789,17 +1189,20 @@ PUBLIC int HTParseInet ARGS2( */ memcpy((void *)&soc_in->sin_addr, phost->h_addr, 4); #else + if (!phost) goto failed; + if (phost->h_length != sizeof soc_in->sin_addr) { + HTAlwaysAlert(host, gettext("Address length looks invalid")); + } memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length); #endif /* VMS && CMU_TCP */ } -#endif /* !NSL_FORK, !DJGPP, !_WINDOWS_NSL */ -#endif /* !NSL_FORK, !DJGPP */ -#endif /* !NSL_FORK */ +#endif /* !DJGPP, !_WINDOWS_NSL */ +#endif /* !DJGPP */ #ifndef _WINDOWS_NSL FREE(host); #endif /* _WINDOWS_NSL */ - } + } /* Alphanumeric node name */ CTRACE(tfp, "HTParseInet: Parsed address as port %d, IP address %d.%d.%d.%d\n", (int)ntohs(soc_in->sin_port), @@ -817,8 +1220,14 @@ failed: #ifndef _WINDOWS_NSL FREE(host); #endif /* _WINDOWS_NSL */ + switch (lynx_nsl_status) { + case HT_NOT_ACCEPTABLE: + case HT_INTERRUPTED: + return lynx_nsl_status; + default: return -1; } +} /* Free our name for the host on which we are - FM ** ------------------------------------------- |