From 80113f7d41d7c3c40c76ed49743aca5e286b5ca9 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 11 Sep 2009 19:31:52 +0000 Subject: [PATCH] Fix race condition that can cause close of socket to hang git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2037 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 3 +++ Documentation/NuttX.html | 5 ++++- net/net_close.c | 35 ++++++++++++++++++++--------------- net/uip/uip_tcpinput.c | 1 + 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index b26a42e3aa..93150d588a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -860,3 +860,6 @@ bug in polling for connections. The logic worked if the poll was inplace before the connection was received; but the poll failed to awaken if the connection was already pending in the backlog when poll() was called. + * net/net_close.c. Fixed another important TCP/IP race condition bug: If + the host closes the TCP connection just before the target calls close(), then + the close operation may hang indefinitely! diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 37caa79337..9c7269825f 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@

NuttX RTOS

-

Last Updated: September 10, 2009

+

Last Updated: September 11, 2009

@@ -1521,6 +1521,9 @@ nuttx-0.4.11 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> bug in polling for connections. The logic worked if the poll was inplace before the connection was received; but the poll failed to awaken if the connection was already pending in the backlog when poll() was called. + * net/net_close.c. Fixed another important TCP/IP race condition bug: If + the host closes the TCP connection just before the target calls close(), then + the close operation may hang indefinitely! pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/net/net_close.c b/net/net_close.c index eb7dbd7114..b05fc338f4 100644 --- a/net/net_close.c +++ b/net/net_close.c @@ -158,30 +158,35 @@ static inline void netclose_disconnect(FAR struct socket *psock) { struct uip_conn *conn = (struct uip_conn*)psock->s_conn; - /* Set up to receive TCP data event callbacks */ + /* Check for the case where the host beat us and disconnected first */ - state.cl_cb = uip_tcpcallbackalloc(conn); - if (state.cl_cb) + if (conn->tcpstateflags == UIP_ESTABLISHED) { - state.cl_psock = psock; - sem_init(&state.cl_sem, 0, 0); + /* Set up to receive TCP data event callbacks */ - state.cl_cb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT; - state.cl_cb->priv = (void*)&state; - state.cl_cb->event = netclose_interrupt; + state.cl_cb = uip_tcpcallbackalloc(conn); + if (state.cl_cb) + { + state.cl_psock = psock; + sem_init(&state.cl_sem, 0, 0); - /* Notify the device driver of the availaibilty of TX data */ + state.cl_cb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT; + state.cl_cb->priv = (void*)&state; + state.cl_cb->event = netclose_interrupt; - netdev_txnotify(&conn->ripaddr); + /* Notify the device driver of the availaibilty of TX data */ - /* Wait for the disconnect event */ + netdev_txnotify(&conn->ripaddr); - (void)sem_wait(&state.cl_sem); + /* Wait for the disconnect event */ - /* We are now disconnected */ + (void)sem_wait(&state.cl_sem); - sem_destroy(&state.cl_sem); - uip_tcpcallbackfree(conn, state.cl_cb); + /* We are now disconnected */ + + sem_destroy(&state.cl_sem); + uip_tcpcallbackfree(conn, state.cl_cb); + } } } diff --git a/net/uip/uip_tcpinput.c b/net/uip/uip_tcpinput.c index 3fc491f6b4..f417c2c7b0 100644 --- a/net/uip/uip_tcpinput.c +++ b/net/uip/uip_tcpinput.c @@ -166,6 +166,7 @@ void uip_tcpinput(struct uip_driver_s *dev) * least queue it it for acceptance). */ + conn->tcpstateflags = UIP_ESTABLISHED; if (uip_accept(dev, conn, tmp16) != OK) { /* No, then we have to give the connection back */