Subject: FTPD semi-zombies
To: None <tech-net@netbsd.org, current-users@netbsd.org>
From: Allen Briggs <briggs@ninthwonder.com>
List: current-users
Date: 06/02/1999 22:44:14
A couple of folks on current-users complained a while back about seeing
ftpd processes hanging around for connections that obviously should have
been dropped due to inactivity or a lost network connection or something
(I usually see them from dialups or overseas--often from browser
connections, too).

This seems to me to be a natural use for keepalives, and I put together
the following patch to set keepalives on the ftpd sockets.  I've had
this patch around for a while, and I'd like to get it into the tree,
but I'd like to see some other people express some opinion on the patch
before I commit it.  Any takers?

Thanks,
-allen

Here's the patch...

Index: ftpd.c
===================================================================
RCS file: /cvsroot/basesrc/libexec/ftpd/ftpd.c,v
retrieving revision 1.65
diff -c -r1.65 ftpd.c
*** ftpd.c	1999/05/24 21:57:19	1.65
--- ftpd.c	1999/06/03 02:39:32
***************
*** 237,243 ****
  	int argc;
  	char *argv[];
  {
! 	int addrlen, ch, on = 1, tos;
  	char *cp, line[LINE_MAX];
  	FILE *fd;
  #ifdef KERBEROS5  
--- 237,243 ----
  	int argc;
  	char *argv[];
  {
! 	int addrlen, ch, on = 1, tos, keepalive;
  	char *cp, line[LINE_MAX];
  	FILE *fd;
  #ifdef KERBEROS5  
***************
*** 328,333 ****
--- 328,340 ----
  	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  		syslog(LOG_ERR, "setsockopt: %m");
  #endif
+ 	/* Set keepalives 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)
***************
*** 1021,1026 ****
--- 1028,1036 ----
  	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  	    (char *) &on, sizeof(on)) < 0)
  		goto bad;
+ 	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+ 	    (char *) &on, sizeof(on)) < 0)
+ 		goto bad;
  	/* anchor socket to avoid multi-homing problems */
  	data_source.sin_len = sizeof(struct sockaddr_in);
  	data_source.sin_family = AF_INET;
***************
*** 1057,1063 ****
  {
  	char sizebuf[32];
  	FILE *file;
! 	int retry = 0, tos;
  
  	file_size = size;
  	byte_count = 0;
--- 1067,1073 ----
  {
  	char sizebuf[32];
  	FILE *file;
! 	int retry = 0, tos, keepalive;
  
  	file_size = size;
  	byte_count = 0;
***************
*** 1085,1090 ****
--- 1095,1106 ----
  		tos = IPTOS_THROUGHPUT;
  		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
  		    sizeof(int));
+ #endif
+ 		/* Set keepalives 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);