summaryrefslogtreecommitdiffstats
path: root/libexec/ftpd
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1995-05-03 16:58:12 +0000
committerwollman <wollman@FreeBSD.org>1995-05-03 16:58:12 +0000
commit687339a1f2d61a6d320ab967f1ec2109472db608 (patch)
treeea7b68bd499ae6904a7bfa6fd18c7e1beff543a8 /libexec/ftpd
parent224e718f65b67a3cfe208d2895e6e87f55fdfffc (diff)
downloadFreeBSD-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.c69
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;
OpenPOWER on IntegriCloud