net/SocketDescriptor: decouple from FileDescriptor on Windows

On Windows, a socket is not a file descriptor; it is a different beast
(and anyway, Windows doesn't have file descriptors).
This commit is contained in:
Max Kellermann 2023-03-29 09:52:37 +02:00
parent 7a5f485cf8
commit 53ec02d5e9
3 changed files with 67 additions and 12 deletions

View File

@ -8,7 +8,6 @@
#include "IPv6Address.hxx" #include "IPv6Address.hxx"
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else #else
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -5,9 +5,17 @@
#define SOCKET_DESCRIPTOR_HXX #define SOCKET_DESCRIPTOR_HXX
#include "Features.hxx" #include "Features.hxx"
#ifndef _WIN32
#include "io/FileDescriptor.hxx" #include "io/FileDescriptor.hxx"
#endif
#include <type_traits> #include <type_traits>
#include <utility>
#ifdef _WIN32
#include <winsock2.h> // for SOCKET, INVALID_SOCKET
#endif
class SocketAddress; class SocketAddress;
class StaticSocketAddress; class StaticSocketAddress;
@ -15,24 +23,44 @@ class IPv4Address;
class IPv6Address; class IPv6Address;
/** /**
* An OO wrapper for a UNIX socket descriptor. * An OO wrapper for a Berkeley or WinSock socket descriptor.
*/ */
class SocketDescriptor : protected FileDescriptor { class SocketDescriptor
#ifndef _WIN32
/* Berkeley sockets are represented as file descriptors */
: protected FileDescriptor
#endif
{
protected: protected:
#ifdef _WIN32
/* WinSock sockets are not file descriptors, they are a
special type */
SOCKET fd;
#else // !_WIN32
explicit constexpr SocketDescriptor(FileDescriptor _fd) noexcept explicit constexpr SocketDescriptor(FileDescriptor _fd) noexcept
:FileDescriptor(_fd) {} :FileDescriptor(_fd) {}
#endif // !_WIN32
public: public:
SocketDescriptor() = default; SocketDescriptor() = default;
#ifdef _WIN32
explicit constexpr SocketDescriptor(SOCKET _fd) noexcept
:fd(_fd) {}
#else // !_WIN32
explicit constexpr SocketDescriptor(int _fd) noexcept explicit constexpr SocketDescriptor(int _fd) noexcept
:FileDescriptor(_fd) {} :FileDescriptor(_fd) {}
#endif // !_WIN32
constexpr bool operator==(SocketDescriptor other) const noexcept { constexpr bool operator==(SocketDescriptor other) const noexcept {
return fd == other.fd; return fd == other.fd;
} }
#ifndef _WIN32 #ifdef _WIN32
constexpr bool IsDefined() const noexcept {
return fd != INVALID_SOCKET;
}
#else // !_WIN32
/** /**
* Convert a #FileDescriptor to a #SocketDescriptor. This is only * Convert a #FileDescriptor to a #SocketDescriptor. This is only
* possible on operating systems where socket descriptors are the * possible on operating systems where socket descriptors are the
@ -52,13 +80,11 @@ public:
constexpr const FileDescriptor &ToFileDescriptor() const noexcept { constexpr const FileDescriptor &ToFileDescriptor() const noexcept {
return *this; return *this;
} }
#endif
using FileDescriptor::IsDefined; using FileDescriptor::IsDefined;
#ifndef _WIN32
using FileDescriptor::IsValid; using FileDescriptor::IsValid;
using FileDescriptor::IsSocket; using FileDescriptor::IsSocket;
#endif #endif // !_WIN32
/** /**
* Determine the socket type, i.e. SOCK_STREAM, SOCK_DGRAM or * Determine the socket type, i.e. SOCK_STREAM, SOCK_DGRAM or
@ -73,25 +99,48 @@ public:
[[gnu::pure]] [[gnu::pure]]
bool IsStream() const noexcept; bool IsStream() const noexcept;
static constexpr SocketDescriptor Undefined() noexcept {
#ifdef _WIN32
return SocketDescriptor{INVALID_SOCKET};
#else // !_WIN32
return SocketDescriptor(FileDescriptor::Undefined());
#endif // !_WIN32
}
#ifndef _WIN32
using FileDescriptor::Get; using FileDescriptor::Get;
using FileDescriptor::Set; using FileDescriptor::Set;
using FileDescriptor::Steal; using FileDescriptor::Steal;
using FileDescriptor::SetUndefined; using FileDescriptor::SetUndefined;
static constexpr SocketDescriptor Undefined() noexcept {
return SocketDescriptor(FileDescriptor::Undefined());
}
using FileDescriptor::EnableCloseOnExec; using FileDescriptor::EnableCloseOnExec;
using FileDescriptor::DisableCloseOnExec; using FileDescriptor::DisableCloseOnExec;
#ifndef _WIN32
using FileDescriptor::SetNonBlocking; using FileDescriptor::SetNonBlocking;
using FileDescriptor::SetBlocking; using FileDescriptor::SetBlocking;
using FileDescriptor::Duplicate; using FileDescriptor::Duplicate;
using FileDescriptor::CheckDuplicate; using FileDescriptor::CheckDuplicate;
using FileDescriptor::Close; using FileDescriptor::Close;
#else #else
constexpr SOCKET Get() const noexcept {
return fd;
}
constexpr void Set(SOCKET _fd) noexcept {
fd = _fd;
}
constexpr void SetUndefined() noexcept {
fd = INVALID_SOCKET;
}
constexpr SOCKET Steal() noexcept {
return std::exchange(fd, INVALID_SOCKET);
}
void EnableCloseOnExec() const noexcept {}
void DisableCloseOnExec() const noexcept {}
bool SetNonBlocking() const noexcept; bool SetNonBlocking() const noexcept;
/** /**

View File

@ -20,13 +20,20 @@ public:
explicit UniqueSocketDescriptor(SocketDescriptor _fd) noexcept explicit UniqueSocketDescriptor(SocketDescriptor _fd) noexcept
:SocketDescriptor(_fd) {} :SocketDescriptor(_fd) {}
#ifndef _WIN32
explicit UniqueSocketDescriptor(FileDescriptor _fd) noexcept explicit UniqueSocketDescriptor(FileDescriptor _fd) noexcept
:SocketDescriptor(_fd) {} :SocketDescriptor(_fd) {}
#endif // !_WIN32
explicit UniqueSocketDescriptor(int _fd) noexcept explicit UniqueSocketDescriptor(int _fd) noexcept
:SocketDescriptor(_fd) {} :SocketDescriptor(_fd) {}
#ifdef _WIN32
UniqueSocketDescriptor(UniqueSocketDescriptor &&other) noexcept
:SocketDescriptor(std::exchange(other.fd, INVALID_SOCKET)) {}
#else // !_WIN32
UniqueSocketDescriptor(UniqueSocketDescriptor &&other) noexcept UniqueSocketDescriptor(UniqueSocketDescriptor &&other) noexcept
:SocketDescriptor(std::exchange(other.fd, -1)) {} :SocketDescriptor(std::exchange(other.fd, -1)) {}
#endif // !_WIN32
~UniqueSocketDescriptor() noexcept { ~UniqueSocketDescriptor() noexcept {
if (IsDefined()) if (IsDefined())