casaroli opened a new pull request, #3959:
URL: https://github.com/apache/nuttx-apps/pull/3959

   ## Summary
   
   Since apache/nuttx#21324, `send()`, `sendto()`, `sendmsg()` and `write()` on 
a stream socket raise `SIGPIPE` when they fail with `EPIPE`. With 
`CONFIG_SIG_SIGPIPE_ACTION`, the default action of `SIGPIPE` ends the task. A 
server that writes to a client that closed the connection then stops for all 
clients.
   
   Today NuttX TCP returns `ENOTCONN`, not `EPIPE`, for a send after the peer 
closed or reset the connection, so TCP servers do not get the signal yet. POSIX 
and Linux return `EPIPE` in this case, and a NuttX change to do the same is 
planned. This PR prepares the TCP servers in apps for it. The servers get 
`EPIPE` as an error and end only the connection with that client.
   
   The fix per program:
   
   - `send()` with `MSG_NOSIGNAL` instead of `send(..., 0)` or `write()`: 
netutils/ftpd, netutils/webserver, system/telnet (telnet_chatd), 
system/fastboot (TCP transport), netutils/xmlrpc, examples/tcpecho, 
examples/xmlrpc, examples/tcp_ipc_server, examples/poll, examples/netloop.
   - `sendmsg()` with `MSG_NOSIGNAL` instead of `writev()`: industry/nxmodbus 
(TCP transport).
   - `signal(SIGPIPE, SIG_IGN)` at the start, as upstream dropbear does in 
svr-main.c: netutils/dropbear. Its writes are in the upstream sources. 
`task_spawn()` starts the NSH sessions with the default action.
   
   `MSG_NOSIGNAL` changes only the one call, so the commands that fastbootd 
(`oem shell`) starts keep the default action. Two programs also stopped on 
`EPIPE` without the signal: telnet_chatd called `exit()` for each send error 
other than `EINTR` and `ECONNRESET`, and a failed send in nxmodbus server mode 
ended the poll loop of examples/nxmbserver. telnet_chatd now handles `EPIPE` as 
`ECONNRESET`, and nxmodbus closes only that client and returns `-EAGAIN`, as it 
does after a failed read.
   
   The first commit fixes older nxstyle errors in the changed files, because 
the CI check runs nxstyle on each changed file as a whole. It changes only the 
layout (`git diff -w` shows only added braces, one moved declaration, two 
wrapped lines and three spelling fixes in comments).
   
   netutils/rexecd has the same problem with a local socket pair, which raises 
`SIGPIPE` already today. It has its own PR: apache/nuttx-apps#3957.
   
   ## Impact
   
   Only the programs above. Without `CONFIG_SIG_SIGPIPE_ACTION` there is no 
change in behaviour: a `SIGPIPE` without a handler is discarded, and the send 
already returned the error. All the changed calls write to sockets, so `send()` 
and `sendmsg()` with `MSG_NOSIGNAL` are equal to `write()` and `writev()` 
there. No documentation change: the pages of these programs in 
Documentation/applications do not describe this behaviour.
   
   ## Testing
   
   qemu-armv8a:nsh (flat build, QEMU with HVF) on nuttx master 4a98cd7b44f, 
with `CONFIG_NET_TCP`, `NET_LOOPBACK`, `NET_TCP_WRITE_BUFFERS`, `SIG_DEFAULT`, 
`SIG_SIGPIPE_ACTION`, small socket buffers (`NET_RECV_BUFSIZE` and 
`NET_SEND_BUFSIZE` 2048), examples/ftpd, fastbootd (TCP, with `oem shell`) and 
examples/tcpecho. A test program (builtin app) runs one case per server over 
127.0.0.1. A first client makes the server block in a send and then resets the 
connection: it closes the socket with unread data. ftpd: `RETR` of a 1 MB file 
in passive mode, then the reset of the data connection. fastbootd: `oem 
filedump` and `upload` of the same file. tcpecho: 6 KiB of data without reading 
the echo. Then a second client checks that the server still serves: the FTP 
greeting, `getvar:version`, and an echo. `ps` shows which servers still run.
   
   To get `EPIPE` from TCP as POSIX gives it, the test applies a test-only 
patch to nuttx (not part of any PR): the TCP send returns `EPIPE` instead of 
`ENOTCONN` after a reset of the connection.
   
   | Case | apps master 54374b3b2, TCP `EPIPE` | this PR, TCP `EPIPE` | apps 
master, nuttx master | this PR, nuttx master |
   |---|---|---|---|---|
   | ftpd: second client | no greeting, FTP daemon ended: FAIL | PASS | PASS | 
PASS |
   | fastbootd: second client | `ECONNREFUSED`, fastbootd ended: FAIL | PASS | 
PASS | PASS |
   | tcpecho: second client | `ECONNREFUSED`, tcpecho ended: FAIL | PASS | PASS 
| PASS |
   | ostest | 0 | 0 | 0 | 0 |
   
   The last two columns show that nuttx master does not give the signal over 
TCP today (`ENOTCONN`), and that the PR does not change that behaviour.
   
   Builds with `EXTRAFLAGS="-Wno-cpp -Werror"`, no compiler warnings: 
qemu-armv8a:nsh (flat, arm64) and rv-virt:nsh64 (flat, rv64) and rv-virt:pnsh64 
(protected, rv64) with every changed program enabled (webserver with sendfile, 
directory list and chunked encoding; fastbootd with TCP, serial and shell; 
nxmodbus TCP server); the defconfigs lm3s6965-ek:tcpecho, stm3240g-eval:xmlrpc, 
stm3240g-eval:webserver, qemu-armv8a:fastboot (with TCP), ntosd-dm320:poll, 
spresense:rndis (ftpd, webserver), stm32f746g-disco:dropbear; 
esp32-devkitc:wifi with examples/tcp_ipc_server (it needs `CONFIG_ESP32_UART1`).
   
   Not run: webserver, telnet_chatd, nxmodbus, dropbear, xmlrpc, 
tcp_ipc_server, poll and netloop (build only; the change in each is the same 
`MSG_NOSIGNAL` flag, or `signal()` for dropbear).
   
   `tools/checkpatch.sh -c -u -m -g` passes.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to