From f46cece11e77bc40233e37e0f27892bb1dcb4eec Mon Sep 17 00:00:00 2001 From: Dominik Thalhammer Date: Tue, 25 Nov 2025 15:46:07 +0100 Subject: [PATCH] :sparkles: Add option to enable reuse address --- include/asyncpp/io/detail/io_engine.h | 1 + include/asyncpp/io/socket.h | 2 ++ src/io_engine_generic_unix.cpp | 6 ++++++ src/io_engine_generic_unix.h | 1 + src/io_engine_iocp.cpp | 7 +++++++ src/socket.cpp | 5 +++++ 6 files changed, 22 insertions(+) diff --git a/include/asyncpp/io/detail/io_engine.h b/include/asyncpp/io/detail/io_engine.h index d984868..be52138 100644 --- a/include/asyncpp/io/detail/io_engine.h +++ b/include/asyncpp/io/detail/io_engine.h @@ -84,6 +84,7 @@ namespace asyncpp::io::detail { virtual void socket_multicast_set_send_interface(socket_handle_t socket, address iface) = 0; virtual void socket_multicast_set_ttl(socket_handle_t socket, size_t ttl) = 0; virtual void socket_multicast_set_loopback(socket_handle_t socket, bool enabled) = 0; + virtual void socket_allow_reuse_address(socket_handle_t socket, bool enabled) = 0; virtual void socket_shutdown(socket_handle_t socket, bool receive, bool send) = 0; virtual bool enqueue_connect(socket_handle_t socket, endpoint ep, completion_data* cd) = 0; virtual bool enqueue_accept(socket_handle_t socket, completion_data* cd) = 0; diff --git a/include/asyncpp/io/socket.h b/include/asyncpp/io/socket.h index 8115a88..7123fea 100644 --- a/include/asyncpp/io/socket.h +++ b/include/asyncpp/io/socket.h @@ -105,6 +105,8 @@ namespace asyncpp::io { void multicast_set_ttl(size_t ttl); void multicast_set_loopback(bool enabled); + void allow_reuse_address(bool enabled); + [[nodiscard]] detail::io_engine::socket_handle_t native_handle() const noexcept { return m_fd; } [[nodiscard]] detail::io_engine::socket_handle_t release() noexcept { if (m_io != nullptr && m_fd != detail::io_engine::invalid_socket_handle) diff --git a/src/io_engine_generic_unix.cpp b/src/io_engine_generic_unix.cpp index b18bbe4..987c17b 100644 --- a/src/io_engine_generic_unix.cpp +++ b/src/io_engine_generic_unix.cpp @@ -234,6 +234,12 @@ namespace asyncpp::io::detail { } } + void io_engine_generic_unix::socket_allow_reuse_address(socket_handle_t socket, bool enabled) { + int val = enabled ? 1 : 0; + auto res = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&val), sizeof(val)); + if (res < 0) throw std::system_error(errno, std::system_category(), "setsockopt failed"); + } + void io_engine_generic_unix::socket_shutdown(socket_handle_t socket, bool receive, bool send) { int mode = 0; if (receive && send) diff --git a/src/io_engine_generic_unix.h b/src/io_engine_generic_unix.h index cadbcaf..c755245 100644 --- a/src/io_engine_generic_unix.h +++ b/src/io_engine_generic_unix.h @@ -19,6 +19,7 @@ namespace asyncpp::io::detail { void socket_multicast_set_send_interface(socket_handle_t socket, address iface) override; void socket_multicast_set_ttl(socket_handle_t socket, size_t ttl) override; void socket_multicast_set_loopback(socket_handle_t socket, bool enabled) override; + void socket_allow_reuse_address(socket_handle_t socket, bool enabled) override; void socket_shutdown(socket_handle_t socket, bool receive, bool send) override; file_handle_t file_open(const char* filename, std::ios_base::openmode mode) override; diff --git a/src/io_engine_iocp.cpp b/src/io_engine_iocp.cpp index d84e5a7..41778c4 100644 --- a/src/io_engine_iocp.cpp +++ b/src/io_engine_iocp.cpp @@ -89,6 +89,7 @@ namespace asyncpp::io::detail { void socket_multicast_set_send_interface(socket_handle_t socket, address iface) override; void socket_multicast_set_ttl(socket_handle_t socket, size_t ttl) override; void socket_multicast_set_loopback(socket_handle_t socket, bool enabled) override; + void socket_allow_reuse_address(socket_handle_t socket, bool enabled) override; void socket_shutdown(socket_handle_t socket, bool receive, bool send) override; bool enqueue_connect(socket_handle_t socket, endpoint ep, completion_data* cd) override; bool enqueue_accept(socket_handle_t socket, completion_data* cd) override; @@ -452,6 +453,12 @@ namespace asyncpp::io::detail { } } + void io_engine_iocp::socket_allow_reuse_address(socket_handle_t socket, bool enabled) { + int val = enabled ? 1 : 0; + auto res = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&val), sizeof(val)); + if (res < 0) throw std::system_error(WSAGetLastError(), std::system_category(), "setsockopt failed"); + } + void io_engine_iocp::socket_shutdown(socket_handle_t socket, bool receive, bool send) { int mode = 0; if (receive && send) diff --git a/src/socket.cpp b/src/socket.cpp index 184b7a7..f3cbfec 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -147,6 +147,11 @@ namespace asyncpp::io { m_io->engine()->socket_multicast_set_loopback(m_fd, enabled); } + void socket::allow_reuse_address(bool enabled) { + if (m_fd == detail::io_engine::invalid_socket_handle) throw std::logic_error("invalid socket"); + m_io->engine()->socket_allow_reuse_address(m_fd, enabled); + } + void socket::close_send() { if (m_fd == detail::io_engine::invalid_socket_handle) throw std::logic_error("invalid socket"); m_io->engine()->socket_shutdown(m_fd, false, true);