Initial socket abstraction
This commit is contained in:
parent
7481419cb0
commit
f67a7b697c
|
@ -0,0 +1,172 @@
|
|||
#include "SocketUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <Ws2tcpip.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace Feather::Sockets
|
||||
{
|
||||
class TCPSocketHandle
|
||||
{
|
||||
public:
|
||||
TCPSocketHandle()
|
||||
{
|
||||
m_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
// Can't create IPv6 socket? Create an IPv4 one.
|
||||
if (!(m_ipv6 = IsValid()))
|
||||
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
~TCPSocketHandle()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool IsIPV6() const { return m_ipv6; }
|
||||
|
||||
bool MarkReusable()
|
||||
{
|
||||
constexpr uint32_t one = 1;
|
||||
return setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
reinterpret_cast<const char*>(&one),
|
||||
socklen_t(sizeof(one))) == 0;
|
||||
}
|
||||
|
||||
bool MarkDualBind()
|
||||
{
|
||||
constexpr uint32_t zero = 0;
|
||||
return setsockopt(m_socket, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
reinterpret_cast<const char*>(&zero),
|
||||
sizeof(zero)) == 0;
|
||||
}
|
||||
|
||||
bool Bind(uint16_t port)
|
||||
{
|
||||
sockaddr_in6 name_ipv6 = {};
|
||||
name_ipv6.sin6_family = AF_INET6;
|
||||
name_ipv6.sin6_port = ntohs(port);
|
||||
|
||||
sockaddr_in name_ipv4 = {};
|
||||
name_ipv4.sin_family = AF_INET;
|
||||
name_ipv4.sin_port = ntohs(port);
|
||||
|
||||
return m_ipv6
|
||||
? BindGeneric(name_ipv6)
|
||||
: BindGeneric(name_ipv4);
|
||||
}
|
||||
|
||||
bool Listen()
|
||||
{
|
||||
return listen(m_socket, SOMAXCONN) == 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool IsValid() const { return m_socket != INVALID_SOCKET; }
|
||||
|
||||
bool MarkNonBlocking()
|
||||
{
|
||||
unsigned long one = 1;
|
||||
return ioctlsocket(m_socket, FIONBIO, &one) != SOCKET_ERROR;
|
||||
}
|
||||
|
||||
bool Close()
|
||||
{
|
||||
return shutdown(m_socket, SD_BOTH) == 0 && closesocket(m_socket) == 0;
|
||||
}
|
||||
|
||||
static bool InitSocketSystem()
|
||||
{
|
||||
WSADATA wsa_data;
|
||||
return WSAStartup(MAKEWORD(1, 1), &wsa_data) == 0;
|
||||
}
|
||||
|
||||
static bool CloseSocketSystem()
|
||||
{
|
||||
return WSACleanup() == 0;
|
||||
}
|
||||
|
||||
using SocketType = SOCKET;
|
||||
#else
|
||||
bool IsValid() const { return m_socket >= 0; }
|
||||
|
||||
bool MarkNonBlocking()
|
||||
{
|
||||
return fcntl(fd, F_SETFL, O_NONBLOCK) != -1;
|
||||
}
|
||||
|
||||
bool Close()
|
||||
{
|
||||
return shutdown(m_socket, SHUT_RDWR) == 0 && close(m_socket) == 0;
|
||||
}
|
||||
|
||||
static bool InitSocketSystem()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CloseSocketSystem()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
using SocketType = int;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
bool BindGeneric(const T& name)
|
||||
{
|
||||
return bind(m_socket, reinterpret_cast<const sockaddr*>(&name), sizeof(name)) == 0;
|
||||
}
|
||||
|
||||
SocketType m_socket;
|
||||
bool m_ipv6;
|
||||
};
|
||||
|
||||
TCPSocket::TCPSocket(uint16_t port)
|
||||
{
|
||||
auto socket = std::make_unique<TCPSocketHandle>();
|
||||
|
||||
if (!socket->IsValid())
|
||||
return;
|
||||
|
||||
if (!socket->MarkReusable())
|
||||
return;
|
||||
|
||||
if (socket->IsIPV6() && !socket->MarkDualBind())
|
||||
return;
|
||||
|
||||
if (!socket->Bind(port))
|
||||
return;
|
||||
|
||||
if (socket->Listen())
|
||||
return;
|
||||
|
||||
m_socket = std::move(socket);
|
||||
}
|
||||
|
||||
TCPSocket::~TCPSocket()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class SocketInitializer
|
||||
{
|
||||
public:
|
||||
SocketInitializer() { TCPSocketHandle::InitSocketSystem(); }
|
||||
~SocketInitializer() { TCPSocketHandle::CloseSocketSystem(); }
|
||||
};
|
||||
|
||||
static SocketInitializer s_socketInitializer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace Feather::Sockets
|
||||
{
|
||||
class TCPSocketHandle;
|
||||
|
||||
class TCPSocket
|
||||
{
|
||||
public:
|
||||
TCPSocket(uint16_t port);
|
||||
~TCPSocket();
|
||||
|
||||
inline bool IsValid() const { return m_socket != nullptr; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<TCPSocketHandle> m_socket;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue