diff --git a/src/cli/socket_utils.h b/src/cli/socket_utils.h deleted file mode 100644 index 76a07de60e1..00000000000 --- a/src/cli/socket_utils.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -* (C) 2014,2017 Jack Lloyd -* 2017 René Korthaus, Rohde & Schwarz Cybersecurity -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_CLI_SOCKET_UTILS_H_ -#define BOTAN_CLI_SOCKET_UTILS_H_ - -#include "cli_exceptions.h" -#include -#include -#include - -#if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) - - #include - #include - -typedef SOCKET socket_type; - -inline socket_type invalid_socket() { - return INVALID_SOCKET; -} - -typedef size_t ssize_t; -typedef int sendrecv_len_type; - -inline void close_socket(socket_type s) { - ::closesocket(s); -} - - #define STDIN_FILENO _fileno(stdin) - -inline void init_sockets() { - WSAData wsa_data; - WORD wsa_version = MAKEWORD(2, 2); - - if(::WSAStartup(wsa_version, &wsa_data) != 0) { - throw Botan_CLI::CLI_Error("WSAStartup() failed: " + std::to_string(WSAGetLastError())); - } - - if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { - ::WSACleanup(); - throw Botan_CLI::CLI_Error("Could not find a usable version of Winsock.dll"); - } -} - -inline void stop_sockets() { - ::WSACleanup(); -} - -inline std::string err_to_string(int e) { - // TODO use strerror_s here - return "Error code " + std::to_string(e); -} - -inline int close(int fd) { - return ::closesocket(fd); -} - -inline int read(int s, void* buf, size_t len) { - return ::recv(s, reinterpret_cast(buf), static_cast(len), 0); -} - -inline int send(int s, const uint8_t* buf, size_t len, int flags) { - return ::send(s, reinterpret_cast(buf), static_cast(len), flags); -} - -#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) - - #include - #include - #include - #include - #include - #include - #include - #include - #include - -typedef int socket_type; -typedef size_t sendrecv_len_type; - -inline socket_type invalid_socket() { - return -1; -} - -inline void close_socket(socket_type s) { - ::close(s); -} - -inline void init_sockets() {} - -inline void stop_sockets() {} - -inline std::string err_to_string(int e) { - return std::strerror(e); -} - -#endif - -#if !defined(MSG_NOSIGNAL) - #define MSG_NOSIGNAL 0 -#endif - -#endif diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index 81a3ad624e5..61c2bc8a315 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -4,6 +4,7 @@ * 2017 René Korthaus, Rohde & Schwarz Cybersecurity * 2022 René Meusel, Hannes Rantzsch - neXenio GmbH * 2023 René Meusel, Rohde & Schwarz Cybersecurity +* 2025 Kagan Can Sit * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -31,8 +32,9 @@ #include #include - #include "socket_utils.h" #include "tls_helpers.h" + #include + #include namespace Botan_CLI { @@ -181,10 +183,10 @@ class TLS_Client final : public Command { "--tls-version=default --session-db= --session-db-pass= " "--next-protocols= --type=tcp --client-cert= --client-cert-key= " "--psk= --psk-identity= --psk-prf=SHA-256 --debug") { - init_sockets(); + Botan::OS::Socket_Platform::socket_init(); } - ~TLS_Client() override { stop_sockets(); } + ~TLS_Client() override { Botan::OS::Socket_Platform::socket_fini(); } TLS_Client(const TLS_Client& other) = delete; TLS_Client(TLS_Client&& other) = delete; @@ -313,7 +315,8 @@ class TLS_Client final : public Command { output() << "EOF on socket\n"; break; } else if(got == -1) { - output() << "Socket error: " << errno << " " << err_to_string(errno) << "\n"; + output() << "Socket error: " << errno << " " << Botan::OS::Socket_Platform::get_last_socket_error() + << "\n"; continue; } @@ -334,7 +337,8 @@ class TLS_Client final : public Command { we_closed = true; break; } else if(got == -1) { - output() << "Stdin error: " << errno << " " << err_to_string(errno) << "\n"; + output() << "Stdin error: " << errno << " " << Botan::OS::Socket_Platform::get_last_socket_error() + << "\n"; continue; } @@ -377,7 +381,8 @@ class TLS_Client final : public Command { if(errno == EINTR) { sent = 0; } else { - throw CLI_Error("Socket write failed errno=" + std::to_string(errno)); + throw CLI_Error("Socket write failed errno=" + std::to_string(errno) + " - " + + Botan::OS::Socket_Platform::get_last_socket_error()); } } @@ -386,24 +391,26 @@ class TLS_Client final : public Command { } private: + using socket_type = Botan::OS::Socket_Platform::socket_type; + using socket_op_ret_type = Botan::OS::Socket_Platform::socket_op_ret_type; + using socklen_type = Botan::OS::Socket_Platform::socklen_type; + using sendrecv_len_type = Botan::OS::Socket_Platform::sendrecv_len_type; + static socket_type connect_to_host(const std::string& host, uint16_t port, bool tcp) { addrinfo hints{}; std::memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM; - addrinfo* res = nullptr; - if(::getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res) != 0) { + Botan::OS::Socket_Platform::unique_addrinfo_ptr res = nullptr; + if(::getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, Botan::out_ptr(res)) != 0) { throw CLI_Error("getaddrinfo failed for " + host); } - socket_type fd = 0; - bool success = false; - - for(addrinfo* rp = res; rp != nullptr; rp = rp->ai_next) { - fd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + for(addrinfo* rp = res.get(); rp != nullptr; rp = rp->ai_next) { + socket_type fd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if(fd == invalid_socket()) { + if(fd == Botan::OS::Socket_Platform::invalid_socket()) { continue; } @@ -411,30 +418,20 @@ class TLS_Client final : public Command { ::close(fd); continue; } - - success = true; - break; + return fd; } - ::freeaddrinfo(res); - - if(!success) { - // no address succeeded - throw CLI_Error("Connecting to host failed"); - } - - return fd; + throw CLI_Error("Connect failed"); } static void dgram_socket_write(int sockfd, const uint8_t buf[], size_t length) { auto r = ::send(sockfd, buf, length, MSG_NOSIGNAL); - if(r == -1) { - throw CLI_Error("Socket write failed errno=" + std::to_string(errno)); + throw CLI_Error("Socket write failed errno=" + Botan::OS::Socket_Platform::get_last_socket_error()); } } - socket_type m_sockfd = invalid_socket(); + socket_type m_sockfd = Botan::OS::Socket_Platform::invalid_socket(); }; namespace { diff --git a/src/cli/tls_server.cpp b/src/cli/tls_server.cpp index 25f04cea70b..c1b4d907e29 100644 --- a/src/cli/tls_server.cpp +++ b/src/cli/tls_server.cpp @@ -3,6 +3,7 @@ * (C) 2014 Jack Lloyd * 2017 René Korthaus, Rohde & Schwarz Cybersecurity * 2023 René Meusel, Rohde & Schwarz Cybersecurity + 2025 Kagan Can Sit * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -40,8 +41,8 @@ #include #include - #include "socket_utils.h" #include "tls_helpers.h" + #include namespace Botan_CLI { @@ -122,10 +123,10 @@ class TLS_Server final : public Command { "tls_server cert-or-pubkey key --port=443 --psk= --psk-identity= --psk-prf=SHA-256 --type=tcp --policy=default --dump-traces= --max-clients=0") #endif { - init_sockets(); + Botan::OS::Socket_Platform::socket_init(); } - ~TLS_Server() override { stop_sockets(); } + ~TLS_Server() override { Botan::OS::Socket_Platform::socket_fini(); } TLS_Server(const TLS_Server& other) = delete; TLS_Server(TLS_Server&& other) = delete; @@ -239,7 +240,8 @@ class TLS_Server final : public Command { ssize_t got = ::recv(m_socket, Botan::cast_uint8_ptr_to_char(buf), sizeof(buf), 0); if(got == -1) { - error_output() << "Error in socket read - " << err_to_string(errno) << std::endl; + error_output() << "Error in socket read - " + << Botan::OS::Socket_Platform::get_last_socket_error() << std::endl; break; } @@ -266,8 +268,8 @@ class TLS_Server final : public Command { } catch(std::exception& e) { error_output() << "Connection problem: " << e.what() << std::endl; if(m_is_tcp) { - close_socket(m_socket); - m_socket = invalid_socket(); + Botan::OS::Socket_Platform::close_socket(m_socket); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); } } } @@ -276,12 +278,12 @@ class TLS_Server final : public Command { } if(m_is_tcp) { - close_socket(m_socket); - m_socket = invalid_socket(); + Botan::OS::Socket_Platform::close_socket(m_socket); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); } } - close_socket(server_fd); + Botan::OS::Socket_Platform::close_socket(server_fd); } public: @@ -293,7 +295,8 @@ class TLS_Server final : public Command { ssize_t sent = ::send(m_socket, buf.data(), static_cast(buf.size()), MSG_NOSIGNAL); if(sent == -1) { - error_output() << "Error writing to socket - " << err_to_string(errno) << std::endl; + error_output() << "Error writing to socket - " << Botan::OS::Socket_Platform::get_last_socket_error() + << std::endl; } else if(sent >= 0 && static_cast(sent) != buf.size()) { error_output() << "Packet of length " << buf.size() << " truncated to " << sent << std::endl; } @@ -317,11 +320,16 @@ class TLS_Server final : public Command { void push_pending_output(std::string line) { m_pending_output.emplace_back(std::move(line)); } private: + using socket_type = Botan::OS::Socket_Platform::socket_type; + using socket_op_ret_type = Botan::OS::Socket_Platform::socket_op_ret_type; + using socklen_type = Botan::OS::Socket_Platform::socklen_type; + using sendrecv_len_type = Botan::OS::Socket_Platform::sendrecv_len_type; + socket_type make_server_socket(uint16_t port) { const int type = m_is_tcp ? SOCK_STREAM : SOCK_DGRAM; socket_type fd = ::socket(PF_INET, type, 0); - if(fd == invalid_socket()) { + if(fd == Botan::OS::Socket_Platform::invalid_socket()) { throw CLI_Error("Unable to acquire socket"); } @@ -334,14 +342,14 @@ class TLS_Server final : public Command { socket_info.sin_addr.s_addr = INADDR_ANY; if(::bind(fd, reinterpret_cast(&socket_info), sizeof(struct sockaddr)) != 0) { - close_socket(fd); + Botan::OS::Socket_Platform::close_socket(fd); throw CLI_Error("server bind failed"); } if(m_is_tcp) { constexpr int backlog = std::min(100, SOMAXCONN); if(::listen(fd, backlog) != 0) { - close_socket(fd); + Botan::OS::Socket_Platform::close_socket(fd); throw CLI_Error("listen failed"); } } @@ -360,7 +368,7 @@ class TLS_Server final : public Command { return fd; } - socket_type m_socket = invalid_socket(); + socket_type m_socket = Botan::OS::Socket_Platform::invalid_socket(); bool m_is_tcp = false; uint32_t m_socket_id = 0; std::list m_pending_output; diff --git a/src/lib/utils/socket/info.txt b/src/lib/utils/socket/info.txt index 29da2b27fe5..d0e6c08d8cd 100644 --- a/src/lib/utils/socket/info.txt +++ b/src/lib/utils/socket/info.txt @@ -10,6 +10,7 @@ name -> "Socket" uri.h socket.h socket_udp.h +socket_platform.h diff --git a/src/lib/utils/socket/socket.cpp b/src/lib/utils/socket/socket.cpp index ab65c35b633..d441b051457 100644 --- a/src/lib/utils/socket/socket.cpp +++ b/src/lib/utils/socket/socket.cpp @@ -1,6 +1,7 @@ /* * (C) 2015,2016,2017 Jack Lloyd * (C) 2016 Daniel Neus +* 2025 Kagan Can Sit * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -10,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -22,27 +25,12 @@ #define BOOST_ASIO_DISABLE_SERIAL_PORT #include #include - -#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) - #include - #include - #include - #include - #include - #include - #include - #include - -#elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) - #include #endif namespace Botan { - namespace { #if defined(BOTAN_HAS_BOOST_ASIO) - class Asio_Socket final : public OS::Socket { public: Asio_Socket(std::string_view hostname, std::string_view service, std::chrono::milliseconds timeout) : @@ -137,105 +125,45 @@ class Asio_Socket final : public OS::Socket { #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) class BSD_Socket final : public OS::Socket { - private: - #if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) - typedef SOCKET socket_type; - typedef int socket_op_ret_type; - typedef int socklen_type; - typedef int sendrecv_len_type; - - static socket_type invalid_socket() { return INVALID_SOCKET; } - - static void close_socket(socket_type s) { ::closesocket(s); } - - static std::string get_last_socket_error() { return std::to_string(::WSAGetLastError()); } - - static bool nonblocking_connect_in_progress() { return (::WSAGetLastError() == WSAEWOULDBLOCK); } - - static void set_nonblocking(socket_type s) { - u_long nonblocking = 1; - ::ioctlsocket(s, FIONBIO, &nonblocking); - } - - static void socket_init() { - WSAData wsa_data; - WORD wsa_version = MAKEWORD(2, 2); - - if(::WSAStartup(wsa_version, &wsa_data) != 0) { - throw System_Error("WSAStartup() failed", WSAGetLastError()); - } - - if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { - ::WSACleanup(); - throw System_Error("Could not find a usable version of Winsock.dll"); - } - } - - static void socket_fini() { ::WSACleanup(); } - #else - typedef int socket_type; - typedef ssize_t socket_op_ret_type; - typedef socklen_t socklen_type; - typedef size_t sendrecv_len_type; - - static socket_type invalid_socket() { return -1; } - - static void close_socket(socket_type s) { ::close(s); } - - static std::string get_last_socket_error() { return ::strerror(errno); } - - static bool nonblocking_connect_in_progress() { return (errno == EINPROGRESS); } - - static void set_nonblocking(socket_type s) { - // NOLINTNEXTLINE(*-vararg) - if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) { - throw System_Error("Setting socket to non-blocking state failed", errno); - } - } - - static void socket_init() {} - - static void socket_fini() {} - #endif - public: BSD_Socket(std::string_view hostname, std::string_view service, std::chrono::microseconds timeout) : - m_timeout(timeout), m_socket(invalid_socket()) { - socket_init(); + m_timeout(timeout) { + Botan::OS::Socket_Platform::socket_init(); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); addrinfo hints{}; + Botan::clear_mem(&hints, 1); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - addrinfo* res = nullptr; - - const std::string hostname_str(hostname); - const std::string service_str(service); - int rc = ::getaddrinfo(hostname_str.c_str(), service_str.c_str(), &hints, &res); + Botan::OS::Socket_Platform::unique_addrinfo_ptr res = nullptr; + int rc = + ::getaddrinfo(std::string(hostname).c_str(), std::string(service).c_str(), &hints, Botan::out_ptr(res)); if(rc != 0) { throw System_Error(fmt("Name resolution failed for {}", hostname), rc); } - for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) { + for(addrinfo* rp = res.get(); (m_socket == Botan::OS::Socket_Platform::invalid_socket()) && rp != nullptr; + rp = rp->ai_next) { if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) { continue; } m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if(m_socket == invalid_socket()) { + if(m_socket == Botan::OS::Socket_Platform::invalid_socket()) { // unsupported socket type? continue; } - set_nonblocking(m_socket); + Botan::OS::Socket_Platform::set_nonblocking(m_socket); int err = ::connect(m_socket, rp->ai_addr, static_cast(rp->ai_addrlen)); if(err == -1) { int active = 0; - if(nonblocking_connect_in_progress()) { + if(Botan::OS::Socket_Platform::nonblocking_connect_in_progress()) { struct timeval timeout_tv = make_timeout_tv(); fd_set write_set; FD_ZERO(&write_set); @@ -259,25 +187,23 @@ class BSD_Socket final : public OS::Socket { } if(active == 0) { - close_socket(m_socket); - m_socket = invalid_socket(); + Botan::OS::Socket_Platform::close_socket(m_socket); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); continue; } } } - ::freeaddrinfo(res); - - if(m_socket == invalid_socket()) { - throw System_Error(fmt("Connecting to {} for service {} failed with errno {}", hostname, service, errno), + if(m_socket == Botan::OS::Socket_Platform::invalid_socket()) { + throw System_Error(fmt("Connection to {} for service {} failed with errno", hostname, service, errno), errno); } } ~BSD_Socket() override { - close_socket(m_socket); - m_socket = invalid_socket(); - socket_fini(); + Botan::OS::Socket_Platform::close_socket(m_socket); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); + Botan::OS::Socket_Platform::socket_fini(); } BSD_Socket(const BSD_Socket& other) = delete; @@ -325,7 +251,6 @@ class BSD_Socket final : public OS::Socket { } socket_op_ret_type got = ::recv(m_socket, cast_uint8_ptr_to_char(buf), static_cast(len), 0); - if(got < 0) { throw System_Error("Socket read failed", errno); } @@ -334,6 +259,15 @@ class BSD_Socket final : public OS::Socket { } private: + // Import socket operation types from Socket_Platform namespace + using socket_type = Botan::OS::Socket_Platform::socket_type; + using socket_op_ret_type = Botan::OS::Socket_Platform::socket_op_ret_type; + using socklen_type = Botan::OS::Socket_Platform::socklen_type; + using sendrecv_len_type = Botan::OS::Socket_Platform::sendrecv_len_type; + + const std::chrono::microseconds m_timeout; + socket_type m_socket; + struct timeval make_timeout_tv() const { struct timeval tv {}; @@ -341,9 +275,6 @@ class BSD_Socket final : public OS::Socket { tv.tv_usec = static_cast(m_timeout.count() % 1000000); return tv; } - - const std::chrono::microseconds m_timeout; - socket_type m_socket; }; #endif diff --git a/src/lib/utils/socket/socket_platform.h b/src/lib/utils/socket/socket_platform.h new file mode 100644 index 00000000000..1075e291d26 --- /dev/null +++ b/src/lib/utils/socket/socket_platform.h @@ -0,0 +1,132 @@ +/* +* Socket Platform +* (C) 2015,2016,2017 Jack Lloyd +* 2016 Daniel Neus +* 2025 Kagan Can Sit +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SOCKET_PLATFORM_H_ +#define BOTAN_SOCKET_PLATFORM_H_ + +#include +#include +#include +#include +#include +#include + +// Platform specific includes +#if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + #include + #include +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace Botan::OS::Socket_Platform { + +#if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + +using socket_type = SOCKET; +using socket_op_ret_type = int; +using socklen_type = int; +using sendrecv_len_type = int; + +[[nodiscard]] inline socket_type invalid_socket() noexcept { + return INVALID_SOCKET; +} + +inline void close_socket(socket_type s) noexcept { + if(s != invalid_socket()) { + ::closesocket(s); + } +} + +[[nodiscard]] inline bool nonblocking_connect_in_progress() noexcept { + return (::WSAGetLastError() == WSAEWOULDBLOCK); +} + +inline void set_nonblocking(socket_type s) { + u_long nonblocking = 1; + if(::ioctlsocket(s, FIONBIO, &nonblocking) != 0) { + throw System_Error("Setting socket to non-blocking state failed", ::WSAGetLastError()); + } +} + +inline void socket_init() { + WSAData wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + + if(::WSAStartup(wsa_version, &wsa_data) != 0) { + throw System_Error("WSAStartup() failed", WSAGetLastError()); + } + + if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { + ::WSACleanup(); + throw System_Error("Could not find a usable version of Winsock.dll"); + } +} + +inline void socket_fini() noexcept { + ::WSACleanup(); +} + +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) + +using socket_type = int; +using socket_op_ret_type = ssize_t; +using socklen_type = socklen_t; +using sendrecv_len_type = size_t; + +// Platform-specific implementations +[[nodiscard]] inline socket_type invalid_socket() noexcept { + return -1; +} + +inline void close_socket(socket_type s) noexcept { + if(s != invalid_socket()) { + ::close(s); + } +} + +[[nodiscard]] inline bool nonblocking_connect_in_progress() noexcept { + return (errno == EINPROGRESS); +} + +inline void set_nonblocking(socket_type s) { + // NOLINTNEXTLINE(*-vararg) + if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) { + throw System_Error("Setting socket to non-blocking state failed", errno); + } +} + +// Posix does not require initialization +inline void socket_init() {} + +inline void socket_fini() noexcept {} +#endif + +#if defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) +using unique_addrinfo_ptr = std::unique_ptr; +#endif + +// Platform-independent functions +[[nodiscard]] inline std::string get_last_socket_error() { + std::error_code ec(errno, std::generic_category()); + return ec.message(); +} +} // namespace Botan::OS::Socket_Platform +#endif // BOTAN_SOCKET_PLATFORM_H diff --git a/src/lib/utils/socket/socket_udp.cpp b/src/lib/utils/socket/socket_udp.cpp index 3fed2313093..061edfe9c8a 100644 --- a/src/lib/utils/socket/socket_udp.cpp +++ b/src/lib/utils/socket/socket_udp.cpp @@ -2,6 +2,7 @@ * (C) 2015,2016,2017 Jack Lloyd * (C) 2016 Daniel Neus * (C) 2019 Nuno Goncalves +* (C) 2025 Kagan Can Sit * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -11,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -24,18 +27,6 @@ #define BOOST_ASIO_DISABLE_SERIAL_PORT #include #include -#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) - #include - #include - #include - #include - #include - #include - #include - #include - -#elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) - #include #endif namespace Botan { @@ -136,52 +127,51 @@ class Asio_SocketUDP final : public OS::SocketUDP { class BSD_SocketUDP final : public OS::SocketUDP { public: BSD_SocketUDP(std::string_view hostname, std::string_view service, std::chrono::microseconds timeout) : - m_timeout(timeout), m_socket(invalid_socket()) { - socket_init(); + m_timeout(timeout) { + Botan::OS::Socket_Platform::socket_init(); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); - addrinfo* res = nullptr; addrinfo hints{}; + clear_mem(&hints, 1); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; - const std::string hostname_str(hostname); - const std::string service_str(service); - - int rc = ::getaddrinfo(hostname_str.c_str(), service_str.c_str(), &hints, &res); + Botan::OS::Socket_Platform::unique_addrinfo_ptr res = nullptr; + int rc = + ::getaddrinfo(std::string(hostname).c_str(), std::string(service).c_str(), &hints, Botan::out_ptr(res)); if(rc != 0) { throw System_Error(fmt("Name resolution failed for {}", hostname), rc); } - for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) { + for(addrinfo* rp = res.get(); (m_socket == Botan::OS::Socket_Platform::invalid_socket()) && rp != nullptr; + rp = rp->ai_next) { if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) { continue; } m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if(m_socket == invalid_socket()) [[unlikely]] { + if(m_socket == Botan::OS::Socket_Platform::invalid_socket()) [[unlikely]] { // unsupported socket type? continue; } - set_nonblocking(m_socket); - memcpy(&sa, res->ai_addr, res->ai_addrlen); - salen = static_cast(res->ai_addrlen); // NOLINT(*-redundant-casting) + Botan::OS::Socket_Platform::set_nonblocking(m_socket); + memcpy(&m_sa, res->ai_addr, res->ai_addrlen); + m_salen = static_cast(res->ai_addrlen); // NOLINT(*-redundant-casting) } - ::freeaddrinfo(res); - - if(m_socket == invalid_socket()) { + if(m_socket == Botan::OS::Socket_Platform::invalid_socket()) { throw System_Error(fmt("Connecting to {} for service {} failed with errno {}", hostname, service, errno), errno); } } ~BSD_SocketUDP() override { - close_socket(m_socket); - m_socket = invalid_socket(); - socket_fini(); + Botan::OS::Socket_Platform::close_socket(m_socket); + m_socket = Botan::OS::Socket_Platform::invalid_socket(); + Botan::OS::Socket_Platform::socket_fini(); } BSD_SocketUDP(const BSD_SocketUDP& other) = delete; @@ -208,8 +198,8 @@ class BSD_SocketUDP final : public OS::SocketUDP { cast_uint8_ptr_to_char(buf + sent_so_far), static_cast(left), 0, - reinterpret_cast(&sa), - salen); + reinterpret_cast(&m_sa), + m_salen); if(sent < 0) { throw System_Error("Socket write failed", errno); } else { @@ -225,14 +215,12 @@ class BSD_SocketUDP final : public OS::SocketUDP { struct timeval timeout = make_timeout_tv(); int active = ::select(static_cast(m_socket + 1), &read_set, nullptr, nullptr, &timeout); - if(active == 0) { throw System_Error("Timeout during socket read"); } socket_op_ret_type got = - ::recvfrom(m_socket, cast_uint8_ptr_to_char(buf), static_cast(len), 0, nullptr, nullptr); - + ::recv(m_socket, reinterpret_cast(buf), static_cast(len), 0); if(got < 0) { throw System_Error("Socket read failed", errno); } @@ -241,65 +229,14 @@ class BSD_SocketUDP final : public OS::SocketUDP { } private: - #if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) - typedef SOCKET socket_type; - typedef int socket_op_ret_type; - typedef int sendrecv_len_type; - - static socket_type invalid_socket() { return INVALID_SOCKET; } - - static void close_socket(socket_type s) { ::closesocket(s); } - - static std::string get_last_socket_error() { return std::to_string(::WSAGetLastError()); } - - static bool nonblocking_connect_in_progress() { return (::WSAGetLastError() == WSAEWOULDBLOCK); } - - static void set_nonblocking(socket_type s) { - u_long nonblocking = 1; - ::ioctlsocket(s, FIONBIO, &nonblocking); - } - - static void socket_init() { - WSAData wsa_data; - WORD wsa_version = MAKEWORD(2, 2); - - if(::WSAStartup(wsa_version, &wsa_data) != 0) { - throw System_Error("WSAStartup() failed", WSAGetLastError()); - } - - if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { - ::WSACleanup(); - throw System_Error("Could not find a usable version of Winsock.dll"); - } - } - - static void socket_fini() { ::WSACleanup(); } - #else - typedef int socket_type; - typedef ssize_t socket_op_ret_type; - typedef size_t sendrecv_len_type; - - static socket_type invalid_socket() { return -1; } - - static void close_socket(socket_type s) { ::close(s); } - - static std::string get_last_socket_error() { return ::strerror(errno); } - - static bool nonblocking_connect_in_progress() { return (errno == EINPROGRESS); } - - static void set_nonblocking(socket_type s) { - // NOLINTNEXTLINE(*-vararg) - if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) { - throw System_Error("Setting socket to non-blocking state failed", errno); - } - } - - static void socket_init() {} - - static void socket_fini() {} - #endif - sockaddr_storage sa = {}; - socklen_t salen; + // Import socket operation types from Socket_Platform namespace + using socket_type = Botan::OS::Socket_Platform::socket_type; + using socket_op_ret_type = Botan::OS::Socket_Platform::socket_op_ret_type; + using socklen_type = Botan::OS::Socket_Platform::socklen_type; + using sendrecv_len_type = Botan::OS::Socket_Platform::sendrecv_len_type; + + sockaddr_storage m_sa; + socklen_t m_salen; struct timeval make_timeout_tv() const { struct timeval tv {};