From 6cc69bfa5100230776910d8f1d463b113df5f561 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 6 Oct 2013 09:48:54 -0600 Subject: Make net_close() nonblocking and free unestablished connections if no free connections available. From Max Holtzberg --- nuttx/ChangeLog | 4 +- nuttx/include/nuttx/net/uip/uip-tcp.h | 21 +++++++-- nuttx/net/net_close.c | 87 ++++++++++++++++------------------- nuttx/net/uip/uip_tcpconn.c | 62 ++++++++++++++++++------- 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 * * 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 * * 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 * * 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); + + /* 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. */ -- cgit v1.2.3