mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
net/tcp: add TCP_RXCLOSE to handle rx is shutdown
notify the local waiting recv process; otherwise, after the peer TX is closed, the wait of the recv process will continue to wait. Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
parent
2ad01e2aab
commit
fa47ab7bd2
8 changed files with 71 additions and 32 deletions
|
|
@ -62,8 +62,8 @@
|
|||
|
||||
/* The following flags may be set in the set of flags by the lower, device-
|
||||
* interfacing layer before calling through the socket layer callback. The
|
||||
* TCP_ACKDATA, XYZ_NEWDATA, and TCP_CLOSE flags may be set at the same time,
|
||||
* whereas the others are mutually exclusive.
|
||||
* TCP_ACKDATA, XYZ_NEWDATA, TCP_CLOSE, TCP_RXCLOSE and TCP_TXCLOSE flags
|
||||
* may be set at the same time, whereas the others are mutually exclusive.
|
||||
*
|
||||
* Connection Specific Events: These are events that may be notified
|
||||
* through callback lists residing in TCP, UDP, or PKT port connection
|
||||
|
|
@ -123,6 +123,19 @@
|
|||
* retransmissions. (TCP only)
|
||||
* OUT: Not used
|
||||
*
|
||||
* TCP_RXCLOSE IN: The remote host has closed the connection, thus the
|
||||
* connection has gone away. (TCP only)
|
||||
* OUT: The socket layer signals that it wants to close the
|
||||
* connection. (TCP only)
|
||||
*
|
||||
* TCP_TXCLOSE IN: The local host has closed the connection, thus the
|
||||
* connection has gone away. (TCP only)
|
||||
* OUT: The socket layer signals that it wants to close the
|
||||
* connection. (TCP only)
|
||||
*
|
||||
* NETDEV_DOWN: IN: The network device has been taken down.
|
||||
* OUT: Not used
|
||||
*
|
||||
* Device Specific Events: These are events that may be notified through
|
||||
* callback lists residing in the network device structure.
|
||||
*
|
||||
|
|
@ -159,12 +172,9 @@
|
|||
* event, not associated with a socket. The appdata
|
||||
* pointer is not used in this case.
|
||||
* OUT: Not used
|
||||
*
|
||||
* NETDEV_DOWN: IN: The network device has been taken down.
|
||||
* OUT: Not used
|
||||
*/
|
||||
|
||||
/* Bits 0-11: Connection specific event bits */
|
||||
/* Bits 0-12: Connection specific event bits */
|
||||
|
||||
#define TCP_ACKDATA (1 << 0)
|
||||
#define TCP_NEWDATA (1 << 1)
|
||||
|
|
@ -193,18 +203,19 @@
|
|||
#define TCP_TIMEDOUT (1 << 9)
|
||||
#define TCP_WAITALL (1 << 10)
|
||||
#define TCP_TXCLOSE (1 << 11)
|
||||
#define TCP_RXCLOSE (1 << 12)
|
||||
|
||||
/* Bit 12: Device specific event bits */
|
||||
/* Bit 13: Device specific event bits */
|
||||
|
||||
#define NETDEV_DOWN (1 << 12)
|
||||
#define NETDEV_DOWN (1 << 13)
|
||||
|
||||
/* Bits 13-15: Encoded device specific poll events. Unlike connection
|
||||
/* Bits 14-16: Encoded device specific poll events. Unlike connection
|
||||
* oriented poll events, device related poll events must distinguish
|
||||
* between what is being polled for since the callbacks all reside in
|
||||
* the same list in the network device structure.
|
||||
*/
|
||||
|
||||
#define DEVPOLL_SHIFT (13)
|
||||
#define DEVPOLL_SHIFT (14)
|
||||
#define DEVPOLL_MASK (7 << DEVPOLL_SHIFT)
|
||||
# define DEVPOLL_NONE (0 << DEVPOLL_SHIFT)
|
||||
# define ARP_POLL (1 << DEVPOLL_SHIFT)
|
||||
|
|
@ -216,7 +227,7 @@
|
|||
|
||||
#define TCP_CONN_EVENTS \
|
||||
(TCP_CLOSE | TCP_ABORT | TCP_CONNECTED | TCP_TIMEDOUT | NETDEV_DOWN | \
|
||||
TCP_TXCLOSE)
|
||||
TCP_TXCLOSE | TCP_RXCLOSE)
|
||||
|
||||
#define TCP_DISCONN_EVENTS \
|
||||
(TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT | NETDEV_DOWN)
|
||||
|
|
|
|||
|
|
@ -189,9 +189,9 @@ struct tcp_conn_s
|
|||
* When an callback is executed from 'list', the input flags are normally
|
||||
* returned, however, the implementation may set one of the following:
|
||||
*
|
||||
* TCP_RXCLOSE - Gracefully close the current connection (RX)
|
||||
* TCP_TXCLOSE - Gracefully close the current connection (TX)
|
||||
* TCP_ABORT - Abort (reset) the current connection on an error that
|
||||
* prevents TCP_CLOSE from working.
|
||||
* TCP_ABORT - Abort (reset) the current connection
|
||||
*
|
||||
* And/Or set/clear the following:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -271,10 +271,10 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Preserve the TCP_ACKDATA, TCP_TXCLOSE, and TCP_ABORT in the response.
|
||||
* These is needed by the network to handle responses and buffer state.
|
||||
* The TCP_NEWDATA indication will trigger the ACK response, but must be
|
||||
* explicitly set in the callback.
|
||||
/* Preserve the TCP_ACKDATA, TCP_CLOSE, TCP_RXCLOSE, TCP_TXCLOSE, and
|
||||
* TCP_ABORT in the response. These is needed by the network to handle
|
||||
* responses and buffer state. The TCP_NEWDATA indication will trigger
|
||||
* the ACK response, but must be explicitly set in the callback.
|
||||
*/
|
||||
|
||||
ninfo("flags: %04x\n", flags);
|
||||
|
|
@ -283,9 +283,9 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
|
|||
* 'list', the input flags are normally returned, however, the
|
||||
* implementation may set one of the following:
|
||||
*
|
||||
* TCP_RXCLOSE - Gracefully close the current connection (RX)
|
||||
* TCP_TXCLOSE - Gracefully close the current connection (TX)
|
||||
* TCP_ABORT - Abort (reset) the current connection on an error that
|
||||
* prevents TCP_CLOSE from working.
|
||||
* TCP_ABORT - Abort (reset) the current connection
|
||||
*
|
||||
* And/Or set/clear the following:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1398,6 +1398,7 @@ found:
|
|||
* has been closed.
|
||||
*/
|
||||
|
||||
flags |= TCP_RXCLOSE;
|
||||
if (dev->d_len > 0)
|
||||
{
|
||||
flags |= TCP_NEWDATA;
|
||||
|
|
@ -1577,7 +1578,7 @@ found:
|
|||
}
|
||||
|
||||
net_incr32(conn->rcvseq, 1); /* ack FIN */
|
||||
tcp_callback(dev, conn, TCP_CLOSE);
|
||||
tcp_callback(dev, conn, TCP_RXCLOSE);
|
||||
tcp_send(dev, conn, TCP_ACK, tcpiplen);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1606,7 +1607,7 @@ found:
|
|||
ninfo("TCP state: TCP_TIME_WAIT\n");
|
||||
|
||||
net_incr32(conn->rcvseq, 1); /* ack FIN */
|
||||
tcp_callback(dev, conn, TCP_CLOSE);
|
||||
tcp_callback(dev, conn, TCP_RXCLOSE);
|
||||
tcp_send(dev, conn, TCP_ACK, tcpiplen);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ static void tcp_close_connection(FAR struct tcp_conn_s *conn, uint16_t flags)
|
|||
* _SF_CONNECTED==0 && _SF_CLOSED==0 - the socket was rudely disconnected
|
||||
*/
|
||||
|
||||
/* The loss of connection was less than graceful. This will
|
||||
* (eventually) be reported as an ENOTCONN error.
|
||||
*/
|
||||
|
||||
if ((flags & TCP_CLOSE) != 0)
|
||||
{
|
||||
/* The peer gracefully closed the connection. Marking the
|
||||
|
|
@ -174,6 +178,10 @@ static uint16_t tcp_monitor_event(FAR struct net_driver_s *dev,
|
|||
conn->sconn.s_flags |= (_SF_BOUND | _SF_CONNECTED);
|
||||
conn->sconn.s_flags &= ~_SF_CLOSED;
|
||||
}
|
||||
else if ((flags & TCP_RXCLOSE) != 0)
|
||||
{
|
||||
conn->shutdown |= SHUT_RD;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
|
@ -294,7 +302,7 @@ int tcp_start_monitor(FAR struct socket *psock)
|
|||
{
|
||||
cb->event = tcp_monitor_event;
|
||||
cb->priv = (FAR void *)conn;
|
||||
cb->flags = TCP_DISCONN_EVENTS;
|
||||
cb->flags = TCP_DISCONN_EVENTS | TCP_RXCLOSE;
|
||||
|
||||
/* Monitor the connected event */
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
|
|||
|
||||
/* Check for data or connection availability events. */
|
||||
|
||||
if ((flags & (TCP_NEWDATA | TCP_BACKLOG)) != 0)
|
||||
if ((flags & (TCP_NEWDATA | TCP_BACKLOG | TCP_RXCLOSE)) != 0)
|
||||
{
|
||||
eventset |= POLLIN;
|
||||
}
|
||||
|
|
@ -301,7 +301,7 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
|||
|
||||
if ((fds->events & POLLIN) != 0)
|
||||
{
|
||||
cb->flags |= TCP_NEWDATA | TCP_BACKLOG;
|
||||
cb->flags |= TCP_NEWDATA | TCP_BACKLOG | TCP_RXCLOSE;
|
||||
}
|
||||
|
||||
/* Save the reference in the poll info structure as fds private as well
|
||||
|
|
@ -312,7 +312,8 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
|||
|
||||
/* Check for read data or backlogged connection availability now */
|
||||
|
||||
if (conn->readahead != NULL || tcp_backlogpending(conn))
|
||||
if (conn->readahead != NULL || tcp_backlogpending(conn) ||
|
||||
(conn->shutdown & SHUT_RD) != 0)
|
||||
{
|
||||
/* Normal data may be read without blocking. */
|
||||
|
||||
|
|
|
|||
|
|
@ -209,10 +209,11 @@ static inline uint16_t tcp_newdata(FAR struct net_driver_s *dev,
|
|||
|
||||
if (recvlen < dev->d_len)
|
||||
{
|
||||
/* Clear the TCP_CLOSE because we effectively dropped the FIN as well.
|
||||
/* Clear the TCP_RXCLOSE because we effectively dropped the FIN as
|
||||
* well.
|
||||
*/
|
||||
|
||||
flags &= ~TCP_CLOSE;
|
||||
flags &= ~TCP_RXCLOSE;
|
||||
}
|
||||
|
||||
net_incr32(conn->rcvseq, recvlen);
|
||||
|
|
@ -522,6 +523,12 @@ static uint16_t tcp_recvhandler(FAR struct net_driver_s *dev,
|
|||
|
||||
/* Wake up the waiting thread */
|
||||
|
||||
nxsem_post(&pstate->ir_sem);
|
||||
}
|
||||
else if ((flags & TCP_RXCLOSE) != 0)
|
||||
{
|
||||
ninfo("TCP_RXCLOSE\n");
|
||||
pstate->ir_result = 0;
|
||||
nxsem_post(&pstate->ir_sem);
|
||||
}
|
||||
}
|
||||
|
|
@ -719,7 +726,8 @@ static ssize_t tcp_recvfrom_one(FAR struct tcp_conn_s *conn, FAR void *buf,
|
|||
|
||||
/* Verify that the SOCK_STREAM has been and still is connected */
|
||||
|
||||
if (!_SS_ISCONNECTED(conn->sconn.s_flags))
|
||||
if (!_SS_ISCONNECTED(conn->sconn.s_flags) ||
|
||||
(conn->shutdown & SHUT_RD) != 0)
|
||||
{
|
||||
/* Was any data transferred from the readahead buffer after we were
|
||||
* disconnected? If so, then return the number of bytes received.
|
||||
|
|
@ -732,7 +740,8 @@ static ssize_t tcp_recvfrom_one(FAR struct tcp_conn_s *conn, FAR void *buf,
|
|||
* recvfrom() will get an end-of-file indication.
|
||||
*/
|
||||
|
||||
if (ret <= 0 && !_SS_ISCLOSED(conn->sconn.s_flags))
|
||||
if (ret <= 0 && !_SS_ISCLOSED(conn->sconn.s_flags) &&
|
||||
(conn->shutdown & SHUT_RD) == 0)
|
||||
{
|
||||
/* Nothing was previously received from the read-ahead buffers.
|
||||
* The SOCK_STREAM must be (re-)connected in order to receive
|
||||
|
|
@ -794,7 +803,8 @@ static ssize_t tcp_recvfrom_one(FAR struct tcp_conn_s *conn, FAR void *buf,
|
|||
state.ir_cb = tcp_callback_alloc(conn);
|
||||
if (state.ir_cb)
|
||||
{
|
||||
state.ir_cb->flags = (TCP_NEWDATA | TCP_DISCONN_EVENTS);
|
||||
state.ir_cb->flags = (TCP_NEWDATA | TCP_RXCLOSE |
|
||||
TCP_DISCONN_EVENTS);
|
||||
state.ir_cb->flags |= (flags & MSG_WAITALL) ? TCP_WAITALL : 0;
|
||||
state.ir_cb->priv = (FAR void *)&state;
|
||||
state.ir_cb->event = tcp_recvhandler;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,15 @@ static uint16_t tcp_shutdown_eventhandler(FAR struct net_driver_s *dev,
|
|||
#endif
|
||||
|
||||
dev->d_len = 0;
|
||||
flags |= TCP_TXCLOSE;
|
||||
if ((conn->shutdown & SHUT_WR) != 0)
|
||||
{
|
||||
flags |= TCP_TXCLOSE;
|
||||
}
|
||||
|
||||
if ((conn->shutdown & SHUT_RD) != 0)
|
||||
{
|
||||
flags |= TCP_RXCLOSE;
|
||||
}
|
||||
|
||||
if (conn->shdcb != NULL)
|
||||
{
|
||||
|
|
@ -165,7 +173,7 @@ int tcp_shutdown(FAR struct socket *psock, int how)
|
|||
conn = psock->s_conn;
|
||||
DEBUGASSERT(conn != NULL);
|
||||
|
||||
if (!(how & SHUT_WR))
|
||||
if (!(how & SHUT_RDWR))
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue