From 9e3341a32ae61994aa5ce4646199dbddfc22ad16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 25 Jan 2017 15:55:07 +0100 Subject: [PATCH 01/48] Commit current work This is a temporary branch because I'm missing a USB drive, huehue --- include/Nazara/Network/ENetHost.hpp | 121 ++++ include/Nazara/Network/ENetHost.inl | 65 ++ include/Nazara/Network/ENetPacket.hpp | 78 +++ include/Nazara/Network/ENetPeer.hpp | 205 ++++++ include/Nazara/Network/ENetPeer.inl | 29 + include/Nazara/Network/ENetProtocol.hpp | 272 ++++++++ src/Nazara/Network/ENetHost.cpp | 743 ++++++++++++++++++++ src/Nazara/Network/ENetPacket.cpp | 23 + src/Nazara/Network/ENetPeer.cpp | 885 ++++++++++++++++++++++++ src/Nazara/Network/ENetSocket.cpp | 642 +++++++++++++++++ 10 files changed, 3063 insertions(+) create mode 100644 include/Nazara/Network/ENetHost.hpp create mode 100644 include/Nazara/Network/ENetHost.inl create mode 100644 include/Nazara/Network/ENetPacket.hpp create mode 100644 include/Nazara/Network/ENetPeer.hpp create mode 100644 include/Nazara/Network/ENetPeer.inl create mode 100644 include/Nazara/Network/ENetProtocol.hpp create mode 100644 src/Nazara/Network/ENetHost.cpp create mode 100644 src/Nazara/Network/ENetPacket.cpp create mode 100644 src/Nazara/Network/ENetPeer.cpp create mode 100644 src/Nazara/Network/ENetSocket.cpp diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp new file mode 100644 index 000000000..87d4dd37b --- /dev/null +++ b/include/Nazara/Network/ENetHost.hpp @@ -0,0 +1,121 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETHOST_HPP +#define NAZARA_ENETHOST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ENetPeer; + + class NAZARA_NETWORK_API ENetHost + { + friend ENetPeer; + friend class Network; + + public: + inline ENetHost(); + ENetHost(const ENetHost&) = delete; + ENetHost(ENetHost&&) = default; + inline ~ENetHost(); + + void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + + bool Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); + bool 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); + 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, UInt32 incomingBandwidth, UInt32 outgoingBandwidth); + void Destroy(); + + void Flush(); + + int Service(ENetEvent* event, UInt32 timeout); + + ENetHost& operator=(const ENetHost&) = delete; + ENetHost& operator=(ENetHost&&) = default; + + private: + bool InitSocket(const IpAddress& address); + + inline void AddToDispatchQueue(ENetPeer* peer); + inline void RemoveFromDispatchQueue(ENetPeer* peer); + + bool DispatchIncomingCommands(ENetEvent* event); + + ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); + bool HandleIncomingCommands(ENetEvent* event); + bool HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData); + + int ReceiveIncomingCommands(ENetEvent* event); + + void NotifyConnect(ENetPeer* peer, ENetEvent* event); + void NotifyDisconnect(ENetPeer*, ENetEvent* event); + + void ThrottleBandwidth(); + + static bool Initialize(); + static void Uninitialize(); + + std::array m_commands; + std::array m_packetData[2]; + std::bernoulli_distribution m_packetLossProbability; + std::size_t m_bandwidthLimitedPeers; + std::size_t m_bufferCount; + std::size_t m_channelLimit; + std::size_t m_commandCount; + std::size_t m_duplicatePeers; + std::size_t m_maximumPacketSize; + std::size_t m_maximumWaitingData; + std::size_t m_receivedDataLength; + std::vector m_peers; + Bitset m_dispatchQueue; + MemoryPool m_packetPool; + IpAddress m_address; + IpAddress m_receivedAddress; + SocketPoller m_poller; + UdpSocket m_socket; + UInt32 m_bandwidthThrottleEpoch; + UInt32 m_connectedPeers; + UInt32 m_mtu; + UInt32 m_randomSeed; + UInt32 m_incomingBandwidth; + UInt32 m_outgoingBandwidth; + UInt32 m_serviceTime; + UInt32 m_totalSentData; + UInt32 m_totalSentPackets; + UInt32 m_totalReceivedData; + UInt32 m_totalReceivedPackets; + UInt8* m_receivedData; + bool m_isSimulationEnabled; + bool m_shouldAcceptConnections; + bool m_recalculateBandwidthLimits; + + static std::mt19937 s_randomGenerator; + static std::mt19937_64 s_randomGenerator64; + }; +} + +#include + +#endif // NAZARA_RUDPSERVER_HPP diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl new file mode 100644 index 000000000..c4a077e8b --- /dev/null +++ b/include/Nazara/Network/ENetHost.inl @@ -0,0 +1,65 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline ENetHost::ENetHost() : + m_packetPool(sizeof(ENetPacket)) + { + } + + inline ENetHost::~ENetHost() + { + Destroy(); + } + + inline bool ENetHost::Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount) + { + NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO + NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + + IpAddress any; + switch (protocol) + { + case NetProtocol_Any: + case NetProtocol_Unknown: + NazaraInternalError("Invalid protocol Any at this point"); + return false; + + case NetProtocol_IPv4: + any = IpAddress::AnyIpV4; + break; + + case NetProtocol_IPv6: + any = IpAddress::AnyIpV6; + break; + } + + any.SetPort(port); + return Create(any, peerCount, channelCount); + } + + inline void ENetHost::Destroy() + { + m_poller.Clear(); + m_peers.clear(); + 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 diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp new file mode 100644 index 000000000..ad1610eb4 --- /dev/null +++ b/include/Nazara/Network/ENetPacket.hpp @@ -0,0 +1,78 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPACKET_HPP +#define NAZARA_ENETPACKET_HPP + +#include +#include + +namespace Nz +{ + enum ENetPacketFlag + { + ENetPacketFlag_NoAllocate, + ENetPacketFlag_Reliable, + ENetPacketFlag_Unsequenced, + ENetPacketFlag_UnreliableFragment, + ENetPacketFlag_Sent + }; + + template<> + struct EnumAsFlags + { + static constexpr bool value = true; + static constexpr int max = ENetPacketFlag_Sent; + }; + + using ENetPacketFlags = Flags; + + class MemoryPool; + + struct ENetPacket + { + MemoryPool* owner; + ENetPacketFlags flags; + NetPacket data; + std::size_t referenceCount = 0; + }; + + struct ENetPacketRef + { + ENetPacketRef() = default; + + ENetPacketRef(ENetPacket* packet) + { + Reset(packet); + } + + ~ENetPacketRef() + { + Reset(); + } + + void Reset(ENetPacket* packet = nullptr); + + operator ENetPacket*() const + { + return m_packet; + } + + ENetPacket* operator->() const + { + return m_packet; + } + + ENetPacketRef& operator=(ENetPacket* packet) + { + Reset(packet); + } + + ENetPacket* m_packet = nullptr; + }; +} + +#endif // NAZARA_ENETPACKET_HPP diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp new file mode 100644 index 000000000..4ae8ca16b --- /dev/null +++ b/include/Nazara/Network/ENetPeer.hpp @@ -0,0 +1,205 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPEER_HPP +#define NAZARA_ENETPEER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ENetHost; + + class NAZARA_NETWORK_API ENetPeer + { + friend ENetHost; + friend struct PacketRef; + + public: + ENetPeer(const ENetPeer&) = delete; + ENetPeer(ENetPeer&&) = default; + ~ENetPeer() = default; + + void Disconnect(UInt32 data); + void DisconnectLater(UInt32 data); + void DisconnectNow(UInt32 data); + + void Ping(); + + bool Receive(ENetPacketRef* packet, UInt8* channelId); + void Reset(); + + bool Send(UInt8 channelId, ENetPacketRef packetRef); + bool Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + + void ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration); + + ENetPeer& operator=(const ENetPeer&) = delete; + ENetPeer& operator=(ENetPeer&&) = default; + + private: + ENetPeer(ENetHost* host, UInt16 peerId); + + void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand); + void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize); + + struct Acknowledgement; + struct Channel; + struct IncomingCommmand; + struct OutgoingCommand; + + // Protocol functions + inline void ChangeState(ENetPeerState state); + inline void DispatchState(ENetPeerState state); + + void DispatchIncomingReliableCommands(Channel& channel); + void DispatchIncomingUnreliableCommands(Channel& channel); + + void OnConnect(); + void OnDisconnect(); + + ENetProtocolCommand RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId); + void RemoveSentUnreliableCommands(); + + void ResetQueues(); + + bool QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime); + IncomingCommmand* QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); + void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); + + void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); + + int Throttle(UInt32 rtt); + + struct Acknowledgement + { + ENetProtocol command; + UInt32 sentTime; + }; + + struct Channel + { + Channel() + { + incomingReliableSequenceNumber = 0; + incomingUnreliableSequenceNumber = 0; + outgoingReliableSequenceNumber = 0; + outgoingUnreliableSequenceNumber = 0; + usedReliableWindows = 0; + reliableWindows.fill(0); + } + + std::array reliableWindows; + std::list incomingReliableCommands; + std::list incomingUnreliableCommands; + UInt16 incomingReliableSequenceNumber; + UInt16 incomingUnreliableSequenceNumber; + UInt16 outgoingReliableSequenceNumber; + UInt16 outgoingUnreliableSequenceNumber; + UInt16 usedReliableWindows; + }; + + struct IncomingCommmand + { + ENetProtocol command; + UInt16 reliableSequenceNumber; + UInt16 unreliableSequenceNumber; + UInt32 fragmentsRemaining; + std::vector fragments; + ENetPacketRef packet; + }; + + struct OutgoingCommand + { + ENetProtocol command; + ENetPacketRef packet; + UInt16 fragmentLength; + UInt16 reliableSequenceNumber; + UInt16 sendAttempts; + UInt16 unreliableSequenceNumber; + UInt32 fragmentOffset; + UInt32 roundTripTimeout; + UInt32 roundTripTimeoutLimit; + UInt32 sentTime; + }; + + ENetHost* m_host; + IpAddress m_address; /**< Internet address of the peer */ + std::vector m_channels; + std::list m_acknowledgements; + std::list m_dispatchedCommands; + std::list m_outgoingReliableCommands; + std::list m_outgoingUnreliableCommands; + std::list m_sentReliableCommands; + std::list m_sentUnreliableCommands; + MemoryPool m_packetPool; + //ENetListNode m_dispatchList; + ENetPeerState m_state; + UInt8 m_incomingSessionID; + UInt8 m_outgoingSessionID; + UInt16 m_incomingPeerID; + UInt16 m_incomingUnsequencedGroup; + UInt16 m_outgoingPeerID; + UInt16 m_outgoingReliableSequenceNumber; + UInt16 m_outgoingUnsequencedGroup; + UInt32 m_connectID; + UInt32 m_earliestTimeout; + UInt32 m_eventData; + UInt32 m_highestRoundTripTimeVariance; + UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + UInt32 m_incomingBandwidthThrottleEpoch; + UInt32 m_incomingDataTotal; + UInt32 m_lastReceiveTime; + UInt32 m_lastRoundTripTime; + UInt32 m_lastRoundTripTimeVariance; + UInt32 m_lastSendTime; + UInt32 m_lowestRoundTripTime; + UInt32 m_mtu; + UInt32 m_nextTimeout; + UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + UInt32 m_outgoingBandwidthThrottleEpoch; + UInt32 m_outgoingDataTotal; + UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + UInt32 m_packetLossEpoch; + UInt32 m_packetLossVariance; + UInt32 m_packetThrottle; + UInt32 m_packetThrottleAcceleration; + UInt32 m_packetThrottleCounter; + UInt32 m_packetThrottleDeceleration; + UInt32 m_packetThrottleEpoch; + UInt32 m_packetThrottleInterval; + UInt32 m_packetThrottleLimit; + UInt32 m_packetsLost; + UInt32 m_packetsSent; + UInt32 m_pingInterval; + UInt32 m_reliableDataInTransit; + UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ + UInt32 m_roundTripTimeVariance; + UInt32 m_timeoutLimit; + UInt32 m_timeoutMaximum; + UInt32 m_timeoutMinimum; + UInt32 m_unsequencedWindow[ENetPeer_ReliableWindowSize / 32]; + UInt32 m_windowSize; + std::size_t m_totalWaitingData; + }; +} + +#include + +#endif // NAZARA_ENETPEER_HPP diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl new file mode 100644 index 000000000..a0cebbc4e --- /dev/null +++ b/include/Nazara/Network/ENetPeer.inl @@ -0,0 +1,29 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline void ENetPeer::ChangeState(ENetPeerState state) + { + if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) + OnConnect(); + else + OnDisconnect(); + + m_state = state; + } + + inline void ENetPeer::DispatchState(ENetPeerState state) + { + ChangeState(state); + + m_host->AddToDispatchQueue(this); + } +} + +#include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp new file mode 100644 index 000000000..d4d74fd01 --- /dev/null +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -0,0 +1,272 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPROTOCOL_HPP +#define NAZARA_ENETPROTOCOL_HPP + +#include +#include +#include + +namespace Nz +{ + // Constants for the ENet implementation and protocol + enum ENetConstants + { + ENetHost_BandwidthThrottleInterval = 1000, + ENetHost_DefaultMaximumPacketSize = 32 * 1024 * 1024, + ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, + ENetHost_DefaultMTU = 1400, + ENetHost_ReceiveBufferSize = 256 * 1024, + ENetHost_SendBufferSize = 256 * 1024, + + ENetPeer_DefaultPacketThrottle = 32, + ENetPeer_DefaultRoundTripTime = 500, + ENetPeer_FreeReliableWindows = 8, + ENetPeer_FreeUnsequencedWindows = 32, + ENetPeer_PacketLossInterval = 10000, + ENetPeer_PacketLossScale = (1 << 16), + ENetPeer_PacketThrottleAcceleration = 2, + ENetPeer_PacketThrottleCounter = 7, + ENetPeer_PacketThrottleDeceleration = 2, + ENetPeer_PacketThrottleInterval = 5000, + ENetPeer_PacketThrottleScale = 32, + ENetPeer_PingInterval = 500, + ENetPeer_ReliableWindows = 16, + ENetPeer_ReliableWindowSize = 0x1000, + ENetPeer_TimeoutLimit = 32, + ENetPeer_TimeoutMaximum = 30000, + ENetPeer_TimeoutMinimum = 5000, + ENetPeer_UnsequencedWindows = 64, + ENetPeer_UnsequencedWindowSize = 1024, + ENetPeer_WindowSizeScale = 64 * 1024, + + ENetProtocol_MaximumChannelCount = 255, + ENetProtocol_MaximumFragmentCount = 1024 * 1024, + ENetProtocol_MaximumMTU = 4096, + ENetProtocol_MaximumPacketCommands = 32, + ENetProtocol_MaximumPeerId = 0xFFF, + ENetProtocol_MaximumWindowSize = 65536, + ENetProtocol_MinimumChannelCount = 1, + ENetProtocol_MinimumMTU = 576, + ENetProtocol_MinimumWindowSize = 4096 + }; + + enum class ENetPeerState + { + AcknowledgingConnect = 2, + AcknowledgingDisconnect = 8, + Connecting = 1, + ConnectionPending = 3, + ConnectionSucceeded = 4, + Connected = 5, + Disconnected = 0, + Disconnecting = 7, + DisconnectLater = 6, + Zombie = 9 + }; + + enum ENetProtocolCommand + { + // Keeping the values is important for compatibility with the native ENet protocol + ENetProtocolCommand_Acknowledge = 1, + ENetProtocolCommand_BandwidthLimit = 10, + ENetProtocolCommand_Connect = 2, + ENetProtocolCommand_Disconnect = 4, + ENetProtocolCommand_None = 0, + ENetProtocolCommand_Ping = 5, + ENetProtocolCommand_SendFragment = 8, + ENetProtocolCommand_SendReliable = 6, + ENetProtocolCommand_SendUnreliable = 7, + ENetProtocolCommand_SendUnreliableFragment = 12, + ENetProtocolCommand_SendUnsequenced = 9, + ENetProtocolCommand_ThrottleConfigure = 11, + ENetProtocolCommand_VerifyConnect = 3, + ENetProtocolCommand_Count = 13, + + ENetProtocolCommand_Mask = 0x0F + }; + + enum ENetProtocolFlag + { + ENetProtocolFlag_Acknowledge = (1 << 7), + ENetProtocolFlag_Unsequenced = (1 << 6), + + ENetProtocolHeaderFlag_Compressed = (1 << 14), + ENetProtocolHeaderFlag_SentTime = (1 << 15), + ENetProtocolHeaderFlag_Mask = ENetProtocolHeaderFlag_Compressed | ENetProtocolHeaderFlag_SentTime, + + ENetProtocolHeaderSessionMask = (3 << 12), + ENetProtocolHeaderSessionShift = 12 + }; + + enum class ENetEventType + { + /** no event occurred within the specified time limit */ + None, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + Connect, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_peer_disconnect, if + * a peer has timed out, or if a connection request initialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + Disconnect, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + Receive + }; + + struct ENetEvent + { + ENetEventType type; + ENetPeer* peer; + UInt8 channelId; + UInt32 data; + ENetPacketRef packet; + }; + + struct ENetProtocolHeader + { + UInt16 peerID; + UInt16 sentTime; + }; + + struct ENetProtocolCommandHeader + { + UInt8 command; + UInt8 channelID; + UInt16 reliableSequenceNumber; + }; + + struct ENetProtocolAcknowledge + { + ENetProtocolCommandHeader header; + UInt16 receivedReliableSequenceNumber; + UInt16 receivedSentTime; + }; + + struct ENetProtocolConnect + { + ENetProtocolCommandHeader header; + UInt16 outgoingPeerID; + UInt8 incomingSessionID; + UInt8 outgoingSessionID; + UInt32 mtu; + UInt32 windowSize; + UInt32 channelCount; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + UInt32 connectID; + UInt32 data; + }; + + struct ENetProtocolBandwidthLimit + { + ENetProtocolCommandHeader header; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + }; + + struct ENetProtocolDisconnect + { + ENetProtocolCommandHeader header; + UInt32 data; + }; + + struct ENetProtocolPing + { + ENetProtocolCommandHeader header; + }; + + struct ENetProtocolSendFragment + { + ENetProtocolCommandHeader header; + UInt16 startSequenceNumber; + UInt16 dataLength; + UInt32 fragmentCount; + UInt32 fragmentNumber; + UInt32 totalLength; + UInt32 fragmentOffset; + }; + + struct ENetProtocolSendReliable + { + ENetProtocolCommandHeader header; + UInt16 dataLength; + }; + + struct ENetProtocolSendUnreliable + { + ENetProtocolCommandHeader header; + UInt16 unreliableSequenceNumber; + UInt16 dataLength; + }; + + struct ENetProtocolSendUnsequenced + { + ENetProtocolCommandHeader header; + UInt16 unsequencedGroup; + UInt16 dataLength; + }; + + struct ENetProtocolThrottleConfigure + { + ENetProtocolCommandHeader header; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + }; + + struct ENetProtocolVerifyConnect + { + ENetProtocolCommandHeader header; + UInt16 outgoingPeerID; + UInt8 incomingSessionID; + UInt8 outgoingSessionID; + UInt32 mtu; + UInt32 windowSize; + UInt32 channelCount; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + UInt32 connectID; + }; + + union ENetProtocol + { + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolConnect connect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolThrottleConfigure throttleConfigure; + ENetProtocolVerifyConnect verifyConnect; + }; +} + +#endif // NAZARA_ENETPROTOCOL_HPP diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp new file mode 100644 index 000000000..05179e615 --- /dev/null +++ b/src/Nazara/Network/ENetHost.cpp @@ -0,0 +1,743 @@ +#include +#include +#include +#include +#include +#include +#include + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +namespace Nz +{ + /// Temporary + template + T HostToNet(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + /// Temporary + template + T NetToHost(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + + void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) + { + ENetPacket* enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->data = std::move(packet); + enetPacket->owner = &m_packetPool; + + for (ENetPeer& peer : m_peers) + { + if (peer.m_state != ENetPeerState::Connected) + continue; + + peer.Send(channelId, enetPacket); + } + } + + bool ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data) + { + NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); + NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); + + std::size_t peerId; + for (peerId = 0; peerId < m_peers.size(); ++peerId) + { + if (m_peers[peerId].m_state == ENetPeerState::Disconnected) + break; + } + + if (peerId >= m_peers.size()) + { + NazaraError("Insufficient peers"); + return false; + } + + m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); + + UInt32 windowSize; + if (m_outgoingBandwidth == 0) + windowSize = ENetProtocol_MaximumWindowSize; + else + windowSize = (m_outgoingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetProtocol_MinimumWindowSize; + + ENetPeer& peer = m_peers[peerId]; + peer.InitOutgoing(channelCount, remoteAddress, ++m_randomSeed, windowSize); + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + + command.connect.channelCount = HostToNet(static_cast(channelCount)); + command.connect.connectID = peer.m_connectID; + command.connect.data = HostToNet(data); + command.connect.incomingBandwidth = HostToNet(m_incomingBandwidth); + command.connect.incomingSessionID = peer.m_incomingSessionID; + command.connect.mtu = HostToNet(peer.m_mtu); + command.connect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + command.connect.outgoingPeerID = HostToNet(peer.m_incomingPeerID); + command.connect.outgoingSessionID = peer.m_outgoingSessionID; + command.connect.packetThrottleAcceleration = HostToNet(peer.m_packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = HostToNet(peer.m_packetThrottleDeceleration); + command.connect.packetThrottleInterval = HostToNet(peer.m_packetThrottleInterval); + command.connect.windowSize = HostToNet(peer.m_windowSize); + + peer.QueueOutgoingCommand(command, nullptr, 0, 0); + + return true; + } + + bool ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data) + { + std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); + if (results.empty()) + 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, channelCount, data); + } + + bool ENetHost::Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount) + { + return Create(address, peerCount, channelCount, 0, 0); + } + + bool ENetHost::Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount, UInt32 incomingBandwidth, UInt32 outgoingBandwidth) + { + NazaraAssert(address.IsValid(), "Invalid listening address"); + + if (peerCount > ENetConstants::ENetProtocol_MaximumPeerId) + { + NazaraError("Peer count exceeds maximum peer count supported by protocol (" + String::Number(ENetConstants::ENetProtocol_MaximumPeerId) + ")"); + return false; + } + + if (!InitSocket(address)) + return false; + + m_peers.resize(peerCount); + + m_address = address; + m_randomSeed = *reinterpret_cast(this); + m_randomSeed += s_randomGenerator(); + m_randomSeed = (m_randomSeed << 16) | (m_randomSeed >> 16); + m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); + m_incomingBandwidth = incomingBandwidth; + m_outgoingBandwidth = outgoingBandwidth; + m_bandwidthThrottleEpoch = 0; + m_recalculateBandwidthLimits = false; + m_mtu = ENetConstants::ENetHost_DefaultMTU; + m_commandCount = 0; + m_bufferCount = 0; + m_receivedAddress = IpAddress::AnyIpV4; + m_receivedData = nullptr; + m_receivedDataLength = 0; + + m_totalSentData = 0; + m_totalSentPackets = 0; + m_totalReceivedData = 0; + m_totalReceivedPackets = 0; + + m_bandwidthLimitedPeers = 0; + m_connectedPeers = 0; + m_duplicatePeers = ENetConstants::ENetProtocol_MaximumPeerId; + m_maximumPacketSize = ENetConstants::ENetHost_DefaultMaximumPacketSize; + m_maximumWaitingData = ENetConstants::ENetHost_DefaultMaximumWaitingData; + + return true; + } + + void ENetHost::Flush() + { + m_serviceTime = GetElapsedMilliseconds(); + + SendOutgoingCommands(nullptr, 0); + } + + int ENetHost::Service(ENetEvent* event, UInt32 timeout) + { + UInt32 waitCondition; + + if (event) + { + event->type = ENetEventType::None; + event->peer = nullptr; + event->packet = nullptr; + + if (DispatchIncomingCommands(event)) + return 1; + } + + m_serviceTime = GetElapsedMilliseconds(); + timeout += m_serviceTime; + + do + { + if (ENET_TIME_DIFFERENCE(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) + ThrottleBandwidth(); + + switch (SendOutgoingCommands(event, true)) + { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error sending outgoing packets"); + #endif + return -1; + + default: + break; + } + + switch (ReceiveIncomingCommands(event)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror("Error receiving incoming packets"); +#endif + + return -1; + + default: + break; + } + + switch (SendOutgoingCommands(event, 1)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror("Error sending outgoing packets"); +#endif + + return -1; + + default: + break; + } + + if (event) + { + switch (DispatchIncomingCommands(event)) + { + 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)) + return 0; + + for (;;) + { + m_serviceTime = GetElapsedMilliseconds(); + + if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + return 0; + + SocketError error; + if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime), &error)) + break; + + if (error != SocketError_NoError) + return -1; + } + + m_serviceTime = GetElapsedMilliseconds(); + } + while (m_poller.IsReady(m_socket)); + + return 0; + } + + bool ENetHost::InitSocket(const IpAddress& address) + { + if (!m_socket.Create(address.GetProtocol())) + return false; + + m_socket.EnableBlocking(false); + m_socket.EnableBroadcasting(true); + m_socket.SetReceiveBufferSize(ENetConstants::ENetHost_ReceiveBufferSize); + m_socket.SetSendBufferSize(ENetConstants::ENetHost_SendBufferSize); + + if (!address.IsLoopback()) + { + if (m_socket.Bind(address) != SocketState_Bound) + { + NazaraError("Failed to bind address " + address.ToString()); + return false; + } + } + + m_poller.RegisterSocket(m_socket); + + return true; + } + + bool ENetHost::DispatchIncomingCommands(ENetEvent* event) + { + for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit)) + { + m_dispatchQueue.Reset(bit); + + ENetPeer& peer = m_peers[bit]; + switch (peer.m_state) + { + case ENetPeerState::ConnectionPending: + case ENetPeerState::ConnectionSucceeded: + peer.ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::Connect; + event->peer = &peer; + event->data = peer.m_eventData; + return true; + + case ENetPeerState::Zombie: + m_recalculateBandwidthLimits = true; + + event->type = ENetEventType::Disconnect; + event->peer = &peer; + event->data = peer.m_eventData; + + peer.Reset(); + return true; + + case ENetPeerState::Connected: + if (peer.m_dispatchedCommands.empty()) + continue; + + if (!peer.Receive(&event->packet, &event->channelId)) + continue; + + event->type = ENetEventType::Receive; + event->peer = &peer; + + if (!peer.m_dispatchedCommands.empty()) + AddToDispatchQueue(&peer); + + return true; + } + } + + return false; + } + + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* header, ENetProtocol* command) + { + UInt32 channelCount = NetToHost(command->connect.channelCount); + + if (channelCount < ENetProtocol_MinimumChannelCount || channelCount > ENetProtocol_MaximumChannelCount) + return nullptr; + + std::size_t duplicatePeers = 0; + ENetPeer* peer = nullptr; + for (ENetPeer& currentPeer : m_peers) + { + if (currentPeer.m_state == ENetPeerState::Disconnected) + { + if (!peer) + peer = ¤tPeer; + } + else if (currentPeer.m_state != ENetPeerState::Connecting) + { + // Compare users without comparing their port + IpAddress first(currentPeer.m_address); + first.SetPort(0); + + IpAddress second(m_receivedAddress); + second.SetPort(0); + + if (first == second) + { + if (currentPeer.m_address.GetPort() == m_receivedAddress.GetPort() && currentPeer.m_connectID == command->connect.connectID) + return nullptr; + + ++duplicatePeers; + } + } + } + + if (!peer || duplicatePeers >= m_duplicatePeers) + return nullptr; + + channelCount = std::min(channelCount, m_channelLimit); + + peer->InitIncoming(channelCount, m_receivedAddress, command->connect); + + UInt32 windowSize; + if (m_incomingBandwidth == 0) + windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + windowSize = (m_incomingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + windowSize = std::max(windowSize, NetToHost(command->connect.windowSize)); + windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + + ENetProtocol verifyCommand; + verifyCommand.header.command = ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge; + verifyCommand.header.channelID = 0xFF; + verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->m_incomingPeerID); + verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; + verifyCommand.verifyConnect.mtu = HostToNet(peer->m_mtu); + verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + verifyCommand.verifyConnect.channelCount = HostToNet(channelCount); + verifyCommand.verifyConnect.incomingBandwidth = HostToNet(m_incomingBandwidth); + verifyCommand.verifyConnect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->m_packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->m_packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->m_packetThrottleDeceleration); + verifyCommand.verifyConnect.connectID = peer->m_connectID; + + peer->QueueOutgoingCommand(verifyCommand, nullptr, 0, 0); + + return peer; + } + + bool ENetHost::HandleIncomingCommands(ENetEvent* event) + { + if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) + return false; + + ENetProtocolHeader* header = reinterpret_cast(m_receivedData); + + peerID = NetToHost(header->peerID); + sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; + flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; + peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + + headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); + if (host->checksum != NULL) + headerSize += sizeof(enet_uint32); + + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) + peer = NULL; + else + if (peerID >= host->peerCount) + return 0; + else + { + peer = &host->peers[peerID]; + + if (peer->state == ENET_PEER_STATE_DISCONNECTED || + peer->state == ENET_PEER_STATE_ZOMBIE || + ((host->receivedAddress.host != peer->address.host || + host->receivedAddress.port != peer->address.port) && + peer->address.host != ENET_HOST_BROADCAST) || + (peer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && + sessionID != peer->incomingSessionID)) + return 0; + } + + return false; + } + + 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)) + return false; + + UInt16 dataLength = NetToHost(command.sendReliable.dataLength); + *currentData += dataLength; + if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) + return false; + + if (!peer.QueueIncomingCommand(command, co)) + + return true; + } + + int ENetHost::ReceiveIncomingCommands(ENetEvent* event) + { + for (unsigned int i = 0; i < 256; ++i) + { + NetPacket packet; + + std::size_t receivedLength; + if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) + return -1; //< Error + + if (receivedLength == 0) + return 0; + + m_receivedData = m_packetData[0].data(); + m_receivedDataLength = receivedLength; + + m_totalReceivedData += receivedLength; + m_totalReceivedPackets++; + + // Intercept + + switch (HandleIncomingCommands(event)) + { + case 1: + return 1; + + case -1: + return -1; + + default: + break; + } + } + + return -1; + } + + void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event) + { + m_recalculateBandwidthLimits = true; + + if (event) + { + peer->ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::Connect; + event->peer = peer; + event->data = peer->m_eventData; + } + else + peer->DispatchState(peer->m_state == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + } + + void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) + { + if (peer->m_state >= ENetPeerState::ConnectionPending) + m_recalculateBandwidthLimits = true; + + if (peer->m_state != ENetPeerState::Connecting && (peer->m_state < ENetPeerState::ConnectionSucceeded)) + peer->Reset(); + else if (event) + { + event->type = ENetEventType::Disconnect; + event->peer = peer; + event->data = peer->m_eventData; + + peer->Reset(); + } + else + { + peer->m_eventData = 0; + + peer->DispatchState(ENetPeerState::Zombie); + } + } + + void ENetHost::ThrottleBandwidth() + { + UInt32 currentTime = GetElapsedMilliseconds(); + UInt32 elapsedTime = currentTime - m_bandwidthThrottleEpoch; + + if (elapsedTime < ENetConstants::ENetHost_BandwidthThrottleInterval) + return; + + m_bandwidthThrottleEpoch = currentTime; + + if (m_connectedPeers == 0) + return; + + UInt32 dataTotal = ~0; + UInt32 bandwidth = ~0; + + if (m_outgoingBandwidth != 0) + { + bandwidth = (m_outgoingBandwidth * elapsedTime) / 1000; + + dataTotal = 0; + for (ENetPeer& peer : m_peers) + { + if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + continue; + + dataTotal += peer.m_outgoingDataTotal; + } + } + + UInt32 peersRemaining = m_connectedPeers; + UInt32 bandwidthLimit = ~0; + UInt32 throttle = ~0; + bool needsAdjustment = m_bandwidthLimitedPeers > 0; + + while (peersRemaining > 0 && needsAdjustment) + { + needsAdjustment = false; + + if (dataTotal <= bandwidth) + throttle = ENetConstants::ENetPeer_PacketThrottleScale; + else + throttle = (bandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / dataTotal; + + for (ENetPeer& peer : m_peers) + { + if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || + peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) + continue; + + UInt32 peerBandwidth = (peer.m_incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer.m_outgoingDataTotal) / ENetConstants::ENetPeer_PacketThrottleScale <= peerBandwidth) + continue; + + peer.m_packetThrottleLimit = (peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal; + + if (peer.m_packetThrottleLimit == 0) + peer.m_packetThrottleLimit = 1; + + if (peer.m_packetThrottle > peer.m_packetThrottleLimit) + peer.m_packetThrottle = peer.m_packetThrottleLimit; + + peer.m_outgoingBandwidthThrottleEpoch = currentTime; + + peer.m_incomingDataTotal = 0; + peer.m_outgoingDataTotal = 0; + + needsAdjustment = true; + --peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + { + if (dataTotal <= bandwidth) + throttle = ENetConstants::ENetPeer_PacketThrottleScale; + else + throttle = (bandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / dataTotal; + + for (ENetPeer& peer : m_peers) + { + if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || + peer.m_outgoingBandwidthThrottleEpoch == currentTime) + continue; + + peer.m_packetThrottleLimit = throttle; + + if (peer.m_packetThrottle > peer.m_packetThrottleLimit) + peer.m_packetThrottle = peer.m_packetThrottleLimit; + + peer.m_incomingDataTotal = 0; + peer.m_outgoingDataTotal = 0; + } + } + + if (m_recalculateBandwidthLimits) + { + m_recalculateBandwidthLimits = false; + + peersRemaining = m_connectedPeers; + bandwidth = m_incomingBandwidth; + needsAdjustment = true; + + if (bandwidth == 0) + bandwidthLimit = 0; + else + { + while (peersRemaining > 0 && needsAdjustment) + { + needsAdjustment = false; + bandwidthLimit = bandwidth / peersRemaining; + + for (ENetPeer& peer : m_peers) + { + if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || + peer.m_incomingBandwidthThrottleEpoch == currentTime) + continue; + + if (peer.m_outgoingBandwidth > 0 && peer.m_outgoingBandwidth >= bandwidthLimit) + continue; + + peer.m_incomingBandwidthThrottleEpoch = currentTime; + + needsAdjustment = true; + --peersRemaining; + bandwidth -= peer.m_outgoingBandwidth; + } + } + } + + for (ENetPeer& peer : m_peers) + { + if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + continue; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + command.bandwidthLimit.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + + if (peer.m_incomingBandwidthThrottleEpoch == currentTime) + command.bandwidthLimit.incomingBandwidth = HostToNet(peer.m_outgoingBandwidth); + else + command.bandwidthLimit.incomingBandwidth = HostToNet(bandwidthLimit); + + peer.QueueOutgoingCommand(command, nullptr, 0, 0); + } + } + } + + bool ENetHost::Initialize() + { + std::random_device device; + s_randomGenerator.seed(device()); + s_randomGenerator64.seed(device()); + + return true; + } + + void ENetHost::Uninitialize() + { + } + + std::mt19937 ENetHost::s_randomGenerator; + std::mt19937_64 ENetHost::s_randomGenerator64; +} \ No newline at end of file diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp new file mode 100644 index 000000000..ec2bc4ab7 --- /dev/null +++ b/src/Nazara/Network/ENetPacket.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +namespace Nz +{ + /// Temporary + void ENetPacketRef::Reset(ENetPacket* packet = nullptr) + { + if (m_packet) + { + if (--m_packet->referenceCount == 0) + { + m_packet->owner->Delete(m_packet); + return; + } + } + + m_packet = packet; + if (m_packet) + m_packet->referenceCount++; + } +} \ No newline at end of file diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp new file mode 100644 index 000000000..9e5471c21 --- /dev/null +++ b/src/Nazara/Network/ENetPeer.cpp @@ -0,0 +1,885 @@ +#include +#include +#include +#include +#include + +namespace Nz +{ + /// Temporary + template + T HostToNet(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + /// Temporary + template + T NetToHost(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + namespace + { + static std::size_t commandSizes[ENetProtocolCommand_Count] = + { + 0, + sizeof(ENetProtocolAcknowledge), + sizeof(ENetProtocolConnect), + sizeof(ENetProtocolVerifyConnect), + sizeof(ENetProtocolDisconnect), + sizeof(ENetProtocolPing), + sizeof(ENetProtocolSendReliable), + sizeof(ENetProtocolSendUnreliable), + sizeof(ENetProtocolSendFragment), + sizeof(ENetProtocolSendUnsequenced), + sizeof(ENetProtocolBandwidthLimit), + sizeof(ENetProtocolThrottleConfigure), + sizeof(ENetProtocolSendFragment) + }; + + std::size_t enet_protocol_command_size(UInt8 commandNumber) + { + return commandSizes[commandNumber & ENetProtocolCommand_Mask]; + } + } + + ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : + m_packetPool(sizeof(ENetPacket)), + m_host(host), + m_incomingPeerID(peerId), + m_incomingSessionID(0xFF), + m_outgoingSessionID(0xFF) + { + Reset(); + } + + void ENetPeer::Disconnect(UInt32 data) + { + if (m_state == ENetPeerState::Disconnecting || + m_state == ENetPeerState::Disconnected || + m_state == ENetPeerState::AcknowledgingDisconnect || + m_state == ENetPeerState::Zombie) + return; + + ResetQueues(); + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Disconnect; + command.header.channelID = 0xFF; + command.disconnect.data = HostToNet(data); + + if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + command.header.command |= ENetProtocolFlag_Acknowledge; + else + command.header.command |= ENetProtocolFlag_Unsequenced; + + QueueOutgoingCommand(command, nullptr, 0, 0); + + if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + { + OnDisconnect(); + + m_state = ENetPeerState::Disconnecting; + } + else + { + m_host->Flush(); + + Reset(); + } + } + + void ENetPeer::DisconnectLater(UInt32 data) + { + if ((m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) && + !m_outgoingReliableCommands.empty() && + !m_outgoingUnreliableCommands.empty() && + !m_sentReliableCommands.empty()) + { + m_state = ENetPeerState::DisconnectLater; + m_eventData = data; + } + else + Disconnect(data); + } + + void ENetPeer::DisconnectNow(UInt32 data) + { + if (m_state == ENetPeerState::Disconnected) + return; + + if (m_state != ENetPeerState::Zombie && m_state != ENetPeerState::Disconnecting) + { + ResetQueues(); + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced; + command.header.channelID = 0xFF; + command.disconnect.data = HostToNet(data); + + QueueOutgoingCommand(command, nullptr, 0, 0); + + m_host->Flush(); + } + + Reset(); + } + + void ENetPeer::Ping() + { + if (m_state != ENetPeerState::Connected) + return; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Ping | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + + QueueOutgoingCommand(command, nullptr, 0, 0); + } + + bool ENetPeer::Receive(ENetPacketRef* packet, UInt8* channelId) + { + if (m_dispatchedCommands.empty()) + return false; + + IncomingCommmand& incomingCommand = m_dispatchedCommands.front(); + + m_totalWaitingData -= incomingCommand.packet->data.GetSize(); + + if (packet) + *packet = std::move(incomingCommand.packet); + + if (channelId) + *channelId = incomingCommand.command.header.channelID; + + m_dispatchedCommands.pop_front(); + + return true; + } + + void ENetPeer::Reset() + { + OnDisconnect(); + + m_outgoingPeerID = ENetConstants::ENetProtocol_MaximumPeerId; + m_connectID = 0; + + m_state = ENetPeerState::Disconnected; + + m_incomingBandwidth = 0; + m_outgoingBandwidth = 0; + m_incomingBandwidthThrottleEpoch = 0; + m_outgoingBandwidthThrottleEpoch = 0; + m_incomingDataTotal = 0; + m_outgoingDataTotal = 0; + m_lastSendTime = 0; + m_lastReceiveTime = 0; + m_nextTimeout = 0; + m_earliestTimeout = 0; + m_packetLossEpoch = 0; + m_packetsSent = 0; + m_packetsLost = 0; + m_packetLoss = 0; + m_packetLossVariance = 0; + m_packetThrottle = ENetConstants::ENetProtocol_MaximumWindowSize; + m_packetThrottleLimit = ENetConstants::ENetPeer_PacketThrottleScale; + m_packetThrottleCounter = 0; + m_packetThrottleEpoch = 0; + m_packetThrottleAcceleration = ENetConstants::ENetPeer_PacketThrottleAcceleration; + m_packetThrottleDeceleration = ENetConstants::ENetPeer_PacketThrottleDeceleration; + m_packetThrottleInterval = ENetConstants::ENetPeer_PacketThrottleInterval; + m_pingInterval = ENetConstants::ENetPeer_PingInterval; + m_timeoutLimit = ENetConstants::ENetPeer_TimeoutLimit; + m_timeoutMinimum = ENetConstants::ENetPeer_TimeoutMinimum; + m_timeoutMaximum = ENetConstants::ENetPeer_TimeoutMaximum; + m_lastRoundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_lowestRoundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_lastRoundTripTimeVariance = 0; + m_highestRoundTripTimeVariance = 0; + m_roundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_roundTripTimeVariance = 0; + m_mtu = m_host->m_mtu; + m_reliableDataInTransit = 0; + m_outgoingReliableSequenceNumber = 0; + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + m_incomingUnsequencedGroup = 0; + m_outgoingUnsequencedGroup = 0; + m_eventData = 0; + m_totalWaitingData = 0; + + std::memset(m_unsequencedWindow, 0, sizeof(m_unsequencedWindow)); + + ResetQueues(); + } + + bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) + { + ENetPacket* enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->data = std::move(packet); + enetPacket->owner = &m_packetPool; + + return Send(channelId, enetPacket); + } + + bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) + { + if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetSize() > m_host->m_maximumPacketSize) + return false; + + Channel& channel = m_channels[channelId]; + + std::size_t fragmentLength = m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment); + //if (m_host->m_checksum != nullptr) + // fragmentLength -= sizeof(UInt32); + + UInt32 packetSize = static_cast(packetRef->data.GetSize()); + if (packetSize > fragmentLength) + { + UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; + UInt32 fragmentNumber; + UInt32 fragmentOffset; + + UInt8 commandNumber; + UInt16 startSequenceNumber; + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount) + return false; + + if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_UnreliableFragment)) == ENetPacketFlag_UnreliableFragment && + channel.outgoingUnreliableSequenceNumber < 0xFFFF) + { + commandNumber = ENetProtocolCommand_SendUnreliable; + startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); + } + else + { + commandNumber = ENetProtocolCommand_SendFragment | ENetProtocolFlag_Acknowledge; + startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); + } + + for (fragmentNumber = 0, + fragmentOffset = 0; + fragmentOffset < packetSize; + ++fragmentNumber, + fragmentOffset += fragmentLength) + { + if (packetSize - fragmentOffset < fragmentLength) + fragmentLength = packetSize - fragmentOffset; + + OutgoingCommand outgoingCommand; + outgoingCommand.fragmentOffset = fragmentOffset; + outgoingCommand.fragmentLength = fragmentLength; + outgoingCommand.packet = packetRef; + outgoingCommand.command.header.command = commandNumber; + outgoingCommand.command.header.channelID = channelId; + outgoingCommand.command.sendFragment.startSequenceNumber = startSequenceNumber; + outgoingCommand.command.sendFragment.dataLength = HostToNet(fragmentLength); + outgoingCommand.command.sendFragment.fragmentCount = HostToNet(fragmentCount); + outgoingCommand.command.sendFragment.fragmentNumber = HostToNet(fragmentNumber); + outgoingCommand.command.sendFragment.totalLength = HostToNet(packetSize); + outgoingCommand.command.sendFragment.fragmentOffset = HostToNet(fragmentOffset); + + SetupOutgoingCommand(outgoingCommand); + } + + return true; + } + + ENetProtocol command; + command.header.channelID = channelId; + + if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_Unsequenced) + command.header.command = ENetProtocolCommand_SendUnsequenced | ENetProtocolFlag_Unsequenced; + else if (packetRef->flags & ENetPacketFlag_Reliable || channel.outgoingUnreliableSequenceNumber >= 0xFFFF) + command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge; + else + command.header.command = ENetProtocolCommand_SendUnreliable; + + QueueOutgoingCommand(command, packetRef, 0, packetSize); + + return true; + } + + void ENetPeer::ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration) + { + m_packetThrottleInterval = interval; + m_packetThrottleAcceleration = acceleration; + m_packetThrottleDeceleration = deceleration; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + + command.throttleConfigure.packetThrottleInterval = HostToNet(interval); + command.throttleConfigure.packetThrottleAcceleration = HostToNet(acceleration); + command.throttleConfigure.packetThrottleDeceleration = HostToNet(deceleration); + + QueueOutgoingCommand(command, nullptr, 0, 0); + } + + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + { + m_channels.resize(channelCount); + m_address = address; + + m_connectID = incomingCommand.connectID; + m_eventData = NetToHost(incomingCommand.data); + m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); + m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); + m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); + m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); + m_state = ENetPeerState::AcknowledgingConnect; + + UInt8 incomingSessionId, outgoingSessionId; + + incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (incomingSessionId == m_outgoingSessionID) + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_outgoingSessionID = incomingSessionId; + + outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (outgoingSessionId == m_incomingSessionID) + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_incomingSessionID = outgoingSessionId; + + m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + + if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) + m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) + { + m_channels.resize(channelCount); + + m_address = address; + m_connectID = connectId; + m_state = ENetPeerState::Connecting; + m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::DispatchIncomingReliableCommands(Channel& channel) + { + auto currentCommand = channel.incomingReliableCommands.begin(); + for (; currentCommand != channel.incomingReliableCommands.end(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if (incomingCommand.fragmentsRemaining > 0 || incomingCommand.reliableSequenceNumber != (channel.incomingReliableSequenceNumber + 1)) + break; + + channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; + + if (!incomingCommand.fragments.empty()) + channel.incomingReliableSequenceNumber += incomingCommand.fragments.size() - 1; + } + + if (currentCommand == channel.incomingReliableCommands.begin()) + return; + + channel.incomingUnreliableSequenceNumber = 0; + + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, channel.incomingReliableCommands.begin(), currentCommand); + + m_host->AddToDispatchQueue(this); + + if (!channel.incomingUnreliableCommands.empty()) + DispatchIncomingUnreliableCommands(channel); + } + + void ENetPeer::DispatchIncomingUnreliableCommands(Channel& channel) + { + std::list::iterator currentCommand; + std::list::iterator droppedCommand; + std::list::iterator startCommand; + + for (droppedCommand = startCommand = currentCommand = channel.incomingUnreliableCommands.begin(); + currentCommand != channel.incomingUnreliableCommands.end(); + ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_SendUnsequenced) + continue; + + if (incomingCommand.reliableSequenceNumber == channel.incomingReliableSequenceNumber) + { + if (incomingCommand.fragmentsRemaining <= 0) + { + channel.incomingUnreliableSequenceNumber = incomingCommand.unreliableSequenceNumber; + continue; + } + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + + droppedCommand = currentCommand; + } + else if (droppedCommand != currentCommand) + { + droppedCommand = currentCommand; + --droppedCommand; + } + } + else + { + UInt16 reliableWindow = incomingCommand.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENetConstants::ENetPeer_ReliableWindowSize - 1) + break; + + droppedCommand = currentCommand; + ++droppedCommand; + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + } + } + + startCommand = currentCommand; + ++startCommand; + } + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + + droppedCommand = currentCommand; + } + + channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); + } + + void ENetPeer::OnConnect() + { + if (m_state != ENetPeerState::Connected && m_state != ENetPeerState::DisconnectLater) + { + if (m_incomingBandwidth != 0) + ++m_host->m_bandwidthLimitedPeers; + + ++m_host->m_connectedPeers; + } + } + + void ENetPeer::OnDisconnect() + { + if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + { + if (m_incomingBandwidth != 0) + --m_host->m_bandwidthLimitedPeers; + + --m_host->m_connectedPeers; + } + } + + ENetProtocolCommand ENetPeer::RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId) + { + std::list* commandList = nullptr; + + bool found = true; + auto currentCommand = m_sentReliableCommands.begin(); + commandList = &m_sentReliableCommands; + for (; currentCommand != m_sentReliableCommands.end(); ++currentCommand) + { + found = true; + + if (currentCommand->reliableSequenceNumber == reliableSequenceNumber && + currentCommand->command.header.channelID == channelId) + break; + } + + bool wasSent = true; + if (currentCommand == m_sentReliableCommands.end()) + { + currentCommand = m_outgoingReliableCommands.begin(); + commandList = &m_sentReliableCommands; + for (; currentCommand != m_outgoingReliableCommands.end(); ++currentCommand) + { + found = true; + + if (currentCommand->sendAttempts < 1) + return ENetProtocolCommand_None; + + if (currentCommand->reliableSequenceNumber == reliableSequenceNumber && + currentCommand->command.header.channelID == channelId) + break; + } + + if (currentCommand == m_outgoingReliableCommands.end()) + return ENetProtocolCommand_None; + + wasSent = false; + } + + if (!found) //< Really useful? + return ENetProtocolCommand_None; + + if (channelId < m_channels.size()) + { + Channel& channel = m_channels[channelId]; + + UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + if (channel.reliableWindows[reliableWindow] > 0) + { + --channel.reliableWindows[reliableWindow]; + if (!channel.reliableWindows[reliableWindow]) + channel.usedReliableWindows &= ~(1 << reliableWindow); + } + } + + ENetProtocolCommand commandNumber = static_cast(currentCommand->command.header.command & ENetProtocolCommand_Mask); + + if (currentCommand->packet && wasSent) + m_reliableDataInTransit -= currentCommand->fragmentLength; + + commandList->erase(currentCommand); + + if (m_sentReliableCommands.empty()) + return commandNumber; + + currentCommand = m_sentReliableCommands.begin(); + m_nextTimeout = currentCommand->sentTime + currentCommand->roundTripTimeout; + + return commandNumber; + } + + void ENetPeer::RemoveSentUnreliableCommands() + { + m_sentUnreliableCommands.clear(); + } + + void ENetPeer::ResetQueues() + { + m_host->RemoveFromDispatchQueue(this); + + m_acknowledgements.clear(); + m_dispatchedCommands.clear(); + m_outgoingReliableCommands.clear(); + m_outgoingUnreliableCommands.clear(); + m_sentReliableCommands.clear(); + m_sentUnreliableCommands.clear(); + + m_channels.clear(); + } + + bool ENetPeer::QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime) + { + if (command.header.channelID < m_channels.size()) + { + Channel& channel = m_channels[command.header.channelID]; + + UInt16 reliableWindow = command.header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (command.header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1 && reliableWindow <= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows) + return false; + } + + Acknowledgement acknowledgment; + acknowledgment.command = command; + acknowledgment.sentTime = sentTime; + + m_outgoingDataTotal += sizeof(Acknowledgement); + + m_acknowledgements.emplace_back(acknowledgment); + + return true; + } + + ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount) + { + static IncomingCommmand dummyCommand; + + UInt32 reliableSequenceNumber = 0; + UInt32 unreliableSequenceNumber = 0; + UInt16 reliableWindow; + UInt16 currentWindow; + + auto discardCommand = [&]() -> IncomingCommmand* + { + if (fragmentCount > 0) + return nullptr; //< Error + + return &dummyCommand; + }; + + if (m_state == ENetPeerState::DisconnectLater) + return discardCommand(); + + Channel& channel = m_channels[command.header.channelID]; + + if ((command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnsequenced) + { + reliableSequenceNumber = command.header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return discardCommand(); + } + + std::list* commandList = nullptr; + std::list::reverse_iterator currentCommand; + + switch (command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendFragment: + case ENetProtocolCommand_SendReliable: + { + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber) + return discardCommand(); + + commandList = &channel.incomingReliableCommands; + + for (currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if (reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + return discardCommand(); + } + } + break; + } + + case ENetProtocolCommand_SendUnreliable: + case ENetProtocolCommand_SendUnreliableFragment: + { + unreliableSequenceNumber = NetToHost(command.sendUnreliable.unreliableSequenceNumber); + + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && unreliableSequenceNumber <= channel.incomingUnreliableSequenceNumber) + return discardCommand(); + + commandList = &channel.incomingUnreliableCommands; + + for (currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if ((command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_SendUnsequenced) //< wtf + continue; + + if (reliableSequenceNumber >= 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 <= unreliableSequenceNumber) + { + if (incomingCommand.unreliableSequenceNumber < unreliableSequenceNumber) + break; + + return discardCommand(); + } + } + break; + } + + case ENetProtocolCommand_SendUnsequenced: + { + commandList = &channel.incomingUnreliableCommands; + + currentCommand = channel.incomingUnreliableCommands.rend(); + break; + } + + default: + return discardCommand(); + } + + if (m_totalWaitingData >= m_host->m_maximumWaitingData) + return nullptr; + + ENetPacket* packet = m_packetPool.New(); + packet->flags = flags; + packet->data.Reset(0, data, dataLength); + packet->owner = &m_packetPool; + + IncomingCommmand incomingCommand; + incomingCommand.reliableSequenceNumber = command.header.reliableSequenceNumber; + incomingCommand.unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand.command = command; + incomingCommand.packet = packet; + incomingCommand.fragments.resize(fragmentCount, 0); + incomingCommand.fragmentsRemaining = fragmentCount; + + auto it = commandList->insert(currentCommand.base(), incomingCommand); + + switch (command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendFragment: + case ENetProtocolCommand_SendReliable: + DispatchIncomingReliableCommands(channel); + break; + + default: + DispatchIncomingUnreliableCommands(channel); + break; + } + + return &(*it); + } + + void ENetPeer::QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length) + { + OutgoingCommand outgoingCommand; + outgoingCommand.command = command; + outgoingCommand.fragmentLength = length; + outgoingCommand.fragmentOffset = length; + outgoingCommand.packet = packet; + + SetupOutgoingCommand(outgoingCommand); + } + + void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand) + { + m_outgoingDataTotal += enet_protocol_command_size(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength; + + if (outgoingCommand.command.header.channelID == 0xFF) + { + ++m_outgoingReliableSequenceNumber; + + outgoingCommand.reliableSequenceNumber = m_outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = 0; + } + else + { + Channel* channel = &m_channels[outgoingCommand.command.header.channelID]; + if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge) + { + ++channel->outgoingReliableSequenceNumber; + channel->outgoingUnreliableSequenceNumber = 0; + + outgoingCommand.reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = 0; + } + else if (outgoingCommand.command.header.command & ENetProtocolFlag_Unsequenced) + { + ++m_outgoingUnsequencedGroup; + + outgoingCommand.reliableSequenceNumber = 0; + outgoingCommand.unreliableSequenceNumber = 0; + } + else + { + if (outgoingCommand.fragmentOffset == 0) + ++channel->outgoingUnreliableSequenceNumber; + + outgoingCommand.reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = channel->outgoingUnreliableSequenceNumber; + } + } + + outgoingCommand.sendAttempts = 0; + outgoingCommand.sentTime = 0; + outgoingCommand.roundTripTimeout = 0; + outgoingCommand.roundTripTimeoutLimit = 0; + outgoingCommand.command.header.reliableSequenceNumber = HostToNet(outgoingCommand.reliableSequenceNumber); + + switch (outgoingCommand.command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendUnreliable: + outgoingCommand.command.sendUnreliable.unreliableSequenceNumber = HostToNet(outgoingCommand.unreliableSequenceNumber); + break; + + case ENetProtocolCommand_SendUnsequenced: + outgoingCommand.command.sendUnsequenced.unsequencedGroup = HostToNet(m_outgoingUnsequencedGroup); + break; + + default: + break; + } + + if (outgoingCommand.command.header.command & ENetProtocolCommand_Acknowledge) + m_outgoingReliableCommands.emplace_back(outgoingCommand); + else + m_outgoingUnreliableCommands.emplace_back(outgoingCommand); + } + + int ENetPeer::Throttle(UInt32 rtt) + { + if (m_lastRoundTripTime <= m_lastRoundTripTimeVariance) + m_packetThrottle = m_packetThrottleLimit; + else + { + if (rtt < m_lastRoundTripTime) + { + m_packetThrottle = std::max(m_packetThrottle + m_packetThrottleAcceleration, m_packetThrottleLimit); + return 1; + } + else if (rtt > m_lastRoundTripTime + 2 * m_lastRoundTripTimeVariance) + { + if (m_packetThrottle > m_packetThrottleDeceleration) + m_packetThrottle -= m_packetThrottleDeceleration; + else + m_packetThrottle = 0; + + return -1; + } + } + + return 0; + } +} \ No newline at end of file diff --git a/src/Nazara/Network/ENetSocket.cpp b/src/Nazara/Network/ENetSocket.cpp new file mode 100644 index 000000000..e86313fb4 --- /dev/null +++ b/src/Nazara/Network/ENetSocket.cpp @@ -0,0 +1,642 @@ +// 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 +#include +#include +#include +#include + +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(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 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(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& 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(m_protocol & 0xFFFF); + UInt16 protocolEnd = static_cast((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(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; +} From 12b4073033d3ef2a360a7cf61484ec7242ea7572 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 26 Jan 2017 09:28:41 +0100 Subject: [PATCH 02/48] Progress --- include/Nazara/Network/ENetHost.hpp | 8 +- include/Nazara/Network/ENetPeer.hpp | 8 +- src/Nazara/Network/ENetHost.cpp | 443 ++++++++++++++++++++++++++-- src/Nazara/Network/ENetPeer.cpp | 43 +-- 4 files changed, 433 insertions(+), 69 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 87d4dd37b..03d10d541 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -63,9 +63,15 @@ namespace Nz bool DispatchIncomingCommands(ENetEvent* event); + bool HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command); + bool HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command); ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); + bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command); bool HandleIncomingCommands(ENetEvent* event); - bool HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData); + bool HandlePing(ENetPeer* peer, const ENetProtocol* command); + bool HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); + bool HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command); + bool HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command); int ReceiveIncomingCommands(ENetEvent* event); diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 4ae8ca16b..7d522f203 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -74,15 +74,15 @@ namespace Nz void OnConnect(); void OnDisconnect(); - ENetProtocolCommand RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId); + ENetProtocolCommand RemoveSentReliableCommand(UInt16 reliableSequenceNumber, UInt8 channelId); void RemoveSentUnreliableCommands(); 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); void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); - + void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); int Throttle(UInt32 rtt); diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 05179e615..5bb9b7bdf 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -27,7 +27,7 @@ namespace Nz return value; #endif } - + /// Temporary template T NetToHost(T value) @@ -39,6 +39,31 @@ namespace Nz #endif } + namespace + { + static std::size_t s_commandSizes[ENetProtocolCommand_Count] = + { + 0, + sizeof(ENetProtocolAcknowledge), + sizeof(ENetProtocolConnect), + sizeof(ENetProtocolVerifyConnect), + sizeof(ENetProtocolDisconnect), + sizeof(ENetProtocolPing), + sizeof(ENetProtocolSendReliable), + sizeof(ENetProtocolSendUnreliable), + sizeof(ENetProtocolSendFragment), + sizeof(ENetProtocolSendUnsequenced), + sizeof(ENetProtocolBandwidthLimit), + sizeof(ENetProtocolThrottleConfigure), + sizeof(ENetProtocolSendFragment) + }; + + std::size_t enet_protocol_command_size(UInt8 commandNumber) + { + return s_commandSizes[commandNumber & ENetProtocolCommand_Mask]; + } + } + void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { @@ -372,6 +397,116 @@ namespace Nz return false; } + bool ENetHost::HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) + { + if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + return true; + + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); + receivedSentTime |= m_serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (m_serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS(m_serviceTime, receivedSentTime)) + return true; + + peer->m_lastReceiveTime = m_serviceTime; + peer->m_earliestTimeout = 0; + + UInt32 roundTripTime = ENET_TIME_DIFFERENCE(m_serviceTime, receivedSentTime); + + peer->Throttle(roundTripTime); + + peer->m_roundTripTimeVariance -= peer->m_roundTripTimeVariance / 4; + + if (roundTripTime >= peer->m_roundTripTime) + { + peer->m_roundTripTime += (roundTripTime - peer->m_roundTripTime) / 8; + peer->m_roundTripTimeVariance += (roundTripTime - peer->m_roundTripTime) / 4; + } + else + { + peer->m_roundTripTime -= (peer->m_roundTripTime - roundTripTime) / 8; + peer->m_roundTripTimeVariance += (peer->m_roundTripTime - roundTripTime) / 4; + } + + if (peer->m_roundTripTime < peer->m_lowestRoundTripTime) + peer->m_lowestRoundTripTime = peer->m_roundTripTime; + + if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance) + peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; + + if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->packetThrottleInterval) + { + peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime; + peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance; + peer->m_lowestRoundTripTime = peer->m_roundTripTime; + peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; + peer->m_packetThrottleEpoch = m_serviceTime; + } + + UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); + + ENetProtocolCommand commandNumber = peer->RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); + + switch (peer->m_state) + { + case ENetPeerState::AcknowledgingConnect: + if (commandNumber != ENetProtocolCommand_VerifyConnect) + return false; + + NotifyConnect(peer, event); + break; + + case ENetPeerState::Disconnecting: + if (commandNumber != ENetProtocolCommand_Disconnect) + return false; + + NotifyDisconnect(peer, event); + break; + + case ENetPeerState::DisconnectLater: + if (peer->m_outgoingReliableCommands.empty() && peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + peer->Disconnect(peer->m_eventData); + + break; + + default: + break; + } + + return true; + } + + bool ENetHost::HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command) + { + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + return false; + + if (peer->m_incomingBandwidth != 0) + --m_bandwidthLimitedPeers; + + peer->m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); + peer->m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); + + if (peer->m_incomingBandwidth != 0) + ++m_bandwidthLimitedPeers; + + if (peer->m_incomingBandwidth == 0 && m_outgoingBandwidth == 0) + peer->m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + { + if (peer->m_incomingBandwidth == 0 || m_outgoingBandwidth == 0) + peer->m_windowSize = (std::max(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + peer->m_windowSize = (std::min(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + peer->m_windowSize = Clamp(peer->m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + return true; + } + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* header, ENetProtocol* command) { UInt32 channelCount = NetToHost(command->connect.channelCount); @@ -410,7 +545,7 @@ namespace Nz if (!peer || duplicatePeers >= m_duplicatePeers) return nullptr; - channelCount = std::min(channelCount, m_channelLimit); + channelCount = std::min(channelCount, m_channelLimit); peer->InitIncoming(channelCount, m_receivedAddress, command->connect); @@ -444,6 +579,37 @@ namespace Nz return peer; } + bool ENetHost::HandleDisconnect(ENetPeer* peer, const ENetProtocol * command) + { + if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie || peer->m_state == ENetPeerState::AcknowledgingDisconnect) + return true; + + peer->ResetQueues(); + + if (peer->m_state == ENetPeerState::ConnectionSucceeded || peer->m_state == ENetPeerState::Disconnecting || peer->m_state == ENetPeerState::Connecting) + peer->DispatchState(ENetPeerState::Zombie); + else + { + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + { + if (peer->m_state == ENetPeerState::ConnectionPending) + m_recalculateBandwidthLimits = true; + + peer->Reset(); + } + else + if (command->header.command & ENetProtocolFlag_Acknowledge) + peer->ChangeState(ENetPeerState::AcknowledgingDisconnect); + else + peer->DispatchState(ENetPeerState::Zombie); + } + + if (peer->m_state != ENetPeerState::Disconnected) + peer->m_eventData = NetToHost(command->disconnect.data); + + return true; + } + bool ENetHost::HandleIncomingCommands(ENetEvent* event) { if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) @@ -451,58 +617,275 @@ namespace Nz ENetProtocolHeader* header = reinterpret_cast(m_receivedData); - peerID = NetToHost(header->peerID); - sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; - flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; - peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + UInt16 peerID = NetToHost(header->peerID); + UInt8 sessionID = (peerID & ENetProtocolHeaderSessionMask) >> ENetProtocolHeaderSessionShift; + UInt16 flags = peerID & ENetProtocolHeaderFlag_Mask; + peerID &= ~(ENetProtocolHeaderFlag_Mask | ENetProtocolHeaderSessionMask); - headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); - if (host->checksum != NULL) - headerSize += sizeof(enet_uint32); + std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); - if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) - peer = NULL; + ENetPeer* peer; + if (peerID == ENetConstants::ENetProtocol_MaximumPeerId) + peer = nullptr; else - if (peerID >= host->peerCount) - return 0; + { + if (peerID >= m_peers.size()) + return false; else { - peer = &host->peers[peerID]; + peer = &m_peers[peerID]; - if (peer->state == ENET_PEER_STATE_DISCONNECTED || - peer->state == ENET_PEER_STATE_ZOMBIE || - ((host->receivedAddress.host != peer->address.host || - host->receivedAddress.port != peer->address.port) && - peer->address.host != ENET_HOST_BROADCAST) || - (peer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && - sessionID != peer->incomingSessionID)) - return 0; + if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + return false; + + if (m_receivedAddress != peer->m_address && peer->m_address != IpAddress::BroadcastIpV4) + return false; + + if (peer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId && sessionID != peer->m_incomingSessionID) + return false; + } + } + + // Compression handling + + // Checksum + + if (peer) + { + peer->m_address = m_receivedAddress; + peer->m_incomingDataTotal += m_receivedDataLength; + } + + auto commandError = [&]() -> bool + { + if (event && event->type != ENetEventType::None) + return true; + + return false; + }; + + UInt8* currentData = m_receivedData + headerSize; + + while (currentData < &m_receivedData[m_receivedDataLength]) + { + ENetProtocol* command = reinterpret_cast(currentData); + + if (currentData + sizeof(ENetProtocolCommandHeader) > &m_receivedData[m_receivedDataLength]) + break; + + UInt8 commandNumber = command->header.command & ENetProtocolCommand_Mask; + if (commandNumber >= ENetProtocolCommand_Count) + break; + + std::size_t commandSize = s_commandSizes[commandNumber]; + if (commandSize == 0 || currentData + commandSize > &m_receivedData[m_receivedDataLength]) + break; + + currentData += commandSize; + + if (!peer && commandNumber != ENetProtocolCommand_Connect) + break; + + command->header.reliableSequenceNumber = NetToHost(command->header.reliableSequenceNumber); + + switch (commandNumber) + { + case ENetProtocolCommand_Acknowledge: + if (!HandleAcknowledge(event, peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_Connect: + if (peer) + return commandError(); + + peer = HandleConnect(header, command); + if (!peer) + return commandError(); + + break; + + case ENetProtocolCommand_VerifyConnect: + if (!HandleVerifyConnect(event, peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_Disconnect: + if (!HandleDisconnect(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_Ping: + if (!HandlePing(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_SendReliable: + if (!HandleSendReliable(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnreliable: + if (!HandleSendUnreliable(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnsequenced: + if (!HandleSendUnsequenced(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendFragment: + if (!HandleSendFragment(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_BandwidthLimit: + if (!HandleBandwidthLimit(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_ThrottleConfigure: + if (!HandleThrottleConfigure(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnreliableFragment: + if (!HandleSendUnreliableFragment(peer, command, ¤tData)) + return commandError(); + + break; + + default: + return commandError(); } - return false; + if (peer && (command->header.command & ENetProtocolCommand_Acknowledge) != 0) + { + UInt16 sentTime; + + if (!(flags & ENetProtocolHeaderFlag_SentTime)) + break; + + sentTime = NetToHost(header->sentTime); + + switch (peer->m_state) + { + case ENetPeerState::Disconnecting: + case ENetPeerState::AcknowledgingConnect: + case ENetPeerState::Disconnected: + case ENetPeerState::Zombie: + break; + + case ENetPeerState::AcknowledgingDisconnect: + if ((command->header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) + peer->QueueAcknowledgement(command, sentTime); + break; + + default: + peer->QueueAcknowledgement(command, sentTime); + break; + } + } + } + + return commandError(); } - bool ENetHost::HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData) + bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* command) { - if (command.header.channelID >= peer.m_channels.size() || (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater)) + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) return false; - UInt16 dataLength = NetToHost(command.sendReliable.dataLength); + return true; + } + + 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)) + return false; + + UInt16 dataLength = NetToHost(command->sendReliable.dataLength); *currentData += dataLength; if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) return false; - if (!peer.QueueIncomingCommand(command, co)) + if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) + return false; return true; } + bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command) + { + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + return false; + + peer->m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + peer->m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); + peer->m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); + + return true; + } + + bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) + { + if (peer->m_state != ENetPeerState::Connecting) + return false; + + UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); + + if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || + NetToHost(command->verifyConnect.packetThrottleInterval) != peer->m_packetThrottleInterval || + NetToHost(command->verifyConnect.packetThrottleAcceleration) != peer->m_packetThrottleAcceleration || + NetToHost(command->verifyConnect.packetThrottleDeceleration) != peer->m_packetThrottleDeceleration || + command->verifyConnect.connectID != peer->m_connectID) + { + peer->m_eventData = 0; + + peer->DispatchState(ENetPeerState::Zombie); + + return false; + } + + peer->RemoveSentReliableCommand(1, 0xFF); + + if (channelCount < peer->m_channels.size()) + peer->m_channels.resize(channelCount); + + peer->m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); + peer->m_incomingSessionID = command->verifyConnect.incomingSessionID; + peer->m_outgoingSessionID = command->verifyConnect.outgoingSessionID; + + UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + peer->m_mtu = std::min(peer->m_mtu, mtu); + + UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + peer->m_windowSize = std::min(peer->m_windowSize, windowSize); + + peer->m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); + peer->m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); + + NotifyConnect(peer, event); + return true; + } + int ENetHost::ReceiveIncomingCommands(ENetEvent* event) { for (unsigned int i = 0; i < 256; ++i) { NetPacket packet; - + std::size_t receivedLength; if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) return -1; //< Error @@ -525,7 +908,7 @@ namespace Nz case -1: return -1; - + default: break; } @@ -740,4 +1123,4 @@ namespace Nz std::mt19937 ENetHost::s_randomGenerator; std::mt19937_64 ENetHost::s_randomGenerator64; -} \ No newline at end of file +} diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 9e5471c21..6f7f33312 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -16,7 +16,7 @@ namespace Nz return value; #endif } - + /// Temporary template T NetToHost(T value) @@ -28,31 +28,6 @@ namespace Nz #endif } - namespace - { - static std::size_t commandSizes[ENetProtocolCommand_Count] = - { - 0, - sizeof(ENetProtocolAcknowledge), - sizeof(ENetProtocolConnect), - sizeof(ENetProtocolVerifyConnect), - sizeof(ENetProtocolDisconnect), - sizeof(ENetProtocolPing), - sizeof(ENetProtocolSendReliable), - sizeof(ENetProtocolSendUnreliable), - sizeof(ENetProtocolSendFragment), - sizeof(ENetProtocolSendUnsequenced), - sizeof(ENetProtocolBandwidthLimit), - sizeof(ENetProtocolThrottleConfigure), - sizeof(ENetProtocolSendFragment) - }; - - std::size_t enet_protocol_command_size(UInt8 commandNumber) - { - return commandSizes[commandNumber & ENetProtocolCommand_Mask]; - } - } - ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : m_packetPool(sizeof(ENetPacket)), m_host(host), @@ -505,8 +480,8 @@ namespace Nz } } - ENetProtocolCommand ENetPeer::RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId) - { + ENetProtocolCommand ENetPeer::RemoveSentReliableCommand(UInt16 reliableSequenceNumber, UInt8 channelId) + { std::list* commandList = nullptr; bool found = true; @@ -595,16 +570,16 @@ namespace Nz m_channels.clear(); } - bool ENetPeer::QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime) + bool ENetPeer::QueueAcknowledgement(ENetProtocol*command, UInt16 sentTime) { - if (command.header.channelID < m_channels.size()) + if (command->header.channelID < m_channels.size()) { - Channel& channel = m_channels[command.header.channelID]; + Channel& channel = m_channels[command->header.channelID]; - UInt16 reliableWindow = command.header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 reliableWindow = command->header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; - if (command.header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + if (command->header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) reliableWindow += ENetConstants::ENetPeer_ReliableWindows; if (reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1 && reliableWindow <= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows) @@ -882,4 +857,4 @@ namespace Nz return 0; } -} \ No newline at end of file +} From 8a59dc88b844992f75fadb72492ea4ffe0515948 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 27 Jan 2017 14:48:31 +0100 Subject: [PATCH 03/48] Commit progression --- include/Nazara/Network/ENetHost.hpp | 30 +- include/Nazara/Network/ENetHost.inl | 12 +- include/Nazara/Network/ENetPacket.hpp | 33 +- include/Nazara/Network/ENetPeer.hpp | 129 ++--- include/Nazara/Network/ENetPeer.inl | 14 +- include/Nazara/Network/ENetProtocol.hpp | 47 +- include/Nazara/Network/Enums.hpp | 2 + src/Nazara/Network/ENetHost.cpp | 711 ++++++++++++++++++++++-- src/Nazara/Network/ENetPacket.cpp | 6 +- src/Nazara/Network/ENetPeer.cpp | 50 +- src/Nazara/Network/ENetSocket.cpp | 642 --------------------- 11 files changed, 865 insertions(+), 811 deletions(-) delete mode 100644 src/Nazara/Network/ENetSocket.cpp diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 03d10d541..3b86a1f25 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +41,10 @@ namespace Nz void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); - bool Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); - bool Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); + bool CheckEvents(ENetEvent* event); + + 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); bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount = 0); @@ -58,8 +61,10 @@ namespace Nz private: bool InitSocket(const IpAddress& address); - inline void AddToDispatchQueue(ENetPeer* peer); - inline void RemoveFromDispatchQueue(ENetPeer* peer); + void AddToDispatchQueue(ENetPeer* peer); + void RemoveFromDispatchQueue(ENetPeer* peer); + + bool CheckTimeouts(ENetPeer* peer, ENetEvent* event); bool DispatchIncomingCommands(ENetEvent* event); @@ -69,7 +74,11 @@ namespace Nz bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command); bool HandleIncomingCommands(ENetEvent* event); 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 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 HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command); @@ -78,12 +87,19 @@ namespace Nz void NotifyConnect(ENetPeer* peer, 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(); + static std::size_t GetCommandSize(UInt8 commandNumber); static bool Initialize(); static void Uninitialize(); std::array m_commands; + std::array m_buffers; std::array m_packetData[2]; std::bernoulli_distribution m_packetLossProbability; std::size_t m_bandwidthLimitedPeers; @@ -93,6 +109,8 @@ namespace Nz std::size_t m_duplicatePeers; std::size_t m_maximumPacketSize; std::size_t m_maximumWaitingData; + std::size_t m_packetSize; + std::size_t m_peerCount; std::size_t m_receivedDataLength; std::vector m_peers; Bitset m_dispatchQueue; @@ -101,6 +119,7 @@ namespace Nz IpAddress m_receivedAddress; SocketPoller m_poller; UdpSocket m_socket; + UInt16 m_headerFlags; UInt32 m_bandwidthThrottleEpoch; UInt32 m_connectedPeers; UInt32 m_mtu; @@ -113,6 +132,7 @@ namespace Nz UInt32 m_totalReceivedData; UInt32 m_totalReceivedPackets; UInt8* m_receivedData; + bool m_continueSending; bool m_isSimulationEnabled; bool m_shouldAcceptConnections; bool m_recalculateBandwidthLimits; diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index c4a077e8b..e547d4e5d 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -50,16 +50,6 @@ namespace Nz m_peers.clear(); 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 diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp index ad1610eb4..54a5d4676 100644 --- a/include/Nazara/Network/ENetPacket.hpp +++ b/include/Nazara/Network/ENetPacket.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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -40,7 +40,7 @@ namespace Nz std::size_t referenceCount = 0; }; - struct ENetPacketRef + struct NAZARA_NETWORK_API ENetPacketRef { ENetPacketRef() = default; @@ -49,6 +49,18 @@ namespace Nz Reset(packet); } + ENetPacketRef(const ENetPacketRef& packet) : + ENetPacketRef() + { + Reset(packet); + } + + ENetPacketRef(ENetPacketRef&& packet) : + m_packet(packet.m_packet) + { + packet.m_packet = nullptr; + } + ~ENetPacketRef() { Reset(); @@ -69,6 +81,23 @@ namespace Nz ENetPacketRef& operator=(ENetPacket* 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; diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 7d522f203..e68b85de9 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -32,6 +32,7 @@ namespace Nz friend struct PacketRef; public: + ENetPeer(ENetHost* host, UInt16 peerId); ENetPeer(const ENetPeer&) = delete; ENetPeer(ENetPeer&&) = default; ~ENetPeer() = default; @@ -40,6 +41,8 @@ namespace Nz void DisconnectLater(UInt32 data); void DisconnectNow(UInt32 data); + inline const IpAddress& GetAddress() const; + void Ping(); bool Receive(ENetPacketRef* packet, UInt8* channelId); @@ -54,8 +57,6 @@ namespace Nz ENetPeer& operator=(ENetPeer&&) = default; private: - ENetPeer(ENetHost* host, UInt16 peerId); - void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand); void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize); @@ -66,7 +67,7 @@ namespace Nz // Protocol functions inline void ChangeState(ENetPeerState state); - inline void DispatchState(ENetPeerState state); + void DispatchState(ENetPeerState state); void DispatchIncomingReliableCommands(Channel& channel); void DispatchIncomingUnreliableCommands(Channel& channel); @@ -80,7 +81,7 @@ namespace Nz void ResetQueues(); 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 SetupOutgoingCommand(OutgoingCommand& outgoingCommand); @@ -139,64 +140,66 @@ namespace Nz UInt32 sentTime; }; - ENetHost* m_host; - IpAddress m_address; /**< Internet address of the peer */ - std::vector m_channels; - std::list m_acknowledgements; - std::list m_dispatchedCommands; - std::list m_outgoingReliableCommands; - std::list m_outgoingUnreliableCommands; - std::list m_sentReliableCommands; - std::list m_sentUnreliableCommands; - MemoryPool m_packetPool; - //ENetListNode m_dispatchList; - ENetPeerState m_state; - UInt8 m_incomingSessionID; - UInt8 m_outgoingSessionID; - UInt16 m_incomingPeerID; - UInt16 m_incomingUnsequencedGroup; - UInt16 m_outgoingPeerID; - UInt16 m_outgoingReliableSequenceNumber; - UInt16 m_outgoingUnsequencedGroup; - UInt32 m_connectID; - UInt32 m_earliestTimeout; - UInt32 m_eventData; - UInt32 m_highestRoundTripTimeVariance; - UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ - UInt32 m_incomingBandwidthThrottleEpoch; - UInt32 m_incomingDataTotal; - UInt32 m_lastReceiveTime; - UInt32 m_lastRoundTripTime; - UInt32 m_lastRoundTripTimeVariance; - UInt32 m_lastSendTime; - UInt32 m_lowestRoundTripTime; - UInt32 m_mtu; - UInt32 m_nextTimeout; - UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ - UInt32 m_outgoingBandwidthThrottleEpoch; - UInt32 m_outgoingDataTotal; - UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ - UInt32 m_packetLossEpoch; - UInt32 m_packetLossVariance; - UInt32 m_packetThrottle; - UInt32 m_packetThrottleAcceleration; - UInt32 m_packetThrottleCounter; - UInt32 m_packetThrottleDeceleration; - UInt32 m_packetThrottleEpoch; - UInt32 m_packetThrottleInterval; - UInt32 m_packetThrottleLimit; - UInt32 m_packetsLost; - UInt32 m_packetsSent; - UInt32 m_pingInterval; - UInt32 m_reliableDataInTransit; - UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ - UInt32 m_roundTripTimeVariance; - UInt32 m_timeoutLimit; - UInt32 m_timeoutMaximum; - UInt32 m_timeoutMinimum; - UInt32 m_unsequencedWindow[ENetPeer_ReliableWindowSize / 32]; - UInt32 m_windowSize; - std::size_t m_totalWaitingData; + static constexpr std::size_t unsequencedWindow = ENetPeer_ReliableWindowSize / 32; + + ENetHost* m_host; + IpAddress m_address; /**< Internet address of the peer */ + std::array m_unsequencedWindow; + std::list m_acknowledgements; + std::list m_dispatchedCommands; + std::list m_outgoingReliableCommands; + std::list m_outgoingUnreliableCommands; + std::list m_sentReliableCommands; + std::list m_sentUnreliableCommands; + std::size_t m_totalWaitingData; + std::vector m_channels; + MemoryPool m_packetPool; + //ENetListNode m_dispatchList; + ENetPeerState m_state; + UInt8 m_incomingSessionID; + UInt8 m_outgoingSessionID; + UInt16 m_incomingPeerID; + UInt16 m_incomingUnsequencedGroup; + UInt16 m_outgoingPeerID; + UInt16 m_outgoingReliableSequenceNumber; + UInt16 m_outgoingUnsequencedGroup; + UInt32 m_connectID; + UInt32 m_earliestTimeout; + UInt32 m_eventData; + UInt32 m_highestRoundTripTimeVariance; + UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + UInt32 m_incomingBandwidthThrottleEpoch; + UInt32 m_incomingDataTotal; + UInt32 m_lastReceiveTime; + UInt32 m_lastRoundTripTime; + UInt32 m_lastRoundTripTimeVariance; + UInt32 m_lastSendTime; + UInt32 m_lowestRoundTripTime; + UInt32 m_mtu; + UInt32 m_nextTimeout; + UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + UInt32 m_outgoingBandwidthThrottleEpoch; + UInt32 m_outgoingDataTotal; + UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + UInt32 m_packetLossEpoch; + UInt32 m_packetLossVariance; + UInt32 m_packetThrottle; + UInt32 m_packetThrottleAcceleration; + UInt32 m_packetThrottleCounter; + UInt32 m_packetThrottleDeceleration; + UInt32 m_packetThrottleEpoch; + UInt32 m_packetThrottleInterval; + UInt32 m_packetThrottleLimit; + UInt32 m_packetsLost; + UInt32 m_packetsSent; + UInt32 m_pingInterval; + UInt32 m_reliableDataInTransit; + UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ + UInt32 m_roundTripTimeVariance; + UInt32 m_timeoutLimit; + UInt32 m_timeoutMaximum; + UInt32 m_timeoutMinimum; + UInt32 m_windowSize; }; } diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index a0cebbc4e..2c7044b6e 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -8,6 +8,11 @@ namespace Nz { + inline const IpAddress& ENetPeer::GetAddress() const + { + return m_address; + } + inline void ENetPeer::ChangeState(ENetPeerState state) { if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) @@ -17,13 +22,6 @@ namespace Nz m_state = state; } - - inline void ENetPeer::DispatchState(ENetPeerState state) - { - ChangeState(state); - - m_host->AddToDispatchQueue(this); - } } #include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index d4d74fd01..8b62f7dc7 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -13,6 +13,8 @@ namespace Nz { + class ENetPeer; + // Constants for the ENet implementation and protocol enum ENetConstants { @@ -140,27 +142,38 @@ namespace Nz 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 sentTime; }; - struct ENetProtocolCommandHeader + struct NAZARA_PACKED ENetProtocolCommandHeader { UInt8 command; UInt8 channelID; UInt16 reliableSequenceNumber; }; - struct ENetProtocolAcknowledge + struct NAZARA_PACKED ENetProtocolAcknowledge { ENetProtocolCommandHeader header; UInt16 receivedReliableSequenceNumber; UInt16 receivedSentTime; }; - struct ENetProtocolConnect + struct NAZARA_PACKED ENetProtocolConnect { ENetProtocolCommandHeader header; UInt16 outgoingPeerID; @@ -178,25 +191,25 @@ namespace Nz UInt32 data; }; - struct ENetProtocolBandwidthLimit + struct NAZARA_PACKED ENetProtocolBandwidthLimit { ENetProtocolCommandHeader header; UInt32 incomingBandwidth; UInt32 outgoingBandwidth; }; - struct ENetProtocolDisconnect + struct NAZARA_PACKED ENetProtocolDisconnect { ENetProtocolCommandHeader header; UInt32 data; }; - struct ENetProtocolPing + struct NAZARA_PACKED ENetProtocolPing { ENetProtocolCommandHeader header; }; - struct ENetProtocolSendFragment + struct NAZARA_PACKED ENetProtocolSendFragment { ENetProtocolCommandHeader header; UInt16 startSequenceNumber; @@ -207,27 +220,27 @@ namespace Nz UInt32 fragmentOffset; }; - struct ENetProtocolSendReliable + struct NAZARA_PACKED ENetProtocolSendReliable { ENetProtocolCommandHeader header; UInt16 dataLength; }; - struct ENetProtocolSendUnreliable + struct NAZARA_PACKED ENetProtocolSendUnreliable { ENetProtocolCommandHeader header; UInt16 unreliableSequenceNumber; UInt16 dataLength; }; - struct ENetProtocolSendUnsequenced + struct NAZARA_PACKED ENetProtocolSendUnsequenced { ENetProtocolCommandHeader header; UInt16 unsequencedGroup; UInt16 dataLength; }; - struct ENetProtocolThrottleConfigure + struct NAZARA_PACKED ENetProtocolThrottleConfigure { ENetProtocolCommandHeader header; UInt32 packetThrottleInterval; @@ -235,7 +248,7 @@ namespace Nz UInt32 packetThrottleDeceleration; }; - struct ENetProtocolVerifyConnect + struct NAZARA_PACKED ENetProtocolVerifyConnect { ENetProtocolCommandHeader header; UInt16 outgoingPeerID; @@ -252,7 +265,7 @@ namespace Nz UInt32 connectID; }; - union ENetProtocol + union NAZARA_PACKED ENetProtocol { ENetProtocolCommandHeader header; ENetProtocolAcknowledge acknowledge; @@ -267,6 +280,10 @@ namespace Nz ENetProtocolThrottleConfigure throttleConfigure; ENetProtocolVerifyConnect verifyConnect; }; + + #ifdef _MSC_VER + #pragma pack(pop) + #endif } #endif // NAZARA_ENETPROTOCOL_HPP diff --git a/include/Nazara/Network/Enums.hpp b/include/Nazara/Network/Enums.hpp index 7dccd7dd1..f80ba6cd9 100644 --- a/include/Nazara/Network/Enums.hpp +++ b/include/Nazara/Network/Enums.hpp @@ -7,6 +7,8 @@ #ifndef NAZARA_ENUMS_NETWORK_HPP #define NAZARA_ENUMS_NETWORK_HPP +#include + namespace Nz { enum NetCode : UInt16 diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 5bb9b7bdf..ffe15635a 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,9 +1,10 @@ -#include +#include #include #include #include #include #include +#include #include #define ENET_TIME_OVERFLOW 86400000 @@ -57,11 +58,6 @@ namespace Nz sizeof(ENetProtocolThrottleConfigure), 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.GetPort() != 0, "Remote address has no port"); @@ -96,7 +104,7 @@ namespace Nz if (peerId >= m_peers.size()) { NazaraError("Insufficient peers"); - return false; + return nullptr; } m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); @@ -130,10 +138,10 @@ namespace Nz 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 results = IpAddress::ResolveHostname(protocol, hostName, service, error); if (results.empty()) @@ -173,7 +181,9 @@ namespace Nz if (!InitSocket(address)) 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_randomSeed = *reinterpret_cast(this); @@ -187,6 +197,7 @@ namespace Nz m_mtu = ENetConstants::ENetHost_DefaultMTU; m_commandCount = 0; m_bufferCount = 0; + m_peerCount = peerCount; m_receivedAddress = IpAddress::AnyIpV4; m_receivedData = nullptr; m_receivedDataLength = 0; @@ -214,8 +225,6 @@ namespace Nz int ENetHost::Service(ENetEvent* event, UInt32 timeout) { - UInt32 waitCondition; - if (event) { event->type = ENetEventType::None; @@ -265,7 +274,7 @@ namespace Nz break; } - switch (SendOutgoingCommands(event, 1)) + switch (SendOutgoingCommands(event, true)) { case 1: return 1; @@ -283,21 +292,8 @@ namespace Nz if (event) { - switch (DispatchIncomingCommands(event)) - { - case 1: - return 1; - - case -1: - #ifdef ENET_DEBUG - perror("Error dispatching incoming packets"); - #endif - - return -1; - - default: - break; - } + if (DispatchIncomingCommands(event)) + return 1; } if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) @@ -310,12 +306,8 @@ namespace Nz if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) return 0; - SocketError error; - if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime), &error)) + if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime))) break; - - if (error != SocketError_NoError) - return -1; } m_serviceTime = GetElapsedMilliseconds(); @@ -349,6 +341,62 @@ namespace Nz 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) { 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); return true; + + default: + break; } } @@ -436,7 +487,7 @@ namespace Nz if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance) 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_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance; @@ -770,7 +821,7 @@ namespace Nz return commandError(); } - if (peer && (command->header.command & ENetProtocolCommand_Acknowledge) != 0) + if (peer && (command->header.command & ENetProtocolFlag_Acknowledge) != 0) { UInt16 sentTime; @@ -810,6 +861,90 @@ namespace Nz 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(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + peer->DispatchIncomingReliableCommands(channel); + } + + return false; + } + 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)) @@ -826,6 +961,152 @@ namespace Nz 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(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(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(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(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) { if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) @@ -901,17 +1182,8 @@ namespace Nz // Intercept - switch (HandleIncomingCommands(event)) - { - case 1: - return 1; - - case -1: - return -1; - - default: - break; - } + if (HandleIncomingCommands(event)) + 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 headerData; + ENetProtocolHeader* header = reinterpret_cast(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(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(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() { 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() { std::random_device device; diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp index ec2bc4ab7..a22cc7fb8 100644 --- a/src/Nazara/Network/ENetPacket.cpp +++ b/src/Nazara/Network/ENetPacket.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include namespace Nz { /// Temporary - void ENetPacketRef::Reset(ENetPacket* packet = nullptr) + void ENetPacketRef::Reset(ENetPacket* packet) { if (m_packet) { @@ -20,4 +20,4 @@ namespace Nz if (m_packet) m_packet->referenceCount++; } -} \ No newline at end of file +} diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6f7f33312..2031755c4 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,7 +1,8 @@ -#include +#include #include #include #include +#include #include namespace Nz @@ -129,7 +130,7 @@ namespace Nz IncomingCommmand& incomingCommand = m_dispatchedCommands.front(); - m_totalWaitingData -= incomingCommand.packet->data.GetSize(); + m_totalWaitingData -= incomingCommand.packet->data.GetDataSize(); if (packet) *packet = std::move(incomingCommand.packet); @@ -192,7 +193,7 @@ namespace Nz m_eventData = 0; m_totalWaitingData = 0; - std::memset(m_unsequencedWindow, 0, sizeof(m_unsequencedWindow)); + m_unsequencedWindow.fill(0); ResetQueues(); } @@ -209,7 +210,7 @@ namespace Nz 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; Channel& channel = m_channels[channelId]; @@ -218,7 +219,7 @@ namespace Nz //if (m_host->m_checksum != nullptr) // fragmentLength -= sizeof(UInt32); - UInt32 packetSize = static_cast(packetRef->data.GetSize()); + UInt32 packetSize = static_cast(packetRef->data.GetDataSize()); if (packetSize > fragmentLength) { UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; @@ -254,7 +255,7 @@ namespace Nz OutgoingCommand outgoingCommand; outgoingCommand.fragmentOffset = fragmentOffset; - outgoingCommand.fragmentLength = fragmentLength; + outgoingCommand.fragmentLength = static_cast(fragmentLength); outgoingCommand.packet = packetRef; outgoingCommand.command.header.command = commandNumber; outgoingCommand.command.header.channelID = channelId; @@ -275,11 +276,20 @@ namespace Nz command.header.channelID = channelId; if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_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) + { command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge; + command.sendReliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } else + { command.header.command = ENetProtocolCommand_SendUnreliable; + command.sendUnreliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } QueueOutgoingCommand(command, packetRef, 0, packetSize); @@ -354,6 +364,13 @@ namespace Nz m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); } + void ENetPeer::DispatchState(ENetPeerState state) + { + ChangeState(state); + + m_host->AddToDispatchQueue(this); + } + void ENetPeer::DispatchIncomingReliableCommands(Channel& channel) { auto currentCommand = channel.incomingReliableCommands.begin(); @@ -375,7 +392,7 @@ namespace Nz 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); @@ -408,7 +425,7 @@ namespace Nz 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); @@ -436,7 +453,7 @@ namespace Nz 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); } @@ -448,7 +465,7 @@ namespace Nz 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); @@ -587,7 +604,7 @@ namespace Nz } Acknowledgement acknowledgment; - acknowledgment.command = command; + acknowledgment.command = *command; acknowledgment.sentTime = sentTime; m_outgoingDataTotal += sizeof(Acknowledgement); @@ -597,7 +614,7 @@ namespace Nz 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; @@ -740,6 +757,9 @@ namespace Nz incomingCommand.fragments.resize(fragmentCount, 0); incomingCommand.fragmentsRemaining = fragmentCount; + if (packet) + m_totalWaitingData += packet->data.GetDataSize(); + auto it = commandList->insert(currentCommand.base(), incomingCommand); switch (command.header.command & ENetProtocolCommand_Mask) @@ -762,7 +782,7 @@ namespace Nz OutgoingCommand outgoingCommand; outgoingCommand.command = command; outgoingCommand.fragmentLength = length; - outgoingCommand.fragmentOffset = length; + outgoingCommand.fragmentOffset = offset; outgoingCommand.packet = packet; SetupOutgoingCommand(outgoingCommand); @@ -770,7 +790,7 @@ namespace Nz 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) { @@ -827,7 +847,7 @@ namespace Nz break; } - if (outgoingCommand.command.header.command & ENetProtocolCommand_Acknowledge) + if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge) m_outgoingReliableCommands.emplace_back(outgoingCommand); else m_outgoingUnreliableCommands.emplace_back(outgoingCommand); diff --git a/src/Nazara/Network/ENetSocket.cpp b/src/Nazara/Network/ENetSocket.cpp deleted file mode 100644 index e86313fb4..000000000 --- a/src/Nazara/Network/ENetSocket.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -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(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 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(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& 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(m_protocol & 0xFFFF); - UInt16 protocolEnd = static_cast((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(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; -} From 0e03aae6dcbae465ce69d65c5da1594eb0698565 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 27 Jan 2017 17:12:23 +0100 Subject: [PATCH 04/48] Network/ENetPeer: Fix compilation --- include/Nazara/Network/ENetPeer.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index e68b85de9..1099e4472 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -16,11 +16,9 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include namespace Nz { From 664e3a33ecab433978ca51bfe2013e377f51bf2f Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 27 Jan 2017 17:19:49 +0100 Subject: [PATCH 05/48] Network/ENet: Fix compilation and warnings --- src/Nazara/Network/ENetHost.cpp | 11 ++++------- src/Nazara/Network/ENetPeer.cpp | 6 +++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index ffe15635a..df77e25c9 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #define ENET_TIME_OVERFLOW 86400000 @@ -145,7 +144,7 @@ namespace Nz { std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); if (results.empty()) - return false; + return nullptr; IpAddress hostnameAddress; for (const HostnameInfo& result : results) @@ -558,7 +557,7 @@ namespace Nz return true; } - ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* header, ENetProtocol* command) + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* /*header*/, ENetProtocol* command) { UInt32 channelCount = NetToHost(command->connect.channelCount); @@ -853,7 +852,7 @@ namespace Nz return commandError(); } - bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* command) + bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* /*command*/) { if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) return false; @@ -1071,7 +1070,7 @@ namespace Nz 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) + 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); @@ -1230,8 +1229,6 @@ 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()) { diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 2031755c4..37afe8958 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -30,11 +30,11 @@ namespace Nz } ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : - m_packetPool(sizeof(ENetPacket)), m_host(host), - m_incomingPeerID(peerId), + m_packetPool(sizeof(ENetPacket)), m_incomingSessionID(0xFF), - m_outgoingSessionID(0xFF) + m_outgoingSessionID(0xFF), + m_incomingPeerID(peerId) { Reset(); } From 8fc734674dff80c25f36edd3565b7a273a04a669 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 11:06:09 +0100 Subject: [PATCH 06/48] Network/ENet: Fix fragments and cleanup --- include/Nazara/Network/ENetPeer.hpp | 18 ++++--- include/Nazara/Network/ENetPeer.inl | 15 ++++++ src/Nazara/Network/ENetHost.cpp | 82 ++++++++++++++--------------- src/Nazara/Network/ENetPeer.cpp | 19 +++---- 4 files changed, 73 insertions(+), 61 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 1099e4472..377d8f734 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -40,6 +40,11 @@ namespace Nz void DisconnectNow(UInt32 data); inline const IpAddress& GetAddress() const; + inline ENetPeerState GetState() const; + + inline bool HasPendingCommands(); + + inline bool IsConnected() const; void Ping(); @@ -116,12 +121,12 @@ namespace Nz struct IncomingCommmand { - ENetProtocol command; - UInt16 reliableSequenceNumber; - UInt16 unreliableSequenceNumber; - UInt32 fragmentsRemaining; - std::vector fragments; - ENetPacketRef packet; + ENetProtocol command; + Bitset<> fragments; + ENetPacketRef packet; + UInt16 reliableSequenceNumber; + UInt16 unreliableSequenceNumber; + UInt32 fragmentsRemaining; }; struct OutgoingCommand @@ -152,7 +157,6 @@ namespace Nz std::size_t m_totalWaitingData; std::vector m_channels; MemoryPool m_packetPool; - //ENetListNode m_dispatchList; ENetPeerState m_state; UInt8 m_incomingSessionID; UInt8 m_outgoingSessionID; diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 2c7044b6e..5c0f76731 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -13,6 +13,21 @@ namespace Nz return m_address; } + inline ENetPeerState ENetPeer::GetState() const + { + return m_state; + } + + inline bool ENetPeer::HasPendingCommands() + { + return m_outgoingReliableCommands.empty() && m_outgoingUnreliableCommands.empty() && m_sentReliableCommands.empty(); + } + + inline bool ENetPeer::IsConnected() const + { + return m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater; + } + inline void ENetPeer::ChangeState(ENetPeerState state) { if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index df77e25c9..a6e98a0c4 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -69,7 +69,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if (peer.m_state != ENetPeerState::Connected) + if (peer.GetState() != ENetPeerState::Connected) continue; peer.Send(channelId, enetPacket); @@ -96,7 +96,7 @@ namespace Nz std::size_t peerId; for (peerId = 0; peerId < m_peers.size(); ++peerId) { - if (m_peers[peerId].m_state == ENetPeerState::Disconnected) + if (m_peers[peerId].GetState() == ENetPeerState::Disconnected) break; } @@ -403,7 +403,7 @@ namespace Nz m_dispatchQueue.Reset(bit); ENetPeer& peer = m_peers[bit]; - switch (peer.m_state) + switch (peer.GetState()) { case ENetPeerState::ConnectionPending: case ENetPeerState::ConnectionSucceeded: @@ -449,7 +449,7 @@ namespace Nz bool ENetHost::HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) { - if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) return true; UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); @@ -499,7 +499,7 @@ namespace Nz ENetProtocolCommand commandNumber = peer->RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); - switch (peer->m_state) + switch (peer->GetState()) { case ENetPeerState::AcknowledgingConnect: if (commandNumber != ENetProtocolCommand_VerifyConnect) @@ -516,7 +516,7 @@ namespace Nz break; case ENetPeerState::DisconnectLater: - if (peer->m_outgoingReliableCommands.empty() && peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + if (!peer->HasPendingCommands()) peer->Disconnect(peer->m_eventData); break; @@ -530,7 +530,7 @@ namespace Nz bool ENetHost::HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command) { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) return false; if (peer->m_incomingBandwidth != 0) @@ -568,12 +568,12 @@ namespace Nz ENetPeer* peer = nullptr; for (ENetPeer& currentPeer : m_peers) { - if (currentPeer.m_state == ENetPeerState::Disconnected) + if (currentPeer.GetState() == ENetPeerState::Disconnected) { if (!peer) peer = ¤tPeer; } - else if (currentPeer.m_state != ENetPeerState::Connecting) + else if (currentPeer.GetState() != ENetPeerState::Connecting) { // Compare users without comparing their port IpAddress first(currentPeer.m_address); @@ -631,18 +631,18 @@ namespace Nz bool ENetHost::HandleDisconnect(ENetPeer* peer, const ENetProtocol * command) { - if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie || peer->m_state == ENetPeerState::AcknowledgingDisconnect) + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie || peer->GetState() == ENetPeerState::AcknowledgingDisconnect) return true; peer->ResetQueues(); - if (peer->m_state == ENetPeerState::ConnectionSucceeded || peer->m_state == ENetPeerState::Disconnecting || peer->m_state == ENetPeerState::Connecting) + if (peer->GetState() == ENetPeerState::ConnectionSucceeded || peer->GetState() == ENetPeerState::Disconnecting || peer->GetState() == ENetPeerState::Connecting) peer->DispatchState(ENetPeerState::Zombie); else { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) { - if (peer->m_state == ENetPeerState::ConnectionPending) + if (peer->GetState() == ENetPeerState::ConnectionPending) m_recalculateBandwidthLimits = true; peer->Reset(); @@ -654,7 +654,7 @@ namespace Nz peer->DispatchState(ENetPeerState::Zombie); } - if (peer->m_state != ENetPeerState::Disconnected) + if (peer->GetState() != ENetPeerState::Disconnected) peer->m_eventData = NetToHost(command->disconnect.data); return true; @@ -685,7 +685,7 @@ namespace Nz { peer = &m_peers[peerID]; - if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) return false; if (m_receivedAddress != peer->m_address && peer->m_address != IpAddress::BroadcastIpV4) @@ -829,7 +829,7 @@ namespace Nz sentTime = NetToHost(header->sentTime); - switch (peer->m_state) + switch (peer->GetState()) { case ENetPeerState::Disconnecting: case ENetPeerState::AcknowledgingConnect: @@ -854,7 +854,7 @@ namespace Nz bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* /*command*/) { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) return false; return true; @@ -862,7 +862,7 @@ namespace Nz 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)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); @@ -909,7 +909,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -926,11 +926,11 @@ namespace Nz return false; } - if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + if (!startCommand->fragments.Test(fragmentNumber)) { --startCommand->fragmentsRemaining; - startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + startCommand->fragments.Set(fragmentNumber); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -946,7 +946,7 @@ namespace Nz 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->IsConnected()) return false; UInt16 dataLength = NetToHost(command->sendReliable.dataLength); @@ -962,7 +962,7 @@ namespace Nz 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)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); @@ -978,7 +978,7 @@ namespace Nz 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)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); @@ -1050,11 +1050,11 @@ namespace Nz return false; } - if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + if (!startCommand->fragments.Test(fragmentNumber)) { --startCommand->fragmentsRemaining; - startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + startCommand->fragments.Set(fragmentNumber); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -1070,7 +1070,7 @@ namespace Nz 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)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); @@ -1108,7 +1108,7 @@ namespace Nz bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command) { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) return false; peer->m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); @@ -1120,7 +1120,7 @@ namespace Nz bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) { - if (peer->m_state != ENetPeerState::Connecting) + if (peer->GetState() != ENetPeerState::Connecting) return false; UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); @@ -1201,15 +1201,15 @@ namespace Nz event->data = peer->m_eventData; } else - peer->DispatchState(peer->m_state == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + peer->DispatchState(peer->GetState() == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); } void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) { - if (peer->m_state >= ENetPeerState::ConnectionPending) + if (peer->GetState() >= ENetPeerState::ConnectionPending) m_recalculateBandwidthLimits = true; - if (peer->m_state != ENetPeerState::Connecting && (peer->m_state < ENetPeerState::ConnectionSucceeded)) + if (peer->GetState() != ENetPeerState::Connecting && (peer->GetState() < ENetPeerState::ConnectionSucceeded)) peer->Reset(); else if (event) { @@ -1394,7 +1394,7 @@ namespace Nz 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) + if (currentPeer->GetState() == ENetPeerState::Disconnected || currentPeer->GetState() == ENetPeerState::Zombie) continue; m_headerFlags = 0; @@ -1560,8 +1560,7 @@ namespace Nz ++m_commandCount; } - if (peer->m_state == ENetPeerState::DisconnectLater && peer->m_outgoingReliableCommands.empty() && - peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + if (peer->GetState() == ENetPeerState::DisconnectLater && !peer->HasPendingCommands()) peer->Disconnect(peer->m_eventData); } @@ -1588,7 +1587,7 @@ namespace Nz dataTotal = 0; for (ENetPeer& peer : m_peers) { - if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + if (peer.IsConnected()) continue; dataTotal += peer.m_outgoingDataTotal; @@ -1611,8 +1610,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || - peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) + if (!peer.IsConnected() || peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) continue; UInt32 peerBandwidth = (peer.m_incomingBandwidth * elapsedTime) / 1000; @@ -1648,8 +1646,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || - peer.m_outgoingBandwidthThrottleEpoch == currentTime) + if (!peer.IsConnected() || peer.m_outgoingBandwidthThrottleEpoch == currentTime) continue; peer.m_packetThrottleLimit = throttle; @@ -1681,8 +1678,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || - peer.m_incomingBandwidthThrottleEpoch == currentTime) + if (!peer.IsConnected() || peer.m_incomingBandwidthThrottleEpoch == currentTime) continue; if (peer.m_outgoingBandwidth > 0 && peer.m_outgoingBandwidth >= bandwidthLimit) @@ -1699,7 +1695,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + if (!peer.IsConnected()) continue; ENetProtocol command; diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 37afe8958..38025108f 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -54,14 +54,14 @@ namespace Nz command.header.channelID = 0xFF; command.disconnect.data = HostToNet(data); - if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + if (IsConnected()) command.header.command |= ENetProtocolFlag_Acknowledge; else command.header.command |= ENetProtocolFlag_Unsequenced; QueueOutgoingCommand(command, nullptr, 0, 0); - if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + if (IsConnected()) { OnDisconnect(); @@ -77,10 +77,7 @@ namespace Nz void ENetPeer::DisconnectLater(UInt32 data) { - if ((m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) && - !m_outgoingReliableCommands.empty() && - !m_outgoingUnreliableCommands.empty() && - !m_sentReliableCommands.empty()) + if (IsConnected() && !m_outgoingReliableCommands.empty() && !m_outgoingUnreliableCommands.empty() && !m_sentReliableCommands.empty()) { m_state = ENetPeerState::DisconnectLater; m_eventData = data; @@ -383,8 +380,8 @@ namespace Nz channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; - if (!incomingCommand.fragments.empty()) - channel.incomingReliableSequenceNumber += incomingCommand.fragments.size() - 1; + if (incomingCommand.fragments.GetSize() == 0) + channel.incomingReliableSequenceNumber += incomingCommand.fragments.GetSize() - 1; } if (currentCommand == channel.incomingReliableCommands.begin()) @@ -477,7 +474,7 @@ namespace Nz void ENetPeer::OnConnect() { - if (m_state != ENetPeerState::Connected && m_state != ENetPeerState::DisconnectLater) + if (!IsConnected()) { if (m_incomingBandwidth != 0) ++m_host->m_bandwidthLimitedPeers; @@ -488,7 +485,7 @@ namespace Nz void ENetPeer::OnDisconnect() { - if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + if (IsConnected()) { if (m_incomingBandwidth != 0) --m_host->m_bandwidthLimitedPeers; @@ -754,7 +751,7 @@ namespace Nz incomingCommand.unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; incomingCommand.command = command; incomingCommand.packet = packet; - incomingCommand.fragments.resize(fragmentCount, 0); + incomingCommand.fragments.Resize(fragmentCount); incomingCommand.fragmentsRemaining = fragmentCount; if (packet) From c9d5f2f1ac449f4026b16f02bbf87e253f975eaf Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 12:08:35 +0100 Subject: [PATCH 07/48] Network/ENet: More cleanup --- include/Nazara/Network/ENetHost.hpp | 2 - include/Nazara/Network/ENetPeer.hpp | 5 +- include/Nazara/Network/ENetPeer.inl | 5 + include/Nazara/Network/ENetProtocol.hpp | 8 ++ src/Nazara/Network/ENetHost.cpp | 89 ++----------- src/Nazara/Network/ENetPeer.cpp | 158 +++++++++++++++--------- 6 files changed, 130 insertions(+), 137 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 3b86a1f25..344ffce82 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -64,8 +64,6 @@ namespace Nz void AddToDispatchQueue(ENetPeer* peer); void RemoveFromDispatchQueue(ENetPeer* peer); - bool CheckTimeouts(ENetPeer* peer, ENetEvent* event); - bool DispatchIncomingCommands(ENetEvent* event); bool HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command); diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 377d8f734..7ccaf3d8d 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -68,8 +68,10 @@ namespace Nz struct IncomingCommmand; struct OutgoingCommand; - // Protocol functions inline void ChangeState(ENetPeerState state); + + bool CheckTimeouts(ENetEvent* event); + void DispatchState(ENetPeerState state); void DispatchIncomingReliableCommands(Channel& channel); @@ -85,6 +87,7 @@ namespace Nz bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime); IncomingCommmand* QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); + inline void QueueOutgoingCommand(ENetProtocol& command); void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 5c0f76731..1e74e0cae 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -37,6 +37,11 @@ namespace Nz m_state = state; } + + inline void ENetPeer::QueueOutgoingCommand(ENetProtocol& command) + { + QueueOutgoingCommand(command, ENetPacketRef(), 0, 0); + } } #include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index 8b62f7dc7..0434cafc2 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -267,6 +267,14 @@ namespace Nz union NAZARA_PACKED ENetProtocol { + ENetProtocol() = default; + + ENetProtocol(UInt8 command, UInt8 channel) + { + header.command = command; + header.channelID = channel; + } + ENetProtocolCommandHeader header; ENetProtocolAcknowledge acknowledge; ENetProtocolBandwidthLimit bandwidthLimit; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index a6e98a0c4..afa870b12 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -117,10 +117,7 @@ namespace Nz ENetPeer& peer = m_peers[peerId]; peer.InitOutgoing(channelCount, remoteAddress, ++m_randomSeed, windowSize); - ENetProtocol command; - command.header.command = ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge; - command.header.channelID = 0xFF; - + ENetProtocol command(ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge, 0xFF); command.connect.channelCount = HostToNet(static_cast(channelCount)); command.connect.connectID = peer.m_connectID; command.connect.data = HostToNet(data); @@ -134,8 +131,7 @@ namespace Nz command.connect.packetThrottleDeceleration = HostToNet(peer.m_packetThrottleDeceleration); command.connect.packetThrottleInterval = HostToNet(peer.m_packetThrottleInterval); command.connect.windowSize = HostToNet(peer.m_windowSize); - - peer.QueueOutgoingCommand(command, nullptr, 0, 0); + peer.QueueOutgoingCommand(command); return &peer; } @@ -350,52 +346,6 @@ namespace Nz 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) { for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit)) @@ -608,9 +558,7 @@ namespace Nz windowSize = std::max(windowSize, NetToHost(command->connect.windowSize)); windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - ENetProtocol verifyCommand; - verifyCommand.header.command = ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge; - verifyCommand.header.channelID = 0xFF; + ENetProtocol verifyCommand(ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge, 0xFF); verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->m_incomingPeerID); verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; @@ -623,8 +571,7 @@ namespace Nz verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->m_packetThrottleAcceleration); verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->m_packetThrottleDeceleration); verifyCommand.verifyConnect.connectID = peer->m_connectID; - - peer->QueueOutgoingCommand(verifyCommand, nullptr, 0, 0); + peer->QueueOutgoingCommand(verifyCommand); return peer; } @@ -930,7 +877,7 @@ namespace Nz { --startCommand->fragmentsRemaining; - startCommand->fragments.Set(fragmentNumber); + startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -1036,7 +983,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -1054,7 +1001,7 @@ namespace Nz { --startCommand->fragmentsRemaining; - startCommand->fragments.Set(fragmentNumber); + startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -1405,8 +1352,7 @@ namespace Nz 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 (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) { if (event && event->type != ENetEventType::None) return 1; @@ -1617,14 +1563,7 @@ namespace Nz if ((throttle * peer.m_outgoingDataTotal) / ENetConstants::ENetPeer_PacketThrottleScale <= peerBandwidth) continue; - peer.m_packetThrottleLimit = (peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal; - - if (peer.m_packetThrottleLimit == 0) - peer.m_packetThrottleLimit = 1; - - if (peer.m_packetThrottle > peer.m_packetThrottleLimit) - peer.m_packetThrottle = peer.m_packetThrottleLimit; - + peer.m_packetThrottleLimit = Clamp((peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal, 0, peer.m_packetThrottleLimit); peer.m_outgoingBandwidthThrottleEpoch = currentTime; peer.m_incomingDataTotal = 0; @@ -1650,9 +1589,7 @@ namespace Nz continue; peer.m_packetThrottleLimit = throttle; - - if (peer.m_packetThrottle > peer.m_packetThrottleLimit) - peer.m_packetThrottle = peer.m_packetThrottleLimit; + peer.m_packetThrottle = std::min(peer.m_packetThrottle, peer.m_packetThrottleLimit); peer.m_incomingDataTotal = 0; peer.m_outgoingDataTotal = 0; @@ -1698,9 +1635,7 @@ namespace Nz if (!peer.IsConnected()) continue; - ENetProtocol command; - command.header.command = ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge; - command.header.channelID = 0xFF; + ENetProtocol command(ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge, 0xFF); command.bandwidthLimit.outgoingBandwidth = HostToNet(m_outgoingBandwidth); if (peer.m_incomingBandwidthThrottleEpoch == currentTime) @@ -1708,7 +1643,7 @@ namespace Nz else command.bandwidthLimit.incomingBandwidth = HostToNet(bandwidthLimit); - peer.QueueOutgoingCommand(command, nullptr, 0, 0); + peer.QueueOutgoingCommand(command); } } } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 38025108f..e444a4d02 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -5,6 +5,15 @@ #include #include +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + namespace Nz { /// Temporary @@ -49,9 +58,7 @@ namespace Nz ResetQueues(); - ENetProtocol command; - command.header.command = ENetProtocolCommand_Disconnect; - command.header.channelID = 0xFF; + ENetProtocol command(ENetProtocolCommand_Disconnect, 0xFF); command.disconnect.data = HostToNet(data); if (IsConnected()) @@ -59,7 +66,7 @@ namespace Nz else command.header.command |= ENetProtocolFlag_Unsequenced; - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); if (IsConnected()) { @@ -95,12 +102,9 @@ namespace Nz { ResetQueues(); - ENetProtocol command; - command.header.command = ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced; - command.header.channelID = 0xFF; + ENetProtocol command(ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced, 0xFF); command.disconnect.data = HostToNet(data); - - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); m_host->Flush(); } @@ -116,8 +120,7 @@ namespace Nz ENetProtocol command; command.header.command = ENetProtocolCommand_Ping | ENetProtocolFlag_Acknowledge; command.header.channelID = 0xFF; - - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); } bool ENetPeer::Receive(ENetPacketRef* packet, UInt8* channelId) @@ -299,66 +302,56 @@ namespace Nz m_packetThrottleAcceleration = acceleration; m_packetThrottleDeceleration = deceleration; - ENetProtocol command; - command.header.command = ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge; - command.header.channelID = 0xFF; - + ENetProtocol command(ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge, 0xFF); command.throttleConfigure.packetThrottleInterval = HostToNet(interval); command.throttleConfigure.packetThrottleAcceleration = HostToNet(acceleration); command.throttleConfigure.packetThrottleDeceleration = HostToNet(deceleration); - - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); } - void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + bool ENetPeer::CheckTimeouts(ENetEvent* event) { - m_channels.resize(channelCount); - m_address = address; + auto currentCommand = m_sentReliableCommands.begin(); + while (currentCommand != m_sentReliableCommands.end()) + { + auto outgoingCommand = currentCommand; - m_connectID = incomingCommand.connectID; - m_eventData = NetToHost(incomingCommand.data); - m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); - m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); - m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); - m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); - m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); - m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); - m_state = ENetPeerState::AcknowledgingConnect; + ++currentCommand; - UInt8 incomingSessionId, outgoingSessionId; + if (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + continue; - incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; - incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - if (incomingSessionId == m_outgoingSessionID) - incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - m_outgoingSessionID = incomingSessionId; + if (m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, m_earliestTimeout)) + m_earliestTimeout = outgoingCommand->sentTime; - outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; - outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - if (outgoingSessionId == m_incomingSessionID) - outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - m_incomingSessionID = outgoingSessionId; + if (m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMaximum || + (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + { + m_host->NotifyDisconnect(this, event); + return true; + } - m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + if (outgoingCommand->packet) + m_reliableDataInTransit -= outgoingCommand->fragmentLength; - if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) - m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; - else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) - m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; - else - m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + ++m_packetsLost; - m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - } + outgoingCommand->roundTripTimeout *= 2; - void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) - { - m_channels.resize(channelCount); + m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); + m_sentReliableCommands.erase(outgoingCommand); - m_address = address; - m_connectID = connectId; - m_state = ENetPeerState::Connecting; - m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + // 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; } void ENetPeer::DispatchState(ENetPeerState state) @@ -472,6 +465,57 @@ namespace Nz channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); } + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + { + m_channels.resize(channelCount); + m_address = address; + + m_connectID = incomingCommand.connectID; + m_eventData = NetToHost(incomingCommand.data); + m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); + m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); + m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); + m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); + m_state = ENetPeerState::AcknowledgingConnect; + + UInt8 incomingSessionId, outgoingSessionId; + + incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (incomingSessionId == m_outgoingSessionID) + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_outgoingSessionID = incomingSessionId; + + outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (outgoingSessionId == m_incomingSessionID) + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_incomingSessionID = outgoingSessionId; + + m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + + if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) + m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) + { + m_channels.resize(channelCount); + + m_address = address; + m_connectID = connectId; + m_state = ENetPeerState::Connecting; + m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + void ENetPeer::OnConnect() { if (!IsConnected()) @@ -498,7 +542,7 @@ namespace Nz { std::list* commandList = nullptr; - bool found = true; + bool found = false; auto currentCommand = m_sentReliableCommands.begin(); commandList = &m_sentReliableCommands; for (; currentCommand != m_sentReliableCommands.end(); ++currentCommand) From 6ab6ec4f14f097849d2aef2a1d90dee7ad9dde59 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 12:14:41 +0100 Subject: [PATCH 08/48] Network/ENetPeer: Improved stability of connections http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html --- src/Nazara/Network/ENetPeer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index e444a4d02..d29860e4d 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -336,7 +336,9 @@ namespace Nz ++m_packetsLost; - outgoingCommand->roundTripTimeout *= 2; + // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html + outgoingCommand->roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; + outgoingCommand->roundTripTimeoutLimit = m_timeoutLimit * outgoingCommand->roundTripTimeout; m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); m_sentReliableCommands.erase(outgoingCommand); From 9d9d7472ca3de240fffb6027c5b336468f062dbd Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 14:09:43 +0100 Subject: [PATCH 09/48] Network/ENetPacket: Fix a huge bug with packets --- src/Nazara/Network/ENetPacket.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp index a22cc7fb8..494ae1a54 100644 --- a/src/Nazara/Network/ENetPacket.cpp +++ b/src/Nazara/Network/ENetPacket.cpp @@ -10,10 +10,7 @@ namespace Nz if (m_packet) { if (--m_packet->referenceCount == 0) - { m_packet->owner->Delete(m_packet); - return; - } } m_packet = packet; From 5207f2c821e79a5d82169a7bc889ea4eaa9269b6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:15:33 +0100 Subject: [PATCH 10/48] Network/ENet: Fix some remaining bugs.... --- src/Nazara/Network/ENetHost.cpp | 4 ++-- src/Nazara/Network/ENetPeer.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index afa870b12..28f586307 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1082,7 +1082,7 @@ namespace Nz peer->DispatchState(ENetPeerState::Zombie); - return false; + return true; } peer->RemoveSentReliableCommand(1, 0xFF); @@ -1201,7 +1201,7 @@ namespace Nz command.header.channelID = acknowledgement.command.header.channelID; command.header.reliableSequenceNumber = reliableSequenceNumber; command.acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; - command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime); + command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime); if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) peer->DispatchState(ENetPeerState::Zombie); diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index d29860e4d..340c3152a 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -375,7 +375,7 @@ namespace Nz channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; - if (incomingCommand.fragments.GetSize() == 0) + if (incomingCommand.fragments.GetSize() > 0) channel.incomingReliableSequenceNumber += incomingCommand.fragments.GetSize() - 1; } From 34828929b2b545d6d9ce90251a97866a47563ba1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:16:14 +0100 Subject: [PATCH 11/48] Network/ENetHost: Fix a bug --- src/Nazara/Network/ENetHost.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 28f586307..814f843ff 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -983,7 +983,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -1068,7 +1068,7 @@ namespace Nz bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) { if (peer->GetState() != ENetPeerState::Connecting) - return false; + return true; UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); @@ -1082,7 +1082,7 @@ namespace Nz peer->DispatchState(ENetPeerState::Zombie); - return true; + return false; } peer->RemoveSentReliableCommand(1, 0xFF); From 4e2a037d6b06cab659a3e9a1430b65c9d0feaca8 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:17:42 +0100 Subject: [PATCH 12/48] Network/ENetPeer: Add total packet lost/sent counter --- include/Nazara/Network/ENetPeer.hpp | 2 ++ src/Nazara/Network/ENetHost.cpp | 1 + src/Nazara/Network/ENetPeer.cpp | 3 +++ 3 files changed, 6 insertions(+) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 7ccaf3d8d..aa3c9f2da 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -205,6 +205,8 @@ namespace Nz UInt32 m_timeoutMaximum; UInt32 m_timeoutMinimum; UInt32 m_windowSize; + UInt64 m_totalPacketLost; + UInt64 m_totalPacketSent; }; } diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 814f843ff..d9a09d2c8 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1320,6 +1320,7 @@ namespace Nz } ++peer->m_packetsSent; + ++peer->m_totalPacketSent; ++m_bufferCount; ++m_commandCount; } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 340c3152a..c969dde4b 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -191,6 +191,8 @@ namespace Nz m_incomingUnsequencedGroup = 0; m_outgoingUnsequencedGroup = 0; m_eventData = 0; + m_totalPacketLost = 0; + m_totalPacketSent = 0; m_totalWaitingData = 0; m_unsequencedWindow.fill(0); @@ -335,6 +337,7 @@ namespace Nz m_reliableDataInTransit -= outgoingCommand->fragmentLength; ++m_packetsLost; + ++m_totalPacketLost; // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html outgoingCommand->roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; From 4e517bc1e3666be901fdb1cf3be08bfd037fdec7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:18:06 +0100 Subject: [PATCH 13/48] Network/ENetHost: Add network simulator --- include/Nazara/Network/ENetHost.hpp | 14 +++++- include/Nazara/Network/ENetHost.inl | 3 +- src/Nazara/Network/ENetHost.cpp | 70 ++++++++++++++++++++++++++--- src/Nazara/Network/ENetPeer.cpp | 1 - 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 344ffce82..0dcf58a86 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -55,6 +55,8 @@ namespace Nz int Service(ENetEvent* event, UInt32 timeout); + void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); + ENetHost& operator=(const ENetHost&) = delete; ENetHost& operator=(ENetHost&&) = default; @@ -96,6 +98,13 @@ namespace Nz static bool Initialize(); static void Uninitialize(); + struct PendingPacket + { + IpAddress from; + NetPacket data; + UInt32 deliveryTime; + }; + std::array m_commands; std::array m_buffers; std::array m_packetData[2]; @@ -110,7 +119,10 @@ namespace Nz std::size_t m_packetSize; std::size_t m_peerCount; std::size_t m_receivedDataLength; + std::uniform_int_distribution m_packetDelayDistribution; std::vector m_peers; + std::vector m_pendingPackets; + UInt8* m_receivedData; Bitset m_dispatchQueue; MemoryPool m_packetPool; IpAddress m_address; @@ -129,10 +141,8 @@ namespace Nz UInt32 m_totalSentPackets; UInt32 m_totalReceivedData; UInt32 m_totalReceivedPackets; - UInt8* m_receivedData; bool m_continueSending; bool m_isSimulationEnabled; - bool m_shouldAcceptConnections; bool m_recalculateBandwidthLimits; static std::mt19937 s_randomGenerator; diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index e547d4e5d..c7e65ab95 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -9,7 +9,8 @@ namespace Nz { inline ENetHost::ENetHost() : - m_packetPool(sizeof(ENetPacket)) + m_packetPool(sizeof(ENetPacket)), + m_isSimulationEnabled(false) { } diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d9a09d2c8..3587e19d1 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -312,6 +312,20 @@ namespace Nz return 0; } + void ENetHost::SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay) + { + NazaraAssert(maxDelay >= minDelay, "Maximum delay cannot be greater than minimum delay"); + + if (packetLossProbability <= 0.0 && minDelay == 0 && maxDelay == 0) + m_isSimulationEnabled = false; + else + { + m_isSimulationEnabled = true; + m_packetDelayDistribution = std::uniform_int_distribution(minDelay, maxDelay); + m_packetLossProbability = std::bernoulli_distribution(packetLossProbability); + } + } + bool ENetHost::InitSocket(const IpAddress& address) { if (!m_socket.Create(address.GetProtocol())) @@ -1111,14 +1125,58 @@ namespace Nz { for (unsigned int i = 0; i < 256; ++i) { - NetPacket packet; - + bool shouldReceive = true; std::size_t receivedLength; - if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) - return -1; //< Error - if (receivedLength == 0) - return 0; + if (m_isSimulationEnabled) + { + for (auto it = m_pendingPackets.begin(); it != m_pendingPackets.end(); ++it) + { + if (m_serviceTime >= it->deliveryTime) + { + shouldReceive = false; + + m_receivedAddress = it->from; + receivedLength = it->data.GetDataSize(); + std::memcpy(m_packetData[0].data(), it->data.GetConstData() + NetPacket::HeaderSize, receivedLength); + + m_pendingPackets.erase(it); + break; + } + } + } + + if (shouldReceive) + { + if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) + return -1; //< Error + + if (receivedLength == 0) + return 0; + + if (m_isSimulationEnabled) + { + if (m_packetLossProbability(s_randomGenerator)) + continue; + + UInt16 delay = m_packetDelayDistribution(s_randomGenerator); + if (delay > 0) + { + PendingPacket pendingPacket; + pendingPacket.deliveryTime = m_serviceTime + delay; + pendingPacket.from = m_receivedAddress; + pendingPacket.data.Reset(0, m_packetData[0].data(), receivedLength); + + auto it = std::upper_bound(m_pendingPackets.begin(), m_pendingPackets.end(), pendingPacket, [] (const PendingPacket& first, const PendingPacket& second) + { + return first.deliveryTime < second.deliveryTime; + }); + + m_pendingPackets.emplace(it, std::move(pendingPacket)); + continue; + } + } + } m_receivedData = m_packetData[0].data(); m_receivedDataLength = receivedLength; diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index c969dde4b..d0181a01d 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #define ENET_TIME_OVERFLOW 86400000 From b5797dfa12b11a307c55525c64b8abbb5b9c16af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 30 Jan 2017 18:08:21 +0100 Subject: [PATCH 14/48] Network/ENetHost: Move handling to ENetPeer --- include/Nazara/Network/ENetHost.hpp | 13 +- include/Nazara/Network/ENetPeer.hpp | 15 +- src/Nazara/Network/ENetHost.cpp | 473 +--------------------------- src/Nazara/Network/ENetPeer.cpp | 449 +++++++++++++++++++++++++- 4 files changed, 475 insertions(+), 475 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 0dcf58a86..fe9956538 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -68,19 +68,8 @@ namespace Nz bool DispatchIncomingCommands(ENetEvent* event); - bool HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command); - bool HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command); ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); - bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command); bool HandleIncomingCommands(ENetEvent* event); - 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 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 HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command); int ReceiveIncomingCommands(ENetEvent* event); diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index aa3c9f2da..c0d24f6f6 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -77,6 +78,18 @@ namespace Nz void DispatchIncomingReliableCommands(Channel& channel); void DispatchIncomingUnreliableCommands(Channel& channel); + bool HandleAcknowledge(const ENetProtocol* command, ENetEvent* event); + bool HandleBandwidthLimit(const ENetProtocol* command); + bool HandleDisconnect(const ENetProtocol* command); + bool HandlePing(const ENetProtocol* command); + bool HandleSendFragment(const ENetProtocol* command, UInt8** data); + bool HandleSendReliable(const ENetProtocol* command, UInt8** data); + bool HandleSendUnreliable(const ENetProtocol* command, UInt8** data); + bool HandleSendUnreliableFragment(const ENetProtocol* command, UInt8** data); + bool HandleSendUnsequenced(const ENetProtocol* command, UInt8** data); + bool HandleThrottleConfigure(const ENetProtocol* command); + bool HandleVerifyConnect(const ENetProtocol* command, ENetEvent* event); + void OnConnect(); void OnDisconnect(); diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 3587e19d1..4da174baf 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -411,116 +411,6 @@ namespace Nz return false; } - bool ENetHost::HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) - { - if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) - return true; - - UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); - receivedSentTime |= m_serviceTime & 0xFFFF0000; - if ((receivedSentTime & 0x8000) > (m_serviceTime & 0x8000)) - receivedSentTime -= 0x10000; - - if (ENET_TIME_LESS(m_serviceTime, receivedSentTime)) - return true; - - peer->m_lastReceiveTime = m_serviceTime; - peer->m_earliestTimeout = 0; - - UInt32 roundTripTime = ENET_TIME_DIFFERENCE(m_serviceTime, receivedSentTime); - - peer->Throttle(roundTripTime); - - peer->m_roundTripTimeVariance -= peer->m_roundTripTimeVariance / 4; - - if (roundTripTime >= peer->m_roundTripTime) - { - peer->m_roundTripTime += (roundTripTime - peer->m_roundTripTime) / 8; - peer->m_roundTripTimeVariance += (roundTripTime - peer->m_roundTripTime) / 4; - } - else - { - peer->m_roundTripTime -= (peer->m_roundTripTime - roundTripTime) / 8; - peer->m_roundTripTimeVariance += (peer->m_roundTripTime - roundTripTime) / 4; - } - - if (peer->m_roundTripTime < peer->m_lowestRoundTripTime) - peer->m_lowestRoundTripTime = peer->m_roundTripTime; - - if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance) - peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; - - if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->m_packetThrottleInterval) - { - peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime; - peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance; - peer->m_lowestRoundTripTime = peer->m_roundTripTime; - peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; - peer->m_packetThrottleEpoch = m_serviceTime; - } - - UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); - - ENetProtocolCommand commandNumber = peer->RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); - - switch (peer->GetState()) - { - case ENetPeerState::AcknowledgingConnect: - if (commandNumber != ENetProtocolCommand_VerifyConnect) - return false; - - NotifyConnect(peer, event); - break; - - case ENetPeerState::Disconnecting: - if (commandNumber != ENetProtocolCommand_Disconnect) - return false; - - NotifyDisconnect(peer, event); - break; - - case ENetPeerState::DisconnectLater: - if (!peer->HasPendingCommands()) - peer->Disconnect(peer->m_eventData); - - break; - - default: - break; - } - - return true; - } - - bool ENetHost::HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command) - { - if (!peer->IsConnected()) - return false; - - if (peer->m_incomingBandwidth != 0) - --m_bandwidthLimitedPeers; - - peer->m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); - peer->m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); - - if (peer->m_incomingBandwidth != 0) - ++m_bandwidthLimitedPeers; - - if (peer->m_incomingBandwidth == 0 && m_outgoingBandwidth == 0) - peer->m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; - else - { - if (peer->m_incomingBandwidth == 0 || m_outgoingBandwidth == 0) - peer->m_windowSize = (std::max(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; - else - peer->m_windowSize = (std::min(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; - - peer->m_windowSize = Clamp(peer->m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - } - - return true; - } - ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* /*header*/, ENetProtocol* command) { UInt32 channelCount = NetToHost(command->connect.channelCount); @@ -590,37 +480,6 @@ namespace Nz return peer; } - bool ENetHost::HandleDisconnect(ENetPeer* peer, const ENetProtocol * command) - { - if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie || peer->GetState() == ENetPeerState::AcknowledgingDisconnect) - return true; - - peer->ResetQueues(); - - if (peer->GetState() == ENetPeerState::ConnectionSucceeded || peer->GetState() == ENetPeerState::Disconnecting || peer->GetState() == ENetPeerState::Connecting) - peer->DispatchState(ENetPeerState::Zombie); - else - { - if (!peer->IsConnected()) - { - if (peer->GetState() == ENetPeerState::ConnectionPending) - m_recalculateBandwidthLimits = true; - - peer->Reset(); - } - else - if (command->header.command & ENetProtocolFlag_Acknowledge) - peer->ChangeState(ENetPeerState::AcknowledgingDisconnect); - else - peer->DispatchState(ENetPeerState::Zombie); - } - - if (peer->GetState() != ENetPeerState::Disconnected) - peer->m_eventData = NetToHost(command->disconnect.data); - - return true; - } - bool ENetHost::HandleIncomingCommands(ENetEvent* event) { if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) @@ -702,7 +561,7 @@ namespace Nz switch (commandNumber) { case ENetProtocolCommand_Acknowledge: - if (!HandleAcknowledge(event, peer, command)) + if (!peer->HandleAcknowledge(command, event)) return commandError(); break; @@ -718,61 +577,61 @@ namespace Nz break; case ENetProtocolCommand_VerifyConnect: - if (!HandleVerifyConnect(event, peer, command)) + if (!peer->HandleVerifyConnect(command, event)) return commandError(); break; case ENetProtocolCommand_Disconnect: - if (!HandleDisconnect(peer, command)) + if (!peer->HandleDisconnect(command)) return commandError(); break; case ENetProtocolCommand_Ping: - if (!HandlePing(peer, command)) + if (!peer->HandlePing(command)) return commandError(); break; case ENetProtocolCommand_SendReliable: - if (!HandleSendReliable(peer, command, ¤tData)) + if (!peer->HandleSendReliable(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_SendUnreliable: - if (!HandleSendUnreliable(peer, command, ¤tData)) + if (!peer->HandleSendUnreliable(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_SendUnsequenced: - if (!HandleSendUnsequenced(peer, command, ¤tData)) + if (!peer->HandleSendUnsequenced(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_SendFragment: - if (!HandleSendFragment(peer, command, ¤tData)) + if (!peer->HandleSendFragment(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_BandwidthLimit: - if (!HandleBandwidthLimit(peer, command)) + if (!peer->HandleBandwidthLimit(command)) return commandError(); break; case ENetProtocolCommand_ThrottleConfigure: - if (!HandleThrottleConfigure(peer, command)) + if (!peer->HandleThrottleConfigure(command)) return commandError(); break; case ENetProtocolCommand_SendUnreliableFragment: - if (!HandleSendUnreliableFragment(peer, command, ¤tData)) + if (!peer->HandleSendUnreliableFragment(command, ¤tData)) return commandError(); break; @@ -813,314 +672,6 @@ namespace Nz return commandError(); } - bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* /*command*/) - { - if (!peer->IsConnected()) - return false; - - return true; - } - - bool ENetHost::HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - 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.GetSize()) - 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.Test(fragmentNumber)) - { - --startCommand->fragmentsRemaining; - - startCommand->fragments.Set(fragmentNumber, true); - - 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(command) + sizeof(ENetProtocolSendFragment), fragmentLength); - - if (startCommand->fragmentsRemaining <= 0) - peer->DispatchIncomingReliableCommands(channel); - } - - return false; - } - - bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - return false; - - UInt16 dataLength = NetToHost(command->sendReliable.dataLength); - *currentData += dataLength; - if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) - return false; - - if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) - return false; - - return true; - } - - bool ENetHost::HandleSendUnreliable(ENetPeer * peer, const ENetProtocol * command, UInt8 ** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - 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(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->IsConnected()) - 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.GetSize()) - return false; - - startCommand = &incomingCommand; - break; - } - } - - if (startCommand) - { - if (!peer->QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) - return false; - } - - if (!startCommand->fragments.Test(fragmentNumber)) - { - --startCommand->fragmentsRemaining; - - startCommand->fragments.Set(fragmentNumber, true); - - 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(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->IsConnected()) - 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(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(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) - { - if (!peer->IsConnected()) - return false; - - peer->m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); - peer->m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); - peer->m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); - - return true; - } - - bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) - { - if (peer->GetState() != ENetPeerState::Connecting) - return true; - - UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); - - if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || - NetToHost(command->verifyConnect.packetThrottleInterval) != peer->m_packetThrottleInterval || - NetToHost(command->verifyConnect.packetThrottleAcceleration) != peer->m_packetThrottleAcceleration || - NetToHost(command->verifyConnect.packetThrottleDeceleration) != peer->m_packetThrottleDeceleration || - command->verifyConnect.connectID != peer->m_connectID) - { - peer->m_eventData = 0; - - peer->DispatchState(ENetPeerState::Zombie); - - return false; - } - - peer->RemoveSentReliableCommand(1, 0xFF); - - if (channelCount < peer->m_channels.size()) - peer->m_channels.resize(channelCount); - - peer->m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); - peer->m_incomingSessionID = command->verifyConnect.incomingSessionID; - peer->m_outgoingSessionID = command->verifyConnect.outgoingSessionID; - - UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); - peer->m_mtu = std::min(peer->m_mtu, mtu); - - UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - peer->m_windowSize = std::min(peer->m_windowSize, windowSize); - - peer->m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); - peer->m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); - - NotifyConnect(peer, event); - return true; - } - int ENetHost::ReceiveIncomingCommands(ENetEvent* event) { for (unsigned int i = 0; i < 256; ++i) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index d0181a01d..e90d77954 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -469,6 +469,453 @@ namespace Nz channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); } + bool ENetPeer::HandleAcknowledge(const ENetProtocol* command, ENetEvent* event) + { + if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie) + return true; + + UInt32 serviceTime = m_host->m_serviceTime; + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); + receivedSentTime |= serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS(serviceTime, receivedSentTime)) + return true; + + m_lastReceiveTime = serviceTime; + m_earliestTimeout = 0; + + UInt32 roundTripTime = ENET_TIME_DIFFERENCE(serviceTime, receivedSentTime); + + Throttle(roundTripTime); + + m_roundTripTimeVariance -= m_roundTripTimeVariance / 4; + + if (roundTripTime >= m_roundTripTime) + { + m_roundTripTime += (roundTripTime - m_roundTripTime) / 8; + m_roundTripTimeVariance += (roundTripTime - m_roundTripTime) / 4; + } + else + { + m_roundTripTime -= (m_roundTripTime - roundTripTime) / 8; + m_roundTripTimeVariance += (m_roundTripTime - roundTripTime) / 4; + } + + m_lowestRoundTripTime = std::min(m_lowestRoundTripTime, m_roundTripTime); + m_highestRoundTripTimeVariance = std::max(m_highestRoundTripTimeVariance, m_roundTripTimeVariance); + + if (m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) + { + m_lastRoundTripTime = m_lowestRoundTripTime; + m_lastRoundTripTimeVariance = m_highestRoundTripTimeVariance; + m_lowestRoundTripTime = m_roundTripTime; + m_highestRoundTripTimeVariance = m_roundTripTimeVariance; + m_packetThrottleEpoch = serviceTime; + } + + UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); + + ENetProtocolCommand commandNumber = RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); + + switch (m_state) + { + case ENetPeerState::AcknowledgingConnect: + if (commandNumber != ENetProtocolCommand_VerifyConnect) + return false; + + m_host->NotifyConnect(this, event); + break; + + case ENetPeerState::Disconnecting: + if (commandNumber != ENetProtocolCommand_Disconnect) + return false; + + m_host->NotifyDisconnect(this, event); + break; + + case ENetPeerState::DisconnectLater: + if (!HasPendingCommands()) + Disconnect(m_eventData); + + break; + + default: + break; + } + + return true; + } + + bool ENetPeer::HandleBandwidthLimit(const ENetProtocol* command) + { + if (!IsConnected()) + return false; + + if (m_incomingBandwidth != 0) + --m_host->m_bandwidthLimitedPeers; + + m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); + m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); + + if (m_incomingBandwidth != 0) + ++m_host->m_bandwidthLimitedPeers; + + if (m_incomingBandwidth == 0 && m_host->m_outgoingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + { + if (m_incomingBandwidth == 0 || m_host->m_outgoingBandwidth == 0) + m_windowSize = (std::max(m_incomingBandwidth, m_host->m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_incomingBandwidth, m_host->m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + return true; + } + + bool ENetPeer::HandleDisconnect(const ENetProtocol* command) + { + if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie || m_state == ENetPeerState::AcknowledgingDisconnect) + return true; + + ResetQueues(); + + if (m_state == ENetPeerState::ConnectionSucceeded || m_state == ENetPeerState::Disconnecting || m_state == ENetPeerState::Connecting) + DispatchState(ENetPeerState::Zombie); + else + { + if (!IsConnected()) + { + if (m_state == ENetPeerState::ConnectionPending) + m_host->m_recalculateBandwidthLimits = true; + + Reset(); + } + else + if (command->header.command & ENetProtocolFlag_Acknowledge) + ChangeState(ENetPeerState::AcknowledgingDisconnect); + else + DispatchState(ENetPeerState::Zombie); + } + + if (m_state != ENetPeerState::Disconnected) + m_eventData = NetToHost(command->disconnect.data); + + return true; + } + + bool ENetPeer::HandlePing(const ENetProtocol* /*command*/) + { + if (!IsConnected()) + return false; + + return true; + } + + bool ENetPeer::HandleSendFragment(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *data += fragmentLength; + if (fragmentLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = 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_host->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.GetSize()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + ENetProtocol hostCommand = *command; + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + + if (!QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount)) + return false; + } + + if (!startCommand->fragments.Test(fragmentNumber)) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments.Set(fragmentNumber, true); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + + std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + DispatchIncomingReliableCommands(channel); + } + + return false; + } + + bool ENetPeer::HandleSendReliable(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 dataLength = NetToHost(command->sendReliable.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) + return false; + + return true; + } + + bool ENetPeer::HandleSendUnreliable(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0)) + return false; + + return true; + } + + bool ENetPeer::HandleSendUnreliableFragment(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *data += fragmentLength; + if (fragmentLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = 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_host->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.GetSize()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + if (!QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) + return false; + } + + if (!startCommand->fragments.Test(fragmentNumber)) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments.Set(fragmentNumber, true); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + + std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + DispatchIncomingUnreliableCommands(channel); + } + + return true; + } + + bool ENetPeer::HandleSendUnsequenced(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + UInt32 unsequencedGroup = NetToHost(command->sendUnsequenced.unsequencedGroup); + UInt32 index = unsequencedGroup % ENetConstants::ENetPeer_UnsequencedWindowSize; + + if (unsequencedGroup < m_incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= static_cast(m_incomingUnsequencedGroup) + ENetConstants::ENetPeer_UnsequencedWindows * ENetConstants::ENetPeer_UnsequencedWindowSize) + return true; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != m_incomingUnsequencedGroup) + { + m_incomingUnsequencedGroup = unsequencedGroup - index; + + m_unsequencedWindow.fill(0); + } + else if (m_unsequencedWindow[index / 32] & (1 << (index % 32))) + return true; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnsequenced), dataLength, ENetPacketFlag_Unsequenced, 0)) + return false; + + m_unsequencedWindow[index / 32] |= 1 << (index % 32); + + return true; + } + + bool ENetPeer::HandleThrottleConfigure(const ENetProtocol* command) + { + if (!IsConnected()) + return false; + + m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); + + return true; + } + + bool ENetPeer::HandleVerifyConnect(const ENetProtocol* command, ENetEvent* event) + { + if (m_state != ENetPeerState::Connecting) + return true; + + UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); + + if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || + NetToHost(command->verifyConnect.packetThrottleInterval) != m_packetThrottleInterval || + NetToHost(command->verifyConnect.packetThrottleAcceleration) != m_packetThrottleAcceleration || + NetToHost(command->verifyConnect.packetThrottleDeceleration) != m_packetThrottleDeceleration || + command->verifyConnect.connectID != m_connectID) + { + m_eventData = 0; + + DispatchState(ENetPeerState::Zombie); + + return false; + } + + RemoveSentReliableCommand(1, 0xFF); + + if (channelCount < m_channels.size()) + m_channels.resize(channelCount); + + m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); + m_incomingSessionID = command->verifyConnect.incomingSessionID; + m_outgoingSessionID = command->verifyConnect.outgoingSessionID; + + UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + m_mtu = std::min(m_mtu, mtu); + + UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + m_windowSize = std::min(m_windowSize, windowSize); + + m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); + m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); + + m_host->NotifyConnect(this, event); + return true; + } + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) { m_channels.resize(channelCount); From 3ff483d2f6e896e58d877e68b04aab74609b1881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 30 Jan 2017 18:08:38 +0100 Subject: [PATCH 15/48] Network/ENetPeer: Add GetPeerId() --- include/Nazara/Network/ENetPeer.hpp | 1 + include/Nazara/Network/ENetPeer.inl | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index c0d24f6f6..a6a00ba23 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -41,6 +41,7 @@ namespace Nz void DisconnectNow(UInt32 data); inline const IpAddress& GetAddress() const; + inline UInt16 GetPeerId() const; inline ENetPeerState GetState() const; inline bool HasPendingCommands(); diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 1e74e0cae..324a1fb80 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -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" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -13,6 +13,11 @@ namespace Nz return m_address; } + inline UInt16 ENetPeer::GetPeerId() const + { + return m_incomingPeerID; + } + inline ENetPeerState ENetPeer::GetState() const { return m_state; From 4f1df53f075831fcd6154a54964d98559ef38964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 31 Jan 2017 15:31:11 +0100 Subject: [PATCH 16/48] Network/ENetPeer: Fix DisconnectLater not waiting for pending commands --- src/Nazara/Network/ENetPeer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index e90d77954..ae0952be5 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -83,7 +83,7 @@ namespace Nz void ENetPeer::DisconnectLater(UInt32 data) { - if (IsConnected() && !m_outgoingReliableCommands.empty() && !m_outgoingUnreliableCommands.empty() && !m_sentReliableCommands.empty()) + if (IsConnected() && HasPendingCommands()) { m_state = ENetPeerState::DisconnectLater; m_eventData = data; @@ -596,10 +596,12 @@ namespace Nz Reset(); } else + { if (command->header.command & ENetProtocolFlag_Acknowledge) ChangeState(ENetPeerState::AcknowledgingDisconnect); else DispatchState(ENetPeerState::Zombie); + } } if (m_state != ENetPeerState::Disconnected) From 2f057191aadf79265a27917be17dfd1e61127c33 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 31 Jan 2017 22:19:17 +0100 Subject: [PATCH 17/48] Network/ENetHost: Add GetServiceTime() --- include/Nazara/Network/ENetHost.hpp | 2 ++ include/Nazara/Network/ENetHost.inl | 5 +++++ src/Nazara/Network/ENetPeer.cpp | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index fe9956538..97b12f2c0 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -53,6 +53,8 @@ namespace Nz void Flush(); + inline UInt32 GetServiceTime() const; + int Service(ENetEvent* event, UInt32 timeout); void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index c7e65ab95..8aa722771 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -51,6 +51,11 @@ namespace Nz m_peers.clear(); m_socket.Close(); } + + inline UInt32 Nz::ENetHost::GetServiceTime() const + { + return m_serviceTime; + } } #include diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index ae0952be5..6c5940629 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -474,7 +474,8 @@ namespace Nz if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie) return true; - UInt32 serviceTime = m_host->m_serviceTime; + UInt32 serviceTime = m_host->GetServiceTime(); + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); receivedSentTime |= serviceTime & 0xFFFF0000; if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) From 6b8d9deb43907d4c5fcb4b3f69b24afac10500fa Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 31 Jan 2017 23:04:53 +0100 Subject: [PATCH 18/48] Network/ENet: Clean up time functions --- include/Nazara/Network/ENetProtocol.hpp | 10 ++++++++ include/Nazara/Network/ENetProtocol.inl | 34 +++++++++++++++++++++++++ src/Nazara/Network/ENetHost.cpp | 23 +++++------------ src/Nazara/Network/ENetPeer.cpp | 14 +++++----- 4 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 include/Nazara/Network/ENetProtocol.inl diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index 0434cafc2..e3df5e092 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -13,6 +13,14 @@ namespace Nz { + constexpr UInt32 ENetTimeOverflow = 24 * 60 * 60 * 1000; + + inline UInt32 ENetTimeDifference(UInt32 a, UInt32 b); + inline bool ENetTimeLess(UInt32 a, UInt32 b); + inline bool ENetTimeLessEqual(UInt32 a, UInt32 b); + inline bool ENetTimeGreater(UInt32 a, UInt32 b); + inline bool ENetTimeGreaterEqual(UInt32 a, UInt32 b); + class ENetPeer; // Constants for the ENet implementation and protocol @@ -294,4 +302,6 @@ namespace Nz #endif } +#include + #endif // NAZARA_ENETPROTOCOL_HPP diff --git a/include/Nazara/Network/ENetProtocol.inl b/include/Nazara/Network/ENetProtocol.inl new file mode 100644 index 000000000..b854f26c8 --- /dev/null +++ b/include/Nazara/Network/ENetProtocol.inl @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + UInt32 ENetTimeDifference(UInt32 a, UInt32 b) + { + return (ENetTimeLess(a, b)) ? b - a : a - b; + } + + bool ENetTimeLess(UInt32 a, UInt32 b) + { + return (a - b >= ENetTimeOverflow); + } + + bool ENetTimeLessEqual(UInt32 a, UInt32 b) + { + return !ENetTimeGreater(a, b); + } + + bool ENetTimeGreater(UInt32 a, UInt32 b) + { + return ENetTimeLess(b, a); + } + + bool ENetTimeGreaterEqual(UInt32 a, UInt32 b) + { + return !ENetTimeLess(a, b); + } +} diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 4da174baf..360142c37 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -6,15 +6,6 @@ #include #include -#define ENET_TIME_OVERFLOW 86400000 - -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) - -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - namespace Nz { /// Temporary @@ -235,7 +226,7 @@ namespace Nz do { - if (ENET_TIME_DIFFERENCE(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) + if (ENetTimeDifference(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) ThrottleBandwidth(); switch (SendOutgoingCommands(event, true)) @@ -291,17 +282,17 @@ namespace Nz return 1; } - if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + if (ENetTimeGreaterEqual(m_serviceTime, timeout)) return 0; for (;;) { m_serviceTime = GetElapsedMilliseconds(); - if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + if (ENetTimeGreaterEqual(m_serviceTime, timeout)) return 0; - if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime))) + if (m_poller.Wait(ENetTimeDifference(timeout, m_serviceTime))) break; } @@ -962,7 +953,7 @@ namespace Nz if (!currentPeer->m_acknowledgements.empty()) SendAcknowledgements(currentPeer); - if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) + if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENetTimeGreaterEqual(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) { if (event && event->type != ENetEventType::None) return 1; @@ -971,7 +962,7 @@ namespace Nz } 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)) + ENetTimeDifference(m_serviceTime, currentPeer->m_lastReceiveTime) >= currentPeer->m_pingInterval && currentPeer->m_mtu - m_packetSize >= sizeof(ENetProtocolPing)) { currentPeer->Ping(); SendReliableOutgoingCommands(currentPeer); @@ -985,7 +976,7 @@ namespace Nz 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) + else if (ENetTimeDifference(m_serviceTime, currentPeer->m_packetLossEpoch) >= ENetPeer_PacketLossInterval && currentPeer->m_packetsSent > 0) { UInt32 packetLoss = currentPeer->m_packetsLost * ENetPeer_PacketLossScale / currentPeer->m_packetsSent; diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6c5940629..33c7fc465 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -319,14 +319,14 @@ namespace Nz ++currentCommand; - if (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + if (ENetTimeDifference(serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) continue; - if (m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, m_earliestTimeout)) + if (m_earliestTimeout == 0 || ENetTimeLess(outgoingCommand->sentTime, m_earliestTimeout)) m_earliestTimeout = outgoingCommand->sentTime; - if (m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMaximum || - (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + if (m_earliestTimeout != 0 && (ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMaximum || + (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) { m_host->NotifyDisconnect(this, event); return true; @@ -481,13 +481,13 @@ namespace Nz if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) receivedSentTime -= 0x10000; - if (ENET_TIME_LESS(serviceTime, receivedSentTime)) + if (ENetTimeLess(serviceTime, receivedSentTime)) return true; m_lastReceiveTime = serviceTime; m_earliestTimeout = 0; - UInt32 roundTripTime = ENET_TIME_DIFFERENCE(serviceTime, receivedSentTime); + UInt32 roundTripTime = ENetTimeDifference(serviceTime, receivedSentTime); Throttle(roundTripTime); @@ -507,7 +507,7 @@ namespace Nz m_lowestRoundTripTime = std::min(m_lowestRoundTripTime, m_roundTripTime); m_highestRoundTripTimeVariance = std::max(m_highestRoundTripTimeVariance, m_roundTripTimeVariance); - if (m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) + if (m_packetThrottleEpoch == 0 || ENetTimeDifference(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) { m_lastRoundTripTime = m_lowestRoundTripTime; m_lastRoundTripTimeVariance = m_highestRoundTripTimeVariance; From 85257da07e80da568c89b65af4bc09a0d90005f3 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 31 Jan 2017 23:05:18 +0100 Subject: [PATCH 19/48] Network/ENet: Fix some warnings --- include/Nazara/Network/ENetHost.hpp | 4 ++-- src/Nazara/Network/ENetHost.cpp | 4 ++-- src/Nazara/Network/ENetPeer.cpp | 23 +++++++---------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 97b12f2c0..376e03002 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -128,10 +128,10 @@ namespace Nz UInt32 m_incomingBandwidth; UInt32 m_outgoingBandwidth; UInt32 m_serviceTime; - UInt32 m_totalSentData; UInt32 m_totalSentPackets; - UInt32 m_totalReceivedData; UInt32 m_totalReceivedPackets; + UInt64 m_totalSentData; + UInt64 m_totalReceivedData; bool m_continueSending; bool m_isSimulationEnabled; bool m_recalculateBandwidthLimits; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 360142c37..0b73a1491 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -440,7 +440,7 @@ namespace Nz if (!peer || duplicatePeers >= m_duplicatePeers) return nullptr; - channelCount = std::min(channelCount, m_channelLimit); + channelCount = std::min(channelCount, UInt32(m_channelLimit)); peer->InitIncoming(channelCount, m_receivedAddress, command->connect); @@ -514,7 +514,7 @@ namespace Nz if (peer) { peer->m_address = m_receivedAddress; - peer->m_incomingDataTotal += m_receivedDataLength; + peer->m_incomingDataTotal += UInt32(m_receivedDataLength); } auto commandError = [&]() -> bool diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 33c7fc465..a3946e56e 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -4,15 +4,6 @@ #include #include -#define ENET_TIME_OVERFLOW 86400000 - -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) - -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - namespace Nz { /// Temporary @@ -216,9 +207,7 @@ namespace Nz Channel& channel = m_channels[channelId]; - std::size_t fragmentLength = m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment); - //if (m_host->m_checksum != nullptr) - // fragmentLength -= sizeof(UInt32); + UInt16 fragmentLength = static_cast(m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment)); UInt32 packetSize = static_cast(packetRef->data.GetDataSize()); if (packetSize > fragmentLength) @@ -252,11 +241,11 @@ namespace Nz fragmentOffset += fragmentLength) { if (packetSize - fragmentOffset < fragmentLength) - fragmentLength = packetSize - fragmentOffset; + fragmentLength = UInt16(packetSize - fragmentOffset); OutgoingCommand outgoingCommand; outgoingCommand.fragmentOffset = fragmentOffset; - outgoingCommand.fragmentLength = static_cast(fragmentLength); + outgoingCommand.fragmentLength = fragmentLength; outgoingCommand.packet = packetRef; outgoingCommand.command.header.command = commandNumber; outgoingCommand.command.header.channelID = channelId; @@ -312,6 +301,8 @@ namespace Nz bool ENetPeer::CheckTimeouts(ENetEvent* event) { + UInt32 serviceTime = m_host->GetServiceTime(); + auto currentCommand = m_sentReliableCommands.begin(); while (currentCommand != m_sentReliableCommands.end()) { @@ -816,7 +807,7 @@ namespace Nz startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) - fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + fragmentLength = static_cast(startCommand->packet->data.GetDataSize() - fragmentOffset); std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); @@ -1285,7 +1276,7 @@ namespace Nz void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand) { - m_outgoingDataTotal += ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength; + m_outgoingDataTotal += static_cast(ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength); if (outgoingCommand.command.header.channelID == 0xFF) { From a087174bf8d6e79b21b4eee36eaa2d015ede121a Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 1 Feb 2017 00:13:08 +0100 Subject: [PATCH 20/48] Network/Algorithm: Add HostToNet and NetToHost --- include/Nazara/Network/Algorithm.hpp | 7 +++++++ include/Nazara/Network/Algorithm.inl | 25 +++++++++++++++++++++++++ src/Nazara/Network/ENetHost.cpp | 24 +----------------------- src/Nazara/Network/ENetPeer.cpp | 26 ++------------------------ 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/include/Nazara/Network/Algorithm.hpp b/include/Nazara/Network/Algorithm.hpp index 001d98059..f2d99b605 100644 --- a/include/Nazara/Network/Algorithm.hpp +++ b/include/Nazara/Network/Algorithm.hpp @@ -11,10 +11,17 @@ #include #include #include +#include namespace Nz { NAZARA_NETWORK_API bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port = nullptr, bool* isIPv6 = nullptr, const char** endOfRead = nullptr); + + template + std::enable_if_t::value, T> HostToNet(T value); + + template + std::enable_if_t::value, T> NetToHost(T value); } #include diff --git a/include/Nazara/Network/Algorithm.inl b/include/Nazara/Network/Algorithm.inl index 5364298d4..4cba24136 100644 --- a/include/Nazara/Network/Algorithm.inl +++ b/include/Nazara/Network/Algorithm.inl @@ -2,6 +2,31 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include +#include #include +namespace Nz +{ + template + std::enable_if_t::value, T> HostToNet(T value) + { +#ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); +#else + return value; +#endif + } + + template + std::enable_if_t::value, T> NetToHost(T value) + { +#ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); +#else + return value; +#endif + } +} + #include diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 0b73a1491..0461b1053 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,35 +1,13 @@ #include #include -#include #include +#include #include #include #include namespace Nz { - /// Temporary - template - T HostToNet(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - - /// Temporary - template - T NetToHost(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - namespace { static std::size_t s_commandSizes[ENetProtocolCommand_Count] = diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index a3946e56e..152f1b4ef 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,33 +1,11 @@ #include -#include +#include #include #include #include namespace Nz { - /// Temporary - template - T HostToNet(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - - /// Temporary - template - T NetToHost(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : m_host(host), m_packetPool(sizeof(ENetPacket)), @@ -683,7 +661,7 @@ namespace Nz startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) - fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + fragmentLength = static_cast(startCommand->packet->data.GetDataSize() - fragmentOffset); std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); From 7b8100dafe2577a878357ad00ed72271976bb66e Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 1 Feb 2017 00:20:22 +0100 Subject: [PATCH 21/48] Network/ENet: Add ENet licence --- include/Nazara/Network/ENetHost.hpp | 12 +++++++++++- include/Nazara/Network/ENetPeer.hpp | 12 +++++++++++- src/Nazara/Network/ENetHost.cpp | 16 +++++++++++++++- src/Nazara/Network/ENetPacket.cpp | 4 ++++ src/Nazara/Network/ENetPeer.cpp | 16 +++++++++++++++- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 376e03002..06d8259c5 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -1,4 +1,14 @@ -// Copyright (C) 2017 Jérôme Leclercq +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index a6a00ba23..4c4248ad8 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -1,4 +1,14 @@ -// Copyright (C) 2017 Jérôme Leclercq +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 0461b1053..3659139ac 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,4 +1,18 @@ -#include +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include #include #include #include diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp index 494ae1a54..4b4157ac4 100644 --- a/src/Nazara/Network/ENetPacket.cpp +++ b/src/Nazara/Network/ENetPacket.cpp @@ -1,3 +1,7 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + #include #include #include diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 152f1b4ef..88b5568ff 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,4 +1,18 @@ -#include +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include #include #include #include From 0f2d315c1d127be6f2f1e698ef77006e61d5dedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 1 Feb 2017 17:51:41 +0100 Subject: [PATCH 22/48] Network/ENet: Fix header dependency --- include/Nazara/Network/ENetHost.hpp | 6 ++---- include/Nazara/Network/ENetPeer.hpp | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 06d8259c5..83e8fd147 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,8 +36,6 @@ namespace Nz { - class ENetPeer; - class NAZARA_NETWORK_API ENetHost { friend ENetPeer; @@ -153,4 +151,4 @@ namespace Nz #include -#endif // NAZARA_RUDPSERVER_HPP +#endif // NAZARA_ENETHOST_HPP diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 4c4248ad8..e2b76c54a 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include From 41d06fed38bccae3183dd720ba4d343dec6ca3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 1 Feb 2017 17:52:01 +0100 Subject: [PATCH 23/48] Network/ENetHost: Fix packet leak when broadcasting with no peer connected --- src/Nazara/Network/ENetHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 3659139ac..aff71c9c3 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -45,7 +45,7 @@ namespace Nz void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - ENetPacket* enetPacket = m_packetPool.New(); + ENetPacketRef enetPacket = m_packetPool.New(); enetPacket->flags = flags; enetPacket->data = std::move(packet); enetPacket->owner = &m_packetPool; From 414779b53c2f582b6307b3f9f8ac43917fdd4494 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 12 Feb 2017 02:18:38 +0100 Subject: [PATCH 24/48] Network/ENetPacket: Remove unused flags --- include/Nazara/Network/ENetPacket.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp index 54a5d4676..5aecb0edd 100644 --- a/include/Nazara/Network/ENetPacket.hpp +++ b/include/Nazara/Network/ENetPacket.hpp @@ -14,18 +14,16 @@ namespace Nz { enum ENetPacketFlag { - ENetPacketFlag_NoAllocate, ENetPacketFlag_Reliable, ENetPacketFlag_Unsequenced, - ENetPacketFlag_UnreliableFragment, - ENetPacketFlag_Sent + ENetPacketFlag_UnreliableFragment }; template<> struct EnumAsFlags { static constexpr bool value = true; - static constexpr int max = ENetPacketFlag_Sent; + static constexpr int max = ENetPacketFlag_UnreliableFragment; }; using ENetPacketFlags = Flags; From 5655ff3fcf51de82a2cb8c9d984aed4d2956cd7a Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 12 Feb 2017 02:19:27 +0100 Subject: [PATCH 25/48] Network/ENetPacketFlags: Add Unreliable flag typedef for zero --- include/Nazara/Network/ENetPacket.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp index 5aecb0edd..54b0c42c6 100644 --- a/include/Nazara/Network/ENetPacket.hpp +++ b/include/Nazara/Network/ENetPacket.hpp @@ -28,6 +28,8 @@ namespace Nz using ENetPacketFlags = Flags; + constexpr ENetPacketFlags ENetPacketFlag_Unreliable = 0; + class MemoryPool; struct ENetPacket From 1904ce1576d914e1f265eb575c8a8d7b5ad9fb16 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 12 Feb 2017 02:21:00 +0100 Subject: [PATCH 26/48] Network/ENetPeer: Fix fragmented packet handling --- src/Nazara/Network/ENetPeer.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 88b5568ff..6f0824af6 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -205,32 +205,24 @@ namespace Nz if (packetSize > fragmentLength) { UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; - UInt32 fragmentNumber; - UInt32 fragmentOffset; - - UInt8 commandNumber; - UInt16 startSequenceNumber; - if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount) return false; + UInt8 commandNumber; + UInt16 startSequenceNumber; if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_UnreliableFragment)) == ENetPacketFlag_UnreliableFragment && channel.outgoingUnreliableSequenceNumber < 0xFFFF) { commandNumber = ENetProtocolCommand_SendUnreliable; - startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); + startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); } else { commandNumber = ENetProtocolCommand_SendFragment | ENetProtocolFlag_Acknowledge; - startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); + startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); } - for (fragmentNumber = 0, - fragmentOffset = 0; - fragmentOffset < packetSize; - ++fragmentNumber, - fragmentOffset += fragmentLength) + for (UInt32 fragmentNumber = 0, fragmentOffset = 0; fragmentOffset < packetSize; ++fragmentNumber, fragmentOffset += fragmentLength) { if (packetSize - fragmentOffset < fragmentLength) fragmentLength = UInt16(packetSize - fragmentOffset); From 890b06bfcb796feb8bd8935a7f07fda205731c7a Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 15 Feb 2017 08:26:56 +0100 Subject: [PATCH 27/48] Network/ENet: Refactor --- include/Nazara/Network/ENetPeer.hpp | 4 ++++ include/Nazara/Network/ENetPeer.inl | 20 ++++++++++++++++++++ src/Nazara/Network/ENetHost.cpp | 28 +++++++++++++++------------- src/Nazara/Network/ENetPeer.cpp | 2 +- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index e2b76c54a..2d11f17a0 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -50,6 +50,10 @@ namespace Nz void DisconnectNow(UInt32 data); inline const IpAddress& GetAddress() const; + inline UInt32 GetMtu() const; + inline UInt32 GetPacketThrottleAcceleration() const; + inline UInt32 GetPacketThrottleDeceleration() const; + inline UInt32 GetPacketThrottleInterval() const; inline UInt16 GetPeerId() const; inline ENetPeerState GetState() const; diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 324a1fb80..fdac3ab4d 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -13,6 +13,26 @@ namespace Nz return m_address; } + inline UInt32 ENetPeer::GetMtu() const + { + return m_mtu; + } + + inline UInt32 ENetPeer::GetPacketThrottleAcceleration() const + { + return m_packetThrottleAcceleration; + } + + inline UInt32 ENetPeer::GetPacketThrottleDeceleration() const + { + return m_packetThrottleDeceleration; + } + + inline UInt32 ENetPeer::GetPacketThrottleInterval() const + { + return m_packetThrottleInterval; + } + inline UInt16 ENetPeer::GetPeerId() const { return m_incomingPeerID; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index aff71c9c3..c4223653c 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -335,12 +335,12 @@ namespace Nz void ENetHost::AddToDispatchQueue(ENetPeer* peer) { - m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID); + m_dispatchQueue.UnboundedSet(peer->GetPeerId()); } void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer) { - m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID); + m_dispatchQueue.UnboundedReset(peer->GetPeerId()); } bool ENetHost::DispatchIncomingCommands(ENetEvent* event) @@ -446,18 +446,20 @@ namespace Nz windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); ENetProtocol verifyCommand(ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge, 0xFF); - verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->m_incomingPeerID); + verifyCommand.verifyConnect.connectID = peer->m_connectID; verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; - verifyCommand.verifyConnect.mtu = HostToNet(peer->m_mtu); - verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + verifyCommand.verifyConnect.channelCount = HostToNet(channelCount); verifyCommand.verifyConnect.incomingBandwidth = HostToNet(m_incomingBandwidth); + verifyCommand.verifyConnect.mtu = HostToNet(peer->GetMtu()); verifyCommand.verifyConnect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); - verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->m_packetThrottleInterval); - verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->m_packetThrottleAcceleration); - verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->m_packetThrottleDeceleration); - verifyCommand.verifyConnect.connectID = peer->m_connectID; + verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->GetPeerId()); + verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->GetPacketThrottleAcceleration()); + verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->GetPacketThrottleDeceleration()); + verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->GetPacketThrottleInterval()); + verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + peer->QueueOutgoingCommand(verifyCommand); return peer; @@ -475,7 +477,7 @@ namespace Nz UInt16 flags = peerID & ENetProtocolHeaderFlag_Mask; peerID &= ~(ENetProtocolHeaderFlag_Mask | ENetProtocolHeaderSessionMask); - std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); + std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime) ? sizeof(ENetProtocolHeader) : NazaraOffsetOf(ENetProtocolHeader, sentTime); ENetPeer* peer; if (peerID == ENetConstants::ENetProtocol_MaximumPeerId) @@ -491,7 +493,7 @@ namespace Nz if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) return false; - if (m_receivedAddress != peer->m_address && peer->m_address != IpAddress::BroadcastIpV4) + if (m_receivedAddress != peer->GetAddress() && peer->GetAddress() != IpAddress::BroadcastIpV4) return false; if (peer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId && sessionID != peer->m_incomingSessionID) @@ -771,7 +773,7 @@ namespace Nz 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)) + if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->GetMtu() - m_packetSize < sizeof(ENetProtocolAcknowledge)) { m_continueSending = true; break; @@ -1013,7 +1015,7 @@ namespace Nz currentPeer->m_lastSendTime = m_serviceTime; std::size_t sentLength; - if (!m_socket.SendMultiple(currentPeer->m_address, m_buffers.data(), m_bufferCount, &sentLength)) + if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) return -1; currentPeer->RemoveSentUnreliableCommands(); diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6f0824af6..0408e6c50 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -845,7 +845,7 @@ namespace Nz if (!IsConnected()) return false; - m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); From 8225ad3b41708724bbfbce62a62943698e6e8c75 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 15 Feb 2017 08:27:15 +0100 Subject: [PATCH 28/48] Network/ENetHost: Optimize acknowledgements handling --- include/Nazara/Network/ENetPeer.hpp | 2 +- src/Nazara/Network/ENetHost.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 2d11f17a0..a9f2a0219 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -178,13 +178,13 @@ namespace Nz ENetHost* m_host; IpAddress m_address; /**< Internet address of the peer */ std::array m_unsequencedWindow; - std::list m_acknowledgements; std::list m_dispatchedCommands; std::list m_outgoingReliableCommands; std::list m_outgoingUnreliableCommands; std::list m_sentReliableCommands; std::list m_sentUnreliableCommands; std::size_t m_totalWaitingData; + std::vector m_acknowledgements; std::vector m_channels; MemoryPool m_packetPool; ENetPeerState m_state; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index c4223653c..6f6c740ad 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -770,8 +770,8 @@ namespace Nz void ENetHost::SendAcknowledgements(ENetPeer* peer) { - auto currentAcknowledgement = peer->m_acknowledgements.begin(); - while (currentAcknowledgement != peer->m_acknowledgements.end()) + auto it = peer->m_acknowledgements.begin(); + for (; it != peer->m_acknowledgements.end(); ++it) { if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->GetMtu() - m_packetSize < sizeof(ENetProtocolAcknowledge)) { @@ -779,7 +779,7 @@ namespace Nz break; } - ENetPeer::Acknowledgement& acknowledgement = *currentAcknowledgement; + ENetPeer::Acknowledgement& acknowledgement = *it; ENetProtocol& command = m_commands[m_commandCount]; NetBuffer& buffer = m_buffers[m_bufferCount]; @@ -800,11 +800,11 @@ namespace Nz if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) peer->DispatchState(ENetPeerState::Zombie); - currentAcknowledgement = peer->m_acknowledgements.erase(currentAcknowledgement); - ++m_bufferCount; ++m_commandCount; } + + peer->m_acknowledgements.erase(peer->m_acknowledgements.begin(), it); } bool ENetHost::SendReliableOutgoingCommands(ENetPeer* peer) From dee5986de5af8d1d31e3db897ed7dcd0e5e3d103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 16 Feb 2017 16:14:24 +0100 Subject: [PATCH 29/48] Network/NetPacket: Allow empty pointer for NetPacket creating (won't initialize memory) --- include/Nazara/Network/NetPacket.inl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Network/NetPacket.inl b/include/Nazara/Network/NetPacket.inl index 6d55831d4..eb68d1e53 100644 --- a/include/Nazara/Network/NetPacket.inl +++ b/include/Nazara/Network/NetPacket.inl @@ -155,7 +155,9 @@ namespace Nz { InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); m_buffer->Resize(HeaderSize + size); - std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); + + if (ptr) + std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); m_netCode = netCode; } From 7b49b3dd0e342db9ac6e6b092779d70bbe09d57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 16 Feb 2017 16:14:40 +0100 Subject: [PATCH 30/48] Network/ENetPeer: Fix crash when handling fragment packets --- src/Nazara/Network/ENetPeer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6f0824af6..c343e7913 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -651,12 +651,13 @@ namespace Nz } } - if (startCommand) + if (!startCommand) { ENetProtocol hostCommand = *command; hostCommand.header.reliableSequenceNumber = startSequenceNumber; - if (!QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount)) + startCommand = QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount); + if (!startCommand) return false; } From b7ee6d7b29e7466ce012523d70bf63164c8de55c Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 16 Feb 2017 23:26:00 +0100 Subject: [PATCH 31/48] Network/ENet: Move all packet allocation to host --- include/Nazara/Network/ENetHost.hpp | 3 +++ include/Nazara/Network/ENetHost.inl | 8 ++++++++ include/Nazara/Network/ENetPeer.hpp | 4 +--- include/Nazara/Network/ENetPeer.inl | 9 +++++++++ src/Nazara/Network/ENetHost.cpp | 21 ++++++++++++++------- src/Nazara/Network/ENetPeer.cpp | 21 ++------------------- 6 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 83e8fd147..b1304ab81 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -71,6 +71,9 @@ namespace Nz ENetHost& operator=(ENetHost&&) = default; private: + ENetPacketRef AllocatePacket(ENetPacketFlags flags); + inline ENetPacketRef AllocatePacket(ENetPacketFlags flags, NetPacket&& data); + bool InitSocket(const IpAddress& address); void AddToDispatchQueue(ENetPeer* peer); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index 8aa722771..9a70d9b78 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -56,6 +56,14 @@ namespace Nz { return m_serviceTime; } + + inline ENetPacketRef ENetHost::AllocatePacket(ENetPacketFlags flags, NetPacket&& data) + { + ENetPacketRef ref = AllocatePacket(flags); + ref->data = std::move(data); + + return ref; + } } #include diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index a9f2a0219..19144c2f2 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,7 @@ namespace Nz friend struct PacketRef; public: - ENetPeer(ENetHost* host, UInt16 peerId); + inline ENetPeer(ENetHost* host, UInt16 peerId); ENetPeer(const ENetPeer&) = delete; ENetPeer(ENetPeer&&) = default; ~ENetPeer() = default; @@ -186,7 +185,6 @@ namespace Nz std::size_t m_totalWaitingData; std::vector m_acknowledgements; std::vector m_channels; - MemoryPool m_packetPool; ENetPeerState m_state; UInt8 m_incomingSessionID; UInt8 m_outgoingSessionID; diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index fdac3ab4d..e9c15fe35 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -8,6 +8,15 @@ namespace Nz { + inline ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : + m_host(host), + m_incomingSessionID(0xFF), + m_outgoingSessionID(0xFF), + m_incomingPeerID(peerId) + { + Reset(); + } + inline const IpAddress& ENetPeer::GetAddress() const { return m_address; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 6f6c740ad..76c81eb38 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -45,10 +45,7 @@ namespace Nz void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - ENetPacketRef enetPacket = m_packetPool.New(); - enetPacket->flags = flags; - enetPacket->data = std::move(packet); - enetPacket->owner = &m_packetPool; + ENetPacketRef enetPacket = AllocatePacket(flags, std::move(packet)); for (ENetPeer& peer : m_peers) { @@ -309,6 +306,15 @@ namespace Nz } } + ENetPacketRef ENetHost::AllocatePacket(ENetPacketFlags flags) + { + ENetPacketRef enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->owner = &m_packetPool; + + return enetPacket; + } + bool ENetHost::InitSocket(const IpAddress& address) { if (!m_socket.Create(address.GetProtocol())) @@ -841,7 +847,7 @@ namespace Nz { UInt32 windowSize = (peer->m_packetThrottle * peer->m_windowSize) / ENetPeer_PacketThrottleScale; - if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->m_mtu)) + if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->GetMtu())) windowExceeded = true; } @@ -855,8 +861,8 @@ namespace Nz 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))) + if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->GetMtu() - m_packetSize < commandSize || + (outgoingCommand->packet && UInt16(peer->GetMtu() - m_packetSize) < UInt16(commandSize + outgoingCommand->fragmentLength))) { m_continueSending = true; break; @@ -1092,6 +1098,7 @@ namespace Nz m_packetSize += packetBuffer.dataLength; + // In order to keep the packet buffer alive until we send it, place it into a temporary queue peer->m_sentUnreliableCommands.emplace_back(std::move(*outgoingCommand)); } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 0408e6c50..3bdfb7537 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -20,16 +20,6 @@ namespace Nz { - ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : - m_host(host), - m_packetPool(sizeof(ENetPacket)), - m_incomingSessionID(0xFF), - m_outgoingSessionID(0xFF), - m_incomingPeerID(peerId) - { - Reset(); - } - void ENetPeer::Disconnect(UInt32 data) { if (m_state == ENetPeerState::Disconnecting || @@ -184,12 +174,7 @@ namespace Nz bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - ENetPacket* enetPacket = m_packetPool.New(); - enetPacket->flags = flags; - enetPacket->data = std::move(packet); - enetPacket->owner = &m_packetPool; - - return Send(channelId, enetPacket); + return Send(channelId, m_host->AllocatePacket(flags, std::move(packet)); } bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) @@ -1214,10 +1199,8 @@ namespace Nz if (m_totalWaitingData >= m_host->m_maximumWaitingData) return nullptr; - ENetPacket* packet = m_packetPool.New(); - packet->flags = flags; + ENetPacketRef packet = m_host->AllocatePacket(flags); packet->data.Reset(0, data, dataLength); - packet->owner = &m_packetPool; IncomingCommmand incomingCommand; incomingCommand.reliableSequenceNumber = command.header.reliableSequenceNumber; From e0dca1b043a8af9d08248456877205936a2178e7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 16 Feb 2017 23:26:28 +0100 Subject: [PATCH 32/48] Network/ENetPeer: Optimize CheckTimeouts function --- src/Nazara/Network/ENetPeer.cpp | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 3bdfb7537..d9ca262cb 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -271,39 +271,38 @@ namespace Nz bool ENetPeer::CheckTimeouts(ENetEvent* event) { UInt32 serviceTime = m_host->GetServiceTime(); + bool timedOut = false; - auto currentCommand = m_sentReliableCommands.begin(); - while (currentCommand != m_sentReliableCommands.end()) + auto it = m_sentReliableCommands.begin(); + for (; it != m_sentReliableCommands.end(); ++it) { - auto outgoingCommand = currentCommand; + OutgoingCommand& command = *it; - ++currentCommand; - - if (ENetTimeDifference(serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + if (ENetTimeDifference(serviceTime, command.sentTime) < command.roundTripTimeout) continue; - if (m_earliestTimeout == 0 || ENetTimeLess(outgoingCommand->sentTime, m_earliestTimeout)) - m_earliestTimeout = outgoingCommand->sentTime; + if (m_earliestTimeout == 0 || ENetTimeLess(command.sentTime, m_earliestTimeout)) + m_earliestTimeout = command.sentTime; if (m_earliestTimeout != 0 && (ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMaximum || - (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + (command.roundTripTimeout >= command.roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) { m_host->NotifyDisconnect(this, event); - return true; + timedOut = true; + break; } - if (outgoingCommand->packet) - m_reliableDataInTransit -= outgoingCommand->fragmentLength; + if (command.packet) + m_reliableDataInTransit -= command.fragmentLength; ++m_packetsLost; ++m_totalPacketLost; // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html - outgoingCommand->roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; - outgoingCommand->roundTripTimeoutLimit = m_timeoutLimit * outgoingCommand->roundTripTimeout; + command.roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; + command.roundTripTimeoutLimit = m_timeoutLimit * command.roundTripTimeout; - m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); - m_sentReliableCommands.erase(outgoingCommand); + m_outgoingReliableCommands.emplace_front(std::move(command)); // Okay this should just never procs, I don't see how it would be possible /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && @@ -315,7 +314,9 @@ namespace Nz }*/ } - return false; + m_sentReliableCommands.erase(m_sentReliableCommands.begin(), it); + + return timedOut; } void ENetPeer::DispatchState(ENetPeerState state) From 490f6becb21446bcfc9732c5727409d30a7f6511 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 16 Feb 2017 23:37:28 +0100 Subject: [PATCH 33/48] Fix compilation... That parenthesis probably didn't make it to GitHub, damn you packet losses! --- src/Nazara/Network/ENetPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 94e223ae9..9e7b3802d 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -174,7 +174,7 @@ namespace Nz bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - return Send(channelId, m_host->AllocatePacket(flags, std::move(packet)); + return Send(channelId, m_host->AllocatePacket(flags, std::move(packet))); } bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) From cc57fed42e0d4605c50f46a96de778d60db9a64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 17 Feb 2017 17:30:27 +0100 Subject: [PATCH 34/48] Network/ENetPeer: Fix crash --- src/Nazara/Network/ENetPeer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 9e7b3802d..e7a39e3e5 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -271,7 +271,6 @@ namespace Nz bool ENetPeer::CheckTimeouts(ENetEvent* event) { UInt32 serviceTime = m_host->GetServiceTime(); - bool timedOut = false; auto it = m_sentReliableCommands.begin(); for (; it != m_sentReliableCommands.end(); ++it) @@ -288,8 +287,7 @@ namespace Nz (command.roundTripTimeout >= command.roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) { m_host->NotifyDisconnect(this, event); - timedOut = true; - break; + return true; } if (command.packet) @@ -316,7 +314,7 @@ namespace Nz m_sentReliableCommands.erase(m_sentReliableCommands.begin(), it); - return timedOut; + return false; } void ENetPeer::DispatchState(ENetPeerState state) From b0d0a63fcac4b3d67bd2f16a7dc25dc3754899da Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 20 Feb 2017 23:37:31 +0100 Subject: [PATCH 35/48] Network/ENet: Add peer-side lag simulation --- include/Nazara/Network/ENetHost.hpp | 12 +++- include/Nazara/Network/ENetPeer.hpp | 7 +++ include/Nazara/Network/ENetPeer.inl | 8 ++- include/Nazara/Network/ENetProtocol.hpp | 2 +- src/Nazara/Network/ENetHost.cpp | 75 +++++++++++++++++++++---- src/Nazara/Network/ENetPeer.cpp | 14 +++++ 6 files changed, 104 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index b1304ab81..edb9155ab 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -100,13 +100,20 @@ namespace Nz static bool Initialize(); static void Uninitialize(); - struct PendingPacket + struct PendingIncomingPacket { IpAddress from; NetPacket data; UInt32 deliveryTime; }; + struct PendingOutgoingPacket + { + IpAddress to; + NetPacket data; + UInt32 deliveryTime; + }; + std::array m_commands; std::array m_buffers; std::array m_packetData[2]; @@ -123,7 +130,8 @@ namespace Nz std::size_t m_receivedDataLength; std::uniform_int_distribution m_packetDelayDistribution; std::vector m_peers; - std::vector m_pendingPackets; + std::vector m_pendingIncomingPackets; + std::vector m_pendingOutgoingPackets; UInt8* m_receivedData; Bitset m_dispatchQueue; MemoryPool m_packetPool; diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 19144c2f2..e3538e6fb 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace Nz @@ -59,6 +60,7 @@ namespace Nz inline bool HasPendingCommands(); inline bool IsConnected() const; + inline bool IsSimulationEnabled() const; void Ping(); @@ -68,6 +70,8 @@ namespace Nz bool Send(UInt8 channelId, ENetPacketRef packetRef); bool Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); + void ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration); ENetPeer& operator=(const ENetPeer&) = delete; @@ -177,12 +181,14 @@ namespace Nz ENetHost* m_host; IpAddress m_address; /**< Internet address of the peer */ std::array m_unsequencedWindow; + std::bernoulli_distribution m_packetLossProbability; std::list m_dispatchedCommands; std::list m_outgoingReliableCommands; std::list m_outgoingUnreliableCommands; std::list m_sentReliableCommands; std::list m_sentUnreliableCommands; std::size_t m_totalWaitingData; + std::uniform_int_distribution m_packetDelayDistribution; std::vector m_acknowledgements; std::vector m_channels; ENetPeerState m_state; @@ -232,6 +238,7 @@ namespace Nz UInt32 m_windowSize; UInt64 m_totalPacketLost; UInt64 m_totalPacketSent; + bool m_isSimulationEnabled; }; } diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index e9c15fe35..bcec4a8c1 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -12,7 +12,8 @@ namespace Nz m_host(host), m_incomingSessionID(0xFF), m_outgoingSessionID(0xFF), - m_incomingPeerID(peerId) + m_incomingPeerID(peerId), + m_isSimulationEnabled(false) { Reset(); } @@ -62,6 +63,11 @@ namespace Nz return m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater; } + inline bool ENetPeer::IsSimulationEnabled() const + { + return m_isSimulationEnabled; + } + inline void ENetPeer::ChangeState(ENetPeerState state) { if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index e3df5e092..7cd613ab0 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -28,7 +28,7 @@ namespace Nz { ENetHost_BandwidthThrottleInterval = 1000, ENetHost_DefaultMaximumPacketSize = 32 * 1024 * 1024, - ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, + ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, ENetHost_DefaultMTU = 1400, ENetHost_ReceiveBufferSize = 256 * 1024, ENetHost_SendBufferSize = 256 * 1024, diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 76c81eb38..84083b24d 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -672,7 +672,7 @@ namespace Nz if (m_isSimulationEnabled) { - for (auto it = m_pendingPackets.begin(); it != m_pendingPackets.end(); ++it) + for (auto it = m_pendingIncomingPackets.begin(); it != m_pendingIncomingPackets.end(); ++it) { if (m_serviceTime >= it->deliveryTime) { @@ -682,7 +682,7 @@ namespace Nz receivedLength = it->data.GetDataSize(); std::memcpy(m_packetData[0].data(), it->data.GetConstData() + NetPacket::HeaderSize, receivedLength); - m_pendingPackets.erase(it); + m_pendingIncomingPackets.erase(it); break; } } @@ -704,17 +704,17 @@ namespace Nz UInt16 delay = m_packetDelayDistribution(s_randomGenerator); if (delay > 0) { - PendingPacket pendingPacket; + PendingIncomingPacket pendingPacket; pendingPacket.deliveryTime = m_serviceTime + delay; pendingPacket.from = m_receivedAddress; pendingPacket.data.Reset(0, m_packetData[0].data(), receivedLength); - auto it = std::upper_bound(m_pendingPackets.begin(), m_pendingPackets.end(), pendingPacket, [] (const PendingPacket& first, const PendingPacket& second) + auto it = std::upper_bound(m_pendingIncomingPackets.begin(), m_pendingIncomingPackets.end(), pendingPacket, [] (const PendingIncomingPacket& first, const PendingIncomingPacket& second) { return first.deliveryTime < second.deliveryTime; }); - m_pendingPackets.emplace(it, std::move(pendingPacket)); + m_pendingIncomingPackets.emplace(it, std::move(pendingPacket)); continue; } } @@ -1020,17 +1020,72 @@ namespace Nz currentPeer->m_lastSendTime = m_serviceTime; - std::size_t sentLength; - if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) - return -1; + // Simulate network by adding delay to packet sending and losing some packets + bool sendNow = true; + if (!currentPeer->IsSimulationEnabled()) + { + sendNow = false; + if (!currentPeer->m_packetLossProbability(s_randomGenerator)) + { + Nz::UInt16 delay = currentPeer->m_packetDelayDistribution(s_randomGenerator); + if (delay == 0) + sendNow = true; + else + { + PendingOutgoingPacket outgoingPacket; + outgoingPacket.deliveryTime = m_serviceTime + delay; + outgoingPacket.to = currentPeer->GetAddress(); + + // Accumulate every temporary buffer into a datagram + for (std::size_t i = 0; i < m_bufferCount; ++i) + { + NetBuffer& buffer = m_buffers[i]; + outgoingPacket.data.Write(buffer.data, buffer.dataLength); + } + + m_totalSentData += outgoingPacket.data.GetDataSize(); + + // Add it to the right place + auto it = std::upper_bound(m_pendingOutgoingPackets.begin(), m_pendingOutgoingPackets.end(), outgoingPacket, [](const PendingOutgoingPacket& first, const PendingOutgoingPacket& second) + { + return first.deliveryTime < second.deliveryTime; + }); + + m_pendingOutgoingPackets.emplace(it, std::move(outgoingPacket)); + } + } + } + + if (sendNow) + { + std::size_t sentLength = 0; + + if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) + return -1; + + m_totalSentData += sentLength; + } currentPeer->RemoveSentUnreliableCommands(); - - m_totalSentData += sentLength; m_totalSentPackets++; } } + if (!m_pendingOutgoingPackets.empty()) + { + auto it = m_pendingOutgoingPackets.begin(); + for (; it != m_pendingOutgoingPackets.end(); ++it) + { + if (m_serviceTime < it->deliveryTime) + break; + + if (!m_socket.Send(it->to, it->data.GetConstData() + NetPacket::HeaderSize, it->data.GetDataSize(), nullptr)) + return -1; + } + + m_pendingOutgoingPackets.erase(m_pendingOutgoingPackets.begin(), it); + } + return 0; } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index e7a39e3e5..1d28cae42 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -177,6 +177,20 @@ namespace Nz return Send(channelId, m_host->AllocatePacket(flags, std::move(packet))); } + void ENetPeer::SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay) + { + NazaraAssert(maxDelay >= minDelay, "Maximum delay cannot be greater than minimum delay"); + + if (packetLossProbability <= 0.0 && minDelay == 0 && maxDelay == 0) + m_isSimulationEnabled = false; + else + { + m_isSimulationEnabled = true; + m_packetDelayDistribution = std::uniform_int_distribution(minDelay, maxDelay); + m_packetLossProbability = std::bernoulli_distribution(packetLossProbability); + } + } + bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) { if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetDataSize() > m_host->m_maximumPacketSize) From 218d9f3974f627355dbf04c7a81994871f467e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 21 Feb 2017 15:58:02 +0100 Subject: [PATCH 36/48] Network/ENetHost: Add GetBoundAddress() --- include/Nazara/Network/ENetHost.hpp | 1 + include/Nazara/Network/ENetHost.inl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index edb9155ab..4941df353 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -61,6 +61,7 @@ namespace Nz void Flush(); + inline Nz::IpAddress GetBoundAddress() const; inline UInt32 GetServiceTime() const; int Service(ENetEvent* event, UInt32 timeout); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index 9a70d9b78..3f35a8f39 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -52,6 +52,11 @@ namespace Nz m_socket.Close(); } + inline Nz::IpAddress ENetHost::GetBoundAddress() const + { + return m_address; + } + inline UInt32 Nz::ENetHost::GetServiceTime() const { return m_serviceTime; From a53a916399058c326e58fcf846ac89481197a169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 21 Feb 2017 16:55:05 +0100 Subject: [PATCH 37/48] Network/ENetHost: Fix simulation being always active --- src/Nazara/Network/ENetHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 84083b24d..d32b6d5f9 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1022,7 +1022,7 @@ namespace Nz // Simulate network by adding delay to packet sending and losing some packets bool sendNow = true; - if (!currentPeer->IsSimulationEnabled()) + if (currentPeer->IsSimulationEnabled()) { sendNow = false; if (!currentPeer->m_packetLossProbability(s_randomGenerator)) From 14022ccee25e702fd4685eccaa644eb1ec651190 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 24 Feb 2017 10:15:13 +0100 Subject: [PATCH 38/48] Network/ENetPeer: Fix crash --- src/Nazara/Network/ENetPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 1d28cae42..5407fec35 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -986,7 +986,7 @@ namespace Nz if (currentCommand == m_sentReliableCommands.end()) { currentCommand = m_outgoingReliableCommands.begin(); - commandList = &m_sentReliableCommands; + commandList = &m_outgoingReliableCommands; for (; currentCommand != m_outgoingReliableCommands.end(); ++currentCommand) { found = true; From f2fb0f62c2dbb66270d0cbde3cc14dc37d60cf0f Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 2 Mar 2017 16:18:34 +0100 Subject: [PATCH 39/48] Switch ENet errors to Nazara --- src/Nazara/Network/ENetHost.cpp | 37 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d32b6d5f9..6f726b644 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -224,9 +224,7 @@ namespace Nz return 1; case -1: - #ifdef ENET_DEBUG - perror("Error sending outgoing packets"); - #endif + NazaraError("Error sending outgoing packets"); return -1; default: @@ -235,34 +233,29 @@ namespace Nz switch (ReceiveIncomingCommands(event)) { - case 1: - return 1; + case 1: + return 1; - case -1: -#ifdef ENET_DEBUG - perror("Error receiving incoming packets"); -#endif + case -1: + NazaraError("Error receiving incoming packets"); + return -1; - return -1; - - default: - break; + default: + break; } switch (SendOutgoingCommands(event, true)) { - case 1: - return 1; + case 1: + return 1; - case -1: -#ifdef ENET_DEBUG - perror("Error sending outgoing packets"); -#endif + case -1: + NazaraError("Error sending outgoing packets"); - return -1; + return -1; - default: - break; + default: + break; } if (event) From b2e4296cc78f640c853b004b607654187ab35b2f Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 8 Mar 2017 21:05:56 +0100 Subject: [PATCH 40/48] Network/ENetHost: Fix peers default values not being initialized --- src/Nazara/Network/ENetHost.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 6f726b644..d4d1be9f9 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -156,10 +156,6 @@ namespace Nz if (!InitSocket(address)) return false; - m_peers.reserve(peerCount); - for (std::size_t i = 0; i < peerCount; ++i) - m_peers.emplace_back(this, UInt16(i)); - m_address = address; m_randomSeed = *reinterpret_cast(this); m_randomSeed += s_randomGenerator(); @@ -188,6 +184,10 @@ namespace Nz m_maximumPacketSize = ENetConstants::ENetHost_DefaultMaximumPacketSize; m_maximumWaitingData = ENetConstants::ENetHost_DefaultMaximumWaitingData; + m_peers.reserve(peerCount); + for (std::size_t i = 0; i < peerCount; ++i) + m_peers.emplace_back(this, UInt16(i)); + return true; } From 1917a0e8dd9a578bdc32bb8141029aab0e77fac0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 8 Mar 2017 21:06:09 +0100 Subject: [PATCH 41/48] Network/ENetPeer: Fix fragments handling --- src/Nazara/Network/ENetPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 5407fec35..2a9adfcbf 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -674,7 +674,7 @@ namespace Nz DispatchIncomingReliableCommands(channel); } - return false; + return true; } bool ENetPeer::HandleSendReliable(const ENetProtocol* command, UInt8** data) From a4fe005e3b0a203610df2f4c780d561740a23009 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 8 Mar 2017 22:40:15 +0100 Subject: [PATCH 42/48] Network/ENetPeer: Fix packets not being resend after timeout sometimes --- src/Nazara/Network/ENetPeer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 2a9adfcbf..5ce92a1e4 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -287,12 +287,15 @@ namespace Nz UInt32 serviceTime = m_host->GetServiceTime(); auto it = m_sentReliableCommands.begin(); - for (; it != m_sentReliableCommands.end(); ++it) + for (; it != m_sentReliableCommands.end();) { OutgoingCommand& command = *it; if (ENetTimeDifference(serviceTime, command.sentTime) < command.roundTripTimeout) + { + ++it; continue; + } if (m_earliestTimeout == 0 || ENetTimeLess(command.sentTime, m_earliestTimeout)) m_earliestTimeout = command.sentTime; @@ -315,6 +318,7 @@ namespace Nz command.roundTripTimeoutLimit = m_timeoutLimit * command.roundTripTimeout; m_outgoingReliableCommands.emplace_front(std::move(command)); + it = m_sentReliableCommands.erase(it); // Okay this should just never procs, I don't see how it would be possible /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && @@ -326,8 +330,6 @@ namespace Nz }*/ } - m_sentReliableCommands.erase(m_sentReliableCommands.begin(), it); - return false; } From d516b0907b8247c61255b8c6041ad9bb67bb5742 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 May 2017 09:11:02 +0200 Subject: [PATCH 43/48] Network/ENetHost: Fix usage of SocketPoller --- src/Nazara/Network/ENetHost.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d4d1be9f9..e12f80454 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -280,7 +280,7 @@ namespace Nz m_serviceTime = GetElapsedMilliseconds(); } - while (m_poller.IsReady(m_socket)); + while (m_poller.IsReadyToRead(m_socket)); return 0; } @@ -327,7 +327,7 @@ namespace Nz } } - m_poller.RegisterSocket(m_socket); + m_poller.RegisterSocket(m_socket, SocketPollEvent_Read); return true; } From ba24181fd69d900881e71277bbecaee2bb7dbf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 17 May 2017 11:29:55 +0200 Subject: [PATCH 44/48] Network/SocketPollerImpl: Fix possible weird behavior with SocketPoller --- src/Nazara/Network/Win32/SocketPollerImpl.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index e228da789..3513ce722 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -136,14 +136,26 @@ namespace Nz #if NAZARA_NETWORK_POLL_SUPPORT activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); #else - m_readyToReadSockets = m_readSockets; - m_readyToWriteSockets = m_writeSockets; + fd_set* readSet = nullptr; + fd_set* writeSet = nullptr; + + if (m_readSockets.fd_count > 0) + { + m_readyToReadSockets = m_readSockets; + readSet = &m_readyToReadSockets; + } + + if (m_writeSockets.fd_count > 0) + { + m_readyToWriteSockets = m_writeSockets; + readSet = &m_readyToWriteSockets; + } timeval tv; tv.tv_sec = static_cast(msTimeout / 1000ULL); tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - activeSockets = ::select(0xDEADBEEF, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows + activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows if (activeSockets == SOCKET_ERROR) { if (error) From 3ca179b954e22b640ef753bd8064727a328d6250 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 19 May 2017 16:31:29 +0200 Subject: [PATCH 45/48] Network/ENet: Separate Connect event into OutgoingConnect and IncomingConnect --- include/Nazara/Network/ENetHost.hpp | 2 +- include/Nazara/Network/ENetProtocol.hpp | 18 +++++++++++------- src/Nazara/Network/ENetHost.cpp | 15 +++++++++++---- src/Nazara/Network/ENetPeer.cpp | 6 +++--- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 4941df353..eb5c7d6de 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -87,7 +87,7 @@ namespace Nz int ReceiveIncomingCommands(ENetEvent* event); - void NotifyConnect(ENetPeer* peer, ENetEvent* event); + void NotifyConnect(ENetPeer* peer, ENetEvent* event, bool incoming); void NotifyDisconnect(ENetPeer*, ENetEvent* event); void SendAcknowledgements(ENetPeer* peer); diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index 7cd613ab0..dab014aa2 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -118,11 +118,6 @@ namespace Nz /** no event occurred within the specified time limit */ None, - /** a connection request initiated by enet_host_connect has completed. - * The peer field contains the peer which successfully connected. - */ - Connect, - /** a peer has disconnected. This event is generated on a successful * completion of a disconnect initiated by enet_peer_disconnect, if * a peer has timed out, or if a connection request initialized by @@ -132,11 +127,20 @@ namespace Nz */ Disconnect, + /** a connection request initiated by enet_host_connect from this host has completed. + * The peer field contains the peer which successfully connected. + */ + OutgoingConnect, + + /** a connection request initiated by enet_host_connect from another host has completed. + * The peer field contains the peer which successfully connected. + */ + IncomingConnect, + /** a packet has been received from a peer. The peer field specifies the * peer which sent the packet. The channelID field specifies the channel * number upon which the packet was received. The packet field contains - * the packet that was received; this packet must be destroyed with - * enet_packet_destroy after use. + * the packet that was received; */ Receive }; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d4d1be9f9..ade03bb10 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -352,10 +352,17 @@ namespace Nz switch (peer.GetState()) { case ENetPeerState::ConnectionPending: + peer.ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::IncomingConnect; + event->peer = &peer; + event->data = peer.m_eventData; + return true; + case ENetPeerState::ConnectionSucceeded: peer.ChangeState(ENetPeerState::Connected); - event->type = ENetEventType::Connect; + event->type = ENetEventType::OutgoingConnect; event->peer = &peer; event->data = peer.m_eventData; return true; @@ -728,7 +735,7 @@ namespace Nz return -1; } - void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event) + void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event, bool incoming) { m_recalculateBandwidthLimits = true; @@ -736,12 +743,12 @@ namespace Nz { peer->ChangeState(ENetPeerState::Connected); - event->type = ENetEventType::Connect; + event->type = (incoming) ? ENetEventType::IncomingConnect : ENetEventType::OutgoingConnect; event->peer = peer; event->data = peer->m_eventData; } else - peer->DispatchState(peer->GetState() == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + peer->DispatchState((peer->GetState() == ENetPeerState::Connecting) ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); } void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 5ce92a1e4..cbae37148 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -501,7 +501,7 @@ namespace Nz if (commandNumber != ENetProtocolCommand_VerifyConnect) return false; - m_host->NotifyConnect(this, event); + m_host->NotifyConnect(this, event, true); break; case ENetPeerState::Disconnecting: @@ -864,7 +864,7 @@ namespace Nz NetToHost(command->verifyConnect.packetThrottleInterval) != m_packetThrottleInterval || NetToHost(command->verifyConnect.packetThrottleAcceleration) != m_packetThrottleAcceleration || NetToHost(command->verifyConnect.packetThrottleDeceleration) != m_packetThrottleDeceleration || - command->verifyConnect.connectID != m_connectID) + command->verifyConnect.connectID != m_connectID) { m_eventData = 0; @@ -891,7 +891,7 @@ namespace Nz m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); - m_host->NotifyConnect(this, event); + m_host->NotifyConnect(this, event, false); return true; } From 3b914422c825aed2b71d01f201866b8bd2f25ddf Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 30 May 2017 00:50:28 +0200 Subject: [PATCH 46/48] SDK/EntityList: Fix warning on GCC --- SDK/include/NDK/EntityList.hpp | 4 ++-- SDK/include/NDK/EntityList.inl | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SDK/include/NDK/EntityList.hpp b/SDK/include/NDK/EntityList.hpp index b659b15fb..8303f7fa4 100644 --- a/SDK/include/NDK/EntityList.hpp +++ b/SDK/include/NDK/EntityList.hpp @@ -59,11 +59,11 @@ namespace Ndk friend EntityList; public: - inline iterator(const iterator& iterator); + inline iterator(const iterator& it); const EntityHandle& operator*() const; - inline iterator& operator=(const iterator& iterator); + inline iterator& operator=(const iterator& it); inline iterator& operator++(); inline iterator operator++(int); diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl index d178d2b09..8d871e2c6 100644 --- a/SDK/include/NDK/EntityList.inl +++ b/SDK/include/NDK/EntityList.inl @@ -207,16 +207,16 @@ namespace Ndk { } - inline EntityList::iterator::iterator(const iterator& iterator) : - m_nextEntityId(iterator.m_nextEntityId), - m_list(iterator.m_list) + inline EntityList::iterator::iterator(const iterator& it) : + m_nextEntityId(it.m_nextEntityId), + m_list(it.m_list) { } - inline EntityList::iterator& EntityList::iterator::operator=(const iterator& iterator) + inline EntityList::iterator& EntityList::iterator::operator=(const iterator& it) { - m_nextEntityId = iterator.m_nextEntityId; - m_list = iterator.m_list; + m_nextEntityId = it.m_nextEntityId; + m_list = it.m_list; return *this; } From c98fb482e7bb54054b6cf40eddd1dffb745824ec Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 5 Jun 2017 15:06:19 +0200 Subject: [PATCH 47/48] Network/ENetPeer: Add GetRoundTripTime method --- include/Nazara/Network/ENetPeer.hpp | 1 + include/Nazara/Network/ENetPeer.inl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index e3538e6fb..4e36378a5 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -55,6 +55,7 @@ namespace Nz inline UInt32 GetPacketThrottleDeceleration() const; inline UInt32 GetPacketThrottleInterval() const; inline UInt16 GetPeerId() const; + inline UInt32 GetRoundTripTime() const; inline ENetPeerState GetState() const; inline bool HasPendingCommands(); diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index bcec4a8c1..d831b4d0d 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -48,6 +48,11 @@ namespace Nz return m_incomingPeerID; } + inline UInt32 ENetPeer::GetRoundTripTime() const + { + return m_roundTripTime; + } + inline ENetPeerState ENetPeer::GetState() const { return m_state; From ab1eccde8247f579184c047933796eb51b8e90c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 9 Jun 2017 02:07:51 +0200 Subject: [PATCH 48/48] Fix compilation --- src/Nazara/Lua/LuaCoroutine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nazara/Lua/LuaCoroutine.cpp b/src/Nazara/Lua/LuaCoroutine.cpp index ea73af31a..197244134 100644 --- a/src/Nazara/Lua/LuaCoroutine.cpp +++ b/src/Nazara/Lua/LuaCoroutine.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Nz