summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-06 09:48:54 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-06 09:48:54 -0600
commit6cc69bfa5100230776910d8f1d463b113df5f561 (patch)
tree56c9b8513f083968d9531df21b0656861215585d
parent242d6094be6146c200ed4e8aeb09b956f1f9ebce (diff)
downloadnuttx-6cc69bfa5100230776910d8f1d463b113df5f561.tar.gz
nuttx-6cc69bfa5100230776910d8f1d463b113df5f561.tar.bz2
nuttx-6cc69bfa5100230776910d8f1d463b113df5f561.zip
Make net_close() nonblocking and free unestablished connections if no free connections available. From Max Holtzberg
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/include/nuttx/net/uip/uip-tcp.h21
-rw-r--r--nuttx/net/net_close.c87
-rw-r--r--nuttx/net/uip/uip_tcpconn.c62
4 files changed, 104 insertions, 70 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 12bcaa04e..96c1c8ba0 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5717,4 +5717,6 @@
caused by the routing table. From Max Holtzberg (2013-10-6).
* arch/arm/src/sama5/sam_lcdc.c and .h: Empty "skeleton" file that
will eventually become an LCDC driver for the SAMA5 (2013-10-6).
-
+ * net/net_close.c, net/uip/uip_tcpcon, and include/nuttx/net/uip/uip-tcp.h:
+ Make net_close() nonblocking and free unestablished connections if no
+ free connections available. From Max Holtzber (2013-10-6).
diff --git a/nuttx/include/nuttx/net/uip/uip-tcp.h b/nuttx/include/nuttx/net/uip/uip-tcp.h
index 80ab0229c..50b3e3c92 100644
--- a/nuttx/include/nuttx/net/uip/uip-tcp.h
+++ b/nuttx/include/nuttx/net/uip/uip-tcp.h
@@ -6,7 +6,8 @@
* of C macros that are used by uIP programs as well as internal uIP
* structures, TCP/IP header structures and function declarations.
*
- * Copyright (C) 2007, 2009-2010, 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009-2010, 2012-2013 Gregory Nutt. All rights
+ * reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This logic was leveraged from uIP which also has a BSD-style license:
@@ -168,8 +169,8 @@ struct uip_conn
*/
#ifdef CONFIG_NET_TCPBACKLOG
- struct uip_conn *blparent;
- struct uip_backlog_s *backlog;
+ FAR struct uip_conn *blparent;
+ FAR struct uip_backlog_s *backlog;
#endif
/* Application callbacks:
@@ -196,14 +197,24 @@ struct uip_conn
* dev->d_len should also be cleared).
*/
- struct uip_callback_s *list;
+ FAR struct uip_callback_s *list;
+
+ /* Close callback. The socket close logic allocates this callback and lets
+ * the connection handle closing itself. So the application won't be
+ * blocked on the close call. The callback has to be freed together with
+ * this connection structure.
+ */
+
+ FAR struct uip_callback_s *closecb;
/* accept() is called when the TCP logic has created a connection */
FAR void *accept_private;
int (*accept)(FAR struct uip_conn *listener, struct uip_conn *conn);
- /* connection_event() is called on any of the subset of connection-related events */
+ /* connection_event() is called on any of the subset of connection-related
+ * events.
+ */
FAR void *connection_private;
void (*connection_event)(FAR struct uip_conn *conn, uint16_t flags);
diff --git a/nuttx/net/net_close.c b/nuttx/net/net_close.c
index 10f7e199e..6e14cafb0 100644
--- a/nuttx/net/net_close.c
+++ b/nuttx/net/net_close.c
@@ -1,7 +1,7 @@
/****************************************************************************
* net/net_close.c
*
- * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -87,38 +87,41 @@ struct tcp_close_s
****************************************************************************/
#ifdef CONFIG_NET_TCP
-static uint16_t netclose_interrupt(struct uip_driver_s *dev, void *pvconn,
- void *pvpriv, uint16_t flags)
+static uint16_t netclose_interrupt(FAR struct uip_driver_s *dev,
+ FAR void *pvconn, FAR void *pvpriv,
+ uint16_t flags)
{
- struct tcp_close_s *pstate = (struct tcp_close_s *)pvpriv;
+ FAR struct uip_conn *conn = (FAR struct uip_conn*)pvconn;
- nllvdbg("flags: %04x\n", flags);
+ DEBUGASSERT(conn != NULL);
- if (pstate)
+ nlldbg("flags: %04x\n", flags);
+
+ /* UIP_CLOSE: The remote host has closed the connection
+ * UIP_ABORT: The remote host has aborted the connection
+ * UIP_TIMEDOUT: The remote did not respond, the connection timed out
+ */
+
+ if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0)
{
- /* UIP_CLOSE: The remote host has closed the connection
- * UIP_ABORT: The remote host has aborted the connection
- */
+ /* The disconnection is complete */
- if ((flags & (UIP_CLOSE|UIP_ABORT)) != 0)
- {
- /* The disconnection is complete */
+ conn->closecb->flags = 0;
+ conn->closecb->priv = NULL;
+ conn->closecb->event = NULL;
- pstate->cl_cb->flags = 0;
- pstate->cl_cb->priv = NULL;
- pstate->cl_cb->event = NULL;
- sem_post(&pstate->cl_sem);
- nllvdbg("Resuming\n");
- }
- else
- {
- /* Drop data received in this state and make sure that UIP_CLOSE
- * is set in the response
- */
+ /* Free connection resources */
- dev->d_len = 0;
- return (flags & ~UIP_NEWDATA) | UIP_CLOSE;
- }
+ uip_tcpfree(conn);
+ }
+ else
+ {
+ /* Drop data received in this state and make sure that UIP_CLOSE
+ * is set in the response
+ */
+
+ dev->d_len = 0;
+ return (flags & ~UIP_NEWDATA) | UIP_CLOSE;
}
return flags;
@@ -158,34 +161,25 @@ static inline void netclose_disconnect(FAR struct socket *psock)
{
struct uip_conn *conn = (struct uip_conn*)psock->s_conn;
+ DEBUGASSERT(conn->closecb == NULL);
+
/* Check for the case where the host beat us and disconnected first */
if (conn->tcpstateflags == UIP_ESTABLISHED)
{
- /* Set up to receive TCP data event callbacks */
+ /* This callback will be freed together with conn */
- state.cl_cb = uip_tcpcallbackalloc(conn);
- if (state.cl_cb)
+ conn->closecb = uip_tcpcallbackalloc(conn);
+ if (conn->closecb)
{
- 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;
+ conn->closecb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT;
+ conn->closecb->event = netclose_interrupt;
- /* Notify the device driver of the availaibilty of TX data */
+ /* Notify the device driver of the availaibilty of TX data */
netdev_txnotify(conn->ripaddr);
-
- /* Wait for the disconnect event */
-
- (void)uip_lockedwait(&state.cl_sem);
-
- /* We are now disconnected */
-
- sem_destroy(&state.cl_sem);
- uip_tcpcallbackfree(conn, state.cl_cb);
}
}
}
@@ -242,17 +236,16 @@ int psock_close(FAR struct socket *psock)
struct uip_conn *conn = psock->s_conn;
/* Is this the last reference to the connection structure (there
- * could be more if the socket was dup'ed.
+ * could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
- /* Yes... free the connection structure */
+ /* Yes... then perform the disconnection now */
uip_unlisten(conn); /* No longer accepting connections */
netclose_disconnect(psock); /* Break any current connections */
conn->crefs = 0; /* No more references on the connection */
- uip_tcpfree(conn); /* Free uIP resources */
}
else
{
diff --git a/nuttx/net/uip/uip_tcpconn.c b/nuttx/net/uip/uip_tcpconn.c
index 31e020f63..7724eacbd 100644
--- a/nuttx/net/uip/uip_tcpconn.c
+++ b/nuttx/net/uip/uip_tcpconn.c
@@ -1,7 +1,7 @@
/****************************************************************************
* net/uip/uip_tcpconn.c
*
- * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2011, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Large parts of this file were leveraged from uIP logic:
@@ -37,10 +37,6 @@
****************************************************************************/
/****************************************************************************
- * Compilation Switches
- ****************************************************************************/
-
-/****************************************************************************
* Included Files
****************************************************************************/
@@ -221,23 +217,29 @@ struct uip_conn *uip_tcpalloc(void)
conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections);
-#if 0 /* Revisit */
/* Is the free list empty? */
if (!conn)
{
- /* As a fallback, check for connection structures in the TIME_WAIT
- * state. If no CLOSED connections are found, then take the oldest
+ /* As a fallback, check for connection structures which are not
+ * established yet.
+ *
+ * Search the active connection list for the oldest connection
+ * that is not in the UIP_ESTABLISHED state.
*/
struct uip_conn *tmp = g_active_tcp_connections.head;
while (tmp)
{
- /* Is this connectin in the UIP_TIME_WAIT state? */
+ nllvdbg("conn: %p state: %02x\n", tmp, tmp->tcpstateflags);
+
+ /* Is this connection in some state other than UIP_ESTABLISHED
+ * state?
+ */
- if (tmp->tcpstateflags == UIP_TIME_WAIT)
+ if (tmp->tcpstateflags != UIP_ESTABLISHED)
{
- /* Is it the oldest one we have seen so far? */
+ /* Yes.. Is it the oldest one we have seen so far? */
if (!conn || tmp->timer > conn->timer)
{
@@ -252,11 +254,27 @@ struct uip_conn *uip_tcpalloc(void)
tmp = tmp->node.flink;
}
- /* If we found one, remove it from the active connection list */
+ /* Did we find a connection that we can re-use? */
- dq_rem(&conn->node, &g_active_tcp_connections);
+ if (conn != NULL)
+ {
+ nlldbg("Closing unestablished connection: %p\n", conn);
+
+ /* Yes... free it. This will remove the connection from the list
+ * of active connections and release all resources held by the
+ * connection.
+ *
+ * REVISIT: Could there be any higher level, socket interface
+ * that needs to be informed that we did this to them?
+ */
+
+ uip_tcpfree(conn);
+
+ /* Now there is guaranteed to be one free connection. Get it! */
+
+ conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections);
+ }
}
-#endif
uip_unlock(flags);
@@ -264,6 +282,7 @@ struct uip_conn *uip_tcpalloc(void)
if (conn)
{
+ memset(conn, 0, sizeof(struct uip_conn));
conn->tcpstateflags = UIP_ALLOCATED;
}
@@ -294,6 +313,13 @@ void uip_tcpfree(struct uip_conn *conn)
DEBUGASSERT(conn->crefs == 0);
flags = uip_lock();
+ /* Check if there is an allocated close callback structure */
+
+ if (conn->closecb != NULL)
+ {
+ uip_tcpcallbackfree(conn, conn->closecb);
+ }
+
/* UIP_ALLOCATED means that that the connection is not in the active list
* yet.
*/
@@ -354,7 +380,7 @@ void uip_tcpfree(struct uip_conn *conn)
struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf)
{
struct uip_conn *conn = (struct uip_conn *)g_active_tcp_connections.head;
- in_addr_t srcipaddr = uip_ip4addr_conv(buf->srcipaddr);
+ in_addr_t srcipaddr = uip_ip4addr_conv(buf->srcipaddr);
while (conn)
{
@@ -421,7 +447,7 @@ struct uip_conn *uip_tcplistener(uint16_t portno)
int i;
/* Check if this port number is in use by any active UIP TCP connection */
-
+
for (i = 0; i < CONFIG_NET_TCP_CONNS; i++)
{
conn = &g_tcp_connections[i];
@@ -432,6 +458,7 @@ struct uip_conn *uip_tcplistener(uint16_t portno)
return conn;
}
}
+
return NULL;
}
@@ -484,6 +511,7 @@ struct uip_conn *uip_tcpaccept(struct uip_tcpip_hdr *buf)
dq_addlast(&conn->node, &g_active_tcp_connections);
}
+
return conn;
}
@@ -569,7 +597,7 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr)
uip_lock_t flags;
int port;
- /* The connection is expected to be in the UIP_ALLOCATED state.. i.e.,
+ /* The connection is expected to be in the UIP_ALLOCATED state.. i.e.,
* allocated via up_tcpalloc(), but not yet put into the active connections
* list.
*/