Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Using zftp with a non-standard port



Lloyd Zusman wrote:
> Peter Stephenson <pws@xxxxxxxxxxxxxxxxxxxxxxxx> writes:
> 
> > Lloyd Zusman wrote:
> >> Is there a way to get zftp to connect using a non-standard port?
> >
> > No, that's never been added; there was never any call.  Part of the
> > problem is that zftp was specifically written to avoid needing options
> > to the commands.
> 
> Well, instead of an option, how about an optional port appended to
> the host after a colon.  If so, then either of the two following
> items could work:
> 
>   host
>   host:port

That seems reasonable.  It fits in well with URIs.

The following patch implements that.  I've tracked down a few
potential problems (which is why it's not as small as it might be)
but I haven't yet handled special ports transparently in the function
system: it won't work when you use a bookmark or try and reopen a
question to a system which timed out if the port was non-standard.
Unfortunately I used `:' there to append the current directory.  It
will need fixing to check for a numeric port extracted from $ZFTP_PORT.

Index: configure.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/configure.ac,v
retrieving revision 1.15
diff -u -r1.15 configure.ac
--- configure.ac	14 Mar 2004 11:27:29 -0000	1.15
+++ configure.ac	23 Mar 2004 12:34:12 -0000
@@ -1053,7 +1053,8 @@
 	       nl_langinfo \
 	       erand48 open_memstream \
 	       wctomb iconv \
-	       grantpt unlockpt ptsname)
+	       grantpt unlockpt ptsname \
+	       htons ntohs)
 AC_FUNC_STRCOLL
 
 if test x$enable_cap = xyes; then
Index: Doc/Zsh/mod_zftp.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_zftp.yo,v
retrieving revision 1.1.1.12
diff -u -r1.1.1.12 mod_zftp.yo
--- Doc/Zsh/mod_zftp.yo	20 Dec 1999 11:24:39 -0000	1.1.1.12
+++ Doc/Zsh/mod_zftp.yo	23 Mar 2004 12:34:12 -0000
@@ -31,15 +31,20 @@
 
 startitem()
 cindex(FTP, starting a session)
-item(tt(open) var(host) [ var(user) [ var(password) [ var(account) ] ] ])(
+item(tt(open) var(host)[tt(:)var(port)] [ var(user) [ var(password) [ var(account) ] ] ])(
 Open a new FTP session to var(host), which may be the name of a TCP/IP
-connected host or an IP number in the standard dot notation.
+connected host or an IP number in the standard dot notation.  If the
+argument is in the form var(host)tt(:)var(port), open a connection to
+TCP port var(port) instead of the standard FTP port 21.  This may be
+the name of a TCP service or a number:  see the description of
+tt(ZFTP_PORT) below for more information.
+
 Remaining arguments are passed to the tt(login) subcommand.  Note that
 if no arguments beyond var(host) are supplied, tt(open) will em(not)
 automatically call tt(login).  If no arguments at all are supplied,
 tt(open) will use the parameters set by the tt(params) subcommand.
 
-After a successful open, the shell variables tt(ZFTP_HOST),
+After a successful open, the shell variables tt(ZFTP_HOST), tt(ZFTP_PORT),
 tt(ZFTP_IP) and tt(ZFTP_SYSTEM) are available; see `Variables'
 below.
 )
@@ -222,7 +227,7 @@
 xitem(tt(close))
 item(tt(quit))(
 Close the current data connection.  This unsets the shell parameters
-tt(ZFTP_HOST), tt(ZFTP_IP), tt(ZFTP_SYSTEM), tt(ZFTP_USER),
+tt(ZFTP_HOST), tt(ZFTP_PORT), tt(ZFTP_IP), tt(ZFTP_SYSTEM), tt(ZFTP_USER),
 tt(ZFTP_ACCOUNT), tt(ZFTP_PWD), tt(ZFTP_TYPE) and tt(ZFTP_MODE).
 )
 item(tt(session) [ var(sessname) ])(
@@ -278,6 +283,18 @@
 saves the overhead for a name lookup, as IP numbers are most commonly
 used when a nameserver is unavailable.
 )
+vindex(ZFTP_PORT)
+item(tt(ZFTP_PORT))(
+Readonly.  The number of the remote TCP port to which the connection is
+open (even if the port was originally specified as a named service).
+Usually this is the standard FTP port, 21.
+
+In the unlikely event that your system does not have the appropriate
+conversion functions, this appears in network byte order.  If your
+system is little-endian, the port then consists of two swapped bytes and the
+standard port will be reported as 5376.  In that case, numeric ports passed
+to tt(zftp open) will also need to be in this format.
+)
 vindex(ZFTP_SYSTEM)
 item(tt(ZFTP_SYSTEM))(
 Readonly.  The system type string returned by the server in response
Index: Functions/Zftp/zfstat
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/Zftp/zfstat,v
retrieving revision 1.2
diff -u -r1.2 zfstat
--- Functions/Zftp/zfstat	8 May 2000 10:45:02 -0000	1.2
+++ Functions/Zftp/zfstat	23 Mar 2004 12:34:12 -0000
@@ -19,6 +19,7 @@
 
 if [[ -n $ZFTP_HOST ]]; then
   print "Host:\t\t$ZFTP_HOST"
+  print "Port:\t\t$ZFTP_PORT"
   print "IP:\t\t$ZFTP_IP"
   [[ -n $ZFTP_SYSTEM ]] && print "System type:\t$ZFTP_SYSTEM"
   if [[ -n $ZFTP_USER ]]; then
Index: Src/Modules/zftp.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/zftp.c,v
retrieving revision 1.29
diff -u -r1.29 zftp.c
--- Src/Modules/zftp.c	29 Oct 2003 19:17:48 -0000	1.29
+++ Src/Modules/zftp.c	23 Mar 2004 12:34:13 -0000
@@ -195,7 +195,7 @@
  * currently there aren't any, which is the way I like it.
  */
 static char *zfparams[] = {
-    "ZFTP_HOST", "ZFTP_IP", "ZFTP_SYSTEM", "ZFTP_USER",
+    "ZFTP_HOST", "ZFTP_PORT", "ZFTP_IP", "ZFTP_SYSTEM", "ZFTP_USER",
     "ZFTP_ACCOUNT", "ZFTP_PWD", "ZFTP_TYPE", "ZFTP_MODE", NULL
 };
 
@@ -1699,8 +1699,8 @@
     struct protoent *zprotop;
     struct servent *zservp;
     struct hostent *zhostp = NULL;
-    char **addrp, *fname;
-    int err, tmout;
+    char **addrp, *fname, *tmpptr, *portnam = "ftp", *hostnam;
+    int err, tmout, port = -1;
     SOCKLEN_T  len;
     int herrno, af, hlen;
 
@@ -1721,12 +1721,47 @@
     if (zfsess->control)
 	zfclose(0);
 
+    hostnam = args[0];
+    if ((tmpptr = strchr(hostnam, ':'))) {
+	char *endptr;
+	/*
+	 * Careful in case we were using saved parameters:
+	 * we need to preserve those.
+	 */
+	char *newhostnam = dupstring(hostnam);
+	tmpptr += (newhostnam - hostnam);
+	hostnam = newhostnam;
+
+	*tmpptr++ = '\0';
+	port = (int)zstrtol(tmpptr, &endptr, 10);
+	/*
+	 * If the port is not numeric, look it up by name below.
+	 */
+	if (*endptr) {
+	    portnam = tmpptr;
+	    port = -1;
+	}
+#if defined(HAVE_NTOHS) && defined(HAVE_HTONS)
+	else {
+	    port = (int)htons((unsigned short)port);
+	}
+#endif
+    }
+
     /* this is going to give 0.  why bother? */
     zprotop = getprotobyname("tcp");
-    zservp = getservbyname("ftp", "tcp");
+    if (!zprotop) {
+	zwarnnam(name, "Can't find protocol TCP (is your network functional)?",
+		 NULL, 0);
+	return 1;
+    }
+    if (port < 0)
+	zservp = getservbyname(portnam, "tcp");
+    else
+	zservp = getservbyport(port, "tcp");
 
     if (!zprotop || !zservp) {
-	zwarnnam(name, "Somebody stole FTP!", NULL, 0);
+	zwarnnam(name, "Can't find port for service `%s'", portnam, 0);
 	return 1;
     }
 
@@ -1762,7 +1797,9 @@
 # define FAILED() do { } while(0)
 #endif
     {
-	zhostp = zsh_getipnodebyname(args[0], af, 0, &herrno);
+	off_t tcp_port;
+
+	zhostp = zsh_getipnodebyname(hostnam, af, 0, &herrno);
 	if (!zhostp || errflag) {
 	    /* should use herror() here if available, but maybe
 	     * needs configure test. on AIX it's present but not
@@ -1771,11 +1808,18 @@
 	     * on the other hand, herror() is obsolete
 	     */
 	    FAILED();
-	    zwarnnam(name, "host not found: %s", args[0], 0);
+	    zwarnnam(name, "host not found: %s", hostnam, 0);
 	    alarm(0);
 	    return 1;
 	}
 	zfsetparam("ZFTP_HOST", ztrdup(zhostp->h_name), ZFPM_READONLY);
+	/* careful with pointer types */
+#if defined(HAVE_NTOHS) && defined(HAVE_HTONS)
+	tcp_port = (off_t)ntohs((unsigned short)zservp->s_port);
+#else
+	tcp_port = (off_t)zservp->s_port;
+#endif
+	zfsetparam("ZFTP_PORT", &tcp_port, ZFPM_READONLY|ZFPM_INTEGER);
 
 #ifdef SUPPORT_IPV6
 	if(af == AF_INET6) {
@@ -1795,6 +1839,7 @@
 	    }
 	    freehostent(zhostp);
 	    zfunsetparam("ZFTP_HOST");
+	    zfunsetparam("ZFTP_PORT");
 	    FAILED();
 	    zwarnnam(name, "socket failed: %e", NULL, errno);
 	    alarm(0);
@@ -1815,8 +1860,7 @@
 	    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);
+		err = tcp_connect(zfsess->control, *addrp, zhostp, zservp->s_port);	    } while (err && errno == EINTR && !errflag);
 	    /* you can check whether it's worth retrying here */
 	}
 

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


**********************************************************************
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom they
are addressed. If you have received this email in error please notify
the system manager.

This footnote also confirms that this email message has been swept by
MIMEsweeper for the presence of computer viruses.

www.mimesweeper.com
**********************************************************************



Messages sorted by: Reverse Date, Date, Thread, Author