96 lines
2.2 KiB
C++
96 lines
2.2 KiB
C++
#include "TCPSocket.h"
|
|
#include "NetworkManager.h"
|
|
|
|
#include "logging/Logger.h"
|
|
|
|
#include <event2/event.h>
|
|
#include <event2/listener.h>
|
|
|
|
namespace Feather::Network
|
|
{
|
|
TCPSocket::TCPSocket()
|
|
{
|
|
m_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
// Can't create IPv6 socket? Create an IPv4 one.
|
|
if (!(m_ipv6 = IsValid()))
|
|
{
|
|
Log::Info("Failed to create IPv6 socket, falling back to IPv4.");
|
|
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
}
|
|
}
|
|
|
|
TCPSocket::~TCPSocket()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
bool TCPSocket::IsIPV6() const
|
|
{
|
|
return m_ipv6;
|
|
}
|
|
|
|
bool TCPSocket::MarkReusable()
|
|
{
|
|
return evutil_make_listen_socket_reuseable(m_socket) == 0;
|
|
}
|
|
|
|
bool TCPSocket::MarkDualBind()
|
|
{
|
|
constexpr uint32_t zero = 0;
|
|
return setsockopt(m_socket, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
reinterpret_cast<const char*>(&zero),
|
|
sizeof(zero)) == 0;
|
|
}
|
|
|
|
bool TCPSocket::MarkNonBlocking()
|
|
{
|
|
return evutil_make_socket_nonblocking(m_socket) == 0;
|
|
}
|
|
|
|
bool TCPSocket::Bind(uint16_t port)
|
|
{
|
|
auto BindGeneric = [&](const auto& name)
|
|
{
|
|
return bind(m_socket, reinterpret_cast<const sockaddr*>(&name), sizeof(name)) == 0;
|
|
};
|
|
|
|
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 TCPSocket::Close()
|
|
{
|
|
if (!IsValid())
|
|
return true;
|
|
|
|
return evutil_closesocket(m_socket) == 0;
|
|
}
|
|
|
|
evconnlistener* TCPSocket::Listen(evconnlistener_cb callback, void* self)
|
|
{
|
|
if (listen(m_socket, SOMAXCONN) != 0)
|
|
return nullptr;
|
|
|
|
return evconnlistener_new(
|
|
NetworkManager::Instance().GetEventBase(),
|
|
callback, self,
|
|
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
|
|
0,
|
|
m_socket);
|
|
}
|
|
|
|
bool TCPSocket::IsValid() const
|
|
{
|
|
return m_socket != EVUTIL_INVALID_SOCKET;
|
|
}
|
|
} |