📄 httcp.c
字号:
data->h.h_addrtype = phost->h_addrtype; data->h.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) { data->h.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 { data->h.h_addr_list = NULL; } if (phost->h_name) { data->h.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 { data->h.h_name = NULL; } if (phost->h_aliases) { data->h.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]); } *p_next_charptr++ = NULL; } else { data->h.h_aliases = NULL; } curlen = p_next_char - (char *)rehostent; return curlen;}#endif /* NSL_FORK */#ifndef HAVE_H_ERRNO#undef h_errno#define h_errno my_errnostatic int my_errno;#else /* we do HAVE_H_ERRNO: */#ifndef h_errno /* there may be a macro as well as the extern data */extern int h_errno;#endif#endif/* 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( char *, str){#ifndef _WINDOWS_NSL char *host = str;#endif#ifdef NSL_FORK /* for transfer of result between from child to parent: */ static AlignedHOSTENT 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; /* sometimes useful to pass this on */ 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; }#ifdef _WINDOWS_NSL strncpy(host, str, sizeof(host));#endif /* _WINDOWS_NSL */ if (!valid_hostname(host)) { lynx_nsl_status = HT_NOT_ACCEPTABLE;#ifdef NO_RECOVERY#ifdef _WINDOWS WSASetLastError(NO_RECOVERY);#else h_errno = NO_RECOVERY;#endif#endif return NULL; }#ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */ CTRACE((tfp, "LYGetHostByName: Calling gethostbyname(%s)\n", host));#endif /* MVS */ CTRACE_FLUSH(tfp); /* so child messages will not mess up parent log */ 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 got_rehostent = 0;#if HAVE_SIGACTION sigset_t old_sigset; sigset_t new_sigset;#endif /* ** Pipe, child pid, status buffers, start time, select() ** control variables. */ pid_t fpid, waitret; int pfd[2], selret, readret;#ifdef HAVE_TYPE_UNIONWAIT union wait waitstat;#else int waitstat = 0;#endif time_t start_time = time((time_t *)0); fd_set readfds; struct timeval one_second; long dns_patience = 30; /* how many seconds will we wait for DNS? */ int child_exited = 0; /* ** Reap any children that have terminated since last time ** through. This might include children that we killed, ** then waited with WNOHANG before they were actually ready ** to be reaped. (Should be max of 1 in this state, but ** the loop is safe if waitpid() is implemented correctly: ** 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; pipe(pfd);#if HAVE_SIGACTION /* * Attempt to prevent a rare situation where the child * could execute the Lynx signal handlers because it gets * killed before it even has a chance to reset its handlers, * resulting in bogus 'Exiting via interrupt' message and * screen corruption or worse. * Should that continue to be reported, for systems without * sigprocmask(), we need to find a different solutions for * those. - kw 19990430 */ sigemptyset(&new_sigset); sigaddset(&new_sigset, SIGTERM); sigaddset(&new_sigset, SIGINT);#ifndef NOSIGHUP sigaddset(&new_sigset, SIGHUP);#endif /* NOSIGHUP */#ifdef SIGTSTP sigaddset(&new_sigset, SIGTSTP);#endif /* SIGTSTP */#ifdef SIGWINCH sigaddset(&new_sigset, SIGWINCH);#endif /* SIGWINCH */ sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset);#endif /* HAVE_SIGACTION */ 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); /* ** 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);#ifndef NOSIGHUP (void) signal(SIGHUP, quench);#endif /* NOSIGHUP */#ifdef SIGTSTP if (no_suspend) (void) signal(SIGTSTP, SIG_IGN); else (void) signal(SIGTSTP, SIG_DFL);#endif /* SIGTSTP */#ifdef SIGWINCH (void) signal(SIGWINCH, SIG_IGN);#endif /* SIGWINCH */#ifndef __linux__#ifndef DOSPATH signal(SIGBUS, SIG_DFL);#endif /* DOSPATH */#endif /* !__linux__ */ signal(SIGSEGV, SIG_DFL); signal(SIGILL, SIG_DFL);#if HAVE_SIGACTION /* Restore signal mask to whatever it was before the fork. -kw */ sigprocmask(SIG_SETMASK, &old_sigset, NULL);#endif /* HAVE_SIGACTION */ /* ** Child won't use read side. -BL */ close(pfd[0]);#ifdef HAVE_H_ERRNO /* to detect cases when it doesn't get set although it should */ h_errno = -2;#endif set_errno(0); phost = gethostbyname(host); statuses.child_errno = errno; statuses.child_h_errno = h_errno;#ifdef HAVE_H_ERRNO statuses.h_errno_valid = YES;#endif#ifdef MVS CTRACE((tfp, "LYGetHostByName: gethostbyname() returned %d\n", phost));#endif /* MVS */#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;#ifdef HAVE_H_ERRNO if (h_errno == -2) /* success, but h_errno unchanged? */ statuses.h_errno_valid = NO;#endif } /* ** 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). */ if (!statuses.child_errno) statuses.child_errno = errno; statuses.rehostentlen = rehostentlen; write(pfd[1], &statuses, sizeof(statuses)); if (rehostentlen) { /* ** Return our resulting rehostent through pipe... */ write(pfd[1], rehostent, rehostentlen); _exit(0); } else { /* ** ... or return error as exit code. */ _exit(1); } }#if HAVE_SIGACTION /* ** (parent) Restore signal mask to whatever it was ** before the fork. - kw */ sigprocmask(SIG_SETMASK, &old_sigset, NULL);#endif /* HAVE_SIGACTION */ /* ** (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 */ if (fpid < 0) { /* fork failed */ close(pfd[0]); goto failed; } while (child_exited || (long)(time((time_t *)0) - start_time) < dns_patience) { 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); } } one_second.tv_sec = 1; one_second.tv_usec = 0; FD_SET(pfd[0], &readfds); /* ** Return when data received, interrupted, or failed. ** If nothing is waiting, we sleep for 1 second in ** select(), to be nice to the system. -BL */#ifdef SOCKS if (socks_flag) selret = Rselect(pfd[0] + 1, (void *)&readfds, NULL, NULL, &one_second); else#endif /* SOCKS */ selret = select(pfd[0] + 1, (void *)&readfds, NULL, NULL, &one_second); 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; set_errno(statuses.child_errno);#ifdef HAVE_H_ERRNO if (statuses.h_errno_valid) { lynx_nsl_status = HT_H_ERRNO_VALID; /* * If something went wrong in the child process * other than normal lookup errors, and it appears * that we have enough info to know what went wrong, * generate diagnostic output. * ENOMEM observed on linux in processes constrained * with ulimit. It would be too unkind to abort * the session, access to local files or through a * proxy may still work. - kw */ if (#ifdef NETDB_INTERNAL /* linux glibc: defined in netdb.h */ (errno && h_errno == NETDB_INTERNAL) ||#endif (errno == ENOMEM && statuses.rehostentlen == 0 && /* should probably be NETDB_INTERNAL if child memory exhausted, but we may find that h_errno remains unchanged. - kw */ h_errno == -2)) {#ifndef MULTINET HTInetStatus("CHILD gethostbyname");#endif HTAlert(LYStrerror(statuses.child_errno)); if (errno == ENOMEM) { /* * Not much point in continuing, right? * Fake a 'z', should shorten pointless * guessing cycle. - kw */ LYFakeZap(YES); } } }#endif /* HAVE_H_ERRNO */ if (statuses.rehostentlen > sizeof(struct hostent)) { /* ** Then get the full reorganized hostent. -BL, kw */ 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; } /* ** Clean up if child exited before & no data received. -BL */ 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; continue; } /* ** Abort if interrupt key pressed. */ if (HTCheckForInterrupt()) { CTRACE((tfp, "LYGetHostByName: INTERRUPTED gethostbyname.\n")); kill(fpid, SIGTERM); waitpid(fpid, NULL, WNOHANG); close(pfd[0]); lynx_nsl_status = HT_INTERRUPTED; return NULL; } } 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",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -