NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
bin/60443: ftp ASCII transfers are too slow
>Number: 60443
>Category: bin
>Synopsis: ftp ASCII transfers are too slow
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Jul 12 08:00:00 +0000 2026
>Originator: RVP
>Release: NetBSD/amd64 11.99.6
>Organization:
>Environment:
NetBSD/amd64 11.99.6
>Description:
FTP ASCII transfers seem to interact badly with Nagle's algorithm
because ASCII xfers rely on libc's BUFSIZ (1KB) internal buffer.
If you write 1KB at a time (relatively slowly because you're doing
getc(3)/putc(3) to locale '\n'), then it looks the 200ms Nagle timeout
comes into play.
At that's what it seems to me from looking at the tcpdump packet times.
>How-To-Repeat:
1. Create a big text file.
dd if=/dev/urandom bs=1m count=100 | sed -n l > in.txt
2. Run ftpd.
/usr/libexec/ftpd -Ddl
3. Run tcpdump to capture packet times.
4. Get or Put the file--active or passive mode don't matter.
Reduce `xferbuf' to 8192 to make the xfer crawl real quick.
Also turn `progress' off. so that interrupts don't confound things.
>Fix:
You need 2 patches. One for ftp(1) and a similar one for ftpd(8).
---START patch ftp(1)---
diff -urN usr.bin/ftp.orig/ftp.c usr.bin/ftp/ftp.c
--- usr.bin/ftp.orig/ftp.c 2026-02-07 03:55:18.973125260 +0000
+++ usr.bin/ftp/ftp.c 2026-02-08 15:51:14.124404272 +0000
@@ -1728,6 +1728,23 @@
return (1);
}
+static FILE *
+ftp_fdopen(int fd, const char *lmode)
+{
+ enum { BSIZ = XFERBUFMIN * 4 }; /* 4K (any >MTU) */
+ FILE *fp;
+ void* buf;
+
+ if ((fp = fdopen(fd, lmode)) == NULL)
+ return NULL;
+ if ((buf = ftp_malloc(BSIZ)) == NULL) {
+ fclose(fp);
+ return NULL;
+ }
+ (void)setvbuf(fp, buf, _IOFBF, BSIZ);
+ return fp;
+}
+
FILE *
dataconn(const char *lmode)
{
@@ -1738,7 +1755,7 @@
socklen_t fromlen;
if (passivemode) /* passive data connection */
- return (fdopen(data, lmode));
+ return (ftp_fdopen(data, lmode));
/* active mode data connection */
@@ -1798,7 +1815,7 @@
}
}
#endif
- return (fdopen(data, lmode));
+ return (ftp_fdopen(data, lmode));
dataconn_failed:
(void)close(data);
---END patch ftp(1)---
---START patch ftpd(8)---
diff -urN libexec/ftpd.orig/ftpd.c libexec/ftpd/ftpd.c
--- libexec/ftpd.orig/ftpd.c 2025-06-28 04:00:41.032045996 +0000
+++ libexec/ftpd/ftpd.c 2026-02-08 15:35:04.378214731 +0000
@@ -1917,6 +1917,23 @@
}
static FILE *
+ftp_fdopen(int fd, const char *lmode)
+{
+ enum { BSIZ = FTP_BUFLEN * 8 }; /* 4KB (any >MTU) */
+ FILE *fp;
+ void* buf;
+
+ if ((fp = fdopen(fd, lmode)) == NULL)
+ return NULL;
+ if ((buf = malloc(BSIZ)) == NULL) {
+ fclose(fp);
+ return NULL;
+ }
+ (void)setvbuf(fp, buf, _IOFBF, BSIZ);
+ return fp;
+}
+
+static FILE *
getdatasock(const char *fmode)
{
int on, s, t, tries;
@@ -1924,7 +1941,7 @@
on = 1;
if (data >= 0)
- return (fdopen(data, fmode));
+ return (ftp_fdopen(data, fmode));
if (! dropprivs) {
if (seteuid((uid_t)0) < 0) {
syslog(LOG_NOTICE, "getdatasock: can't seteuid 0: %m");
@@ -1979,7 +1996,7 @@
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
#endif
- return (fdopen(s, fmode));
+ return (ftp_fdopen(s, fmode));
bad:
/* Return the real value of errno (close may change it) */
t = errno;
@@ -2044,13 +2061,13 @@
#endif
reply(150, "Opening %s mode data connection for '%s'%s.",
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
- return (fdopen(pdata, fmode));
+ return (ftp_fdopen(pdata, fmode));
}
if (data >= 0) {
reply(125, "Using existing data connection for '%s'%s.",
name, sizebuf);
usedefault = 1;
- return (fdopen(data, fmode));
+ return (ftp_fdopen(data, fmode));
}
if (usedefault)
data_dest = his_addr;
---END patch ftpd(8)---
Home |
Main Index |
Thread Index |
Old Index