mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:58:59 +08:00
Merged in masayuki2009/nuttx.nuttx/fix_tcp_active_close (pull request #923)
net/inet: Fix tcp active close in inet_close.c In previous implementation, FIN packet was not sent when a socket is actively closed (e.g. telnetd or webserver) without SO_LINGER. This issue happens because the socket closing sequence waits for the status.cl_sem only if lingering timeout is set. However, in many server use-cases, SO_LINGER is not usually set and even in these cases, FIN packet must be sent correctly. This PR changes the logic in inet_close.c so that it can wait for status.cl_sem regardless of SO_LINGER. Instead, if SO_LINGER is set, it waits for the semaphore with timeout option. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
committed by
Gregory Nutt
parent
5dc1618982
commit
ed9fe70024
+27
-44
@@ -78,10 +78,10 @@
|
|||||||
struct tcp_close_s
|
struct tcp_close_s
|
||||||
{
|
{
|
||||||
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
|
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
|
||||||
FAR struct socket *cl_psock; /* Reference to the TCP socket */
|
FAR struct socket *cl_psock; /* Reference to the TCP socket */
|
||||||
sem_t cl_sem; /* Signals disconnect completion */
|
sem_t cl_sem; /* Signals disconnect completion */
|
||||||
int cl_result; /* The result of the close */
|
int cl_result; /* The result of the close */
|
||||||
|
#ifdef CONFIG_NET_SOLINGER
|
||||||
clock_t cl_start; /* Time close started (in ticks) */
|
clock_t cl_start; /* Time close started (in ticks) */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -158,9 +158,7 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
FAR void *pvconn, FAR void *pvpriv,
|
FAR void *pvconn, FAR void *pvpriv,
|
||||||
uint16_t flags)
|
uint16_t flags)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
|
||||||
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
|
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
|
||||||
#endif
|
|
||||||
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
|
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
|
||||||
|
|
||||||
DEBUGASSERT(conn != NULL);
|
DEBUGASSERT(conn != NULL);
|
||||||
@@ -178,7 +176,6 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
{
|
{
|
||||||
/* The disconnection is complete */
|
/* The disconnection is complete */
|
||||||
|
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
|
||||||
/* pstate non-NULL means that we are performing a LINGERing close. */
|
/* pstate non-NULL means that we are performing a LINGERing close. */
|
||||||
|
|
||||||
if (pstate != NULL)
|
if (pstate != NULL)
|
||||||
@@ -194,7 +191,6 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
/* Free connection resources */
|
/* Free connection resources */
|
||||||
|
|
||||||
@@ -247,7 +243,6 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
|
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
|
||||||
end_wait:
|
end_wait:
|
||||||
pstate->cl_cb->flags = 0;
|
pstate->cl_cb->flags = 0;
|
||||||
pstate->cl_cb->priv = NULL;
|
pstate->cl_cb->priv = NULL;
|
||||||
@@ -256,7 +251,6 @@ end_wait:
|
|||||||
|
|
||||||
ninfo("Resuming\n");
|
ninfo("Resuming\n");
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif /* NET_TCP_HAVE_STACK */
|
#endif /* NET_TCP_HAVE_STACK */
|
||||||
|
|
||||||
@@ -332,7 +326,7 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
|||||||
struct tcp_close_s state;
|
struct tcp_close_s state;
|
||||||
FAR struct tcp_conn_s *conn;
|
FAR struct tcp_conn_s *conn;
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
#ifdef CONFIG_NET_SOLINGER
|
||||||
bool linger;
|
struct timespec abstime;
|
||||||
#endif
|
#endif
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
||||||
@@ -375,15 +369,6 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
|||||||
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
|
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
|
||||||
state.cl_cb->event = tcp_close_eventhandler;
|
state.cl_cb->event = tcp_close_eventhandler;
|
||||||
|
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
|
||||||
/* Check for a lingering close */
|
|
||||||
|
|
||||||
linger = _SO_GETOPT(psock->s_options, SO_LINGER);
|
|
||||||
|
|
||||||
/* Has a lingering close been requested */
|
|
||||||
|
|
||||||
if (linger)
|
|
||||||
{
|
|
||||||
/* A non-NULL value of the priv field means that lingering is
|
/* A non-NULL value of the priv field means that lingering is
|
||||||
* enabled.
|
* enabled.
|
||||||
*/
|
*/
|
||||||
@@ -402,56 +387,54 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
|||||||
nxsem_init(&state.cl_sem, 0, 0);
|
nxsem_init(&state.cl_sem, 0, 0);
|
||||||
nxsem_setprotocol(&state.cl_sem, SEM_PRIO_NONE);
|
nxsem_setprotocol(&state.cl_sem, SEM_PRIO_NONE);
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_SOLINGER
|
||||||
/* Record the time that we started the wait (in ticks) */
|
/* Record the time that we started the wait (in ticks) */
|
||||||
|
|
||||||
state.cl_start = clock_systimer();
|
state.cl_start = clock_systimer();
|
||||||
}
|
#endif
|
||||||
else
|
|
||||||
#endif /* CONFIG_NET_SOLINGER */
|
|
||||||
|
|
||||||
{
|
|
||||||
/* We will close immediately. The NULL priv field signals this */
|
|
||||||
|
|
||||||
state.cl_cb->priv = NULL;
|
|
||||||
|
|
||||||
/* No further references on the connection */
|
|
||||||
|
|
||||||
conn->crefs = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notify the device driver of the availability of TX data */
|
/* Notify the device driver of the availability of TX data */
|
||||||
|
|
||||||
tcp_close_txnotify(psock, conn);
|
tcp_close_txnotify(psock, conn);
|
||||||
|
|
||||||
#ifdef CONFIG_NET_SOLINGER
|
|
||||||
/* Wait only if we are lingering */
|
|
||||||
|
|
||||||
if (linger)
|
|
||||||
{
|
|
||||||
/* Wait for the disconnect event */
|
/* Wait for the disconnect event */
|
||||||
|
|
||||||
(void)net_lockedwait(&state.cl_sem);
|
#ifdef CONFIG_NET_SOLINGER
|
||||||
|
DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime));
|
||||||
|
|
||||||
|
/* NOTE: s_linger's unit is deciseconds,
|
||||||
|
* so we don't need to update abstime.tv_nsec here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstime.tv_sec += psock->s_linger / DSEC_PER_SEC;
|
||||||
|
|
||||||
|
if (-ETIMEDOUT == net_timedwait(&state.cl_sem, &abstime))
|
||||||
|
{
|
||||||
|
state.cl_result = -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)net_timedwait(&state.cl_sem, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We are now disconnected */
|
/* We are now disconnected */
|
||||||
|
|
||||||
nxsem_destroy(&state.cl_sem);
|
nxsem_destroy(&state.cl_sem);
|
||||||
tcp_callback_free(conn, state.cl_cb);
|
tcp_callback_free(conn, state.cl_cb);
|
||||||
|
|
||||||
/* Free the connection */
|
/* Free the connection
|
||||||
|
* No more references on the connection
|
||||||
|
*/
|
||||||
|
|
||||||
conn->crefs = 0; /* No more references on the connection */
|
conn->crefs = 0;
|
||||||
tcp_free(conn); /* Free network resources */
|
|
||||||
|
|
||||||
/* Get the result of the close */
|
/* Get the result of the close */
|
||||||
|
|
||||||
ret = state.cl_result;
|
ret = state.cl_result;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NET_SOLINGER */
|
|
||||||
}
|
/* Free network resources */
|
||||||
else
|
|
||||||
{
|
|
||||||
tcp_free(conn);
|
tcp_free(conn);
|
||||||
}
|
|
||||||
|
|
||||||
net_unlock();
|
net_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user