zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: tcp cleanup and breakage
@ 2002-07-04  9:46 Clint Adams
  2002-07-04 10:23 ` Peter Stephenson
  2002-07-04 10:42 ` Borsenkow Andrej
  0 siblings, 2 replies; 7+ messages in thread
From: Clint Adams @ 2002-07-04  9:46 UTC (permalink / raw)
  To: zsh-workers

The highlights of this patch:

getaddrinfo and getnameinfo are used instead of gethostbyname2,
getipnodebyname, getservbyname, getprotobyname, inet_aton, inet_ntop,
and other fun functions.  This means that zsh/net/tcp and zsh/zftp
would be damn near useless on systems with broken or missing
getaddrinfo() in the absence of compatibility functions/workarounds.

ztcp now takes -4 and -6 on systems with IPv6 support.  These are also
largely useless due to the inconsistent implementation of IPv6 in tcp.

ztcp -l now takes an argument in the form bind.addr:port as well as the
previous syntax of ztcp -l port.

Neither zftp nor ztcp try multiple addresses anymore.  I had originally
moved the address-trying loop to tcp_connect(), where it proceeded to
cause me much anguish, so I removed it.  I imagine that a feature like
this could be desirable if non-blocking connects are implemented as
well.

Some other things may have been fixed or broken, and some inexplicable
changes in whitespace occurred.  I won't commit this.

Index: zshconfig.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
retrieving revision 1.28
diff -u -r1.28 zshconfig.ac
--- zshconfig.ac	6 May 2002 14:50:11 -0000	1.28
+++ zshconfig.ac	4 Jul 2002 09:43:14 -0000
@@ -934,7 +934,7 @@
 	       waitpid wait3 \
 	       sigaction sigblock sighold sigrelse sigsetmask sigprocmask \
 	       killpg setpgid setpgrp tcsetpgrp tcgetattr nice \
-	       gethostname gethostbyname2 getipnodebyname \
+	       gethostname getaddrinfo \
 	       inet_aton inet_pton inet_ntop \
 	       getlogin getpwent getpwnam getpwuid getgrgid getgrnam \
 	       initgroups nis_list \
Index: Src/Modules/tcp.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/tcp.c,v
retrieving revision 1.32
diff -u -r1.32 tcp.c
--- Src/Modules/tcp.c	5 Jun 2002 21:02:37 -0000	1.32
+++ Src/Modules/tcp.c	4 Jul 2002 09:43:16 -0000
@@ -48,10 +48,6 @@
 # undef HAVE_POLL
 #endif
 
-#ifdef USE_LOCAL_H_ERRNO
-int h_errno;
-#endif
-
 /* We use the RFC 2553 interfaces.  If the functions don't exist in the
  * library, simulate them. */
 
@@ -64,148 +60,7 @@
 #endif
 
 /**/
-#ifndef HAVE_INET_NTOP
-
-/**/
-mod_export char const *
-zsh_inet_ntop(int af, void const *cp, char *buf, size_t len)
-{       
-    if (af != AF_INET) {
-	errno = EAFNOSUPPORT;
-	return NULL;
-    } 
-    if (len < INET_ADDRSTRLEN) {
-	errno = ENOSPC;
-	return NULL;
-    }
-    strcpy(buf, inet_ntoa(*(struct in_addr *)cp));
-    return buf;
-}
-
-/**/
-#else /* !HAVE_INET_NTOP */
-
-/**/
-# define zsh_inet_ntop inet_ntop
-
-/**/
-#endif /* !HAVE_INET_NTOP */
-
-/**/
-#ifndef HAVE_INET_ATON
-
-# ifndef INADDR_NONE
-#  define INADDR_NONE 0xffffffffUL
-# endif
-
-/**/
-mod_export int zsh_inet_aton(char const *src, struct in_addr *dst)
-{
-    return (dst->s_addr = inet_addr(src)) != INADDR_NONE;
-}
-
-/**/
-#else /* !HAVE_INET_ATON */
-
-/**/
-# define zsh_inet_aton inet_aton
-
-/**/
-#endif /* !HAVE_INET_ATON */
-
-/**/
-#ifndef HAVE_INET_PTON
-
-/**/
-mod_export int
-zsh_inet_pton(int af, char const *src, void *dst)
-{
-    if (af != AF_INET) {
-	errno = EAFNOSUPPORT;
-	return -1;
-    }
-    return !!zsh_inet_aton(src, dst);
-}
-
-#else /* !HAVE_INET_PTON */
-
-# define zsh_inet_pton inet_pton
-
-/**/
-#endif /* !HAVE_INET_PTON */
-
-/**/
-#ifndef HAVE_GETIPNODEBYNAME
-
-/**/
-# ifndef HAVE_GETHOSTBYNAME2
-
-/**/
-mod_export struct hostent *
-zsh_gethostbyname2(char const *name, int af)
-{
-    if (af != AF_INET) {
-	h_errno = NO_RECOVERY;
-	return NULL;
-    }
-    return gethostbyname(name);
-}
-
-/**/
-#else /* !HAVE_GETHOSTBYNAME2 */
-
-/**/
-# define zsh_gethostbyname2 gethostbyname2
-
-/**/
-# endif /* !HAVE_GETHOSTBYNAME2 */
-
-/* note: this is not a complete implementation.  If ignores the flags,
-   and does not provide the memory allocation of the standard interface.
-   Each returned structure will overwrite the previous one. */
-
-/**/
-mod_export struct hostent *
-zsh_getipnodebyname(char const *name, int af, int flags, int *errorp)
-{
-    static struct hostent ahe;
-    static char nbuf[16];
-    static char *addrlist[] = { nbuf, NULL };
-# ifdef SUPPORT_IPV6
-    static char pbuf[INET6_ADDRSTRLEN];
-# else
-    static char pbuf[INET_ADDRSTRLEN];
-# endif
-    struct hostent *he;
-    if (zsh_inet_pton(af, name, nbuf) == 1) {
-	zsh_inet_ntop(af, nbuf, pbuf, sizeof(pbuf));
-	ahe.h_name = pbuf;
-	ahe.h_aliases = addrlist+1;
-	ahe.h_addrtype = af;
-	ahe.h_length = (af == AF_INET) ? 4 : 16;
-	ahe.h_addr_list = addrlist;
-	return &ahe;
-    }
-    he = zsh_gethostbyname2(name, af);
-    if (!he)
-	*errorp = h_errno;
-    return he;
-}
-
-/**/
-mod_export void
-freehostent(struct hostent *ptr)
-{
-}
-
-/**/
-#else /* !HAVE_GETIPNODEBYNAME */
-
-/**/
-# define zsh_getipnodebyname getipnodebyname
-
-/**/
-#endif /* !HAVE_GETIPNODEBYNAME */
+#ifdef HAVE_GETADDRINFO
 
 LinkList ztcp_sessions;
 
@@ -310,39 +165,32 @@
 
 /**/
 mod_export int
-tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port)
+tcp_connect(Tcp_session sess, struct addrinfo *zai)
 {
-    int salen;
+    memcpy(&(sess->peer), zai->ai_addr, zai->ai_addrlen);
 #ifdef SUPPORT_IPV6
-    if (zhost->h_addrtype==AF_INET6) {
-	memcpy(&(sess->peer.in6.sin6_addr), addrp, zhost->h_length);
-	sess->peer.in6.sin6_port = d_port;
+    if (zai->ai_family == PF_INET6) {
+	sess->peer.in6.sin6_family = zai->ai_family;
 	sess->peer.in6.sin6_flowinfo = 0;
 # ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
 	sess->peer.in6.sin6_scope_id = 0;
+    }
 # endif
-	sess->peer.in6.sin6_family = zhost->h_addrtype;
-	salen = sizeof(struct sockaddr_in6);
-    } else
+    else
 #endif /* SUPPORT_IPV6 */
-    {
-	memcpy(&(sess->peer.in.sin_addr), addrp, zhost->h_length);
-	sess->peer.in.sin_port = d_port;
-	sess->peer.in.sin_family = zhost->h_addrtype;
-	salen = sizeof(struct sockaddr_in);
-    }
+	sess->peer.in.sin_family = zai->ai_family;
 
-    return connect(sess->fd, (struct sockaddr *)&(sess->peer), salen);
+    return connect(sess->fd, (struct sockaddr *)&(sess->peer), zai->ai_addrlen);
 }
 
 static int
 bin_ztcp(char *nam, char **args, char *ops, int func)
 {
-    int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0;
+    int gai_errno, err=1, force=0, verbose=0, test=0, targetfd=0,
+    	pf = PF_INET;
     SOCKLEN_T  len;
-    char **addrp, *desthost, *localname, *remotename, **dargs;
-    struct hostent *zthost = NULL, *ztpeer = NULL;
-    struct servent *srv;
+    char *desthost, *destservice, *localname, *remotename, **dargs;
+    struct addrinfo *zthost = NULL, zthints;
     Tcp_session sess = NULL;
 
     if (ops['f'])
@@ -354,6 +202,14 @@
     if (ops['t'])
         test = 1;
 
+#ifdef SUPPORT_IPV6
+    if (ops['4'])
+	pf = PF_INET;
+
+    if (ops['6'])
+	pf = PF_INET6;
+#endif /* SUPPORT_IPV6 */
+
     if (ops['d']) {
 	targetfd = atoi(args[0]);
 	dargs = args + 1;
@@ -396,44 +252,52 @@
 	}
     }
     else if (ops['l']) {
-	int lport = 0;
+	char *localhost, *localport;
 
 	if (!dargs[0]) {
 	    zwarnnam(nam, "-l requires an argument", NULL, 0);
 	    return 1;
 	}
 
-	srv = getservbyname(dargs[0], "tcp");
-	if (srv)
-	    lport = srv->s_port;
-	else
-	    lport = htons(atoi(dargs[0]));
-	if (!lport) { zwarnnam(nam, "bad service name or port number", NULL, 0);
-	return 1;
+	if ((localport = memchr(localhost = dargs[0], (int)':', strlen(dargs[0]))) == NULL) {
+	    localhost = dupstring("0.0.0.0");
+	    localport = dargs[0];
+	}
+	else {
+	    *localport++ = '\0';
+	}
+
+	memset(&zthints, 0, sizeof(zthints));
+	zthints.ai_protocol = IPPROTO_TCP;
+	zthints.ai_flags = AI_CANONNAME;
+	zthints.ai_socktype = SOCK_STREAM;
+
+	if ((gai_errno = zsh_getaddrinfo(localhost, localport, &zthints, &zthost))) {
+	    zwarnnam(nam, "bad service name, port number, or hostname: %s: %d", dargs[0], gai_errno);
+	    return 1;
 	}
-	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN);
+	sess = tcp_socket(pf, SOCK_STREAM, IPPROTO_IP, ZTCP_LISTEN);
 
 	if (!sess) {
 	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
 	    return 1;
 	}
+	if ((sess->fd) == -1) {
+	    zwarnnam(nam, "socket error: %e", NULL, errno);
+	    return 1;
+	}
 #ifdef SO_OOBINLINE
 	len = 1;
 	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
 #endif
-	if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr)))
-	{
-	    zwarnnam(nam, "bad address: %s", "0.0.0.0", 0);
-	    return 1;
-	}
 
-	sess->sock.in.sin_family = AF_INET;
-	sess->sock.in.sin_port = lport;
+	memcpy(&(sess->sock.a), zthost->ai_addr, sizeof(struct sockaddr));
 
+	freeaddrinfo(zthost);
 
 	if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in)))
 	{
-	    zwarnnam(nam, "could not bind to %s: %e", "0.0.0.0", errno);
+	    zwarnnam(nam, "could not bind to %s: %e", dargs[0], errno);
 	    tcp_close(sess);
 	    return 1;
 	}
@@ -561,16 +425,21 @@
 
 		if (sess->fd != -1)
 		{
-		    zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET);
-		    if (zthost)
-			localname = zthost->h_name;
-		    else
-			localname = ztrdup(inet_ntoa(sess->sock.in.sin_addr));
-		    ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET);
-		    if (ztpeer)
-			remotename = ztpeer->h_name;
-		    else
-			remotename = ztrdup(inet_ntoa(sess->peer.in.sin_addr));
+		    char *hostname;
+		    hostname = malloc(255);
+
+		    if (!zsh_getnameinfo((struct sockaddr *)&(sess->sock.a), sizeof(sess->sock.a), hostname, 255, NULL, 0, 0))
+			localname = hostname;
+		    else {
+			localname = ztrdup("ERR");
+		    }
+
+		    if (!zsh_getnameinfo((struct sockaddr *)&(sess->peer.a), sizeof(sess->peer.a), hostname, 255, NULL, 0, 0))
+			remotename = hostname;
+		    else {
+			remotename = ztrdup("ERR");
+		    }
+
 		    if (ops['L']) {
 			int schar;
 			if (sess->flags & ZTCP_ZFTP)
@@ -599,26 +468,30 @@
 	    return 0;
 	}
 	else if (!dargs[1]) {
-	    destport = htons(23);
+	    destservice = ztrdup("telnet");
 	}
 	else {
-
-	    srv = getservbyname(dargs[1],"tcp");
-	    if (srv)
-		destport = srv->s_port;
-	    else
-		destport = htons(atoi(dargs[1]));
+	    destservice = ztrdup(dargs[1]);
 	}
-	
+
+	memset(&zthints, 0, sizeof(zthints));
+	zthints.ai_protocol = IPPROTO_TCP;
+	zthints.ai_flags = AI_CANONNAME;
+
 	desthost = ztrdup(dargs[0]);
-	
-	zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno);
-	if (!zthost || errflag) {
-	    zwarnnam(nam, "host resolution failure: %s", desthost, 0);
+
+	gai_errno = zsh_getaddrinfo(desthost, destservice, &zthints, &zthost);
+
+	zsfree(desthost);
+	zsfree(destservice);
+
+	if (gai_errno) {
+	    /* gai_strerror could be more useful here */
+	    zwarnnam(nam, "host/service resolution failure: %s: %d", desthost, gai_errno);
 	    return 1;
 	}
 	
-	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);
+	sess = tcp_socket(pf, SOCK_STREAM, IPPROTO_IP, 0);
 
 	if (!sess) {
 	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
@@ -632,23 +505,13 @@
 
 	if (sess->fd < 0) {
 	    zwarnnam(nam, "socket creation failed: %e", NULL, errno);
-	    zsfree(desthost);
 	    zts_delete(sess);
 	    return 1;
 	}
 	
-	for (addrp = zthost->h_addr_list; err && *addrp; addrp++) {
-	    if (zthost->h_length != 4)
-		zwarnnam(nam, "address length mismatch", NULL, 0);
-	    do {
-		err = tcp_connect(sess, *addrp, zthost, destport);
-	    } while (err && errno == EINTR && !errflag);
-	}
-	
-	if (err) {
+	if ((err = tcp_connect(sess, zthost))) {
 	    zwarnnam(nam, "connection failed: %e", NULL, errno);
 	    tcp_close(sess);
-	    zsfree(desthost);
 	    return 1;
 	}
 	else
@@ -662,7 +525,7 @@
 
 	    if (verbose)
 		printf("%s:%d is now on fd %d\n",
-			desthost, destport, sess->fd);
+		       zthost->ai_canonname, ntohs(((struct sockaddr_in *)(zthost->ai_addr))->sin_port), sess->fd);
 	}
 	
 	zsfree(desthost);
@@ -672,9 +535,16 @@
 }
 
 static struct builtin bintab[] = {
+#ifdef SUPPORT_IPV6
+    BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acdflLtv46", NULL),
+#else
     BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acdflLtv", NULL),
+#endif /* SUPPORT_IPV6 */
 };
 
+/**/
+#endif /* HAVE_GETADDRINFO */
+
 /* The load/unload routines required by the zsh library interface */
 
 /**/
@@ -688,8 +558,12 @@
 int
 boot_(Module m)
 {
+#ifdef HAVE_GETADDRINFO
     ztcp_sessions = znewlinklist();
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+#else
+    return 1;
+#endif /* HAVE_GETADDRINFO */
 }
 
 
@@ -697,9 +571,11 @@
 int
 cleanup_(Module m)
 {
+#ifdef HAVE_GETADDRINFO
     tcp_cleanup();
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     freelinklist(ztcp_sessions, (FreeFunc) ztcp_free_session);
+#endif /* HAVE_GETADDRINFO */
     return 0;
 }
 
Index: Src/Modules/tcp.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/tcp.h,v
retrieving revision 1.6
diff -u -r1.6 tcp.h
--- Src/Modules/tcp.h	2 Oct 2001 02:35:01 -0000	1.6
+++ Src/Modules/tcp.h	4 Jul 2002 09:43:16 -0000
@@ -93,3 +93,6 @@
 #ifndef INET6_ADDRSTRLEN
 # define INET6_ADDRSTRLEN 46
 #endif
+
+#define zsh_getnameinfo getnameinfo
+#define zsh_getaddrinfo getaddrinfo
Index: Src/Modules/zftp.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/zftp.c,v
retrieving revision 1.27
diff -u -r1.27 zftp.c
--- Src/Modules/zftp.c	15 May 2002 20:38:18 -0000	1.27
+++ Src/Modules/zftp.c	4 Jul 2002 09:43:22 -0000
@@ -639,7 +639,7 @@
 	    case WILL:
 	    case WONT:
 		ch = fgetc(zfsess->cin);
-		/* whatever it wants to do, stop it. */
+				/* whatever it wants to do, stop it. */
 		cmdbuf[0] = (char)IAC;
 		cmdbuf[1] = (char)DONT;
 		cmdbuf[2] = ch;
@@ -649,7 +649,7 @@
 	    case DO:
 	    case DONT:
 		ch = fgetc(zfsess->cin);
-		/* well, tough, we're not going to. */
+				/* well, tough, we're not going to. */
 		cmdbuf[0] = (char)IAC;
 		cmdbuf[1] = (char)WONT;
 		cmdbuf[2] = ch;
@@ -657,7 +657,7 @@
 		continue;
 
 	    case EOF:
-		/* strange machine. */
+				/* strange machine. */
 		zcfinish = 2;
 		break;
 
@@ -828,7 +828,7 @@
      * We use the fd directly; there's no point even using
      * stdio with line buffering, since we always send the
      * complete line in one string anyway.
-     */
+	 */
     int ret, tmout;
 
     if (!zfsess->control)
@@ -1014,8 +1014,11 @@
 	if(zdsockp->a.sa_family == AF_INET6) {
 	    /* see RFC 2428 for explanation */
 	    strcpy(portcmd, "EPRT |2|");
-	    zsh_inet_ntop(AF_INET6, &zdsockp->in6.sin6_addr,
-			  portcmd+8, INET6_ADDRSTRLEN);
+
+	    zsh_getnameinfo(&(zdsockp->a), sizeof(struct sockaddr),
+			    (char *)portcmd+8, INET6_ADDRSTRLEN,
+			    NULL, 0, NI_NUMERICHOST);
+
 	    sprintf(strchr(portcmd, 0), "|%u|\r\n",
 		    (unsigned)ntohs(zdsockp->in6.sin6_port));
 	} else
@@ -1514,7 +1517,7 @@
 	if (n > 0) {
 	    char *iptr;
 	    if (toasc) {
-		/* \n -> \r\n it shouldn't happen to a dog. */
+				/* \n -> \r\n it shouldn't happen to a dog. */
 		char *iptr = ascbuf, *optr = lsbuf;
 		int cnt = n;
 		while (cnt--) {
@@ -1526,7 +1529,7 @@
 		}
 	    }
 	    if (fromasc && (iptr = memchr(lsbuf, '\r', n))) {
-		/* \r\n -> \n */
+				/* \r\n -> \n */
 		char *optr = iptr;
 		int cnt = n - (iptr - lsbuf);
 		while (cnt--) {
@@ -1542,13 +1545,13 @@
 	    sofar += n;
 
 	    for (;;) {
-		/*
-		 * in principle, write can be interrupted after
-		 * safely writing some bytes, and will return the
-		 * number already written, which may not be the
-		 * complete buffer.  so make this robust.  they call me
-		 * `robustness stephenson'.  in my dreams.
-		 */
+				/*
+				 * in principle, write can be interrupted after
+				 * safely writing some bytes, and will return the
+				 * number already written, which may not be the
+				 * complete buffer.  so make this robust.  they call me
+				 * `robustness stephenson'.  in my dreams.
+				 */
 		int newn = write_ptr(fdout, optr, n, wtmout);
 		if (newn == n)
 		    break;
@@ -1696,13 +1699,11 @@
 static int
 zftp_open(char *name, char **args, int flags)
 {
-    struct protoent *zprotop;
-    struct servent *zservp;
-    struct hostent *zhostp = NULL;
-    char **addrp, *fname;
+    struct addrinfo *zhostp = NULL, zthints;
+    char *fname;
     int err, tmout;
     SOCKLEN_T  len;
-    int herrno, af, hlen;
+    int gai_errno, af, hlen;
 
     if (!*args) {
 	if (zfsess->userparams)
@@ -1721,15 +1722,6 @@
     if (zfsess->control)
 	zfclose(0);
 
-    /* this is going to give 0.  why bother? */
-    zprotop = getprotobyname("tcp");
-    zservp = getservbyname("ftp", "tcp");
-
-    if (!zprotop || !zservp) {
-	zwarnnam(name, "Somebody stole FTP!", NULL, 0);
-	return 1;
-    }
-
     /* don't try talking to server yet */
     zcfinish = 2;
 
@@ -1762,20 +1754,20 @@
 # define FAILED() do { } while(0)
 #endif
     {
-	zhostp = zsh_getipnodebyname(args[0], af, 0, &herrno);
-	if (!zhostp || errflag) {
-	    /* should use herror() here if available, but maybe
-	     * needs configure test. on AIX it's present but not
-	     * in headers.
-	     * 
-	     * on the other hand, herror() is obsolete
-	     */
+
+	memset(&zthints, 0, sizeof(zthints));
+	zthints.ai_protocol = IPPROTO_TCP;
+	zthints.ai_flags = AI_CANONNAME;
+
+
+	if ((gai_errno = zsh_getaddrinfo(args[0], "ftp", &zthints, &zhostp))) {
+	    /* could use gai_strerror() */
 	    FAILED();
-	    zwarnnam(name, "host not found: %s", args[0], 0);
+	    zwarnnam(name, "host not found: %s: %d", args[0], gai_errno);
 	    alarm(0);
 	    return 1;
 	}
-	zfsetparam("ZFTP_HOST", ztrdup(zhostp->h_name), ZFPM_READONLY);
+	zfsetparam("ZFTP_HOST", ztrdup(zhostp->ai_canonname), ZFPM_READONLY);
 
 #ifdef SUPPORT_IPV6
 	if(af == AF_INET6) {
@@ -1793,7 +1785,7 @@
 		tcp_close(zfsess->control);
 		zfsess->control = NULL;
 	    }
-	    freehostent(zhostp);
+	    freeaddrinfo(zhostp);
 	    zfunsetparam("ZFTP_HOST");
 	    FAILED();
 	    zwarnnam(name, "socket failed: %e", NULL, errno);
@@ -1810,18 +1802,10 @@
 
 	err = 1;
 
-	/* try all possible IP's */
-	for (addrp = zhostp->h_addr_list; err && *addrp; addrp++) {
-	    if(hlen != zhostp->h_length)
-		zwarnnam(name, "address length mismatch", NULL, 0);
-	    do {
-		err = tcp_connect(zfsess->control, *addrp, zhostp, zservp->s_port);
-	    } while (err && errno == EINTR && !errflag);
-	    /* you can check whether it's worth retrying here */
-	}
+	err = tcp_connect(zfsess->control, zhostp);
 
 	if (err) {
-	    freehostent(zhostp);
+	    freeaddrinfo(zhostp);
 	    zfclose(0);
 	    FAILED();
 	    zwarnnam(name, "connect failed: %e", NULL, errno);
@@ -1838,11 +1822,12 @@
 #else
 	char pbuf[INET_ADDRSTRLEN];
 #endif
-	addrp--;
-	zsh_inet_ntop(af, *addrp, pbuf, sizeof(pbuf));
+	zsh_getnameinfo(&(zfsess->control->peer.a), sizeof(struct sockaddr),
+			pbuf, sizeof(pbuf), NULL, 0, NI_NUMERICHOST);
+
 	zfsetparam("ZFTP_IP", ztrdup(pbuf), ZFPM_READONLY);
     }
-    freehostent(zhostp);
+    freeaddrinfo(zhostp);
     /* now we can talk to the control connection */
     zcfinish = 0;
 
@@ -2163,13 +2148,13 @@
 		;
 	    systype = ztrduppfx(ptr, eptr-ptr);
 	    if (!strncmp(systype, "UNIX Type: L8", 13)) {
-		/*
-		 * Use binary for transfers.  This simple test saves much
-		 * hassle for all concerned, particularly me.
-		 *
-		 * We could set this based just on the UNIX part,
-		 * but I don't really know the consequences of that.
-		 */
+				/*
+				 * Use binary for transfers.  This simple test saves much
+				 * hassle for all concerned, particularly me.
+				 *
+				 * We could set this based just on the UNIX part,
+				 * but I don't really know the consequences of that.
+				 */
 		zfstatusp[zfsessno] |= ZFST_IMAG;
 	    }
 	    zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY);
@@ -2262,10 +2247,10 @@
     int ret;
 
     /*
-     * RFC959 says this must be ASCII or EBCDIC, not image format.
-     * I rather suspect on a UNIX server we get away handsomely
-     * with doing everything, including this, as image.
-     */
+	 * RFC959 says this must be ASCII or EBCDIC, not image format.
+	 * I rather suspect on a UNIX server we get away handsomely
+	 * with doing everything, including this, as image.
+	 */
     zfsettype(ZFST_ASCI);
 
     cmd = zfargstring((flags & ZFTP_NLST) ? "NLST" : "LIST", args);
@@ -2528,9 +2513,9 @@
 	    if ((!(zfprefs & ZFPF_DUMB) &&
 		 (zfstatusp[zfsessno] & (ZFST_NOSZ|ZFST_TRSZ)) != ZFST_TRSZ)
 		|| !recv) {
-		/* the final 0 is a local fd to fstat if recv is zero */
+				/* the final 0 is a local fd to fstat if recv is zero */
 		zfstats(*args, recv, &sz, NULL, 0);
-		/* even if it doesn't support SIZE, it may tell us */
+				/* even if it doesn't support SIZE, it may tell us */
 		if (recv && sz == -1)
 		    getsize = 1;
 	    } else
@@ -3029,22 +3014,22 @@
 	for (ptr = prefs; *ptr; ptr++) {
 	    switch (toupper(STOUC(*ptr))) {
 	    case 'S':
-		/* sendport */
+				/* sendport */
 		zfprefs |= ZFPF_SNDP;
 		break;
 
 	    case 'P':
-		/*
-		 * passive
-		 * If we have already been told to use sendport mode,
-		 * we're never going to use passive mode.
-		 */
+				/*
+				 * passive
+				 * If we have already been told to use sendport mode,
+				 * we're never going to use passive mode.
+				 */
 		if (!(zfprefs & ZFPF_SNDP))
 		    zfprefs |= ZFPF_PASV;
 		break;
 
 	    case 'D':
-		/* dumb */
+				/* dumb */
 		zfprefs |= ZFPF_DUMB;
 		break;
 
@@ -3082,7 +3067,7 @@
     /*
      * There are various parameters hanging around, but they're
      * all non-special so are entirely non-life-threatening.
-     */
+	 */
     LinkNode nptr;
     Zftp_session cursess = zfsess;
     for (zfsessno = 0, nptr = firstnode(zfsessions); nptr;
@@ -3090,9 +3075,9 @@
 	zfsess = (Zftp_session)nptr->dat;
 	zfclosedata();
 	/*
-	 * When closing the current session, do the usual unsetting,
-	 * otherwise don't.
-	 */
+		 * When closing the current session, do the usual unsetting,
+		 * otherwise don't.
+		 */
 	zfclose(zfsess != cursess);
     }
     zsfree(lastmsg);


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: tcp cleanup and breakage
  2002-07-04  9:46 PATCH: tcp cleanup and breakage Clint Adams
@ 2002-07-04 10:23 ` Peter Stephenson
  2002-07-04 17:01   ` Clint Adams
  2002-07-04 10:42 ` Borsenkow Andrej
  1 sibling, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2002-07-04 10:23 UTC (permalink / raw)
  To: Zsh hackers list

Clint Adams wrote:
> Some other things may have been fixed or broken, and some inexplicable
> changes in whitespace occurred.  I won't commit this.

No point sending a full patch at the moment (translation: I'm too lazy
to send a diff without CVS to make it for me), but desthost is being freed
twice in the final `else' of bin_ztcp.  It should probably look like:

	desthost = ztrdup(dargs[0]);

	gai_errno = zsh_getaddrinfo(desthost, destservice, &zthints, &zthost);

	zsfree(destservice);

	if (gai_errno) {
	    /* gai_strerror could be more useful here */
	    zwarnnam(nam, "host/service resolution failure: %s: %d", desthost, gai_errno);
	    zsfree(desthost);
	    return 1;
	}
	zsfree(desthost);

and remove the zsfree(desthost) right at the end of that block.  Unless
it doesn't need ztrdup'ing at all any more.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: PATCH: tcp cleanup and breakage
  2002-07-04  9:46 PATCH: tcp cleanup and breakage Clint Adams
  2002-07-04 10:23 ` Peter Stephenson
@ 2002-07-04 10:42 ` Borsenkow Andrej
  2002-07-04 10:56   ` Peter Stephenson
  1 sibling, 1 reply; 7+ messages in thread
From: Borsenkow Andrej @ 2002-07-04 10:42 UTC (permalink / raw)
  To: 'Clint Adams', zsh-workers

> getaddrinfo and getnameinfo are used instead of gethostbyname2,
> getipnodebyname, getservbyname, getprotobyname, inet_aton, inet_ntop,
> and other fun functions.  This means that zsh/net/tcp and zsh/zftp
> would be damn near useless on systems with broken or missing
> getaddrinfo() in the absence of compatibility functions/workarounds.
> 

Why?

-andrej


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: tcp cleanup and breakage
  2002-07-04 10:42 ` Borsenkow Andrej
@ 2002-07-04 10:56   ` Peter Stephenson
  2002-07-04 16:59     ` Clint Adams
  0 siblings, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2002-07-04 10:56 UTC (permalink / raw)
  To: Zsh hackers list

Borsenkow Andrej wrote:
> > getaddrinfo and getnameinfo are used instead of gethostbyname2,
> > getipnodebyname, getservbyname, getprotobyname, inet_aton, inet_ntop,
> > and other fun functions.  This means that zsh/net/tcp and zsh/zftp
> > would be damn near useless on systems with broken or missing
> > getaddrinfo() in the absence of compatibility functions/workarounds.
> > 
> 
> Why?

I presume this is to make the core code neater and move compatilibity
code somewhere else.  But it won't work under cygwin until there are
such functions, so they'll have to be written before this gets
committed.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: tcp cleanup and breakage
  2002-07-04 10:56   ` Peter Stephenson
@ 2002-07-04 16:59     ` Clint Adams
  2002-07-04 22:31       ` Clint Adams
  0 siblings, 1 reply; 7+ messages in thread
From: Clint Adams @ 2002-07-04 16:59 UTC (permalink / raw)
  To: Zsh hackers list

> I presume this is to make the core code neater and move compatilibity
> code somewhere else.  But it won't work under cygwin until there are
> such functions, so they'll have to be written before this gets
> committed.

Also, getaddrinfo() is required by SUSv3, whereas
gethostbyaddr/gethostbyname are deprecated, and
getipnodebyname/getipnodebyaddr aren't even mentioned.
Since that obviously has no practical merit, getaddrinfo()
facilitates support of IPv6.  In addition, with the patch applied,
there're more places that accept service names in lieu of TCP port
numbers.  Nothing that couldn't be achieved by other methods and a great
deal more difficulty.

I imagine that simplified compatibility functions should be relatively
easy, however.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: tcp cleanup and breakage
  2002-07-04 10:23 ` Peter Stephenson
@ 2002-07-04 17:01   ` Clint Adams
  0 siblings, 0 replies; 7+ messages in thread
From: Clint Adams @ 2002-07-04 17:01 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

> No point sending a full patch at the moment (translation: I'm too lazy
> to send a diff without CVS to make it for me), but desthost is being freed
> twice in the final `else' of bin_ztcp.  It should probably look like:

I've also got a nagging feeling that I forgot to free something else
somewhere.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: tcp cleanup and breakage
  2002-07-04 16:59     ` Clint Adams
@ 2002-07-04 22:31       ` Clint Adams
  0 siblings, 0 replies; 7+ messages in thread
From: Clint Adams @ 2002-07-04 22:31 UTC (permalink / raw)
  To: Zsh hackers list

> I imagine that simplified compatibility functions should be relatively
> easy, however.

So these don't do IPv6, aren't very robust, and have other flaws, but
they do seem to function.

Index: zshconfig.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
retrieving revision 1.28
diff -w -u -r1.28 zshconfig.ac
--- zshconfig.ac	6 May 2002 14:50:11 -0000	1.28
+++ zshconfig.ac	4 Jul 2002 22:22:46 -0000
@@ -934,8 +934,7 @@
 	       waitpid wait3 \
 	       sigaction sigblock sighold sigrelse sigsetmask sigprocmask \
 	       killpg setpgid setpgrp tcsetpgrp tcgetattr nice \
-	       gethostname gethostbyname2 getipnodebyname \
-	       inet_aton inet_pton inet_ntop \
+	       gethostname getaddrinfo freeaddrinfo getnameinfo \
 	       getlogin getpwent getpwnam getpwuid getgrgid getgrnam \
 	       initgroups nis_list \
 	       setuid seteuid setreuid setresuid setsid \
Index: Src/Modules/tcp.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/tcp.c,v
retrieving revision 1.32
diff -w -u -r1.32 tcp.c
--- Src/Modules/tcp.c	5 Jun 2002 21:02:37 -0000	1.32
+++ Src/Modules/tcp.c	4 Jul 2002 22:22:49 -0000
@@ -48,10 +48,6 @@
 # undef HAVE_POLL
 #endif
 
-#ifdef USE_LOCAL_H_ERRNO
-int h_errno;
-#endif
-
 /* We use the RFC 2553 interfaces.  If the functions don't exist in the
  * library, simulate them. */
 
@@ -64,148 +60,146 @@
 #endif
 
 /**/
-#ifndef HAVE_INET_NTOP
+#ifndef HAVE_GETADDRINFO
+
+/* We presume if getaddrinfo() is absent, we have gethostbyname and
+ * getservbyname, without testing for them.  We also force IPv4, do
+ * very little error checking, and don't ever return a linked list.
+ */
 
 /**/
-mod_export char const *
-zsh_inet_ntop(int af, void const *cp, char *buf, size_t len)
+mod_export int
+zsh_getaddrinfo(const char *node, const char *service,
+		const struct addrinfo *hints, struct addrinfo **res)
 {       
-    if (af != AF_INET) {
-	errno = EAFNOSUPPORT;
-	return NULL;
+    struct addrinfo *ai;
+
+    ai = zalloc(sizeof(struct addrinfo));
+    ai->ai_family = PF_INET;
+    ai->ai_socktype = SOCK_STREAM;
+    ai->ai_protocol = IPPROTO_IP;
+    ai->ai_next = NULL;
+
+    *res = ai;
+
+    if (node) {
+	struct hostent *he;
+	struct sockaddr_in *sin;
+	char *s;
+
+	he = gethostbyname(node);
+	if (he) {
+	    if ((hints->ai_flags & AI_CANONNAME) == AI_CANONNAME) {
+		s = ztrdup(he->h_name);
+		ai->ai_canonname = s;
     } 
-    if (len < INET_ADDRSTRLEN) {
-	errno = ENOSPC;
-	return NULL;
+			
+	    sin = (struct sockaddr_in *)ai->ai_addr = zalloc(sizeof(struct sockaddr));
+	    sin->sin_addr.s_addr = ((struct in_addr *)he->h_addr_list[0])->s_addr;
+	    sin->sin_family = AF_INET;
+	    sin->sin_port = 0;
+	    ai->ai_addrlen = sizeof(struct sockaddr_in);
     }
-    strcpy(buf, inet_ntoa(*(struct in_addr *)cp));
-    return buf;
 }
 
-/**/
-#else /* !HAVE_INET_NTOP */
+    if (service) {
+	struct servent *se;
 
-/**/
-# define zsh_inet_ntop inet_ntop
+	se = getservbyname(service, "tcp");
 
-/**/
-#endif /* !HAVE_INET_NTOP */
+	if (!(ai->ai_addr))
+	    ai->ai_addr = zalloc(sizeof(struct sockaddr));
 
-/**/
-#ifndef HAVE_INET_ATON
+	if (se)
+	    ((struct sockaddr_in *)ai->ai_addr)->sin_port = se->s_port;
+	else
+	    ((struct sockaddr_in *)ai->ai_addr)->sin_port = htons(atoi(service));
+    }
 
-# ifndef INADDR_NONE
-#  define INADDR_NONE 0xffffffffUL
-# endif
 
-/**/
-mod_export int zsh_inet_aton(char const *src, struct in_addr *dst)
-{
-    return (dst->s_addr = inet_addr(src)) != INADDR_NONE;
+    return 0;
 }
 
 /**/
-#else /* !HAVE_INET_ATON */
-
+#else /* HAVE_GETADDRINFO */
 /**/
-# define zsh_inet_aton inet_aton
-
+#define zsh_getaddrinfo getaddrinfo
 /**/
-#endif /* !HAVE_INET_ATON */
+#endif /* HAVE_GETADDRINFO */
 
 /**/
-#ifndef HAVE_INET_PTON
+#ifndef HAVE_GETNAMEINFO
+
+/* We presume if getnameinfo() is absent, we have gethostbyaddr and
+ * getservbyport, without testing for them.  We also force IPv4, do very
+ * little error checking, and return 1 for all errors.
+ */
 
 /**/
 mod_export int
-zsh_inet_pton(int af, char const *src, void *dst)
+zsh_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
+		size_t hostlen, char *serv, size_t servlen, int flags)
 {
-    if (af != AF_INET) {
-	errno = EAFNOSUPPORT;
-	return -1;
-    }
-    return !!zsh_inet_aton(src, dst);
-}
-
-#else /* !HAVE_INET_PTON */
-
-# define zsh_inet_pton inet_pton
+    if (sa == NULL)
+	return 1;
 
-/**/
-#endif /* !HAVE_INET_PTON */
+    if (host) {
+	struct hostent *he;
 
-/**/
-#ifndef HAVE_GETIPNODEBYNAME
+	he = gethostbyaddr((char *)sa, (int)salen, AF_INET);
 
-/**/
-# ifndef HAVE_GETHOSTBYNAME2
+	if (he)
+	    memcpy(host, he->h_name, hostlen);
+	else
+	    return 1;
+    }
 
-/**/
-mod_export struct hostent *
-zsh_gethostbyname2(char const *name, int af)
+    if (serv)
 {
-    if (af != AF_INET) {
-	h_errno = NO_RECOVERY;
-	return NULL;
+	struct servent *se;
+
+	se = getservbyport(((struct sockaddr_in *)sa)->sin_port, "tcp");
+	if (se)
+	    memcpy(serv, se->s_name, servlen);
+	else
+	    return 1;
     }
-    return gethostbyname(name);
+
+    return 0;
 }
 
 /**/
-#else /* !HAVE_GETHOSTBYNAME2 */
-
+#else /* HAVE_GETNAMEINFO */
 /**/
-# define zsh_gethostbyname2 gethostbyname2
-
+#define zsh_getnameinfo getnameinfo
 /**/
-# endif /* !HAVE_GETHOSTBYNAME2 */
-
-/* note: this is not a complete implementation.  If ignores the flags,
-   and does not provide the memory allocation of the standard interface.
-   Each returned structure will overwrite the previous one. */
+#endif /* HAVE_GETNAMEINFO */
 
 /**/
-mod_export struct hostent *
-zsh_getipnodebyname(char const *name, int af, int flags, int *errorp)
-{
-    static struct hostent ahe;
-    static char nbuf[16];
-    static char *addrlist[] = { nbuf, NULL };
-# ifdef SUPPORT_IPV6
-    static char pbuf[INET6_ADDRSTRLEN];
-# else
-    static char pbuf[INET_ADDRSTRLEN];
-# endif
-    struct hostent *he;
-    if (zsh_inet_pton(af, name, nbuf) == 1) {
-	zsh_inet_ntop(af, nbuf, pbuf, sizeof(pbuf));
-	ahe.h_name = pbuf;
-	ahe.h_aliases = addrlist+1;
-	ahe.h_addrtype = af;
-	ahe.h_length = (af == AF_INET) ? 4 : 16;
-	ahe.h_addr_list = addrlist;
-	return &ahe;
-    }
-    he = zsh_gethostbyname2(name, af);
-    if (!he)
-	*errorp = h_errno;
-    return he;
-}
+#ifndef HAVE_FREEADDRINFO
+/* On the completely unexpected chance that we are using a real
+ * getaddrinfo() yet a compatibility freeaddrinfo(), recurse to
+ * the end of the list, then free everything dynamically-allocated.
+ */
 
 /**/
 mod_export void
-freehostent(struct hostent *ptr)
+zsh_freeaddrinfo(struct addrinfo *res)
 {
+    if (res->ai_next)
+	zsh_freeaddrinfo(res->ai_next);
+    if (res->ai_canonname)
+	free(res->ai_canonname);
+    if (res->ai_addr)
+	free(res->ai_addr);
+    free(res);
 }
-
 /**/
-#else /* !HAVE_GETIPNODEBYNAME */
-
+#else /* HAVE_FREEADDRINFO */
 /**/
-# define zsh_getipnodebyname getipnodebyname
-
+#define zsh_freeaddrinfo freeaddrinfo
 /**/
-#endif /* !HAVE_GETIPNODEBYNAME */
+#endif /* HAVE_FREEADDRINFO */
 
 LinkList ztcp_sessions;
 
@@ -310,39 +304,32 @@
 
 /**/
 mod_export int
-tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port)
+tcp_connect(Tcp_session sess, struct addrinfo *zai)
 {
-    int salen;
+    memcpy(&(sess->peer), zai->ai_addr, zai->ai_addrlen);
 #ifdef SUPPORT_IPV6
-    if (zhost->h_addrtype==AF_INET6) {
-	memcpy(&(sess->peer.in6.sin6_addr), addrp, zhost->h_length);
-	sess->peer.in6.sin6_port = d_port;
+    if (zai->ai_family == PF_INET6) {
+	sess->peer.in6.sin6_family = zai->ai_family;
 	sess->peer.in6.sin6_flowinfo = 0;
 # ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
 	sess->peer.in6.sin6_scope_id = 0;
+    }
 # endif
-	sess->peer.in6.sin6_family = zhost->h_addrtype;
-	salen = sizeof(struct sockaddr_in6);
-    } else
+    else
 #endif /* SUPPORT_IPV6 */
-    {
-	memcpy(&(sess->peer.in.sin_addr), addrp, zhost->h_length);
-	sess->peer.in.sin_port = d_port;
-	sess->peer.in.sin_family = zhost->h_addrtype;
-	salen = sizeof(struct sockaddr_in);
-    }
+	sess->peer.in.sin_family = zai->ai_family;
 
-    return connect(sess->fd, (struct sockaddr *)&(sess->peer), salen);
+    return connect(sess->fd, (struct sockaddr *)&(sess->peer), zai->ai_addrlen);
 }
 
 static int
 bin_ztcp(char *nam, char **args, char *ops, int func)
 {
-    int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0;
+    int gai_errno, err=1, force=0, verbose=0, test=0, targetfd=0,
+	pf = PF_INET;
     SOCKLEN_T  len;
-    char **addrp, *desthost, *localname, *remotename, **dargs;
-    struct hostent *zthost = NULL, *ztpeer = NULL;
-    struct servent *srv;
+    char *desthost, *destservice, *localname, *remotename, **dargs;
+    struct addrinfo *zthost = NULL, zthints;
     Tcp_session sess = NULL;
 
     if (ops['f'])
@@ -354,6 +341,14 @@
     if (ops['t'])
         test = 1;
 
+#ifdef SUPPORT_IPV6
+    if (ops['4'])
+	pf = PF_INET;
+
+    if (ops['6'])
+	pf = PF_INET6;
+#endif /* SUPPORT_IPV6 */
+
     if (ops['d']) {
 	targetfd = atoi(args[0]);
 	dargs = args + 1;
@@ -396,44 +391,52 @@
 	}
     }
     else if (ops['l']) {
-	int lport = 0;
+	char *localhost, *localport;
 
 	if (!dargs[0]) {
 	    zwarnnam(nam, "-l requires an argument", NULL, 0);
 	    return 1;
 	}
 
-	srv = getservbyname(dargs[0], "tcp");
-	if (srv)
-	    lport = srv->s_port;
-	else
-	    lport = htons(atoi(dargs[0]));
-	if (!lport) { zwarnnam(nam, "bad service name or port number", NULL, 0);
+	if ((localport = memchr(localhost = dargs[0], (int)':', strlen(dargs[0]))) == NULL) {
+	    localhost = dupstring("0.0.0.0");
+	    localport = dargs[0];
+	}
+	else {
+	    *localport++ = '\0';
+	}
+
+	memset(&zthints, 0, sizeof(zthints));
+	zthints.ai_protocol = IPPROTO_TCP;
+	zthints.ai_flags = AI_CANONNAME;
+	zthints.ai_socktype = SOCK_STREAM;
+
+	if ((gai_errno = zsh_getaddrinfo(localhost, localport, &zthints, &zthost))) {
+	    zwarnnam(nam, "bad service name, port number, or hostname: %s: %d", dargs[0], gai_errno);
 	return 1;
 	}
-	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN);
+	sess = tcp_socket(pf, SOCK_STREAM, IPPROTO_IP, ZTCP_LISTEN);
 
 	if (!sess) {
 	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
 	    return 1;
 	}
+	if ((sess->fd) == -1) {
+	    zwarnnam(nam, "socket error: %e", NULL, errno);
+	    return 1;
+	}
 #ifdef SO_OOBINLINE
 	len = 1;
 	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
 #endif
-	if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr)))
-	{
-	    zwarnnam(nam, "bad address: %s", "0.0.0.0", 0);
-	    return 1;
-	}
 
-	sess->sock.in.sin_family = AF_INET;
-	sess->sock.in.sin_port = lport;
+	memcpy(&(sess->sock.a), zthost->ai_addr, sizeof(struct sockaddr));
 
+	zsh_freeaddrinfo(zthost);
 
 	if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in)))
 	{
-	    zwarnnam(nam, "could not bind to %s: %e", "0.0.0.0", errno);
+	    zwarnnam(nam, "could not bind to %s: %e", dargs[0], errno);
 	    tcp_close(sess);
 	    return 1;
 	}
@@ -561,16 +564,21 @@
 
 		if (sess->fd != -1)
 		{
-		    zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET);
-		    if (zthost)
-			localname = zthost->h_name;
-		    else
-			localname = ztrdup(inet_ntoa(sess->sock.in.sin_addr));
-		    ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET);
-		    if (ztpeer)
-			remotename = ztpeer->h_name;
-		    else
-			remotename = ztrdup(inet_ntoa(sess->peer.in.sin_addr));
+		    char *hostname;
+		    hostname = zalloc(255);
+
+		    if (!zsh_getnameinfo((struct sockaddr *)&(sess->sock.a), sizeof(sess->sock.a), hostname, 255, NULL, 0, 0))
+			localname = hostname;
+		    else {
+			localname = ztrdup("ERR");
+		    }
+
+		    if (!zsh_getnameinfo((struct sockaddr *)&(sess->peer.a), sizeof(sess->peer.a), hostname, 255, NULL, 0, 0))
+			remotename = hostname;
+		    else {
+			remotename = ztrdup("ERR");
+		    }
+
 		    if (ops['L']) {
 			int schar;
 			if (sess->flags & ZTCP_ZFTP)
@@ -594,31 +602,38 @@
 			       sess->fd,
 			       (sess->flags & ZTCP_ZFTP) ? " ZFTP" : "");
 		    }
+
+		    zsfree(localname);
+		    zsfree(remotename);
 		}
 	    }
 	    return 0;
 	}
 	else if (!dargs[1]) {
-	    destport = htons(23);
+	    destservice = ztrdup("telnet");
 	}
 	else {
-
-	    srv = getservbyname(dargs[1],"tcp");
-	    if (srv)
-		destport = srv->s_port;
-	    else
-		destport = htons(atoi(dargs[1]));
+	    destservice = ztrdup(dargs[1]);
 	}
 	
+	memset(&zthints, 0, sizeof(zthints));
+	zthints.ai_protocol = IPPROTO_TCP;
+	zthints.ai_flags = AI_CANONNAME;
+
 	desthost = ztrdup(dargs[0]);
 	
-	zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno);
-	if (!zthost || errflag) {
-	    zwarnnam(nam, "host resolution failure: %s", desthost, 0);
+	gai_errno = zsh_getaddrinfo(desthost, destservice, &zthints, &zthost);
+
+	zsfree(desthost);
+	zsfree(destservice);
+
+	if (gai_errno) {
+	    /* gai_strerror could be more useful here */
+	    zwarnnam(nam, "host/service resolution failure: %s: %d", desthost, gai_errno);
 	    return 1;
 	}
 	
-	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);
+	sess = tcp_socket(pf, SOCK_STREAM, IPPROTO_IP, 0);
 
 	if (!sess) {
 	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
@@ -632,23 +647,15 @@
 
 	if (sess->fd < 0) {
 	    zwarnnam(nam, "socket creation failed: %e", NULL, errno);
-	    zsfree(desthost);
 	    zts_delete(sess);
+	    zsh_freeaddrinfo(zthost);
 	    return 1;
 	}
 	
-	for (addrp = zthost->h_addr_list; err && *addrp; addrp++) {
-	    if (zthost->h_length != 4)
-		zwarnnam(nam, "address length mismatch", NULL, 0);
-	    do {
-		err = tcp_connect(sess, *addrp, zthost, destport);
-	    } while (err && errno == EINTR && !errflag);
-	}
-	
-	if (err) {
+	if ((err = tcp_connect(sess, zthost))) {
 	    zwarnnam(nam, "connection failed: %e", NULL, errno);
 	    tcp_close(sess);
-	    zsfree(desthost);
+	    zsh_freeaddrinfo(zthost);
 	    return 1;
 	}
 	else
@@ -662,17 +669,21 @@
 
 	    if (verbose)
 		printf("%s:%d is now on fd %d\n",
-			desthost, destport, sess->fd);
+		       zthost->ai_canonname, ntohs(((struct sockaddr_in *)(zthost->ai_addr))->sin_port), sess->fd);
 	}
 	
-	zsfree(desthost);
+	zsh_freeaddrinfo(zthost);
     }
 
     return 0;
 }
 
 static struct builtin bintab[] = {
+#ifdef SUPPORT_IPV6
+    BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acdflLtv46", NULL),
+#else
     BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acdflLtv", NULL),
+#endif /* SUPPORT_IPV6 */
 };
 
 /* The load/unload routines required by the zsh library interface */
Index: Src/Modules/zftp.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/zftp.c,v
retrieving revision 1.27
diff -w -u -r1.27 zftp.c
--- Src/Modules/zftp.c	15 May 2002 20:38:18 -0000	1.27
+++ Src/Modules/zftp.c	4 Jul 2002 22:22:54 -0000
@@ -1014,8 +1014,11 @@
 	if(zdsockp->a.sa_family == AF_INET6) {
 	    /* see RFC 2428 for explanation */
 	    strcpy(portcmd, "EPRT |2|");
-	    zsh_inet_ntop(AF_INET6, &zdsockp->in6.sin6_addr,
-			  portcmd+8, INET6_ADDRSTRLEN);
+
+	    zsh_getnameinfo(&(zdsockp->a), sizeof(struct sockaddr),
+			    (char *)portcmd+8, INET6_ADDRSTRLEN,
+			    NULL, 0, NI_NUMERICHOST);
+
 	    sprintf(strchr(portcmd, 0), "|%u|\r\n",
 		    (unsigned)ntohs(zdsockp->in6.sin6_port));
 	} else
@@ -1696,13 +1699,11 @@
 static int
 zftp_open(char *name, char **args, int flags)
 {
-    struct protoent *zprotop;
-    struct servent *zservp;
-    struct hostent *zhostp = NULL;
-    char **addrp, *fname;
+    struct addrinfo *zhostp = NULL, zthints;
+    char *fname;
     int err, tmout;
     SOCKLEN_T  len;
-    int herrno, af, hlen;
+    int gai_errno, af, hlen;
 
     if (!*args) {
 	if (zfsess->userparams)
@@ -1721,15 +1722,6 @@
     if (zfsess->control)
 	zfclose(0);
 
-    /* this is going to give 0.  why bother? */
-    zprotop = getprotobyname("tcp");
-    zservp = getservbyname("ftp", "tcp");
-
-    if (!zprotop || !zservp) {
-	zwarnnam(name, "Somebody stole FTP!", NULL, 0);
-	return 1;
-    }
-
     /* don't try talking to server yet */
     zcfinish = 2;
 
@@ -1762,20 +1754,20 @@
 # define FAILED() do { } while(0)
 #endif
     {
-	zhostp = zsh_getipnodebyname(args[0], af, 0, &herrno);
-	if (!zhostp || errflag) {
-	    /* should use herror() here if available, but maybe
-	     * needs configure test. on AIX it's present but not
-	     * in headers.
-	     * 
-	     * on the other hand, herror() is obsolete
-	     */
+
+	memset(&zthints, 0, sizeof(zthints));
+	zthints.ai_protocol = IPPROTO_TCP;
+	zthints.ai_flags = AI_CANONNAME;
+
+
+	if ((gai_errno = zsh_getaddrinfo(args[0], "ftp", &zthints, &zhostp))) {
+	    /* could use gai_strerror() */
 	    FAILED();
-	    zwarnnam(name, "host not found: %s", args[0], 0);
+	    zwarnnam(name, "host not found: %s: %d", args[0], gai_errno);
 	    alarm(0);
 	    return 1;
 	}
-	zfsetparam("ZFTP_HOST", ztrdup(zhostp->h_name), ZFPM_READONLY);
+	zfsetparam("ZFTP_HOST", ztrdup(zhostp->ai_canonname), ZFPM_READONLY);
 
 #ifdef SUPPORT_IPV6
 	if(af == AF_INET6) {
@@ -1793,7 +1785,7 @@
 		tcp_close(zfsess->control);
 		zfsess->control = NULL;
 	    }
-	    freehostent(zhostp);
+	    freeaddrinfo(zhostp);
 	    zfunsetparam("ZFTP_HOST");
 	    FAILED();
 	    zwarnnam(name, "socket failed: %e", NULL, errno);
@@ -1810,18 +1802,10 @@
 
 	err = 1;
 
-	/* try all possible IP's */
-	for (addrp = zhostp->h_addr_list; err && *addrp; addrp++) {
-	    if(hlen != zhostp->h_length)
-		zwarnnam(name, "address length mismatch", NULL, 0);
-	    do {
-		err = tcp_connect(zfsess->control, *addrp, zhostp, zservp->s_port);
-	    } while (err && errno == EINTR && !errflag);
-	    /* you can check whether it's worth retrying here */
-	}
+	err = tcp_connect(zfsess->control, zhostp);
 
 	if (err) {
-	    freehostent(zhostp);
+	    freeaddrinfo(zhostp);
 	    zfclose(0);
 	    FAILED();
 	    zwarnnam(name, "connect failed: %e", NULL, errno);
@@ -1838,11 +1822,12 @@
 #else
 	char pbuf[INET_ADDRSTRLEN];
 #endif
-	addrp--;
-	zsh_inet_ntop(af, *addrp, pbuf, sizeof(pbuf));
+	zsh_getnameinfo(&(zfsess->control->peer.a), sizeof(struct sockaddr),
+			pbuf, sizeof(pbuf), NULL, 0, NI_NUMERICHOST);
+
 	zfsetparam("ZFTP_IP", ztrdup(pbuf), ZFPM_READONLY);
     }
-    freehostent(zhostp);
+    freeaddrinfo(zhostp);
     /* now we can talk to the control connection */
     zcfinish = 0;
 


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2002-07-04 22:31 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-04  9:46 PATCH: tcp cleanup and breakage Clint Adams
2002-07-04 10:23 ` Peter Stephenson
2002-07-04 17:01   ` Clint Adams
2002-07-04 10:42 ` Borsenkow Andrej
2002-07-04 10:56   ` Peter Stephenson
2002-07-04 16:59     ` Clint Adams
2002-07-04 22:31       ` Clint Adams

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).