CTRACE(tfp, "LYGetHostByName: INTERRUPTED gethostbyname.\n");
CTRACE((tfp, "LYGetHostByName: INTERRUPTED gethostbyname.\n"));
PUBLIC struct hostent * LYGetHostByName ARGS1(	CONST char *,	str){#ifndef _WINDOWS_NSL    CONST char *host = str;#endif /* _WINDOWS_NSL */#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;#ifdef NO_RECOVERY	h_errno = NO_RECOVERY;#endif	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, "LYGetHostByName: Calling gethostbyname(%s)\n", host);#endif /* MVS */    CTRACE_FLUSH(tfp);  /* so child messages will not mess 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;	/*	**	Pipe, child pid, status buffers, start time, select()	**	control variables.	*/	pid_t fpid, waitret;	int pfd[2], selret, readret, waitstat = 0;	time_t start_time = time(NULL);	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	    **  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 ((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);	    /*	    **  Child won't use read side.  -BL	    */	    close(pfd[0]);	    phost = gethostbyname(host);	    statuses.child_h_errno = h_errno;	    statuses.h_errno_valid = YES;#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;	    }	    /*	    **  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));	    if (rehostentlen) {		/*		**  Return our resulting rehostent through pipe...		*/		write(pfd[1], rehostent, rehostentlen);		_exit(0);	    } else {		/*		**  ... 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 */	if (fpid < 0) {     /* fork failed */		close(pfd[0]);		goto failed;	}	while (child_exited || time(NULL) - 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);		}	    }	    timeout.tv_sec = 1;	    timeout.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, &timeout);	    else#endif /* SOCKS */		selret = select(pfd[0] + 1, (void *)&readfds, NULL, NULL, &timeout);	    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 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",		       (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, "LYGetHostByName: NSL_FORK child %d dumped core!\n",			   (int)waitret);		}#endif /* WCOREDUMP */	    } else if (WIFSTOPPED(waitstat)) {		CTRACE(tfp, "LYGetHostByName: NSL_FORK child %d is stopped, status 0x%x!\n",		       (int)waitret, waitstat);	    }	}	if (!got_rehostent) {	    goto failed;	}    }#else /* Not NSL_FORK: */#ifdef _WINDOWS_NSL    {#ifdef __BORLANDC__		HANDLE hThread, dwThreadID;#else		unsigned long hThread, dwThreadID;#endif /* __BORLANDC__ */		phost = (struct hostent *) NULL;		hThread = CreateThread((void *)NULL, 4096UL,#ifdef __BORLANDC__			 (LPTHREAD_START_ROUTINE)_fork_func,#else			 (unsigned long (*)())_fork_func,#endif /* __BORLANDC__ */			 (void *)NULL, 0UL, (unsigned long *)&dwThreadID);		if (!hThread)			 MessageBox((void *)NULL, "CreateThread",				"CreateThread Failed", 0L);		donelookup = FALSE;		while (!donelookup)			if (HTCheckForInterrupt())			 {			  /* Note that host is a character array and is not freed */			  /* to avoid possible subthread problems: */			  if (!CloseHandle(hThread))				 MessageBox((void *)NULL, "CloseHandle","CloseHandle Failed",						0L);			  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((char *)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;}