This commit is contained in:
ricardgb 2026-08-01 21:15:00 +08:00 committed by GitHub
commit 894e8a2942
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -125,6 +125,27 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
goto errout;
}
/* If the daemon was started without standard streams (e.g. spawned by
* nsh_telnetstart() before a USB console exists), socket() may have
* returned a descriptor in 0..2. The "go silent" close(0)..close(2)
* at the top of the accept loop below would then destroy the listen
* socket: every subsequent accept4() fails and the daemon serves
* nothing. Move the descriptor above the standard-stream range.
*/
if (listensd <= 2)
{
int highsd = fcntl(listensd, F_DUPFD_CLOEXEC, 3);
if (highsd < 0)
{
nerr("ERROR: F_DUPFD_CLOEXEC failed: %d\n", errno);
goto errout_with_socket;
}
close(listensd);
listensd = highsd;
}
#ifdef CONFIG_NET_SOCKOPTS
/* Set socket to reuse address */
@ -202,17 +223,33 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
acceptsd = accept4(listensd, &addr.generic, &addrlen, SOCK_CLOEXEC);
if (acceptsd < 0)
{
/* Just continue if a signal was received */
int err = errno;
if (errno == EINTR)
/* A bad listen socket can never recover - exiting loudly beats
* spinning forever while serving nothing.
*/
if (err == EBADF || err == ENOTSOCK || err == EINVAL ||
err == EOPNOTSUPP)
{
continue;
}
else
{
nerr("ERROR: accept failed: %d\n", errno);
nerr("ERROR: accept failed fatally: %d\n", err);
goto errout_with_socket;
}
/* Everything else is transient: a peer that reset before the
* accept completed (a port scan, nc -z, ECONNABORTED), a
* signal, or the interface bouncing. None of those may take
* the daemon down; the pause keeps a persistent transient
* (interface down) from busy-spinning.
*/
nerr("ERROR: accept failed: %d\n", err);
if (err != EINTR)
{
usleep(100 * 1000);
}
continue;
}
#ifdef CONFIG_NET_SOLINGER
@ -225,8 +262,14 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER,
&ling, sizeof(struct linger)) < 0)
{
/* Per-connection failure (e.g. the peer already reset the
* connection - a port scan does this). Drop the connection and
* keep accepting; exiting here lets any probe kill the daemon.
*/
nerr("ERROR: setsockopt failed: %d\n", errno);
goto errout_with_acceptsd;
close(acceptsd);
continue;
}
#endif
@ -236,7 +279,8 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
if (drvrfd < 0)
{
nerr("ERROR: open(/dev/telnet) failed: %d\n", errno);
goto errout_with_acceptsd;
close(acceptsd);
continue;
}
/* Create a character device to "wrap" the accepted socket descriptor */
@ -249,9 +293,10 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
if (ioctl(drvrfd, SIOCTELNET,
(unsigned long)((uintptr_t)&session)) < 0)
{
nerr("ERROR: open(/dev/telnet) failed: %d\n", errno);
nerr("ERROR: SIOCTELNET failed: %d\n", errno);
close(drvrfd);
goto errout_with_acceptsd;
close(acceptsd);
continue;
}
close(drvrfd);
@ -262,8 +307,12 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
drvrfd = open(session.ts_devpath, O_RDWR);
if (drvrfd < 0)
{
/* The socket now belongs to the telnet driver instance; just
* keep accepting.
*/
nerr("ERROR: Failed to open %s: %d\n", session.ts_devpath, errno);
goto errout_with_socket;
continue;
}
/* Use this driver as stdin, stdout, and stderror */
@ -319,16 +368,12 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
if (ret > 0)
{
nerr("ERROR: Failed start the telnet session: %d\n", ret);
errno = ret;
goto errout_with_socket;
continue;
}
}
#endif
}
errout_with_acceptsd:
close(acceptsd);
errout_with_socket:
close(listensd);
errout: