Subject: Re: FIN_WAIT_2 and timeouts?
To: None <netbsd-help@netbsd.org>
From: James K. Lowden <jklowden@schemamania.org>
List: netbsd-help
Date: 02/20/2002 00:00:08
On Tue, Feb 19, 2002 at 04:43:59PM -0800, Tracy Nelson wrote:
> From: "Jeremy C. Reed" <reed@reedmedia.net>
> > > Where can I learn about the timeouts for FIN_WAIT_2?
> 
> The Apache docs give some information about FIN_WAIT_2.  Apparently, the
> TCP/IP spec doesn't mandate a timeout when closing both sides of a
> connection.  On systems that don't implement this timeout, connections can
> hang indefinitely in FIN_WAIT_2.  They suggest getting the latest TCP/IP
> patches for your distribution.  I'm not familiar enough with TCP stacks to
> check the source and see what's up with NetBSD, maybe it's possible that a
> timeout needs to be added.  Seems strange, though, I thought NetBSD had a
> pretty good stack.

I haven't done anything with the kernel besides build it and read
McKusick's book, but from his description and a look at the sources,
the NetBSD TCP stack implements a timeout on FIN_WAIT_2.  It is done
in src/sys/netinet/tcp_input.c and src/sys/netinet/tcp_usrreq.c.  

tcp_input.c:
	 	/*
		 * In FIN_WAIT_2 state enter the TIME_WAIT state,
		 * starting the time-wait timer, turning off the other 
		 * standard timers.
		 */
		case TCPS_FIN_WAIT_2:
			tp->t_state = TCPS_TIME_WAIT;
			tcp_canceltimers(tp);
			TCP_TIMER_ARM(tp, TCPT_2MSL, 2 * TCPTV_MSL);
			soisdisconnected(so);
			break;
			
tcp_usrreq.c
		/*
		 * If we are in FIN_WAIT_2, we arrived here because the
		 * application did a shutdown of the send side.  Like the
		 * case of a transition from FIN_WAIT_1 to FIN_WAIT_2 after
		 * a full close, we start a timer to make sure sockets are
		 * not left in FIN_WAIT_2 forever.
		 */
		if ((tp->t_state == TCPS_FIN_WAIT_2) && (tcp_maxidle > 0))
			TCP_TIMER_ARM(tp, TCPT_2MSL, tcp_maxidle);

The tcp_input.c use is (I think) straightforward:  TCPTV_MSL is
defined in /usr/include/netinet/tcp_timer.h as:
	#define	TCPTV_MSL	( 30*PR_SLOWHZ)
which is in /usr/include/sys/protosw.h:
	#define	PR_SLOWHZ	2		/* 2 slow timeouts per second */
	
So I think we're at 2 * 30 * 1/2 = 30 seconds for the FIN_WAIT_2
timer.  

The tcp_input.c use gets nasty quickly.  tcp_maxidle is a global
variable initialized from tcp_keepcnt * tcp_keepintvl (8 and
75*PR_SLOWHZ, respectively, i.e. 5 minutes) in
src/sys/netinet/tcp_timer.c::tcp_slowtimo().  But the addresses of
tcp_keepcnt and tcp_keepintvl get passed around as part of a
TCPCTL_VARIABLES structure to sysctl among other places, so it's
hardly invulnerable to change.  You can set them yourself with
sysctl(8).  

And as you can see, if the tcp_maxidle were to become zero (or
negative??) somehow, then there's no timeout and it will wait forever.
For some value of "forever", of course.  

It looks to me that if it ain't timed out yet, it ain't gonna. 
Whether that's a bug or a feature, I don't know.  

Regards, 

--jkl