Network: First commit
Former-commit-id: ec8697acc51569f5043e4f70e4cf42f1c5dc487c
This commit is contained in:
parent
dfa6f06337
commit
1bbf038cc6
|
|
@ -0,0 +1,19 @@
|
||||||
|
MODULE.Name = "Network"
|
||||||
|
|
||||||
|
MODULE.Libraries = {
|
||||||
|
"NazaraCore"
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE.OsFiles.Windows = {
|
||||||
|
"../src/Nazara/Network/Win32/**.hpp",
|
||||||
|
"../src/Nazara/Network/Win32/**.cpp"
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE.OsFiles.Posix = {
|
||||||
|
"../src/Nazara/Network/Posix/**.hpp",
|
||||||
|
"../src/Nazara/Network/Posix/**.cpp"
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE.OsLibraries.Windows = {
|
||||||
|
"ws2_32"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// This file was automatically generated on 09 Nov 2015 at 13:52:47
|
||||||
|
|
||||||
|
/*
|
||||||
|
Nazara Engine - Network module
|
||||||
|
|
||||||
|
Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_GLOBAL_NETWORK_HPP
|
||||||
|
#define NAZARA_GLOBAL_NETWORK_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Network/AbstractSocket.hpp>
|
||||||
|
#include <Nazara/Network/Algorithm.hpp>
|
||||||
|
#include <Nazara/Network/Config.hpp>
|
||||||
|
#include <Nazara/Network/Enums.hpp>
|
||||||
|
#include <Nazara/Network/IpAddress.hpp>
|
||||||
|
#include <Nazara/Network/Network.hpp>
|
||||||
|
#include <Nazara/Network/SocketHandle.hpp>
|
||||||
|
#include <Nazara/Network/TcpBase.hpp>
|
||||||
|
#include <Nazara/Network/TcpClient.hpp>
|
||||||
|
#include <Nazara/Network/TcpServer.hpp>
|
||||||
|
#include <Nazara/Network/UdpSocket.hpp>
|
||||||
|
|
||||||
|
#endif // NAZARA_GLOBAL_NETWORK_HPP
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_ABSTRACTSOCKET_HPP
|
||||||
|
#define NAZARA_ABSTRACTSOCKET_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/Signal.hpp>
|
||||||
|
#include <Nazara/Network/Config.hpp>
|
||||||
|
#include <Nazara/Network/Enums.hpp>
|
||||||
|
#include <Nazara/Network/SocketHandle.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class NAZARA_NETWORK_API AbstractSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractSocket(const AbstractSocket&) = delete;
|
||||||
|
AbstractSocket(AbstractSocket&& abstractSocket);
|
||||||
|
virtual ~AbstractSocket();
|
||||||
|
|
||||||
|
void Close();
|
||||||
|
|
||||||
|
void EnableBlocking(bool blocking);
|
||||||
|
|
||||||
|
inline SocketError GetLastError() const;
|
||||||
|
inline SocketHandle GetNativeHandle() const;
|
||||||
|
inline SocketState GetState() const;
|
||||||
|
inline SocketType GetType() const;
|
||||||
|
|
||||||
|
inline bool IsBlockingEnabled() const;
|
||||||
|
|
||||||
|
unsigned int QueryAvailableBytes() const;
|
||||||
|
|
||||||
|
// Slots
|
||||||
|
NazaraSignal(OnStateChange, const AbstractSocket* /*socket*/, SocketState /*oldState*/, SocketState /*newState*/);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AbstractSocket(SocketType type);
|
||||||
|
|
||||||
|
inline void ChangeState(SocketState newState);
|
||||||
|
|
||||||
|
virtual void OnClose();
|
||||||
|
virtual void OnOpened();
|
||||||
|
|
||||||
|
bool Open(NetProtocol protocol);
|
||||||
|
void Open(SocketHandle existingHandle);
|
||||||
|
|
||||||
|
NetProtocol m_protocol;
|
||||||
|
SocketError m_lastError;
|
||||||
|
SocketHandle m_handle;
|
||||||
|
SocketState m_state;
|
||||||
|
SocketType m_type;
|
||||||
|
bool m_isBlockingEnabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/AbstractSocket.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_ABSTRACTSOCKET_HPP
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// 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/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline SocketError AbstractSocket::GetLastError() const
|
||||||
|
{
|
||||||
|
return m_lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SocketHandle AbstractSocket::GetNativeHandle() const
|
||||||
|
{
|
||||||
|
return m_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SocketState AbstractSocket::GetState() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SocketType AbstractSocket::GetType() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool AbstractSocket::IsBlockingEnabled() const
|
||||||
|
{
|
||||||
|
return m_isBlockingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void AbstractSocket::ChangeState(SocketState newState)
|
||||||
|
{
|
||||||
|
if (m_state != newState)
|
||||||
|
{
|
||||||
|
SocketState oldState = m_state;
|
||||||
|
m_state = newState;
|
||||||
|
OnStateChange(this, oldState, m_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_ALGORITHM_NETWORK_HPP
|
||||||
|
#define NAZARA_ALGORITHM_NETWORK_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port = nullptr, bool* isIPv6 = nullptr, const char** endOfRead = nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/Algorithm.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_ALGORITHM_NETWORK_HPP
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Core module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
Nazara Engine - Network module
|
||||||
|
|
||||||
|
Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_CONFIG_NETWORK_HPP
|
||||||
|
#define NAZARA_CONFIG_NETWORK_HPP
|
||||||
|
|
||||||
|
/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci
|
||||||
|
|
||||||
|
// Utilise le MemoryManager pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes)
|
||||||
|
#define NAZARA_NETWORK_MANAGE_MEMORY 0
|
||||||
|
|
||||||
|
// Active les tests de sécurité basés sur le code (Conseillé pour le développement)
|
||||||
|
#define NAZARA_NETWORK_SAFE 1
|
||||||
|
|
||||||
|
/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code
|
||||||
|
|
||||||
|
/// Vérification des valeurs et types de certaines constantes
|
||||||
|
#include <Nazara/Network/ConfigCheck.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_STATIC)
|
||||||
|
#define NAZARA_NETWORK_API
|
||||||
|
#else
|
||||||
|
#ifdef NAZARA_NETWORK_BUILD
|
||||||
|
#define NAZARA_NETWORK_API NAZARA_EXPORT
|
||||||
|
#else
|
||||||
|
#define NAZARA_NETWORK_API NAZARA_IMPORT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NAZARA_CONFIG_NETWORK_HPP
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_CONFIG_CHECK_NETWORK_HPP
|
||||||
|
#define NAZARA_CONFIG_CHECK_NETWORK_HPP
|
||||||
|
|
||||||
|
/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
// On force la valeur de MANAGE_MEMORY en mode debug
|
||||||
|
#if defined(NAZARA_DEBUG) && !NAZARA_NETWORK_MANAGE_MEMORY
|
||||||
|
#undef NAZARA_NETWORK_MANAGE_MEMORY
|
||||||
|
#define NAZARA_NETWORK_MANAGE_MEMORY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NAZARA_CONFIG_CHECK_NETWORK_HPP
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// 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/Config.hpp>
|
||||||
|
#if NAZARA_MODULENAME_MANAGE_MEMORY
|
||||||
|
#include <Nazara/Core/Debug/NewRedefinition.hpp>
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp
|
||||||
|
#if NAZARA_MODULENAME_MANAGE_MEMORY
|
||||||
|
#undef delete
|
||||||
|
#undef new
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_ENUMS_NETWORK_HPP
|
||||||
|
#define NAZARA_ENUMS_NETWORK_HPP
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
enum NetProtocol
|
||||||
|
{
|
||||||
|
NetProtocol_Any,
|
||||||
|
NetProtocol_IPv4,
|
||||||
|
NetProtocol_IPv6,
|
||||||
|
|
||||||
|
NetProtocol_Max = NetProtocol_IPv6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SocketError
|
||||||
|
{
|
||||||
|
SocketError_NoError,
|
||||||
|
|
||||||
|
SocketError_AddressNotAvailable, //< The address is already in use (when binding/listening)
|
||||||
|
SocketError_ConnectionClosed, //< The connection has been closed
|
||||||
|
SocketError_ConnectionRefused, //< The connection attempt was refused
|
||||||
|
SocketError_DatagramSize, //< The datagram size is over the system limit
|
||||||
|
SocketError_Internal, //< The error is coming from the engine
|
||||||
|
SocketError_NetworkError, //< The network system has failed (maybe network is down)
|
||||||
|
SocketError_NotInitialized, //< Nazara network has not been initialized
|
||||||
|
SocketError_NotSupported, //< The operation is not supported (e.g. creating a bluetooth socket on a system without any bluetooth adaptater)
|
||||||
|
SocketError_ResourceError, //< The operating system lacks the resources to proceed (e.g. memory/socket descriptor)
|
||||||
|
SocketError_UnreachableHost, //< The host is not reachable
|
||||||
|
SocketError_TimedOut, //< The operation timed out
|
||||||
|
SocketError_Unknown, //< The last operation failed with an unlisted error code
|
||||||
|
|
||||||
|
SocketError_Max = SocketError_Unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SocketState
|
||||||
|
{
|
||||||
|
SocketState_Bound, //< The socket is currently bound
|
||||||
|
SocketState_Connecting, //< The socket is currently connecting
|
||||||
|
SocketState_Connected, //< The socket is currently connected
|
||||||
|
SocketState_NotConnected, //< The socket is not connected (or has been disconnected)
|
||||||
|
|
||||||
|
SocketState_Max = SocketState_NotConnected
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SocketType
|
||||||
|
{
|
||||||
|
SocketType_Raw,
|
||||||
|
SocketType_TCP,
|
||||||
|
SocketType_UDP,
|
||||||
|
|
||||||
|
SocketType_Max = SocketType_UDP
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NAZARA_ENUMS_NETWORK_HPP
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_IPADDRESS_HPP
|
||||||
|
#define NAZARA_IPADDRESS_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/String.hpp>
|
||||||
|
#include <Nazara/Network/Config.hpp>
|
||||||
|
#include <Nazara/Network/Enums.hpp>
|
||||||
|
#include <array>
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
struct HostnameInfo;
|
||||||
|
|
||||||
|
class NAZARA_NETWORK_API IpAddress
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using IPv4 = std::array<UInt8, 4>; //< four 8bits blocks
|
||||||
|
using IPv6 = std::array<UInt16, 8>; //< eight 16bits blocks
|
||||||
|
|
||||||
|
inline IpAddress();
|
||||||
|
inline IpAddress(const IPv4& ip, UInt16 port = 0);
|
||||||
|
inline IpAddress(const IPv6& ip, UInt16 port = 0);
|
||||||
|
inline IpAddress(const UInt8& a, const UInt8& b, const UInt8& c, const UInt8& d, UInt16 port = 0);
|
||||||
|
inline IpAddress(const UInt16& a, const UInt16& b, const UInt16& c, const UInt16& d, const UInt16& e, const UInt16& f, const UInt16& g, const UInt16& h, UInt16 port = 0);
|
||||||
|
inline IpAddress(const char* address);
|
||||||
|
inline IpAddress(const String& address);
|
||||||
|
IpAddress(const IpAddress&) = default;
|
||||||
|
IpAddress(IpAddress&&) = default;
|
||||||
|
~IpAddress() = default;
|
||||||
|
|
||||||
|
bool BuildFromAddress(const char* address);
|
||||||
|
|
||||||
|
inline UInt16 GetPort() const;
|
||||||
|
inline NetProtocol GetProtocol() const;
|
||||||
|
|
||||||
|
bool IsLoopback() const;
|
||||||
|
inline bool IsValid() const;
|
||||||
|
|
||||||
|
inline void SetPort(UInt16 port);
|
||||||
|
|
||||||
|
inline IPv4 ToIPv4() const;
|
||||||
|
inline IPv6 ToIPv6() const;
|
||||||
|
String ToString() const;
|
||||||
|
inline UInt32 ToUInt32() const;
|
||||||
|
|
||||||
|
inline operator bool() const;
|
||||||
|
|
||||||
|
IpAddress& operator=(const IpAddress&) = default;
|
||||||
|
IpAddress& operator=(IpAddress&&) = default;
|
||||||
|
|
||||||
|
static String ResolveAddress(const IpAddress& address, String* service = nullptr);
|
||||||
|
static std::vector<HostnameInfo> ResolveHostname(NetProtocol procol, const String& hostname, const String& protocol = "http");
|
||||||
|
|
||||||
|
inline friend std::ostream& operator<<(std::ostream& out, const IpAddress& address);
|
||||||
|
|
||||||
|
inline friend bool operator==(const IpAddress& first, const IpAddress& second);
|
||||||
|
inline friend bool operator!=(const IpAddress& first, const IpAddress& second);
|
||||||
|
inline friend bool operator<(const IpAddress& first, const IpAddress& second);
|
||||||
|
inline friend bool operator<=(const IpAddress& first, const IpAddress& second);
|
||||||
|
inline friend bool operator>(const IpAddress& first, const IpAddress& second);
|
||||||
|
inline friend bool operator>=(const IpAddress& first, const IpAddress& second);
|
||||||
|
|
||||||
|
static IpAddress AnyIpV4;
|
||||||
|
static IpAddress AnyIpV6;
|
||||||
|
static IpAddress BroadcastIpV4;
|
||||||
|
static IpAddress Invalid;
|
||||||
|
static IpAddress LoopbackIpV4;
|
||||||
|
static IpAddress LoopbackIpV6;
|
||||||
|
|
||||||
|
private:
|
||||||
|
union
|
||||||
|
{
|
||||||
|
IPv4 m_ipv4;
|
||||||
|
IPv6 m_ipv6;
|
||||||
|
};
|
||||||
|
|
||||||
|
NetProtocol m_protocol;
|
||||||
|
UInt16 m_port;
|
||||||
|
bool m_isValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HostnameInfo
|
||||||
|
{
|
||||||
|
IpAddress address;
|
||||||
|
String canonicalName;
|
||||||
|
int flags;
|
||||||
|
int family;
|
||||||
|
int socketType;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/IpAddress.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_IPADDRESS_HPP
|
||||||
|
|
@ -0,0 +1,205 @@
|
||||||
|
// 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/Core/Error.hpp>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline IpAddress::IpAddress() :
|
||||||
|
m_isValid(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IpAddress(const IPv4& ip, UInt16 port) :
|
||||||
|
m_isValid(true),
|
||||||
|
m_ipv4(ip),
|
||||||
|
m_protocol(NetProtocol_IPv4),
|
||||||
|
m_port(port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IpAddress(const IPv6& ip, UInt16 port) :
|
||||||
|
m_isValid(true),
|
||||||
|
m_ipv6(ip),
|
||||||
|
m_protocol(NetProtocol_IPv6),
|
||||||
|
m_port(port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IpAddress(const UInt8& a, const UInt8& b, const UInt8& c, const UInt8& d, UInt16 port) :
|
||||||
|
IpAddress(IPv4{a, b, c, d}, port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IpAddress(const UInt16& a, const UInt16& b, const UInt16& c, const UInt16& d, const UInt16& e, const UInt16& f, const UInt16& g, const UInt16& h, UInt16 port) :
|
||||||
|
IpAddress(IPv6{a, b, c, d, e, f, g, h}, port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IpAddress(const char* address)
|
||||||
|
{
|
||||||
|
BuildFromAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IpAddress(const String& address)
|
||||||
|
{
|
||||||
|
BuildFromAddress(address.GetConstBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt16 IpAddress::GetPort() const
|
||||||
|
{
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NetProtocol IpAddress::GetProtocol() const
|
||||||
|
{
|
||||||
|
return m_protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IpAddress::IsValid() const
|
||||||
|
{
|
||||||
|
return m_isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IpAddress::SetPort(UInt16 port)
|
||||||
|
{
|
||||||
|
m_port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IPv4 IpAddress::ToIPv4() const
|
||||||
|
{
|
||||||
|
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4");
|
||||||
|
|
||||||
|
return m_ipv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::IPv6 IpAddress::ToIPv6() const
|
||||||
|
{
|
||||||
|
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv6, "IP is not a valid IPv6");
|
||||||
|
|
||||||
|
return m_ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt32 IpAddress::ToUInt32() const
|
||||||
|
{
|
||||||
|
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4");
|
||||||
|
|
||||||
|
return UInt32(m_ipv4[0]) << 24 |
|
||||||
|
UInt32(m_ipv4[1]) << 16 |
|
||||||
|
UInt32(m_ipv4[2]) << 8 |
|
||||||
|
UInt32(m_ipv4[3]) << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress::operator bool() const
|
||||||
|
{
|
||||||
|
return IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, const IpAddress& address)
|
||||||
|
{
|
||||||
|
out << "IpAddress(" << address.ToString() << ')';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const IpAddress& first, const IpAddress& second)
|
||||||
|
{
|
||||||
|
// We need to check the validity of each address before comparing them
|
||||||
|
if (!first.m_isValid || !second.m_isValid)
|
||||||
|
return first.m_isValid == second.m_isValid;
|
||||||
|
|
||||||
|
// Then the protocol
|
||||||
|
if (first.m_protocol != second.m_protocol)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Each protocol has its variables to compare
|
||||||
|
switch (first.m_protocol)
|
||||||
|
{
|
||||||
|
case NetProtocol_IPv4:
|
||||||
|
{
|
||||||
|
if (first.m_ipv4 != second.m_ipv4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NetProtocol_IPv6:
|
||||||
|
{
|
||||||
|
if (first.m_ipv6 != second.m_ipv6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the port, in case there is one
|
||||||
|
if (first.m_port != second.m_port)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const IpAddress& first, const IpAddress& second)
|
||||||
|
{
|
||||||
|
return !operator==(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<(const IpAddress& first, const IpAddress& second)
|
||||||
|
{
|
||||||
|
// If the second address is invalid, there's no way we're lower than it
|
||||||
|
if (!second.m_isValid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// By this point, the second address is valid, thus check our validity
|
||||||
|
if (!first.m_isValid)
|
||||||
|
return true; // Invalid address are lower than valid one
|
||||||
|
|
||||||
|
// Compare protocols
|
||||||
|
if (first.m_protocol != second.m_protocol)
|
||||||
|
return first.m_protocol < second.m_protocol;
|
||||||
|
|
||||||
|
// Compare IP (thanks to std::array comparison operator)
|
||||||
|
switch (first.m_protocol)
|
||||||
|
{
|
||||||
|
case NetProtocol_IPv4:
|
||||||
|
{
|
||||||
|
if (first.m_ipv4 != second.m_ipv4)
|
||||||
|
return first.m_ipv4 < second.m_ipv4;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NetProtocol_IPv6:
|
||||||
|
{
|
||||||
|
if (first.m_ipv6 != second.m_ipv6)
|
||||||
|
return first.m_ipv6 < second.m_ipv6;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare port
|
||||||
|
if (first.m_port != second.m_port)
|
||||||
|
return first.m_port < second.m_port;
|
||||||
|
|
||||||
|
return false; //< Same address
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<=(const IpAddress& first, const IpAddress& second)
|
||||||
|
{
|
||||||
|
return !operator<(second, first);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator>(const IpAddress& first, const IpAddress& second)
|
||||||
|
{
|
||||||
|
return second < first;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator>=(const IpAddress& first, const IpAddress& second)
|
||||||
|
{
|
||||||
|
return !operator<(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_MODULENAME_HPP
|
||||||
|
#define NAZARA_MODULENAME_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/Initializer.hpp>
|
||||||
|
#include <Nazara/Network/Config.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class NAZARA_NETWORK_API Network
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Network() = delete;
|
||||||
|
~Network() = delete;
|
||||||
|
|
||||||
|
static bool Initialize();
|
||||||
|
|
||||||
|
static bool IsInitialized();
|
||||||
|
|
||||||
|
static void Uninitialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static unsigned int s_moduleReferenceCounter;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NAZARA_MODULENAME_HPP
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SOCKETHANDLE_HPP
|
||||||
|
#define NAZARA_SOCKETHANDLE_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <basetsd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
using SocketHandle = UINT_PTR;
|
||||||
|
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||||
|
using SocketHandle = int;
|
||||||
|
#else
|
||||||
|
#error Lack of implementation: SocketHandle
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NAZARA_SOCKETHANDLE_HPP
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_TCPBASE_HPP
|
||||||
|
#define NAZARA_TCPBASE_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Network/AbstractSocket.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class NAZARA_NETWORK_API TcpBase : public AbstractSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~TcpBase() = default;
|
||||||
|
|
||||||
|
inline bool IsLowDelayEnabled() const;
|
||||||
|
inline bool IsKeepAliveEnabled() const;
|
||||||
|
|
||||||
|
// Slots
|
||||||
|
NazaraSignal(OnStateChange, const TcpBase* /*socket*/, SocketState /*newState*/);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TcpBase();
|
||||||
|
TcpBase(TcpBase&& tcpBase);
|
||||||
|
|
||||||
|
virtual void OnOpened() override;
|
||||||
|
|
||||||
|
SocketState m_state;
|
||||||
|
UInt64 m_keepAliveInterval;
|
||||||
|
UInt64 m_keepAliveTime;
|
||||||
|
bool m_isLowDelayEnabled;
|
||||||
|
bool m_isKeepAliveEnabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/TcpBase.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_TCPBASE_HPP
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// 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 <utility>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline TcpBase::TcpBase() :
|
||||||
|
AbstractSocket(SocketType_TCP)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TcpBase::TcpBase(TcpBase&& tcpBase) :
|
||||||
|
AbstractSocket(std::move(tcpBase)),
|
||||||
|
m_state(tcpBase.m_state),
|
||||||
|
m_keepAliveInterval(tcpBase.m_keepAliveInterval),
|
||||||
|
m_keepAliveTime(tcpBase.m_keepAliveTime),
|
||||||
|
m_isLowDelayEnabled(tcpBase.m_isLowDelayEnabled),
|
||||||
|
m_isKeepAliveEnabled(tcpBase.m_isKeepAliveEnabled)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool TcpBase::IsLowDelayEnabled() const
|
||||||
|
{
|
||||||
|
return m_isLowDelayEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool TcpBase::IsKeepAliveEnabled() const
|
||||||
|
{
|
||||||
|
return m_isKeepAliveEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_TCPCLIENT_HPP
|
||||||
|
#define NAZARA_TCPCLIENT_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/Signal.hpp>
|
||||||
|
#include <Nazara/Network/TcpBase.hpp>
|
||||||
|
#include <Nazara/Network/IpAddress.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class NAZARA_NETWORK_API TcpClient : public TcpBase
|
||||||
|
{
|
||||||
|
friend class TcpServer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TcpClient() = default;
|
||||||
|
inline TcpClient(TcpClient&& tcpClient);
|
||||||
|
~TcpClient() = default;
|
||||||
|
|
||||||
|
SocketState Connect(const IpAddress& remoteAddress, UInt64 msTimeout = 3000);
|
||||||
|
inline void Disconnect();
|
||||||
|
|
||||||
|
void EnableLowDelay(bool lowDelay);
|
||||||
|
void EnableKeepAlive(bool keepAlive, UInt64 msTime = 10000, UInt64 msInterval = 1000);
|
||||||
|
|
||||||
|
inline UInt64 GetKeepAliveInterval() const;
|
||||||
|
inline UInt64 GetKeepAliveTime() const;
|
||||||
|
inline IpAddress GetRemoteAddress() const;
|
||||||
|
|
||||||
|
SocketState QueryState();
|
||||||
|
|
||||||
|
bool Receive(void* buffer, std::size_t size, std::size_t* received);
|
||||||
|
|
||||||
|
bool Send(const void* buffer, std::size_t size, std::size_t* sent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnClose() override;
|
||||||
|
void OnOpened() override;
|
||||||
|
|
||||||
|
void Reset(SocketHandle handle, const IpAddress& peerAddress);
|
||||||
|
|
||||||
|
IpAddress m_peerAddress;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/TcpClient.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_TCPCLIENT_HPP
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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 <utility>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline TcpClient::TcpClient(TcpClient&& tcpClient) :
|
||||||
|
TcpBase(std::move(tcpClient)),
|
||||||
|
m_peerAddress(std::move(tcpClient.m_peerAddress))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TcpClient::Disconnect()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt64 TcpClient::GetKeepAliveInterval() const
|
||||||
|
{
|
||||||
|
return m_keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt64 TcpClient::GetKeepAliveTime() const
|
||||||
|
{
|
||||||
|
return m_keepAliveTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress TcpClient::GetRemoteAddress() const
|
||||||
|
{
|
||||||
|
return m_peerAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_TCPSERVER_HPP
|
||||||
|
#define NAZARA_TCPSERVER_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Network/TcpBase.hpp>
|
||||||
|
#include <Nazara/Network/IpAddress.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class TcpClient;
|
||||||
|
|
||||||
|
class NAZARA_NETWORK_API TcpServer : public TcpBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TcpServer() = default;
|
||||||
|
inline TcpServer(TcpServer&& tcpServer);
|
||||||
|
~TcpServer() = default;
|
||||||
|
|
||||||
|
bool AcceptClient(TcpClient* newClient);
|
||||||
|
|
||||||
|
inline IpAddress GetBoundAddress() const;
|
||||||
|
inline UInt16 GetBoundPort() const;
|
||||||
|
|
||||||
|
inline SocketState Listen(NetProtocol protocol, UInt16 port, unsigned int queueSize = 10);
|
||||||
|
SocketState Listen(const IpAddress& address, unsigned int queueSize = 10);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnClose() override;
|
||||||
|
void OnOpened() override;
|
||||||
|
|
||||||
|
IpAddress m_boundAddress;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/TcpServer.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_TCPSERVER_HPP
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// 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 <utility>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline TcpServer::TcpServer(TcpServer&& tcpServer) :
|
||||||
|
TcpBase(std::move(tcpServer)),
|
||||||
|
m_boundAddress(std::move(tcpServer.m_boundAddress))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress TcpServer::GetBoundAddress() const
|
||||||
|
{
|
||||||
|
return m_boundAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt16 TcpServer::GetBoundPort() const
|
||||||
|
{
|
||||||
|
return m_boundAddress.GetPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SocketState TcpServer::Listen(NetProtocol protocol, UInt16 port, unsigned int queueSize)
|
||||||
|
{
|
||||||
|
NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO
|
||||||
|
|
||||||
|
IpAddress any;
|
||||||
|
switch (protocol)
|
||||||
|
{
|
||||||
|
case NetProtocol_IPv4:
|
||||||
|
any = IpAddress::AnyIpV4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NetProtocol_IPv6:
|
||||||
|
any = IpAddress::AnyIpV6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
any.SetPort(port);
|
||||||
|
return Listen(any, queueSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_UDPSOCKET_HPP
|
||||||
|
#define NAZARA_UDPSOCKET_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Network/AbstractSocket.hpp>
|
||||||
|
#include <Nazara/Network/IpAddress.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class NAZARA_NETWORK_API UdpSocket : public AbstractSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline UdpSocket();
|
||||||
|
inline UdpSocket(NetProtocol protocol);
|
||||||
|
inline UdpSocket(UdpSocket&& udpSocket);
|
||||||
|
~UdpSocket() = default;
|
||||||
|
|
||||||
|
inline SocketState Bind(UInt16 port);
|
||||||
|
SocketState Bind(const IpAddress& address);
|
||||||
|
|
||||||
|
inline bool Create(NetProtocol protocol);
|
||||||
|
|
||||||
|
inline IpAddress GetBoundAddress() const;
|
||||||
|
inline UInt16 GetBoundPort() const;
|
||||||
|
inline SocketState GetState() const;
|
||||||
|
|
||||||
|
unsigned int QueryMaxDatagramSize();
|
||||||
|
|
||||||
|
bool Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received);
|
||||||
|
|
||||||
|
bool Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnClose() override;
|
||||||
|
void OnOpened() override;
|
||||||
|
|
||||||
|
IpAddress m_boundAddress;
|
||||||
|
SocketState m_state;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/UdpSocket.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_UDPSOCKET_HPP
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// 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/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline UdpSocket::UdpSocket() :
|
||||||
|
AbstractSocket(SocketType_UDP)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UdpSocket::UdpSocket(NetProtocol protocol) :
|
||||||
|
UdpSocket()
|
||||||
|
{
|
||||||
|
Create(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UdpSocket::UdpSocket(UdpSocket&& udpSocket) :
|
||||||
|
AbstractSocket(std::move(udpSocket)),
|
||||||
|
m_boundAddress(std::move(udpSocket.m_boundAddress)),
|
||||||
|
m_state(udpSocket.m_state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SocketState UdpSocket::Bind(UInt16 port)
|
||||||
|
{
|
||||||
|
IpAddress any;
|
||||||
|
switch (m_protocol)
|
||||||
|
{
|
||||||
|
case NetProtocol_IPv4:
|
||||||
|
any = IpAddress::AnyIpV4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NetProtocol_IPv6:
|
||||||
|
any = IpAddress::AnyIpV6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
any.SetPort(port);
|
||||||
|
return Bind(any);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UdpSocket::Create(NetProtocol protocol)
|
||||||
|
{
|
||||||
|
return Open(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IpAddress UdpSocket::GetBoundAddress() const
|
||||||
|
{
|
||||||
|
return m_boundAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt16 UdpSocket::GetBoundPort() const
|
||||||
|
{
|
||||||
|
return m_boundAddress.GetPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SocketState UdpSocket::GetState() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/AbstractSocket.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <utility>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Socket
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
AbstractSocket::AbstractSocket(SocketType type) :
|
||||||
|
m_handle(SocketImpl::InvalidHandle),
|
||||||
|
m_state(SocketState_NotConnected),
|
||||||
|
m_type(type),
|
||||||
|
m_isBlockingEnabled(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractSocket::AbstractSocket(AbstractSocket&& abstractSocket) :
|
||||||
|
m_protocol(abstractSocket.m_protocol),
|
||||||
|
m_lastError(abstractSocket.m_lastError),
|
||||||
|
m_handle(abstractSocket.m_handle),
|
||||||
|
m_state(abstractSocket.m_state),
|
||||||
|
m_type(abstractSocket.m_type),
|
||||||
|
m_isBlockingEnabled(abstractSocket.m_isBlockingEnabled)
|
||||||
|
{
|
||||||
|
abstractSocket.m_handle = SocketImpl::InvalidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractSocket::~AbstractSocket()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSocket::Close()
|
||||||
|
{
|
||||||
|
if (m_handle != SocketImpl::InvalidHandle)
|
||||||
|
{
|
||||||
|
OnClose();
|
||||||
|
|
||||||
|
SocketImpl::Close(m_handle);
|
||||||
|
m_handle = SocketImpl::InvalidHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSocket::EnableBlocking(bool blocking)
|
||||||
|
{
|
||||||
|
if (m_isBlockingEnabled != blocking)
|
||||||
|
{
|
||||||
|
if (m_handle != SocketImpl::InvalidHandle)
|
||||||
|
SocketImpl::SetBlocking(m_handle, blocking, &m_lastError);
|
||||||
|
|
||||||
|
m_isBlockingEnabled = blocking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int AbstractSocket::QueryAvailableBytes() const
|
||||||
|
{
|
||||||
|
if (m_handle == SocketImpl::InvalidHandle)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return SocketImpl::QueryAvailableBytes(m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSocket::OnClose()
|
||||||
|
{
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSocket::OnOpened()
|
||||||
|
{
|
||||||
|
SocketError error;
|
||||||
|
if (!SocketImpl::SetBlocking(m_handle, m_isBlockingEnabled, &error))
|
||||||
|
NazaraWarning("Failed to set socket blocking mode (0x" + String::Number(ERROR, 16) + ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractSocket::Open(NetProtocol protocol)
|
||||||
|
{
|
||||||
|
if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol)
|
||||||
|
{
|
||||||
|
SocketHandle handle = SocketImpl::Create(protocol, m_type, &m_lastError);
|
||||||
|
if (handle == SocketImpl::InvalidHandle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_protocol = protocol;
|
||||||
|
Open(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSocket::Open(SocketHandle handle)
|
||||||
|
{
|
||||||
|
NazaraAssert(handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||||
|
|
||||||
|
Close();
|
||||||
|
|
||||||
|
m_handle = handle;
|
||||||
|
OnOpened();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,257 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/Algorithm.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead)
|
||||||
|
{
|
||||||
|
const char* ptr = str;
|
||||||
|
unsigned int val = 0;
|
||||||
|
while (*ptr >= '0' && *ptr <= '9')
|
||||||
|
{
|
||||||
|
val *= 10;
|
||||||
|
val += *ptr - '0';
|
||||||
|
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str == ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (number)
|
||||||
|
*number = val;
|
||||||
|
|
||||||
|
if (endOfRead)
|
||||||
|
*endOfRead = ptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead)
|
||||||
|
{
|
||||||
|
const char* ptr = str;
|
||||||
|
unsigned int val = 0;
|
||||||
|
while ((*ptr >= '0' && *ptr <= '9') || ((*ptr & 0x5F) >= 'A' && (*ptr & 0x5F) <= 'F'))
|
||||||
|
{
|
||||||
|
val *= 16;
|
||||||
|
val += (*ptr > '9') ? ((*ptr & 0x5F) - 'A' + 10) : *ptr - '0';
|
||||||
|
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str == ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (number)
|
||||||
|
*number = val;
|
||||||
|
|
||||||
|
if (endOfRead)
|
||||||
|
*endOfRead = ptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From http://rosettacode.org/wiki/Parse_an_IP_Address
|
||||||
|
// Parse a textual IPv4 or IPv6 address, optionally with port, into a binary
|
||||||
|
// array (for the address, in host order), and an optionally provided port.
|
||||||
|
// Also, indicate which of those forms (4 or 6) was parsed.
|
||||||
|
bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead)
|
||||||
|
{
|
||||||
|
NazaraAssert(addressPtr, "Invalid address string");
|
||||||
|
NazaraAssert(result, "Invalid result pointer");
|
||||||
|
|
||||||
|
//find first colon, dot, and open bracket
|
||||||
|
const char* colonPtr = std::strchr(addressPtr, ':');
|
||||||
|
const char* dotPtr = std::strchr(addressPtr, '.');
|
||||||
|
const char* openBracketPtr = std::strchr(addressPtr, '[');
|
||||||
|
|
||||||
|
// we'll consider this to (probably) be IPv6 if we find an open
|
||||||
|
// bracket, or an absence of dots, or if there is a colon, and it
|
||||||
|
// precedes any dots that may or may not be there
|
||||||
|
bool detectedIPv6 = openBracketPtr || !dotPtr || (colonPtr && (!dotPtr || colonPtr < dotPtr));
|
||||||
|
|
||||||
|
// OK, now do a little further sanity check our initial guess...
|
||||||
|
if (detectedIPv6)
|
||||||
|
{
|
||||||
|
// if open bracket, then must have close bracket that follows somewhere
|
||||||
|
const char* closeBracketPtr = std::strchr(addressPtr, ']');
|
||||||
|
if (openBracketPtr && (!closeBracketPtr || closeBracketPtr < openBracketPtr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else // probably ipv4
|
||||||
|
{
|
||||||
|
// dots must exist, and precede any colons
|
||||||
|
if (!dotPtr || (colonPtr && colonPtr < dotPtr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK, there should be no correctly formed strings which are miscategorized,
|
||||||
|
// and now any format errors will be found out as we continue parsing
|
||||||
|
// according to plan.
|
||||||
|
if (!detectedIPv6) //try to parse as IPv4
|
||||||
|
{
|
||||||
|
// 4 dotted quad decimal; optional port if there is a colon
|
||||||
|
// since there are just 4, and because the last one can be terminated
|
||||||
|
// differently, I'm just going to unroll any potential loop.
|
||||||
|
UInt8* resultPtr = result;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
unsigned int value;
|
||||||
|
if (!Detail::ParseDecimal(addressPtr, &value, &addressPtr) || value > 255) //must be in range and followed by dot and nonempty
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
if (*addressPtr != '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
addressPtr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*resultPtr++ = static_cast<UInt8>(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // try to parse as IPv6
|
||||||
|
{
|
||||||
|
UInt8* resultPtr;
|
||||||
|
UInt8* zeroLoc;
|
||||||
|
|
||||||
|
// up to 8 16-bit hex quantities, separated by colons, with at most one
|
||||||
|
// empty quantity, acting as a stretchy run of zeros. optional port
|
||||||
|
// if there are brackets followed by colon and decimal port number.
|
||||||
|
// A further form allows an ipv4 dotted quad instead of the last two
|
||||||
|
// 16-bit quantities, but only if in the ipv4 space ::ffff:x:x .
|
||||||
|
|
||||||
|
if (openBracketPtr) // start past the open bracket, if it exists
|
||||||
|
addressPtr = openBracketPtr + 1;
|
||||||
|
|
||||||
|
resultPtr = result;
|
||||||
|
zeroLoc = nullptr; // if we find a 'zero compression' location
|
||||||
|
|
||||||
|
bool mappedIPv4 = false;
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < 8; ++i) // we've got up to 8 of these, so we will use a loop
|
||||||
|
{
|
||||||
|
const char* savedPtr = addressPtr;
|
||||||
|
unsigned int value; // get value; these are hex
|
||||||
|
if (!Detail::ParseHexadecimal(addressPtr, &value, &addressPtr)) // if empty, we are zero compressing; note the loc
|
||||||
|
{
|
||||||
|
if (zeroLoc) //there can be only one!
|
||||||
|
{
|
||||||
|
// unless it's a terminal empty field, then this is OK, it just means we're done with the host part
|
||||||
|
if (resultPtr == zeroLoc)
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // otherwise, it's a format error
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*addressPtr != ':') // empty field can only be via :
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (i == 0 && *++addressPtr != ':') // leading zero compression requires an extra peek, and adjustment
|
||||||
|
return false;
|
||||||
|
|
||||||
|
zeroLoc = resultPtr;
|
||||||
|
++addressPtr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ('.' == *addressPtr) // special case of ipv4 convenience notation
|
||||||
|
{
|
||||||
|
addressPtr = savedPtr;
|
||||||
|
|
||||||
|
// who knows how to parse ipv4? we do!
|
||||||
|
UInt8 result[16];
|
||||||
|
bool isIPv6;
|
||||||
|
if (!ParseIPAddress(addressPtr, result, nullptr, &isIPv6, &addressPtr) || isIPv6) // must parse and must be ipv4
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// transfer addrlocal into the present location
|
||||||
|
for (unsigned int j = 0; j < 4; ++j)
|
||||||
|
*(resultPtr++) = result[j];
|
||||||
|
|
||||||
|
++i; // pretend like we took another short, since the ipv4 effectively is two shorts
|
||||||
|
mappedIPv4 = true; // remember how we got here for further validation later
|
||||||
|
break; // totally done with address
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > 65535) // must be 16 bit quantity
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*(resultPtr++) = value >> 8;
|
||||||
|
*(resultPtr++) = value & 0xFF;
|
||||||
|
|
||||||
|
if (*addressPtr == ':') // typical case inside; carry on
|
||||||
|
++addressPtr;
|
||||||
|
else // some other terminating character; done with this parsing parts
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle any zero compression we found
|
||||||
|
if (zeroLoc)
|
||||||
|
{
|
||||||
|
std::ptrdiff_t nHead = (int) (zeroLoc - result); // how much before zero compression
|
||||||
|
std::ptrdiff_t nTail = i * 2 - nHead; // how much after zero compression
|
||||||
|
std::ptrdiff_t nZeros = 16 - nTail - nHead; // how much zeros
|
||||||
|
std::memmove(&result[16 - nTail], zeroLoc, nTail); // scootch stuff down
|
||||||
|
std::memset(zeroLoc, 0, nZeros); // clear the compressed zeros
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation of ipv4 subspace ::ffff:x.x
|
||||||
|
if (mappedIPv4)
|
||||||
|
{
|
||||||
|
static const UInt8 abyPfx[] = {0,0, 0,0, 0,0, 0,0, 0,0, 0xFF,0xFF};
|
||||||
|
if (std::memcmp(result, abyPfx, sizeof(abyPfx)) != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close bracket
|
||||||
|
if (openBracketPtr)
|
||||||
|
{
|
||||||
|
if (*addressPtr != ']')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++addressPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if asked to read the port
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
if (*addressPtr == ':') // have port part
|
||||||
|
{
|
||||||
|
++addressPtr; // past the colon
|
||||||
|
|
||||||
|
unsigned int portValue;
|
||||||
|
if (!Detail::ParseDecimal(addressPtr, &portValue, nullptr) || portValue > 65535)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (port)
|
||||||
|
*port = static_cast<UInt16>(portValue);
|
||||||
|
}
|
||||||
|
else // finished just with IP address
|
||||||
|
*port = 0; // indicate we have no port part
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIPv6)
|
||||||
|
*isIPv6 = detectedIPv6;
|
||||||
|
|
||||||
|
if (endOfRead)
|
||||||
|
*endOfRead = addressPtr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 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/Config.hpp>
|
||||||
|
#if NAZARA_NETWORK_MANAGE_MEMORY
|
||||||
|
|
||||||
|
#include <Nazara/Core/MemoryManager.hpp>
|
||||||
|
#include <new> // Is this necessary ?
|
||||||
|
|
||||||
|
void* operator new(std::size_t size)
|
||||||
|
{
|
||||||
|
return Nz::MemoryManager::Allocate(size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* operator new[](std::size_t size)
|
||||||
|
{
|
||||||
|
return Nz::MemoryManager::Allocate(size, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void* pointer) noexcept
|
||||||
|
{
|
||||||
|
Nz::MemoryManager::Free(pointer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void* pointer) noexcept
|
||||||
|
{
|
||||||
|
Nz::MemoryManager::Free(pointer, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NAZARA_NETWORK_MANAGE_MEMORY
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
// 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 <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Core/StringStream.hpp>
|
||||||
|
#include <Nazara/Network/Algorithm.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <Nazara/Network/SystemSocket.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/IpAddressImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Network
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
bool IpAddress::BuildFromAddress(const char* address)
|
||||||
|
{
|
||||||
|
m_isValid = false;
|
||||||
|
|
||||||
|
bool isIPv6;
|
||||||
|
UInt8 result[16];
|
||||||
|
if (!ParseIPAddress(address, result, &m_port, &isIPv6, nullptr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_isValid = true;
|
||||||
|
if (isIPv6)
|
||||||
|
{
|
||||||
|
m_protocol = NetProtocol_IPv6;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 8; ++i)
|
||||||
|
m_ipv6[i] = UInt32(result[i*2]) << 8 | result[i*2 + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_protocol = NetProtocol_IPv4;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
m_ipv4[i] = result[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpAddress::IsLoopback() const
|
||||||
|
{
|
||||||
|
if (!m_isValid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NazaraAssert(m_protocol <= NetProtocol_Max, "Protocol has value out of enum");
|
||||||
|
switch (m_protocol)
|
||||||
|
{
|
||||||
|
case NetProtocol_IPv4:
|
||||||
|
return m_ipv4[0] == 127;
|
||||||
|
|
||||||
|
case NetProtocol_IPv6:
|
||||||
|
return m_ipv6 == LoopbackIpV6.m_ipv6; // Only compare the ip value
|
||||||
|
}
|
||||||
|
|
||||||
|
NazaraInternalError("Invalid protocol for IpAddress (0x" + String::Number(m_protocol) + ')');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String IpAddress::ToString() const
|
||||||
|
{
|
||||||
|
StringStream stream;
|
||||||
|
|
||||||
|
if (m_isValid)
|
||||||
|
{
|
||||||
|
NazaraAssert(m_protocol <= NetProtocol_Max, "Protocol has value out of enum");
|
||||||
|
switch (m_protocol)
|
||||||
|
{
|
||||||
|
case NetProtocol_IPv4:
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
stream << int(m_ipv4[i]);
|
||||||
|
if (i != 3)
|
||||||
|
stream << '.';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NetProtocol_IPv6:
|
||||||
|
// Canonical representation of an IPv6
|
||||||
|
// https://tools.ietf.org/html/rfc5952
|
||||||
|
|
||||||
|
// Find the longest zero sequence
|
||||||
|
int f0 = -1;
|
||||||
|
int l0 = -1;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if (m_ipv6[i] == 0)
|
||||||
|
{
|
||||||
|
unsigned int j;
|
||||||
|
for (j = i + 1; j < 8; ++j)
|
||||||
|
{
|
||||||
|
if (m_ipv6[j] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j - i > std::max<unsigned int>(l0 - f0, 1))
|
||||||
|
{
|
||||||
|
f0 = i;
|
||||||
|
l0 = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need brackets around our IPv6 address if we have a port
|
||||||
|
if (m_port != 0)
|
||||||
|
stream << '[';
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if (i == f0)
|
||||||
|
{
|
||||||
|
stream << "::";
|
||||||
|
i = l0;
|
||||||
|
if (i >= 8)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (i != 0)
|
||||||
|
stream << ':';
|
||||||
|
|
||||||
|
stream << String::Number(m_ipv6[i], 16).ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_port != 0)
|
||||||
|
stream << ']';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_port != 0)
|
||||||
|
stream << ':' << m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
String IpAddress::ResolveAddress(const IpAddress& address, String* service)
|
||||||
|
{
|
||||||
|
String hostname;
|
||||||
|
IpAddressImpl::ResolveAddress(address, &hostname, service);
|
||||||
|
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HostnameInfo> IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service)
|
||||||
|
{
|
||||||
|
return IpAddressImpl::ResolveHostname(protocol, hostname, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddress IpAddress::AnyIpV4(0, 0, 0, 0);
|
||||||
|
IpAddress IpAddress::AnyIpV6(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
IpAddress IpAddress::BroadcastIpV4(255, 255, 255, 255);
|
||||||
|
IpAddress IpAddress::Invalid;
|
||||||
|
IpAddress IpAddress::LoopbackIpV4(127, 0, 0, 1);
|
||||||
|
IpAddress IpAddress::LoopbackIpV6(0, 0, 0, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
// 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/Network.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Core/Core.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Core/Log.hpp>
|
||||||
|
#include <Nazara/Network/Config.hpp>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Network
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
bool Network::Initialize()
|
||||||
|
{
|
||||||
|
if (s_moduleReferenceCounter > 0)
|
||||||
|
{
|
||||||
|
s_moduleReferenceCounter++;
|
||||||
|
return true; // Already initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize module dependencies
|
||||||
|
if (!Core::Initialize())
|
||||||
|
{
|
||||||
|
NazaraError("Failed to initialize core module");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_moduleReferenceCounter++;
|
||||||
|
|
||||||
|
CallOnExit onExit(Network::Uninitialize);
|
||||||
|
|
||||||
|
// Initialize module here
|
||||||
|
if (!SocketImpl::Initialize())
|
||||||
|
{
|
||||||
|
NazaraError("Failed to initialize socket implementation");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onExit.Reset();
|
||||||
|
|
||||||
|
NazaraNotice("Initialized: Network module");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Network::IsInitialized()
|
||||||
|
{
|
||||||
|
return s_moduleReferenceCounter != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::Uninitialize()
|
||||||
|
{
|
||||||
|
if (s_moduleReferenceCounter != 1)
|
||||||
|
{
|
||||||
|
// Either the module is not initialized, either it was initialized multiple times
|
||||||
|
if (s_moduleReferenceCounter > 1)
|
||||||
|
s_moduleReferenceCounter--;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_moduleReferenceCounter = 0;
|
||||||
|
|
||||||
|
// Uninitialize module here
|
||||||
|
SocketImpl::Uninitialize();
|
||||||
|
|
||||||
|
NazaraNotice("Uninitialized: Network module");
|
||||||
|
|
||||||
|
// Free module dependencies
|
||||||
|
Core::Uninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Network::s_moduleReferenceCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/TcpBase.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <limits>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Socket
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
void TcpBase::OnOpened()
|
||||||
|
{
|
||||||
|
AbstractSocket::OnOpened();
|
||||||
|
|
||||||
|
m_isLowDelayEnabled = false; //< Nagle's algorithm, is this enabled everywhere?
|
||||||
|
m_isKeepAliveEnabled = false; //< default documentation value, OS can change this (TODO: Query OS default value)
|
||||||
|
m_keepAliveInterval = 1000; //< default documentation value, OS can change this (TODO: Query OS default value)
|
||||||
|
m_keepAliveTime = 7200000; //< default documentation value, OS can change this (TODO: Query OS default value)
|
||||||
|
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/TcpClient.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <limits>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Socket
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
SocketState TcpClient::Connect(const IpAddress& remoteAddress, UInt64 msTimeout)
|
||||||
|
{
|
||||||
|
NazaraAssert(remoteAddress.IsValid(), "Invalid remote address");
|
||||||
|
NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port");
|
||||||
|
|
||||||
|
Open(remoteAddress.GetProtocol());
|
||||||
|
|
||||||
|
CallOnExit restoreBlocking;
|
||||||
|
if (m_isBlockingEnabled)
|
||||||
|
{
|
||||||
|
SocketImpl::SetBlocking(m_handle, false);
|
||||||
|
restoreBlocking.Reset([this] ()
|
||||||
|
{
|
||||||
|
SocketImpl::SetBlocking(m_handle, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketState state;
|
||||||
|
if (msTimeout > 0)
|
||||||
|
state = SocketImpl::Connect(m_handle, remoteAddress, msTimeout, &m_lastError);
|
||||||
|
else
|
||||||
|
state = SocketImpl::Connect(m_handle, remoteAddress, &m_lastError);
|
||||||
|
|
||||||
|
if (state != SocketState_NotConnected)
|
||||||
|
m_peerAddress = remoteAddress;
|
||||||
|
|
||||||
|
ChangeState(state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::EnableLowDelay(bool lowDelay)
|
||||||
|
{
|
||||||
|
if (m_isLowDelayEnabled != lowDelay)
|
||||||
|
{
|
||||||
|
SocketImpl::SetBlocking(m_handle, lowDelay, &m_lastError);
|
||||||
|
m_isLowDelayEnabled = lowDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::EnableKeepAlive(bool keepAlive, UInt64 msTime, UInt64 msInterval)
|
||||||
|
{
|
||||||
|
if (m_isKeepAliveEnabled != keepAlive || m_keepAliveTime != msTime || m_keepAliveInterval != msInterval)
|
||||||
|
{
|
||||||
|
SocketImpl::SetKeepAlive(m_handle, keepAlive, msTime, msInterval, &m_lastError);
|
||||||
|
m_isKeepAliveEnabled = keepAlive;
|
||||||
|
m_keepAliveInterval = msInterval;
|
||||||
|
m_keepAliveTime = msTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketState TcpClient::QueryState()
|
||||||
|
{
|
||||||
|
// Check our state depending on our last state
|
||||||
|
switch (m_state)
|
||||||
|
{
|
||||||
|
case SocketState_Connecting:
|
||||||
|
{
|
||||||
|
// If we were connecting, check how it's going
|
||||||
|
SocketError getError;
|
||||||
|
SocketError error = SocketImpl::GetLastError(m_handle, &getError);
|
||||||
|
|
||||||
|
if (getError != SocketError_NoError)
|
||||||
|
break; //< Do not update state if we cannot get socket state
|
||||||
|
|
||||||
|
if (error == SocketError_NoError)
|
||||||
|
{
|
||||||
|
// No error yet, we're still connecting or connected, check that by connecting again
|
||||||
|
return Connect(m_peerAddress, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Our connection attempt failed
|
||||||
|
m_lastError = error;
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Check our peer address, if it works we're connected
|
||||||
|
SocketError error;
|
||||||
|
m_peerAddress = SocketImpl::QueryPeerAddress(m_handle, &error);
|
||||||
|
if (m_peerAddress == IpAddress::Invalid)
|
||||||
|
{
|
||||||
|
// Other errors mean a problem while getting the peer address
|
||||||
|
if (error == SocketError_ConnectionClosed)
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ChangeState(SocketState_Connected); // If we are not connecting and have a peer address, we are connected
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpClient::Receive(void* buffer, std::size_t size, std::size_t* received)
|
||||||
|
{
|
||||||
|
NazaraAssert(buffer && size > 0, "Invalid buffer");
|
||||||
|
|
||||||
|
int read;
|
||||||
|
if (!SocketImpl::Receive(m_handle, buffer, static_cast<int>(size), &read, &m_lastError))
|
||||||
|
{
|
||||||
|
switch (m_lastError)
|
||||||
|
{
|
||||||
|
case SocketError_ConnectionClosed:
|
||||||
|
case SocketError_ConnectionRefused:
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (received)
|
||||||
|
*received = read;
|
||||||
|
|
||||||
|
ChangeState(SocketState_Connected);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpClient::Send(const void* buffer, std::size_t size, std::size_t* sent)
|
||||||
|
{
|
||||||
|
NazaraAssert(buffer && size > 0, "Invalid buffer");
|
||||||
|
|
||||||
|
CallOnExit updateSent;
|
||||||
|
std::size_t totalByteSent = 0;
|
||||||
|
if (sent)
|
||||||
|
{
|
||||||
|
updateSent.Reset([sent, &totalByteSent] ()
|
||||||
|
{
|
||||||
|
*sent = totalByteSent;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
while (totalByteSent < size)
|
||||||
|
{
|
||||||
|
int sendSize = static_cast<int>(std::min<std::size_t>(size - totalByteSent, std::numeric_limits<int>::max())); //< Handle very large send
|
||||||
|
int sentSize;
|
||||||
|
if (!SocketImpl::Send(m_handle, reinterpret_cast<const UInt8*>(buffer) + totalByteSent, sendSize, &sentSize, &m_lastError))
|
||||||
|
{
|
||||||
|
switch (m_lastError)
|
||||||
|
{
|
||||||
|
case SocketError_ConnectionClosed:
|
||||||
|
case SocketError_ConnectionRefused:
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalByteSent += sentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeState(SocketState_Connected);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::OnClose()
|
||||||
|
{
|
||||||
|
TcpBase::OnClose();
|
||||||
|
|
||||||
|
m_peerAddress = IpAddress::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::OnOpened()
|
||||||
|
{
|
||||||
|
TcpBase::OnOpened();
|
||||||
|
|
||||||
|
m_peerAddress = IpAddress::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::Reset(SocketHandle handle, const IpAddress& peerAddress)
|
||||||
|
{
|
||||||
|
Open(handle);
|
||||||
|
m_peerAddress = peerAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/TcpServer.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Network/TcpClient.hpp>
|
||||||
|
#include <limits>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Socket
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
bool TcpServer::AcceptClient(TcpClient* newClient)
|
||||||
|
{
|
||||||
|
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Server isn't listening");
|
||||||
|
NazaraAssert(newClient, "Invalid client socket");
|
||||||
|
|
||||||
|
IpAddress clientAddress;
|
||||||
|
SocketHandle handle = SocketImpl::Accept(m_handle, &clientAddress, &m_lastError);
|
||||||
|
if (handle != SocketImpl::InvalidHandle)
|
||||||
|
{
|
||||||
|
newClient->Reset(handle, clientAddress);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketState TcpServer::Listen(const IpAddress& address, unsigned int queueSize)
|
||||||
|
{
|
||||||
|
NazaraAssert(address.IsValid(), "Invalid address");
|
||||||
|
|
||||||
|
Open(address.GetProtocol());
|
||||||
|
|
||||||
|
SocketState state = SocketImpl::Listen(m_handle, address, queueSize, &m_lastError);
|
||||||
|
if (state == SocketState_Bound)
|
||||||
|
m_boundAddress = SocketImpl::QuerySocketAddress(m_handle);
|
||||||
|
|
||||||
|
ChangeState(state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::OnClose()
|
||||||
|
{
|
||||||
|
TcpBase::OnClose();
|
||||||
|
|
||||||
|
m_boundAddress = IpAddress::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::OnOpened()
|
||||||
|
{
|
||||||
|
TcpBase::OnOpened();
|
||||||
|
|
||||||
|
m_boundAddress = IpAddress::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Network/UdpSocket.hpp>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#else
|
||||||
|
#error Missing implementation: Socket
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
SocketState UdpSocket::Bind(const IpAddress& address)
|
||||||
|
{
|
||||||
|
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
|
||||||
|
NazaraAssert(address.IsValid(), "Invalid address");
|
||||||
|
|
||||||
|
SocketState state = SocketImpl::Bind(m_handle, address, &m_lastError);
|
||||||
|
if (state == SocketState_Bound)
|
||||||
|
m_boundAddress = SocketImpl::QuerySocketAddress(m_handle);
|
||||||
|
|
||||||
|
ChangeState(state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int UdpSocket::QueryMaxDatagramSize()
|
||||||
|
{
|
||||||
|
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
|
||||||
|
|
||||||
|
return SocketImpl::QueryMaxDatagramSize(m_handle, &m_lastError);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UdpSocket::Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received)
|
||||||
|
{
|
||||||
|
NazaraAssert(buffer && size > 0, "Invalid buffer");
|
||||||
|
|
||||||
|
int read;
|
||||||
|
if (!SocketImpl::ReceiveFrom(m_handle, buffer, static_cast<int>(size), from, &read, &m_lastError))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (received)
|
||||||
|
*received = read;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UdpSocket::Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent)
|
||||||
|
{
|
||||||
|
NazaraAssert(to.IsValid(), "Invalid ip address");
|
||||||
|
NazaraAssert(to.GetProtocol() == m_protocol, "IP Address has a different protocol than the socket");
|
||||||
|
NazaraAssert(buffer && size > 0, "Invalid buffer");
|
||||||
|
|
||||||
|
int byteSent;
|
||||||
|
if (!SocketImpl::SendTo(m_handle, buffer, static_cast<int>(size), to, &byteSent, &m_lastError))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (sent)
|
||||||
|
*sent = byteSent;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpSocket::OnClose()
|
||||||
|
{
|
||||||
|
m_boundAddress = IpAddress::Invalid;
|
||||||
|
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpSocket::OnOpened()
|
||||||
|
{
|
||||||
|
m_boundAddress = IpAddress::Invalid;
|
||||||
|
|
||||||
|
ChangeState(SocketState_NotConnected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,240 @@
|
||||||
|
// 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/Win32/IpAddressImpl.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
#if NAZARA_CORE_WINDOWS_VISTA
|
||||||
|
using addrinfoImpl = addrinfoW;
|
||||||
|
|
||||||
|
int GetAddressInfo(const String& hostname, const String& service, const addrinfoImpl* hints, addrinfoImpl** results)
|
||||||
|
{
|
||||||
|
return GetAddrInfoW(hostname.GetWideString().c_str(), service.GetWideString().c_str(), &hints, &servinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetHostnameInfo(sockaddr* socketAddress, socklen_t socketLen, String* hostname, String* service)
|
||||||
|
{
|
||||||
|
std::array<wchar_t, NI_MAXHOST> hostnameBuffer;
|
||||||
|
std::array<wchar_t, NI_MAXSERV> serviceBuffer;
|
||||||
|
|
||||||
|
int result = GetNameInfoW(socketAddress, socketLen, hostnameBuffer.data(), hostnameBuffer.size(), serviceBuffer.data(), serviceBuffer.size(), NI_NUMERICSERV);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
if (hostname)
|
||||||
|
hostname->Set(hostnameBuffer.data());
|
||||||
|
|
||||||
|
if (service)
|
||||||
|
service->Set(serviceBuffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeAddressInfo(addrinfoImpl* results)
|
||||||
|
{
|
||||||
|
FreeAddrInfoW(results);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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(), NI_NUMERICSERV);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
if (hostname)
|
||||||
|
hostname->Set(hostnameBuffer.data());
|
||||||
|
|
||||||
|
if (service)
|
||||||
|
service->Set(serviceBuffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeAddressInfo(addrinfoImpl* results)
|
||||||
|
{
|
||||||
|
freeaddrinfo(results);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddress IpAddressImpl::FromAddrinfo(const addrinfo* info)
|
||||||
|
{
|
||||||
|
switch (info->ai_family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
{
|
||||||
|
sockaddr_in* ipv4 = reinterpret_cast<sockaddr_in*>(info->ai_addr);
|
||||||
|
|
||||||
|
auto& rawIpV4 = ipv4->sin_addr.S_un.S_un_b;
|
||||||
|
return IpAddress(rawIpV4.s_b1, rawIpV4.s_b2, rawIpV4.s_b3, rawIpV4.s_b4, ntohs(ipv4->sin_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
sockaddr_in6* ipv6 = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
|
||||||
|
|
||||||
|
auto& rawIpV6 = ipv6->sin6_addr.u.Word;
|
||||||
|
return IpAddress(rawIpV6[0], rawIpV6[1], rawIpV6[2], rawIpV6[3], rawIpV6[4], rawIpV6[5], rawIpV6[6], rawIpV6[7], ntohs(ipv6->sin6_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IpAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddress IpAddressImpl::FromAddrinfo(const addrinfoW* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in* addressv4)
|
||||||
|
{
|
||||||
|
auto& rawIpV4 = addressv4->sin_addr.S_un.S_un_b;
|
||||||
|
return IpAddress(rawIpV4.s_b1, rawIpV4.s_b2, rawIpV4.s_b3, rawIpV4.s_b4, ntohs(addressv4->sin_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in6* addressv6)
|
||||||
|
{
|
||||||
|
auto& rawIpV6 = addressv6->sin6_addr.u.Word;
|
||||||
|
return IpAddress(rawIpV6[0], rawIpV6[1], rawIpV6[2], rawIpV6[3], rawIpV6[4], rawIpV6[5], rawIpV6[6], rawIpV6[7], ntohs(addressv6->sin6_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service)
|
||||||
|
{
|
||||||
|
SockAddrBuffer socketAddress;
|
||||||
|
socklen_t socketAddressLen = ToSockAddr(ipAddress, socketAddress.data());
|
||||||
|
|
||||||
|
return Detail::GetHostnameInfo(reinterpret_cast<sockaddr*>(socketAddress.data()), socketAddressLen, hostname, service) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HostnameInfo> IpAddressImpl::ResolveHostname(NetProtocol procol, const String& hostname, const String& service)
|
||||||
|
{
|
||||||
|
std::vector<HostnameInfo> results;
|
||||||
|
|
||||||
|
Detail::addrinfoImpl hints;
|
||||||
|
std::memset(&hints, 0, sizeof(Detail::addrinfoImpl));
|
||||||
|
hints.ai_family = SocketImpl::TranslateNetProtocolToAF(procol);
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
|
Detail::addrinfoImpl* servinfo;
|
||||||
|
int rv;
|
||||||
|
if ((rv = Detail::GetAddressInfo(hostname, service, &hints, &servinfo)) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||||
|
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.family = p->ai_family;
|
||||||
|
result.flags = p->ai_flags;
|
||||||
|
result.socketType = p->ai_socktype;
|
||||||
|
|
||||||
|
results.push_back(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_un.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)
|
||||||
|
socketAddress->sin6_addr.u.Word[i] = htons(address[i]);
|
||||||
|
|
||||||
|
IN6_ADDR any = in6addr_any;
|
||||||
|
|
||||||
|
return sizeof(sockaddr_in6);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
NazaraInternalError("Unhandled ip protocol (0x" + String::Number(ipAddress.GetProtocol()) + ')');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NazaraError("Invalid ip address");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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 <winsock2.h>
|
||||||
|
#include <ws2tcpip.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 FromAddrinfo(const addrinfoW* 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);
|
||||||
|
static std::vector<HostnameInfo> ResolveHostname(NetProtocol procol, const String& hostname, const String& service);
|
||||||
|
|
||||||
|
static socklen_t ToSockAddr(const IpAddress& ipAddress, void* buffer);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,639 @@
|
||||||
|
// 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/Win32/SocketImpl.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Core/Log.hpp>
|
||||||
|
#include <Nazara/Network/Win32/IpAddressImpl.hpp>
|
||||||
|
#include <Mstcpip.h>
|
||||||
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
SocketHandle SocketImpl::Accept(SocketHandle handle, IpAddress* address, SocketError* error)
|
||||||
|
{
|
||||||
|
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||||
|
|
||||||
|
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||||
|
int bufferLength = static_cast<int>(nameBuffer.size());
|
||||||
|
|
||||||
|
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 = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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 = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketImpl::Close(SocketHandle handle)
|
||||||
|
{
|
||||||
|
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||||
|
|
||||||
|
if (closesocket(handle) == SOCKET_ERROR)
|
||||||
|
NazaraWarning("Failed to close socket: " + Error::GetLastSystemError(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketImpl::ClearErrorCode(SocketHandle handle)
|
||||||
|
{
|
||||||
|
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||||
|
|
||||||
|
if (GetLastError(handle, nullptr) < 0)
|
||||||
|
NazaraWarning("Failed to clear socket error code: " + Error::GetLastSystemError(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = WSAGetLastError();
|
||||||
|
switch (errorCode) //< Check for "normal errors" first
|
||||||
|
{
|
||||||
|
case WSAEALREADY:
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
return SocketState_Connecting;
|
||||||
|
|
||||||
|
case WSAEISCONN:
|
||||||
|
return SocketState_Connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (errorCode == WSAEADDRNOTAVAIL)
|
||||||
|
*error = SocketError_ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case
|
||||||
|
else
|
||||||
|
*error = TranslateWSAErrorToSocketError(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 > 0)
|
||||||
|
{
|
||||||
|
int code = GetLastErrorCode(handle, error);
|
||||||
|
if (code < 0) //< GetLastSocketError() failed
|
||||||
|
return SocketState_NotConnected;
|
||||||
|
|
||||||
|
if (code)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(code);
|
||||||
|
|
||||||
|
return SocketState_NotConnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = SocketError_TimedOut;
|
||||||
|
|
||||||
|
return SocketState_NotConnected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
return SocketState_NotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
*error = SocketError_NoError;
|
||||||
|
|
||||||
|
state = SocketState_Connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketImpl::Initialize()
|
||||||
|
{
|
||||||
|
int errorCode = WSAStartup(MAKEWORD(2, 2), &s_WSA);
|
||||||
|
if (errorCode != 0)
|
||||||
|
{
|
||||||
|
NazaraError("Failed to initialize Windows Socket 2.2: " + Error::GetLastSystemError(errorCode));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NazaraDebug("Initialized Windows Socket " + String::Number(LOBYTE(s_WSA.wVersion)) + '.' + String::Number(HIBYTE(s_WSA.wVersion)) + " (" + String(s_WSA.szDescription) + ')');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketError SocketImpl::GetLastError(SocketHandle handle, SocketError* error)
|
||||||
|
{
|
||||||
|
int code = GetLastErrorCode(handle, error);
|
||||||
|
if (code < 0)
|
||||||
|
return SocketError_Internal;
|
||||||
|
|
||||||
|
return TranslateWSAErrorToSocketError(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SocketImpl::GetLastErrorCode()
|
||||||
|
{
|
||||||
|
return WSAGetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SocketImpl::GetLastErrorCode(SocketHandle handle, SocketError* error)
|
||||||
|
{
|
||||||
|
int code;
|
||||||
|
int codeLength = sizeof(code);
|
||||||
|
|
||||||
|
if (getsockopt(handle, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&code), &codeLength) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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 = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
return SocketState_NotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(handle, queueSize) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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 (ioctlsocket(handle, FIONREAD, &availableBytes) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
availableBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
*error = SocketError_NoError;
|
||||||
|
|
||||||
|
return availableBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int SocketImpl::QueryMaxDatagramSize(SocketHandle handle, SocketError* error)
|
||||||
|
{
|
||||||
|
unsigned int code;
|
||||||
|
int codeLength = sizeof(code);
|
||||||
|
|
||||||
|
if (getsockopt(handle, SOL_SOCKET, SO_MAX_MSG_SIZE, reinterpret_cast<char*>(&code), &codeLength) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
*error = SocketError_NoError;
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddress SocketImpl::QueryPeerAddress(SocketHandle handle, SocketError* error)
|
||||||
|
{
|
||||||
|
NazaraAssert(handle != InvalidHandle, "Invalid handle");
|
||||||
|
|
||||||
|
IpAddressImpl::SockAddrBuffer nameBuffer;
|
||||||
|
int bufferLength = static_cast<int>(nameBuffer.size());
|
||||||
|
|
||||||
|
if (getpeername(handle, reinterpret_cast<sockaddr*>(nameBuffer.data()), &bufferLength) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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;
|
||||||
|
int bufferLength = static_cast<int>(nameBuffer.size());
|
||||||
|
|
||||||
|
if (getsockname(handle, reinterpret_cast<sockaddr*>(nameBuffer.data()), &bufferLength) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
int errorCode = WSAGetLastError();
|
||||||
|
if (errorCode == WSAEINVAL)
|
||||||
|
*error = SocketError_NoError;
|
||||||
|
else
|
||||||
|
*error = TranslateWSAErrorToSocketError(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 = WSAGetLastError();
|
||||||
|
switch (errorCode)
|
||||||
|
{
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
{
|
||||||
|
// If we have no data and are not blocking, return true with 0 byte read
|
||||||
|
byteRead = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(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;
|
||||||
|
int bufferLength = static_cast<int>(nameBuffer.size());
|
||||||
|
|
||||||
|
IpAddress senderIp;
|
||||||
|
|
||||||
|
int byteRead = recvfrom(handle, reinterpret_cast<char*>(buffer), length, 0, reinterpret_cast<sockaddr*>(&nameBuffer), &bufferLength);
|
||||||
|
if (byteRead == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
int errorCode = WSAGetLastError();
|
||||||
|
switch (errorCode)
|
||||||
|
{
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
{
|
||||||
|
// 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 = TranslateWSAErrorToSocketError(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 = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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 = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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 (ioctlsocket(handle, FIONBIO, &block) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
tcp_keepalive keepAlive;
|
||||||
|
keepAlive.onoff = (enabled) ? 1 : 0;
|
||||||
|
keepAlive.keepaliveinterval = static_cast<ULONG>(msInterval);
|
||||||
|
keepAlive.keepalivetime = static_cast<ULONG>(msTime);
|
||||||
|
|
||||||
|
DWORD dummy; //< byteReturned
|
||||||
|
if (!WSAIoctl(handle, SIO_KEEPALIVE_VALS, &keepAlive, sizeof(keepAlive), nullptr, 0, &dummy, nullptr, nullptr))
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||||
|
|
||||||
|
return false; //< Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
*error = SocketError_NoError;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketError SocketImpl::TranslateWSAErrorToSocketError(int error)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return SocketError_NoError;
|
||||||
|
|
||||||
|
// Engine error
|
||||||
|
case WSAEACCES:
|
||||||
|
case WSAEBADF:
|
||||||
|
case WSAEINVAL:
|
||||||
|
case WSAEFAULT:
|
||||||
|
case WSAENOTSOCK:
|
||||||
|
case WSAEPROTOTYPE:
|
||||||
|
case WSA_INVALID_HANDLE:
|
||||||
|
return SocketError_Internal;
|
||||||
|
|
||||||
|
case WSAEADDRNOTAVAIL:
|
||||||
|
case WSAEADDRINUSE:
|
||||||
|
return SocketError_AddressNotAvailable;
|
||||||
|
|
||||||
|
case WSAEAFNOSUPPORT:
|
||||||
|
case WSAEPFNOSUPPORT:
|
||||||
|
case WSAEOPNOTSUPP:
|
||||||
|
case WSAEPROTONOSUPPORT:
|
||||||
|
case WSAESOCKTNOSUPPORT:
|
||||||
|
return SocketError_NotSupported;
|
||||||
|
|
||||||
|
// Those are not errors and should have been handled before the call
|
||||||
|
case WSAEALREADY:
|
||||||
|
case WSAEISCONN:
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
return SocketError_Internal;
|
||||||
|
|
||||||
|
case WSAECONNREFUSED:
|
||||||
|
return SocketError_ConnectionRefused;
|
||||||
|
|
||||||
|
case WSAEMSGSIZE:
|
||||||
|
return SocketError_DatagramSize;
|
||||||
|
|
||||||
|
case WSAEMFILE:
|
||||||
|
case WSAENOBUFS:
|
||||||
|
case WSA_NOT_ENOUGH_MEMORY:
|
||||||
|
return SocketError_ResourceError;
|
||||||
|
|
||||||
|
case WSAENOTCONN:
|
||||||
|
case WSAESHUTDOWN:
|
||||||
|
return SocketError_ConnectionClosed;
|
||||||
|
|
||||||
|
case WSAEHOSTUNREACH:
|
||||||
|
return SocketError_UnreachableHost;
|
||||||
|
|
||||||
|
case WSAENETDOWN:
|
||||||
|
case WSAENETUNREACH:
|
||||||
|
return SocketError_NetworkError;
|
||||||
|
|
||||||
|
case WSANOTINITIALISED:
|
||||||
|
return SocketError_NotInitialized;
|
||||||
|
|
||||||
|
case WSAETIMEDOUT:
|
||||||
|
return SocketError_TimedOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
NazaraWarning("Unhandled WinSock 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
|
||||||
|
};
|
||||||
|
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
|
||||||
|
};
|
||||||
|
static_assert(sizeof(socketType) / sizeof(int) == SocketType_Max + 1, "Socket type array is incomplete");
|
||||||
|
|
||||||
|
return socketType[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketImpl::Uninitialize()
|
||||||
|
{
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketHandle SocketImpl::InvalidHandle = INVALID_SOCKET;
|
||||||
|
WSADATA SocketImpl::s_WSA;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// 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>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
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 unsigned int QueryMaxDatagramSize(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 SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error = nullptr);
|
||||||
|
|
||||||
|
static SocketError TranslateWSAErrorToSocketError(int error);
|
||||||
|
static int TranslateNetProtocolToAF(NetProtocol protocol);
|
||||||
|
static int TranslateSocketTypeToSock(SocketType type);
|
||||||
|
|
||||||
|
static void Uninitialize();
|
||||||
|
|
||||||
|
static SocketHandle InvalidHandle;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static WSADATA s_WSA;
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue