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"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>

View File

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

View File

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