diff options
author | wollman <wollman@FreeBSD.org> | 1995-05-03 16:58:12 +0000 |
---|---|---|
committer | wollman <wollman@FreeBSD.org> | 1995-05-03 16:58:12 +0000 |
commit | 687339a1f2d61a6d320ab967f1ec2109472db608 (patch) | |
tree | ea7b68bd499ae6904a7bfa6fd18c7e1beff543a8 /libexec/ftpd | |
parent | 224e718f65b67a3cfe208d2895e6e87f55fdfffc (diff) | |
download | FreeBSD-src-687339a1f2d61a6d320ab967f1ec2109472db608.zip FreeBSD-src-687339a1f2d61a6d320ab967f1ec2109472db608.tar.gz |
Speed up ftpd and make it more efficient:
- set TCP_NOPUSH to keep from sending short packets at each write(2) boundary
- set SO_SNDBUF to 64k so we have a reasonable amount of buffer space
- for a regular file in binary mode which is not being restarted and is
. smaller than 16 Meg, use mmap(2) and write(2) the whole file in one big
gulp
In the most common circumstances, this should dramatically reduce the
system-call load from ftpd, since the call to write() will not return until
the entire file has been written, rather than writing just a few K at a time
in a loop.
Diffstat (limited to 'libexec/ftpd')
-rw-r--r-- | libexec/ftpd/ftpd.c | 69 |
1 files changed, 62 insertions, 7 deletions
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index 0277586..81c02c3 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -49,10 +49,12 @@ static char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94"; #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/wait.h> +#include <sys/mman.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <netinet/tcp.h> #define FTP_NAMES #include <arpa/ftp.h> @@ -187,7 +189,7 @@ static FILE *getdatasock __P((char *)); static char *gunique __P((char *)); static void lostconn __P((int)); static int receive_data __P((FILE *, FILE *)); -static void send_data __P((FILE *, FILE *, off_t)); +static void send_data __P((FILE *, FILE *, off_t, off_t, int)); static struct passwd * sgetpwnam __P((char *)); static char *sgetsave __P((char *)); @@ -739,7 +741,8 @@ retrieve(cmd, name) #ifdef STATS time(&start); #endif - send_data(fin, dout, st.st_blksize); + send_data(fin, dout, st.st_blksize, st.st_size, + restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)); #ifdef STATS if (cmd == 0 && guest && stats) logxfer( name, st.st_size, start); @@ -857,6 +860,23 @@ getdatasock(mode) if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); #endif +#ifdef TCP_NOPUSH + /* + * Turn off push flag to keep sender TCP from sending short packets + * at the boundaries of each write(). Should probably do a SO_SNDBUF + * to set the send buffer size as well, but that may not be desirable + * in heavy-load situations. + */ + on = 1; + if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) + syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); +#endif +#ifdef SO_SNDBUF + on = 65536; + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) + syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); +#endif + return (fdopen(s, mode)); bad: /* Return the real value of errno (close may change it) */ @@ -941,17 +961,20 @@ dataconn(name, size, mode) /* * Tranfer the contents of "instr" to "outstr" peer using the appropriate - * encapsulation of the data subject * to Mode, Structure, and Type. + * encapsulation of the data subject to Mode, Structure, and Type. * * NB: Form isn't handled. */ static void -send_data(instr, outstr, blksize) +send_data(instr, outstr, blksize, filesize, isreg) FILE *instr, *outstr; off_t blksize; + off_t filesize; + int isreg; { int c, cnt, filefd, netfd; - char *buf; + char *buf, *bp; + size_t len; transflag++; if (setjmp(urgcatch)) { @@ -981,13 +1004,45 @@ send_data(instr, outstr, blksize) case TYPE_I: case TYPE_L: + /* + * isreg is only set if we are not doing restart and we + * are sending a regular file + */ + netfd = fileno(outstr); + filefd = fileno(instr); + + if (isreg && filesize < (off_t)16 * 1024 * 1024) { + buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, + (off_t)0); + if (!buf) { + syslog(LOG_WARNING, "mmap(%lu): %m", + (unsigned long)filesize); + goto oldway; + } + bp = buf; + len = filesize; + do { + cnt = write(netfd, bp, len); + len -= cnt; + bp += cnt; + if (cnt > 0) byte_count += cnt; + } while(cnt > 0 && len > 0); + + transflag = 0; + munmap(buf, (size_t)filesize); + if (cnt < 0) + goto data_err; + reply(226, "Transfer complete."); + return; + } + +oldway: if ((buf = malloc((u_int)blksize)) == NULL) { transflag = 0; perror_reply(451, "Local resource failure: malloc"); return; } - netfd = fileno(outstr); - filefd = fileno(instr); + while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && write(netfd, buf, cnt) == cnt) byte_count += cnt; |