Documentation for module: Network

Former-commit-id: d36042138d0883eb118cc9a70f94f3522214dd46
This commit is contained in:
Gawaboumga 2016-05-30 14:22:31 +02:00
parent 96b958d655
commit 0a99058c4d
25 changed files with 1368 additions and 25 deletions

View File

@ -6,31 +6,62 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Gets the last error
* \return Socket error
*/
inline SocketError AbstractSocket::GetLastError() const inline SocketError AbstractSocket::GetLastError() const
{ {
return m_lastError; return m_lastError;
} }
/*!
* \brief Gets the internal socket handle
* \return Socket handle
*/
inline SocketHandle AbstractSocket::GetNativeHandle() const inline SocketHandle AbstractSocket::GetNativeHandle() const
{ {
return m_handle; return m_handle;
} }
/*!
* \brief Gets the internal state
* \return Socket state
*/
inline SocketState AbstractSocket::GetState() const inline SocketState AbstractSocket::GetState() const
{ {
return m_state; return m_state;
} }
/*!
* \brief Gets the internal type
* \return Socket type
*/
inline SocketType AbstractSocket::GetType() const inline SocketType AbstractSocket::GetType() const
{ {
return m_type; return m_type;
} }
/*!
* \brief Checks whether the blocking is enabled
* \return true If successful
*/
inline bool AbstractSocket::IsBlockingEnabled() const inline bool AbstractSocket::IsBlockingEnabled() const
{ {
return m_isBlockingEnabled; return m_isBlockingEnabled;
} }
/*!
* \brief Updates the state of the socket
*
* \param newState Next state for the socket
*/
inline void AbstractSocket::UpdateState(SocketState newState) inline void AbstractSocket::UpdateState(SocketState newState)
{ {
if (m_state != newState) if (m_state != newState)

View File

@ -27,17 +27,22 @@
#ifndef NAZARA_CONFIG_NETWORK_HPP #ifndef NAZARA_CONFIG_NETWORK_HPP
#define 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 #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 #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> #include <Nazara/Network/ConfigCheck.hpp>
#if defined(NAZARA_STATIC) #if defined(NAZARA_STATIC)

View File

@ -7,11 +7,11 @@
#ifndef NAZARA_CONFIG_CHECK_NETWORK_HPP #ifndef NAZARA_CONFIG_CHECK_NETWORK_HPP
#define 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> #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 #if defined(NAZARA_DEBUG) && !NAZARA_NETWORK_MANAGE_MEMORY
#undef NAZARA_NETWORK_MANAGE_MEMORY #undef NAZARA_NETWORK_MANAGE_MEMORY
#define NAZARA_NETWORK_MANAGE_MEMORY 0 #define NAZARA_NETWORK_MANAGE_MEMORY 0

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Engine - Network module" // This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp // 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 #if NAZARA_NETWORK_MANAGE_MEMORY
#undef delete #undef delete
#undef new #undef new

View File

@ -9,11 +9,22 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a IpAddress object by default
*/
inline IpAddress::IpAddress() : inline IpAddress::IpAddress() :
m_isValid(false) 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) : inline IpAddress::IpAddress(const IPv4& ip, UInt16 port) :
m_ipv4(ip), m_ipv4(ip),
m_protocol(NetProtocol_IPv4), 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) : inline IpAddress::IpAddress(const IPv6& ip, UInt16 port) :
m_ipv6(ip), m_ipv6(ip),
m_protocol(NetProtocol_IPv6), 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) : inline IpAddress::IpAddress(const UInt8& a, const UInt8& b, const UInt8& c, const UInt8& d, UInt16 port) :
IpAddress(IPv4{a, b, c, d}, 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) : 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) 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) inline IpAddress::IpAddress(const char* address)
{ {
BuildFromAddress(address); BuildFromAddress(address);
} }
/*!
* Constructs a IpAddress object with a string
*
* \param address Hostname or textual IP address
*/
inline IpAddress::IpAddress(const String& address) inline IpAddress::IpAddress(const String& address)
{ {
BuildFromAddress(address.GetConstBuffer()); BuildFromAddress(address.GetConstBuffer());
} }
/*!
* \brief Gets the port
* \return Port attached to the IP address
*/
inline UInt16 IpAddress::GetPort() const inline UInt16 IpAddress::GetPort() const
{ {
return m_port; return m_port;
} }
/*!
* \brief Gets the net protocol
* \return Protocol attached to the IP address
*/
inline NetProtocol IpAddress::GetProtocol() const inline NetProtocol IpAddress::GetProtocol() const
{ {
return m_protocol; return m_protocol;
} }
/*!
* \brief Checks whether the IP address is valid
* \return true If successful
*/
inline bool IpAddress::IsValid() const inline bool IpAddress::IsValid() const
{ {
return m_isValid; return m_isValid;
} }
/*!
* \brief Sets the port
*
* \param port Port attached to the IP address
*/
inline void IpAddress::SetPort(UInt16 port) inline void IpAddress::SetPort(UInt16 port)
{ {
m_port = 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 inline IpAddress::IPv4 IpAddress::ToIPv4() const
{ {
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4"); NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4");
@ -77,6 +149,13 @@ namespace Nz
return m_ipv4; 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 inline IpAddress::IPv6 IpAddress::ToIPv6() const
{ {
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv6, "IP is not a valid IPv6"); NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv6, "IP is not a valid IPv6");
@ -84,6 +163,13 @@ namespace Nz
return m_ipv6; 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 inline UInt32 IpAddress::ToUInt32() const
{ {
NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4"); NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4");
@ -94,17 +180,40 @@ namespace Nz
UInt32(m_ipv4[3]) << 0; UInt32(m_ipv4[3]) << 0;
} }
/*!
* \brief Converts IpAddress to boolean
* \return true If IpAddress is valid
*
* \see IsValid
*/
inline IpAddress::operator bool() const inline IpAddress::operator bool() const
{ {
return IsValid(); 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) inline std::ostream& operator<<(std::ostream& out, const IpAddress& address)
{ {
out << "IpAddress(" << address.ToString() << ')'; out << "IpAddress(" << address.ToString() << ')';
return out; 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) inline bool operator==(const IpAddress& first, const IpAddress& second)
{ {
// We need to check the validity of each address before comparing them // We need to check the validity of each address before comparing them
@ -146,11 +255,27 @@ namespace Nz
return true; 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) inline bool operator!=(const IpAddress& first, const IpAddress& second)
{ {
return !operator==(first, 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) 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 the second address is invalid, there's no way we're lower than it
@ -196,16 +321,40 @@ namespace Nz
return false; //< Same address 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) inline bool operator<=(const IpAddress& first, const IpAddress& second)
{ {
return !operator<(second, first); 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) inline bool operator>(const IpAddress& first, const IpAddress& second)
{ {
return second < first; 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) inline bool operator>=(const IpAddress& first, const IpAddress& second)
{ {
return !operator<(first, second); return !operator<(first, second);
@ -217,6 +366,13 @@ namespace std
template<> template<>
struct hash<Nz::IpAddress> 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 size_t operator()(const Nz::IpAddress& ip) const
{ {
if (!ip) if (!ip)
@ -224,7 +380,7 @@ namespace std
// This is SDBM adapted for IP addresses, tested to generate the least collisions possible // This is SDBM adapted for IP addresses, tested to generate the least collisions possible
// (It doesn't mean it cannot be improved though) // (It doesn't mean it cannot be improved though)
std::size_t h = 0; std::size_t hash = 0;
switch (ip.GetProtocol()) switch (ip.GetProtocol())
{ {
case Nz::NetProtocol_Any: case Nz::NetProtocol_Any:
@ -233,20 +389,20 @@ namespace std
case Nz::NetProtocol_IPv4: case Nz::NetProtocol_IPv4:
{ {
h = ip.ToUInt32() + (h << 6) + (h << 16) - h; hash = ip.ToUInt32() + (hash << 6) + (hash << 16) - hash;
break; break;
} }
case Nz::NetProtocol_IPv6: case Nz::NetProtocol_IPv6:
{ {
Nz::IpAddress::IPv6 v6 = ip.ToIPv6(); Nz::IpAddress::IPv6 v6 = ip.ToIPv6();
for (std::size_t i = 0; i < v6.size(); i++) 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; break;
} }
} }
return ip.GetPort() + (h << 6) + (h << 16) - h; return ip.GetPort() + (hash << 6) + (hash << 16) - hash;
} }
}; };
} }

View File

@ -9,21 +9,46 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a NetPacket object by default
*/
inline NetPacket::NetPacket() : inline NetPacket::NetPacket() :
m_netCode(NetCode_Invalid) 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) inline NetPacket::NetPacket(UInt16 netCode, std::size_t minCapacity)
{ {
Reset(netCode, 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) inline NetPacket::NetPacket(UInt16 netCode, const void* ptr, std::size_t size)
{ {
Reset(netCode, ptr, 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) : inline NetPacket::NetPacket(NetPacket&& packet) :
ByteStream(std::move(packet)), ByteStream(std::move(packet)),
m_buffer(std::move(packet.m_buffer)), m_buffer(std::move(packet.m_buffer)),
@ -35,12 +60,23 @@ namespace Nz
SetStream(&m_memoryStream); SetStream(&m_memoryStream);
} }
/*!
* \brief Destructs the object
*/
inline NetPacket::~NetPacket() inline NetPacket::~NetPacket()
{ {
FlushBits(); //< Needs to be done here as the stream will be freed before ByteStream calls it FlushBits(); //< Needs to be done here as the stream will be freed before ByteStream calls it
FreeStream(); 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 inline const UInt8* NetPacket::GetConstData() const
{ {
NazaraAssert(m_buffer, "Invalid buffer"); NazaraAssert(m_buffer, "Invalid buffer");
@ -48,6 +84,13 @@ namespace Nz
return m_buffer->GetConstBuffer(); 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 inline UInt8* NetPacket::GetData() const
{ {
NazaraAssert(m_buffer, "Invalid buffer"); NazaraAssert(m_buffer, "Invalid buffer");
@ -55,6 +98,11 @@ namespace Nz
return m_buffer->GetBuffer(); return m_buffer->GetBuffer();
} }
/*!
* \brief Gets the size of the data
* \return Size of the data
*/
inline size_t NetPacket::GetDataSize() const inline size_t NetPacket::GetDataSize() const
{ {
if (m_buffer) if (m_buffer)
@ -63,22 +111,46 @@ namespace Nz
return 0; return 0;
} }
/*!
* \brief Gets the packet number
* \return Packet number
*/
inline UInt16 NetPacket::GetNetCode() const inline UInt16 NetPacket::GetNetCode() const
{ {
return m_netCode; return m_netCode;
} }
/*!
* \brief Resets the packet
*/
inline void NetPacket::Reset() inline void NetPacket::Reset()
{ {
FreeStream(); 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) inline void NetPacket::Reset(UInt16 netCode, std::size_t minCapacity)
{ {
InitStream(HeaderSize + minCapacity, HeaderSize, OpenMode_ReadWrite); InitStream(HeaderSize + minCapacity, HeaderSize, OpenMode_ReadWrite);
m_netCode = netCode; 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) inline void NetPacket::Reset(UInt16 netCode, const void* ptr, std::size_t size)
{ {
InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly);
@ -88,6 +160,14 @@ namespace Nz
m_netCode = netCode; 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) inline void NetPacket::Resize(std::size_t newSize)
{ {
NazaraAssert(m_buffer, "Invalid buffer"); NazaraAssert(m_buffer, "Invalid buffer");
@ -95,11 +175,24 @@ namespace Nz
m_buffer->Resize(newSize); m_buffer->Resize(newSize);
} }
/*!
* \brief Sets the packet number
*
* \param netCode Packet number
*/
inline void NetPacket::SetNetCode(UInt16 netCode) inline void NetPacket::SetNetCode(UInt16 netCode)
{ {
m_netCode = 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) inline NetPacket& Nz::NetPacket::operator=(NetPacket&& packet)
{ {
FreeStream(); FreeStream();

View File

@ -8,31 +8,66 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Closes the connection
*/
inline void RUdpConnection::Close() inline void RUdpConnection::Close()
{ {
m_socket.Close(); m_socket.Close();
} }
/*!
* \brief Disconnects the connection
*
* \see Close
*/
inline void RUdpConnection::Disconnect() inline void RUdpConnection::Disconnect()
{ {
Close(); Close();
} }
/*!
* \brief Gets the bound address
* \return IpAddress we are linked to
*/
inline IpAddress RUdpConnection::GetBoundAddress() const inline IpAddress RUdpConnection::GetBoundAddress() const
{ {
return m_socket.GetBoundAddress(); return m_socket.GetBoundAddress();
} }
/*!
* \brief Gets the port of the bound address
* \return Port we are linked to
*/
inline UInt16 RUdpConnection::GetBoundPort() const inline UInt16 RUdpConnection::GetBoundPort() const
{ {
return m_socket.GetBoundPort(); return m_socket.GetBoundPort();
} }
/*!
* \brief Gets the last error
* \return Socket error
*/
inline SocketError RUdpConnection::GetLastError() const inline SocketError RUdpConnection::GetLastError() const
{ {
return m_lastError; 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) inline bool RUdpConnection::Listen(NetProtocol protocol, UInt16 port)
{ {
NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO
@ -59,16 +94,36 @@ namespace Nz
return Listen(any); return Listen(any);
} }
/*!
* \brief Sets the protocol id
*
* \param protocolId Protocol ID like NNet
*/
inline void RUdpConnection::SetProtocolId(UInt32 protocolId) inline void RUdpConnection::SetProtocolId(UInt32 protocolId)
{ {
m_protocol = 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) inline void RUdpConnection::SetTimeBeforeAck(UInt32 ms)
{ {
m_forceAckSendTime = ms * 1000; //< Store in microseconds for easier handling 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) inline unsigned int RUdpConnection::ComputeSequenceDifference(SequenceIndex sequence, SequenceIndex sequence2)
{ {
unsigned int difference; unsigned int difference;
@ -80,6 +135,13 @@ namespace Nz
return 0; 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) inline bool RUdpConnection::HasPendingPackets(PeerData& peer)
{ {
for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority) for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority)
@ -94,6 +156,14 @@ namespace Nz
return false; 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) inline bool RUdpConnection::IsAckMoreRecent(SequenceIndex ack, SequenceIndex ack2)
{ {
constexpr SequenceIndex maxDifference = std::numeric_limits<SequenceIndex>::max() / 2; constexpr SequenceIndex maxDifference = std::numeric_limits<SequenceIndex>::max() / 2;
@ -106,6 +176,13 @@ namespace Nz
return false; ///< Same ack 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) inline bool RUdpConnection::IsReliable(PacketReliability reliability)
{ {
switch (reliability) switch (reliability)
@ -122,6 +199,14 @@ namespace Nz
return false; 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) inline void RUdpConnection::SimulateNetwork(double packetLoss)
{ {
NazaraAssert(packetLoss >= 0.0 && packetLoss <= 1.0, "Packet loss must be in range [0..1]"); NazaraAssert(packetLoss >= 0.0 && packetLoss <= 1.0, "Packet loss must be in range [0..1]");

View File

@ -79,8 +79,8 @@ namespace Nz
PendingPacket m_pendingPacket; PendingPacket m_pendingPacket;
UInt64 m_keepAliveInterval; UInt64 m_keepAliveInterval;
UInt64 m_keepAliveTime; UInt64 m_keepAliveTime;
bool m_isKeepAliveEnabled;
bool m_isLowDelayEnabled; bool m_isLowDelayEnabled;
bool m_isKeepAliveEnabled;
}; };
} }

View File

@ -7,6 +7,10 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a TcpClient object by default
*/
inline TcpClient::TcpClient() : inline TcpClient::TcpClient() :
AbstractSocket(SocketType_TCP), AbstractSocket(SocketType_TCP),
Stream(StreamOption_Sequential), Stream(StreamOption_Sequential),
@ -17,31 +21,62 @@ namespace Nz
{ {
} }
/*!
* \brief Disconnects the connection
*
* \see Close
*/
inline void TcpClient::Disconnect() inline void TcpClient::Disconnect()
{ {
Close(); Close();
} }
/*!
* \brief Gets the interval between two keep alive pings
* \return Interval in milliseconds between two pings
*/
inline UInt64 TcpClient::GetKeepAliveInterval() const inline UInt64 TcpClient::GetKeepAliveInterval() const
{ {
return m_keepAliveInterval; return m_keepAliveInterval;
} }
/*!
* \brief Gets the time before expiration of connection
* \return Time in milliseconds before expiration
*/
inline UInt64 TcpClient::GetKeepAliveTime() const inline UInt64 TcpClient::GetKeepAliveTime() const
{ {
return m_keepAliveTime; return m_keepAliveTime;
} }
/*!
* \brief Gets the remote address
* \return Address of peer
*/
inline IpAddress TcpClient::GetRemoteAddress() const inline IpAddress TcpClient::GetRemoteAddress() const
{ {
return m_peerAddress; return m_peerAddress;
} }
/*!
* \brief Checks whether low delay is enabled
* \return true If it is the case
*/
inline bool TcpClient::IsLowDelayEnabled() const inline bool TcpClient::IsLowDelayEnabled() const
{ {
return m_isLowDelayEnabled; return m_isLowDelayEnabled;
} }
/*!
* \brief Checks whether the keep alive flag is enabled
* \return true If it is the case
*/
inline bool TcpClient::IsKeepAliveEnabled() const inline bool TcpClient::IsKeepAliveEnabled() const
{ {
return m_isKeepAliveEnabled; return m_isKeepAliveEnabled;

View File

@ -7,27 +7,58 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a TcpServer object by default
*/
inline TcpServer::TcpServer() : inline TcpServer::TcpServer() :
AbstractSocket(SocketType_TCP) 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) : inline TcpServer::TcpServer(TcpServer&& tcpServer) :
AbstractSocket(std::move(tcpServer)), AbstractSocket(std::move(tcpServer)),
m_boundAddress(std::move(tcpServer.m_boundAddress)) m_boundAddress(std::move(tcpServer.m_boundAddress))
{ {
} }
/*!
* \brief Gets the bound address
* \return IpAddress we are linked to
*/
inline IpAddress TcpServer::GetBoundAddress() const inline IpAddress TcpServer::GetBoundAddress() const
{ {
return m_boundAddress; return m_boundAddress;
} }
/*!
* \brief Gets the port of the bound address
* \return Port we are linked to
*/
inline UInt16 TcpServer::GetBoundPort() const inline UInt16 TcpServer::GetBoundPort() const
{ {
return m_boundAddress.GetPort(); 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) inline SocketState TcpServer::Listen(NetProtocol protocol, UInt16 port, unsigned int queueSize)
{ {
NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO

View File

@ -49,7 +49,6 @@ namespace Nz
void OnOpened() override; void OnOpened() override;
IpAddress m_boundAddress; IpAddress m_boundAddress;
SocketState m_state;
bool m_isBroadCastingEnabled; bool m_isBroadCastingEnabled;
}; };
} }

View File

@ -6,24 +6,46 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a UdpSocket object by default
*/
inline UdpSocket::UdpSocket() : inline UdpSocket::UdpSocket() :
AbstractSocket(SocketType_UDP) AbstractSocket(SocketType_UDP)
{ {
} }
/*!
* \brief Constructs a UdpSocket object with a net protocol
*
* \param protocol Net protocol to use
*/
inline UdpSocket::UdpSocket(NetProtocol protocol) : inline UdpSocket::UdpSocket(NetProtocol protocol) :
UdpSocket() UdpSocket()
{ {
Create(protocol); 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) : inline UdpSocket::UdpSocket(UdpSocket&& udpSocket) :
AbstractSocket(std::move(udpSocket)), AbstractSocket(std::move(udpSocket)),
m_boundAddress(std::move(udpSocket.m_boundAddress)), m_boundAddress(std::move(udpSocket.m_boundAddress))
m_state(udpSocket.m_state)
{ {
} }
/*!
* \brief Binds a specific port
* \return State of the socket
*
* \param port Port to bind
*/
inline SocketState UdpSocket::Bind(UInt16 port) inline SocketState UdpSocket::Bind(UInt16 port)
{ {
IpAddress any; IpAddress any;
@ -47,6 +69,13 @@ namespace Nz
return Bind(any); return Bind(any);
} }
/*!
* \brief Creates a UDP socket
* \return true If successful
*
* \param protocol Net protocol to use
*/
bool UdpSocket::Create(NetProtocol protocol) bool UdpSocket::Create(NetProtocol protocol)
{ {
NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol");
@ -54,21 +83,41 @@ namespace Nz
return Open(protocol); return Open(protocol);
} }
/*!
* \brief Gets the bound address
* \return IpAddress we are linked to
*/
inline IpAddress UdpSocket::GetBoundAddress() const inline IpAddress UdpSocket::GetBoundAddress() const
{ {
return m_boundAddress; return m_boundAddress;
} }
/*!
* \brief Gets the port of the bound address
* \return Port we are linked to
*/
inline UInt16 UdpSocket::GetBoundPort() const inline UInt16 UdpSocket::GetBoundPort() const
{ {
return m_boundAddress.GetPort(); return m_boundAddress.GetPort();
} }
/*!
* \brief Gets the state of the socket
* \return State of the socket
*/
inline SocketState UdpSocket::GetState() const inline SocketState UdpSocket::GetState() const
{ {
return m_state; return m_state;
} }
/*!
* \brief Checks whether the broadcasting is enabled
* \return true If it is the case
*/
inline bool UdpSocket::IsBroadcastingEnabled() const inline bool UdpSocket::IsBroadcastingEnabled() const
{ {
return m_isBroadCastingEnabled; return m_isBroadCastingEnabled;

View File

@ -17,6 +17,18 @@
namespace Nz 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) : AbstractSocket::AbstractSocket(SocketType type) :
m_lastError(SocketError_NoError), m_lastError(SocketError_NoError),
m_handle(SocketImpl::InvalidHandle), 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) : AbstractSocket::AbstractSocket(AbstractSocket&& abstractSocket) :
m_protocol(abstractSocket.m_protocol), m_protocol(abstractSocket.m_protocol),
m_lastError(abstractSocket.m_lastError), m_lastError(abstractSocket.m_lastError),
@ -37,11 +55,21 @@ namespace Nz
abstractSocket.m_handle = SocketImpl::InvalidHandle; abstractSocket.m_handle = SocketImpl::InvalidHandle;
} }
/*!
* \brief Destructs the object and calls Close
*
* \see Close
*/
AbstractSocket::~AbstractSocket() AbstractSocket::~AbstractSocket()
{ {
Close(); Close();
} }
/*!
* \brief Closes the socket
*/
void AbstractSocket::Close() void AbstractSocket::Close()
{ {
if (m_handle != SocketImpl::InvalidHandle) 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) void AbstractSocket::EnableBlocking(bool blocking)
{ {
if (m_isBlockingEnabled != 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 std::size_t AbstractSocket::QueryAvailableBytes() const
{ {
if (m_handle == SocketImpl::InvalidHandle) if (m_handle == SocketImpl::InvalidHandle)
@ -72,11 +111,21 @@ namespace Nz
return SocketImpl::QueryAvailableBytes(m_handle); return SocketImpl::QueryAvailableBytes(m_handle);
} }
/*!
* \brief Operation to do when closing socket
*/
void AbstractSocket::OnClose() void AbstractSocket::OnClose()
{ {
UpdateState(SocketState_NotConnected); UpdateState(SocketState_NotConnected);
} }
/*!
* \brief Operation to do when opening socket
*
* \remark Produces a NazaraWarning if blocking failed
*/
void AbstractSocket::OnOpened() void AbstractSocket::OnOpened()
{ {
SocketError errorCode; SocketError errorCode;
@ -84,6 +133,11 @@ namespace Nz
NazaraWarning("Failed to set socket blocking mode (0x" + String::Number(errorCode, 16) + ')'); 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) bool AbstractSocket::Open(NetProtocol protocol)
{ {
if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol) if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol)
@ -99,6 +153,13 @@ namespace Nz
return true; 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) void AbstractSocket::Open(SocketHandle handle)
{ {
NazaraAssert(handle != SocketImpl::InvalidHandle, "Invalid handle"); NazaraAssert(handle != SocketImpl::InvalidHandle, "Invalid handle");
@ -109,6 +170,13 @@ namespace Nz
OnOpened(); OnOpened();
} }
/*!
* \brief Moves the AbstractSocket into this
* \return A reference to this
*
* \param abstractSocket AbstractSocket to move in this
*/
AbstractSocket& AbstractSocket::operator=(AbstractSocket&& abstractSocket) AbstractSocket& AbstractSocket::operator=(AbstractSocket&& abstractSocket)
{ {
Close(); Close();

View File

@ -11,6 +11,15 @@ namespace Nz
{ {
namespace Detail 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) bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead)
{ {
const char* ptr = str; const char* ptr = str;
@ -35,6 +44,15 @@ namespace Nz
return true; 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) bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead)
{ {
const char* ptr = str; 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 * \ingroup network
// array (for the address, in host order), and an optionally provided port. * \brief Parse a textual IPv4 or IPv6 address
// Also, indicate which of those forms (4 or 6) was parsed. * \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) bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead)
{ {
NazaraAssert(addressPtr, "Invalid address string"); NazaraAssert(addressPtr, "Invalid address string");

View File

@ -22,6 +22,19 @@
namespace Nz 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) bool IpAddress::BuildFromAddress(const char* address)
{ {
m_isValid = false; m_isValid = false;
@ -50,6 +63,13 @@ namespace Nz
return true; 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 bool IpAddress::IsLoopback() const
{ {
if (!m_isValid) if (!m_isValid)
@ -73,6 +93,13 @@ namespace Nz
return false; 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 String IpAddress::ToString() const
{ {
StringStream stream; StringStream stream;
@ -153,6 +180,17 @@ namespace Nz
return stream; 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) String IpAddress::ResolveAddress(const IpAddress& address, String* service, ResolveError* error)
{ {
NazaraAssert(address.IsValid(), "Invalid address"); NazaraAssert(address.IsValid(), "Invalid address");
@ -163,6 +201,18 @@ namespace Nz
return hostname; 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) std::vector<HostnameInfo> IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service, ResolveError* error)
{ {
NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol");

View File

@ -9,11 +9,36 @@
namespace Nz 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) void NetPacket::OnReceive(UInt16 netCode, const void* data, std::size_t size)
{ {
Reset(netCode, data, 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 const void* NetPacket::OnSend(std::size_t* newSize) const
{ {
NazaraAssert(newSize, "Invalid size pointer"); NazaraAssert(newSize, "Invalid size pointer");
@ -30,6 +55,15 @@ namespace Nz
return m_buffer->GetBuffer(); 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) bool NetPacket::DecodeHeader(const void* data, UInt16* packetSize, UInt16* netCode)
{ {
MemoryView stream(data, HeaderSize); MemoryView stream(data, HeaderSize);
@ -40,6 +74,15 @@ namespace Nz
return Unserialize(context, packetSize) && Unserialize(context, netCode); 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) bool NetPacket::EncodeHeader(void* data, UInt16 packetSize, UInt16 netCode)
{ {
MemoryView stream(data, HeaderSize); MemoryView stream(data, HeaderSize);
@ -50,11 +93,19 @@ namespace Nz
return Serialize(context, packetSize) && Serialize(context, netCode); return Serialize(context, packetSize) && Serialize(context, netCode);
} }
/*!
* \brief Operation to do when stream is empty
*/
void NetPacket::OnEmptyStream() void NetPacket::OnEmptyStream()
{ {
Reset(0); Reset(0);
} }
/*!
* \brief Frees the stream
*/
void NetPacket::FreeStream() void NetPacket::FreeStream()
{ {
if (!m_buffer) if (!m_buffer)
@ -66,6 +117,16 @@ namespace Nz
s_availableBuffers.emplace_back(std::make_pair(size, std::move(m_buffer))); 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) 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"); NazaraAssert(minCapacity >= cursorPos, "Cannot init stream with a smaller capacity than wanted cursor pos");
@ -92,12 +153,21 @@ namespace Nz
SetStream(&m_memoryStream); SetStream(&m_memoryStream);
} }
/*!
* \brief Initializes the NetPacket class
* \return true If initialization is successful
*/
bool NetPacket::Initialize() bool NetPacket::Initialize()
{ {
s_availableBuffersMutex = std::make_unique<Mutex>(); s_availableBuffersMutex = std::make_unique<Mutex>();
return true; return true;
} }
/*!
* \brief Uninitializes the NetPacket class
*/
void NetPacket::Uninitialize() void NetPacket::Uninitialize()
{ {
s_availableBuffers.clear(); s_availableBuffers.clear();

View File

@ -24,9 +24,23 @@
namespace Nz 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() bool Network::Initialize()
{ {
if (s_moduleReferenceCounter > 0) if (IsInitialized())
{ {
s_moduleReferenceCounter++; s_moduleReferenceCounter++;
return true; // Already initialized return true; // Already initialized
@ -68,11 +82,22 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Checks whether the module is initialized
* \return true if module is initialized
*/
bool Network::IsInitialized() bool Network::IsInitialized()
{ {
return s_moduleReferenceCounter != 0; return s_moduleReferenceCounter != 0;
} }
/*!
* \brief Uninitializes the Core module
*
* \remark Produces a NazaraNotice
*/
void Network::Uninitialize() void Network::Uninitialize()
{ {
if (s_moduleReferenceCounter != 1) if (s_moduleReferenceCounter != 1)

View File

@ -10,6 +10,16 @@
namespace Nz 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() : RUdpConnection::RUdpConnection() :
m_peerIterator(0), m_peerIterator(0),
m_forceAckSendTime(10'000), //< 10ms 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) 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.IsValid(), "Invalid remote address");
NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port");
@ -39,6 +60,16 @@ namespace Nz
return true; 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) bool RUdpConnection::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error)
{ {
std::vector<HostnameInfo> results = IpAddress::ResolveHostname(protocol, hostName, service, error); std::vector<HostnameInfo> results = IpAddress::ResolveHostname(protocol, hostName, service, error);
@ -64,6 +95,13 @@ namespace Nz
return Connect(hostnameAddress); 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) bool RUdpConnection::Listen(const IpAddress& address)
{ {
if (!InitSocket(address.GetProtocol())) if (!InitSocket(address.GetProtocol()))
@ -72,8 +110,19 @@ namespace Nz
return m_socket.Bind(address) == SocketState_Bound; 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) bool RUdpConnection::PollMessage(RUdpMessage* message)
{ {
NazaraAssert(message, "Invalid message");
if (m_receivedMessages.empty()) if (m_receivedMessages.empty())
return false; return false;
@ -82,6 +131,16 @@ namespace Nz
return true; 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) bool RUdpConnection::Send(const IpAddress& peerIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet)
{ {
auto it = m_peerByIP.find(peerIp); auto it = m_peerByIP.find(peerIp);
@ -92,6 +151,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Updates the reliable connection
*/
void RUdpConnection::Update() void RUdpConnection::Update()
{ {
m_currentTime = m_clock.GetMicroseconds(); m_currentTime = m_clock.GetMicroseconds();
@ -156,6 +219,14 @@ namespace Nz
//m_activeClients.Reset(); //m_activeClients.Reset();
} }
/*!
* \brief Disconnects a peer
*
* \param peerIndex Index of the peer
*
* \remark Produces a NazaraNotice
*/
void RUdpConnection::DisconnectPeer(std::size_t peerIndex) void RUdpConnection::DisconnectPeer(std::size_t peerIndex)
{ {
PeerData& peer = m_peers[peerIndex]; PeerData& peer = m_peers[peerIndex];
@ -193,6 +264,15 @@ namespace Nz
m_peers.pop_back(); 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) void RUdpConnection::EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet)
{ {
UInt16 protocolBegin = static_cast<UInt16>(m_protocol & 0xFFFF); UInt16 protocolBegin = static_cast<UInt16>(m_protocol & 0xFFFF);
@ -208,6 +288,15 @@ namespace Nz
EnqueuePacketInternal(peer, priority, reliability, std::move(data)); 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) void RUdpConnection::EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data)
{ {
PendingPacket pendingPacket; PendingPacket pendingPacket;
@ -219,6 +308,13 @@ namespace Nz
m_activeClients.UnboundedSet(peer.index); 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) bool RUdpConnection::InitSocket(NetProtocol protocol)
{ {
CallOnExit updateLastError([this] CallOnExit updateLastError([this]
@ -233,6 +329,14 @@ namespace Nz
return true; 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) void RUdpConnection::ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits)
{ {
auto it = peer.pendingAckQueue.begin(); 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) RUdpConnection::PeerData& RUdpConnection::RegisterPeer(const IpAddress& address, PeerState state)
{ {
PeerData data; PeerData data;
@ -266,7 +378,7 @@ namespace Nz
data.index = m_peers.size(); data.index = m_peers.size();
data.lastPacketTime = m_currentTime; data.lastPacketTime = m_currentTime;
data.lastPingTime = 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; data.state = state;
m_activeClients.UnboundedSet(data.index); m_activeClients.UnboundedSet(data.index);
@ -276,6 +388,14 @@ namespace Nz
return m_peers.back(); 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) void RUdpConnection::OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token)
{ {
// Call hook to check if client should be accepted or not // Call hook to check if client should be accepted or not
@ -292,6 +412,13 @@ namespace Nz
EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionAcceptedPacket); 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) void RUdpConnection::OnPacketLost(PeerData& peer, PendingAckPacket&& packet)
{ {
//NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(packet.sequenceId)); //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)); 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) void RUdpConnection::OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet)
{ {
UInt16 protocolBegin; 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) void RUdpConnection::SendPacket(PeerData& peer, PendingPacket&& packet)
{ {
if (peer.state == PeerState_WillAck) if (peer.state == PeerState_WillAck)
@ -448,7 +590,7 @@ namespace Nz
{ {
if (ack == remoteSequence) if (ack == remoteSequence)
continue; continue;
unsigned int difference = ComputeSequenceDifference(remoteSequence, ack); unsigned int difference = ComputeSequenceDifference(remoteSequence, ack);
if (difference <= 32U) if (difference <= 32U)
previousAcks |= (1U << (difference - 1)); previousAcks |= (1U << (difference - 1));
@ -473,6 +615,11 @@ namespace Nz
peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket)); peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket));
} }
/*!
* \brief Initializes the RUdpConnection class
* \return true
*/
bool RUdpConnection::Initialize() bool RUdpConnection::Initialize()
{ {
std::random_device device; std::random_device device;
@ -481,6 +628,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the RUdpConnection class
*/
void RUdpConnection::Uninitialize() void RUdpConnection::Uninitialize()
{ {
} }

View File

@ -20,6 +20,22 @@
namespace Nz 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) SocketState TcpClient::Connect(const IpAddress& remoteAddress)
{ {
NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); NazaraAssert(remoteAddress.IsValid(), "Invalid remote address");
@ -45,6 +61,17 @@ namespace Nz
return state; 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) SocketState TcpClient::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error)
{ {
UpdateState(SocketState_Resolving); UpdateState(SocketState_Resolving);
@ -73,6 +100,14 @@ namespace Nz
return Connect(hostnameAddress); 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) void TcpClient::EnableLowDelay(bool lowDelay)
{ {
if (m_isLowDelayEnabled != 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) void TcpClient::EnableKeepAlive(bool keepAlive, UInt64 msTime, UInt64 msInterval)
{ {
if (m_isKeepAliveEnabled != keepAlive || m_keepAliveTime != msTime || m_keepAliveInterval != 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 bool TcpClient::EndOfStream() const
{ {
return QueryAvailableBytes() == 0; 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 UInt64 TcpClient::GetCursorPos() const
{ {
NazaraError("GetCursorPos() cannot be used on sequential streams"); NazaraError("GetCursorPos() cannot be used on sequential streams");
return 0; return 0;
} }
/*!
* \brief Gets the size of the raw memory available
* \return Size of the memory available
*/
UInt64 TcpClient::GetSize() const UInt64 TcpClient::GetSize() const
{ {
return QueryAvailableBytes(); 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) bool TcpClient::Receive(void* buffer, std::size_t size, std::size_t* received)
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
@ -142,6 +214,17 @@ namespace Nz
return true; 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) 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 //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; m_pendingPacket.received += received;
//TODO: Should never happen in production !
NazaraAssert(m_pendingPacket.received <= NetPacket::HeaderSize, "Received more data than header size"); NazaraAssert(m_pendingPacket.received <= NetPacket::HeaderSize, "Received more data than header size");
if (m_pendingPacket.received >= NetPacket::HeaderSize) if (m_pendingPacket.received >= NetPacket::HeaderSize)
{ {
@ -185,6 +269,7 @@ namespace Nz
m_pendingPacket.received += received; m_pendingPacket.received += received;
//TODO: Should never happen in production !
NazaraAssert(m_pendingPacket.received <= packetSize, "Received more data than packet size"); NazaraAssert(m_pendingPacket.received <= packetSize, "Received more data than packet size");
if (m_pendingPacket.received >= packetSize) if (m_pendingPacket.received >= packetSize)
{ {
@ -202,6 +287,19 @@ namespace Nz
return false; 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) bool TcpClient::Send(const void* buffer, std::size_t size, std::size_t* sent)
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
@ -244,6 +342,15 @@ namespace Nz
return true; 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) bool TcpClient::SendPacket(const NetPacket& packet)
{ {
std::size_t size = 0; std::size_t size = 0;
@ -258,12 +365,30 @@ namespace Nz
return Send(ptr, size, nullptr); 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) bool TcpClient::SetCursorPos(UInt64 offset)
{ {
NazaraError("SetCursorPos() cannot be used on sequential streams"); NazaraError("SetCursorPos() cannot be used on sequential streams");
return false; 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) bool TcpClient::WaitForConnected(UInt64 msTimeout)
{ {
switch (m_state) switch (m_state)
@ -308,10 +433,18 @@ namespace Nz
return false; return false;
} }
/*!
* \brief Flushes the stream
*/
void TcpClient::FlushStream() void TcpClient::FlushStream()
{ {
} }
/*!
* \brief Operation to do when closing socket
*/
void TcpClient::OnClose() void TcpClient::OnClose()
{ {
AbstractSocket::OnClose(); AbstractSocket::OnClose();
@ -320,6 +453,12 @@ namespace Nz
m_peerAddress = IpAddress::Invalid; 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() void TcpClient::OnOpened()
{ {
AbstractSocket::OnOpened(); AbstractSocket::OnOpened();
@ -336,6 +475,16 @@ namespace Nz
m_openMode = OpenMode_ReadWrite; 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) std::size_t TcpClient::ReadBlock(void* buffer, std::size_t size)
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
@ -357,6 +506,13 @@ namespace Nz
return received; 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) void TcpClient::Reset(SocketHandle handle, const IpAddress& peerAddress)
{ {
Open(handle); Open(handle);
@ -365,8 +521,20 @@ namespace Nz
UpdateState(SocketState_Connected); 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) std::size_t TcpClient::WriteBlock(const void* buffer, std::size_t size)
{ {
NazaraAssert(buffer, "Invalid buffer");
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
CallOnExit restoreBlocking; CallOnExit restoreBlocking;

View File

@ -19,6 +19,22 @@
namespace Nz 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) bool TcpServer::AcceptClient(TcpClient* newClient)
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Server isn't listening"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Server isn't listening");
@ -35,6 +51,16 @@ namespace Nz
return false; 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) SocketState TcpServer::Listen(const IpAddress& address, unsigned int queueSize)
{ {
NazaraAssert(address.IsValid(), "Invalid address"); NazaraAssert(address.IsValid(), "Invalid address");
@ -49,6 +75,10 @@ namespace Nz
return state; return state;
} }
/*!
* \brief Operation to do when closing socket
*/
void TcpServer::OnClose() void TcpServer::OnClose()
{ {
AbstractSocket::OnClose(); AbstractSocket::OnClose();
@ -56,6 +86,10 @@ namespace Nz
m_boundAddress = IpAddress::Invalid; m_boundAddress = IpAddress::Invalid;
} }
/*!
* \brief Operation to do when opening socket
*/
void TcpServer::OnOpened() void TcpServer::OnOpened()
{ {
AbstractSocket::OnOpened(); AbstractSocket::OnOpened();

View File

@ -17,6 +17,16 @@
namespace Nz 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) SocketState UdpSocket::Bind(const IpAddress& address)
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
@ -30,6 +40,14 @@ namespace Nz
return state; return state;
} }
/*!
* \brief Enables broadcasting
*
* \param broadcasting Should the UDP broadcast
*
* \remark Produces a NazaraAssert if socket is invalid
*/
void UdpSocket::EnableBroadcasting(bool broadcasting) void UdpSocket::EnableBroadcasting(bool broadcasting)
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); 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() std::size_t UdpSocket::QueryMaxDatagramSize()
{ {
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
@ -48,8 +73,22 @@ namespace Nz
return SocketImpl::QueryMaxDatagramSize(m_handle, &m_lastError); 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) 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"); NazaraAssert(buffer && size > 0, "Invalid buffer");
int read; int read;
@ -62,8 +101,21 @@ namespace Nz
return true; 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) 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 // 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 // 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()); packet->Reset(NetCode_Invalid, std::numeric_limits<UInt16>::max());
@ -97,6 +149,20 @@ namespace Nz
return true; 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) 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.IsValid(), "Invalid ip address");
@ -113,6 +179,16 @@ namespace Nz
return true; 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) bool UdpSocket::SendPacket(const IpAddress& to, const NetPacket& packet)
{ {
std::size_t size = 0; std::size_t size = 0;
@ -127,6 +203,10 @@ namespace Nz
return Send(to, ptr, size, nullptr); return Send(to, ptr, size, nullptr);
} }
/*!
* \brief Operation to do when closing socket
*/
void UdpSocket::OnClose() void UdpSocket::OnClose()
{ {
AbstractSocket::OnClose(); AbstractSocket::OnClose();
@ -134,6 +214,10 @@ namespace Nz
m_boundAddress = IpAddress::Invalid; m_boundAddress = IpAddress::Invalid;
} }
/*!
* \brief Operation to do when opening socket
*/
void UdpSocket::OnOpened() void UdpSocket::OnOpened()
{ {
AbstractSocket::OnOpened(); AbstractSocket::OnOpened();

View File

@ -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");
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}