Stop logging normal client disconnects as exceptions

Clients that connect and close without sending a request -- health checks
(nc ... < /dev/null), port scanners, reset connections -- made
async_read_some throw eof, which the catch block logged as
"echo exception: End of file [asio.misc:2 ...]", spamming the logs.

Read with as_tuple so the error comes back as an error_code instead of an
exception: on any read error just return quietly. Writes likewise use
as_tuple and ignore errors (best-effort reply). The try/catch remains only
as a backstop for genuinely unexpected exceptions.
This commit is contained in:
pmb
2026-06-15 16:43:06 -07:00
parent 54650af252
commit 011f8c4838
+16 -6
View File
@@ -1,5 +1,6 @@
#include <iostream> #include <iostream>
#include <boost/asio/as_tuple.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/deferred.hpp> #include <boost/asio/deferred.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
@@ -41,8 +42,14 @@ awaitable<void> echo(tcp::socket socket, std::string client_addr, bool trackable
} }
char data[1024]; char data[1024];
auto bytes_read = auto [read_ec, bytes_read] = co_await socket.async_read_some(
co_await socket.async_read_some(boost::asio::buffer(data), deferred); boost::asio::buffer(data), boost::asio::as_tuple(deferred));
if (read_ec) {
// Client hung up before sending a request: health checks (which connect
// and immediately close), port scanners, and reset connections all land
// here. This is normal -- don't log it as an exception.
co_return;
}
std::string username(data, bytes_read); std::string username(data, bytes_read);
// Remove trailing \r\n characters // Remove trailing \r\n characters
while (!username.empty() && while (!username.empty() &&
@@ -70,12 +77,15 @@ awaitable<void> echo(tcp::socket socket, std::string client_addr, bool trackable
std::printf("finger miss from %s for '%s' (not tracked)\n", std::printf("finger miss from %s for '%s' (not tracked)\n",
client_addr.c_str(), username.c_str()); client_addr.c_str(), username.c_str());
} }
co_await async_write( // Best-effort reply; ignore write errors (the client may have already
socket, boost::asio::buffer(std::string("No plan found\r\n")), // gone away).
deferred); co_await async_write(socket,
boost::asio::buffer(std::string("No plan found\r\n")),
boost::asio::as_tuple(deferred));
co_return; co_return;
} }
co_await async_write(socket, boost::asio::buffer(response), deferred); co_await async_write(socket, boost::asio::buffer(response),
boost::asio::as_tuple(deferred));
co_return; co_return;
} catch (std::exception &e) { } catch (std::exception &e) {
std::printf("echo exception: %s\n", e.what()); std::printf("echo exception: %s\n", e.what());