timeout.tv_usec = 100000;
PUBLIC int HTDoConnect ARGS4(	CONST char *,	url,	char *, 	protocol,	int,		default_port,	int *,		s){    struct sockaddr_in soc_address;    struct sockaddr_in *soc_in = &soc_address;    int status;    char *line = NULL;    char *p1 = NULL;    char *at_sign = NULL;    char *host = NULL;    /*    **	Set up defaults.    */    memset(soc_in, 0, sizeof(*soc_in));    soc_in->sin_family = AF_INET;    soc_in->sin_port = htons(default_port);    /*    **	Get node name and optional port number.    */    p1 = HTParse(url, "", PARSE_HOST);    if ((at_sign = strchr(p1, '@')) != NULL) {	/*	**  If there's an @ then use the stuff after it as a hostname.	*/	StrAllocCopy(host, (at_sign + 1));    } else {	StrAllocCopy(host, p1);    }    FREE(p1);    HTSprintf0 (&line, gettext("Looking up %s."), host);    _HTProgress (line);    status = HTParseInet(soc_in, host);    if (status) {	if (status != HT_INTERRUPTED) {	    if (status == HT_NOT_ACCEPTABLE) {		/*  Not HTProgress, so warning won't be overwritten		 *  immediately; but not HTAlert, because typically		 *  there will be other alerts from the callers. - kw		 */		HTUserMsg2(gettext("Invalid hostname %s"), host);	    } else {		HTSprintf0 (&line,			 gettext("Unable to locate remote host %s."), host);		_HTProgress(line);	    }	    status = HT_NO_DATA;	}	FREE(host);	FREE(line);	return status;    }    HTSprintf0 (&line, gettext("Making %s connection to %s."), protocol, host);    _HTProgress (line);    FREE(host);    FREE(line);    /*    **	Now, let's get a socket set up from the server for the data.    */    *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    if (*s == -1) {	HTAlert(gettext("socket failed."));	return HT_NO_DATA;    }#ifndef DOSPATH#if !defined(NO_IOCTL) || defined(USE_FCNTL)    /*    **	Make the socket non-blocking, so the connect can be canceled.    **	This means that when we issue the connect we should NOT    **	have to wait for the accept on the other end.    */    {#ifdef USE_FCNTL	int ret = fcntl(*s, F_SETFL, O_NONBLOCK);#else	int val = 1;	int ret = IOCTL(*s, FIONBIO, &val);#endif /* USE_FCNTL */	if (ret == -1)	    _HTProgress(gettext("Could not make connection non-blocking."));    }#endif /* !NO_IOCTL || USE_FCNTL */#endif /* !DOSPATH */    /*    **	Issue the connect.  Since the server can't do an instantaneous    **	accept and we are non-blocking, this will almost certainly return    **	a negative status.    */#ifdef SOCKS    if (socks_flag) {	status = Rconnect(*s, (struct sockaddr*)&soc_address,			  sizeof(soc_address));	/*	**  For long Rbind.	*/	socks_bind_remoteAddr = soc_address.sin_addr.s_addr;    } else#endif /* SOCKS */    status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));#ifndef DJGPP    /*    **	According to the Sun man page for connect:    **	   EINPROGRESS	       The socket is non-blocking and the  con-    **			       nection cannot be completed immediately.    **			       It is possible to select(2) for	comple-    **			       tion  by  selecting the socket for writ-    **			       ing.    **	According to the Motorola SVR4 man page for connect:    **	   EAGAIN	       The socket is non-blocking and the  con-    **			       nection cannot be completed immediately.    **			       It is possible to select for  completion    **			       by  selecting  the  socket  for writing.    **			       However, this is only  possible	if  the    **			       socket  STREAMS	module	is  the topmost    **			       module on  the  protocol  stack	with  a    **			       write  service  procedure.  This will be    **			       the normal case.    */    if ((status < 0) &&	(SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EAGAIN)) {	struct timeval timeout;	int ret;	int tries=0;	ret = 0;	while (ret <= 0) {	    fd_set writefds;	    /*	    **	Protect against an infinite loop.	    */	    if (tries++ >= 180000) {		HTAlert(gettext("Connection failed for 180,000 tries."));		return HT_NO_DATA;	    }#ifdef _WINDOWS_NSL	    timeout.tv_sec = 100;#else	    timeout.tv_sec = 0;#endif /* _WINDOWS_NSL */	    timeout.tv_usec = 100000;	    FD_ZERO(&writefds);	    FD_SET(*s, &writefds);#ifdef SOCKS	    if (socks_flag)		ret = Rselect(FD_SETSIZE, NULL,			      (void *)&writefds, NULL, &timeout);	    else#endif /* SOCKS */	    ret = select(FD_SETSIZE, NULL, (void *)&writefds, NULL, &timeout);	   /*	   **  If we suspend, then it is possible that select will be	   **  interrupted.  Allow for this possibility. - JED	   */	   if ((ret == -1) && (errno == EINTR))	     continue;	    /*	    **	Again according to the Sun and Motorola man pages for connect:	    **	   EALREADY	       The socket is non-blocking and a  previ-	    **			       ous  connection attempt has not yet been	    **			       completed.	    **	Thus if the SOCKET_ERRNO is NOT EALREADY we have a real error,	    **	and should break out here and return that error.	    **	Otherwise if it is EALREADY keep on trying to complete the	    **	connection.	    */	    if ((ret < 0) && (SOCKET_ERRNO != EALREADY)) {		status = ret;		break;	    } else if (ret > 0) {		/*		**  Extra check here for connection success, if we try to		**  connect again, and get EISCONN, it means we have a		**  successful connection.  But don't check with SOCKS.		*/#ifdef SOCKS		if (socks_flag) {		    status = 0;		} else {#endif /* SOCKS */		status = connect(*s, (struct sockaddr*)&soc_address,				 sizeof(soc_address));#ifdef UCX		/*		**  A UCX feature: Instead of returning EISCONN		**		 UCX returns EADDRINUSE.		**  Test for this status also.		*/		if ((status < 0) && ((SOCKET_ERRNO == EISCONN) ||				     (SOCKET_ERRNO == EADDRINUSE)))#else		if ((status < 0) && (SOCKET_ERRNO == EISCONN))#endif /* UCX */		{		    status = 0;		}		if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */		    ret = 0; /* keep going */		else		    break;#ifdef SOCKS		}#endif /* SOCKS */	    }#ifdef SOCKS	    else if (!socks_flag)#else	    else#endif /* SOCKS */	    {		/*		**  The select says we aren't ready yet.  Try to connect		**  again to make sure.  If we don't get EALREADY or EISCONN,		**  something has gone wrong.  Break out and report it.		**		**  For some reason, SVR4 returns EAGAIN here instead of		**  EALREADY, even though the man page says it should be		**  EALREADY.		**		**  For some reason, UCX pre 3 apparently returns		**  errno = 18242 instead the EALREADY or EISCONN.		*/		status = connect(*s, (struct sockaddr*)&soc_address,				 sizeof(soc_address));		if ((status < 0) &&		    (SOCKET_ERRNO != EALREADY && SOCKET_ERRNO != EAGAIN) &&#ifdef UCX		    (SOCKET_ERRNO != 18242) &&#endif /* UCX */		    (SOCKET_ERRNO != EISCONN)) {		    break;		}	    }	    if (HTCheckForInterrupt()) {		CTRACE(tfp, "*** INTERRUPTED in middle of connect.\n");		status = HT_INTERRUPTED;		SOCKET_ERRNO = EINTR;		break;	    }	}    }#endif /* !DJGPP */    if (status < 0) {	/*	**  The connect attempt failed or was interrupted,	**  so close up the socket.	*/	NETCLOSE(*s);    }#ifndef DOSPATH#if !defined(NO_IOCTL) || defined(USE_FCNTL)    else {	/*	**  Make the socket blocking again on good connect.	*/#ifdef USE_FCNTL	int ret = fcntl(*s, F_SETFL, 0);#else	int val = 0;	int ret = IOCTL(*s, FIONBIO, &val);#endif /* USE_FCNTL */	if (ret == -1)	    _HTProgress(gettext("Could not restore socket to blocking."));    }#endif /* !NO_IOCTL || USE_FCNTL */#endif /* !DOSPATH */    return status;}