Networking: TCP disconnection callbacks are not retained in a list. This will support mutiple callbacks per lower-level TCP connection structure. That is necessary for the cae where a socket is dup'ed and shares the same lower-level connection structure. NOTE: There still needs to be a call to tcp_start_monitor() when the socket is dup'ed.

This commit is contained in:
Gregory Nutt 2017-08-29 10:38:01 -06:00
parent ed58536c3a
commit 9db65dea78
3 changed files with 77 additions and 86 deletions

View File

@ -74,15 +74,6 @@
#define tcp_callback_free(conn,cb) \ #define tcp_callback_free(conn,cb) \
devif_conn_callback_free((conn)->dev, (cb), &(conn)->list) devif_conn_callback_free((conn)->dev, (cb), &(conn)->list)
/* These macros allocate and free callback structures used for receiving
* notifications of device-related events.
*/
#define tcp_monitor_callback_alloc(conn) \
devif_callback_alloc((conn)->dev, NULL)
#define tcp_monitor_callback_free(conn,cb) \
devif_conn_callback_free((conn)->dev, (cb), NULL)
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* TCP write buffer access macros */ /* TCP write buffer access macros */
@ -231,6 +222,14 @@ struct tcp_conn_s
FAR struct devif_callback_s *list; FAR struct devif_callback_s *list;
/* connevents is a list of callbacks for each socket the uses this
* connection (there can be more that one in the event that the the socket
* was dup'ed). It is used with the network monitor to handle
* asynchronous loss-of-connection events.
*/
FAR struct devif_callback_s *connevents;
/* accept() is called when the TCP logic has created a connection /* accept() is called when the TCP logic has created a connection
* *
* accept_private: This is private data that will be available to the * accept_private: This is private data that will be available to the
@ -241,24 +240,6 @@ struct tcp_conn_s
FAR void *accept_private; FAR void *accept_private;
int (*accept)(FAR struct tcp_conn_s *listener, FAR struct tcp_conn_s *conn); int (*accept)(FAR struct tcp_conn_s *listener, FAR struct tcp_conn_s *conn);
/* connection_event() is called on any of the subset of connection-related
* events.
*
* connection_private: This is private data that will be available to
* the connection_event() handler when it is invoked with a point to
* this structure as an argument.
* connection_devcb: this is the allocated callback structure that is
* used to
* connection_event: This is the pointer to the connection event
* handler.
*/
FAR void *connection_private;
FAR struct devif_callback_s *connection_devcb;
uint16_t (*connection_event)(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags);
}; };
/* This structure supports TCP write buffering */ /* This structure supports TCP write buffering */

View File

@ -193,12 +193,11 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
* callback. * callback.
*/ */
if (((flags & TCP_CONN_EVENTS) != 0) && conn->connection_event) if ((flags & TCP_CONN_EVENTS) != 0)
{ {
/* Perform the callback */ /* Perform the callback disconnect callbacks */
flags = conn->connection_event(dev, conn, conn->connection_private, flags = devif_conn_event(dev, conn, flags, conn->connevents);
flags);
} }
return flags; return flags;

View File

@ -56,8 +56,8 @@
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
static void connection_closed(FAR struct socket *psock, uint16_t flags); static void tcp_close_connection(FAR struct socket *psock, uint16_t flags);
static uint16_t connection_event(FAR struct net_driver_s *dev, static uint16_t tcp_disconnect_event(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv, FAR void *pvconn, FAR void *pvpriv,
uint16_t flags); uint16_t flags);
@ -66,7 +66,7 @@ static uint16_t connection_event(FAR struct net_driver_s *dev,
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: connection_closed * Name: tcp_close_connection
* *
* Description: * Description:
* Called when a loss-of-connection event has occurred. * Called when a loss-of-connection event has occurred.
@ -83,7 +83,7 @@ static uint16_t connection_event(FAR struct net_driver_s *dev,
* *
****************************************************************************/ ****************************************************************************/
static void connection_closed(FAR struct socket *psock, uint16_t flags) static void tcp_close_connection(FAR struct socket *psock, uint16_t flags)
{ {
/* These loss-of-connection events may be reported: /* These loss-of-connection events may be reported:
* *
@ -121,7 +121,7 @@ static void connection_closed(FAR struct socket *psock, uint16_t flags)
} }
/**************************************************************************** /****************************************************************************
* Name: connection_event * Name: tcp_disconnect_event
* *
* Description: * Description:
* Some connection related event has occurred * Some connection related event has occurred
@ -139,13 +139,13 @@ static void connection_closed(FAR struct socket *psock, uint16_t flags)
* *
****************************************************************************/ ****************************************************************************/
static uint16_t connection_event(FAR struct net_driver_s *dev, static uint16_t tcp_disconnect_event(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv, FAR void *pvconn, FAR void *pvpriv,
uint16_t flags) uint16_t flags)
{ {
FAR struct socket *psock = (FAR struct socket *)pvpriv; FAR struct socket *psock = (FAR struct socket *)pvpriv;
if (psock) if (psock != NULL)
{ {
ninfo("flags: %04x s_flags: %02x\n", flags, psock->s_flags); ninfo("flags: %04x s_flags: %02x\n", flags, psock->s_flags);
@ -155,7 +155,7 @@ static uint16_t connection_event(FAR struct net_driver_s *dev,
if ((flags & TCP_DISCONN_EVENTS) != 0) if ((flags & TCP_DISCONN_EVENTS) != 0)
{ {
connection_closed(psock, flags); tcp_close_connection(psock, flags);
} }
/* TCP_CONNECTED: The socket is successfully connected */ /* TCP_CONNECTED: The socket is successfully connected */
@ -188,9 +188,51 @@ static uint16_t connection_event(FAR struct net_driver_s *dev,
return flags; return flags;
} }
/****************************************************************************
* Name: tcp_shutdown_monitor
*
* Description:
* Stop monitoring TCP connection changes for a given socket.
*
* Input Parameters:
* conn - The TCP connection of interest
* flags - Indicates the type of shutdown. TCP_CLOSE or TCP_ABORT
*
* Returned Value:
* None
*
* Assumptions:
* The caller holds the network lock (if not, it will be locked momentarily
* by this function).
*
****************************************************************************/
void tcp_shutdown_monitor(FAR struct tcp_conn_s *conn, uint16_t flags)
{
DEBUGASSERT(conn);
/* Perform callbacks to assure that all sockets, including dup'ed copies,
* are informed of the loss of connection event.
*/
net_lock();
(void)tcp_callback(conn->dev, conn, flags);
/* Free all allocated connection event callback structure s*/
while (conn->connevents != NULL)
{
devif_conn_callback_free(conn->dev, conn->connevents,
&conn->connevents);
}
net_unlock();
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: tcp_start_monitor * Name: tcp_start_monitor
* *
@ -231,13 +273,7 @@ int tcp_start_monitor(FAR struct socket *psock)
{ {
/* Invoke the TCP_CLOSE connection event now */ /* Invoke the TCP_CLOSE connection event now */
(void)connection_event(NULL, conn, psock, TCP_CLOSE); tcp_shutdown_monitor(conn, TCP_CLOSE);
/* Make sure that the monitor is stopped */
conn->connection_private = NULL;
conn->connection_devcb = NULL;
conn->connection_event = NULL;
/* And return -ENOTCONN to indicate the monitor was not started /* And return -ENOTCONN to indicate the monitor was not started
* because the socket was already disconnected. * because the socket was already disconnected.
@ -247,28 +283,18 @@ int tcp_start_monitor(FAR struct socket *psock)
return -ENOTCONN; return -ENOTCONN;
} }
DEBUGASSERT(conn->connection_event == NULL &&
conn->connection_devcb == NULL);
/* Allocate a callback structure that we will use to get callbacks if /* Allocate a callback structure that we will use to get callbacks if
* the network goes down. * the network goes down.
*/ */
cb = tcp_monitor_callback_alloc(conn); cb = devif_callback_alloc(conn->dev, &conn->connevents);
if (cb != NULL) if (cb != NULL)
{ {
cb->event = connection_event; cb->event = tcp_disconnect_event;
cb->priv = (FAR void *)psock; cb->priv = (FAR void *)psock;
cb->flags = NETDEV_DOWN; cb->flags = TCP_DISCONN_EVENTS;
} }
conn->connection_devcb = cb;
/* Set up to receive callbacks on connection-related events */
conn->connection_private = (FAR void *)psock;
conn->connection_event = connection_event;
net_unlock(); net_unlock();
return OK; return OK;
} }
@ -277,7 +303,8 @@ int tcp_start_monitor(FAR struct socket *psock)
* Name: tcp_stop_monitor * Name: tcp_stop_monitor
* *
* Description: * Description:
* Stop monitoring TCP connection changes for a given socket * Stop monitoring TCP connection changes for a given socket. This is part
* of a graceful shutdown.
* *
* Input Parameters: * Input Parameters:
* conn - The TCP connection of interest * conn - The TCP connection of interest
@ -293,33 +320,23 @@ int tcp_start_monitor(FAR struct socket *psock)
void tcp_stop_monitor(FAR struct tcp_conn_s *conn) void tcp_stop_monitor(FAR struct tcp_conn_s *conn)
{ {
DEBUGASSERT(conn); DEBUGASSERT(conn != NULL);
/* Free any allocated device event callback structure */ /* Stop the network monitor */
net_lock(); tcp_shutdown_monitor(conn, TCP_CLOSE);
if (conn->connection_devcb)
{
tcp_monitor_callback_free(conn, conn->connection_devcb);
}
/* Nullify all connection event data */
conn->connection_private = NULL;
conn->connection_devcb = NULL;
conn->connection_event = NULL;
net_unlock();
} }
/**************************************************************************** /****************************************************************************
* Name: tcp_lost_connection * Name: tcp_lost_connection
* *
* Description: * Description:
* Called when a loss-of-connection event has occurred. * Called when a loss-of-connection event has occurred. This is for an
* unexpected disconnection of some sort from the host.
* *
* Parameters: * Parameters:
* psock The TCP socket structure associated. * psock - The TCP socket structure associated.
* flags Set of connection events events * flags - Set of connection events events
* *
* Returned Value: * Returned Value:
* None * None
@ -334,15 +351,9 @@ void tcp_lost_connection(FAR struct socket *psock, uint16_t flags)
{ {
DEBUGASSERT(psock != NULL && psock->s_conn != NULL); DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
/* Close the connection */
net_lock();
connection_closed(psock, flags);
/* Stop the network monitor */ /* Stop the network monitor */
tcp_stop_monitor((FAR struct tcp_conn_s *)psock->s_conn); tcp_shutdown_monitor((FAR struct tcp_conn_s *)psock->s_conn, flags);
net_unlock();
} }
#endif /* NET_TCP_HAVE_STACK */ #endif /* NET_TCP_HAVE_STACK */