$NetBSD: patch-ao,v 1.2 2000/01/15 22:55:48 hubertf Exp $

diff -x *.orig -urN ./WWW/Library/Implementation/HTTCP.c /usr/pkgsrc/www/lynx/work.unpatched/lynx2-8-2/WWW/Library/Implementation/HTTCP.c
--- ./WWW/Library/Implementation/HTTCP.c	Mon May 24 21:00:53 1999
+++ /usr/pkgsrc/www/lynx/work.unpatched/lynx2-8-2/WWW/Library/Implementation/HTTCP.c	Sat Jan 15 07:57:18 2000
@@ -297,13 +297,15 @@
 PUBLIC CONST char * HTInetString ARGS1(
 	SockA*, 	soc_in)
 {
-    static char string[16];
-    sprintf(string, "%d.%d.%d.%d",
-	    (int)*((unsigned char *)(&soc_in->sin_addr)+0),
-	    (int)*((unsigned char *)(&soc_in->sin_addr)+1),
-	    (int)*((unsigned char *)(&soc_in->sin_addr)+2),
-	    (int)*((unsigned char *)(&soc_in->sin_addr)+3));
-    return string;
+    static char hostbuf[MAXHOSTNAMELEN];
+    getnameinfo((struct sockaddr *)soc_in,
+#ifdef SIN6_LEN
+	    ((struct sockaddr *)soc_in)->sa_len,
+#else
+	    SA_LEN((struct sockaddr *)soc_in),
+#endif
+	    hostbuf, sizeof(hostbuf), NULL, 0, NI_NUMERICHOST);
+    return hostbuf;
 }
 #endif /* !DECNET */
 
@@ -1051,11 +1053,13 @@
 **	*soc_in is filled in.  If no port is specified in str, that
 **		field is left unchanged in *soc_in.
 */
-PUBLIC int HTParseInet ARGS2(
+PUBLIC int HTParseInet ARGS3(
 	SockA *,	soc_in,
-	CONST char *,	str)
+	CONST char *,	str,
+	int, default_port)
 {
     char *port;
+    char portstr[NI_MAXSERV];
     int dotcount_ip = 0;	/* for dotted decimal IP addr */
 #ifndef _WINDOWS_NSL
     char *host = NULL;
@@ -1078,28 +1082,18 @@
     /*
     **	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 */
-	}
+
+    if (!strrchr(host, ']'))
+	port = strrchr(host, ':');
+    else
+	port = strrchr(strrchr(host, ']'), ':');
+
+    if (port) {
+      *port++ = 0;            /* Chop off port */
+    }
+    else {
+      sprintf(portstr,"%d", default_port);
+      port = portstr;
     }
 
 #ifdef DECNET
@@ -1113,6 +1107,13 @@
 		soc_in->sdn_objnum, host);
 #else  /* parse Internet host: */
 
+    /* [host] case */
+    if (host[0] == '[' && host[strlen(host) - 1] == ']') {
+	host[strlen(host) - 1] = '\0';
+	host++;
+    }
+
+#ifndef INET6
     if (*host >= '0' && *host <= '9') {   /* Test for numeric node address: */
 	char *strptr = host;
 	while (*strptr) {
@@ -1127,11 +1128,14 @@
 	    dotcount_ip = 0;
 	}
     }
+#endif
 
     /*
     **	Parse host number if present.
     */
-    if (dotcount_ip == 3) {   /* Numeric node address: */
+#ifndef INET6
+    if (dotcount_ip == 3)   /* Numeric node address: */
+    {
 
 #ifdef DJGPP
 	soc_in->sin_addr.s_addr = htonl(aton(host));
@@ -1159,7 +1163,9 @@
 #ifndef _WINDOWS_NSL
 	FREE(host);
 #endif /* _WINDOWS_NSL */
-    } else {		    /* Alphanumeric node name: */
+    } else
+#endif
+    {		    /* Alphanumeric node name: */
 
 #ifdef MVS	/* Outstanding problem with crash in MVS gethostbyname */
 	CTRACE(tfp, "HTParseInet: Calling LYGetHostByName(%s)\n", host);
@@ -1181,10 +1187,18 @@
 	memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length);
 #else /* !DJGPP, !_WINDOWS_NSL: */
 	{
-	    struct hostent  *phost;
-	    phost = LYGetHostByName(host);	/* See above */
+	    struct addrinfo hints, *res;
+	    int error;
 
-	    if (!phost) goto failed;
+	    memset(&hints, 0, sizeof(hints));
+	    hints.ai_family = PF_UNSPEC;
+	    error = getaddrinfo(host, port, &hints, &res);
+
+	    if (error || !res) {
+		CTRACE(tfp, "HTParseInet: getaddrinfo(%s): %s\n", host,
+			gai_strerror(error));
+		goto failed;
+	    }
 #if defined(VMS) && defined(CMU_TCP)
 	    /*
 	    **  In LIBCMU, phost->h_length contains not the length of one address
@@ -1194,14 +1208,18 @@
 	    **  longer supported, and CMU users are encouraged to obtain and use
 	    **  SOCKETSHR/NETLIB instead. - S. Bjorndahl
 	    */
-	    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"));
+	    if (res->ai_family == AF_INET) {
+		memcpy((void *)&soc_in->sin_addr,
+		    &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4);
+	    } else {
+		CTRACE(tfp, "HTParseInet: unsupported address family %d\n",
+			res->ai_family);
+		goto failed;
 	    }
-	    memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length);
+#else
+	    memcpy((void *)soc_in, res->ai_addr, res->ai_addrlen);
 #endif /* VMS && CMU_TCP */
+	    freeaddrinfo(res);
 	}
 #endif /* !DJGPP, !_WINDOWS_NSL */
 #endif /* !DJGPP */
@@ -1211,12 +1229,14 @@
 
     }	/* Alphanumeric node name */
 
+#ifndef INET6
     CTRACE(tfp, "HTParseInet: Parsed address as port %d, IP address %d.%d.%d.%d\n",
 		(int)ntohs(soc_in->sin_port),
 		(int)*((unsigned char *)(&soc_in->sin_addr)+0),
 		(int)*((unsigned char *)(&soc_in->sin_addr)+1),
 		(int)*((unsigned char *)(&soc_in->sin_addr)+2),
 		(int)*((unsigned char *)(&soc_in->sin_addr)+3));
+#endif
 #endif	/* Internet vs. Decnet */
 
     return 0;	/* OK */
@@ -1232,8 +1252,50 @@
     case HT_INTERRUPTED:
 	return lynx_nsl_status;
     default:
-    return -1;
+        return -1;
+    }
 }
+
+PRIVATE struct addrinfo *
+HTGetAddrInfo ARGS2(
+    CONST char *, str,
+    CONST int, defport)
+{
+    struct addrinfo hints, *res;
+    int error;
+    char *p;
+    char *s;
+    char *host, *port;
+    char pbuf[10];
+
+    s = strdup(str);
+
+    if (s[0] == '[' && (p = strchr(s, ']')) != NULL) {
+	*p++ = '\0';
+	host = s + 1;
+    } else {
+	p = s;
+	host = &s[0];
+    }
+    port = strrchr(p, ':');
+    if (port) {
+	*port++ = '\0';
+    } else {
+	snprintf(pbuf, sizeof(pbuf), "%d", defport);
+	port = pbuf;
+    }
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    error = getaddrinfo(host, port, &hints, &res);
+    if (error || !res) {
+	CTRACE(tfp, "HTGetAddrInfo: getaddrinfo(%s, %s): %s\n", host, port,
+		gai_strerror(error));
+	return NULL;
+    }
+
+    return res;
 }
 
 #ifdef LY_FIND_LEAKS
@@ -1262,7 +1324,8 @@
     char *domain_name;			/* The name of this host domain */
 #endif /* UCX */
 #ifdef NEED_HOST_ADDRESS		/* no -- needs name server! */
-    struct hostent * phost;		/* Pointer to host -- See netdb.h */
+    struct addrinfo hints, *res;
+    int error;
 #endif /* NEED_HOST_ADDRESS */
     int namelength = sizeof(name);
 
@@ -1290,14 +1353,20 @@
 
 #ifndef DECNET	/* Decnet ain't got no damn name server 8#OO */
 #ifdef NEED_HOST_ADDRESS		/* no -- needs name server! */
-    phost = gethostbyname(name);	/* See netdb.h */
-    if (!OK_HOST(phost)) {
-	CTRACE(tfp, "TCP: Can't find my own internet node address for `%s'!!\n",
-		    name);
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_CANONNAME;
+    error = getaddrinfo(name, NULL, &hints, &res);
+    if (error || !res || !res->ai_canonname) {
+	CTRACE(tfp, "TCP: %s: `%s'\n", gai_strerror(error), name);
+	if (res)
+	    freeaddrinfo(res);
 	return;  /* Fail! */
     }
-    StrAllocCopy(hostname, phost->h_name);
-    memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
+    StrAllocCopy(hostname, res->ai_canonname);
+    memcpy(&HTHostAddress, res->ai_addr, res->ai_addrlen);
+    freeaddrinfo(res);
     CTRACE(tfp, "     Name server says that I am `%s' = %s\n",
 		hostname, HTInetString(&HTHostAddress));
 #endif /* NEED_HOST_ADDRESS */
@@ -1322,20 +1391,14 @@
 	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);
+    int error;
+    struct sockaddr *sa;
+    struct addrinfo *res, *res0;
 
     /*
     **	Get node name and optional port number.
@@ -1353,25 +1416,15 @@
 
     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;
-	}
+    /* HTParseInet() is useless! */
+    _HTProgress(host);
+    res0 = HTGetAddrInfo(host, default_port);
+    if (res0 == NULL) {
+	sprintf (line, "Unable to locate remote host %s.", host);
+	_HTProgress(line);
 	FREE(host);
 	FREE(line);
-	return status;
+	return HT_NO_DATA;
     }
 
     HTSprintf0 (&line, gettext("Making %s connection to %s."), protocol, host);
@@ -1379,199 +1432,214 @@
     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;
-    }
+    for (res = res0; res; res = res->ai_next) {
+	/*
+	**	Now, let's get a socket set up from the server for the data.
+	*/
+	*s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+	if (*s == -1) {
+	    char hostbuf[1024], portbuf[1024];
+	    getnameinfo(res->ai_addr, res->ai_addrlen,
+		    hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
+		    NI_NUMERICHOST|NI_NUMERICSERV);
+	    HTSprintf0 (&line, "socket failed: family %d addr %s port %s.",
+		    res->ai_family, hostbuf, portbuf);
+	    _HTProgress (line);
+	    FREE(line);
+	    continue;
+	}
 
 #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.
-    */
-    {
+	/*
+	**	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);
+	    int ret = fcntl(*s, F_SETFL, O_NONBLOCK);
 #else
-	int val = 1;
-	int ret = IOCTL(*s, FIONBIO, &val);
+	    int val = 1;
+	    int ret = IOCTL(*s, FIONBIO, &val);
 #endif /* USE_FCNTL */
-	if (ret == -1)
-	    _HTProgress(gettext("Could not make connection non-blocking."));
-    }
+	    if (ret == -1)
+		_HTProgress("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.
+	**	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.
 	*/
-	socks_bind_remoteAddr = soc_address.sin_addr.s_addr;
-    } else
+#ifdef SOCKS
+	if (socks_flag) {
+	    status = Rconnect(*s, res->ai_addr, res->ai_addrlen);
+	    /*
+	    **  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));
+	status = connect(*s, res->ai_addr, res->ai_addrlen);
 #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;
+	/*
+	**	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;
-	    }
+		/*
+		**	Protect against an infinite loop.
+		*/
+		if (tries++ >= 180000) {
+		    HTAlert("Connection failed for 180,000 tries.");
+		    FREE(line);
+		    freeaddrinfo(res0);
+		    return HT_NO_DATA;
+		}
 
 #ifdef _WINDOWS_NSL
-	    timeout.tv_sec = 100;
+		timeout.tv_sec = 100;
 #else
-	    timeout.tv_sec = 0;
+		timeout.tv_sec = 0;
 #endif /* _WINDOWS_NSL */
-	    timeout.tv_usec = 100000;
-	    FD_ZERO(&writefds);
-	    FD_SET(*s, &writefds);
+		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
+		if (socks_flag)
+		    ret = Rselect(FD_SETSIZE, NULL,
+				  (void *)&writefds, NULL, &timeout);
+		else
 #endif /* SOCKS */
-	    ret = select(FD_SETSIZE, NULL, (void *)&writefds, NULL, &timeout);
+		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;
+	       /*
+	       **  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.
+		**	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 {
+		    if (socks_flag) {
+			status = 0;
+		    } else
 #endif /* SOCKS */
-		status = connect(*s, (struct sockaddr*)&soc_address,
-				 sizeof(soc_address));
+		    {
+			status = connect(*s, res->ai_addr, res->ai_addrlen);
 #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)))
+			/*
+			**  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))
+			if ((status < 0) && (SOCKET_ERRNO == EISCONN))
 #endif /* UCX */
-		{
-		    status = 0;
-		}
+			{
+			    status = 0;
+			}
 
-		if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */
-		    ret = 0; /* keep going */
-		else
-		    break;
-#ifdef SOCKS
+			if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */
+			    ret = 0; /* keep going */
+			else
+			    break;
+		    }
 		}
-#endif /* SOCKS */
-	    }
 #ifdef SOCKS
-	    else if (!socks_flag)
+		else if (!socks_flag)
 #else
-	    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)) {
+		{
+		    /*
+		    **  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, res->ai_addr, res->ai_addrlen);
+		    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;
 		}
 	    }
-	    if (HTCheckForInterrupt()) {
-		CTRACE(tfp, "*** INTERRUPTED in middle of connect.\n");
-		status = HT_INTERRUPTED;
-		SOCKET_ERRNO = EINTR;
-		break;
-	    }
 	}
+
+	if (status < 0) {
+	    NETCLOSE(*s);
+	    *s = -1;
+	    continue;
+	}
+
+	break;
     }
 #endif /* !DJGPP */
-    if (status < 0) {
+    if (*s < 0) {
 	/*
 	**  The connect attempt failed or was interrupted,
 	**  so close up the socket.
@@ -1596,6 +1664,8 @@
 #endif /* !NO_IOCTL || USE_FCNTL */
 #endif /* !DOSPATH */
 
+    FREE(line);
+    freeaddrinfo(res0);
     return status;
 }
 
