You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/06/30 11:39:26 UTC

[incubator-nuttx] 03/03: tcp_close: disable send callback before sending FIN

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 08e9dff0e9dcfb43ca76208bf569adc735842c8c
Author: YAMAMOTO Takashi <ya...@midokura.com>
AuthorDate: Tue Jun 29 20:00:57 2021 +0900

    tcp_close: disable send callback before sending FIN
    
    This fixes connection closing issues with CONFIG_NET_TCP_WRITE_BUFFERS.
    
    Because TCP_CLOSE is used for both of input and output for tcp_callback,
    the close callback and the send callback confuses each other as
    the following. As it effectively disposes the connection immediately,
    we end up with responding to the consequent ACK and FIN/ACK from the peer
    with RSTs.
    
    tcp_timer
        -> tcp_close_eventhandler
            returns TCP_CLOSE (meaning an active close)
        -> psock_send_eventhandler
            called with TCP_CLOSE from tcp_close_eventhandler, misinterpet as
            a passive close.
            -> tcp_lost_connection
                -> tcp_shutdown_monitor
                    -> tcp_callback
                        -> tcp_close_eventhandler
                            misinterpret TCP_CLOSE from itself as
                            a passive close
---
 net/tcp/tcp_close.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/net/tcp/tcp_close.c b/net/tcp/tcp_close.c
index 2998d0d..36e71b8 100644
--- a/net/tcp/tcp_close.c
+++ b/net/tcp/tcp_close.c
@@ -139,6 +139,22 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
        * is set in the response
        */
 
+#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
+      FAR struct socket *psock = pstate->cl_psock;
+
+      /* We don't need the send callback anymore. */
+
+      if (psock->s_sndcb != NULL)
+        {
+          psock->s_sndcb->flags = 0;
+          psock->s_sndcb->event = NULL;
+
+          /* The callback will be freed by tcp_free. */
+
+          psock->s_sndcb = NULL;
+        }
+#endif
+
       dev->d_len = 0;
       flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
     }