Networking: Fix a runaway recursion problem introduced the previous fixe for shutting down dup'ed sockets.

This commit is contained in:
Gregory Nutt 2017-08-29 12:27:58 -06:00
parent d40ee8e79d
commit 0f7a52bc28
11 changed files with 86 additions and 44 deletions

View File

@ -508,7 +508,7 @@ int inet_close(FAR struct socket *psock)
/* Stop the network monitor */ /* Stop the network monitor */
tcp_stop_monitor(conn); tcp_stop_monitor(conn, TCP_CLOSE);
} }
else else
{ {

View File

@ -737,15 +737,9 @@ static uint16_t inet_tcp_interrupt(FAR struct net_driver_s *dev,
{ {
ninfo("Lost connection\n"); ninfo("Lost connection\n");
/* Stop further callbacks */
pstate->ir_cb->flags = 0;
pstate->ir_cb->priv = NULL;
pstate->ir_cb->event = NULL;
/* Handle loss-of-connection event */ /* Handle loss-of-connection event */
tcp_lost_connection(pstate->ir_sock, flags); tcp_lost_connection(pstate->ir_sock, pstate->ir_cb, flags);
/* Check if the peer gracefully closed the connection. */ /* Check if the peer gracefully closed the connection. */

View File

@ -439,11 +439,11 @@ static uint16_t tcp_send_interrupt(FAR struct net_driver_s *dev,
else if ((flags & TCP_DISCONN_EVENTS) != 0) else if ((flags & TCP_DISCONN_EVENTS) != 0)
{ {
/* Report not connected */
ninfo("Lost connection\n"); ninfo("Lost connection\n");
tcp_lost_connection(sinfo->s_sock, flags); /* Report the disconnection event to all socket clones */
tcp_lost_connection(sinfo->s_sock, sinfo->s_cb, flags);
sinfo->s_result = -ENOTCONN; sinfo->s_result = -ENOTCONN;
goto end_wait; goto end_wait;
} }

View File

@ -62,6 +62,15 @@
* Description: * Description:
* Performs the low level, common portion of net_dupsd() and net_dupsd2() * Performs the low level, common portion of net_dupsd() and net_dupsd2()
* *
* Input Parameters:
* psock1 - The existing socket that is being cloned.
* psock2 - A reference to an uninitialized socket structure alloated by
* the caller.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/ ****************************************************************************/
int net_clone(FAR struct socket *psock1, FAR struct socket *psock2) int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)

View File

@ -557,10 +557,12 @@ 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 sockets associated with
* a given TCP connection stucture.
* *
* Input Parameters: * Input Parameters:
* conn - The TCP connection of interest * conn - The TCP connection of interest
* flags Set of disconnection events
* *
* Returned Value: * Returned Value:
* None * None
@ -571,27 +573,33 @@ 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, uint16_t flags);
/**************************************************************************** /****************************************************************************
* 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 been detected by network
* "interrupt" handling logic. Perform operations like tcp_stop_monitor
* but (1) explicitly amek this socket and (2) disable further callbacks
* the "interrupt handler".
* *
* Parameters: * Parameters:
* psock The TCP socket structure associated. * psock - The TCP socket structure associated.
* flags Set of connection events events * cb - devif callback structure
* flags - Set of connection events events
* *
* Returned Value: * Returned Value:
* None * None
* *
* Assumptions: * Assumptions:
* The caller holds the network lock. * The caller holds the network lock (if not, it will be locked momentarily
* by this function).
* *
****************************************************************************/ ****************************************************************************/
void tcp_lost_connection(FAR struct socket *psock, uint16_t flags); void tcp_lost_connection(FAR struct socket *psock,
FAR struct devif_callback_s *cb, uint16_t flags);
/**************************************************************************** /****************************************************************************
* Name: tcp_ipv4_select * Name: tcp_ipv4_select

View File

@ -152,7 +152,7 @@ static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
{ {
/* Failed to connect. Stop the connection event monitor */ /* Failed to connect. Stop the connection event monitor */
tcp_stop_monitor(conn); tcp_stop_monitor(conn, TCP_CLOSE);
} }
} }
@ -411,7 +411,7 @@ int psock_tcp_connect(FAR struct socket *psock,
* happen in this context, but just in case... * happen in this context, but just in case...
*/ */
tcp_lost_connection(psock, TCP_ABORT); tcp_stop_monitor(psock->s_conn, TCP_ABORT);
} }
} }
} }

View File

@ -302,11 +302,12 @@ 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. This is part * Stop monitoring TCP connection changes for a sockets associated with
* of a graceful shutdown. * a given TCP connection stucture.
* *
* Input Parameters: * Input Parameters:
* conn - The TCP connection of interest * conn - The TCP connection of interest
* flags Set of disconnection events
* *
* Returned Value: * Returned Value:
* None * None
@ -317,24 +318,27 @@ 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, uint16_t flags)
{ {
DEBUGASSERT(conn != NULL); DEBUGASSERT(conn != NULL);
/* Stop the network monitor */ /* Stop the network monitor */
tcp_shutdown_monitor(conn, TCP_CLOSE); tcp_shutdown_monitor(conn, flags);
} }
/**************************************************************************** /****************************************************************************
* Name: tcp_lost_connection * Name: tcp_lost_connection
* *
* Description: * Description:
* Called when a loss-of-connection event has occurred. This is for an * Called when a loss-of-connection event has been detected by network
* unexpected disconnection of some sort from the host. * "interrupt" handling logic. Perform operations like tcp_stop_monitor
* but (1) explicitly amek this socket and (2) disable further callbacks
* the "interrupt handler".
* *
* Parameters: * Parameters:
* psock - The TCP socket structure associated. * psock - The TCP socket structure associated.
* cb - devif callback structure
* flags - Set of connection events events * flags - Set of connection events events
* *
* Returned Value: * Returned Value:
@ -346,11 +350,26 @@ void tcp_stop_monitor(FAR struct tcp_conn_s *conn)
* *
****************************************************************************/ ****************************************************************************/
void tcp_lost_connection(FAR struct socket *psock, uint16_t flags) void tcp_lost_connection(FAR struct socket *psock,
FAR struct devif_callback_s *cb, uint16_t flags)
{ {
DEBUGASSERT(psock != NULL && psock->s_conn != NULL); DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
/* Stop the network monitor */ /* Nullify the callback structure so that recursive callbacks are not
* received by the "interrupt handler" due to disconnection processing.
*/
cb->flags = 0;
cb->priv = NULL;
cb->event = NULL;
/* Make sure that this socket is explicitly marked. It may not bet a
* callback due to the above nullification.
*/
tcp_close_connection(psock, flags);
/* Then stop the network monitor */
tcp_shutdown_monitor((FAR struct tcp_conn_s *)psock->s_conn, flags); tcp_shutdown_monitor((FAR struct tcp_conn_s *)psock->s_conn, flags);
} }

View File

@ -73,8 +73,8 @@ struct tcp_poll_s
* Name: tcp_poll_interrupt * Name: tcp_poll_interrupt
* *
* Description: * Description:
* This function is called from the interrupt level to perform the actual * This function is called to perform the actual TCP receive operation via
* TCP receive operation via by the device interface layer. * the device interface layer.
* *
* Parameters: * Parameters:
* dev The structure of the network driver that caused the interrupt * dev The structure of the network driver that caused the interrupt
@ -124,14 +124,20 @@ static uint16_t tcp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn,
{ {
/* Mark that the connection has been lost */ /* Mark that the connection has been lost */
tcp_lost_connection(info->psock, flags); tcp_lost_connection(info->psock, pstate->cb, flags);
eventset |= (POLLERR | POLLHUP); eventset |= (POLLERR | POLLHUP);
} }
/* Awaken the caller of poll() if requested event occurred. */ /* Awaken the caller of poll() if requested event occurred. */
if (eventset) if (eventset != 0)
{ {
/* Stop further callbacks */
pstate->cb->flags = 0;
pstate->cb->priv = NULL;
pstate->cb->event = NULL;
info->fds->revents |= eventset; info->fds->revents |= eventset;
sem_post(info->fds->sem); sem_post(info->fds->sem);
} }

View File

@ -515,7 +515,7 @@ static uint16_t psock_send_interrupt(FAR struct net_driver_s *dev,
{ {
/* Report not connected */ /* Report not connected */
tcp_lost_connection(psock, flags); tcp_lost_connection(psock, psock->s_sndcb, flags);
} }
/* Free write buffers and terminate polling */ /* Free write buffers and terminate polling */
@ -1030,14 +1030,14 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
/* Allocate resources to receive a callback */ /* Allocate resources to receive a callback */
if (!psock->s_sndcb) if (psock->s_sndcb == NULL)
{ {
psock->s_sndcb = tcp_callback_alloc(conn); psock->s_sndcb = tcp_callback_alloc(conn);
} }
/* Test if the callback has been allocated */ /* Test if the callback has been allocated */
if (!psock->s_sndcb) if (psock->s_sndcb == NULL)
{ {
/* A buffer allocation error occurred */ /* A buffer allocation error occurred */

View File

@ -396,11 +396,11 @@ static uint16_t tcpsend_interrupt(FAR struct net_driver_s *dev,
else if ((flags & TCP_DISCONN_EVENTS) != 0) else if ((flags & TCP_DISCONN_EVENTS) != 0)
{ {
/* Report not connected */
ninfo("Lost connection\n"); ninfo("Lost connection\n");
tcp_lost_connection(pstate->snd_sock, flags); /* Report not connected */
tcp_lost_connection(pstate->snd_sock, pstate->snd_cb, flags);
pstate->snd_sent = -ENOTCONN; pstate->snd_sent = -ENOTCONN;
goto end_wait; goto end_wait;
} }

View File

@ -222,14 +222,20 @@ static uint16_t ack_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn,
else if ((flags & TCP_DISCONN_EVENTS) != 0) else if ((flags & TCP_DISCONN_EVENTS) != 0)
{ {
/* Report not connected */
nwarn("WARNING: Lost connection\n"); nwarn("WARNING: Lost connection\n");
tcp_lost_connection(pstate->snd_sock, flags); /* Report not connected */
tcp_lost_connection(pstate->snd_sock, pstate->snd_ackcb, flags);
pstate->snd_sent = -ENOTCONN; pstate->snd_sent = -ENOTCONN;
} }
/* Prohibit further callbacks */
pstate->snd_ackcb->flags = 0;
pstate->snd_ackcb->priv = NULL;
pstate->snd_ackcb->event = NULL;
/* Wake up the waiting thread */ /* Wake up the waiting thread */
sem_post(&pstate->snd_sem); sem_post(&pstate->snd_sem);
@ -344,11 +350,11 @@ static uint16_t sendfile_interrupt(FAR struct net_driver_s *dev, FAR void *pvcon
if ((flags & TCP_DISCONN_EVENTS) != 0) if ((flags & TCP_DISCONN_EVENTS) != 0)
{ {
/* Report not connected */
nwarn("WARNING: Lost connection\n"); nwarn("WARNING: Lost connection\n");
tcp_lost_connection(pstate->snd_sock, flags); /* Report not connected */
tcp_lost_connection(pstate->snd_sock, pstate->snd_datacb, flags);
pstate->snd_sent = -ENOTCONN; pstate->snd_sent = -ENOTCONN;
goto end_wait; goto end_wait;
} }