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
This commit is contained in:
patacongo 2009-09-11 19:31:52 +00:00
parent c8dec461fc
commit 80113f7d41
4 changed files with 28 additions and 16 deletions

View File

@ -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!

View File

@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
<p>Last Updated: September 10, 2009</p>
<p>Last Updated: September 11, 2009</p>
</td>
</tr>
</table>
@ -1521,6 +1521,9 @@ nuttx-0.4.11 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
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 &lt;spudmonkey@racsa.co.cr&gt;

View File

@ -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);
}
}
}

View File

@ -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 */