mirror of
https://github.com/apache/nuttx.git
synced 2026-05-22 05:42:05 +08:00
net/tcp: add support for the CLOSE_WAIT state
CLOSE-WAIT - represents waiting for a connection termination request
from the local user.
TCP A TCP B
1. ESTABLISHED ESTABLISHED
2. (Close)
FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> --> CLOSE-WAIT
3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT
4. (Close)
TIME-WAIT <-- <SEQ=300><ACK=101><CTL=FIN,ACK> <-- LAST-ACK
5. TIME-WAIT --> <SEQ=101><ACK=301><CTL=ACK> --> CLOSED
6. (2 MSL)
CLOSED
in the current state, we can continue to send data until the user
calls shutdown or close, then directly enter the TCP_LAST_ACK state
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
@@ -19,6 +19,7 @@ Network Support
|
||||
wqueuedeadlocks.rst
|
||||
tcp_network_perf.rst
|
||||
delay_act_and_tcp_perf.rst
|
||||
tcp_state_machine.rst
|
||||
|
||||
``net`` Directory Structure ::
|
||||
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
=============================
|
||||
NuttX TCP State Machine Notes
|
||||
=============================
|
||||
|
||||
This document describes how the current NuttX TCP stack implements TCP
|
||||
state transitions. It is based on the in-tree implementation (primarily
|
||||
in ``net/tcp``) and focuses on *what the code does today* rather than a
|
||||
generic RFC 793 description.
|
||||
|
||||
Scope
|
||||
=====
|
||||
|
||||
* TCP connection state is tracked per ``struct tcp_conn_s``.
|
||||
* State transitions happen mainly in:
|
||||
|
||||
* ``net/tcp/tcp_input.c`` (incoming segments and most transitions)
|
||||
* ``net/tcp/tcp_timer.c`` (timeouts and retransmissions)
|
||||
* ``net/tcp/tcp_conn.c`` (connect/listen-side allocation and initial state)
|
||||
* ``net/tcp/tcp_close.c`` (active close initiation)
|
||||
|
||||
State Representation
|
||||
====================
|
||||
|
||||
NuttX stores TCP state in ``tcp_conn_s::tcpstateflags``.
|
||||
|
||||
* Bits 0-3 are the state (``TCP_STATE_MASK``).
|
||||
* Bit 4 is a flag (``TCP_STOPPED``) used by the socket layer to stop data flow.
|
||||
|
||||
The state values are defined in ``include/nuttx/net/tcp.h``:
|
||||
|
||||
* ``TCP_CLOSED``
|
||||
* ``TCP_ALLOCATED`` (NuttX-internal: allocated but not yet connected)
|
||||
* ``TCP_SYN_RCVD``
|
||||
* ``TCP_SYN_SENT``
|
||||
* ``TCP_ESTABLISHED``
|
||||
* ``TCP_FIN_WAIT_1``
|
||||
* ``TCP_FIN_WAIT_2``
|
||||
* ``TCP_CLOSE_WAIT``
|
||||
* ``TCP_CLOSING``
|
||||
* ``TCP_TIME_WAIT``
|
||||
* ``TCP_LAST_ACK``
|
||||
* ``TCP_STOPPED``
|
||||
|
||||
Supported vs Unsupported (RFC State View)
|
||||
=========================================
|
||||
|
||||
NuttX largely follows the classic TCP state machine, the table below maps the traditional RFC 793 state names to what exists in
|
||||
NuttX today.
|
||||
|
||||
.. list-table:: RFC TCP states and their NuttX support
|
||||
:header-rows: 1
|
||||
:widths: auto
|
||||
|
||||
* - RFC state name
|
||||
- NuttX representation
|
||||
- Supported
|
||||
- Notes
|
||||
* - CLOSED
|
||||
- ``TCP_CLOSED``
|
||||
- Yes
|
||||
- Connection is unused/available.
|
||||
* - LISTEN
|
||||
- No ``tcpstateflags`` state
|
||||
- Partially
|
||||
- Listening is implemented via the listener table in ``net/tcp/tcp_listen.c``(``tcp_listenports[]``) rather than a per-connection LISTEN state.
|
||||
* - SYN-SENT
|
||||
- ``TCP_SYN_SENT``
|
||||
- Yes
|
||||
- Set by ``tcp_connect()`` in ``net/tcp/tcp_conn.c``.
|
||||
* - SYN-RECEIVED
|
||||
- ``TCP_SYN_RCVD``
|
||||
- Yes
|
||||
- Set when accepting an incoming SYN (new connection allocated for a listener).
|
||||
* - ESTABLISHED
|
||||
- ``TCP_ESTABLISHED``
|
||||
- Yes
|
||||
- Data transfer state.
|
||||
* - FIN-WAIT-1
|
||||
- ``TCP_FIN_WAIT_1``
|
||||
- Yes
|
||||
- Entered on active close (local FIN sent). However, it is currently unable to continue receiving data in this state
|
||||
* - FIN-WAIT-2
|
||||
- ``TCP_FIN_WAIT_2``
|
||||
- Yes
|
||||
- Entered after ACK for local FIN (when peer hasn't closed yet). However, it is currently unable to continue receiving data in this state
|
||||
* - CLOSE-WAIT
|
||||
- Not implemented
|
||||
- Yes
|
||||
- The TCP input path explicitly notes CLOSE_WAIT is not implemented; NuttX forces the application to close when FIN is received and moves directly toward ``TCP_LAST_ACK``.
|
||||
* - CLOSING
|
||||
- ``TCP_CLOSING``
|
||||
- Yes
|
||||
- Used for simultaneous close handling.
|
||||
* - LAST-ACK
|
||||
- ``TCP_LAST_ACK``
|
||||
- Yes
|
||||
- Used after receiving FIN and sending FIN in response.
|
||||
* - TIME-WAIT
|
||||
- ``TCP_TIME_WAIT``
|
||||
- Yes
|
||||
- Used after the close handshake; timer-driven cleanup.
|
||||
|
||||
Note on ``TCP_ALLOCATED``
|
||||
-------------------------
|
||||
|
||||
``TCP_ALLOCATED`` is NuttX-specific and has no direct RFC state name.
|
||||
It is the pre-connect/pre-accept state for a newly created socket connection.
|
||||
|
||||
High-level Transition Summary
|
||||
=============================
|
||||
|
||||
This section summarizes the most common state paths.
|
||||
|
||||
Active open (connect)
|
||||
---------------------
|
||||
|
||||
Typical client-side flow:
|
||||
|
||||
::
|
||||
|
||||
TCP_ALLOCATED
|
||||
-> TCP_SYN_SENT (tcp_connect() prepares SYN)
|
||||
-> TCP_ESTABLISHED (tcp_input receives SYN|ACK and replies ACK)
|
||||
|
||||
Passive open (listen/accept)
|
||||
----------------------------
|
||||
|
||||
Listening sockets are registered in the listener table (not a LISTEN state).
|
||||
When a SYN arrives:
|
||||
|
||||
::
|
||||
|
||||
listener in tcp_listenports[]
|
||||
-> new conn: TCP_SYN_RCVD (tcp_allocaccept() in tcp_conn.c)
|
||||
-> TCP_ESTABLISHED (tcp_input receives final ACK)
|
||||
-> accept() wakes up (tcp_accept_connection())
|
||||
|
||||
Graceful close (active close)
|
||||
-----------------------------
|
||||
|
||||
When the application initiates a close (or ``shutdown(SHUT_WR)``), the stack
|
||||
sends FIN and transitions:
|
||||
|
||||
::
|
||||
|
||||
TCP_ESTABLISHED
|
||||
-> TCP_FIN_WAIT_1
|
||||
-> TCP_FIN_WAIT_2 (ACK of our FIN)
|
||||
-> TCP_TIME_WAIT (FIN from peer)
|
||||
-> TCP_CLOSED (timer expiry)
|
||||
|
||||
Simultaneous close
|
||||
------------------
|
||||
|
||||
If FIN is received while we are in ``TCP_FIN_WAIT_1`` and our FIN has not been
|
||||
fully ACKed, NuttX can enter ``TCP_CLOSING``:
|
||||
|
||||
::
|
||||
|
||||
TCP_FIN_WAIT_1
|
||||
-> TCP_CLOSING
|
||||
-> TCP_TIME_WAIT (ACK of our FIN)
|
||||
|
||||
Passive close (peer closes first)
|
||||
---------------------------------
|
||||
|
||||
When FIN is received in ESTABLISHED, the application is notified
|
||||
via callbacks. the stack sends ACK and goes to ``TCP_CLOSE_WAIT``:
|
||||
|
||||
::
|
||||
|
||||
TCP_ESTABLISHED
|
||||
-> TCP_CLOSE_WAIT (FIN received)
|
||||
-> TCP_CLOSED (ACK of our FIN)
|
||||
|
||||
Detailed State Handling
|
||||
=======================
|
||||
|
||||
TCP_SYN_SENT
|
||||
------------
|
||||
|
||||
* Entered by ``tcp_connect()`` (``net/tcp/tcp_conn.c``).
|
||||
* On receiving ``SYN|ACK`` with a valid ACK:
|
||||
|
||||
* Parses options (e.g., MSS).
|
||||
* Sets ``TCP_ESTABLISHED``.
|
||||
* Updates ``rcvseq`` and window tracking.
|
||||
* Notifies the socket layer using ``TCP_CONNECTED``.
|
||||
|
||||
* On unexpected control segments or failure:
|
||||
|
||||
* The connection is aborted (``TCP_ABORT`` callback) and a RST may be sent.
|
||||
|
||||
TCP_SYN_RCVD
|
||||
------------
|
||||
|
||||
* Entered for a newly accepted connection when a SYN matches a listener.
|
||||
Allocation and initialization occur in ``tcp_allocaccept()``
|
||||
(``net/tcp/tcp_conn.c``).
|
||||
* A SYN-ACK is sent. The retransmission is handled by ``tcp_timer.c``.
|
||||
* On receiving the final ACK (``TCP_ACKDATA``):
|
||||
|
||||
* Transition to ``TCP_ESTABLISHED``.
|
||||
* ``tcp_accept_connection()`` is called to hand the connection to the
|
||||
listening socket/accept logic.
|
||||
|
||||
TCP_ESTABLISHED
|
||||
---------------
|
||||
|
||||
* Normal data transfer occurs here.
|
||||
* Incoming data and ACK processing is handled in ``net/tcp/tcp_input.c``.
|
||||
* If a FIN is received:
|
||||
|
||||
* The application is notified (``TCP_CLOSE`` flag is included in callback).
|
||||
* NuttX transitions to ``TCP_CLOSE_WAIT`` and sends ``ACK``.
|
||||
|
||||
TCP_CLOSE_WAIT
|
||||
--------------
|
||||
|
||||
* Only entered when a FIN is received in ESTABLISHED.
|
||||
* The application is notified (``TCP_CLOSE`` flag in callback).
|
||||
* NuttX can send data until the application initiates close.
|
||||
* On application close request:
|
||||
* NuttX sends FIN and transitions to ``TCP_LAST_ACK``.
|
||||
|
||||
TCP_FIN_WAIT_1
|
||||
--------------
|
||||
|
||||
* Entered when the application requests a graceful close.
|
||||
This is initiated in ``net/tcp/tcp_appsend.c`` when the callback result
|
||||
contains ``TCP_CLOSE``.
|
||||
|
||||
* On receiving FIN:
|
||||
|
||||
* If the FIN also ACKs our FIN and ``tx_unacked == 0``: transition to
|
||||
``TCP_TIME_WAIT``.
|
||||
* Otherwise: transition to ``TCP_CLOSING``.
|
||||
* In both cases, ACK the peer FIN.
|
||||
|
||||
* On receiving an ACK that completes ACK of our FIN (and no FIN from peer):
|
||||
|
||||
* Transition to ``TCP_FIN_WAIT_2``.
|
||||
|
||||
* Data received in FIN_WAIT_1:
|
||||
|
||||
* Current behavior is to send a RST and force ``TCP_CLOSED``.
|
||||
* The implementation notes this as a TODO to improve shutdown behavior.
|
||||
|
||||
TCP_FIN_WAIT_2
|
||||
--------------
|
||||
|
||||
* Waiting for the peer FIN after our FIN was ACKed.
|
||||
* On receiving FIN:
|
||||
|
||||
* Transition to ``TCP_TIME_WAIT``.
|
||||
* ACK the FIN and notify close.
|
||||
|
||||
* Data received in FIN_WAIT_2:
|
||||
|
||||
* Current behavior is to send a RST and force ``TCP_CLOSED``.
|
||||
|
||||
TCP_CLOSING
|
||||
-----------
|
||||
|
||||
* Simultaneous close case.
|
||||
* When the ACK for our FIN is received (``TCP_ACKDATA``):
|
||||
|
||||
* Transition to ``TCP_TIME_WAIT``.
|
||||
|
||||
TCP_LAST_ACK
|
||||
------------
|
||||
|
||||
* Entered after FIN is received in ESTABLISHED and the application chooses
|
||||
to close, causing the stack to send FIN.
|
||||
* On receiving ACK for our FIN (``TCP_ACKDATA``):
|
||||
|
||||
* Transition to ``TCP_CLOSED``.
|
||||
* Notify close via callback.
|
||||
|
||||
TCP_TIME_WAIT
|
||||
-------------
|
||||
|
||||
* NuttX responds to segments by sending an ACK.
|
||||
* Cleanup is timer-driven (see ``tcp_timer.c``):
|
||||
|
||||
* ``TCP_TIME_WAIT`` are handled as "wait for timeout" states.
|
||||
* When the per-connection timer expires, the state becomes ``TCP_CLOSED``.
|
||||
|
||||
Timers, Retransmissions, and Failure Handling
|
||||
=============================================
|
||||
|
||||
The TCP timer handler in ``net/tcp/tcp_timer.c`` drives:
|
||||
|
||||
* Retransmission for connections with ``tx_unacked > 0``.
|
||||
* State-specific retransmit behavior:
|
||||
|
||||
* ``TCP_SYN_RCVD``: retransmit SYN-ACK.
|
||||
* ``TCP_SYN_SENT``: retransmit SYN.
|
||||
* ``TCP_ESTABLISHED``: request retransmit via callback (``TCP_REXMIT``).
|
||||
* ``TCP_FIN_WAIT_1``, ``TCP_CLOSING``, ``TCP_LAST_ACK``: retransmit FIN|ACK.
|
||||
|
||||
* Timeout cleanup:
|
||||
|
||||
* ``TCP_SYN_RCVD``: if SYN-ACK retransmits exceed limit, the half-open
|
||||
connection is closed and freed.
|
||||
* ``TCP_SYN_SENT`` and established cases: if retransmits exceed limit, the
|
||||
connection is closed, the socket is notified (``TCP_TIMEDOUT``), and a
|
||||
RST may be sent.
|
||||
|
||||
Deviations and Notable Simplifications
|
||||
======================================
|
||||
|
||||
* LISTEN is not an explicit TCP state; it is represented by listener table entries.
|
||||
* FIN_WAIT_* data handling is currently strict: received payload data in
|
||||
FIN_WAIT_1/2 results in sending RST and closing the connection.
|
||||
* RST processing is intentionally simple (accept RST and close).
|
||||
|
||||
Where to Look in the Code
|
||||
=========================
|
||||
|
||||
* State definitions: ``include/nuttx/net/tcp.h``
|
||||
* Incoming-segment state logic: ``net/tcp/tcp_input.c``
|
||||
* Retransmission/timeout logic: ``net/tcp/tcp_timer.c``
|
||||
* Connect path / SYN_SENT setup: ``net/tcp/tcp_conn.c``
|
||||
* Accept path / SYN_RCVD allocation: ``net/tcp/tcp_conn.c``
|
||||
* Active close initiation: ``net/tcp/tcp_close.c`` and ``net/tcp/tcp_shutdown.c``
|
||||
* Listener table (LISTEN semantics): ``net/tcp/tcp_listen.c``
|
||||
@@ -88,9 +88,10 @@
|
||||
# define TCP_ESTABLISHED 0x04
|
||||
# define TCP_FIN_WAIT_1 0x05
|
||||
# define TCP_FIN_WAIT_2 0x06
|
||||
# define TCP_CLOSING 0x07
|
||||
# define TCP_TIME_WAIT 0x08
|
||||
# define TCP_LAST_ACK 0x09
|
||||
# define TCP_CLOSE_WAIT 0x07
|
||||
# define TCP_CLOSING 0x08
|
||||
# define TCP_TIME_WAIT 0x09
|
||||
# define TCP_LAST_ACK 0x0a
|
||||
# define TCP_STOPPED 0x10 /* Bit 4: stopped */
|
||||
/* Bit 5-7: Unused, but not available */
|
||||
|
||||
|
||||
@@ -194,13 +194,14 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
||||
|
||||
else if ((result & TCP_CLOSE) != 0)
|
||||
{
|
||||
conn->tcpstateflags = TCP_FIN_WAIT_1;
|
||||
conn->tcpstateflags = conn->tcpstateflags == TCP_CLOSE_WAIT ?
|
||||
TCP_LAST_ACK : TCP_FIN_WAIT_1;
|
||||
conn->tx_unacked = 1;
|
||||
conn->nrtx = 0;
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1;
|
||||
#endif
|
||||
ninfo("TCP state: TCP_FIN_WAIT_1\n");
|
||||
ninfo("TCP state: %d\n", conn->tcpstateflags);
|
||||
|
||||
dev->d_sndlen = 0;
|
||||
tcp_send(dev, conn, TCP_FIN | TCP_ACK, hdrlen);
|
||||
|
||||
+4
-2
@@ -153,7 +153,8 @@ static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev,
|
||||
* TCP_CLOSE is handled above.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->tcpstateflags == TCP_ESTABLISHED);
|
||||
DEBUGASSERT(conn->tcpstateflags == TCP_ESTABLISHED ||
|
||||
conn->tcpstateflags == TCP_CLOSE_WAIT);
|
||||
|
||||
/* Drop data received in this state and make sure that TCP_CLOSE
|
||||
* is set in the response
|
||||
@@ -236,7 +237,8 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
||||
*/
|
||||
|
||||
if ((conn->tcpstateflags == TCP_ESTABLISHED ||
|
||||
conn->tcpstateflags == TCP_LAST_ACK) &&
|
||||
conn->tcpstateflags == TCP_LAST_ACK ||
|
||||
conn->tcpstateflags == TCP_CLOSE_WAIT) &&
|
||||
(conn->clscb = tcp_callback_alloc(conn)) != NULL)
|
||||
{
|
||||
/* Free rx buffers of the connection immediately */
|
||||
|
||||
@@ -109,7 +109,8 @@ void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
|
||||
|
||||
/* Verify that the connection is established. */
|
||||
|
||||
if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED)
|
||||
if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED ||
|
||||
(conn->tcpstateflags & TCP_STATE_MASK) == TCP_CLOSE_WAIT)
|
||||
{
|
||||
/* Set up for the callback. We can't know in advance if the
|
||||
* application is going to send a IPv4 or an IPv6 packet, so this
|
||||
|
||||
+43
-23
@@ -982,8 +982,7 @@ found:
|
||||
g_netstats.tcp.drop, seq, TCP_SEQ_ADD(seq, dev->d_len),
|
||||
dev->d_len);
|
||||
|
||||
dev->d_len = 0;
|
||||
return;
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1046,7 +1045,8 @@ found:
|
||||
* bytes
|
||||
*/
|
||||
|
||||
if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED)
|
||||
if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED ||
|
||||
(conn->tcpstateflags & TCP_STATE_MASK) == TCP_CLOSE_WAIT)
|
||||
{
|
||||
nwarn("WARNING: ackseq > unackseq\n");
|
||||
nwarn("sndseq=%" PRIu32 " tx_unacked=%" PRIu32
|
||||
@@ -1109,7 +1109,8 @@ found:
|
||||
|
||||
/* Check if no packet need to retransmission, clear timer. */
|
||||
|
||||
if (conn->tx_unacked == 0 && conn->tcpstateflags == TCP_ESTABLISHED)
|
||||
if (conn->tx_unacked == 0 && (conn->tcpstateflags == TCP_ESTABLISHED ||
|
||||
conn->tcpstateflags == TCP_CLOSE_WAIT))
|
||||
{
|
||||
timeout = 0;
|
||||
}
|
||||
@@ -1397,8 +1398,6 @@ found:
|
||||
* has been closed.
|
||||
*/
|
||||
|
||||
flags |= TCP_CLOSE;
|
||||
|
||||
if (dev->d_len > 0)
|
||||
{
|
||||
flags |= TCP_NEWDATA;
|
||||
@@ -1406,23 +1405,10 @@ found:
|
||||
|
||||
result = tcp_callback(dev, conn, flags);
|
||||
|
||||
if ((result & TCP_CLOSE) != 0)
|
||||
{
|
||||
conn->tcpstateflags = TCP_LAST_ACK;
|
||||
conn->tx_unacked = 1;
|
||||
conn->nrtx = 0;
|
||||
net_incr32(conn->rcvseq, 1); /* ack FIN */
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
conn->sndseq_max = tcp_getsequence(conn->sndseq) + 1;
|
||||
#endif
|
||||
ninfo("TCP state: TCP_LAST_ACK\n");
|
||||
tcp_send(dev, conn, TCP_FIN | TCP_ACK, tcpiplen);
|
||||
}
|
||||
else
|
||||
{
|
||||
ninfo("TCP: Dropped a FIN\n");
|
||||
tcp_appsend(dev, conn, result);
|
||||
}
|
||||
conn->tcpstateflags = TCP_CLOSE_WAIT;
|
||||
net_incr32(conn->rcvseq, 1); /* ack FIN */
|
||||
ninfo("TCP state: TCP_CLOSE_WAIT\n");
|
||||
tcp_appsend(dev, conn, result | TCP_SNDACK);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1681,6 +1667,40 @@ found:
|
||||
ninfo("TCP state: TCP_TIME_WAIT\n");
|
||||
}
|
||||
|
||||
goto drop;
|
||||
|
||||
case TCP_CLOSE_WAIT:
|
||||
#ifdef CONFIG_NET_TCP_KEEPALIVE
|
||||
/* If the established socket receives an ACK or any kind of data
|
||||
* from the remote peer (whether we accept it or not), then reset
|
||||
* the keep alive timer.
|
||||
*/
|
||||
|
||||
if (conn->keepalive && (tcp->flags & TCP_ACK) != 0)
|
||||
{
|
||||
/* Reset the "alive" timer. */
|
||||
|
||||
tcp_update_keeptimer(conn, conn->keepidle);
|
||||
conn->keepretries = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((flags & TCP_ACKDATA) != 0)
|
||||
{
|
||||
dev->d_sndlen = 0;
|
||||
|
||||
/* Provide the packet to the application */
|
||||
|
||||
result = tcp_callback(dev, conn, flags);
|
||||
|
||||
/* Send the response, ACKing the data or not, as appropriate */
|
||||
|
||||
tcp_appsend(dev, conn, result);
|
||||
return;
|
||||
}
|
||||
|
||||
goto drop;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -197,8 +197,8 @@ static void retransmit_segment(FAR struct tcp_conn_s *conn,
|
||||
* retransmitted, and un-ACKed, if expired is not zero, the
|
||||
* connection will be closed.
|
||||
*
|
||||
* field expired can only be updated at TCP_ESTABLISHED
|
||||
* state
|
||||
* field expired can only be updated at TCP_ESTABLISHED and
|
||||
* TCP_CLOSE_WAIT state.
|
||||
*/
|
||||
|
||||
conn->expired++;
|
||||
@@ -936,7 +936,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
||||
* retransmitted, and un-ACKed, if expired is not zero, the
|
||||
* connection will be closed.
|
||||
*
|
||||
* field expired can only be updated at TCP_ESTABLISHED state
|
||||
* field expired can only be updated at TCP_ESTABLISHED and
|
||||
* TCP_CLOSE_WAIT state.
|
||||
*/
|
||||
|
||||
conn->expired++;
|
||||
@@ -1012,7 +1013,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
||||
* will have to wait for the next polling cycle.
|
||||
*/
|
||||
|
||||
if ((conn->tcpstateflags & TCP_ESTABLISHED) &&
|
||||
if ((conn->tcpstateflags & TCP_ESTABLISHED ||
|
||||
conn->tcpstateflags & TCP_CLOSE_WAIT) &&
|
||||
((flags & TCP_NEWDATA) == 0) &&
|
||||
(flags & (TCP_POLL | TCP_REXMIT | TCP_ACKDATA)) &&
|
||||
!(sq_empty(&conn->write_q)) &&
|
||||
|
||||
@@ -112,7 +112,8 @@ static inline int tcp_send_fin(FAR struct socket *psock)
|
||||
|
||||
if ((conn->tcpstateflags == TCP_ESTABLISHED ||
|
||||
conn->tcpstateflags == TCP_SYN_SENT ||
|
||||
conn->tcpstateflags == TCP_SYN_RCVD))
|
||||
conn->tcpstateflags == TCP_SYN_RCVD ||
|
||||
conn->tcpstateflags == TCP_CLOSE_WAIT))
|
||||
{
|
||||
if ((conn->shdcb = tcp_callback_alloc(conn)) == NULL)
|
||||
{
|
||||
|
||||
+3
-1
@@ -623,6 +623,7 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
|
||||
goto done;
|
||||
|
||||
case TCP_ESTABLISHED:
|
||||
case TCP_CLOSE_WAIT:
|
||||
|
||||
/* In the ESTABLISHED state, we call upon the application
|
||||
* to do the actual retransmit after which we jump into
|
||||
@@ -673,7 +674,8 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
|
||||
* connection has been established.
|
||||
*/
|
||||
|
||||
else if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED)
|
||||
else if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED ||
|
||||
(conn->tcpstateflags & TCP_STATE_MASK) == TCP_CLOSE_WAIT)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP_KEEPALIVE
|
||||
/* Is this an established connected with KeepAlive enabled? */
|
||||
|
||||
Reference in New Issue
Block a user