Make net_close() nonblocking and free unestablished connections if no free connections available. From Max Holtzberg

This commit is contained in:
Gregory Nutt 2013-10-06 09:48:54 -06:00
parent d3fa588250
commit 4c884a5079
4 changed files with 105 additions and 71 deletions

View File

@ -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).

View File

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

View File

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

View File

@ -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:
@ -36,10 +36,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);
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)
{
@ -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.
*/