Re: [PATCH 3/10]: Dedicated auxiliary states to support passive-close

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Em Thu, Jul 12, 2007 at 03:23:39PM +0100, Gerrit Renker escreveu:
> [DCCP]: Dedicated auxiliary states to support passive-close
> 
> This adds two auxiliary states to deal with passive closes:
>   * PASSIVE_1 (reached from OPEN via reception of Close) and
>   * PASSIVE_2 (reached from OPEN via reception of CloseReq)


Perhaps we should rename PASSIVE_1 (magic number) to PASSIVE_CLOSEREQ
and PASSIVE_2 to PASSIVE_CLOSE, and also CLOSEREQ to ACTIVE_CLOSEREQ?

I'll defer these patches till we get some more discussion. There are
many more unrelated patches to work on after all :)

- Arnaldo

> to the internal state machine.
> 
> The PASSIVE_1 and PASSIVE_2 states represent the two ways a passive-close
> can happen in DCCP.  The addition of these states is not merely to
> increase clarity. These states are required by the implementation to
> allow a receiver to process unread data before acknowledging the received
> connection-termination-request (i.e. the Close/CloseReq).
> 
> Fix:
> ----
>  This patch uses the PASSIVE_1 and PASSIVE_2 states to explicitly refer to
>  passive-closing states and to protect against external wipeout of internal
>  receive queues. The macroscopic behaviour is compatible with RFC 4340, but
>  without the auxiliary states, buggy, absurd and abnormal behaviour of the
>  socket API will continue. Which is to say, without auxiliary states it does
>  not work.
> 
>  As a consequence, the count of DCCP_STATE_MASK has been increased, to account
>  for the number of new states. 
> 
> 
> Implementation Note:
> --------------------
>  To keep compatibility with sk_stream_wait_connect():
>  * DCCP_CLOSING continues to map into TCP_CLOSING (since this state can be
>    either passive- or active-close)
>  * DCCP_CLOSEREQ maps into TCP_FIN_WAIT1 (since it is always active-close)
> 
>  It is tempting to keep the clever merge of the CLOSEREQ and CLOSING states.
>  However, with the number of possible state transitions, this would require:
> 
>  * quite a number of `if' statements to distinguish all predecessors of
>    the CLOSING state (server/client, active/passive, server timewait yes/no);
> 
>  * two different branches from the CLOSING state:
>    - to TIMEWAIT if it is not an active server-close without keeping timewait state
>    - to CLOSED otherwise (and requiring to receive a Close instead of a Reset).
>  
>  In light of this, I think it is cleaner to implement separate CLOSEREQ and CLOSING
>  states (this is done by the subsequent patches).
> 
> Further documentation is on http://www.erg.abdn.ac.uk/users/gerrit/dccp/docs/closing_states/
> 
> 
>                     Why this is necessary [can be removed]
>                     --------------------------------------
> 
>  The two states are not mentioned in the DCCP specification [RFC 4340, 8.4].
>  In fact, RFC 4340 is silent about passive-close. In a nutshell, suppose that
>  the CLOSE_WAIT and LAST_ACK states were removed from TCP, i.e. a FIN triggers
>  direct transition from ESTABLISHED to CLOSED - similar problem. 
>  The detailed account is as follows.
> 
>  The first problem lies in using inet_stream_connect():
> 
>  An absurd case arises if we let the protocol machinery, not the application,
>  go through the states. If the protocol machinery allows to proceed to DCCP_CLOSED
>  (which corresponds to TCP_CLOSE), connect() returns with -ECONNABORTED, even if
>  there was data in the receive queue. 
> 
>  Therefore, if we want to keep the useful abstraction of inet_stream_connect(), we
>  need to make sure that a passive close can not lead to DCCP_CLOSE via the protocol
>  machinery alone. 
> 
>  The second problem is also related to entering DCCP_CLOSED too early: 
> 
>  Even if connect() were fixed, if a passive-close can directly trigger a state 
>  transition from OPEN to DCCP_CLOSED, the receiver may not be able to read data
>  from its input queue. The reason is that the input queue has already been wiped, 
>  DCCP_CLOSED state has been entered, while the SOCK_DONE flag has not yet been set.
>  Consequently, any subsequent call to dccp_recvmsg terminates in -ENOTCONN, 
>  and this despite of a potentially full receive queue.
> 
> 
> Signed-off-by: Gerrit Renker <gerrit@xxxxxxxxxxxxxx>
> ---
>  include/linux/dccp.h |   22 +++++++++++++++++++++-
>  net/dccp/proto.c     |    3 +++
>  2 files changed, 24 insertions(+), 1 deletion(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -230,16 +230,35 @@ enum dccp_state {
>  	DCCP_REQUESTING	= TCP_SYN_SENT,
>  	DCCP_LISTEN	= TCP_LISTEN,
>  	DCCP_RESPOND	= TCP_SYN_RECV,
> +	/*
> +	 *			Close states:
> +	 *
> +	 * CLOSEREQ is active-server close only.
> +	 * CLOSING can have three different meanings [RFC 4340, 8.3]:
> +	 *  a. Client has performed active-close, sent a Close to peer from
> +	 *     state OPEN or PARTOPEN, waiting for the final Reset
> +	 *     (in this case, SOCK_DONE == 1).
> +	 *  b. Client performs passive-Close, by receiving an CloseReq in OPEN
> +	 *     or PARTOPEN state. It sends a Close and waits for final Reset
> +	 *     (in this case, SOCK_DONE == 0).
> +	 *  c. Server decides to hold TIMEWAIT state & performs an active-close.
> +	 * To avoid erasing receive queues too early, the transitional states
> +	 * PASSIVE_1 (from OPEN => CLOSED) and PASSIVE_2 (from (PART)OPEN to
> +	 * CLOSING, corresponds to (b) above) are used.
> +	 */
> +	DCCP_CLOSEREQ	= TCP_FIN_WAIT1,
>  	DCCP_CLOSING	= TCP_CLOSING,
>  	DCCP_TIME_WAIT	= TCP_TIME_WAIT,
>  	DCCP_CLOSED	= TCP_CLOSE,
>  	/* Everything below here is specific to DCCP only */
>  	DCCP_INTRINSICS = TCP_MAX_STATES,
>  	DCCP_PARTOPEN,
> +	DCCP_PASSIVE_1,		/* any node receiving a Close  */
> +	DCCP_PASSIVE_2,		/* client receiving a CloseReq */
>  	DCCP_MAX_STATES
>  };
>  
> -#define DCCP_STATE_MASK 0xf
> +#define DCCP_STATE_MASK 0x1f
>  #define DCCP_ACTION_FIN (1<<7)
>  
>  enum {
> @@ -247,6 +266,7 @@ enum {
>  	DCCPF_REQUESTING = TCPF_SYN_SENT,
>  	DCCPF_LISTEN	 = TCPF_LISTEN,
>  	DCCPF_RESPOND	 = TCPF_SYN_RECV,
> +	DCCPF_CLOSEREQ	 = TCPF_FIN_WAIT1,
>  	DCCPF_CLOSING	 = TCPF_CLOSING,
>  	DCCPF_TIME_WAIT	 = TCPF_TIME_WAIT,
>  	DCCPF_CLOSED	 = TCPF_CLOSE,
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -139,6 +139,9 @@ const char *dccp_state_name(const int st
>  	[DCCP_LISTEN]	  = "LISTEN",
>  	[DCCP_RESPOND]	  = "RESPOND",
>  	[DCCP_CLOSING]	  = "CLOSING",
> +	[DCCP_CLOSEREQ]	  = "CLOSEREQ",
> +	[DCCP_PASSIVE_1]  = "PASSIVE_1",
> +	[DCCP_PASSIVE_2]  = "PASSIVE_2",
>  	[DCCP_TIME_WAIT]  = "TIME_WAIT",
>  	[DCCP_CLOSED]	  = "CLOSED",
>  	};
> -
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
-
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux