Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Mar 1999 08:40:01 -0800 (PST)
From:      Martin Kammerhofer <dada@localhost.tu-graz.ac.at>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/3948: nonworking t/tcp server side
Message-ID:  <199903301640.IAA17999@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/3948; it has been noted by GNATS.

From: Martin Kammerhofer <dada@localhost.tu-graz.ac.at>
To: FreeBSD problems <freebsd-gnats-submit@freebsd.org>
Cc: brian@firehouse.net
Subject: Re: kern/3948: nonworking t/tcp server side
Date: Tue, 30 Mar 1999 00:24:06 +0200 (CEST)

 The problem is a benign bug in tcp_output.c. It has nothing to do
 with delayed acks. It shows up when two conditions hold:
  1. The accepting server reads it's input before sending to the socket.
     (If the server writes a greeting message just after the accept, it
     will be piggy backed on the SYN/ACK segment as expected.)
  2. The server has a large socket buffer space compared to the
     MSS obtained from the clients initial packet.
 
 Here is in detail was goes wrong:
  1. The clients sends a SFP segment with request data to the server port.
  2. The server decides in tcp_input() do delay the ACK. (Until the
     TCP fast timer runs).
  3. The server accepts the connection.
  4. The server reads from the socket. tcp_usr_rcvd() (in tcp_usrreq.c)
     calls tcp_output() to check if a window update should be sent.
  5. It passes the following test [snippet from tcp_output.c]:
 	/*
 	 * Compare available window to amount of window
 	 * known to peer (as advertised window less
 	 * next expected input).  If the difference is at least two
 	 * max size segments, or at least 50% of the maximum possible
 	 * window, then want to send a window update to peer.
 	 */
 	if (win > 0) {
 		/*
 		 * "adv" is the amount we can increase the window,
 		 * taking into account that we are limited by
 		 * TCP_MAXWIN << tp->rcv_scale.
 		 */
 		long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
 			(tp->rcv_adv - tp->rcv_nxt);
 
 		if (adv >= (long) (2 * tp->t_maxseg))
 			goto send;
 		if (2 * adv >= (long) so->so_rcv.sb_hiwat)
 			goto send;
 	}
 	[end of snippet]
 	
     win is the amount of available space in the socket and is
     typically large because only one segment has been received.
  6. The "goto send" does what you expect from the label's name.
 
 Doing that test here in the context of a half synchronized T/TCP
 connection is a bug. The idea is to let the peer know that a
 considerable larger window is available now. But in T/TCP's half
 synchronized CLOSE-WAIT* state there is no window advertised to
 the client - the client has not seen any packet yet.
 The fix is simple: change the test from (win > 0) to
 (win > 0 && !(tp->t_flags & TF_NEEDSYN)). See below for a patch.
 
 Although this bug has been reported for FreeBSD 2.2.1 and I verified
 my fix with 2.2.8-STABLE it affects the MAIN branch too. (I looked
 into the repository version.)
 
 With this tiny patch you could get what rfc1644 promises on page 1:
 [quote]
 
    (d)  The minimum transaction latency for a client should be RTT +
         SPT, where RTT is the round-trip time and SPT is the server
         processing time.
 
    (e)  In favorable circumstances, a reliable request/response
         handshake should be achievable with exactly one packet in each
         direction.
 [quote off]
 
 What a pity that almost nobody uses T/TCP :(
 
 Regards,
   Martin
 --
 Kommunikation läßt sich durch nichts ersetzen.
 
 <=========== cut here ==============
 --- /src/sys/netinet/tcp_output.c.orig	Tue Mar 30 00:19:16 1999
 +++ /src/sys/netinet/tcp_output.c	Mon Mar 29 22:52:57 1999
 @@ -241,15 +241,15 @@
  	/*
  	 * Compare available window to amount of window
  	 * known to peer (as advertised window less
  	 * next expected input).  If the difference is at least two
  	 * max size segments, or at least 50% of the maximum possible
  	 * window, then want to send a window update to peer.
  	 */
 -	if (win > 0) {
 +	if (win > 0 && !(tp->t_flags & TF_NEEDSYN)) {
  		/*
  		 * "adv" is the amount we can increase the window,
  		 * taking into account that we are limited by
  		 * TCP_MAXWIN << tp->rcv_scale.
  		 */
  		long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
  			(tp->rcv_adv - tp->rcv_nxt);
 
 
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199903301640.IAA17999>