Commit progression
This commit is contained in:
parent
12b4073033
commit
8a59dc88b8
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <Nazara/Network/ENetHost.hpp>
|
#include <Nazara/Network/ENetHost.hpp>
|
||||||
#include <Nazara/Network/ENetProtocol.hpp>
|
#include <Nazara/Network/ENetProtocol.hpp>
|
||||||
#include <Nazara/Network/IpAddress.hpp>
|
#include <Nazara/Network/IpAddress.hpp>
|
||||||
|
#include <Nazara/Network/NetBuffer.hpp>
|
||||||
#include <Nazara/Network/NetPacket.hpp>
|
#include <Nazara/Network/NetPacket.hpp>
|
||||||
#include <Nazara/Network/SocketPoller.hpp>
|
#include <Nazara/Network/SocketPoller.hpp>
|
||||||
#include <Nazara/Network/UdpSocket.hpp>
|
#include <Nazara/Network/UdpSocket.hpp>
|
||||||
|
|
@ -40,8 +41,10 @@ namespace Nz
|
||||||
|
|
||||||
void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet);
|
void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet);
|
||||||
|
|
||||||
bool Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0);
|
bool CheckEvents(ENetEvent* event);
|
||||||
bool Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0);
|
|
||||||
|
ENetPeer* Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0);
|
||||||
|
ENetPeer* Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0);
|
||||||
|
|
||||||
inline bool Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount = 0);
|
inline bool Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount = 0);
|
||||||
bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount = 0);
|
bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount = 0);
|
||||||
|
|
@ -58,8 +61,10 @@ namespace Nz
|
||||||
private:
|
private:
|
||||||
bool InitSocket(const IpAddress& address);
|
bool InitSocket(const IpAddress& address);
|
||||||
|
|
||||||
inline void AddToDispatchQueue(ENetPeer* peer);
|
void AddToDispatchQueue(ENetPeer* peer);
|
||||||
inline void RemoveFromDispatchQueue(ENetPeer* peer);
|
void RemoveFromDispatchQueue(ENetPeer* peer);
|
||||||
|
|
||||||
|
bool CheckTimeouts(ENetPeer* peer, ENetEvent* event);
|
||||||
|
|
||||||
bool DispatchIncomingCommands(ENetEvent* event);
|
bool DispatchIncomingCommands(ENetEvent* event);
|
||||||
|
|
||||||
|
|
@ -69,7 +74,11 @@ namespace Nz
|
||||||
bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command);
|
bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command);
|
||||||
bool HandleIncomingCommands(ENetEvent* event);
|
bool HandleIncomingCommands(ENetEvent* event);
|
||||||
bool HandlePing(ENetPeer* peer, const ENetProtocol* command);
|
bool HandlePing(ENetPeer* peer, const ENetProtocol* command);
|
||||||
|
bool HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData);
|
||||||
bool HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData);
|
bool HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData);
|
||||||
|
bool HandleSendUnreliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData);
|
||||||
|
bool HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData);
|
||||||
|
bool HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData);
|
||||||
bool HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command);
|
bool HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command);
|
||||||
bool HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command);
|
bool HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command);
|
||||||
|
|
||||||
|
|
@ -78,12 +87,19 @@ namespace Nz
|
||||||
void NotifyConnect(ENetPeer* peer, ENetEvent* event);
|
void NotifyConnect(ENetPeer* peer, ENetEvent* event);
|
||||||
void NotifyDisconnect(ENetPeer*, ENetEvent* event);
|
void NotifyDisconnect(ENetPeer*, ENetEvent* event);
|
||||||
|
|
||||||
|
void SendAcknowledgements(ENetPeer* peer);
|
||||||
|
bool SendReliableOutgoingCommands(ENetPeer* peer);
|
||||||
|
int SendOutgoingCommands(ENetEvent* event, bool checkForTimeouts);
|
||||||
|
void SendUnreliableOutgoingCommands(ENetPeer* peer);
|
||||||
|
|
||||||
void ThrottleBandwidth();
|
void ThrottleBandwidth();
|
||||||
|
|
||||||
|
static std::size_t GetCommandSize(UInt8 commandNumber);
|
||||||
static bool Initialize();
|
static bool Initialize();
|
||||||
static void Uninitialize();
|
static void Uninitialize();
|
||||||
|
|
||||||
std::array<ENetProtocol, ENetConstants::ENetProtocol_MaximumPacketCommands> m_commands;
|
std::array<ENetProtocol, ENetConstants::ENetProtocol_MaximumPacketCommands> m_commands;
|
||||||
|
std::array<NetBuffer, ENetConstants::ENetProtocol_MaximumPacketCommands * 2 + 1> m_buffers;
|
||||||
std::array<UInt8, ENetConstants::ENetProtocol_MaximumMTU> m_packetData[2];
|
std::array<UInt8, ENetConstants::ENetProtocol_MaximumMTU> m_packetData[2];
|
||||||
std::bernoulli_distribution m_packetLossProbability;
|
std::bernoulli_distribution m_packetLossProbability;
|
||||||
std::size_t m_bandwidthLimitedPeers;
|
std::size_t m_bandwidthLimitedPeers;
|
||||||
|
|
@ -93,6 +109,8 @@ namespace Nz
|
||||||
std::size_t m_duplicatePeers;
|
std::size_t m_duplicatePeers;
|
||||||
std::size_t m_maximumPacketSize;
|
std::size_t m_maximumPacketSize;
|
||||||
std::size_t m_maximumWaitingData;
|
std::size_t m_maximumWaitingData;
|
||||||
|
std::size_t m_packetSize;
|
||||||
|
std::size_t m_peerCount;
|
||||||
std::size_t m_receivedDataLength;
|
std::size_t m_receivedDataLength;
|
||||||
std::vector<ENetPeer> m_peers;
|
std::vector<ENetPeer> m_peers;
|
||||||
Bitset<UInt64> m_dispatchQueue;
|
Bitset<UInt64> m_dispatchQueue;
|
||||||
|
|
@ -101,6 +119,7 @@ namespace Nz
|
||||||
IpAddress m_receivedAddress;
|
IpAddress m_receivedAddress;
|
||||||
SocketPoller m_poller;
|
SocketPoller m_poller;
|
||||||
UdpSocket m_socket;
|
UdpSocket m_socket;
|
||||||
|
UInt16 m_headerFlags;
|
||||||
UInt32 m_bandwidthThrottleEpoch;
|
UInt32 m_bandwidthThrottleEpoch;
|
||||||
UInt32 m_connectedPeers;
|
UInt32 m_connectedPeers;
|
||||||
UInt32 m_mtu;
|
UInt32 m_mtu;
|
||||||
|
|
@ -113,6 +132,7 @@ namespace Nz
|
||||||
UInt32 m_totalReceivedData;
|
UInt32 m_totalReceivedData;
|
||||||
UInt32 m_totalReceivedPackets;
|
UInt32 m_totalReceivedPackets;
|
||||||
UInt8* m_receivedData;
|
UInt8* m_receivedData;
|
||||||
|
bool m_continueSending;
|
||||||
bool m_isSimulationEnabled;
|
bool m_isSimulationEnabled;
|
||||||
bool m_shouldAcceptConnections;
|
bool m_shouldAcceptConnections;
|
||||||
bool m_recalculateBandwidthLimits;
|
bool m_recalculateBandwidthLimits;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -50,16 +50,6 @@ namespace Nz
|
||||||
m_peers.clear();
|
m_peers.clear();
|
||||||
m_socket.Close();
|
m_socket.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ENetHost::AddToDispatchQueue(ENetPeer* peer)
|
|
||||||
{
|
|
||||||
m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer)
|
|
||||||
{
|
|
||||||
m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Network/DebugOff.hpp>
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace Nz
|
||||||
std::size_t referenceCount = 0;
|
std::size_t referenceCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetPacketRef
|
struct NAZARA_NETWORK_API ENetPacketRef
|
||||||
{
|
{
|
||||||
ENetPacketRef() = default;
|
ENetPacketRef() = default;
|
||||||
|
|
||||||
|
|
@ -49,6 +49,18 @@ namespace Nz
|
||||||
Reset(packet);
|
Reset(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENetPacketRef(const ENetPacketRef& packet) :
|
||||||
|
ENetPacketRef()
|
||||||
|
{
|
||||||
|
Reset(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
ENetPacketRef(ENetPacketRef&& packet) :
|
||||||
|
m_packet(packet.m_packet)
|
||||||
|
{
|
||||||
|
packet.m_packet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
~ENetPacketRef()
|
~ENetPacketRef()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
|
@ -69,6 +81,23 @@ namespace Nz
|
||||||
ENetPacketRef& operator=(ENetPacket* packet)
|
ENetPacketRef& operator=(ENetPacket* packet)
|
||||||
{
|
{
|
||||||
Reset(packet);
|
Reset(packet);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENetPacketRef& operator=(const ENetPacketRef& packet)
|
||||||
|
{
|
||||||
|
Reset(packet);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENetPacketRef& operator=(ENetPacketRef&& packet)
|
||||||
|
{
|
||||||
|
m_packet = packet.m_packet;
|
||||||
|
packet.m_packet = nullptr;
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENetPacket* m_packet = nullptr;
|
ENetPacket* m_packet = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -32,6 +32,7 @@ namespace Nz
|
||||||
friend struct PacketRef;
|
friend struct PacketRef;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
ENetPeer(ENetHost* host, UInt16 peerId);
|
||||||
ENetPeer(const ENetPeer&) = delete;
|
ENetPeer(const ENetPeer&) = delete;
|
||||||
ENetPeer(ENetPeer&&) = default;
|
ENetPeer(ENetPeer&&) = default;
|
||||||
~ENetPeer() = default;
|
~ENetPeer() = default;
|
||||||
|
|
@ -40,6 +41,8 @@ namespace Nz
|
||||||
void DisconnectLater(UInt32 data);
|
void DisconnectLater(UInt32 data);
|
||||||
void DisconnectNow(UInt32 data);
|
void DisconnectNow(UInt32 data);
|
||||||
|
|
||||||
|
inline const IpAddress& GetAddress() const;
|
||||||
|
|
||||||
void Ping();
|
void Ping();
|
||||||
|
|
||||||
bool Receive(ENetPacketRef* packet, UInt8* channelId);
|
bool Receive(ENetPacketRef* packet, UInt8* channelId);
|
||||||
|
|
@ -54,8 +57,6 @@ namespace Nz
|
||||||
ENetPeer& operator=(ENetPeer&&) = default;
|
ENetPeer& operator=(ENetPeer&&) = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ENetPeer(ENetHost* host, UInt16 peerId);
|
|
||||||
|
|
||||||
void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand);
|
void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand);
|
||||||
void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize);
|
void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize);
|
||||||
|
|
||||||
|
|
@ -66,7 +67,7 @@ namespace Nz
|
||||||
|
|
||||||
// Protocol functions
|
// Protocol functions
|
||||||
inline void ChangeState(ENetPeerState state);
|
inline void ChangeState(ENetPeerState state);
|
||||||
inline void DispatchState(ENetPeerState state);
|
void DispatchState(ENetPeerState state);
|
||||||
|
|
||||||
void DispatchIncomingReliableCommands(Channel& channel);
|
void DispatchIncomingReliableCommands(Channel& channel);
|
||||||
void DispatchIncomingUnreliableCommands(Channel& channel);
|
void DispatchIncomingUnreliableCommands(Channel& channel);
|
||||||
|
|
@ -80,7 +81,7 @@ namespace Nz
|
||||||
void ResetQueues();
|
void ResetQueues();
|
||||||
|
|
||||||
bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime);
|
bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime);
|
||||||
IncomingCommmand* QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount);
|
IncomingCommmand* QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount);
|
||||||
void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length);
|
void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length);
|
||||||
|
|
||||||
void SetupOutgoingCommand(OutgoingCommand& outgoingCommand);
|
void SetupOutgoingCommand(OutgoingCommand& outgoingCommand);
|
||||||
|
|
@ -139,64 +140,66 @@ namespace Nz
|
||||||
UInt32 sentTime;
|
UInt32 sentTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
ENetHost* m_host;
|
static constexpr std::size_t unsequencedWindow = ENetPeer_ReliableWindowSize / 32;
|
||||||
IpAddress m_address; /**< Internet address of the peer */
|
|
||||||
std::vector<Channel> m_channels;
|
ENetHost* m_host;
|
||||||
std::list<Acknowledgement> m_acknowledgements;
|
IpAddress m_address; /**< Internet address of the peer */
|
||||||
std::list<IncomingCommmand> m_dispatchedCommands;
|
std::array<UInt32, unsequencedWindow> m_unsequencedWindow;
|
||||||
std::list<OutgoingCommand> m_outgoingReliableCommands;
|
std::list<Acknowledgement> m_acknowledgements;
|
||||||
std::list<OutgoingCommand> m_outgoingUnreliableCommands;
|
std::list<IncomingCommmand> m_dispatchedCommands;
|
||||||
std::list<OutgoingCommand> m_sentReliableCommands;
|
std::list<OutgoingCommand> m_outgoingReliableCommands;
|
||||||
std::list<OutgoingCommand> m_sentUnreliableCommands;
|
std::list<OutgoingCommand> m_outgoingUnreliableCommands;
|
||||||
MemoryPool m_packetPool;
|
std::list<OutgoingCommand> m_sentReliableCommands;
|
||||||
//ENetListNode m_dispatchList;
|
std::list<OutgoingCommand> m_sentUnreliableCommands;
|
||||||
ENetPeerState m_state;
|
std::size_t m_totalWaitingData;
|
||||||
UInt8 m_incomingSessionID;
|
std::vector<Channel> m_channels;
|
||||||
UInt8 m_outgoingSessionID;
|
MemoryPool m_packetPool;
|
||||||
UInt16 m_incomingPeerID;
|
//ENetListNode m_dispatchList;
|
||||||
UInt16 m_incomingUnsequencedGroup;
|
ENetPeerState m_state;
|
||||||
UInt16 m_outgoingPeerID;
|
UInt8 m_incomingSessionID;
|
||||||
UInt16 m_outgoingReliableSequenceNumber;
|
UInt8 m_outgoingSessionID;
|
||||||
UInt16 m_outgoingUnsequencedGroup;
|
UInt16 m_incomingPeerID;
|
||||||
UInt32 m_connectID;
|
UInt16 m_incomingUnsequencedGroup;
|
||||||
UInt32 m_earliestTimeout;
|
UInt16 m_outgoingPeerID;
|
||||||
UInt32 m_eventData;
|
UInt16 m_outgoingReliableSequenceNumber;
|
||||||
UInt32 m_highestRoundTripTimeVariance;
|
UInt16 m_outgoingUnsequencedGroup;
|
||||||
UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */
|
UInt32 m_connectID;
|
||||||
UInt32 m_incomingBandwidthThrottleEpoch;
|
UInt32 m_earliestTimeout;
|
||||||
UInt32 m_incomingDataTotal;
|
UInt32 m_eventData;
|
||||||
UInt32 m_lastReceiveTime;
|
UInt32 m_highestRoundTripTimeVariance;
|
||||||
UInt32 m_lastRoundTripTime;
|
UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */
|
||||||
UInt32 m_lastRoundTripTimeVariance;
|
UInt32 m_incomingBandwidthThrottleEpoch;
|
||||||
UInt32 m_lastSendTime;
|
UInt32 m_incomingDataTotal;
|
||||||
UInt32 m_lowestRoundTripTime;
|
UInt32 m_lastReceiveTime;
|
||||||
UInt32 m_mtu;
|
UInt32 m_lastRoundTripTime;
|
||||||
UInt32 m_nextTimeout;
|
UInt32 m_lastRoundTripTimeVariance;
|
||||||
UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */
|
UInt32 m_lastSendTime;
|
||||||
UInt32 m_outgoingBandwidthThrottleEpoch;
|
UInt32 m_lowestRoundTripTime;
|
||||||
UInt32 m_outgoingDataTotal;
|
UInt32 m_mtu;
|
||||||
UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
|
UInt32 m_nextTimeout;
|
||||||
UInt32 m_packetLossEpoch;
|
UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */
|
||||||
UInt32 m_packetLossVariance;
|
UInt32 m_outgoingBandwidthThrottleEpoch;
|
||||||
UInt32 m_packetThrottle;
|
UInt32 m_outgoingDataTotal;
|
||||||
UInt32 m_packetThrottleAcceleration;
|
UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
|
||||||
UInt32 m_packetThrottleCounter;
|
UInt32 m_packetLossEpoch;
|
||||||
UInt32 m_packetThrottleDeceleration;
|
UInt32 m_packetLossVariance;
|
||||||
UInt32 m_packetThrottleEpoch;
|
UInt32 m_packetThrottle;
|
||||||
UInt32 m_packetThrottleInterval;
|
UInt32 m_packetThrottleAcceleration;
|
||||||
UInt32 m_packetThrottleLimit;
|
UInt32 m_packetThrottleCounter;
|
||||||
UInt32 m_packetsLost;
|
UInt32 m_packetThrottleDeceleration;
|
||||||
UInt32 m_packetsSent;
|
UInt32 m_packetThrottleEpoch;
|
||||||
UInt32 m_pingInterval;
|
UInt32 m_packetThrottleInterval;
|
||||||
UInt32 m_reliableDataInTransit;
|
UInt32 m_packetThrottleLimit;
|
||||||
UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */
|
UInt32 m_packetsLost;
|
||||||
UInt32 m_roundTripTimeVariance;
|
UInt32 m_packetsSent;
|
||||||
UInt32 m_timeoutLimit;
|
UInt32 m_pingInterval;
|
||||||
UInt32 m_timeoutMaximum;
|
UInt32 m_reliableDataInTransit;
|
||||||
UInt32 m_timeoutMinimum;
|
UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */
|
||||||
UInt32 m_unsequencedWindow[ENetPeer_ReliableWindowSize / 32];
|
UInt32 m_roundTripTimeVariance;
|
||||||
UInt32 m_windowSize;
|
UInt32 m_timeoutLimit;
|
||||||
std::size_t m_totalWaitingData;
|
UInt32 m_timeoutMaximum;
|
||||||
|
UInt32 m_timeoutMinimum;
|
||||||
|
UInt32 m_windowSize;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
inline const IpAddress& ENetPeer::GetAddress() const
|
||||||
|
{
|
||||||
|
return m_address;
|
||||||
|
}
|
||||||
|
|
||||||
inline void ENetPeer::ChangeState(ENetPeerState state)
|
inline void ENetPeer::ChangeState(ENetPeerState state)
|
||||||
{
|
{
|
||||||
if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater)
|
if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater)
|
||||||
|
|
@ -17,13 +22,6 @@ namespace Nz
|
||||||
|
|
||||||
m_state = state;
|
m_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ENetPeer::DispatchState(ENetPeerState state)
|
|
||||||
{
|
|
||||||
ChangeState(state);
|
|
||||||
|
|
||||||
m_host->AddToDispatchQueue(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Network/DebugOff.hpp>
|
#include <Nazara/Network/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
class ENetPeer;
|
||||||
|
|
||||||
// Constants for the ENet implementation and protocol
|
// Constants for the ENet implementation and protocol
|
||||||
enum ENetConstants
|
enum ENetConstants
|
||||||
{
|
{
|
||||||
|
|
@ -140,27 +142,38 @@ namespace Nz
|
||||||
ENetPacketRef packet;
|
ENetPacketRef packet;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolHeader
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#define NAZARA_PACKED
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define NAZARA_PACKED __attribute__ ((packed))
|
||||||
|
#else
|
||||||
|
#define NAZARA_PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct NAZARA_PACKED ENetProtocolHeader
|
||||||
{
|
{
|
||||||
UInt16 peerID;
|
UInt16 peerID;
|
||||||
UInt16 sentTime;
|
UInt16 sentTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolCommandHeader
|
struct NAZARA_PACKED ENetProtocolCommandHeader
|
||||||
{
|
{
|
||||||
UInt8 command;
|
UInt8 command;
|
||||||
UInt8 channelID;
|
UInt8 channelID;
|
||||||
UInt16 reliableSequenceNumber;
|
UInt16 reliableSequenceNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolAcknowledge
|
struct NAZARA_PACKED ENetProtocolAcknowledge
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 receivedReliableSequenceNumber;
|
UInt16 receivedReliableSequenceNumber;
|
||||||
UInt16 receivedSentTime;
|
UInt16 receivedSentTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolConnect
|
struct NAZARA_PACKED ENetProtocolConnect
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 outgoingPeerID;
|
UInt16 outgoingPeerID;
|
||||||
|
|
@ -178,25 +191,25 @@ namespace Nz
|
||||||
UInt32 data;
|
UInt32 data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolBandwidthLimit
|
struct NAZARA_PACKED ENetProtocolBandwidthLimit
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt32 incomingBandwidth;
|
UInt32 incomingBandwidth;
|
||||||
UInt32 outgoingBandwidth;
|
UInt32 outgoingBandwidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolDisconnect
|
struct NAZARA_PACKED ENetProtocolDisconnect
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt32 data;
|
UInt32 data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolPing
|
struct NAZARA_PACKED ENetProtocolPing
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolSendFragment
|
struct NAZARA_PACKED ENetProtocolSendFragment
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 startSequenceNumber;
|
UInt16 startSequenceNumber;
|
||||||
|
|
@ -207,27 +220,27 @@ namespace Nz
|
||||||
UInt32 fragmentOffset;
|
UInt32 fragmentOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolSendReliable
|
struct NAZARA_PACKED ENetProtocolSendReliable
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 dataLength;
|
UInt16 dataLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolSendUnreliable
|
struct NAZARA_PACKED ENetProtocolSendUnreliable
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 unreliableSequenceNumber;
|
UInt16 unreliableSequenceNumber;
|
||||||
UInt16 dataLength;
|
UInt16 dataLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolSendUnsequenced
|
struct NAZARA_PACKED ENetProtocolSendUnsequenced
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 unsequencedGroup;
|
UInt16 unsequencedGroup;
|
||||||
UInt16 dataLength;
|
UInt16 dataLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolThrottleConfigure
|
struct NAZARA_PACKED ENetProtocolThrottleConfigure
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt32 packetThrottleInterval;
|
UInt32 packetThrottleInterval;
|
||||||
|
|
@ -235,7 +248,7 @@ namespace Nz
|
||||||
UInt32 packetThrottleDeceleration;
|
UInt32 packetThrottleDeceleration;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENetProtocolVerifyConnect
|
struct NAZARA_PACKED ENetProtocolVerifyConnect
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
UInt16 outgoingPeerID;
|
UInt16 outgoingPeerID;
|
||||||
|
|
@ -252,7 +265,7 @@ namespace Nz
|
||||||
UInt32 connectID;
|
UInt32 connectID;
|
||||||
};
|
};
|
||||||
|
|
||||||
union ENetProtocol
|
union NAZARA_PACKED ENetProtocol
|
||||||
{
|
{
|
||||||
ENetProtocolCommandHeader header;
|
ENetProtocolCommandHeader header;
|
||||||
ENetProtocolAcknowledge acknowledge;
|
ENetProtocolAcknowledge acknowledge;
|
||||||
|
|
@ -267,6 +280,10 @@ namespace Nz
|
||||||
ENetProtocolThrottleConfigure throttleConfigure;
|
ENetProtocolThrottleConfigure throttleConfigure;
|
||||||
ENetProtocolVerifyConnect verifyConnect;
|
ENetProtocolVerifyConnect verifyConnect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // NAZARA_ENETPROTOCOL_HPP
|
#endif // NAZARA_ENETPROTOCOL_HPP
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef NAZARA_ENUMS_NETWORK_HPP
|
#ifndef NAZARA_ENUMS_NETWORK_HPP
|
||||||
#define NAZARA_ENUMS_NETWORK_HPP
|
#define NAZARA_ENUMS_NETWORK_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
enum NetCode : UInt16
|
enum NetCode : UInt16
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
#include <Nazara/Network/ENetHost.hpp>
|
#include <Nazara/Network/ENetHost.hpp>
|
||||||
#include <Nazara/Core/Clock.hpp>
|
#include <Nazara/Core/Clock.hpp>
|
||||||
#include <Nazara/Core/Endianness.hpp>
|
#include <Nazara/Core/Endianness.hpp>
|
||||||
#include <Nazara/Core/OffsetOf.hpp>
|
#include <Nazara/Core/OffsetOf.hpp>
|
||||||
#include <Nazara/Network/ENetPeer.hpp>
|
#include <Nazara/Network/ENetPeer.hpp>
|
||||||
#include <Nazara/Network/NetPacket.hpp>
|
#include <Nazara/Network/NetPacket.hpp>
|
||||||
|
#include <iostream>
|
||||||
#include <Nazara/Network/Debug.hpp>
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
#define ENET_TIME_OVERFLOW 86400000
|
#define ENET_TIME_OVERFLOW 86400000
|
||||||
|
|
@ -57,11 +58,6 @@ namespace Nz
|
||||||
sizeof(ENetProtocolThrottleConfigure),
|
sizeof(ENetProtocolThrottleConfigure),
|
||||||
sizeof(ENetProtocolSendFragment)
|
sizeof(ENetProtocolSendFragment)
|
||||||
};
|
};
|
||||||
|
|
||||||
std::size_t enet_protocol_command_size(UInt8 commandNumber)
|
|
||||||
{
|
|
||||||
return s_commandSizes[commandNumber & ENetProtocolCommand_Mask];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -81,7 +77,19 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data)
|
bool ENetHost::CheckEvents(ENetEvent* event)
|
||||||
|
{
|
||||||
|
if (!event)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
event->type = ENetEventType::None;
|
||||||
|
event->peer = nullptr;
|
||||||
|
event->packet.Reset();
|
||||||
|
|
||||||
|
return DispatchIncomingCommands(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
ENetPeer* ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data)
|
||||||
{
|
{
|
||||||
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");
|
||||||
|
|
@ -96,7 +104,7 @@ namespace Nz
|
||||||
if (peerId >= m_peers.size())
|
if (peerId >= m_peers.size())
|
||||||
{
|
{
|
||||||
NazaraError("Insufficient peers");
|
NazaraError("Insufficient peers");
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_channelLimit = Clamp<std::size_t>(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount);
|
m_channelLimit = Clamp<std::size_t>(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount);
|
||||||
|
|
@ -130,10 +138,10 @@ namespace Nz
|
||||||
|
|
||||||
peer.QueueOutgoingCommand(command, nullptr, 0, 0);
|
peer.QueueOutgoingCommand(command, nullptr, 0, 0);
|
||||||
|
|
||||||
return true;
|
return &peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data)
|
ENetPeer* ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data)
|
||||||
{
|
{
|
||||||
std::vector<HostnameInfo> results = IpAddress::ResolveHostname(protocol, hostName, service, error);
|
std::vector<HostnameInfo> results = IpAddress::ResolveHostname(protocol, hostName, service, error);
|
||||||
if (results.empty())
|
if (results.empty())
|
||||||
|
|
@ -173,7 +181,9 @@ namespace Nz
|
||||||
if (!InitSocket(address))
|
if (!InitSocket(address))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_peers.resize(peerCount);
|
m_peers.reserve(peerCount);
|
||||||
|
for (std::size_t i = 0; i < peerCount; ++i)
|
||||||
|
m_peers.emplace_back(this, UInt16(i));
|
||||||
|
|
||||||
m_address = address;
|
m_address = address;
|
||||||
m_randomSeed = *reinterpret_cast<UInt32*>(this);
|
m_randomSeed = *reinterpret_cast<UInt32*>(this);
|
||||||
|
|
@ -187,6 +197,7 @@ namespace Nz
|
||||||
m_mtu = ENetConstants::ENetHost_DefaultMTU;
|
m_mtu = ENetConstants::ENetHost_DefaultMTU;
|
||||||
m_commandCount = 0;
|
m_commandCount = 0;
|
||||||
m_bufferCount = 0;
|
m_bufferCount = 0;
|
||||||
|
m_peerCount = peerCount;
|
||||||
m_receivedAddress = IpAddress::AnyIpV4;
|
m_receivedAddress = IpAddress::AnyIpV4;
|
||||||
m_receivedData = nullptr;
|
m_receivedData = nullptr;
|
||||||
m_receivedDataLength = 0;
|
m_receivedDataLength = 0;
|
||||||
|
|
@ -214,8 +225,6 @@ namespace Nz
|
||||||
|
|
||||||
int ENetHost::Service(ENetEvent* event, UInt32 timeout)
|
int ENetHost::Service(ENetEvent* event, UInt32 timeout)
|
||||||
{
|
{
|
||||||
UInt32 waitCondition;
|
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
{
|
{
|
||||||
event->type = ENetEventType::None;
|
event->type = ENetEventType::None;
|
||||||
|
|
@ -265,7 +274,7 @@ namespace Nz
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (SendOutgoingCommands(event, 1))
|
switch (SendOutgoingCommands(event, true))
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -283,21 +292,8 @@ namespace Nz
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
{
|
{
|
||||||
switch (DispatchIncomingCommands(event))
|
if (DispatchIncomingCommands(event))
|
||||||
{
|
return 1;
|
||||||
case 1:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
#ifdef ENET_DEBUG
|
|
||||||
perror("Error dispatching incoming packets");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout))
|
if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout))
|
||||||
|
|
@ -310,12 +306,8 @@ namespace Nz
|
||||||
if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout))
|
if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SocketError error;
|
if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime)))
|
||||||
if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime), &error))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (error != SocketError_NoError)
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_serviceTime = GetElapsedMilliseconds();
|
m_serviceTime = GetElapsedMilliseconds();
|
||||||
|
|
@ -349,6 +341,62 @@ namespace Nz
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ENetHost::AddToDispatchQueue(ENetPeer* peer)
|
||||||
|
{
|
||||||
|
m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer)
|
||||||
|
{
|
||||||
|
m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ENetHost::CheckTimeouts(ENetPeer* peer, ENetEvent* event)
|
||||||
|
{
|
||||||
|
auto currentCommand = peer->m_sentReliableCommands.begin();
|
||||||
|
|
||||||
|
while (currentCommand != peer->m_sentReliableCommands.end())
|
||||||
|
{
|
||||||
|
auto outgoingCommand = currentCommand;
|
||||||
|
|
||||||
|
++currentCommand;
|
||||||
|
|
||||||
|
if (ENET_TIME_DIFFERENCE(m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (peer->m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, peer->m_earliestTimeout))
|
||||||
|
peer->m_earliestTimeout = outgoingCommand->sentTime;
|
||||||
|
|
||||||
|
if (peer->m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_earliestTimeout) >= peer->m_timeoutMaximum ||
|
||||||
|
(outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_earliestTimeout) >= peer->m_timeoutMinimum)))
|
||||||
|
{
|
||||||
|
NotifyDisconnect(peer, event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outgoingCommand->packet)
|
||||||
|
peer->m_reliableDataInTransit -= outgoingCommand->fragmentLength;
|
||||||
|
|
||||||
|
++peer->m_packetsLost;
|
||||||
|
|
||||||
|
outgoingCommand->roundTripTimeout *= 2;
|
||||||
|
|
||||||
|
peer->m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand));
|
||||||
|
peer->m_sentReliableCommands.erase(outgoingCommand);
|
||||||
|
|
||||||
|
// Okay this should just never procs, I don't see how it would be possible
|
||||||
|
/*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) &&
|
||||||
|
!enet_list_empty(&peer->sentReliableCommands))
|
||||||
|
{
|
||||||
|
outgoingCommand = (ENetOutgoingCommand *) currentCommand;
|
||||||
|
|
||||||
|
peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ENetHost::DispatchIncomingCommands(ENetEvent* event)
|
bool ENetHost::DispatchIncomingCommands(ENetEvent* event)
|
||||||
{
|
{
|
||||||
for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit))
|
for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit))
|
||||||
|
|
@ -391,6 +439,9 @@ namespace Nz
|
||||||
AddToDispatchQueue(&peer);
|
AddToDispatchQueue(&peer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -436,7 +487,7 @@ namespace Nz
|
||||||
if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance)
|
if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance)
|
||||||
peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance;
|
peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance;
|
||||||
|
|
||||||
if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->packetThrottleInterval)
|
if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->m_packetThrottleInterval)
|
||||||
{
|
{
|
||||||
peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime;
|
peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime;
|
||||||
peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance;
|
peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance;
|
||||||
|
|
@ -770,7 +821,7 @@ namespace Nz
|
||||||
return commandError();
|
return commandError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer && (command->header.command & ENetProtocolCommand_Acknowledge) != 0)
|
if (peer && (command->header.command & ENetProtocolFlag_Acknowledge) != 0)
|
||||||
{
|
{
|
||||||
UInt16 sentTime;
|
UInt16 sentTime;
|
||||||
|
|
||||||
|
|
@ -810,6 +861,90 @@ namespace Nz
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ENetHost::HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData)
|
||||||
|
{
|
||||||
|
if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength);
|
||||||
|
*currentData += fragmentLength;
|
||||||
|
if (fragmentLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ENetPeer::Channel& channel = peer->m_channels[command->header.channelID];
|
||||||
|
UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber);
|
||||||
|
UInt16 startWindow = startSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize;
|
||||||
|
UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize;
|
||||||
|
|
||||||
|
if (startSequenceNumber < channel.incomingReliableSequenceNumber)
|
||||||
|
startWindow += ENetConstants::ENetPeer_ReliableWindows;
|
||||||
|
|
||||||
|
if (startWindow < currentWindow || startWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber);
|
||||||
|
UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount);
|
||||||
|
UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset);
|
||||||
|
UInt32 totalLength = NetToHost(command->sendFragment.totalLength);
|
||||||
|
|
||||||
|
if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_maximumPacketSize ||
|
||||||
|
fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ENetPeer::IncomingCommmand* startCommand = nullptr;
|
||||||
|
for (auto currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand)
|
||||||
|
{
|
||||||
|
ENetPeer::IncomingCommmand& incomingCommand = *currentCommand;
|
||||||
|
|
||||||
|
if (startSequenceNumber >= channel.incomingReliableSequenceNumber)
|
||||||
|
{
|
||||||
|
if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (incomingCommand.reliableSequenceNumber <= startSequenceNumber)
|
||||||
|
{
|
||||||
|
if (incomingCommand.reliableSequenceNumber < startSequenceNumber)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment ||
|
||||||
|
totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
startCommand = &incomingCommand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startCommand)
|
||||||
|
{
|
||||||
|
ENetProtocol hostCommand = *command;
|
||||||
|
hostCommand.header.reliableSequenceNumber = startSequenceNumber;
|
||||||
|
|
||||||
|
if (!peer->QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0)
|
||||||
|
{
|
||||||
|
--startCommand->fragmentsRemaining;
|
||||||
|
|
||||||
|
startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32));
|
||||||
|
|
||||||
|
if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize())
|
||||||
|
fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset;
|
||||||
|
|
||||||
|
std::memcpy(startCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + fragmentOffset, reinterpret_cast<const UInt8*>(command) + sizeof(ENetProtocolSendFragment), fragmentLength);
|
||||||
|
|
||||||
|
if (startCommand->fragmentsRemaining <= 0)
|
||||||
|
peer->DispatchIncomingReliableCommands(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData)
|
bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData)
|
||||||
{
|
{
|
||||||
if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater))
|
if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater))
|
||||||
|
|
@ -826,6 +961,152 @@ namespace Nz
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ENetHost::HandleSendUnreliable(ENetPeer * peer, const ENetProtocol * command, UInt8 ** currentData)
|
||||||
|
{
|
||||||
|
if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength);
|
||||||
|
*currentData += dataLength;
|
||||||
|
if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!peer->QueueIncomingCommand(*command, reinterpret_cast<const UInt8*>(command) + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ENetHost::HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData)
|
||||||
|
{
|
||||||
|
if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength);
|
||||||
|
*currentData += fragmentLength;
|
||||||
|
if (fragmentLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ENetPeer::Channel& channel = peer->m_channels[command->header.channelID];
|
||||||
|
UInt32 reliableSequenceNumber = command->header.reliableSequenceNumber;
|
||||||
|
UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber);
|
||||||
|
|
||||||
|
UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize;
|
||||||
|
UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize;
|
||||||
|
|
||||||
|
if (startSequenceNumber < channel.incomingReliableSequenceNumber)
|
||||||
|
reliableWindow += ENetConstants::ENetPeer_ReliableWindows;
|
||||||
|
|
||||||
|
if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && startSequenceNumber <= channel.incomingUnreliableSequenceNumber)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber);
|
||||||
|
UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount);
|
||||||
|
UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset);
|
||||||
|
UInt32 totalLength = NetToHost(command->sendFragment.totalLength);
|
||||||
|
|
||||||
|
if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_maximumPacketSize ||
|
||||||
|
fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ENetPeer::IncomingCommmand* startCommand = nullptr;
|
||||||
|
for (auto currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand)
|
||||||
|
{
|
||||||
|
ENetPeer::IncomingCommmand& incomingCommand = *currentCommand;
|
||||||
|
|
||||||
|
if (startSequenceNumber >= channel.incomingReliableSequenceNumber)
|
||||||
|
{
|
||||||
|
if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (incomingCommand.unreliableSequenceNumber <= startSequenceNumber)
|
||||||
|
{
|
||||||
|
if (incomingCommand.unreliableSequenceNumber < startSequenceNumber)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment ||
|
||||||
|
totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
startCommand = &incomingCommand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startCommand)
|
||||||
|
{
|
||||||
|
if (!peer->QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0)
|
||||||
|
{
|
||||||
|
--startCommand->fragmentsRemaining;
|
||||||
|
|
||||||
|
startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32));
|
||||||
|
|
||||||
|
if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize())
|
||||||
|
fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset;
|
||||||
|
|
||||||
|
std::memcpy(startCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + fragmentOffset, reinterpret_cast<const UInt8*>(command) + sizeof(ENetProtocolSendFragment), fragmentLength);
|
||||||
|
|
||||||
|
if (startCommand->fragmentsRemaining <= 0)
|
||||||
|
peer->DispatchIncomingUnreliableCommands(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ENetHost::HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData)
|
||||||
|
{
|
||||||
|
if (command->header.channelID >= peer->m_channels.size() || peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength);
|
||||||
|
*currentData += dataLength;
|
||||||
|
if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UInt32 unsequencedGroup = NetToHost(command->sendUnsequenced.unsequencedGroup);
|
||||||
|
UInt32 index = unsequencedGroup % ENetConstants::ENetPeer_UnsequencedWindowSize;
|
||||||
|
|
||||||
|
if (unsequencedGroup < peer->m_incomingUnsequencedGroup)
|
||||||
|
unsequencedGroup += 0x10000;
|
||||||
|
|
||||||
|
if (unsequencedGroup >= static_cast<UInt32>(peer->m_incomingUnsequencedGroup) + ENetConstants::ENetPeer_UnsequencedWindows * ENetConstants::ENetPeer_UnsequencedWindowSize)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
unsequencedGroup &= 0xFFFF;
|
||||||
|
|
||||||
|
if (unsequencedGroup - index != peer->m_incomingUnsequencedGroup)
|
||||||
|
{
|
||||||
|
peer->m_incomingUnsequencedGroup = unsequencedGroup - index;
|
||||||
|
|
||||||
|
peer->m_unsequencedWindow.fill(0);
|
||||||
|
}
|
||||||
|
else if (peer->m_unsequencedWindow[index / 32] & (1 << (index % 32)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!peer->QueueIncomingCommand(*command, reinterpret_cast<const UInt8*>(command) + sizeof(ENetProtocolSendUnsequenced), dataLength, ENetPacketFlag_Unsequenced, 0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
peer->m_unsequencedWindow[index / 32] |= 1 << (index % 32);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command)
|
bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command)
|
||||||
{
|
{
|
||||||
if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)
|
if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)
|
||||||
|
|
@ -901,17 +1182,8 @@ namespace Nz
|
||||||
|
|
||||||
// Intercept
|
// Intercept
|
||||||
|
|
||||||
switch (HandleIncomingCommands(event))
|
if (HandleIncomingCommands(event))
|
||||||
{
|
return 1;
|
||||||
case 1:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -956,6 +1228,346 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ENetHost::SendAcknowledgements(ENetPeer* peer)
|
||||||
|
{
|
||||||
|
std::cout << "SendAcknowledgements " << peer->m_acknowledgements.size() << std::endl;
|
||||||
|
|
||||||
|
auto currentAcknowledgement = peer->m_acknowledgements.begin();
|
||||||
|
while (currentAcknowledgement != peer->m_acknowledgements.end())
|
||||||
|
{
|
||||||
|
if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->m_mtu - m_packetSize < sizeof(ENetProtocolAcknowledge))
|
||||||
|
{
|
||||||
|
m_continueSending = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENetPeer::Acknowledgement& acknowledgement = *currentAcknowledgement;
|
||||||
|
|
||||||
|
ENetProtocol& command = m_commands[m_commandCount];
|
||||||
|
NetBuffer& buffer = m_buffers[m_bufferCount];
|
||||||
|
|
||||||
|
buffer.data = &command;
|
||||||
|
buffer.dataLength = sizeof(ENetProtocolAcknowledge);
|
||||||
|
|
||||||
|
m_packetSize += buffer.dataLength;
|
||||||
|
|
||||||
|
UInt16 reliableSequenceNumber = HostToNet(acknowledgement.command.header.reliableSequenceNumber);
|
||||||
|
|
||||||
|
command.header.command = ENetProtocolCommand_Acknowledge;
|
||||||
|
command.header.channelID = acknowledgement.command.header.channelID;
|
||||||
|
command.header.reliableSequenceNumber = reliableSequenceNumber;
|
||||||
|
command.acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber;
|
||||||
|
command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime);
|
||||||
|
|
||||||
|
if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect)
|
||||||
|
peer->DispatchState(ENetPeerState::Zombie);
|
||||||
|
|
||||||
|
currentAcknowledgement = peer->m_acknowledgements.erase(currentAcknowledgement);
|
||||||
|
|
||||||
|
++m_bufferCount;
|
||||||
|
++m_commandCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ENetHost::SendReliableOutgoingCommands(ENetPeer* peer)
|
||||||
|
{
|
||||||
|
bool canPing = true;
|
||||||
|
bool windowExceeded = false;
|
||||||
|
bool windowWrap = false;
|
||||||
|
|
||||||
|
auto currentCommand = peer->m_outgoingReliableCommands.begin();
|
||||||
|
while (currentCommand != peer->m_outgoingReliableCommands.end())
|
||||||
|
{
|
||||||
|
auto outgoingCommand = currentCommand;
|
||||||
|
|
||||||
|
UInt16 reliableWindow = outgoingCommand->reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize;
|
||||||
|
ENetPeer::Channel* channel = (outgoingCommand->command.header.channelID < peer->m_channels.size()) ? &peer->m_channels[outgoingCommand->command.header.channelID] : nullptr;
|
||||||
|
if (channel)
|
||||||
|
{
|
||||||
|
if (!windowWrap && outgoingCommand->sendAttempts < 1 && !(outgoingCommand->reliableSequenceNumber % ENetPeer_ReliableWindowSize) &&
|
||||||
|
((channel->reliableWindows[(reliableWindow + ENetPeer_ReliableWindows - 1) % ENetPeer_ReliableWindows] >= ENetPeer_ReliableWindowSize) ||
|
||||||
|
channel->usedReliableWindows & ((((1 << ENetPeer_ReliableWindows) - 1) << reliableWindow) |
|
||||||
|
(((1 << ENetPeer_FreeReliableWindows) - 1) >> (ENetPeer_ReliableWindows - reliableWindow)))))
|
||||||
|
windowWrap = true;
|
||||||
|
|
||||||
|
if (windowWrap)
|
||||||
|
{
|
||||||
|
++currentCommand;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outgoingCommand->packet)
|
||||||
|
{
|
||||||
|
if (!windowExceeded)
|
||||||
|
{
|
||||||
|
UInt32 windowSize = (peer->m_packetThrottle * peer->m_windowSize) / ENetPeer_PacketThrottleScale;
|
||||||
|
|
||||||
|
if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->m_mtu))
|
||||||
|
windowExceeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowExceeded)
|
||||||
|
{
|
||||||
|
++currentCommand;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canPing = false;
|
||||||
|
|
||||||
|
std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask];
|
||||||
|
if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->m_mtu - m_packetSize < commandSize ||
|
||||||
|
(outgoingCommand->packet && UInt16(peer->m_mtu - m_packetSize) < UInt16(commandSize + outgoingCommand->fragmentLength)))
|
||||||
|
{
|
||||||
|
m_continueSending = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++currentCommand;
|
||||||
|
|
||||||
|
if (channel && outgoingCommand->sendAttempts < 1)
|
||||||
|
{
|
||||||
|
channel->usedReliableWindows |= 1 << reliableWindow;
|
||||||
|
++channel->reliableWindows[reliableWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
++outgoingCommand->sendAttempts;
|
||||||
|
|
||||||
|
if (outgoingCommand->roundTripTimeout == 0)
|
||||||
|
{
|
||||||
|
outgoingCommand->roundTripTimeout = peer->m_roundTripTime + 4 * peer->m_roundTripTimeVariance;
|
||||||
|
outgoingCommand->roundTripTimeoutLimit = peer->m_timeoutLimit * outgoingCommand->roundTripTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peer->m_sentReliableCommands.empty())
|
||||||
|
peer->m_nextTimeout = m_serviceTime + outgoingCommand->roundTripTimeout;
|
||||||
|
|
||||||
|
peer->m_sentReliableCommands.emplace_back(std::move(*outgoingCommand));
|
||||||
|
peer->m_outgoingReliableCommands.erase(outgoingCommand);
|
||||||
|
|
||||||
|
outgoingCommand = peer->m_sentReliableCommands.end();
|
||||||
|
--outgoingCommand;
|
||||||
|
|
||||||
|
outgoingCommand->sentTime = m_serviceTime;
|
||||||
|
|
||||||
|
ENetProtocol& command = m_commands[m_commandCount];
|
||||||
|
NetBuffer& buffer = m_buffers[m_bufferCount];
|
||||||
|
|
||||||
|
buffer.data = &command;
|
||||||
|
buffer.dataLength = commandSize;
|
||||||
|
|
||||||
|
m_packetSize += buffer.dataLength;
|
||||||
|
m_headerFlags |= ENetProtocolHeaderFlag_SentTime;
|
||||||
|
|
||||||
|
command = outgoingCommand->command;
|
||||||
|
|
||||||
|
if (outgoingCommand->packet)
|
||||||
|
{
|
||||||
|
++m_bufferCount;
|
||||||
|
|
||||||
|
NetBuffer& packetBuffer = m_buffers[m_bufferCount];
|
||||||
|
packetBuffer.data = outgoingCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + outgoingCommand->fragmentOffset;
|
||||||
|
packetBuffer.dataLength = outgoingCommand->fragmentLength;
|
||||||
|
|
||||||
|
m_packetSize += packetBuffer.dataLength;
|
||||||
|
|
||||||
|
peer->m_reliableDataInTransit += outgoingCommand->fragmentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
++peer->m_packetsSent;
|
||||||
|
++m_bufferCount;
|
||||||
|
++m_commandCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canPing;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ENetHost::SendOutgoingCommands(ENetEvent* event, bool checkForTimeouts)
|
||||||
|
{
|
||||||
|
std::array<UInt8, sizeof(ENetProtocolHeader) + sizeof(UInt32)> headerData;
|
||||||
|
ENetProtocolHeader* header = reinterpret_cast<ENetProtocolHeader*>(headerData.data());
|
||||||
|
|
||||||
|
m_continueSending = true;
|
||||||
|
|
||||||
|
while (m_continueSending)
|
||||||
|
{
|
||||||
|
m_continueSending = false;
|
||||||
|
|
||||||
|
for (std::size_t peer = 0; peer < m_peerCount; ++peer)
|
||||||
|
{
|
||||||
|
ENetPeer* currentPeer = &m_peers[peer];
|
||||||
|
if (currentPeer->m_state == ENetPeerState::Disconnected || currentPeer->m_state == ENetPeerState::Zombie)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_headerFlags = 0;
|
||||||
|
m_commandCount = 0;
|
||||||
|
m_bufferCount = 1;
|
||||||
|
m_packetSize = sizeof(ENetProtocolHeader);
|
||||||
|
|
||||||
|
if (!currentPeer->m_acknowledgements.empty())
|
||||||
|
SendAcknowledgements(currentPeer);
|
||||||
|
|
||||||
|
if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) &&
|
||||||
|
CheckTimeouts(currentPeer, event))
|
||||||
|
{
|
||||||
|
if (event && event->type != ENetEventType::None)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((currentPeer->m_outgoingReliableCommands.empty() || SendReliableOutgoingCommands(currentPeer)) && currentPeer->m_sentReliableCommands.empty() &&
|
||||||
|
ENET_TIME_DIFFERENCE(m_serviceTime, currentPeer->m_lastReceiveTime) >= currentPeer->m_pingInterval && currentPeer->m_mtu - m_packetSize >= sizeof(ENetProtocolPing))
|
||||||
|
{
|
||||||
|
currentPeer->Ping();
|
||||||
|
SendReliableOutgoingCommands(currentPeer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentPeer->m_outgoingUnreliableCommands.empty())
|
||||||
|
SendUnreliableOutgoingCommands(currentPeer);
|
||||||
|
|
||||||
|
if (m_commandCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (currentPeer->m_packetLossEpoch == 0)
|
||||||
|
currentPeer->m_packetLossEpoch = m_serviceTime;
|
||||||
|
else if (ENET_TIME_DIFFERENCE(m_serviceTime, currentPeer->m_packetLossEpoch) >= ENetPeer_PacketLossInterval && currentPeer->m_packetsSent > 0)
|
||||||
|
{
|
||||||
|
UInt32 packetLoss = currentPeer->m_packetsLost * ENetPeer_PacketLossScale / currentPeer->m_packetsSent;
|
||||||
|
|
||||||
|
#ifdef ENET_DEBUG
|
||||||
|
printf("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer->incomingPeerID, currentPeer->packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->roundTripTime, currentPeer->roundTripTimeVariance, currentPeer->packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size(¤tPeer->outgoingReliableCommands), enet_list_size(¤tPeer->outgoingUnreliableCommands), currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingReliableCommands) : 0, currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingUnreliableCommands) : 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
currentPeer->m_packetLossVariance -= currentPeer->m_packetLossVariance / 4;
|
||||||
|
|
||||||
|
if (packetLoss >= currentPeer->m_packetLoss)
|
||||||
|
{
|
||||||
|
currentPeer->m_packetLoss += (packetLoss - currentPeer->m_packetLoss) / 8;
|
||||||
|
currentPeer->m_packetLossVariance += (packetLoss - currentPeer->m_packetLoss) / 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentPeer->m_packetLoss -= (currentPeer->m_packetLoss - packetLoss) / 8;
|
||||||
|
currentPeer->m_packetLossVariance += (currentPeer->m_packetLoss - packetLoss) / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPeer->m_packetLossEpoch = m_serviceTime;
|
||||||
|
currentPeer->m_packetsSent = 0;
|
||||||
|
currentPeer->m_packetsLost = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
m_buffers[0].data = headerData.data();
|
||||||
|
if (m_headerFlags & ENetProtocolHeaderFlag_SentTime)
|
||||||
|
{
|
||||||
|
header->sentTime = HostToNet(static_cast<UInt16>(m_serviceTime));
|
||||||
|
|
||||||
|
m_buffers[0].dataLength = sizeof(ENetProtocolHeader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_buffers[0].dataLength = NazaraOffsetOf(ENetProtocolHeader, sentTime);
|
||||||
|
|
||||||
|
if (currentPeer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId)
|
||||||
|
m_headerFlags |= currentPeer->m_outgoingSessionID << ENetProtocolHeaderSessionShift;
|
||||||
|
|
||||||
|
header->peerID = HostToNet(static_cast<UInt16>(currentPeer->m_outgoingPeerID | m_headerFlags));
|
||||||
|
|
||||||
|
currentPeer->m_lastSendTime = m_serviceTime;
|
||||||
|
|
||||||
|
std::size_t sentLength;
|
||||||
|
if (!m_socket.SendMultiple(currentPeer->m_address, m_buffers.data(), m_bufferCount, &sentLength))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
currentPeer->RemoveSentUnreliableCommands();
|
||||||
|
|
||||||
|
m_totalSentData += sentLength;
|
||||||
|
m_totalSentPackets++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENetHost::SendUnreliableOutgoingCommands(ENetPeer* peer)
|
||||||
|
{
|
||||||
|
auto currentCommand = peer->m_outgoingUnreliableCommands.begin();
|
||||||
|
while (currentCommand != peer->m_outgoingUnreliableCommands.end())
|
||||||
|
{
|
||||||
|
auto outgoingCommand = currentCommand;
|
||||||
|
|
||||||
|
std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask];
|
||||||
|
|
||||||
|
if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->m_mtu - m_packetSize < commandSize ||
|
||||||
|
(outgoingCommand->packet && peer->m_mtu - m_packetSize < commandSize + outgoingCommand->fragmentLength))
|
||||||
|
{
|
||||||
|
m_continueSending = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++currentCommand;
|
||||||
|
|
||||||
|
if (outgoingCommand->packet && outgoingCommand->fragmentOffset == 0)
|
||||||
|
{
|
||||||
|
peer->m_packetThrottleCounter += ENetConstants::ENetPeer_PacketThrottleCounter;
|
||||||
|
peer->m_packetThrottleCounter %= ENetConstants::ENetPeer_PacketThrottleScale;
|
||||||
|
|
||||||
|
if (peer->m_packetThrottleCounter > peer->m_packetThrottle)
|
||||||
|
{
|
||||||
|
UInt16 reliableSequenceNumber = outgoingCommand->reliableSequenceNumber;
|
||||||
|
UInt16 unreliableSequenceNumber = outgoingCommand->unreliableSequenceNumber;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
peer->m_outgoingUnreliableCommands.erase(outgoingCommand);
|
||||||
|
|
||||||
|
if (currentCommand == peer->m_outgoingUnreliableCommands.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
outgoingCommand = currentCommand;
|
||||||
|
if (outgoingCommand->reliableSequenceNumber != reliableSequenceNumber || outgoingCommand->unreliableSequenceNumber != unreliableSequenceNumber)
|
||||||
|
break;
|
||||||
|
|
||||||
|
++currentCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ENetProtocol& command = m_commands[m_commandCount];
|
||||||
|
NetBuffer& buffer = m_buffers[m_bufferCount];
|
||||||
|
|
||||||
|
buffer.data = &command;
|
||||||
|
buffer.dataLength = commandSize;
|
||||||
|
|
||||||
|
command = outgoingCommand->command;
|
||||||
|
|
||||||
|
if (outgoingCommand->packet)
|
||||||
|
{
|
||||||
|
++m_bufferCount;
|
||||||
|
|
||||||
|
NetBuffer& packetBuffer = m_buffers[m_bufferCount];
|
||||||
|
packetBuffer.data = outgoingCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + outgoingCommand->fragmentOffset;
|
||||||
|
packetBuffer.dataLength = outgoingCommand->fragmentLength;
|
||||||
|
|
||||||
|
m_packetSize += packetBuffer.dataLength;
|
||||||
|
|
||||||
|
peer->m_sentUnreliableCommands.emplace_back(std::move(*outgoingCommand));
|
||||||
|
}
|
||||||
|
|
||||||
|
peer->m_outgoingUnreliableCommands.erase(outgoingCommand);
|
||||||
|
|
||||||
|
++m_bufferCount;
|
||||||
|
++m_commandCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peer->m_state == ENetPeerState::DisconnectLater && peer->m_outgoingReliableCommands.empty() &&
|
||||||
|
peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty())
|
||||||
|
peer->Disconnect(peer->m_eventData);
|
||||||
|
}
|
||||||
|
|
||||||
void ENetHost::ThrottleBandwidth()
|
void ENetHost::ThrottleBandwidth()
|
||||||
{
|
{
|
||||||
UInt32 currentTime = GetElapsedMilliseconds();
|
UInt32 currentTime = GetElapsedMilliseconds();
|
||||||
|
|
@ -1108,6 +1720,11 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t ENetHost::GetCommandSize(UInt8 commandNumber)
|
||||||
|
{
|
||||||
|
return s_commandSizes[commandNumber & ENetProtocolCommand_Mask];
|
||||||
|
}
|
||||||
|
|
||||||
bool ENetHost::Initialize()
|
bool ENetHost::Initialize()
|
||||||
{
|
{
|
||||||
std::random_device device;
|
std::random_device device;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
#include <Nazara/Network/ENetPacket.hpp>
|
#include <Nazara/Network/ENetPacket.hpp>
|
||||||
#include <Nazara/Core/MemoryPool.hpp>
|
#include <Nazara/Core/MemoryPool.hpp>
|
||||||
#include <Nazara/Network/Debug.hpp>
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
/// Temporary
|
/// Temporary
|
||||||
void ENetPacketRef::Reset(ENetPacket* packet = nullptr)
|
void ENetPacketRef::Reset(ENetPacket* packet)
|
||||||
{
|
{
|
||||||
if (m_packet)
|
if (m_packet)
|
||||||
{
|
{
|
||||||
|
|
@ -20,4 +20,4 @@ namespace Nz
|
||||||
if (m_packet)
|
if (m_packet)
|
||||||
m_packet->referenceCount++;
|
m_packet->referenceCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
#include <Nazara/Network/ENetPeer.hpp>
|
#include <Nazara/Network/ENetPeer.hpp>
|
||||||
#include <Nazara/Core/Endianness.hpp>
|
#include <Nazara/Core/Endianness.hpp>
|
||||||
#include <Nazara/Network/ENetHost.hpp>
|
#include <Nazara/Network/ENetHost.hpp>
|
||||||
#include <Nazara/Network/NetPacket.hpp>
|
#include <Nazara/Network/NetPacket.hpp>
|
||||||
|
#include <iostream>
|
||||||
#include <Nazara/Network/Debug.hpp>
|
#include <Nazara/Network/Debug.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
|
|
@ -129,7 +130,7 @@ namespace Nz
|
||||||
|
|
||||||
IncomingCommmand& incomingCommand = m_dispatchedCommands.front();
|
IncomingCommmand& incomingCommand = m_dispatchedCommands.front();
|
||||||
|
|
||||||
m_totalWaitingData -= incomingCommand.packet->data.GetSize();
|
m_totalWaitingData -= incomingCommand.packet->data.GetDataSize();
|
||||||
|
|
||||||
if (packet)
|
if (packet)
|
||||||
*packet = std::move(incomingCommand.packet);
|
*packet = std::move(incomingCommand.packet);
|
||||||
|
|
@ -192,7 +193,7 @@ namespace Nz
|
||||||
m_eventData = 0;
|
m_eventData = 0;
|
||||||
m_totalWaitingData = 0;
|
m_totalWaitingData = 0;
|
||||||
|
|
||||||
std::memset(m_unsequencedWindow, 0, sizeof(m_unsequencedWindow));
|
m_unsequencedWindow.fill(0);
|
||||||
|
|
||||||
ResetQueues();
|
ResetQueues();
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +210,7 @@ namespace Nz
|
||||||
|
|
||||||
bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef)
|
bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef)
|
||||||
{
|
{
|
||||||
if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetSize() > m_host->m_maximumPacketSize)
|
if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetDataSize() > m_host->m_maximumPacketSize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Channel& channel = m_channels[channelId];
|
Channel& channel = m_channels[channelId];
|
||||||
|
|
@ -218,7 +219,7 @@ namespace Nz
|
||||||
//if (m_host->m_checksum != nullptr)
|
//if (m_host->m_checksum != nullptr)
|
||||||
// fragmentLength -= sizeof(UInt32);
|
// fragmentLength -= sizeof(UInt32);
|
||||||
|
|
||||||
UInt32 packetSize = static_cast<UInt32>(packetRef->data.GetSize());
|
UInt32 packetSize = static_cast<UInt32>(packetRef->data.GetDataSize());
|
||||||
if (packetSize > fragmentLength)
|
if (packetSize > fragmentLength)
|
||||||
{
|
{
|
||||||
UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength;
|
UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength;
|
||||||
|
|
@ -254,7 +255,7 @@ namespace Nz
|
||||||
|
|
||||||
OutgoingCommand outgoingCommand;
|
OutgoingCommand outgoingCommand;
|
||||||
outgoingCommand.fragmentOffset = fragmentOffset;
|
outgoingCommand.fragmentOffset = fragmentOffset;
|
||||||
outgoingCommand.fragmentLength = fragmentLength;
|
outgoingCommand.fragmentLength = static_cast<UInt16>(fragmentLength);
|
||||||
outgoingCommand.packet = packetRef;
|
outgoingCommand.packet = packetRef;
|
||||||
outgoingCommand.command.header.command = commandNumber;
|
outgoingCommand.command.header.command = commandNumber;
|
||||||
outgoingCommand.command.header.channelID = channelId;
|
outgoingCommand.command.header.channelID = channelId;
|
||||||
|
|
@ -275,11 +276,20 @@ namespace Nz
|
||||||
command.header.channelID = channelId;
|
command.header.channelID = channelId;
|
||||||
|
|
||||||
if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_Unsequenced)
|
if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_Unsequenced)
|
||||||
|
{
|
||||||
command.header.command = ENetProtocolCommand_SendUnsequenced | ENetProtocolFlag_Unsequenced;
|
command.header.command = ENetProtocolCommand_SendUnsequenced | ENetProtocolFlag_Unsequenced;
|
||||||
|
command.sendUnsequenced.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize()));
|
||||||
|
}
|
||||||
else if (packetRef->flags & ENetPacketFlag_Reliable || channel.outgoingUnreliableSequenceNumber >= 0xFFFF)
|
else if (packetRef->flags & ENetPacketFlag_Reliable || channel.outgoingUnreliableSequenceNumber >= 0xFFFF)
|
||||||
|
{
|
||||||
command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge;
|
command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge;
|
||||||
|
command.sendReliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize()));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
command.header.command = ENetProtocolCommand_SendUnreliable;
|
command.header.command = ENetProtocolCommand_SendUnreliable;
|
||||||
|
command.sendUnreliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize()));
|
||||||
|
}
|
||||||
|
|
||||||
QueueOutgoingCommand(command, packetRef, 0, packetSize);
|
QueueOutgoingCommand(command, packetRef, 0, packetSize);
|
||||||
|
|
||||||
|
|
@ -354,6 +364,13 @@ namespace Nz
|
||||||
m_windowSize = Clamp<UInt32>(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize);
|
m_windowSize = Clamp<UInt32>(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ENetPeer::DispatchState(ENetPeerState state)
|
||||||
|
{
|
||||||
|
ChangeState(state);
|
||||||
|
|
||||||
|
m_host->AddToDispatchQueue(this);
|
||||||
|
}
|
||||||
|
|
||||||
void ENetPeer::DispatchIncomingReliableCommands(Channel& channel)
|
void ENetPeer::DispatchIncomingReliableCommands(Channel& channel)
|
||||||
{
|
{
|
||||||
auto currentCommand = channel.incomingReliableCommands.begin();
|
auto currentCommand = channel.incomingReliableCommands.begin();
|
||||||
|
|
@ -375,7 +392,7 @@ namespace Nz
|
||||||
|
|
||||||
channel.incomingUnreliableSequenceNumber = 0;
|
channel.incomingUnreliableSequenceNumber = 0;
|
||||||
|
|
||||||
m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, channel.incomingReliableCommands.begin(), currentCommand);
|
m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingReliableCommands, channel.incomingReliableCommands.begin(), currentCommand);
|
||||||
|
|
||||||
m_host->AddToDispatchQueue(this);
|
m_host->AddToDispatchQueue(this);
|
||||||
|
|
||||||
|
|
@ -408,7 +425,7 @@ namespace Nz
|
||||||
|
|
||||||
if (startCommand != currentCommand)
|
if (startCommand != currentCommand)
|
||||||
{
|
{
|
||||||
m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand);
|
m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand);
|
||||||
|
|
||||||
m_host->AddToDispatchQueue(this);
|
m_host->AddToDispatchQueue(this);
|
||||||
|
|
||||||
|
|
@ -436,7 +453,7 @@ namespace Nz
|
||||||
|
|
||||||
if (startCommand != currentCommand)
|
if (startCommand != currentCommand)
|
||||||
{
|
{
|
||||||
m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand);
|
m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand);
|
||||||
|
|
||||||
m_host->AddToDispatchQueue(this);
|
m_host->AddToDispatchQueue(this);
|
||||||
}
|
}
|
||||||
|
|
@ -448,7 +465,7 @@ namespace Nz
|
||||||
|
|
||||||
if (startCommand != currentCommand)
|
if (startCommand != currentCommand)
|
||||||
{
|
{
|
||||||
m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand);
|
m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand);
|
||||||
|
|
||||||
m_host->AddToDispatchQueue(this);
|
m_host->AddToDispatchQueue(this);
|
||||||
|
|
||||||
|
|
@ -587,7 +604,7 @@ namespace Nz
|
||||||
}
|
}
|
||||||
|
|
||||||
Acknowledgement acknowledgment;
|
Acknowledgement acknowledgment;
|
||||||
acknowledgment.command = command;
|
acknowledgment.command = *command;
|
||||||
acknowledgment.sentTime = sentTime;
|
acknowledgment.sentTime = sentTime;
|
||||||
|
|
||||||
m_outgoingDataTotal += sizeof(Acknowledgement);
|
m_outgoingDataTotal += sizeof(Acknowledgement);
|
||||||
|
|
@ -597,7 +614,7 @@ namespace Nz
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount)
|
ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount)
|
||||||
{
|
{
|
||||||
static IncomingCommmand dummyCommand;
|
static IncomingCommmand dummyCommand;
|
||||||
|
|
||||||
|
|
@ -740,6 +757,9 @@ namespace Nz
|
||||||
incomingCommand.fragments.resize(fragmentCount, 0);
|
incomingCommand.fragments.resize(fragmentCount, 0);
|
||||||
incomingCommand.fragmentsRemaining = fragmentCount;
|
incomingCommand.fragmentsRemaining = fragmentCount;
|
||||||
|
|
||||||
|
if (packet)
|
||||||
|
m_totalWaitingData += packet->data.GetDataSize();
|
||||||
|
|
||||||
auto it = commandList->insert(currentCommand.base(), incomingCommand);
|
auto it = commandList->insert(currentCommand.base(), incomingCommand);
|
||||||
|
|
||||||
switch (command.header.command & ENetProtocolCommand_Mask)
|
switch (command.header.command & ENetProtocolCommand_Mask)
|
||||||
|
|
@ -762,7 +782,7 @@ namespace Nz
|
||||||
OutgoingCommand outgoingCommand;
|
OutgoingCommand outgoingCommand;
|
||||||
outgoingCommand.command = command;
|
outgoingCommand.command = command;
|
||||||
outgoingCommand.fragmentLength = length;
|
outgoingCommand.fragmentLength = length;
|
||||||
outgoingCommand.fragmentOffset = length;
|
outgoingCommand.fragmentOffset = offset;
|
||||||
outgoingCommand.packet = packet;
|
outgoingCommand.packet = packet;
|
||||||
|
|
||||||
SetupOutgoingCommand(outgoingCommand);
|
SetupOutgoingCommand(outgoingCommand);
|
||||||
|
|
@ -770,7 +790,7 @@ namespace Nz
|
||||||
|
|
||||||
void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand)
|
void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand)
|
||||||
{
|
{
|
||||||
m_outgoingDataTotal += enet_protocol_command_size(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength;
|
m_outgoingDataTotal += ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength;
|
||||||
|
|
||||||
if (outgoingCommand.command.header.channelID == 0xFF)
|
if (outgoingCommand.command.header.channelID == 0xFF)
|
||||||
{
|
{
|
||||||
|
|
@ -827,7 +847,7 @@ namespace Nz
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outgoingCommand.command.header.command & ENetProtocolCommand_Acknowledge)
|
if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge)
|
||||||
m_outgoingReliableCommands.emplace_back(outgoingCommand);
|
m_outgoingReliableCommands.emplace_back(outgoingCommand);
|
||||||
else
|
else
|
||||||
m_outgoingUnreliableCommands.emplace_back(outgoingCommand);
|
m_outgoingUnreliableCommands.emplace_back(outgoingCommand);
|
||||||
|
|
|
||||||
|
|
@ -1,642 +0,0 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
|
||||||
// This file is part of the "Nazara Engine - Utility module"
|
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
||||||
|
|
||||||
#include <Nazara/Network/ENetHost.hpp>
|
|
||||||
#include <Nazara/Core/CallOnExit.hpp>
|
|
||||||
#include <Nazara/Core/Log.hpp>
|
|
||||||
#include <Nazara/Network/NetPacket.hpp>
|
|
||||||
#include <Nazara/Network/Debug.hpp>
|
|
||||||
|
|
||||||
namespace Nz
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
* \ingroup network
|
|
||||||
* \class Nz::ENetConnection
|
|
||||||
* \brief Network class that represents a reliable UDP connection, based on ENet library
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Constructs a RUdpConnection object by default
|
|
||||||
*/
|
|
||||||
|
|
||||||
ENetSocket::ENetSocket() :
|
|
||||||
m_bandwidthThrottleEpoch(0),
|
|
||||||
m_mtu(ENetConstants::DefaultMTU),
|
|
||||||
m_isSimulationEnabled(false),
|
|
||||||
m_shouldAcceptConnections(true)
|
|
||||||
{
|
|
||||||
m_randomSeed = *reinterpret_cast<UInt32*>(this);
|
|
||||||
m_randomSeed += s_randomGenerator();
|
|
||||||
m_randomSeed = (m_randomSeed << 16) | (m_randomSeed >> 16);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \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(remoteAddress.IsValid(), "Invalid remote address");
|
|
||||||
NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port");
|
|
||||||
|
|
||||||
PeerData& client = RegisterPeer(remoteAddress, PeerState_Connecting);
|
|
||||||
client.stateData1 = s_randomGenerator();
|
|
||||||
|
|
||||||
NetPacket connectionRequestPacket(NetCode_RequestConnection);
|
|
||||||
connectionRequestPacket << client.stateData1;
|
|
||||||
|
|
||||||
EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionRequestPacket);
|
|
||||||
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);
|
|
||||||
if (results.empty())
|
|
||||||
{
|
|
||||||
m_lastError = SocketError_ResolveError;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IpAddress hostnameAddress;
|
|
||||||
for (const HostnameInfo& result : results)
|
|
||||||
{
|
|
||||||
if (!result.address)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (result.socketType != SocketType_UDP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
hostnameAddress = result.address;
|
|
||||||
break; //< Take first valid address
|
|
||||||
}
|
|
||||||
|
|
||||||
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()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
*message = std::move(m_receivedMessages.front());
|
|
||||||
m_receivedMessages.pop();
|
|
||||||
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);
|
|
||||||
if (it == m_peerByIP.end())
|
|
||||||
return false; /// Silently fail (probably a disconnected client)
|
|
||||||
|
|
||||||
EnqueuePacket(m_peers[it->second], priority, reliability, packet);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Updates the reliable connection
|
|
||||||
*/
|
|
||||||
|
|
||||||
void RUdpConnection::Update()
|
|
||||||
{
|
|
||||||
m_currentTime = m_clock.GetMicroseconds();
|
|
||||||
|
|
||||||
NetPacket receivedPacket;
|
|
||||||
IpAddress senderIp;
|
|
||||||
while (m_socket.ReceivePacket(&receivedPacket, &senderIp))
|
|
||||||
OnPacketReceived(senderIp, std::move(receivedPacket));
|
|
||||||
|
|
||||||
//for (unsigned int i = m_activeClients.FindFirst(); i != m_activeClients.npos; i = m_activeClients.FindNext(i))
|
|
||||||
//{
|
|
||||||
// PeerData& clientData = m_peers[i];
|
|
||||||
|
|
||||||
CallOnExit resetIterator([this] () { m_peerIterator = m_peers.size(); });
|
|
||||||
|
|
||||||
for (m_peerIterator = 0; m_peerIterator < m_peers.size(); ++m_peerIterator)
|
|
||||||
{
|
|
||||||
PeerData& peer = m_peers[m_peerIterator];
|
|
||||||
|
|
||||||
UInt32 timeSinceLastPacket = static_cast<UInt32>(m_currentTime - peer.lastPacketTime);
|
|
||||||
if (timeSinceLastPacket > m_timeBeforeTimeOut)
|
|
||||||
{
|
|
||||||
DisconnectPeer(peer.index);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (timeSinceLastPacket > m_timeBeforePing)
|
|
||||||
{
|
|
||||||
if (m_currentTime - peer.lastPingTime > m_pingInterval)
|
|
||||||
{
|
|
||||||
NetPacket pingPacket(NetCode_Ping);
|
|
||||||
EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pingPacket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peer.state == PeerState_WillAck && m_currentTime - peer.stateData1 > m_forceAckSendTime)
|
|
||||||
{
|
|
||||||
NetPacket acknowledgePacket(NetCode_Acknowledge);
|
|
||||||
EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Reliable, acknowledgePacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority)
|
|
||||||
{
|
|
||||||
std::vector<PendingPacket>& pendingPackets = peer.pendingPackets[priority];
|
|
||||||
for (PendingPacket& packetData : pendingPackets)
|
|
||||||
SendPacket(peer, std::move(packetData));
|
|
||||||
|
|
||||||
pendingPackets.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = peer.pendingAckQueue.begin();
|
|
||||||
while (it != peer.pendingAckQueue.end())
|
|
||||||
{
|
|
||||||
if (m_currentTime - it->timeSent > 2 * peer.roundTripTime)
|
|
||||||
{
|
|
||||||
OnPacketLost(peer, std::move(*it));
|
|
||||||
it = peer.pendingAckQueue.erase(it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//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];
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": " + peer.address.ToString() + " has been disconnected due to time-out");
|
|
||||||
|
|
||||||
OnPeerDisconnected(this, peer.address);
|
|
||||||
|
|
||||||
// Remove from IP lookup table
|
|
||||||
m_peerByIP.erase(peer.address);
|
|
||||||
|
|
||||||
// Can we safely "remove" this slot?
|
|
||||||
if (m_peerIterator >= m_peers.size() - 1 || peerIndex > m_peerIterator)
|
|
||||||
{
|
|
||||||
// Yes we can
|
|
||||||
PeerData& newSlot = m_peers[peerIndex];
|
|
||||||
newSlot = std::move(m_peers.back());
|
|
||||||
newSlot.index = peerIndex; //< Update the moved slot index before resizing (in case it's the last one)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Nope, let's be tricky
|
|
||||||
PeerData& current = m_peers[m_peerIterator];
|
|
||||||
PeerData& newSlot = m_peers[peerIndex];
|
|
||||||
|
|
||||||
newSlot = std::move(current);
|
|
||||||
newSlot.index = peerIndex; //< Update the moved slot index
|
|
||||||
|
|
||||||
current = std::move(m_peers.back());
|
|
||||||
current.index = m_peerIterator; //< Update the moved slot index
|
|
||||||
|
|
||||||
--m_peerIterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop the last entry (from where we moved our slot)
|
|
||||||
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);
|
|
||||||
UInt16 protocolEnd = static_cast<UInt16>((m_protocol & 0xFFFF0000) >> 16);
|
|
||||||
|
|
||||||
NetPacket data(packet.GetNetCode(), MessageHeader + packet.GetDataSize() + MessageFooter);
|
|
||||||
data << protocolBegin;
|
|
||||||
|
|
||||||
data.GetStream()->SetCursorPos(NetPacket::HeaderSize + MessageHeader);
|
|
||||||
data.Write(packet.GetConstData() + NetPacket::HeaderSize, packet.GetDataSize());
|
|
||||||
|
|
||||||
data << protocolEnd;
|
|
||||||
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;
|
|
||||||
pendingPacket.data = std::move(data);
|
|
||||||
pendingPacket.priority = priority;
|
|
||||||
pendingPacket.reliability = reliability;
|
|
||||||
|
|
||||||
peer.pendingPackets[priority].emplace_back(std::move(pendingPacket));
|
|
||||||
m_activeClients.UnboundedSet(peer.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Inits the internal socket
|
|
||||||
* \return true If successful
|
|
||||||
*
|
|
||||||
* \param protocol Net protocol to use
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool ENetSocket::InitSocket(NetProtocol protocol)
|
|
||||||
{
|
|
||||||
CallOnExit updateLastError([this]
|
|
||||||
{
|
|
||||||
m_lastError = m_socket.GetLastError();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!m_socket.Create(protocol))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_socket.EnableBlocking(false);
|
|
||||||
m_socket.SetReceiveBufferSize(ENetConstants::ReceiveBufferSize);
|
|
||||||
m_socket.SetSendBufferSize(ENetConstants::SendBufferSize);
|
|
||||||
|
|
||||||
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();
|
|
||||||
while (it != peer.pendingAckQueue.end())
|
|
||||||
{
|
|
||||||
bool acked = false;
|
|
||||||
if (lastAck == it->sequenceId)
|
|
||||||
acked = true;
|
|
||||||
else if (!IsAckMoreRecent(it->sequenceId, lastAck))
|
|
||||||
{
|
|
||||||
unsigned int difference = ComputeSequenceDifference(lastAck, it->sequenceId);
|
|
||||||
if (difference <= 32)
|
|
||||||
acked = (ackBits >> (difference - 1)) & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acked)
|
|
||||||
{
|
|
||||||
it = peer.pendingAckQueue.erase(it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \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;
|
|
||||||
data.address = address;
|
|
||||||
data.localSequence = 0;
|
|
||||||
data.remoteSequence = 0;
|
|
||||||
data.index = m_peers.size();
|
|
||||||
data.lastPacketTime = m_currentTime;
|
|
||||||
data.lastPingTime = m_currentTime;
|
|
||||||
data.roundTripTime = 1'000'000; ///< Okay that's quite a lot
|
|
||||||
data.state = state;
|
|
||||||
|
|
||||||
m_activeClients.UnboundedSet(data.index);
|
|
||||||
m_peerByIP[address] = data.index;
|
|
||||||
|
|
||||||
m_peers.emplace_back(std::move(data));
|
|
||||||
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
|
|
||||||
OnPeerConnection(this, address);
|
|
||||||
|
|
||||||
PeerData& client = RegisterPeer(address, PeerState_Aknowledged);
|
|
||||||
client.remoteSequence = sequenceId;
|
|
||||||
|
|
||||||
/// Acknowledge connection
|
|
||||||
NetPacket connectionAcceptedPacket(NetCode_AcknowledgeConnection);
|
|
||||||
//connectionAcceptedPacket << address;
|
|
||||||
connectionAcceptedPacket << ~token;
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
if (IsReliable(packet.reliability))
|
|
||||||
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;
|
|
||||||
UInt16 protocolEnd;
|
|
||||||
SequenceIndex sequenceId;
|
|
||||||
SequenceIndex lastAck;
|
|
||||||
UInt32 ackBits;
|
|
||||||
|
|
||||||
packet.GetStream()->SetCursorPos(packet.GetSize() - MessageFooter);
|
|
||||||
packet >> protocolEnd;
|
|
||||||
|
|
||||||
packet.GetStream()->SetCursorPos(NetPacket::HeaderSize);
|
|
||||||
packet >> protocolBegin;
|
|
||||||
|
|
||||||
UInt32 protocolId = static_cast<UInt32>(protocolEnd) << 16 | protocolBegin;
|
|
||||||
if (protocolId != m_protocol)
|
|
||||||
return; ///< Ignore
|
|
||||||
|
|
||||||
packet >> sequenceId >> lastAck >> ackBits;
|
|
||||||
|
|
||||||
auto it = m_peerByIP.find(peerIp);
|
|
||||||
if (it == m_peerByIP.end())
|
|
||||||
{
|
|
||||||
switch (packet.GetNetCode())
|
|
||||||
{
|
|
||||||
case NetCode_RequestConnection:
|
|
||||||
{
|
|
||||||
UInt64 token;
|
|
||||||
packet >> token;
|
|
||||||
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString() + ": " + String::Number(token));
|
|
||||||
if (!m_shouldAcceptConnections)
|
|
||||||
return; //< Ignore
|
|
||||||
|
|
||||||
OnClientRequestingConnection(peerIp, sequenceId, token);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return; //< Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PeerData& peer = m_peers[it->second];
|
|
||||||
peer.lastPacketTime = m_currentTime;
|
|
||||||
|
|
||||||
if (peer.receivedQueue.find(sequenceId) != peer.receivedQueue.end())
|
|
||||||
return; //< Ignore
|
|
||||||
|
|
||||||
if (m_isSimulationEnabled && m_packetLossProbability(s_randomGenerator))
|
|
||||||
{
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(sequenceId) + " from " + peerIp.ToString() + " for simulation purpose");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
///< Receiving a packet from an acknowledged client means the connection works in both ways
|
|
||||||
if (peer.state == PeerState_Aknowledged && packet.GetNetCode() != NetCode_RequestConnection)
|
|
||||||
{
|
|
||||||
peer.state = PeerState_Connected;
|
|
||||||
OnPeerAcknowledged(this, peerIp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsAckMoreRecent(sequenceId, peer.remoteSequence))
|
|
||||||
peer.remoteSequence = sequenceId;
|
|
||||||
|
|
||||||
ProcessAcks(peer, lastAck, ackBits);
|
|
||||||
|
|
||||||
peer.receivedQueue.insert(sequenceId);
|
|
||||||
|
|
||||||
switch (packet.GetNetCode())
|
|
||||||
{
|
|
||||||
case NetCode_Acknowledge:
|
|
||||||
return; //< Do not switch to will ack mode (to prevent infinite replies, just let's ping/pong do that)
|
|
||||||
|
|
||||||
case NetCode_AcknowledgeConnection:
|
|
||||||
{
|
|
||||||
if (peer.state == PeerState_Connected)
|
|
||||||
break;
|
|
||||||
|
|
||||||
IpAddress externalAddress;
|
|
||||||
UInt64 token;
|
|
||||||
packet /*>> externalAddress*/ >> token;
|
|
||||||
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_AcknowledgeConnection from " + peerIp.ToString() + ": " + String::Number(token));
|
|
||||||
if (token == ~peer.stateData1)
|
|
||||||
{
|
|
||||||
peer.state = PeerState_Connected;
|
|
||||||
OnConnectedToPeer(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NazaraNotice("Received wrong token (" + String::Number(token) + " instead of " + String::Number(~peer.stateData1) + ") from client " + peer.address);
|
|
||||||
return; //< Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NetCode_RequestConnection:
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString());
|
|
||||||
return; //< Ignore
|
|
||||||
|
|
||||||
case NetCode_Ping:
|
|
||||||
{
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Ping from " + peerIp.ToString());
|
|
||||||
|
|
||||||
NetPacket pongPacket(NetCode_Pong);
|
|
||||||
EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pongPacket);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NetCode_Pong:
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Pong from " + peerIp.ToString());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received 0x" + String::Number(packet.GetNetCode(), 16) + " from " + peerIp.ToString());
|
|
||||||
RUdpMessage receivedMessage;
|
|
||||||
receivedMessage.from = peerIp;
|
|
||||||
receivedMessage.data = std::move(packet);
|
|
||||||
|
|
||||||
m_receivedMessages.emplace(std::move(receivedMessage));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HasPendingPackets(peer))
|
|
||||||
{
|
|
||||||
peer.state = PeerState_WillAck;
|
|
||||||
peer.stateData1 = m_currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \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)
|
|
||||||
peer.state = PeerState_Connected;
|
|
||||||
|
|
||||||
SequenceIndex remoteSequence = peer.remoteSequence;
|
|
||||||
|
|
||||||
UInt32 previousAcks = 0;
|
|
||||||
for (SequenceIndex ack : peer.receivedQueue)
|
|
||||||
{
|
|
||||||
if (ack == remoteSequence)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
unsigned int difference = ComputeSequenceDifference(remoteSequence, ack);
|
|
||||||
if (difference <= 32U)
|
|
||||||
previousAcks |= (1U << (difference - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
SequenceIndex sequenceId = ++peer.localSequence;
|
|
||||||
|
|
||||||
packet.data.GetStream()->SetCursorPos(NetPacket::HeaderSize + sizeof(UInt16)); ///< Protocol begin has already been filled
|
|
||||||
packet.data << sequenceId;
|
|
||||||
packet.data << remoteSequence;
|
|
||||||
packet.data << previousAcks;
|
|
||||||
|
|
||||||
m_socket.SendPacket(peer.address, packet.data);
|
|
||||||
|
|
||||||
PendingAckPacket pendingAckPacket;
|
|
||||||
pendingAckPacket.data = std::move(packet.data);
|
|
||||||
pendingAckPacket.priority = packet.priority;
|
|
||||||
pendingAckPacket.reliability = packet.reliability;
|
|
||||||
pendingAckPacket.sequenceId = sequenceId;
|
|
||||||
pendingAckPacket.timeSent = m_currentTime;
|
|
||||||
|
|
||||||
peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Initializes the RUdpConnection class
|
|
||||||
* \return true
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool RUdpConnection::Initialize()
|
|
||||||
{
|
|
||||||
std::random_device device;
|
|
||||||
s_randomGenerator.seed(device());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Uninitializes the RUdpConnection class
|
|
||||||
*/
|
|
||||||
|
|
||||||
void RUdpConnection::Uninitialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::mt19937_64 RUdpConnection::s_randomGenerator;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue