mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 23:40:19 +08:00
Make net_close() nonblocking and free unestablished connections if no free connections available. From Max Holtzberg
This commit is contained in:
@@ -5717,4 +5717,6 @@
|
|||||||
caused by the routing table. From Max Holtzberg (2013-10-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
|
* 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).
|
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).
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
* of C macros that are used by uIP programs as well as internal uIP
|
* of C macros that are used by uIP programs as well as internal uIP
|
||||||
* structures, TCP/IP header structures and function declarations.
|
* 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>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* This logic was leveraged from uIP which also has a BSD-style license:
|
* This logic was leveraged from uIP which also has a BSD-style license:
|
||||||
@@ -168,8 +169,8 @@ struct uip_conn
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_NET_TCPBACKLOG
|
#ifdef CONFIG_NET_TCPBACKLOG
|
||||||
struct uip_conn *blparent;
|
FAR struct uip_conn *blparent;
|
||||||
struct uip_backlog_s *backlog;
|
FAR struct uip_backlog_s *backlog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Application callbacks:
|
/* Application callbacks:
|
||||||
@@ -196,14 +197,24 @@ struct uip_conn
|
|||||||
* dev->d_len should also be cleared).
|
* 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 */
|
/* accept() is called when the TCP logic has created a connection */
|
||||||
|
|
||||||
FAR void *accept_private;
|
FAR void *accept_private;
|
||||||
int (*accept)(FAR struct uip_conn *listener, struct uip_conn *conn);
|
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;
|
FAR void *connection_private;
|
||||||
void (*connection_event)(FAR struct uip_conn *conn, uint16_t flags);
|
void (*connection_event)(FAR struct uip_conn *conn, uint16_t flags);
|
||||||
|
|||||||
+41
-48
@@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* net/net_close.c
|
* 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>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -87,38 +87,41 @@ struct tcp_close_s
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_NET_TCP
|
#ifdef CONFIG_NET_TCP
|
||||||
static uint16_t netclose_interrupt(struct uip_driver_s *dev, void *pvconn,
|
static uint16_t netclose_interrupt(FAR struct uip_driver_s *dev,
|
||||||
void *pvpriv, uint16_t flags)
|
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
|
/* The disconnection is complete */
|
||||||
* UIP_ABORT: The remote host has aborted the connection
|
|
||||||
|
conn->closecb->flags = 0;
|
||||||
|
conn->closecb->priv = NULL;
|
||||||
|
conn->closecb->event = NULL;
|
||||||
|
|
||||||
|
/* Free connection resources */
|
||||||
|
|
||||||
|
uip_tcpfree(conn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Drop data received in this state and make sure that UIP_CLOSE
|
||||||
|
* is set in the response
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((flags & (UIP_CLOSE|UIP_ABORT)) != 0)
|
dev->d_len = 0;
|
||||||
{
|
return (flags & ~UIP_NEWDATA) | UIP_CLOSE;
|
||||||
/* The disconnection is complete */
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
dev->d_len = 0;
|
|
||||||
return (flags & ~UIP_NEWDATA) | UIP_CLOSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags;
|
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;
|
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 */
|
/* Check for the case where the host beat us and disconnected first */
|
||||||
|
|
||||||
if (conn->tcpstateflags == UIP_ESTABLISHED)
|
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);
|
conn->closecb = uip_tcpcallbackalloc(conn);
|
||||||
if (state.cl_cb)
|
if (conn->closecb)
|
||||||
{
|
{
|
||||||
state.cl_psock = psock;
|
/* Set up to receive TCP data event callbacks */
|
||||||
sem_init(&state.cl_sem, 0, 0);
|
|
||||||
|
|
||||||
state.cl_cb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT;
|
conn->closecb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT;
|
||||||
state.cl_cb->priv = (void*)&state;
|
conn->closecb->event = netclose_interrupt;
|
||||||
state.cl_cb->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);
|
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;
|
struct uip_conn *conn = psock->s_conn;
|
||||||
|
|
||||||
/* Is this the last reference to the connection structure (there
|
/* 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)
|
if (conn->crefs <= 1)
|
||||||
{
|
{
|
||||||
/* Yes... free the connection structure */
|
/* Yes... then perform the disconnection now */
|
||||||
|
|
||||||
uip_unlisten(conn); /* No longer accepting connections */
|
uip_unlisten(conn); /* No longer accepting connections */
|
||||||
netclose_disconnect(psock); /* Break any current connections */
|
netclose_disconnect(psock); /* Break any current connections */
|
||||||
conn->crefs = 0; /* No more references on the connection */
|
conn->crefs = 0; /* No more references on the connection */
|
||||||
uip_tcpfree(conn); /* Free uIP resources */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+42
-14
@@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* net/uip/uip_tcpconn.c
|
* 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>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Large parts of this file were leveraged from uIP logic:
|
* Large parts of this file were leveraged from uIP logic:
|
||||||
@@ -36,10 +36,6 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Compilation Switches
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Included Files
|
* Included Files
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -221,23 +217,29 @@ struct uip_conn *uip_tcpalloc(void)
|
|||||||
|
|
||||||
conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections);
|
conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections);
|
||||||
|
|
||||||
#if 0 /* Revisit */
|
|
||||||
/* Is the free list empty? */
|
/* Is the free list empty? */
|
||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
{
|
{
|
||||||
/* As a fallback, check for connection structures in the TIME_WAIT
|
/* As a fallback, check for connection structures which are not
|
||||||
* state. If no CLOSED connections are found, then take the oldest
|
* 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;
|
struct uip_conn *tmp = g_active_tcp_connections.head;
|
||||||
while (tmp)
|
while (tmp)
|
||||||
{
|
{
|
||||||
/* Is this connectin in the UIP_TIME_WAIT state? */
|
nllvdbg("conn: %p state: %02x\n", tmp, tmp->tcpstateflags);
|
||||||
|
|
||||||
if (tmp->tcpstateflags == UIP_TIME_WAIT)
|
/* Is this connection in some state other than UIP_ESTABLISHED
|
||||||
|
* state?
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
if (!conn || tmp->timer > conn->timer)
|
||||||
{
|
{
|
||||||
@@ -252,11 +254,27 @@ struct uip_conn *uip_tcpalloc(void)
|
|||||||
tmp = tmp->node.flink;
|
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);
|
uip_unlock(flags);
|
||||||
|
|
||||||
@@ -264,6 +282,7 @@ struct uip_conn *uip_tcpalloc(void)
|
|||||||
|
|
||||||
if (conn)
|
if (conn)
|
||||||
{
|
{
|
||||||
|
memset(conn, 0, sizeof(struct uip_conn));
|
||||||
conn->tcpstateflags = UIP_ALLOCATED;
|
conn->tcpstateflags = UIP_ALLOCATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,6 +313,13 @@ void uip_tcpfree(struct uip_conn *conn)
|
|||||||
DEBUGASSERT(conn->crefs == 0);
|
DEBUGASSERT(conn->crefs == 0);
|
||||||
flags = uip_lock();
|
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
|
/* UIP_ALLOCATED means that that the connection is not in the active list
|
||||||
* yet.
|
* yet.
|
||||||
*/
|
*/
|
||||||
@@ -432,6 +458,7 @@ struct uip_conn *uip_tcplistener(uint16_t portno)
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,6 +511,7 @@ struct uip_conn *uip_tcpaccept(struct uip_tcpip_hdr *buf)
|
|||||||
|
|
||||||
dq_addlast(&conn->node, &g_active_tcp_connections);
|
dq_addlast(&conn->node, &g_active_tcp_connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user