net: tcp: Handle special case where accepted socket is closed

Handle this corner case with TCP connection closing:

1) Client A connects, it is accepted and can send data to us
2) Client B connects, the application needs to call accept()
   before we will receive any data from client A to the application.
   The app has not yet called accept() at this point (for
   whatever reason).
3) Client B then disconnects and we receive FIN. The connection
   cleanup is a bit tricky as the client is in half-connected state
   meaning that the connection is in established state but the
   accept_q in socket queue contains still data which needs to be
   cleared.
4) Client A then disconnects, all data is sent etc

The above was not working correctly as the system did not handle the
step 3) properly. The client B was accepted in the application even
if the connection was closing.

After this commit, the commit called "net: tcp: Accept connections
only in LISTENING state" and related other commits are no longer
needed and are reverted.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2019-10-17 16:42:22 +03:00
commit d88f25bd76
3 changed files with 113 additions and 7 deletions

View file

@ -58,6 +58,12 @@ enum net_context_state {
/** Remote address set */
#define NET_CONTEXT_REMOTE_ADDR_SET BIT(8)
/** Is the socket accepting connections */
#define NET_CONTEXT_ACCEPTING_SOCK BIT(9)
/** Is the socket closing / closed */
#define NET_CONTEXT_CLOSING_SOCK BIT(10)
struct net_context;
/**
@ -334,6 +340,70 @@ static inline bool net_context_is_used(struct net_context *context)
return context->flags & NET_CONTEXT_IN_USE;
}
/**
* @brief Is this context is accepting data now.
*
* @param context Network context.
*
* @return True if the context is accepting connections, False otherwise.
*/
static inline bool net_context_is_accepting(struct net_context *context)
{
NET_ASSERT(context);
return context->flags & NET_CONTEXT_ACCEPTING_SOCK;
}
/**
* @brief Set this context to accept data now.
*
* @param context Network context.
* @param accepting True if accepting, False if not
*/
static inline void net_context_set_accepting(struct net_context *context,
bool accepting)
{
NET_ASSERT(context);
if (accepting) {
context->flags |= NET_CONTEXT_ACCEPTING_SOCK;
} else {
context->flags &= ~NET_CONTEXT_ACCEPTING_SOCK;
}
}
/**
* @brief Is this context closing.
*
* @param context Network context.
*
* @return True if the context is closing, False otherwise.
*/
static inline bool net_context_is_closing(struct net_context *context)
{
NET_ASSERT(context);
return context->flags & NET_CONTEXT_CLOSING_SOCK;
}
/**
* @brief Set this context to closing.
*
* @param context Network context.
* @param closing True if closing, False if not
*/
static inline void net_context_set_closing(struct net_context *context,
bool closing)
{
NET_ASSERT(context);
if (closing) {
context->flags |= NET_CONTEXT_CLOSING_SOCK;
} else {
context->flags &= ~NET_CONTEXT_CLOSING_SOCK;
}
}
#define NET_CONTEXT_STATE_SHIFT 1
#define NET_CONTEXT_STATE_MASK 0x03