Documentation for module: Network
Former-commit-id: 0563349542b717b602d5a6eb7728bd40b2af7e1f
This commit is contained in:
parent
2c941827ed
commit
36c1ef1b97
|
|
@ -6,31 +6,62 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Gets the last error
|
||||
* \return Socket error
|
||||
*/
|
||||
|
||||
inline SocketError AbstractSocket::GetLastError() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal socket handle
|
||||
* \return Socket handle
|
||||
*/
|
||||
|
||||
inline SocketHandle AbstractSocket::GetNativeHandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal state
|
||||
* \return Socket state
|
||||
*/
|
||||
|
||||
inline SocketState AbstractSocket::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal type
|
||||
* \return Socket type
|
||||
*/
|
||||
|
||||
inline SocketType AbstractSocket::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the blocking is enabled
|
||||
* \return true If successful
|
||||
*/
|
||||
|
||||
inline bool AbstractSocket::IsBlockingEnabled() const
|
||||
{
|
||||
return m_isBlockingEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the state of the socket
|
||||
*
|
||||
* \param newState Next state for the socket
|
||||
*/
|
||||
|
||||
inline void AbstractSocket::UpdateState(SocketState newState)
|
||||
{
|
||||
if (m_state != newState)
|
||||
|
|
|
|||
|
|
@ -27,17 +27,22 @@
|
|||
#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
|
||||
/*!
|
||||
* \defgroup network (NazaraNetwork) Network module
|
||||
* Network/System module including classes to handle networking elements...
|
||||
*/
|
||||
|
||||
// Utilise le MemoryManager pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes)
|
||||
/// Each modification of a paramater of the module needs a recompilation of the unit
|
||||
|
||||
// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower)
|
||||
#define NAZARA_NETWORK_MANAGE_MEMORY 0
|
||||
|
||||
// Active les tests de sécurité basés sur le code (Conseillé pour le développement)
|
||||
// Activate the security tests based on the code (Advised for development)
|
||||
#define NAZARA_NETWORK_SAFE 1
|
||||
|
||||
/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code
|
||||
/// Each modification of a parameter following implies a modification (often minor) of the code
|
||||
|
||||
/// Vérification des valeurs et types de certaines constantes
|
||||
/// Checking the values and types of certain constants
|
||||
#include <Nazara/Network/ConfigCheck.hpp>
|
||||
|
||||
#if defined(NAZARA_STATIC)
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
#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
|
||||
/// This file is used to check the constant values defined in Config.hpp
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// On force la valeur de MANAGE_MEMORY en mode debug
|
||||
// We fore the value of MANAGE_MEMORY in debug
|
||||
#if defined(NAZARA_DEBUG) && !NAZARA_NETWORK_MANAGE_MEMORY
|
||||
#undef NAZARA_NETWORK_MANAGE_MEMORY
|
||||
#define NAZARA_NETWORK_MANAGE_MEMORY 0
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// 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
|
||||
// We suppose that Debug.hpp is already included, same goes for Config.hpp
|
||||
#if NAZARA_NETWORK_MANAGE_MEMORY
|
||||
#undef delete
|
||||
#undef new
|
||||
|
|
|
|||
|
|
@ -9,11 +9,22 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a IpAddress object by default
|
||||
*/
|
||||
|
||||
inline IpAddress::IpAddress() :
|
||||
m_isValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a IpAddress object with an IP and a port
|
||||
*
|
||||
* \param ip IPv4 address
|
||||
* \param port Port of the IP
|
||||
*/
|
||||
|
||||
inline IpAddress::IpAddress(const IPv4& ip, UInt16 port) :
|
||||
m_ipv4(ip),
|
||||
m_protocol(NetProtocol_IPv4),
|
||||
|
|
@ -22,6 +33,13 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a IpAddress object with an IP and a port
|
||||
*
|
||||
* \param ip IPv6 address
|
||||
* \param port Port of the IP
|
||||
*/
|
||||
|
||||
inline IpAddress::IpAddress(const IPv6& ip, UInt16 port) :
|
||||
m_ipv6(ip),
|
||||
m_protocol(NetProtocol_IPv6),
|
||||
|
|
@ -30,46 +48,100 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a IpAddress object with an IP and a port
|
||||
*
|
||||
* \param ip IPv4 address (a.b.c.d)
|
||||
* \param port Port of the IP
|
||||
*/
|
||||
|
||||
inline IpAddress::IpAddress(const UInt8& a, const UInt8& b, const UInt8& c, const UInt8& d, UInt16 port) :
|
||||
IpAddress(IPv4{a, b, c, d}, port)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a IpAddress object with an IP and a port
|
||||
*
|
||||
* \param ip IPv6 address (a.b.c.d.e.f.g.h)
|
||||
* \param port Port of the IP
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructs a IpAddress object with a C-string
|
||||
*
|
||||
* \param address Hostname or textual IP address
|
||||
*/
|
||||
|
||||
inline IpAddress::IpAddress(const char* address)
|
||||
{
|
||||
BuildFromAddress(address);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructs a IpAddress object with a string
|
||||
*
|
||||
* \param address Hostname or textual IP address
|
||||
*/
|
||||
|
||||
inline IpAddress::IpAddress(const String& address)
|
||||
{
|
||||
BuildFromAddress(address.GetConstBuffer());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the port
|
||||
* \return Port attached to the IP address
|
||||
*/
|
||||
|
||||
inline UInt16 IpAddress::GetPort() const
|
||||
{
|
||||
return m_port;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the net protocol
|
||||
* \return Protocol attached to the IP address
|
||||
*/
|
||||
|
||||
inline NetProtocol IpAddress::GetProtocol() const
|
||||
{
|
||||
return m_protocol;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the IP address is valid
|
||||
* \return true If successful
|
||||
*/
|
||||
|
||||
inline bool IpAddress::IsValid() const
|
||||
{
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the port
|
||||
*
|
||||
* \param port Port attached to the IP address
|
||||
*/
|
||||
|
||||
inline void IpAddress::SetPort(UInt16 port)
|
||||
{
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts IpAddress to IPv4
|
||||
* \return Corresponding IPv4
|
||||
*
|
||||
* \remark Produces a NazaraAssert if net protocol is not IPv4
|
||||
*/
|
||||
|
||||
inline IpAddress::IPv4 IpAddress::ToIPv4() const
|
||||
{
|
||||
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4");
|
||||
|
|
@ -77,6 +149,13 @@ namespace Nz
|
|||
return m_ipv4;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts IpAddress to IPv6
|
||||
* \return Corresponding IPv6
|
||||
*
|
||||
* \remark Produces a NazaraAssert if net protocol is not IPv6
|
||||
*/
|
||||
|
||||
inline IpAddress::IPv6 IpAddress::ToIPv6() const
|
||||
{
|
||||
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv6, "IP is not a valid IPv6");
|
||||
|
|
@ -84,6 +163,13 @@ namespace Nz
|
|||
return m_ipv6;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts IpAddress to UInt32
|
||||
* \return Corresponding UInt32
|
||||
*
|
||||
* \remark Produces a NazaraAssert if net protocol is not IPv4
|
||||
*/
|
||||
|
||||
inline UInt32 IpAddress::ToUInt32() const
|
||||
{
|
||||
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4");
|
||||
|
|
@ -94,17 +180,40 @@ namespace Nz
|
|||
UInt32(m_ipv4[3]) << 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts IpAddress to boolean
|
||||
* \return true If IpAddress is valid
|
||||
*
|
||||
* \see IsValid
|
||||
*/
|
||||
|
||||
inline IpAddress::operator bool() const
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Output operator
|
||||
* \return The stream
|
||||
*
|
||||
* \param out The stream
|
||||
* \param address The address to output
|
||||
*/
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const IpAddress& address)
|
||||
{
|
||||
out << "IpAddress(" << address.ToString() << ')';
|
||||
return out;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares the IpAddress to other one
|
||||
* \return true if the ip addresses are the same
|
||||
*
|
||||
* \param first First ip address to compare
|
||||
* \param second Second ip address to compare with
|
||||
*/
|
||||
|
||||
inline bool operator==(const IpAddress& first, const IpAddress& second)
|
||||
{
|
||||
// We need to check the validity of each address before comparing them
|
||||
|
|
@ -146,11 +255,27 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares the IpAddress to other one
|
||||
* \return false if the ip addresses are the same
|
||||
*
|
||||
* \param first First ip address to compare
|
||||
* \param second Second ip address to compare with
|
||||
*/
|
||||
|
||||
inline bool operator!=(const IpAddress& first, const IpAddress& second)
|
||||
{
|
||||
return !operator==(first, second);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares the IpAddress to other one
|
||||
* \return true if this ip address is inferior to the other one
|
||||
*
|
||||
* \param first First ip address to compare
|
||||
* \param second Second ip address to compare with
|
||||
*/
|
||||
|
||||
inline bool operator<(const IpAddress& first, const IpAddress& second)
|
||||
{
|
||||
// If the second address is invalid, there's no way we're lower than it
|
||||
|
|
@ -196,16 +321,40 @@ namespace Nz
|
|||
return false; //< Same address
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares the IpAddress to other one
|
||||
* \return true if this ip address is inferior or equal to the other one
|
||||
*
|
||||
* \param first First ip address to compare
|
||||
* \param second Second ip address to compare with
|
||||
*/
|
||||
|
||||
inline bool operator<=(const IpAddress& first, const IpAddress& second)
|
||||
{
|
||||
return !operator<(second, first);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares the IpAddress to other one
|
||||
* \return true if this ip address is greather to the other one
|
||||
*
|
||||
* \param first First ip address to compare
|
||||
* \param second Second ip address to compare with
|
||||
*/
|
||||
|
||||
inline bool operator>(const IpAddress& first, const IpAddress& second)
|
||||
{
|
||||
return second < first;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares the IpAddress to other one
|
||||
* \return true if this ip address is greather or equal to the other one
|
||||
*
|
||||
* \param first First ip address to compare
|
||||
* \param second Second ip address to compare with
|
||||
*/
|
||||
|
||||
inline bool operator>=(const IpAddress& first, const IpAddress& second)
|
||||
{
|
||||
return !operator<(first, second);
|
||||
|
|
@ -217,6 +366,13 @@ namespace std
|
|||
template<>
|
||||
struct hash<Nz::IpAddress>
|
||||
{
|
||||
/*!
|
||||
* \brief Converts IpAddress to hash
|
||||
* \return Hash of the IpAddress
|
||||
*
|
||||
* \param ip IpAddress to hash
|
||||
*/
|
||||
|
||||
size_t operator()(const Nz::IpAddress& ip) const
|
||||
{
|
||||
if (!ip)
|
||||
|
|
@ -224,7 +380,7 @@ namespace std
|
|||
|
||||
// This is SDBM adapted for IP addresses, tested to generate the least collisions possible
|
||||
// (It doesn't mean it cannot be improved though)
|
||||
std::size_t h = 0;
|
||||
std::size_t hash = 0;
|
||||
switch (ip.GetProtocol())
|
||||
{
|
||||
case Nz::NetProtocol_Any:
|
||||
|
|
@ -233,20 +389,20 @@ namespace std
|
|||
|
||||
case Nz::NetProtocol_IPv4:
|
||||
{
|
||||
h = ip.ToUInt32() + (h << 6) + (h << 16) - h;
|
||||
hash = ip.ToUInt32() + (hash << 6) + (hash << 16) - hash;
|
||||
break;
|
||||
}
|
||||
case Nz::NetProtocol_IPv6:
|
||||
{
|
||||
Nz::IpAddress::IPv6 v6 = ip.ToIPv6();
|
||||
for (std::size_t i = 0; i < v6.size(); i++)
|
||||
h = v6[i] + (h << 6) + (h << 16) - h;
|
||||
hash = v6[i] + (hash << 6) + (hash << 16) - hash;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ip.GetPort() + (h << 6) + (h << 16) - h;
|
||||
return ip.GetPort() + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,21 +9,46 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a NetPacket object by default
|
||||
*/
|
||||
|
||||
inline NetPacket::NetPacket() :
|
||||
m_netCode(NetCode_Invalid)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a NetPacket object with a packet number and a minimal capacity
|
||||
*
|
||||
* \param netCode Packet number
|
||||
* \param minCapacity Minimal capacity of the packet
|
||||
*/
|
||||
|
||||
inline NetPacket::NetPacket(UInt16 netCode, std::size_t minCapacity)
|
||||
{
|
||||
Reset(netCode, minCapacity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a NetPacket object with a packet number and raw memory
|
||||
*
|
||||
* \param netCode Packet number
|
||||
* \param ptr Raw memory
|
||||
* \param size Size of the memory
|
||||
*/
|
||||
|
||||
inline NetPacket::NetPacket(UInt16 netCode, const void* ptr, std::size_t size)
|
||||
{
|
||||
Reset(netCode, ptr, size);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a NetPacket object with another one by move semantic
|
||||
*
|
||||
* \param packet NetPacket to move into this
|
||||
*/
|
||||
|
||||
inline NetPacket::NetPacket(NetPacket&& packet) :
|
||||
ByteStream(std::move(packet)),
|
||||
m_buffer(std::move(packet.m_buffer)),
|
||||
|
|
@ -35,12 +60,23 @@ namespace Nz
|
|||
SetStream(&m_memoryStream);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object
|
||||
*/
|
||||
|
||||
inline NetPacket::~NetPacket()
|
||||
{
|
||||
FlushBits(); //< Needs to be done here as the stream will be freed before ByteStream calls it
|
||||
FreeStream();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the raw buffer
|
||||
* \return Constant raw buffer
|
||||
*
|
||||
* \remark Produces a NazaraAssert if internal buffer is invalid
|
||||
*/
|
||||
|
||||
inline const UInt8* NetPacket::GetConstData() const
|
||||
{
|
||||
NazaraAssert(m_buffer, "Invalid buffer");
|
||||
|
|
@ -48,6 +84,13 @@ namespace Nz
|
|||
return m_buffer->GetConstBuffer();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the raw buffer
|
||||
* \return Raw buffer
|
||||
*
|
||||
* \remark Produces a NazaraAssert if internal buffer is invalid
|
||||
*/
|
||||
|
||||
inline UInt8* NetPacket::GetData() const
|
||||
{
|
||||
NazaraAssert(m_buffer, "Invalid buffer");
|
||||
|
|
@ -55,6 +98,11 @@ namespace Nz
|
|||
return m_buffer->GetBuffer();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the size of the data
|
||||
* \return Size of the data
|
||||
*/
|
||||
|
||||
inline size_t NetPacket::GetDataSize() const
|
||||
{
|
||||
if (m_buffer)
|
||||
|
|
@ -63,22 +111,46 @@ namespace Nz
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the packet number
|
||||
* \return Packet number
|
||||
*/
|
||||
|
||||
inline UInt16 NetPacket::GetNetCode() const
|
||||
{
|
||||
return m_netCode;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the packet
|
||||
*/
|
||||
|
||||
inline void NetPacket::Reset()
|
||||
{
|
||||
FreeStream();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the packet with a packet number and a minimal capacity
|
||||
*
|
||||
* \param netCode Packet number
|
||||
* \param minCapacity Minimal capacity of the packet
|
||||
*/
|
||||
|
||||
inline void NetPacket::Reset(UInt16 netCode, std::size_t minCapacity)
|
||||
{
|
||||
InitStream(HeaderSize + minCapacity, HeaderSize, OpenMode_ReadWrite);
|
||||
m_netCode = netCode;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the packet with a packet number and raw memory
|
||||
*
|
||||
* \param netCode Packet number
|
||||
* \param ptr Raw memory
|
||||
* \param size Size of the memory
|
||||
*/
|
||||
|
||||
inline void NetPacket::Reset(UInt16 netCode, const void* ptr, std::size_t size)
|
||||
{
|
||||
InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly);
|
||||
|
|
@ -88,6 +160,14 @@ namespace Nz
|
|||
m_netCode = netCode;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resizes the packet
|
||||
*
|
||||
* \param newSize Size for the resizing operation
|
||||
*
|
||||
* \remark Produces a NazaraAssert if internal buffer is invalid
|
||||
*/
|
||||
|
||||
inline void NetPacket::Resize(std::size_t newSize)
|
||||
{
|
||||
NazaraAssert(m_buffer, "Invalid buffer");
|
||||
|
|
@ -95,11 +175,24 @@ namespace Nz
|
|||
m_buffer->Resize(newSize);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the packet number
|
||||
*
|
||||
* \param netCode Packet number
|
||||
*/
|
||||
|
||||
inline void NetPacket::SetNetCode(UInt16 netCode)
|
||||
{
|
||||
m_netCode = netCode;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Moves the NetPacket into this
|
||||
* \return A reference to this
|
||||
*
|
||||
* \param packet NetPacket to move in this
|
||||
*/
|
||||
|
||||
inline NetPacket& Nz::NetPacket::operator=(NetPacket&& packet)
|
||||
{
|
||||
FreeStream();
|
||||
|
|
|
|||
|
|
@ -8,31 +8,66 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Closes the connection
|
||||
*/
|
||||
|
||||
inline void RUdpConnection::Close()
|
||||
{
|
||||
m_socket.Close();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disconnects the connection
|
||||
*
|
||||
* \see Close
|
||||
*/
|
||||
|
||||
inline void RUdpConnection::Disconnect()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bound address
|
||||
* \return IpAddress we are linked to
|
||||
*/
|
||||
|
||||
inline IpAddress RUdpConnection::GetBoundAddress() const
|
||||
{
|
||||
return m_socket.GetBoundAddress();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the port of the bound address
|
||||
* \return Port we are linked to
|
||||
*/
|
||||
|
||||
inline UInt16 RUdpConnection::GetBoundPort() const
|
||||
{
|
||||
return m_socket.GetBoundPort();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the last error
|
||||
* \return Socket error
|
||||
*/
|
||||
|
||||
inline SocketError RUdpConnection::GetLastError() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Listens to a socket
|
||||
* \return true If successfully bound
|
||||
*
|
||||
* \param protocol Net protocol to listen to
|
||||
* \param port Port to listen to
|
||||
*
|
||||
* \remark Produces a NazaraAssert if protocol is unknown or any
|
||||
*/
|
||||
|
||||
inline bool RUdpConnection::Listen(NetProtocol protocol, UInt16 port)
|
||||
{
|
||||
NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO
|
||||
|
|
@ -59,16 +94,36 @@ namespace Nz
|
|||
return Listen(any);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the protocol id
|
||||
*
|
||||
* \param protocolId Protocol ID like NNet
|
||||
*/
|
||||
|
||||
inline void RUdpConnection::SetProtocolId(UInt32 protocolId)
|
||||
{
|
||||
m_protocol = protocolId;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the time before ack
|
||||
*
|
||||
* \param Time before acking to send many together (in ms)
|
||||
*/
|
||||
|
||||
inline void RUdpConnection::SetTimeBeforeAck(UInt32 ms)
|
||||
{
|
||||
m_forceAckSendTime = ms * 1000; //< Store in microseconds for easier handling
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Computes the difference of sequence
|
||||
* \return Delta between the two sequences
|
||||
*
|
||||
* \param sequence First sequence
|
||||
* \param sequence2 Second sequence
|
||||
*/
|
||||
|
||||
inline unsigned int RUdpConnection::ComputeSequenceDifference(SequenceIndex sequence, SequenceIndex sequence2)
|
||||
{
|
||||
unsigned int difference;
|
||||
|
|
@ -80,6 +135,13 @@ namespace Nz
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the peer has pending packets
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param peer Data relative to the peer
|
||||
*/
|
||||
|
||||
inline bool RUdpConnection::HasPendingPackets(PeerData& peer)
|
||||
{
|
||||
for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority)
|
||||
|
|
@ -94,6 +156,14 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the ack is more recent
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param ack First sequence
|
||||
* \param ack2 Second sequence
|
||||
*/
|
||||
|
||||
inline bool RUdpConnection::IsAckMoreRecent(SequenceIndex ack, SequenceIndex ack2)
|
||||
{
|
||||
constexpr SequenceIndex maxDifference = std::numeric_limits<SequenceIndex>::max() / 2;
|
||||
|
|
@ -106,6 +176,13 @@ namespace Nz
|
|||
return false; ///< Same ack
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the connection is reliable
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \remark Produces a NazaraError if enumeration is invalid
|
||||
*/
|
||||
|
||||
inline bool RUdpConnection::IsReliable(PacketReliability reliability)
|
||||
{
|
||||
switch (reliability)
|
||||
|
|
@ -122,6 +199,14 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Simulates the loss of packets on network
|
||||
*
|
||||
* \param packetLoss Ratio of packet loss according to bernoulli distribution
|
||||
*
|
||||
* \remark Produces a NazaraAssert if packetLoss is not in between 0.0 and 1.0
|
||||
*/
|
||||
|
||||
inline void RUdpConnection::SimulateNetwork(double packetLoss)
|
||||
{
|
||||
NazaraAssert(packetLoss >= 0.0 && packetLoss <= 1.0, "Packet loss must be in range [0..1]");
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ namespace Nz
|
|||
PendingPacket m_pendingPacket;
|
||||
UInt64 m_keepAliveInterval;
|
||||
UInt64 m_keepAliveTime;
|
||||
bool m_isKeepAliveEnabled;
|
||||
bool m_isLowDelayEnabled;
|
||||
bool m_isKeepAliveEnabled;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a TcpClient object by default
|
||||
*/
|
||||
|
||||
inline TcpClient::TcpClient() :
|
||||
AbstractSocket(SocketType_TCP),
|
||||
Stream(StreamOption_Sequential),
|
||||
|
|
@ -17,31 +21,62 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disconnects the connection
|
||||
*
|
||||
* \see Close
|
||||
*/
|
||||
|
||||
inline void TcpClient::Disconnect()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the interval between two keep alive pings
|
||||
* \return Interval in milliseconds between two pings
|
||||
*/
|
||||
|
||||
inline UInt64 TcpClient::GetKeepAliveInterval() const
|
||||
{
|
||||
return m_keepAliveInterval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the time before expiration of connection
|
||||
* \return Time in milliseconds before expiration
|
||||
*/
|
||||
|
||||
inline UInt64 TcpClient::GetKeepAliveTime() const
|
||||
{
|
||||
return m_keepAliveTime;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the remote address
|
||||
* \return Address of peer
|
||||
*/
|
||||
|
||||
inline IpAddress TcpClient::GetRemoteAddress() const
|
||||
{
|
||||
return m_peerAddress;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether low delay is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
inline bool TcpClient::IsLowDelayEnabled() const
|
||||
{
|
||||
return m_isLowDelayEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the keep alive flag is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
inline bool TcpClient::IsKeepAliveEnabled() const
|
||||
{
|
||||
return m_isKeepAliveEnabled;
|
||||
|
|
|
|||
|
|
@ -7,27 +7,58 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a TcpServer object by default
|
||||
*/
|
||||
|
||||
inline TcpServer::TcpServer() :
|
||||
AbstractSocket(SocketType_TCP)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a TcpServer object with another one by move semantic
|
||||
*
|
||||
* \param tcpServer TcpServer to move into this
|
||||
*/
|
||||
|
||||
inline TcpServer::TcpServer(TcpServer&& tcpServer) :
|
||||
AbstractSocket(std::move(tcpServer)),
|
||||
m_boundAddress(std::move(tcpServer.m_boundAddress))
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bound address
|
||||
* \return IpAddress we are linked to
|
||||
*/
|
||||
|
||||
inline IpAddress TcpServer::GetBoundAddress() const
|
||||
{
|
||||
return m_boundAddress;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the port of the bound address
|
||||
* \return Port we are linked to
|
||||
*/
|
||||
|
||||
inline UInt16 TcpServer::GetBoundPort() const
|
||||
{
|
||||
return m_boundAddress.GetPort();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Listens to a socket
|
||||
* \return State of the socket
|
||||
*
|
||||
* \param protocol Net protocol to listen to
|
||||
* \param port Port to listen to
|
||||
* \param queueSize Size of the queue
|
||||
*
|
||||
* \remark Produces a NazaraAssert if protocol is unknown or any
|
||||
*/
|
||||
|
||||
inline SocketState TcpServer::Listen(NetProtocol protocol, UInt16 port, unsigned int queueSize)
|
||||
{
|
||||
NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ namespace Nz
|
|||
void OnOpened() override;
|
||||
|
||||
IpAddress m_boundAddress;
|
||||
SocketState m_state;
|
||||
bool m_isBroadCastingEnabled;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,24 +6,46 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a UdpSocket object by default
|
||||
*/
|
||||
|
||||
inline UdpSocket::UdpSocket() :
|
||||
AbstractSocket(SocketType_UDP)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a UdpSocket object with a net protocol
|
||||
*
|
||||
* \param protocol Net protocol to use
|
||||
*/
|
||||
|
||||
inline UdpSocket::UdpSocket(NetProtocol protocol) :
|
||||
UdpSocket()
|
||||
{
|
||||
Create(protocol);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a UdpSocket object with another one by move semantic
|
||||
*
|
||||
* \param udpSocket UdpSocket to move into this
|
||||
*/
|
||||
|
||||
inline UdpSocket::UdpSocket(UdpSocket&& udpSocket) :
|
||||
AbstractSocket(std::move(udpSocket)),
|
||||
m_boundAddress(std::move(udpSocket.m_boundAddress)),
|
||||
m_state(udpSocket.m_state)
|
||||
m_boundAddress(std::move(udpSocket.m_boundAddress))
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Binds a specific port
|
||||
* \return State of the socket
|
||||
*
|
||||
* \param port Port to bind
|
||||
*/
|
||||
|
||||
inline SocketState UdpSocket::Bind(UInt16 port)
|
||||
{
|
||||
IpAddress any;
|
||||
|
|
@ -47,6 +69,13 @@ namespace Nz
|
|||
return Bind(any);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a UDP socket
|
||||
* \return true If successful
|
||||
*
|
||||
* \param protocol Net protocol to use
|
||||
*/
|
||||
|
||||
bool UdpSocket::Create(NetProtocol protocol)
|
||||
{
|
||||
NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol");
|
||||
|
|
@ -54,21 +83,41 @@ namespace Nz
|
|||
return Open(protocol);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bound address
|
||||
* \return IpAddress we are linked to
|
||||
*/
|
||||
|
||||
inline IpAddress UdpSocket::GetBoundAddress() const
|
||||
{
|
||||
return m_boundAddress;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the port of the bound address
|
||||
* \return Port we are linked to
|
||||
*/
|
||||
|
||||
inline UInt16 UdpSocket::GetBoundPort() const
|
||||
{
|
||||
return m_boundAddress.GetPort();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the state of the socket
|
||||
* \return State of the socket
|
||||
*/
|
||||
|
||||
inline SocketState UdpSocket::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the broadcasting is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
inline bool UdpSocket::IsBroadcastingEnabled() const
|
||||
{
|
||||
return m_isBroadCastingEnabled;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,18 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::AbstractSocket
|
||||
* \brief Network class that represents the base of socket
|
||||
*
|
||||
* \remark This class is abstract
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a AbstractSocket object with a type
|
||||
*/
|
||||
|
||||
AbstractSocket::AbstractSocket(SocketType type) :
|
||||
m_lastError(SocketError_NoError),
|
||||
m_handle(SocketImpl::InvalidHandle),
|
||||
|
|
@ -26,6 +38,12 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a AbstractSocket object with another one by move semantic
|
||||
*
|
||||
* \param abstractSocket AbstractSocket to move into this
|
||||
*/
|
||||
|
||||
AbstractSocket::AbstractSocket(AbstractSocket&& abstractSocket) :
|
||||
m_protocol(abstractSocket.m_protocol),
|
||||
m_lastError(abstractSocket.m_lastError),
|
||||
|
|
@ -37,11 +55,21 @@ namespace Nz
|
|||
abstractSocket.m_handle = SocketImpl::InvalidHandle;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls Close
|
||||
*
|
||||
* \see Close
|
||||
*/
|
||||
|
||||
AbstractSocket::~AbstractSocket()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Closes the socket
|
||||
*/
|
||||
|
||||
void AbstractSocket::Close()
|
||||
{
|
||||
if (m_handle != SocketImpl::InvalidHandle)
|
||||
|
|
@ -53,6 +81,12 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables blocking
|
||||
*
|
||||
* \param blocking Should the read block
|
||||
*/
|
||||
|
||||
void AbstractSocket::EnableBlocking(bool blocking)
|
||||
{
|
||||
if (m_isBlockingEnabled != blocking)
|
||||
|
|
@ -64,6 +98,11 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Queries the available bytes
|
||||
* \return Number of bytes which can be read
|
||||
*/
|
||||
|
||||
std::size_t AbstractSocket::QueryAvailableBytes() const
|
||||
{
|
||||
if (m_handle == SocketImpl::InvalidHandle)
|
||||
|
|
@ -72,11 +111,21 @@ namespace Nz
|
|||
return SocketImpl::QueryAvailableBytes(m_handle);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when closing socket
|
||||
*/
|
||||
|
||||
void AbstractSocket::OnClose()
|
||||
{
|
||||
UpdateState(SocketState_NotConnected);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when opening socket
|
||||
*
|
||||
* \remark Produces a NazaraWarning if blocking failed
|
||||
*/
|
||||
|
||||
void AbstractSocket::OnOpened()
|
||||
{
|
||||
SocketError errorCode;
|
||||
|
|
@ -84,6 +133,11 @@ namespace Nz
|
|||
NazaraWarning("Failed to set socket blocking mode (0x" + String::Number(errorCode, 16) + ')');
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Opens the socket according to a net protocol
|
||||
* \return true If successful
|
||||
*/
|
||||
|
||||
bool AbstractSocket::Open(NetProtocol protocol)
|
||||
{
|
||||
if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol)
|
||||
|
|
@ -99,6 +153,13 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Opens the socket according to a socket handle
|
||||
* \return true If successful
|
||||
*
|
||||
* \remark Produces a NazaraAssert if handle is invalid
|
||||
*/
|
||||
|
||||
void AbstractSocket::Open(SocketHandle handle)
|
||||
{
|
||||
NazaraAssert(handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||
|
|
@ -109,6 +170,13 @@ namespace Nz
|
|||
OnOpened();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Moves the AbstractSocket into this
|
||||
* \return A reference to this
|
||||
*
|
||||
* \param abstractSocket AbstractSocket to move in this
|
||||
*/
|
||||
|
||||
AbstractSocket& AbstractSocket::operator=(AbstractSocket&& abstractSocket)
|
||||
{
|
||||
Close();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,15 @@ namespace Nz
|
|||
{
|
||||
namespace Detail
|
||||
{
|
||||
/*!
|
||||
* \brief Parses a decimal number
|
||||
* \return true If successful
|
||||
*
|
||||
* \param str C-string symbolizing the string to parse
|
||||
* \param number Optional argument to return the number parsed
|
||||
* \param endOfRead Optional argument to determine where parsing stopped
|
||||
*/
|
||||
|
||||
bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead)
|
||||
{
|
||||
const char* ptr = str;
|
||||
|
|
@ -35,6 +44,15 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Parses a hexadecimal number
|
||||
* \return true If successful
|
||||
*
|
||||
* \param str C-string symbolizing the string to parse
|
||||
* \param number Optional argument to return the number parsed
|
||||
* \param endOfRead Optional argument to determine where parsing stopped
|
||||
*/
|
||||
|
||||
bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead)
|
||||
{
|
||||
const char* ptr = str;
|
||||
|
|
@ -60,10 +78,26 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \brief Parse a textual IPv4 or IPv6 address
|
||||
* \return true If successful
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \param addressPtr C-string which symbolizes the ip adress
|
||||
* \param result Byte array to return the result in
|
||||
* \param port Optional argument to resolve according to a specific port
|
||||
* \param isIPv6 Optional argument to determine if the address is IPv6
|
||||
* \param endOfRead Optional argument to determine where parsing stopped
|
||||
*
|
||||
* \remark Produces a NazaraAssert if addressPtr is invalid
|
||||
* \remark Produces a NazaraAssert if result is invalid
|
||||
*/
|
||||
|
||||
bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead)
|
||||
{
|
||||
NazaraAssert(addressPtr, "Invalid address string");
|
||||
|
|
|
|||
|
|
@ -22,6 +22,19 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::IpAddress
|
||||
* \brief Network class that represents an IP address
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Builds the IP from a hostname
|
||||
* \return true If successful
|
||||
*
|
||||
* \remark address C-string symbolizing the IP address or hostname
|
||||
*/
|
||||
|
||||
bool IpAddress::BuildFromAddress(const char* address)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
|
@ -50,6 +63,13 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the IP address is loopback
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \remark Produces a NazaraAssert if internal protocol is invalid (should never happen)
|
||||
*/
|
||||
|
||||
bool IpAddress::IsLoopback() const
|
||||
{
|
||||
if (!m_isValid)
|
||||
|
|
@ -73,6 +93,13 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gives a string representation
|
||||
* \return A string representation of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if internal protocol is invalid (should never happen)
|
||||
*/
|
||||
|
||||
String IpAddress::ToString() const
|
||||
{
|
||||
StringStream stream;
|
||||
|
|
@ -153,6 +180,17 @@ namespace Nz
|
|||
return stream;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resolves the address based on the IP
|
||||
* \return Hostname of the address
|
||||
*
|
||||
* \param address IP address to resolve
|
||||
* \param service Optional argument to specify the protocol used
|
||||
* \param error Optional argument to get the error
|
||||
*
|
||||
* \remark Produces a NazaraAssert if address is invalid
|
||||
*/
|
||||
|
||||
String IpAddress::ResolveAddress(const IpAddress& address, String* service, ResolveError* error)
|
||||
{
|
||||
NazaraAssert(address.IsValid(), "Invalid address");
|
||||
|
|
@ -163,6 +201,18 @@ namespace Nz
|
|||
return hostname;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resolves the address based on the hostname
|
||||
* \return Informations about the host: IP(s) of the address, names, ...
|
||||
*
|
||||
* \param protocol Net protocol to use
|
||||
* \param hostname Hostname to resolve
|
||||
* \param service Specify the service used (http, ...)
|
||||
* \param error Optional argument to get the error
|
||||
*
|
||||
* \remark Produces a NazaraAssert if net protocol is set to unknown
|
||||
*/
|
||||
|
||||
std::vector<HostnameInfo> IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service, ResolveError* error)
|
||||
{
|
||||
NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol");
|
||||
|
|
|
|||
|
|
@ -9,11 +9,36 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::NetPacket
|
||||
* \brief Network class that represents a packet
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when receiving data
|
||||
*
|
||||
* \param netCode Packet number
|
||||
* \param data Raw memory
|
||||
* \param size Size of the memory
|
||||
*/
|
||||
|
||||
void NetPacket::OnReceive(UInt16 netCode, const void* data, std::size_t size)
|
||||
{
|
||||
Reset(netCode, data, size);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when sending data
|
||||
* \return Beggining of the raw memory
|
||||
*
|
||||
* \param newSize Size of the memory to send
|
||||
*
|
||||
* \remark Produces a NazaraAssert if newSize is invalid
|
||||
* \remark Produces a NazaraAssert if net code is invalid
|
||||
* \remark Produces a NazaraError if header could not be encoded
|
||||
*/
|
||||
|
||||
const void* NetPacket::OnSend(std::size_t* newSize) const
|
||||
{
|
||||
NazaraAssert(newSize, "Invalid size pointer");
|
||||
|
|
@ -30,6 +55,15 @@ namespace Nz
|
|||
return m_buffer->GetBuffer();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Decodes the header of the packet
|
||||
* \return true If successful
|
||||
*
|
||||
* \param data Raw memory
|
||||
* \param packetSize Size of the packet
|
||||
* \param netCode Packet number
|
||||
*/
|
||||
|
||||
bool NetPacket::DecodeHeader(const void* data, UInt16* packetSize, UInt16* netCode)
|
||||
{
|
||||
MemoryView stream(data, HeaderSize);
|
||||
|
|
@ -40,6 +74,15 @@ namespace Nz
|
|||
return Unserialize(context, packetSize) && Unserialize(context, netCode);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Encodes the header of the packet
|
||||
* \return true If successful
|
||||
*
|
||||
* \param data Raw memory
|
||||
* \param packetSize Size of the packet
|
||||
* \param netCode Packet number
|
||||
*/
|
||||
|
||||
bool NetPacket::EncodeHeader(void* data, UInt16 packetSize, UInt16 netCode)
|
||||
{
|
||||
MemoryView stream(data, HeaderSize);
|
||||
|
|
@ -50,11 +93,19 @@ namespace Nz
|
|||
return Serialize(context, packetSize) && Serialize(context, netCode);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when stream is empty
|
||||
*/
|
||||
|
||||
void NetPacket::OnEmptyStream()
|
||||
{
|
||||
Reset(0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Frees the stream
|
||||
*/
|
||||
|
||||
void NetPacket::FreeStream()
|
||||
{
|
||||
if (!m_buffer)
|
||||
|
|
@ -66,6 +117,16 @@ namespace Nz
|
|||
s_availableBuffers.emplace_back(std::make_pair(size, std::move(m_buffer)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Inits the internal stream
|
||||
*
|
||||
* \param minCapacity Minimal capacity of the stream
|
||||
* \param cursorPos Position of the cursor in the stream
|
||||
* \param openMode Flag of the stream
|
||||
*
|
||||
* \remark Produces a NazaraAssert if cursor position is greather than the capacity
|
||||
*/
|
||||
|
||||
void NetPacket::InitStream(std::size_t minCapacity, UInt64 cursorPos, UInt32 openMode)
|
||||
{
|
||||
NazaraAssert(minCapacity >= cursorPos, "Cannot init stream with a smaller capacity than wanted cursor pos");
|
||||
|
|
@ -92,12 +153,21 @@ namespace Nz
|
|||
SetStream(&m_memoryStream);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the NetPacket class
|
||||
* \return true If initialization is successful
|
||||
*/
|
||||
|
||||
bool NetPacket::Initialize()
|
||||
{
|
||||
s_availableBuffersMutex = std::make_unique<Mutex>();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the NetPacket class
|
||||
*/
|
||||
|
||||
void NetPacket::Uninitialize()
|
||||
{
|
||||
s_availableBuffers.clear();
|
||||
|
|
|
|||
|
|
@ -24,9 +24,23 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::Network
|
||||
* \brief Network class that represents the module initializer of Network
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Initializes the Network module
|
||||
* \return true if initialization is successful
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
* \remark Produces a NazaraError if one submodule failed
|
||||
*/
|
||||
|
||||
bool Network::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
if (IsInitialized())
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Already initialized
|
||||
|
|
@ -68,11 +82,22 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the module is initialized
|
||||
* \return true if module is initialized
|
||||
*/
|
||||
|
||||
bool Network::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the Core module
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
|
||||
void Network::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,16 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::RUdpConnection
|
||||
* \brief Network class that represents a reliable UDP connection
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a RUdpConnection object by default
|
||||
*/
|
||||
|
||||
RUdpConnection::RUdpConnection() :
|
||||
m_peerIterator(0),
|
||||
m_forceAckSendTime(10'000), //< 10ms
|
||||
|
|
@ -23,9 +33,20 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Connects to the IpAddress
|
||||
* \return true
|
||||
*
|
||||
* \param remoteAddress Address to connect to
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is not bound
|
||||
* \remark Produces a NazaraAssert if remote is invalid
|
||||
* \remark Produces a NazaraAssert if port is not specified
|
||||
*/
|
||||
|
||||
bool RUdpConnection::Connect(const IpAddress& remoteAddress)
|
||||
{
|
||||
NazaraAssert(m_socket.GetState() != SocketState_Bound, "Socket must be bound first");
|
||||
NazaraAssert(m_socket.GetState() == SocketState_Bound, "Socket must be bound first");
|
||||
NazaraAssert(remoteAddress.IsValid(), "Invalid remote address");
|
||||
NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port");
|
||||
|
||||
|
|
@ -39,6 +60,16 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Connects to the hostname
|
||||
* \return true If successful
|
||||
*
|
||||
* \param hostName Hostname of the remote
|
||||
* \param protocol Net protocol to use
|
||||
* \param service Specify the protocol used
|
||||
* \param error Optional argument to get the error
|
||||
*/
|
||||
|
||||
bool RUdpConnection::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error)
|
||||
{
|
||||
std::vector<HostnameInfo> results = IpAddress::ResolveHostname(protocol, hostName, service, error);
|
||||
|
|
@ -64,6 +95,13 @@ namespace Nz
|
|||
return Connect(hostnameAddress);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Listens to a socket
|
||||
* \return true If successfully bound
|
||||
*
|
||||
* \param remoteAddress Address to listen to
|
||||
*/
|
||||
|
||||
bool RUdpConnection::Listen(const IpAddress& address)
|
||||
{
|
||||
if (!InitSocket(address.GetProtocol()))
|
||||
|
|
@ -72,8 +110,19 @@ namespace Nz
|
|||
return m_socket.Bind(address) == SocketState_Bound;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Polls the message
|
||||
* \return true If there is a message
|
||||
*
|
||||
* \param message Message to poll
|
||||
*
|
||||
* \remark Produces a NazaraAssert if message is invalid
|
||||
*/
|
||||
|
||||
bool RUdpConnection::PollMessage(RUdpMessage* message)
|
||||
{
|
||||
NazaraAssert(message, "Invalid message");
|
||||
|
||||
if (m_receivedMessages.empty())
|
||||
return false;
|
||||
|
||||
|
|
@ -82,6 +131,16 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sends the packet to a peer
|
||||
* \return true If peer exists (false may result from disconnected client)
|
||||
*
|
||||
* \param peerIp IpAddress of the peer
|
||||
* \param priority Priority of the packet
|
||||
* \param reliability Policy of reliability of the packet
|
||||
* \param packet Packet to send
|
||||
*/
|
||||
|
||||
bool RUdpConnection::Send(const IpAddress& peerIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet)
|
||||
{
|
||||
auto it = m_peerByIP.find(peerIp);
|
||||
|
|
@ -92,6 +151,10 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the reliable connection
|
||||
*/
|
||||
|
||||
void RUdpConnection::Update()
|
||||
{
|
||||
m_currentTime = m_clock.GetMicroseconds();
|
||||
|
|
@ -156,6 +219,14 @@ namespace Nz
|
|||
//m_activeClients.Reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disconnects a peer
|
||||
*
|
||||
* \param peerIndex Index of the peer
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
|
||||
void RUdpConnection::DisconnectPeer(std::size_t peerIndex)
|
||||
{
|
||||
PeerData& peer = m_peers[peerIndex];
|
||||
|
|
@ -193,6 +264,15 @@ namespace Nz
|
|||
m_peers.pop_back();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enqueues a packet in the sending list
|
||||
*
|
||||
* \param peer Data relative to the peer
|
||||
* \param priority Priority of the packet
|
||||
* \param reliability Policy of reliability of the packet
|
||||
* \param packet Packet to send
|
||||
*/
|
||||
|
||||
void RUdpConnection::EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet)
|
||||
{
|
||||
UInt16 protocolBegin = static_cast<UInt16>(m_protocol & 0xFFFF);
|
||||
|
|
@ -208,6 +288,15 @@ namespace Nz
|
|||
EnqueuePacketInternal(peer, priority, reliability, std::move(data));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enqueues internally a packet in the sending list
|
||||
*
|
||||
* \param peer Data relative to the peer
|
||||
* \param priority Priority of the packet
|
||||
* \param reliability Policy of reliability of the packet
|
||||
* \param packet Packet to send
|
||||
*/
|
||||
|
||||
void RUdpConnection::EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data)
|
||||
{
|
||||
PendingPacket pendingPacket;
|
||||
|
|
@ -219,6 +308,13 @@ namespace Nz
|
|||
m_activeClients.UnboundedSet(peer.index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Inits the internal socket
|
||||
* \return true If successful
|
||||
*
|
||||
* \param protocol Net protocol to use
|
||||
*/
|
||||
|
||||
bool RUdpConnection::InitSocket(NetProtocol protocol)
|
||||
{
|
||||
CallOnExit updateLastError([this]
|
||||
|
|
@ -233,6 +329,14 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Processes the acks
|
||||
*
|
||||
* \param peer Data relative to the peer
|
||||
* \param lastAck Last index of the ack
|
||||
* \param ackBits Bits for acking
|
||||
*/
|
||||
|
||||
void RUdpConnection::ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits)
|
||||
{
|
||||
auto it = peer.pendingAckQueue.begin();
|
||||
|
|
@ -257,6 +361,14 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Registers a peer
|
||||
* \return Data relative to the peer
|
||||
*
|
||||
* \param address Address of the peer
|
||||
* \param state Status of the peer
|
||||
*/
|
||||
|
||||
RUdpConnection::PeerData& RUdpConnection::RegisterPeer(const IpAddress& address, PeerState state)
|
||||
{
|
||||
PeerData data;
|
||||
|
|
@ -266,7 +378,7 @@ namespace Nz
|
|||
data.index = m_peers.size();
|
||||
data.lastPacketTime = m_currentTime;
|
||||
data.lastPingTime = m_currentTime;
|
||||
data.roundTripTime = 1000000; ///< Okay that's quite a lot
|
||||
data.roundTripTime = 1'000'000; ///< Okay that's quite a lot
|
||||
data.state = state;
|
||||
|
||||
m_activeClients.UnboundedSet(data.index);
|
||||
|
|
@ -276,6 +388,14 @@ namespace Nz
|
|||
return m_peers.back();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when client requests a connection
|
||||
*
|
||||
* \param address Address of the peer
|
||||
* \param sequenceId Sequence index for the ack
|
||||
* \param token Token for connection
|
||||
*/
|
||||
|
||||
void RUdpConnection::OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token)
|
||||
{
|
||||
// Call hook to check if client should be accepted or not
|
||||
|
|
@ -292,6 +412,13 @@ namespace Nz
|
|||
EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionAcceptedPacket);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when a packet is lost
|
||||
*
|
||||
* \param peer Data relative to the peer
|
||||
* \param packet Pending packet
|
||||
*/
|
||||
|
||||
void RUdpConnection::OnPacketLost(PeerData& peer, PendingAckPacket&& packet)
|
||||
{
|
||||
//NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(packet.sequenceId));
|
||||
|
|
@ -300,6 +427,14 @@ namespace Nz
|
|||
EnqueuePacketInternal(peer, packet.priority, packet.reliability, std::move(packet.data));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when receiving a packet
|
||||
*
|
||||
* \param peerIndex Index of the peer
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
|
||||
void RUdpConnection::OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet)
|
||||
{
|
||||
UInt16 protocolBegin;
|
||||
|
|
@ -436,6 +571,13 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sends a packet to a peer
|
||||
*
|
||||
* \param peer Data relative to the peer
|
||||
* \param packet Pending packet
|
||||
*/
|
||||
|
||||
void RUdpConnection::SendPacket(PeerData& peer, PendingPacket&& packet)
|
||||
{
|
||||
if (peer.state == PeerState_WillAck)
|
||||
|
|
@ -448,7 +590,7 @@ namespace Nz
|
|||
{
|
||||
if (ack == remoteSequence)
|
||||
continue;
|
||||
|
||||
|
||||
unsigned int difference = ComputeSequenceDifference(remoteSequence, ack);
|
||||
if (difference <= 32U)
|
||||
previousAcks |= (1U << (difference - 1));
|
||||
|
|
@ -473,6 +615,11 @@ namespace Nz
|
|||
peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the RUdpConnection class
|
||||
* \return true
|
||||
*/
|
||||
|
||||
bool RUdpConnection::Initialize()
|
||||
{
|
||||
std::random_device device;
|
||||
|
|
@ -481,6 +628,10 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the RUdpConnection class
|
||||
*/
|
||||
|
||||
void RUdpConnection::Uninitialize()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,22 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::TcpClient
|
||||
* \brief Network class that represents a client in a TCP connection
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Connects to the IpAddress
|
||||
* \return State of the socket
|
||||
*
|
||||
* \param remoteAddress Address to connect to
|
||||
*
|
||||
* \remark Produces a NazaraAssert if remote is invalid
|
||||
* \remark Produces a NazaraAssert if remote's port is not specified
|
||||
*/
|
||||
|
||||
SocketState TcpClient::Connect(const IpAddress& remoteAddress)
|
||||
{
|
||||
NazaraAssert(remoteAddress.IsValid(), "Invalid remote address");
|
||||
|
|
@ -45,6 +61,17 @@ namespace Nz
|
|||
return state;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Connects to the hostname
|
||||
* \return State of the socket
|
||||
*
|
||||
* \param hostName Hostname of the remote
|
||||
* \param protocol Net protocol to use
|
||||
* \param service Specify the protocol used
|
||||
* \param error Optional argument to get the error
|
||||
*/
|
||||
|
||||
SocketState TcpClient::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error)
|
||||
{
|
||||
UpdateState(SocketState_Resolving);
|
||||
|
|
@ -73,6 +100,14 @@ namespace Nz
|
|||
return Connect(hostnameAddress);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables low delay in emitting
|
||||
*
|
||||
* \param lowDelay Should low delay be used
|
||||
*
|
||||
* \remark This may produce lag
|
||||
*/
|
||||
|
||||
void TcpClient::EnableLowDelay(bool lowDelay)
|
||||
{
|
||||
if (m_isLowDelayEnabled != lowDelay)
|
||||
|
|
@ -84,6 +119,14 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables the keep alive flag
|
||||
*
|
||||
* \param keepAlive Should the connection be kept alive
|
||||
* \param msTime Time in milliseconds before expiration
|
||||
* \param msInterval Interval in milliseconds between two pings
|
||||
*/
|
||||
|
||||
void TcpClient::EnableKeepAlive(bool keepAlive, UInt64 msTime, UInt64 msInterval)
|
||||
{
|
||||
if (m_isKeepAliveEnabled != keepAlive || m_keepAliveTime != msTime || m_keepAliveInterval != msInterval)
|
||||
|
|
@ -97,22 +140,51 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the stream reached the end of the stream
|
||||
* \return true if there is no more available bytes
|
||||
*/
|
||||
|
||||
bool TcpClient::EndOfStream() const
|
||||
{
|
||||
return QueryAvailableBytes() == 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the position of the cursor
|
||||
* \return 0
|
||||
*
|
||||
* \remark Produces a NazaraError because it is a special stream
|
||||
*/
|
||||
|
||||
UInt64 TcpClient::GetCursorPos() const
|
||||
{
|
||||
NazaraError("GetCursorPos() cannot be used on sequential streams");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the size of the raw memory available
|
||||
* \return Size of the memory available
|
||||
*/
|
||||
|
||||
UInt64 TcpClient::GetSize() const
|
||||
{
|
||||
return QueryAvailableBytes();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Receives the data available
|
||||
* \return true If data received
|
||||
*
|
||||
* \param buffer Raw memory to write
|
||||
* \param size Size of the buffer
|
||||
* \param received Optional argument to get the number of bytes received
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
* \remark Produces a NazaraAssert if buffer and its size is invalid
|
||||
*/
|
||||
|
||||
bool TcpClient::Receive(void* buffer, std::size_t size, std::size_t* received)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||
|
|
@ -142,6 +214,17 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Receives the packet available
|
||||
* \return true If packet received
|
||||
*
|
||||
* \param packet Packet to receive
|
||||
*
|
||||
* \remark Produces a NazaraAssert if packet is invalid
|
||||
* \remark Produces a NazaraAssert if packet size is inferior to the header size
|
||||
* \remark Produces a NazaraWarning if packet's header is invalid
|
||||
*/
|
||||
|
||||
bool TcpClient::ReceivePacket(NetPacket* packet)
|
||||
{
|
||||
//TODO: Every packet requires at least two Receive call, using an internal buffer of a fixed size would prevent this
|
||||
|
|
@ -157,6 +240,7 @@ namespace Nz
|
|||
|
||||
m_pendingPacket.received += received;
|
||||
|
||||
//TODO: Should never happen in production !
|
||||
NazaraAssert(m_pendingPacket.received <= NetPacket::HeaderSize, "Received more data than header size");
|
||||
if (m_pendingPacket.received >= NetPacket::HeaderSize)
|
||||
{
|
||||
|
|
@ -185,6 +269,7 @@ namespace Nz
|
|||
|
||||
m_pendingPacket.received += received;
|
||||
|
||||
//TODO: Should never happen in production !
|
||||
NazaraAssert(m_pendingPacket.received <= packetSize, "Received more data than packet size");
|
||||
if (m_pendingPacket.received >= packetSize)
|
||||
{
|
||||
|
|
@ -202,6 +287,19 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sends the data available
|
||||
* \return true If data sended
|
||||
*
|
||||
* \param buffer Raw memory to read
|
||||
* \param size Size of the buffer
|
||||
* \param sent Optional argument to get the number of bytes sent
|
||||
*
|
||||
* \remark Large sending are handled, you do not need to call this multiple time
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
* \remark Produces a NazaraAssert if buffer and its size is invalid
|
||||
*/
|
||||
|
||||
bool TcpClient::Send(const void* buffer, std::size_t size, std::size_t* sent)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||
|
|
@ -244,6 +342,15 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sends the packet available
|
||||
* \return true If packet sent
|
||||
*
|
||||
* \param packet Packet to send
|
||||
*
|
||||
* \remark Produces a NazaraError if packet could not be prepared for sending
|
||||
*/
|
||||
|
||||
bool TcpClient::SendPacket(const NetPacket& packet)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
|
|
@ -258,12 +365,30 @@ namespace Nz
|
|||
return Send(ptr, size, nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the cursor
|
||||
* \return false
|
||||
*
|
||||
* \param offset Offset according to the beginning of the stream
|
||||
*
|
||||
* \remark Produces a NazaraError because it is a special stream
|
||||
*/
|
||||
|
||||
bool TcpClient::SetCursorPos(UInt64 offset)
|
||||
{
|
||||
NazaraError("SetCursorPos() cannot be used on sequential streams");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Waits for being connected before time out
|
||||
* \return true If connection is successful
|
||||
*
|
||||
* \param msTimeout Time in milliseconds before time out
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
*/
|
||||
|
||||
bool TcpClient::WaitForConnected(UInt64 msTimeout)
|
||||
{
|
||||
switch (m_state)
|
||||
|
|
@ -308,10 +433,18 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Flushes the stream
|
||||
*/
|
||||
|
||||
void TcpClient::FlushStream()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when closing socket
|
||||
*/
|
||||
|
||||
void TcpClient::OnClose()
|
||||
{
|
||||
AbstractSocket::OnClose();
|
||||
|
|
@ -320,6 +453,12 @@ namespace Nz
|
|||
m_peerAddress = IpAddress::Invalid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when opening socket
|
||||
*
|
||||
* \remark Produces a NazaraWarning if delay mode or keep alive failed
|
||||
*/
|
||||
|
||||
void TcpClient::OnOpened()
|
||||
{
|
||||
AbstractSocket::OnOpened();
|
||||
|
|
@ -336,6 +475,16 @@ namespace Nz
|
|||
m_openMode = OpenMode_ReadWrite;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reads blocks
|
||||
* \return Number of blocks read
|
||||
*
|
||||
* \param buffer Preallocated buffer to contain information read
|
||||
* \param size Size of the read and thus of the buffer
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
*/
|
||||
|
||||
std::size_t TcpClient::ReadBlock(void* buffer, std::size_t size)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||
|
|
@ -357,6 +506,13 @@ namespace Nz
|
|||
return received;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the connection with a new socket and a peer address
|
||||
*
|
||||
* \param handle Socket to connect
|
||||
* \param peerAddress Address to connect to
|
||||
*/
|
||||
|
||||
void TcpClient::Reset(SocketHandle handle, const IpAddress& peerAddress)
|
||||
{
|
||||
Open(handle);
|
||||
|
|
@ -365,8 +521,20 @@ namespace Nz
|
|||
UpdateState(SocketState_Connected);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Writes blocks
|
||||
* \return Number of blocks written
|
||||
*
|
||||
* \param buffer Preallocated buffer containing information to write
|
||||
* \param size Size of the writting and thus of the buffer
|
||||
*
|
||||
* \remark Produces a NazaraAssert if buffer is nullptr
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
*/
|
||||
|
||||
std::size_t TcpClient::WriteBlock(const void* buffer, std::size_t size)
|
||||
{
|
||||
NazaraAssert(buffer, "Invalid buffer");
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||
|
||||
CallOnExit restoreBlocking;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,22 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::TcpServer
|
||||
* \brief Network class that represents a server in a TCP connection
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Accepts a client
|
||||
* \return true If client'socket is valid
|
||||
*
|
||||
* \param newClient Client connection
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
* \remark Produces a NazaraAssert if newClient is invalid
|
||||
*/
|
||||
|
||||
bool TcpServer::AcceptClient(TcpClient* newClient)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Server isn't listening");
|
||||
|
|
@ -35,6 +51,16 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Listens to a socket
|
||||
* \return State of the socket
|
||||
*
|
||||
* \param address Address to listen to
|
||||
* \param queueSize Size of the queue
|
||||
*
|
||||
* \remark Produces a NazaraAssert if address is invalid
|
||||
*/
|
||||
|
||||
SocketState TcpServer::Listen(const IpAddress& address, unsigned int queueSize)
|
||||
{
|
||||
NazaraAssert(address.IsValid(), "Invalid address");
|
||||
|
|
@ -49,6 +75,10 @@ namespace Nz
|
|||
return state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when closing socket
|
||||
*/
|
||||
|
||||
void TcpServer::OnClose()
|
||||
{
|
||||
AbstractSocket::OnClose();
|
||||
|
|
@ -56,6 +86,10 @@ namespace Nz
|
|||
m_boundAddress = IpAddress::Invalid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when opening socket
|
||||
*/
|
||||
|
||||
void TcpServer::OnOpened()
|
||||
{
|
||||
AbstractSocket::OnOpened();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,16 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Binds a specific IpAddress
|
||||
* \return State of the socket
|
||||
*
|
||||
* \param address Address to bind
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
* \remark Produces a NazaraAssert if address is invalid
|
||||
*/
|
||||
|
||||
SocketState UdpSocket::Bind(const IpAddress& address)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
|
||||
|
|
@ -30,6 +40,14 @@ namespace Nz
|
|||
return state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables broadcasting
|
||||
*
|
||||
* \param broadcasting Should the UDP broadcast
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
*/
|
||||
|
||||
void UdpSocket::EnableBroadcasting(bool broadcasting)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
|
||||
|
|
@ -41,6 +59,13 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the maximum datagram size allowed
|
||||
* \return Number of bytes
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
*/
|
||||
|
||||
std::size_t UdpSocket::QueryMaxDatagramSize()
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
|
||||
|
|
@ -48,8 +73,22 @@ namespace Nz
|
|||
return SocketImpl::QueryMaxDatagramSize(m_handle, &m_lastError);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Receives the data available
|
||||
* \return true If data received
|
||||
*
|
||||
* \param buffer Raw memory to write
|
||||
* \param size Size of the buffer
|
||||
* \param from IpAddress of the peer
|
||||
* \param received Optional argument to get the number of bytes received
|
||||
*
|
||||
* \remark Produces a NazaraAssert if socket is invalid
|
||||
* \remark Produces a NazaraAssert if buffer and its size is invalid
|
||||
*/
|
||||
|
||||
bool UdpSocket::Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received)
|
||||
{
|
||||
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
|
||||
NazaraAssert(buffer && size > 0, "Invalid buffer");
|
||||
|
||||
int read;
|
||||
|
|
@ -62,8 +101,21 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Receives the packet available
|
||||
* \return true If packet received
|
||||
*
|
||||
* \param packet Packet to receive
|
||||
* \param from IpAddress of the peer
|
||||
*
|
||||
* \remark Produces a NazaraAssert if packet is invalid
|
||||
* \remark Produces a NazaraWarning if packet's header is invalid
|
||||
*/
|
||||
|
||||
bool UdpSocket::ReceivePacket(NetPacket* packet, IpAddress* from)
|
||||
{
|
||||
NazaraAssert(packet, "Invalid packet");
|
||||
|
||||
// I'm not sure what's the best between having a 65k bytes buffer ready for any datagram size
|
||||
// or querying the next datagram size every time, for now I'll leave it as is
|
||||
packet->Reset(NetCode_Invalid, std::numeric_limits<UInt16>::max());
|
||||
|
|
@ -97,6 +149,20 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sends the data available
|
||||
* \return true If data sended
|
||||
*
|
||||
* \param to IpAddress of the peer
|
||||
* \param buffer Raw memory to read
|
||||
* \param size Size of the buffer
|
||||
* \param sent Optional argument to get the number of bytes sent
|
||||
*
|
||||
* \remark Produces a NazaraAssert if peer address is invalid
|
||||
* \remark Produces a NazaraAssert if protocol of communication is not the same than the peer
|
||||
* \remark Produces a NazaraAssert if buffer and its size is invalid
|
||||
*/
|
||||
|
||||
bool UdpSocket::Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent)
|
||||
{
|
||||
NazaraAssert(to.IsValid(), "Invalid ip address");
|
||||
|
|
@ -113,6 +179,16 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sends the packet available
|
||||
* \return true If packet sent
|
||||
*
|
||||
* \param to IpAddress of the peer
|
||||
* \param packet Packet to send
|
||||
*
|
||||
* \remark Produces a NazaraError if packet could not be prepared for sending
|
||||
*/
|
||||
|
||||
bool UdpSocket::SendPacket(const IpAddress& to, const NetPacket& packet)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
|
|
@ -127,6 +203,10 @@ namespace Nz
|
|||
return Send(to, ptr, size, nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when closing socket
|
||||
*/
|
||||
|
||||
void UdpSocket::OnClose()
|
||||
{
|
||||
AbstractSocket::OnClose();
|
||||
|
|
@ -134,6 +214,10 @@ namespace Nz
|
|||
m_boundAddress = IpAddress::Invalid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to do when opening socket
|
||||
*/
|
||||
|
||||
void UdpSocket::OnOpened()
|
||||
{
|
||||
AbstractSocket::OnOpened();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
SCENARIO("IpAddress", "[NETWORK][IPADDRESS]")
|
||||
{
|
||||
GIVEN("Two default IpAddress")
|
||||
{
|
||||
Nz::IpAddress ipAddressV4;
|
||||
Nz::IpAddress ipAddressV6;
|
||||
|
||||
WHEN("We parse localhost")
|
||||
{
|
||||
Nz::String localhostIPv4 = "127.0.0.1";
|
||||
Nz::String localhostIPv6 = "::1";
|
||||
REQUIRE(ipAddressV4.BuildFromAddress(localhostIPv4.GetConstBuffer()));
|
||||
REQUIRE(ipAddressV6.BuildFromAddress(localhostIPv6.GetConstBuffer()));
|
||||
|
||||
THEN("It's the loop back")
|
||||
{
|
||||
REQUIRE(ipAddressV4.IsLoopback());
|
||||
REQUIRE(ipAddressV6.IsLoopback());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("No IpAddress")
|
||||
{
|
||||
WHEN("We get the IP of Nazara")
|
||||
{
|
||||
std::vector<Nz::HostnameInfo> hostnameInfos = Nz::IpAddress::ResolveHostname(Nz::NetProtocol_IPv4, "nazara.digitalpulsesoftware.net");
|
||||
|
||||
THEN("Result is not null")
|
||||
{
|
||||
REQUIRE(!hostnameInfos.empty());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We convert IP to hostname")
|
||||
{
|
||||
Nz::IpAddress google(8, 8, 8, 8);
|
||||
THEN("Google (DNS) is 8.8.8.8")
|
||||
{
|
||||
REQUIRE(Nz::IpAddress::ResolveAddress(google) == "google-public-dns-a.google.com");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#include <Nazara/Network/RUdpConnection.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
|
||||
SCENARIO("RUdpConnection", "[NETWORK][RUDPCONNECTION]")
|
||||
{
|
||||
GIVEN("Two RUdpConnection, one client, one server")
|
||||
{
|
||||
Nz::UInt16 port = 64266;
|
||||
Nz::RUdpConnection server;
|
||||
REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port));
|
||||
Nz::IpAddress serverIP = server.GetBoundAddress();
|
||||
REQUIRE(serverIP.IsValid());
|
||||
Nz::RUdpConnection client;
|
||||
REQUIRE(client.Listen(Nz::NetProtocol_IPv4, port + 1));
|
||||
Nz::IpAddress clientIP = client.GetBoundAddress();
|
||||
REQUIRE(client.Connect(serverIP));
|
||||
REQUIRE(clientIP.IsValid());
|
||||
|
||||
WHEN("We send data from client")
|
||||
{
|
||||
Nz::NetPacket packet(1);
|
||||
Nz::Vector3f vector123(1.f, 2.f, 3.f);
|
||||
packet << vector123;
|
||||
REQUIRE(client.Send(serverIP, Nz::PacketPriority_Immediate, Nz::PacketReliability_Reliable, packet));
|
||||
client.Update();
|
||||
|
||||
THEN("We should get it on the server")
|
||||
{
|
||||
Nz::RUdpMessage rudpMessage;
|
||||
server.Update();
|
||||
REQUIRE(server.PollMessage(&rudpMessage));
|
||||
Nz::Vector3f result;
|
||||
rudpMessage.data >> result;
|
||||
REQUIRE(result == vector123);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#include <Nazara/Network/TcpClient.hpp>
|
||||
#include <Nazara/Network/TcpServer.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Network/NetPacket.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
SCENARIO("TCP", "[NETWORK][TCP]")
|
||||
{
|
||||
GIVEN("Two TCP, one client, one server")
|
||||
{
|
||||
// Avoid reusing the same socket
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(1025, 64245);
|
||||
|
||||
Nz::UInt16 port = dis(gen);
|
||||
Nz::TcpServer server;
|
||||
REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port) == Nz::SocketState_Bound);
|
||||
Nz::IpAddress serverIP = server.GetBoundAddress();
|
||||
REQUIRE(serverIP.IsValid());
|
||||
Nz::TcpClient client;
|
||||
REQUIRE(client.Connect(serverIP) == Nz::SocketState_Connecting);
|
||||
Nz::IpAddress clientIP = client.GetRemoteAddress();
|
||||
REQUIRE(clientIP.IsValid());
|
||||
|
||||
Nz::TcpClient serverToClient;
|
||||
REQUIRE(server.AcceptClient(&serverToClient));
|
||||
|
||||
WHEN("We send data from client")
|
||||
{
|
||||
Nz::NetPacket packet(1);
|
||||
Nz::Vector3f vector123(1.f, 2.f, 3.f);
|
||||
packet << vector123;
|
||||
REQUIRE(client.SendPacket(packet));
|
||||
|
||||
THEN("We should get it on the server")
|
||||
{
|
||||
Nz::NetPacket resultPacket;
|
||||
REQUIRE(serverToClient.ReceivePacket(&resultPacket));
|
||||
Nz::Vector3f result;
|
||||
resultPacket >> result;
|
||||
REQUIRE(result == vector123);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#include <Nazara/Network/UdpSocket.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Network/NetPacket.hpp>
|
||||
|
||||
SCENARIO("UdpSocket", "[NETWORK][UDPSOCKET]")
|
||||
{
|
||||
GIVEN("Two UdpSocket, one client, one server")
|
||||
{
|
||||
Nz::UInt16 port = 64256;
|
||||
Nz::UdpSocket server(Nz::NetProtocol_IPv4);
|
||||
REQUIRE(server.Bind(port) == Nz::SocketState_Bound);
|
||||
Nz::IpAddress serverIP = server.GetBoundAddress();
|
||||
REQUIRE(serverIP.IsValid());
|
||||
Nz::UdpSocket client(Nz::NetProtocol_IPv4);
|
||||
REQUIRE(client.Bind(port + 1) == Nz::SocketState_Bound);
|
||||
Nz::IpAddress clientIP = client.GetBoundAddress();
|
||||
REQUIRE(clientIP.IsValid());
|
||||
|
||||
WHEN("We send data from client")
|
||||
{
|
||||
Nz::NetPacket packet(1);
|
||||
Nz::Vector3f vector123(1.f, 2.f, 3.f);
|
||||
packet << vector123;
|
||||
REQUIRE(client.SendPacket(serverIP, packet));
|
||||
|
||||
THEN("We should get it on the server")
|
||||
{
|
||||
Nz::NetPacket resultPacket;
|
||||
Nz::IpAddress fromIp;
|
||||
REQUIRE(server.ReceivePacket(&resultPacket, &fromIp));
|
||||
Nz::Vector3f result;
|
||||
resultPacket >> result;
|
||||
REQUIRE(result == vector123);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue