From fb83ceaf57d661b005236eab1a6fd54a0f480c30 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 14 Nov 2022 08:28:43 -0500 Subject: [PATCH] LibCore: Allow TCPServer's port to be reused after it exits This hasn't been an issue on Serenity, but on Linux, if a program opens a TCPServer on some port and then exits, that program can't be re-run until the OS makes the port available again. This is usually ~2x the TCP socket's maximum segment lifetime, upwards of a minute. Add an option to TCPServer to allow re-using the port after the program exits. --- Userland/Libraries/LibCore/TCPServer.cpp | 8 +++++++- Userland/Libraries/LibCore/TCPServer.h | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibCore/TCPServer.cpp b/Userland/Libraries/LibCore/TCPServer.cpp index 1402a001a1..26fa624d1a 100644 --- a/Userland/Libraries/LibCore/TCPServer.cpp +++ b/Userland/Libraries/LibCore/TCPServer.cpp @@ -39,13 +39,19 @@ TCPServer::~TCPServer() MUST(Core::System::close(m_fd)); } -ErrorOr TCPServer::listen(IPv4Address const& address, u16 port) +ErrorOr TCPServer::listen(IPv4Address const& address, u16 port, AllowAddressReuse allow_address_reuse) { if (m_listening) return Error::from_errno(EADDRINUSE); auto socket_address = SocketAddress(address, port); auto in = socket_address.to_sockaddr_in(); + + if (allow_address_reuse == AllowAddressReuse::Yes) { + int option = 1; + TRY(Core::System::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option))); + } + TRY(Core::System::bind(m_fd, (sockaddr const*)&in, sizeof(in))); TRY(Core::System::listen(m_fd, 5)); m_listening = true; diff --git a/Userland/Libraries/LibCore/TCPServer.h b/Userland/Libraries/LibCore/TCPServer.h index d2357ec188..3af4141bcc 100644 --- a/Userland/Libraries/LibCore/TCPServer.h +++ b/Userland/Libraries/LibCore/TCPServer.h @@ -20,8 +20,13 @@ public: static ErrorOr> try_create(Object* parent = nullptr); virtual ~TCPServer() override; + enum class AllowAddressReuse { + Yes, + No, + }; + bool is_listening() const { return m_listening; } - ErrorOr listen(IPv4Address const& address, u16 port); + ErrorOr listen(IPv4Address const& address, u16 port, AllowAddressReuse = AllowAddressReuse::No); ErrorOr set_blocking(bool blocking); ErrorOr> accept();