First implementation of Posix Network
Former-commit-id: 2b73870d8eef4dc92038224164396390ac43df46
This commit is contained in:
parent
7f4a7c1012
commit
1d04ac8f13
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: Socket
|
||||
#endif
|
||||
|
|
@ -105,4 +107,4 @@ namespace Nz
|
|||
m_handle = handle;
|
||||
OnOpened();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/IpAddressImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/IpAddressImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: Network
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: Network
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,309 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/Posix/IpAddressImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
using addrinfoImpl = addrinfo;
|
||||
|
||||
int GetAddressInfo(const String& hostname, const String& service, const addrinfoImpl* hints, addrinfoImpl** results)
|
||||
{
|
||||
return getaddrinfo(hostname.GetConstBuffer(), service.GetConstBuffer(), hints, results);
|
||||
}
|
||||
|
||||
int GetHostnameInfo(sockaddr* socketAddress, socklen_t socketLen, String* hostname, String* service, int flags)
|
||||
{
|
||||
std::array<char, NI_MAXHOST> hostnameBuffer;
|
||||
std::array<char, NI_MAXSERV> serviceBuffer;
|
||||
|
||||
int result = getnameinfo(socketAddress, socketLen, hostnameBuffer.data(), hostnameBuffer.size(), serviceBuffer.data(), serviceBuffer.size(), flags);
|
||||
if (result == 0)
|
||||
{
|
||||
if (hostname)
|
||||
hostname->Set(hostnameBuffer.data());
|
||||
|
||||
if (service)
|
||||
service->Set(serviceBuffer.data());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FreeAddressInfo(addrinfoImpl* results)
|
||||
{
|
||||
freeaddrinfo(results);
|
||||
}
|
||||
|
||||
IpAddress::IPv4 convertSockaddrToIPv4(const in_addr& addr)
|
||||
{
|
||||
union byteToInt
|
||||
{
|
||||
UInt8 b[sizeof(uint32_t)];
|
||||
uint32_t i;
|
||||
};
|
||||
|
||||
byteToInt hostOrder;
|
||||
hostOrder.i = ntohl(addr.s_addr);
|
||||
|
||||
return { hostOrder.b[3], hostOrder.b[2], hostOrder.b[1], hostOrder.b[0] };
|
||||
}
|
||||
|
||||
IpAddress::IPv6 convertSockaddr6ToIPv6(const in6_addr& addr)
|
||||
{
|
||||
union byteToInt
|
||||
{
|
||||
UInt8 b[sizeof(uint32_t)];
|
||||
uint32_t i;
|
||||
};
|
||||
|
||||
IpAddress::IPv6 ipv6Addr;
|
||||
|
||||
for (auto i = 0; i < 4; ++i)
|
||||
{
|
||||
byteToInt hostOrder;
|
||||
hostOrder.i = 0;
|
||||
std::copy(addr.s6_addr + 4 * i, addr.s6_addr + 4 * (i + 1), hostOrder.b);
|
||||
ipv6Addr[2 * i] = (hostOrder.b[3] << 8) + hostOrder.b[2];
|
||||
ipv6Addr[2 * i + 1] = (hostOrder.b[1] << 8) + hostOrder.b[0];
|
||||
}
|
||||
|
||||
return ipv6Addr;
|
||||
}
|
||||
}
|
||||
|
||||
IpAddress IpAddressImpl::FromAddrinfo(const addrinfo* info)
|
||||
{
|
||||
switch (info->ai_family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
sockaddr_in* ipv4 = reinterpret_cast<sockaddr_in*>(info->ai_addr);
|
||||
|
||||
return FromSockAddr(ipv4);
|
||||
}
|
||||
|
||||
case AF_INET6:
|
||||
{
|
||||
sockaddr_in6* ipv6 = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
|
||||
|
||||
return FromSockAddr(ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
return IpAddress::Invalid;
|
||||
}
|
||||
|
||||
IpAddress IpAddressImpl::FromSockAddr(const sockaddr* address)
|
||||
{
|
||||
switch (address->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return FromSockAddr(reinterpret_cast<const sockaddr_in*>(address));
|
||||
|
||||
case AF_INET6:
|
||||
return FromSockAddr(reinterpret_cast<const sockaddr_in6*>(address));
|
||||
}
|
||||
|
||||
return IpAddress::Invalid;
|
||||
}
|
||||
|
||||
IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in* addressv4)
|
||||
{
|
||||
IpAddress::IPv4 ip4Address = Detail::convertSockaddrToIPv4(addressv4->sin_addr);
|
||||
return IpAddress(ip4Address, ntohs(addressv4->sin_port));
|
||||
}
|
||||
|
||||
IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in6* addressv6)
|
||||
{
|
||||
IpAddress::IPv6 ip6Address = Detail::convertSockaddr6ToIPv6(addressv6->sin6_addr);
|
||||
return IpAddress(ip6Address, ntohs(addressv6->sin6_port));
|
||||
}
|
||||
|
||||
bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service, ResolveError* error)
|
||||
{
|
||||
SockAddrBuffer socketAddress;
|
||||
socklen_t socketAddressLen = ToSockAddr(ipAddress, socketAddress.data());
|
||||
|
||||
if (Detail::GetHostnameInfo(reinterpret_cast<sockaddr*>(socketAddress.data()), socketAddressLen, hostname, service, NI_NUMERICSERV) != 0)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateEAIErrorToResolveError(errno);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = ResolveError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<HostnameInfo> IpAddressImpl::ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error)
|
||||
{
|
||||
std::vector<HostnameInfo> results;
|
||||
|
||||
Detail::addrinfoImpl hints;
|
||||
std::memset(&hints, 0, sizeof(Detail::addrinfoImpl));
|
||||
hints.ai_family = SocketImpl::TranslateNetProtocolToAF(procol);
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
Detail::addrinfoImpl* servinfo;
|
||||
if (Detail::GetAddressInfo(hostname, service, &hints, &servinfo) != 0)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateEAIErrorToResolveError(errno);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
CallOnExit onExit([servinfo]()
|
||||
{
|
||||
Detail::FreeAddressInfo(servinfo);
|
||||
});
|
||||
|
||||
// loop through all the results and connect to the first we can
|
||||
for (Detail::addrinfoImpl* p = servinfo; p != nullptr; p = p->ai_next)
|
||||
{
|
||||
HostnameInfo result;
|
||||
result.address = FromAddrinfo(p);
|
||||
result.canonicalName = String::Unicode(p->ai_canonname);
|
||||
result.protocol = TranslatePFToNetProtocol(p->ai_family);
|
||||
result.socketType = TranslateSockToNetProtocol(p->ai_socktype);
|
||||
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = ResolveError_NoError;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
socklen_t IpAddressImpl::ToSockAddr(const IpAddress& ipAddress, void* buffer)
|
||||
{
|
||||
if (ipAddress.IsValid())
|
||||
{
|
||||
switch (ipAddress.GetProtocol())
|
||||
{
|
||||
case NetProtocol_IPv4:
|
||||
{
|
||||
sockaddr_in* socketAddress = reinterpret_cast<sockaddr_in*>(buffer);
|
||||
|
||||
std::memset(socketAddress, 0, sizeof(sockaddr_in));
|
||||
socketAddress->sin_family = AF_INET;
|
||||
socketAddress->sin_port = htons(ipAddress.GetPort());
|
||||
socketAddress->sin_addr.s_addr = htonl(ipAddress.ToUInt32());
|
||||
|
||||
return sizeof(sockaddr_in);
|
||||
}
|
||||
|
||||
case NetProtocol_IPv6:
|
||||
{
|
||||
sockaddr_in6* socketAddress = reinterpret_cast<sockaddr_in6*>(buffer);
|
||||
|
||||
std::memset(socketAddress, 0, sizeof(sockaddr_in6));
|
||||
socketAddress->sin6_family = AF_INET6;
|
||||
socketAddress->sin6_port = htons(ipAddress.GetPort());
|
||||
|
||||
IpAddress::IPv6 address = ipAddress.ToIPv6();
|
||||
for (unsigned int i = 0; i < 8; ++i)
|
||||
{
|
||||
UInt16 networkOrder = htons(address[i]);
|
||||
socketAddress->sin6_addr.s6_addr[2 * i] = networkOrder / 256;
|
||||
socketAddress->sin6_addr.s6_addr[2 * i + 1] = networkOrder % 256;
|
||||
}
|
||||
|
||||
return sizeof(sockaddr_in6);
|
||||
}
|
||||
|
||||
default:
|
||||
NazaraInternalError("Unhandled ip protocol (0x" + String::Number(ipAddress.GetProtocol()) + ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NazaraError("Invalid ip address");
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetProtocol IpAddressImpl::TranslatePFToNetProtocol(int family)
|
||||
{
|
||||
switch (family)
|
||||
{
|
||||
case PF_INET:
|
||||
return NetProtocol_IPv4;
|
||||
|
||||
case PF_INET6:
|
||||
return NetProtocol_IPv6;
|
||||
|
||||
default:
|
||||
return NetProtocol_Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
SocketType IpAddressImpl::TranslateSockToNetProtocol(int socketType)
|
||||
{
|
||||
switch (socketType)
|
||||
{
|
||||
case SOCK_STREAM:
|
||||
return SocketType_TCP;
|
||||
|
||||
case SOCK_DGRAM:
|
||||
return SocketType_UDP;
|
||||
|
||||
case SOCK_RAW:
|
||||
return SocketType_Raw;
|
||||
|
||||
default:
|
||||
return SocketType_Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
ResolveError IpAddressImpl::TranslateEAIErrorToResolveError(int error)
|
||||
{
|
||||
// http://man7.org/linux/man-pages/man3/gai_strerror.3.html
|
||||
switch (error)
|
||||
{
|
||||
case 0:
|
||||
return ResolveError_NoError;
|
||||
|
||||
// Engine error
|
||||
case EAI_BADFLAGS:
|
||||
case EAI_SYSTEM:
|
||||
return ResolveError_Internal;
|
||||
|
||||
case EAI_FAMILY:
|
||||
case EAI_SERVICE:
|
||||
case EAI_SOCKTYPE:
|
||||
return ResolveError_ProtocolNotSupported;
|
||||
|
||||
case EAI_NONAME:
|
||||
return ResolveError_NotFound;
|
||||
|
||||
case EAI_FAIL:
|
||||
return ResolveError_NonRecoverable;
|
||||
|
||||
case EAI_NODATA:
|
||||
return ResolveError_NotInitialized;
|
||||
|
||||
case EAI_MEMORY:
|
||||
return ResolveError_ResourceError;
|
||||
|
||||
case EAI_AGAIN:
|
||||
return ResolveError_TemporaryFailure;
|
||||
}
|
||||
|
||||
NazaraWarning("Unhandled EAI error: " + Error::GetLastSystemError(error) + " (" + String::Number(error) + ") as " + gai_strerror(error));
|
||||
return ResolveError_Unknown;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class IpAddressImpl
|
||||
{
|
||||
public:
|
||||
using SockAddrBuffer = std::array<UInt8, sizeof(sockaddr_in6)>;
|
||||
|
||||
IpAddressImpl() = delete;
|
||||
~IpAddressImpl() = delete;
|
||||
|
||||
static IpAddress FromAddrinfo(const addrinfo* info);
|
||||
static IpAddress FromSockAddr(const sockaddr* address);
|
||||
static IpAddress FromSockAddr(const sockaddr_in* addressv4);
|
||||
static IpAddress FromSockAddr(const sockaddr_in6* addressv6);
|
||||
|
||||
static bool ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service, ResolveError* error);
|
||||
static std::vector<HostnameInfo> ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error);
|
||||
|
||||
static socklen_t ToSockAddr(const IpAddress& ipAddress, void* buffer);
|
||||
static NetProtocol TranslatePFToNetProtocol(int family);
|
||||
static SocketType TranslateSockToNetProtocol(int socketType);
|
||||
static ResolveError TranslateEAIErrorToResolveError(int error);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,746 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Network/Posix/IpAddressImpl.hpp>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
constexpr int SOCKET_ERROR = -1;
|
||||
|
||||
SocketHandle SocketImpl::Accept(SocketHandle handle, IpAddress* address, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
socklen_t bufferLength = sizeof(sockaddr_in);
|
||||
|
||||
SocketHandle newClient = accept(handle, reinterpret_cast<sockaddr*>(&nameBuffer), &bufferLength);
|
||||
if (newClient != InvalidHandle)
|
||||
{
|
||||
if (address)
|
||||
*address = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(&nameBuffer));
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
}
|
||||
|
||||
return newClient;
|
||||
}
|
||||
|
||||
SocketState SocketImpl::Bind(SocketHandle handle, const IpAddress& address, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(address.IsValid(), "Invalid address");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data());
|
||||
|
||||
if (bind(handle, reinterpret_cast<const sockaddr*>(&nameBuffer), bufferLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return SocketState_Bound;
|
||||
}
|
||||
|
||||
SocketHandle SocketImpl::Create(NetProtocol protocol, SocketType type, SocketError* error)
|
||||
{
|
||||
NazaraAssert(protocol != NetProtocol_Any, "Any protocol is not supported for socket creation");
|
||||
NazaraAssert(type <= SocketType_Max, "Type has value out of enum");
|
||||
|
||||
SocketHandle handle = socket(TranslateNetProtocolToAF(protocol), TranslateSocketTypeToSock(type), 0);
|
||||
if (handle == InvalidHandle && error != nullptr)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SocketImpl::Close(SocketHandle handle)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
if (close(handle) == SOCKET_ERROR)
|
||||
NazaraWarning("Failed to close socket: " + Error::GetLastSystemError(GetLastErrorCode()));
|
||||
}
|
||||
|
||||
void SocketImpl::ClearErrorCode(SocketHandle handle)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
if (GetLastError(handle, nullptr) < 0)
|
||||
NazaraWarning("Failed to clear socket error code: " + Error::GetLastSystemError(GetLastErrorCode()));
|
||||
}
|
||||
|
||||
SocketState SocketImpl::Connect(SocketHandle handle, const IpAddress& address, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(address.IsValid(), "Invalid address");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data());
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
// Clear socket error status
|
||||
ClearErrorCode(handle);
|
||||
|
||||
if (connect(handle, reinterpret_cast<const sockaddr*>(nameBuffer.data()), bufferLength) == SOCKET_ERROR)
|
||||
{
|
||||
int errorCode = GetLastErrorCode();
|
||||
switch (errorCode) //< Check for "normal errors" first
|
||||
{
|
||||
case EALREADY:
|
||||
case EINPROGRESS:
|
||||
return SocketState_Connecting;
|
||||
|
||||
case EISCONN:
|
||||
return SocketState_Connected;
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (errorCode == EADDRNOTAVAIL)
|
||||
*error = SocketError_ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case
|
||||
else
|
||||
*error = TranslateErrnoToResolveError(errorCode);
|
||||
}
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
|
||||
return SocketState_Connected;
|
||||
}
|
||||
|
||||
SocketState SocketImpl::Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error)
|
||||
{
|
||||
SocketState state = Connect(handle, address, error);
|
||||
if (state == SocketState_Connecting)
|
||||
{
|
||||
// http://developerweb.net/viewtopic.php?id=3196
|
||||
fd_set localSet;
|
||||
FD_ZERO(&localSet);
|
||||
FD_SET(handle, &localSet);
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
|
||||
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
|
||||
|
||||
int ret = select(0, nullptr, &localSet, &localSet, (msTimeout > 0) ? &tv : nullptr);
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
int code = GetLastErrorCode(handle, error);
|
||||
if (code < 0) //< GetLastErrorCode() failed
|
||||
return SocketState_NotConnected;
|
||||
|
||||
if (code)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(code);
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
if (error)
|
||||
*error = SocketError_TimedOut;
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
state = SocketState_Connected;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool SocketImpl::Initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SocketError SocketImpl::GetLastError(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
int code = GetLastErrorCode(handle, error);
|
||||
if (code < 0)
|
||||
return SocketError_Internal;
|
||||
|
||||
return TranslateErrnoToResolveError(code);
|
||||
}
|
||||
|
||||
int SocketImpl::GetLastErrorCode()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
int SocketImpl::GetLastErrorCode(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
int code;
|
||||
unsigned int codeLength = sizeof(code);
|
||||
|
||||
if (getsockopt(handle, SOL_SOCKET, SO_ERROR, &code, &codeLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
SocketState SocketImpl::Listen(SocketHandle handle, const IpAddress& address, unsigned queueSize, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(address.IsValid(), "Invalid address");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data());
|
||||
|
||||
if (bind(handle, reinterpret_cast<const sockaddr*>(&nameBuffer), bufferLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
|
||||
if (listen(handle, queueSize) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return SocketState_NotConnected;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return SocketState_Bound;
|
||||
}
|
||||
|
||||
unsigned int SocketImpl::QueryAvailableBytes(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
u_long availableBytes;
|
||||
if (ioctl(handle, FIONREAD, &availableBytes) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return availableBytes;
|
||||
}
|
||||
|
||||
bool SocketImpl::QueryBroadcasting(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
bool code;
|
||||
unsigned int codeLength = sizeof(code);
|
||||
|
||||
if (getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &code, &codeLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
bool SocketImpl::QueryKeepAlive(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
bool code;
|
||||
unsigned int codeLength = sizeof(code);
|
||||
|
||||
if (getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &code, &codeLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
unsigned int SocketImpl::QueryMaxDatagramSize(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
unsigned int code;
|
||||
unsigned int codeLength = sizeof(code);
|
||||
|
||||
if (getsockopt(handle, IPPROTO_IP, IP_MTU, &code, &codeLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
bool SocketImpl::QueryNoDelay(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
bool code;
|
||||
unsigned int codeLength = sizeof(code);
|
||||
|
||||
if (getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &code, &codeLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
IpAddress SocketImpl::QueryPeerAddress(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
socklen_t bufferLength = sizeof(sockaddr_in);
|
||||
|
||||
if (getpeername(handle, reinterpret_cast<sockaddr*>(nameBuffer.data()), &bufferLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return IpAddress();
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return IpAddressImpl::FromSockAddr(reinterpret_cast<sockaddr*>(nameBuffer.data()));
|
||||
}
|
||||
|
||||
IpAddress SocketImpl::QuerySocketAddress(SocketHandle handle, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
socklen_t bufferLength = sizeof(sockaddr_in);
|
||||
|
||||
if (getsockname(handle, reinterpret_cast<sockaddr*>(nameBuffer.data()), &bufferLength) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
int errorCode = GetLastErrorCode();
|
||||
if (errorCode == EINVAL)
|
||||
*error = SocketError_NoError;
|
||||
else
|
||||
*error = TranslateErrnoToResolveError(errorCode);
|
||||
}
|
||||
|
||||
return IpAddress();
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return IpAddressImpl::FromSockAddr(reinterpret_cast<sockaddr*>(nameBuffer.data()));
|
||||
}
|
||||
|
||||
|
||||
bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(buffer && length > 0, "Invalid buffer");
|
||||
|
||||
int byteRead = recv(handle, reinterpret_cast<char*>(buffer), length, 0);
|
||||
if (byteRead == SOCKET_ERROR)
|
||||
{
|
||||
int errorCode = GetLastErrorCode();
|
||||
switch (errorCode)
|
||||
{
|
||||
case EWOULDBLOCK:
|
||||
{
|
||||
// If we have no data and are not blocking, return true with 0 byte read
|
||||
byteRead = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(errorCode);
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (byteRead == 0)
|
||||
{
|
||||
if (error)
|
||||
*error = SocketError_ConnectionClosed;
|
||||
|
||||
return false; //< Connection has been closed
|
||||
}
|
||||
|
||||
if (read)
|
||||
*read = byteRead;
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(buffer && length > 0, "Invalid buffer");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
socklen_t bufferLength = sizeof(sockaddr_in);
|
||||
|
||||
IpAddress senderIp;
|
||||
|
||||
int byteRead = recvfrom(handle, buffer, length, 0, reinterpret_cast<sockaddr*>(&nameBuffer), &bufferLength);
|
||||
if (byteRead == SOCKET_ERROR)
|
||||
{
|
||||
int errorCode = GetLastErrorCode();
|
||||
switch (errorCode)
|
||||
{
|
||||
case EWOULDBLOCK:
|
||||
{
|
||||
// If we have no data and are not blocking, return true with 0 byte read
|
||||
byteRead = 0;
|
||||
senderIp = IpAddress::Invalid;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(errorCode);
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (byteRead == 0)
|
||||
{
|
||||
if (error)
|
||||
*error = SocketError_ConnectionClosed;
|
||||
|
||||
return false; //< Connection closed
|
||||
}
|
||||
else // else we received something
|
||||
senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(&nameBuffer));
|
||||
|
||||
if (from)
|
||||
*from = senderIp;
|
||||
|
||||
if (read)
|
||||
*read = byteRead;
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(buffer && length > 0, "Invalid buffer");
|
||||
|
||||
int byteSent = send(handle, reinterpret_cast<const char*>(buffer), length, 0);
|
||||
if (byteSent == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (sent)
|
||||
*sent = byteSent;
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
NazaraAssert(buffer && length > 0, "Invalid buffer");
|
||||
|
||||
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||
int bufferLength = IpAddressImpl::ToSockAddr(to, nameBuffer.data());
|
||||
|
||||
int byteSent = sendto(handle, reinterpret_cast<const char*>(buffer), length, 0, reinterpret_cast<const sockaddr*>(nameBuffer.data()), bufferLength);
|
||||
if (byteSent == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (sent)
|
||||
*sent = byteSent;
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::SetBlocking(SocketHandle handle, bool blocking, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
u_long block = (blocking) ? 0 : 1;
|
||||
if (ioctl(handle, FIONBIO, &block) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::SetBroadcasting(SocketHandle handle, bool broadcasting, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
bool option = broadcasting;
|
||||
if (setsockopt(handle, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&option), sizeof(option)) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
int keepAlive = enabled ? 1 : 0;
|
||||
int keepIdle = msTime / 1000; // Linux works with seconds.
|
||||
int keepInterval = msInterval / 1000; // Linux works with seconds.
|
||||
|
||||
if (setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &keepAlive , sizeof(keepAlive)) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (setsockopt(handle, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(keepIdle)) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (setsockopt(handle, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(keepInterval)) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::SetNoDelay(SocketHandle handle, bool nodelay, SocketError* error)
|
||||
{
|
||||
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||
|
||||
int option = nodelay ? 1 : 0;
|
||||
if (setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return false; //< Error
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SocketError SocketImpl::TranslateErrnoToResolveError(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case 0:
|
||||
return SocketError_NoError;
|
||||
|
||||
// Engine error
|
||||
case EACCES:
|
||||
case EBADF:
|
||||
case EINVAL:
|
||||
case EFAULT:
|
||||
case ENOTSOCK:
|
||||
case EPROTOTYPE:
|
||||
return SocketError_Internal;
|
||||
|
||||
case EADDRNOTAVAIL:
|
||||
case EADDRINUSE:
|
||||
return SocketError_AddressNotAvailable;
|
||||
|
||||
case EAFNOSUPPORT:
|
||||
case EPFNOSUPPORT:
|
||||
case EOPNOTSUPP:
|
||||
case EPROTONOSUPPORT:
|
||||
case ESOCKTNOSUPPORT:
|
||||
return SocketError_NotSupported;
|
||||
|
||||
// Those are not errors and should have been handled before the call
|
||||
case EALREADY:
|
||||
case EISCONN:
|
||||
case EWOULDBLOCK:
|
||||
return SocketError_Internal;
|
||||
|
||||
case ECONNREFUSED:
|
||||
return SocketError_ConnectionRefused;
|
||||
|
||||
case EMSGSIZE:
|
||||
return SocketError_DatagramSize;
|
||||
|
||||
case EMFILE:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
return SocketError_ResourceError;
|
||||
|
||||
case ENOTCONN:
|
||||
case ESHUTDOWN:
|
||||
return SocketError_ConnectionClosed;
|
||||
|
||||
case EHOSTUNREACH:
|
||||
return SocketError_UnreachableHost;
|
||||
|
||||
case ENETDOWN:
|
||||
case ENETUNREACH:
|
||||
return SocketError_NetworkError;
|
||||
|
||||
case ENODATA:
|
||||
return SocketError_NotInitialized;
|
||||
|
||||
case ETIMEDOUT:
|
||||
return SocketError_TimedOut;
|
||||
}
|
||||
|
||||
NazaraWarning("Unhandled POSIX error: " + Error::GetLastSystemError(error) + " (" + String::Number(error) + ')');
|
||||
return SocketError_Unknown;
|
||||
}
|
||||
|
||||
int SocketImpl::TranslateNetProtocolToAF(NetProtocol protocol)
|
||||
{
|
||||
NazaraAssert(protocol <= NetProtocol_Max, "Protocol has value out of enum");
|
||||
|
||||
static int addressFamily[] = {
|
||||
AF_UNSPEC, //< NetProtocol_Any
|
||||
AF_INET, //< NetProtocol_IPv4
|
||||
AF_INET6, //< NetProtocol_IPv6
|
||||
-1 //< NetProtocol_Unknown
|
||||
};
|
||||
static_assert(sizeof(addressFamily) / sizeof(int) == NetProtocol_Max + 1, "Address family array is incomplete");
|
||||
|
||||
return addressFamily[protocol];
|
||||
}
|
||||
|
||||
int SocketImpl::TranslateSocketTypeToSock(SocketType type)
|
||||
{
|
||||
NazaraAssert(type <= SocketType_Max, "Socket type has value out of enum");
|
||||
|
||||
static int socketType[] = {
|
||||
SOCK_RAW, //< SocketType_Raw
|
||||
SOCK_STREAM, //< SocketType_TCP
|
||||
SOCK_DGRAM, //< SocketType_UDP
|
||||
-1 //< SocketType_Unknown
|
||||
};
|
||||
static_assert(sizeof(socketType) / sizeof(int) == SocketType_Max + 1, "Socket type array is incomplete");
|
||||
|
||||
return socketType[type];
|
||||
}
|
||||
|
||||
void SocketImpl::Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
SocketHandle SocketImpl::InvalidHandle = -1;
|
||||
SocketImpl::socketID SocketImpl::s_socket;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/SocketHandle.hpp>
|
||||
#include <Nazara/Network/Enums.hpp>
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class SocketImpl
|
||||
{
|
||||
public:
|
||||
SocketImpl() = delete;
|
||||
~SocketImpl() = delete;
|
||||
|
||||
static SocketHandle Accept(SocketHandle handle, IpAddress* address, SocketError* error);
|
||||
|
||||
static SocketState Bind(SocketHandle handle, const IpAddress& address, SocketError* error);
|
||||
|
||||
static SocketHandle Create(NetProtocol protocol, SocketType type, SocketError* error);
|
||||
|
||||
static void ClearErrorCode(SocketHandle handle);
|
||||
static void Close(SocketHandle handle);
|
||||
|
||||
static SocketState Connect(SocketHandle handle, const IpAddress& address, SocketError* error);
|
||||
static SocketState Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error);
|
||||
|
||||
static bool Initialize();
|
||||
|
||||
static SocketError GetLastError(SocketHandle handle, SocketError* error = nullptr);
|
||||
static int GetLastErrorCode();
|
||||
static int GetLastErrorCode(SocketHandle handle, SocketError* error = nullptr);
|
||||
|
||||
static SocketState Listen(SocketHandle handle, const IpAddress& address, unsigned queueSize, SocketError* error);
|
||||
|
||||
static unsigned int QueryAvailableBytes(SocketHandle handle, SocketError* error = nullptr);
|
||||
static bool QueryBroadcasting(SocketHandle handle, SocketError* error = nullptr);
|
||||
static bool QueryKeepAlive(SocketHandle handle, SocketError* error = nullptr);
|
||||
static unsigned int QueryMaxDatagramSize(SocketHandle handle, SocketError* error = nullptr);
|
||||
static bool QueryNoDelay(SocketHandle handle, SocketError* error = nullptr);
|
||||
static IpAddress QueryPeerAddress(SocketHandle handle, SocketError* error = nullptr);
|
||||
static IpAddress QuerySocketAddress(SocketHandle handle, SocketError* error = nullptr);
|
||||
|
||||
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
|
||||
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
|
||||
|
||||
static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error);
|
||||
static bool SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error);
|
||||
|
||||
static bool SetBlocking(SocketHandle handle, bool blocking, SocketError* error = nullptr);
|
||||
static bool SetBroadcasting(SocketHandle handle, bool broadcasting, SocketError* error = nullptr);
|
||||
static bool SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error = nullptr);
|
||||
static bool SetNoDelay(SocketHandle handle, bool nodelay, SocketError* error = nullptr);
|
||||
|
||||
static SocketError TranslateErrnoToResolveError(int error);
|
||||
static int TranslateNetProtocolToAF(NetProtocol protocol);
|
||||
static int TranslateSocketTypeToSock(SocketType type);
|
||||
|
||||
static void Uninitialize();
|
||||
|
||||
static SocketHandle InvalidHandle;
|
||||
|
||||
private:
|
||||
using socketID = int;
|
||||
static socketID s_socket;
|
||||
};
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: Socket
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: Socket
|
||||
#endif
|
||||
|
|
@ -60,4 +62,4 @@ namespace Nz
|
|||
|
||||
m_boundAddress = IpAddress::Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: Socket
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue