diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2007-06-16 08:58:34 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2007-06-16 08:58:34 +0000 |
commit | 5ba6b2ba2df8fc791ddaed159225dbbcdf674cf5 (patch) | |
tree | 6fcf6a2b18e6258d84d0a2dddcd8eaa4d5a2563a | |
parent | 3c0ffca3b0a9e275fb40c1bb21cb96e0da507384 (diff) |
implement a `keep-alive' option that sends bytes over an inactive
connection. The FTP protocol provides us with a NOOP operation that
is perfectly suitable for that, and so far servers are happy with it.
Sending the command slowly is an idea I borrowed from spamd.
No change for people not using the option, so it can't break normal ftp.
okay beck@, jmc@
-rw-r--r-- | usr.bin/ftp/extern.h | 3 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.1 | 18 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.c | 79 | ||||
-rw-r--r-- | usr.bin/ftp/main.c | 26 |
4 files changed, 114 insertions, 12 deletions
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h index 864913387d6..8fefe122e5b 100644 --- a/usr.bin/ftp/extern.h +++ b/usr.bin/ftp/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.30 2007/06/13 13:52:26 pyr Exp $ */ +/* $OpenBSD: extern.h,v 1.31 2007/06/16 08:58:33 espie Exp $ */ /* $NetBSD: extern.h,v 1.17 1997/08/18 10:20:19 lukem Exp $ */ /* @@ -208,6 +208,7 @@ extern int proxy; extern char reply_string[]; extern off_t restart_point; extern int NCMDS; +extern int keep_alive_timeout; extern char *__progname; /* from crt0.o */ diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1 index b6dfe8fae35..ffeae81112b 100644 --- a/usr.bin/ftp/ftp.1 +++ b/usr.bin/ftp/ftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ftp.1,v 1.60 2007/06/13 18:43:16 jmc Exp $ +.\" $OpenBSD: ftp.1,v 1.61 2007/06/16 08:58:33 espie Exp $ .\" $NetBSD: ftp.1,v 1.22 1997/08/18 10:20:22 lukem Exp $ .\" .\" Copyright (c) 1985, 1989, 1990, 1993 @@ -30,7 +30,7 @@ .\" .\" @(#)ftp.1 8.3 (Berkeley) 10/9/94 .\" -.Dd $Mdocdate: June 13 2007 $ +.Dd $Mdocdate: June 16 2007 $ .Dt FTP 1 .Os .Sh NAME @@ -40,6 +40,7 @@ .Nm ftp .Op Fl 46AadEegimnptVv .Op Fl c Ar cookie +.Op Fl k Ar seconds .Op Fl P Ar port .Op Fl r Ar seconds .Op Ar host Op Ar port @@ -134,6 +135,19 @@ Disables file name globbing. .It Fl i Turns off interactive prompting during multiple file transfers. +.It Fl k Ar seconds +Sends a byte after each +.Ar seconds +period over the control connection during long transfers, +so that incorrectly configured network equipment won't +agressively drop it. +The FTP protocol supports a +.Dv NOOP +command that can be used for that purpose. +This assumes the FTP server can deal with extra commands coming over +the control connection during a transfer. +Well-behaved servers queue those commands, and process them after the +transfer. .It Fl m Causes .Nm diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c index 252b27585f2..3a9cf82bd69 100644 --- a/usr.bin/ftp/ftp.c +++ b/usr.bin/ftp/ftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftp.c,v 1.66 2007/03/06 05:16:01 beck Exp $ */ +/* $OpenBSD: ftp.c,v 1.67 2007/06/16 08:58:33 espie Exp $ */ /* $NetBSD: ftp.c,v 1.27 1997/08/18 10:20:23 lukem Exp $ */ /* @@ -60,7 +60,7 @@ */ #if !defined(lint) && !defined(SMALL) -static const char rcsid[] = "$OpenBSD: ftp.c,v 1.66 2007/03/06 05:16:01 beck Exp $"; +static const char rcsid[] = "$OpenBSD: ftp.c,v 1.67 2007/06/16 08:58:33 espie Exp $"; #endif /* not lint and not SMALL */ #include <sys/types.h> @@ -325,6 +325,73 @@ command(const char *fmt, ...) return (r); } +int keep_alive_timeout = 0; /* 0 -> no timeout */ + +static int full_noops_sent = 0; +static time_t last_timestamp = 0; /* 0 -> no measurement yet */ +static char noop[] = "NOOP\r\n"; +#define NOOP_LENGTH (sizeof noop - 1) +static int current_nop_pos = 0; /* 0 -> no noop started */ + +/* to achieve keep alive, we send noop one byte at a time */ +void +send_noop_char() +{ + if (debug) + fprintf(ttyout, "---> %c\n", noop[current_nop_pos]); + fputc(noop[current_nop_pos++], cout); + (void)fflush(cout); + if (current_nop_pos >= NOOP_LENGTH) { + full_noops_sent++; + current_nop_pos = 0; + } +} + +void +may_reset_noop_timeout() +{ + if (keep_alive_timeout != 0) + last_timestamp = time(NULL); +} + +void +may_receive_noop_ack() +{ + int i; + + /* finish sending last incomplete noop */ + if (current_nop_pos != 0) { + fputs(&(noop[current_nop_pos]), cout); + if (debug) + fprintf(ttyout, "---> %s\n", &(noop[current_nop_pos])); + (void)fflush(cout); + current_nop_pos = 0; + full_noops_sent++; + } + /* and get the replies */ + for (i = 0; i < full_noops_sent; i++) + (void)getreply(0); + + full_noops_sent = 0; +} + +void +may_send_noop_char() +{ + if (keep_alive_timeout != 0) { + if (last_timestamp != 0) { + time_t t = time(NULL); + + if (t - last_timestamp >= keep_alive_timeout) { + last_timestamp = t; + send_noop_char(); + } + } else { + last_timestamp = time(NULL); + } + } +} + char reply_string[BUFSIZ]; /* first line of previous reply */ int @@ -631,6 +698,7 @@ sendrequest(const char *cmd, const char *local, const char *remote, if (dout == NULL) goto abort; progressmeter(-1); + may_reset_noop_timeout(); oldintp = signal(SIGPIPE, SIG_IGN); switch (curtype) { @@ -638,6 +706,7 @@ sendrequest(const char *cmd, const char *local, const char *remote, case TYPE_L: errno = d = 0; while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) { + may_send_noop_char(); bytes += c; for (bufp = buf; c > 0; c -= d, bufp += d) if ((d = write(fileno(dout), bufp, (size_t)c)) @@ -668,6 +737,7 @@ sendrequest(const char *cmd, const char *local, const char *remote, case TYPE_A: while ((c = fgetc(fin)) != EOF) { + may_send_noop_char(); if (c == '\n') { while (hash && (!progress || filesize < 0) && (bytes >= hashbytes)) { @@ -710,6 +780,7 @@ sendrequest(const char *cmd, const char *local, const char *remote, (*closefunc)(fin); (void)fclose(dout); (void)getreply(0); + may_receive_noop_ack(); (void)signal(SIGINT, oldintr); (void)signal(SIGINFO, oldinti); if (oldintp) @@ -938,6 +1009,7 @@ recvrequest(const char *cmd, const char * volatile local, const char *remote, preserve = 0; } progressmeter(-1); + may_reset_noop_timeout(); switch (curtype) { case TYPE_I: @@ -956,6 +1028,7 @@ recvrequest(const char *cmd, const char * volatile local, const char *remote, ssize_t wr; size_t rd = c; + may_send_noop_char(); d = 0; do { wr = write(fileno(fout), buf + d, rd); @@ -1018,6 +1091,7 @@ done: } } while ((c = fgetc(din)) != EOF) { + may_send_noop_char(); if (c == '\n') bare_lfs++; while (c == '\r') { @@ -1077,6 +1151,7 @@ break2: (void)signal(SIGPIPE, oldintp); (void)fclose(din); (void)getreply(0); + may_receive_noop_ack(); if (bytes >= 0 && is_retr) { if (bytes > 0) ptransfer(0); diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c index 43ce223e1a9..c83ad2440c2 100644 --- a/usr.bin/ftp/main.c +++ b/usr.bin/ftp/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.64 2007/06/13 18:43:16 jmc Exp $ */ +/* $OpenBSD: main.c,v 1.65 2007/06/16 08:58:33 espie Exp $ */ /* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */ /* @@ -66,7 +66,7 @@ static const char copyright[] = #endif /* not lint */ #if !defined(lint) && !defined(SMALL) -static const char rcsid[] = "$OpenBSD: main.c,v 1.64 2007/06/13 18:43:16 jmc Exp $"; +static const char rcsid[] = "$OpenBSD: main.c,v 1.65 2007/06/16 08:58:33 espie Exp $"; #endif /* not lint and not SMALL */ /* @@ -181,7 +181,7 @@ main(volatile int argc, char *argv[]) cookiefile = getenv("http_cookies"); #endif - while ((ch = getopt(argc, argv, "46Aac:dEegimno:pP:r:tvV")) != -1) { + while ((ch = getopt(argc, argv, "46Aac:dEegik:mno:pP:r:tvV")) != -1) { switch (ch) { case '4': family = PF_INET; @@ -227,6 +227,15 @@ main(volatile int argc, char *argv[]) interactive = 0; break; + case 'k': + keep_alive_timeout = strtonum(optarg, 0, INT_MAX, + &errstr); + if (errstr != NULL) { + warnx("keep alive amount is %s: %s", errstr, + optarg); + usage(); + } + break; case 'm': progress = -1; break; @@ -252,9 +261,11 @@ main(volatile int argc, char *argv[]) case 'r': retry_connect = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) - errx(1, "retry amount is %s: %s", errstr, + if (errstr != NULL) { + warnx("retry amount is %s: %s", errstr, optarg); + usage(); + } break; case 't': @@ -746,8 +757,9 @@ void usage(void) { (void)fprintf(stderr, - "usage: %s [-46AadEegimnptVv] [-c cookie] [-P port] " - "[-r seconds] [host [port]]\n" + "usage: %s [-46AadEegimnptVv] [-c cookie] [-k seconds] " + "[-P port] [-r seconds]\n" + " [host [port]]\n" " %s [-o output] ftp://[user:password@]host[:port]/file[/]\n" " %s [-o output] http://host[:port]/file\n" #ifndef SMALL |