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 f933738a0b91ea31c8b586667740186e17478fa6 Author: Ricard Rosson <[email protected]> AuthorDate: Mon Oct 26 20:25:46 2026 +0000 netutils/telnetd: Anchor 0..2 to /dev/null instead of closing them. When the daemon is started without standard streams (e.g. spawned by nsh_telnetstart() before a USB console device exists), descriptors 0..2 are free, so socket() can return the listen socket in that range. The "go silent" close(0)..close(2) at the top of the accept loop then closes the listen socket itself: every subsequent accept4() fails and the daemon serves nothing, while still appearing to run. The same applies to an accepted socket or session driver landing in 0..2, which the per-session dup2(0..2) would clobber. Fix the cause rather than relocating the one descriptor: anchor any free slot in 0..2 to /dev/null before creating the listen socket, and in the accept loop re-anchor 0..2 to /dev/null instead of closing them. 0..2 are then always occupied, so no descriptor the daemon creates can be allocated in the standard-stream range. Select DEV_NULL, which DEFAULT_SMALL configurations otherwise leave out: without /dev/null the daemon cannot start. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Ricard Rosson <[email protected]> --- netutils/telnetd/Kconfig | 1 + netutils/telnetd/telnetd_daemon.c | 47 +++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/netutils/telnetd/Kconfig b/netutils/telnetd/Kconfig index 896bbd62f..423d218b9 100644 --- a/netutils/telnetd/Kconfig +++ b/netutils/telnetd/Kconfig @@ -8,5 +8,6 @@ config NETUTILS_TELNETD default n depends on NET && NET_TCP select NETDEV_TELNET + select DEV_NULL ---help--- Enable support for the Telnet daemon. diff --git a/netutils/telnetd/telnetd_daemon.c b/netutils/telnetd/telnetd_daemon.c index c1512113c..18dfbe5f7 100644 --- a/netutils/telnetd/telnetd_daemon.c +++ b/netutils/telnetd/telnetd_daemon.c @@ -81,6 +81,7 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config) socklen_t addrlen; int listensd; int acceptsd; + int nullfd; #ifdef CONFIG_NET_SOCKOPTS int optval; #endif @@ -115,6 +116,31 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config) } #endif /* CONFIG_SCHED_HAVE_PARENT && CONFIG_ENABLE_ALL_SIGNALS */ + /* If the daemon was started without standard streams (e.g. spawned by + * nsh_telnetstart() before a USB console exists), descriptors 0..2 are + * free and any descriptor created below -- the listen socket, an + * accepted socket or a session driver -- could be allocated in the + * standard-stream range, where the per-session dup2(0..2) would clobber + * it. Anchor any free slot in 0..2 to /dev/null first so that can + * never happen. + */ + + for (; ; ) + { + nullfd = open("/dev/null", O_RDWR); + if (nullfd < 0) + { + nerr("ERROR: open(/dev/null) failed: %d\n", errno); + goto errout; + } + + if (nullfd > 2) + { + close(nullfd); + break; + } + } + /* Create a new TCP socket to use to listen for connections */ listensd = socket(config->d_family, SOCK_STREAM | SOCK_CLOEXEC, 0); @@ -190,11 +216,24 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config) #endif int drvrfd; - /* Now go silent. */ + /* Now go silent: detach from the previous session's driver (or the + * startup streams) by re-anchoring 0..2 to /dev/null instead of + * closing them. Closing would leave 0..2 free, and accept4() or + * open() below could then allocate into the standard-stream range + * where the dup2(0..2) for the next session would clobber it. + */ - close(0); - close(1); - close(2); + nullfd = open("/dev/null", O_RDWR); + if (nullfd >= 0) + { + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + if (nullfd > 2) + { + close(nullfd); + } + } ninfo("Accepting connections on port %d\n", ntohs(config->d_port));
