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

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

commit 5255ef5b3beac214d82ad2be2926bf98f92fb1be
Author: Marco Casaroli <[email protected]>
AuthorDate: Tue Nov 3 01:16:15 2026 +0100

    net/tcp: Return EPIPE from a send after the connection was closed.
    
    POSIX: a send on a connection-mode socket that is no longer connected
    fails with EPIPE, and the caller gets SIGPIPE unless MSG_NOSIGNAL is
    given.  After the peer closed a TCP connection, the next send got a
    reset, and every send after it failed with ENOTCONN.  So
    psock_sigpipe() did not raise SIGPIPE, and a program that writes to a
    closed connection did not end.
    
    The send paths now return -EPIPE when the socket is not connected and
    _SF_CLOSED is set (the connection was closed or reset by the peer), and
    -ENOTCONN as before for a socket that never was connected.  This is
    TCP_NOTCONN_ERROR() in tcp.h, used in the buffered send, the unbuffered
    send and tcp_sendfile(), and in the event handlers of the unbuffered
    send and of tcp_sendfile().
    
    A connection lost by a timeout or a network down event clears
    _SF_CLOSED too, so a send after it still fails with ENOTCONN.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 net/tcp/tcp.h                 |  8 ++++++++
 net/tcp/tcp_send_buffered.c   |  7 ++++---
 net/tcp/tcp_send_unbuffered.c | 14 ++++++++------
 net/tcp/tcp_sendfile.c        |  8 +++++---
 4 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 2bdb0f50665..22332f104e3 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -100,6 +100,14 @@
 #define TCP_SEQ_ADD(a, b)   ((uint32_t)((a) + (b)))
 #define TCP_SEQ_SUB(a, b)   ((uint32_t)((a) - (b)))
 
+/* The error of a send on a TCP socket that is not connected: -EPIPE if the
+ * connection was closed (POSIX: the socket is no longer connected), else
+ * -ENOTCONN.
+ */
+
+#define TCP_NOTCONN_ERROR(conn) \
+  (_SS_ISCLOSED((conn)->sconn.s_flags) ? -EPIPE : -ENOTCONN)
+
 /* The TCP options flags */
 
 #define TCP_WSCALE            0x01U /* Window Scale option enabled */
diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c
index b32076731a4..0e3edbccc86 100644
--- a/net/tcp/tcp_send_buffered.c
+++ b/net/tcp/tcp_send_buffered.c
@@ -1330,7 +1330,8 @@ static unsigned int tcp_send_gettimeout(clock_t start, 
unsigned int timeout)
  *   ENOTSOCK
  *     The argument s is not a socket.
  *   EPIPE
- *     The local end has been shut down on a connection oriented socket.
+ *     The local end has been shut down on a connection oriented socket, or
+ *     the connection was closed.
  *     In this case the process will also receive a SIGPIPE unless
  *     MSG_NOSIGNAL is set.
  *
@@ -1361,7 +1362,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR 
const void *buf,
   if (!_SS_ISCONNECTED(conn->sconn.s_flags))
     {
       nerr("ERROR: Not connected\n");
-      ret = -ENOTCONN;
+      ret = TCP_NOTCONN_ERROR(conn);
       goto errout;
     }
 
@@ -1429,7 +1430,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR 
const void *buf,
       if (!_SS_ISCONNECTED(conn->sconn.s_flags))
         {
           nerr("ERROR: No longer connected\n");
-          ret = -ENOTCONN;
+          ret = TCP_NOTCONN_ERROR(conn);
           goto errout_with_lock;
         }
 
diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c
index 0113c729f61..8fe57eb63e7 100644
--- a/net/tcp/tcp_send_unbuffered.c
+++ b/net/tcp/tcp_send_unbuffered.c
@@ -322,7 +322,7 @@ static uint32_t tcpsend_eventhandler(FAR struct 
net_driver_s *dev,
           tcp_lost_connection(conn, pstate->snd_cb, flags);
         }
 
-      pstate->snd_sent = -ENOTCONN;
+      pstate->snd_sent = TCP_NOTCONN_ERROR(conn);
       goto end_wait;
     }
 
@@ -473,7 +473,8 @@ end_wait:
  *   ENOTSOCK
  *     The argument s is not a socket.
  *   EPIPE
- *     The local end has been shut down on a connection oriented socket.
+ *     The local end has been shut down on a connection oriented socket, or
+ *     the connection was closed.
  *     In this case the process will also receive a SIGPIPE unless
  *     MSG_NOSIGNAL is set.
  *
@@ -500,14 +501,15 @@ ssize_t psock_tcp_send(FAR struct socket *psock,
   conn = psock->s_conn;
 
   /* Check early if this is an un-connected socket, if so, then
-   * return -ENOTCONN. Note, we will have to check this again, as we can't
-   * guarantee the state won't change until we have the network locked.
+   * return -ENOTCONN (-EPIPE after the connection was closed).  Note, we
+   * will have to check this again, as we can't guarantee the state won't
+   * change until we have the network locked.
    */
 
   if (!_SS_ISCONNECTED(conn->sconn.s_flags))
     {
       nerr("ERROR: Not connected\n");
-      ret = -ENOTCONN;
+      ret = TCP_NOTCONN_ERROR(conn);
       goto errout;
     }
 
@@ -566,7 +568,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock,
     {
       nerr("ERROR: No longer connected\n");
       conn_dev_unlock(&conn->sconn, conn->dev);
-      ret = -ENOTCONN;
+      ret = TCP_NOTCONN_ERROR(conn);
       goto errout;
     }
 
diff --git a/net/tcp/tcp_sendfile.c b/net/tcp/tcp_sendfile.c
index edfb7ac259b..50fe745b449 100644
--- a/net/tcp/tcp_sendfile.c
+++ b/net/tcp/tcp_sendfile.c
@@ -310,7 +310,7 @@ static uint32_t sendfile_eventhandler(FAR struct 
net_driver_s *dev,
 
       /* Report not connected */
 
-      pstate->snd_sent = -ENOTCONN;
+      pstate->snd_sent = TCP_NOTCONN_ERROR(conn);
       goto end_wait;
     }
 
@@ -425,12 +425,14 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct 
file *infile,
   conn = psock->s_conn;
   DEBUGASSERT(conn != NULL);
 
-  /* If this is an un-connected socket, then return ENOTCONN */
+  /* If this is an un-connected socket, then return ENOTCONN (EPIPE after
+   * the connection was closed).
+   */
 
   if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(conn->sconn.s_flags))
     {
       nerr("ERROR: Not connected\n");
-      return -ENOTCONN;
+      return TCP_NOTCONN_ERROR(conn);
     }
 
   /* Make sure that we have the IP address mapping */

Reply via email to