Subject: Re: ftpd never dies (again)
To: Eric Delcamp <e.delcamp@wanadoo.fr>
From: Allen Briggs <briggs@canolog.ninthwonder.com>
List: current-users
Date: 03/27/1999 21:22:59
> On Sat, Mar 27, 1999 at 05:24:49PM -0500, Allen Briggs wrote:
> > I'm seeing this too, it seems to happen when remote users get cut off
> > due to network lossage of one sort or another.  I see it in STOR or RETR
> > or sometimes LIST.  netstat lists the connections as ESTABLISHED.
> Hmm.  But if keepalive was working, shouldn't it kill the connection
> sooner or later (and make ftpd die as well)?

I just took a look at the code.  There is no keepalive explicitly set
by ftpd, so if the server is waiting for data, it will never time out.
The only timeouts appear to be on the initial connect and when waiting
for a command.

Setting keepalive on the socket would be the easiest fix for this.
Anyone object to the following patch?

-allen

Index: ftpd.c
===================================================================
RCS file: /cvsroot/src/libexec/ftpd/ftpd.c,v
retrieving revision 1.61
diff -c -r1.61 ftpd.c
*** ftpd.c	1998/12/28 04:54:01	1.61
--- ftpd.c	1999/03/28 02:20:43
***************
*** 187,193 ****
  	int argc;
  	char *argv[];
  {
! 	int addrlen, ch, on = 1, tos;
  	char *cp, line[LINE_MAX];
  	FILE *fd;
  #ifdef KERBEROS5  
--- 187,193 ----
  	int argc;
  	char *argv[];
  {
! 	int addrlen, ch, on = 1, tos, keepalive;
  	char *cp, line[LINE_MAX];
  	FILE *fd;
  #ifdef KERBEROS5  
***************
*** 278,283 ****
--- 278,290 ----
  	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  		syslog(LOG_ERR, "setsockopt: %m");
  #endif
+ 	/* Set keep-alives on the socket to detect dropped connections. */
+ #ifdef SO_KEEPALIVE
+ 	keepalive = 1;
+ 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
+ 	    sizeof(int)) < 0)
+ 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+ #endif
  
  #ifdef	F_SETOWN
  	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
***************
*** 972,978 ****
  {
  	char sizebuf[32];
  	FILE *file;
! 	int retry = 0, tos;
  
  	file_size = size;
  	byte_count = 0;
--- 979,985 ----
  {
  	char sizebuf[32];
  	FILE *file;
! 	int retry = 0, tos, keepalive;
  
  	file_size = size;
  	byte_count = 0;
***************
*** 1000,1005 ****
--- 1007,1018 ----
  		tos = IPTOS_THROUGHPUT;
  		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
  		    sizeof(int));
+ #endif
+ 		/* Set keep-alives on the socket to detect dropped conns. */
+ #ifdef SO_KEEPALIVE
+ 		keepalive = 1;
+ 		(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+ 		    (char *)&keepalive, sizeof(int));
  #endif
  		reply(150, "Opening %s mode data connection for '%s'%s.",
  		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);