Subject: bin/18686: a fix for ftp(1) to allow longer command reply timeout to be specified
To: None <gnats-bugs@gnats.netbsd.org>
From: Greg A. Woods <woods@weird.com>
List: netbsd-bugs
Date: 10/17/2002 18:12:37
>Number:         18686
>Category:       bin
>Synopsis:       a fix for ftp(1) to allow longer command reply timeout to be specified
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Oct 17 15:13:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Greg A. Woods
>Release:        netbsd-1-6 2002/10/15
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:
System: NetBSD 1.6.x
>Description:

	ftp has a hard-coded 60-second "reply" timeout that causes
	failures which are not experienced when using the older NetBSD
	ftp command, nor when using ftp on other systems such as
	SunOS-5.6, when connecting to very slow/distant servers.

>How-To-Repeat:

	try to ftp a file from a very slow and very distant server, such
	as ftp.it.usyd.edu.au (which may be having DNS resolver problems
	too, causing it to respond even more slowly)

	observe that 1.3.3's ftp works -- it just takes a long time, as
	does the ftp on SunOS-5.6.

>Fix:

	60 seconds might be too slow for a default -- consider
	increasing it to at least 120 seconds

	Apply the following changes to basesrc/usr.bin/ftp so that any
	timeout can be specified at run-time.  Note these are diffs
	against the netbsd-1-6 branch.

Index: ftp.1
===================================================================
RCS file: /cvs/master/m-NetBSD/main/basesrc/usr.bin/ftp/ftp.1,v
retrieving revision 1.82.2.1
diff -c -r1.82.2.1 ftp.1
*** ftp.1	9 Jul 2002 08:37:18 -0000	1.82.2.1
--- ftp.1	17 Oct 2002 22:03:06 -0000
***************
*** 68,74 ****
  .\"
  .\"	@(#)ftp.1	8.3 (Berkeley) 10/9/94
  .\"
! .Dd July 7, 2002
  .Dt FTP 1
  .Os
  .Sh NAME
--- 68,74 ----
  .\"
  .\"	@(#)ftp.1	8.3 (Berkeley) 10/9/94
  .\"
! .Dd October 17, 2002
  .Dt FTP 1
  .Os
  .Sh NAME
***************
*** 101,106 ****
--- 101,107 ----
  .Sm on
  .Xc
  .Oc
+ .Op Fl W Ar timeout
  .Ek
  .Bk -words
  .\" [[user@]host [port]]
***************
*** 326,331 ****
--- 327,336 ----
  and
  .Ic progress ,
  overriding the default of enabled when output is to a terminal.
+ .It Fl W Ar timeout
+ Set the command reply timeout to
+ .Ar timeout
+ seconds.  The default is sixty (60) seconds.
  .El
  .Pp
  The client host with which
Index: ftp.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/basesrc/usr.bin/ftp/ftp.c,v
retrieving revision 1.119
diff -c -r1.119 ftp.c
*** ftp.c	7 May 2002 02:04:09 -0000	1.119
--- ftp.c	17 Oct 2002 21:51:44 -0000
***************
*** 410,416 ****
  	for (line = 0 ;; line++) {
  		dig = n = code = 0;
  		cp = current_line;
! 		while (alarmtimer(60),((c = getc(cin)) != '\n')) {
  			if (c == IAC) {     /* handle telnet commands */
  				switch (c = getc(cin)) {
  				case WILL:
--- 410,416 ----
  	for (line = 0 ;; line++) {
  		dig = n = code = 0;
  		cp = current_line;
! 		while (alarmtimer(reply_timeout),((c = getc(cin)) != '\n')) {
  			if (c == IAC) {     /* handle telnet commands */
  				switch (c = getc(cin)) {
  				case WILL:
Index: ftp_var.h
===================================================================
RCS file: /cvs/master/m-NetBSD/main/basesrc/usr.bin/ftp/ftp_var.h,v
retrieving revision 1.62
diff -c -r1.62 ftp_var.h
*** ftp_var.h	26 Dec 2001 09:40:16 -0000	1.62
--- ftp_var.h	17 Oct 2002 21:53:01 -0000
***************
*** 198,203 ****
--- 198,205 ----
  #define	DEFAULTPROMPT	"ftp> "	/* default prompt  if `set prompt' is empty */
  #define	DEFAULTRPROMPT	""	/* default rprompt if `set rprompt' is empty */
  
+ #define DEFAULT_REPLY_TIMEOUT	60	/* default command reply timeout in seconds */
+ 
  #define	TMPFILE		"ftpXXXXXXXXXX"
  
  
***************
*** 327,332 ****
--- 329,335 ----
  					 * first (`xxx-') and last (`xxx ')
  					 */
  
+ GLOBAL	int      reply_timeout;
  
  GLOBAL	FILE	*cin;
  GLOBAL	FILE	*cout;
Index: main.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/basesrc/usr.bin/ftp/main.c,v
retrieving revision 1.80
diff -c -r1.80 main.c
*** main.c	18 Mar 2002 20:14:03 -0000	1.80
--- main.c	17 Oct 2002 21:58:16 -0000
***************
*** 191,196 ****
--- 191,197 ----
  	isupload = 0;
  	reply_callback = NULL;
  	family = AF_UNSPEC;
+ 	reply_timeout = DEFAULT_REPLY_TIMEOUT;
  
  	netrc[0] = '\0';
  	cp = getenv("NETRC");
***************
*** 280,286 ****
  		}
  	}
  
! 	while ((ch = getopt(argc, argv, "46AadefginN:o:pP:r:RtT:u:vV")) != -1) {
  		switch (ch) {
  		case '4':
  			family = AF_INET;
--- 281,287 ----
  		}
  	}
  
! 	while ((ch = getopt(argc, argv, "46AadefginN:o:pP:r:RtT:u:vVW:")) != -1) {
  		switch (ch) {
  		case '4':
  			family = AF_INET;
***************
*** 405,410 ****
--- 406,417 ----
  			progress = verbose = 0;
  			break;
  
+ 		case 'W':
+ 			reply_timeout = strtol(optarg, &ep, 10);
+ 			if (reply_timeout < 1 || *ep != '\0')
+ 				errx(1, "bad reply timeout value: %s", optarg);
+ 			break;
+ 
  		default:
  			usage();
  		}
***************
*** 682,688 ****
  			 * such commands as invalid.
  			 */
  			if (strchr(margv[0], ':') != NULL ||
! 			    el_parse(el, margc, (const char **)margv) != 0)
  #endif /* !NO_EDITCOMPLETE */
  				fputs("?Invalid command.\n", ttyout);
  			continue;
--- 689,695 ----
  			 * such commands as invalid.
  			 */
  			if (strchr(margv[0], ':') != NULL ||
! 			    el_parse(el, margc, (char **)margv) != 0)
  #endif /* !NO_EDITCOMPLETE */
  				fputs("?Invalid command.\n", ttyout);
  			continue;
***************
*** 1017,1023 ****
  	const char *progname = getprogname();
  
  	(void)fprintf(stderr,
! "usage: %s [-46AadefginpRtvV] [-N netrc] [-o outfile] [-P port] [-r retry]\n"
  "           [-T dir,max[,inc][[user@]host [port]]] [host:path[/]]\n"
  "           [file:///file] [ftp://[user[:pass]@]host[:port]/path[/]]\n"
  "           [http://[user[:pass]@]host[:port]/path] [...]\n"
--- 1024,1031 ----
  	const char *progname = getprogname();
  
  	(void)fprintf(stderr,
! "usage: %s [-46AadefginpRtvV] [-N netrc] [-o outfile] [-P port]\n"
! "           [-r retry] [-W tmout]\n"
  "           [-T dir,max[,inc][[user@]host [port]]] [host:path[/]]\n"
  "           [file:///file] [ftp://[user[:pass]@]host[:port]/path[/]]\n"
  "           [http://[user[:pass]@]host[:port]/path] [...]\n"
>Release-Note:
>Audit-Trail:
>Unformatted: