From 7e4dd3e49d4c9fe3f966d76005bafaf0a2b575e1 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 19 Apr 2024 17:50:52 +0200 Subject: [PATCH] socket: add sys_object alike wrapper for sockets Unlike Posix, Windows handles HANDLE (file, pipe) and SOCKET descriptors differently. It uses different close(), different errno... So sys_object was not usable for socket without templating operations to a traits class. Signed-off-by: Simon Rozman --- include/stdex/socket.hpp | 32 +++++++++++++ include/stdex/system.hpp | 99 +++++++++++++++++++++++----------------- 2 files changed, 88 insertions(+), 43 deletions(-) diff --git a/include/stdex/socket.hpp b/include/stdex/socket.hpp index da70cc45a..abfc1bfed 100644 --- a/include/stdex/socket.hpp +++ b/include/stdex/socket.hpp @@ -6,6 +6,7 @@ #pragma once #include "compat.hpp" +#include "system.hpp" #if defined(_WIN32) #include "windows.h" #include @@ -25,4 +26,35 @@ namespace stdex constexpr socket_t invalid_socket = ((socket_t)-1); inline int closesocket(_In_ socket_t socket) { return ::close(socket); } #endif + + /// + /// Socket operations + /// + struct socket_traits + { + static inline const socket_t invalid_handle = stdex::invalid_socket; + + /// + /// Closes socket + /// + static void close(_In_ socket_t h) + { + int result = closesocket(h); +#ifdef _WIN32 + int werrno = WSAGetLastError(); + if (result >= 0 || werrno == WSAENOTSOCK) + return; + throw std::system_error(werrno, std::system_category(), "closesocket failed"); +#else + if (result >= 0 || errno == EBADF) + return; + throw std::system_error(errno, std::system_category(), "closesocket failed"); +#endif + } + }; + + /// + /// Socket + /// + using socket = basic_sys_object; } diff --git a/include/stdex/system.hpp b/include/stdex/system.hpp index 763bb5245..59a463377 100644 --- a/include/stdex/system.hpp +++ b/include/stdex/system.hpp @@ -93,45 +93,46 @@ namespace stdex using sregex = std::basic_regex; /// - /// Operating system object (file, pipe, anything with an OS handle etc.) + /// Operating system object base class /// - class sys_object + template + class basic_sys_object { public: - sys_object(_In_opt_ sys_handle h = invalid_handle) : m_h(h) {} + basic_sys_object(_In_opt_ T h = TR::invalid_handle) : m_h(h) {} - sys_object(_In_ const sys_object& other) : m_h(other.m_h != invalid_handle ? duplicate(other.m_h) : invalid_handle) {} + basic_sys_object(_In_ const basic_sys_object& other) : m_h(other.m_h != TR::invalid_handle ? TR::duplicate(other.m_h) : TR::invalid_handle) {} - sys_object& operator =(_In_ const sys_object& other) + basic_sys_object& operator =(_In_ const basic_sys_object& other) { if (this != std::addressof(other)) { - if (m_h != invalid_handle) - close(m_h); - m_h = other.m_h != invalid_handle ? duplicate(other.m_h) : invalid_handle; + if (m_h != TR::invalid_handle) + TR::close(m_h); + m_h = other.m_h != TR::invalid_handle ? TR::duplicate(other.m_h) : TR::invalid_handle; } return *this; } - sys_object(_Inout_ sys_object&& other) noexcept : m_h(other.m_h) + basic_sys_object(_Inout_ basic_sys_object&& other) noexcept : m_h(other.m_h) { - other.m_h = invalid_handle; + other.m_h = TR::invalid_handle; } - sys_object& operator =(_Inout_ sys_object&& other) noexcept + basic_sys_object& operator =(_Inout_ basic_sys_object&& other) noexcept { if (this != std::addressof(other)) { - if (m_h != invalid_handle) - close(m_h); + if (m_h != TR::invalid_handle) + TR::close(m_h); m_h = other.m_h; - other.m_h = invalid_handle; + other.m_h = TR::invalid_handle; } return *this; } - virtual ~sys_object() noexcept(false) + virtual ~basic_sys_object() noexcept(false) { - if (m_h != invalid_handle) - close(m_h); + if (m_h != TR::invalid_handle) + TR::close(m_h); } /// @@ -139,21 +140,48 @@ namespace stdex /// virtual void close() { - if (m_h != invalid_handle) { - close(m_h); - m_h = invalid_handle; + if (m_h != TR::invalid_handle) { + TR::close(m_h); + m_h = TR::invalid_handle; } } /// /// Returns true if object has a valid handle /// - operator bool() const noexcept { return m_h != invalid_handle; } + operator bool() const noexcept { return m_h != TR::invalid_handle; } /// /// Returns object handle /// - sys_handle get() const noexcept { return m_h; } + T get() const noexcept { return m_h; } + + protected: + T m_h; + }; + + /// + /// System object operations + /// + struct sys_object_traits + { + static inline const sys_handle invalid_handle = stdex::invalid_handle; + + /// + /// Closes object + /// + static void close(_In_ sys_handle h) + { +#if defined(_WIN32) + if (CloseHandle(h) || GetLastError() == ERROR_INVALID_HANDLE) + return; + throw std::system_error(GetLastError(), std::system_category(), "CloseHandle failed"); +#else + if (::close(h) >= 0 || errno == EBADF) + return; + throw std::system_error(errno, std::system_category(), "close failed"); +#endif + } /// /// Duplicates given object @@ -161,7 +189,7 @@ namespace stdex static sys_handle duplicate(_In_ sys_handle h, _In_ bool inherit = false) { sys_handle h_new; -#ifdef _WIN32 +#if defined(_WIN32) HANDLE process = GetCurrentProcess(); if (DuplicateHandle(process, h, process, &h_new, 0, inherit, DUPLICATE_SAME_ACCESS)) return h_new; @@ -173,28 +201,13 @@ namespace stdex throw std::system_error(errno, std::system_category(), "dup failed"); #endif } - - protected: - /// - /// Closes object - /// - static void close(_In_ sys_handle h) - { -#ifdef _WIN32 - if (CloseHandle(h) || GetLastError() == ERROR_INVALID_HANDLE) - return; - throw std::system_error(GetLastError(), std::system_category(), "CloseHandle failed"); -#else - if (::close(h) >= 0 || errno == EBADF) - return; - throw std::system_error(errno, std::system_category(), "close failed"); -#endif - } - - protected: - sys_handle m_h; }; + /// + /// Operating system object (file, pipe, anything with an OS handle etc.) + /// + using sys_object = basic_sys_object; + #ifdef _WIN32 template class safearray_accessor