Documentation for module: Network
Former-commit-id: 0563349542b717b602d5a6eb7728bd40b2af7e1f
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user