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-apps.git

commit a94b062af302de51e2489ebc5c70b693f81a0ddf
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Nov 2 11:16:01 2026 +0100

    industry/nxmodbus: Do not die of SIGPIPE when a TCP client closes.
    
    nxmb_tcp_send() writes the response with writev().  When the client
    closed the connection, the write fails with EPIPE.  A write to a stream
    socket whose peer is gone also raises SIGPIPE, and with
    CONFIG_SIG_SIGPIPE_ACTION the default action ends the application that
    runs the Modbus server.  Without the signal, nxmb_poll() returns the
    error, and a server loop that stops on errors other than EAGAIN (as
    examples/nxmbserver does) stops.
    
    Send with sendmsg() and MSG_NOSIGNAL.  In server mode, a failed send
    closes only this client and returns -EAGAIN, as a failed read does.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 industry/nxmodbus/transport/nxmb_tcp.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/industry/nxmodbus/transport/nxmb_tcp.c 
b/industry/nxmodbus/transport/nxmb_tcp.c
index f4b2dc940..dd1442054 100644
--- a/industry/nxmodbus/transport/nxmb_tcp.c
+++ b/industry/nxmodbus/transport/nxmb_tcp.c
@@ -375,6 +375,7 @@ static int nxmb_tcp_send(nxmb_handle_t ctx)
   FAR struct nxmb_tcp_client_s *client;
   uint8_t                       header[MBAP_FC_SIZE];
   struct iovec                  iov[2];
+  struct msghdr                 msg;
   uint16_t                      data_len;
   uint16_t                      total;
   ssize_t                       sent;
@@ -420,7 +421,7 @@ static int nxmb_tcp_send(nxmb_handle_t ctx)
 
   data_len = ctx->adu.length - 2;
 
-  /* Emit MBAP header + PDU data via writev() to avoid a stack-side
+  /* Emit MBAP header + PDU data via sendmsg() to avoid a stack-side
    * copy. The kernel gathers both iovecs into a single TCP segment.
    */
 
@@ -431,10 +432,24 @@ static int nxmb_tcp_send(nxmb_handle_t ctx)
   iov[1].iov_base = ctx->adu.data;
   iov[1].iov_len  = data_len;
 
+  memset(&msg, 0, sizeof(msg));
+  msg.msg_iov    = iov;
+  msg.msg_iovlen = (data_len > 0) ? 2 : 1;
+
   total = MBAP_FC_SIZE + data_len;
-  sent  = writev(fd, iov, (data_len > 0) ? 2 : 1);
+  sent  = sendmsg(fd, &msg, MSG_NOSIGNAL);
   if (sent != total)
     {
+      if (!ctx->is_client)
+        {
+          /* As for a failed read, drop only this client */
+
+          close(fd);
+          client->fd        = -1;
+          state->active_idx = -1;
+          return -EAGAIN;
+        }
+
       return (sent < 0) ? -errno : -EIO;
     }
 

Reply via email to