From owner-freebsd-bugs Tue Mar 30 8:40:19 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id 5A27914CFD for ; Tue, 30 Mar 1999 08:40:18 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.2/8.9.2) id IAA17999; Tue, 30 Mar 1999 08:40:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Date: Tue, 30 Mar 1999 08:40:01 -0800 (PST) Message-Id: <199903301640.IAA17999@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Martin Kammerhofer Subject: Re: kern/3948: nonworking t/tcp server side Reply-To: Martin Kammerhofer Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org The following reply was made to PR kern/3948; it has been noted by GNATS. From: Martin Kammerhofer To: FreeBSD problems 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