NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/60443: ftp ASCII transfers are too slow



The following reply was made to PR bin/60443; it has been noted by GNATS.

From: Luke Mewburn <luke%mewburn.net@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: gnats-admin%netbsd.org@localhost, netbsd-bugs%netbsd.org@localhost
Subject: Re: bin/60443: ftp ASCII transfers are too slow
Date: Sun, 19 Jul 2026 18:02:56 +1000

 On 26-07-12 08:00, rvp%SDF.ORG@localhost via gnats wrote:
   | 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.
 
 
   | 
   | ---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) */
 
 
 I think we could use a similar buffer sizing logic to what I
 implemented in ftp.c 1.181 on 2026/02/07 in recvrequest():
 
 	if (rcvbuf_size == 0)
 		bufsize = XFERBUFMAX;
 	else
 		bufsize = MAX(XFERBUFMIN, MIN(rcvbuf_size, XFERBUFMAX));
 
 (maybe this logic could be centralized for easier reuse).
 
 
 Unless this will cause issues on low memory systems with large
 stdio buffer and separate binary mode read buffer?
 
 
   | +	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);
 
 Doesn't this leak "buf" because we've allocated it?
 
 What if we just call setvbuf() with buf==NULL which
 should let the stdio cleanup when the FILE is closed?
 
 I've done a bit of reading into different setvbuf()
 man pages (POSIX, Linux, NetBSD, macOS, cppreference), and it
 seems that all support auto-allocating if buf==NULL and freeing
 on close.
 
 POSIX setvbuf(3) states (https://pubs.opengroup.org/onlinepubs/9699919799/functions/setvbuf.html):
 	If buf is not a null pointer, the array it points to may be used
 	instead of a buffer allocated by setvbuf() and the argument size
 	specifies the size of the array; otherwise, size may determine
 	the size of a buffer allocated by the setvbuf() function.
 
 Linux setvbuf(3) states:
 	If the argument buf is NULL, only the mode is affected;
 	a new buffer will be allocated on the next read or write
 	operation.
 
 However, NetBSD setvbuf(3) states:
 	(If the size argument is not zero but buf is NULL,
 	a buffer of the given size will be allocated immediately,
 	and released on close.  This is an extension to ANSI C;
 	portable code should use a size of 0 with any NULL buffer.)
 
 macOS has a variation of this - understandable since both are 4.xBSD
 derived man pages.
 
 cppreference.com (https://en.cppreference.com/c/io/setvbuf)
 	If buffer is a null pointer, resizes the internal buffer to
 	size.
 
 
 regards,
 Luke.
 



Home | Main Index | Thread Index | Old Index