[PATCH 3/4]: Integrate state transitions for passive-close

2007-11-28 Thread Gerrit Renker
[DCCP]: Integrate state transitions for passive-close

This adds the necessary state transitions for the two forms of passive-close

 * PASSIVE_CLOSE- which is entered when a host   receives a Close;
 * PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.

Here is a detailed account of what the patch does in each state.
  
1) Receiving CloseReq
--
  The pseudo-code in 8.5 says:

 Step 13: Process CloseReq
  If P.type == CloseReq and S.state  CLOSEREQ,
  Generate Close
  S.state := CLOSING
  Set CLOSING timer.

  This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, 
PARTOPEN, and OPEN.

   * CLOSED: silently ignore - it may be a late or duplicate CloseReq;
   * LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know 
we are the client);
   * REQUEST:perform Step 13 directly (no need to enqueue packet);
   * OPEN/PARTOPEN:  enter PASSIVE_CLOSEREQ so that the application has a 
chance to process unread data.

  When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any 
other state, the CloseReq is ignored.
  I think that this offers some robustness against rare and pathological cases: 
e.g. a simultaneous close where
  the client sends a Close and the server a CloseReq. The client will then be 
retransmitting its Close until it
  gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
  
2) Receiving Close
---
  The code below from 8.5 is unconditional.

 Step 14: Process Close
  If P.type == Close,
  Generate Reset(Closed)
  Tear down connection
  Drop packet and return

  Thus we need to consider all states:
   * CLOSED:   silently ignore, since this can happen when a 
retransmitted or late Close arrives;
   * LISTEN:   dccp_rcv_state_process() will generate a Reset (No 
Connection);
   * REQUEST:  perform Step 14 directly (no need to enqueue packet);
   * RESPOND:  dccp_check_req() will generate a Reset (Packet Error) 
-- left it at that;
   * OPEN/PARTOPEN:enter PASSIVE_CLOSE so that application has a chance to 
process unread data;
   * CLOSEREQ: server performed active-close -- perform Step 14;
   * CLOSING:  simultaneous-close: use a tie-breaker to avoid message 
ping-pong (see comment);
   * PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq 
and now a Close);
   * TIMEWAIT: packet is ignored.

   Note that the condition of receiving a packet in state CLOSED here is 
different from the condition there
   is no socket for such a connection: the socket still exists, but its state 
indicates it is unusable.

   Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = 
TCP_CLOSING, so that 
   sk_stream_wait_close() will wait for the final Reset (which will trigger 
CLOSING = CLOSED).

Signed-off-by: Gerrit Renker [EMAIL PROTECTED]
---
 include/linux/dccp.h |1 
 net/dccp/input.c |   88 ++-
 net/dccp/proto.c |   88 +--
 3 files changed, 131 insertions(+), 46 deletions(-)

--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -32,16 +32,56 @@ static void dccp_fin(struct sock *sk, st
sk-sk_data_ready(sk, 0);
 }
 
-static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
+static int dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
 {
-   dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
-   dccp_fin(sk, skb);
-   dccp_set_state(sk, DCCP_CLOSED);
-   sk_wake_async(sk, 1, POLL_HUP);
+   int queued = 0;
+
+   switch (sk-sk_state) {
+   /*
+* We ignore Close when received in one of the following states:
+*  - CLOSED(may be a late or duplicate packet)
+*  - PASSIVE_CLOSEREQ  (the peer has sent a CloseReq earlier)
+*  - RESPOND   (already handled by dccp_check_req)
+*/
+   case DCCP_CLOSING:
+   /*
+* Simultaneous-close: receiving a Close after sending one. This
+* can happen if both client and server perform active-close and
+* will result in an endless ping-pong of crossing and retrans-
+* mitted Close packets, which only terminates when one of the
+* nodes times out (min. 64 seconds). Quicker convergence can be
+* achieved when one of the nodes acts as tie-breaker.
+* This is ok as both ends are done with data transfer and each
+* end is just waiting for the other to acknowledge termination.
+*/
+   if (dccp_sk(sk)-dccps_role != DCCP_ROLE_CLIENT)
+   break;
+   /* fall through */
+   case DCCP_REQUESTING:
+   case DCCP_ACTIVE_CLOSEREQ:
+   

Re: [PATCH 3/4]: Integrate state transitions for passive-close

2007-11-28 Thread Arnaldo Carvalho de Melo
Em Wed, Nov 28, 2007 at 08:35:10AM +, Gerrit Renker escreveu:
 [DCCP]: Integrate state transitions for passive-close
 
 This adds the necessary state transitions for the two forms of passive-close
 
  * PASSIVE_CLOSE- which is entered when a host   receives a Close;
  * PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
 
 Here is a detailed account of what the patch does in each state.
   
 1) Receiving CloseReq
 --
   The pseudo-code in 8.5 says:
 
  Step 13: Process CloseReq
   If P.type == CloseReq and S.state  CLOSEREQ,
   Generate Close
   S.state := CLOSING
   Set CLOSING timer.
 
   This means we need to address what to do in CLOSED, LISTEN, REQUEST, 
 RESPOND, PARTOPEN, and OPEN.
 
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we 
 know we are the client);
* REQUEST:perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN:  enter PASSIVE_CLOSEREQ so that the application has a 
 chance to process unread data.
 
   When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any 
 other state, the CloseReq is ignored.
   I think that this offers some robustness against rare and pathological 
 cases: e.g. a simultaneous close where
   the client sends a Close and the server a CloseReq. The client will then be 
 retransmitting its Close until it
   gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
   
 2) Receiving Close
 ---
   The code below from 8.5 is unconditional.
 
  Step 14: Process Close
   If P.type == Close,
   Generate Reset(Closed)
   Tear down connection
   Drop packet and return
 
   Thus we need to consider all states:
* CLOSED:   silently ignore, since this can happen when a 
 retransmitted or late Close arrives;
* LISTEN:   dccp_rcv_state_process() will generate a Reset (No 
 Connection);
* REQUEST:  perform Step 14 directly (no need to enqueue packet);
* RESPOND:  dccp_check_req() will generate a Reset (Packet 
 Error) -- left it at that;
* OPEN/PARTOPEN:enter PASSIVE_CLOSE so that application has a chance 
 to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING:  simultaneous-close: use a tie-breaker to avoid message 
 ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq 
 and now a Close);
* TIMEWAIT: packet is ignored.
 
Note that the condition of receiving a packet in state CLOSED here is 
 different from the condition there
is no socket for such a connection: the socket still exists, but its 
 state indicates it is unusable.
 
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = 
 TCP_CLOSING, so that 
sk_stream_wait_close() will wait for the final Reset (which will trigger 
 CLOSING = CLOSED).
 
 Signed-off-by: Gerrit Renker [EMAIL PROTECTED]

Applied
-
To unsubscribe from this list: send the line unsubscribe dccp in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html