Network/ENetHost: Add network simulator

This commit is contained in:
Lynix 2017-01-28 17:18:06 +01:00
parent 4e2a037d6b
commit 4e517bc1e3
4 changed files with 78 additions and 10 deletions

View File

@ -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<ENetProtocol, ENetConstants::ENetProtocol_MaximumPacketCommands> m_commands;
std::array<NetBuffer, ENetConstants::ENetProtocol_MaximumPacketCommands * 2 + 1> m_buffers;
std::array<UInt8, ENetConstants::ENetProtocol_MaximumMTU> m_packetData[2];
@ -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<UInt16> m_packetDelayDistribution;
std::vector<ENetPeer> m_peers;
std::vector<PendingPacket> m_pendingPackets;
UInt8* m_receivedData;
Bitset<UInt64> 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;

View File

@ -9,7 +9,8 @@
namespace Nz
{
inline ENetHost::ENetHost() :
m_packetPool(sizeof(ENetPacket))
m_packetPool(sizeof(ENetPacket)),
m_isSimulationEnabled(false)
{
}

View File

@ -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<UInt16>(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;

View File

@ -2,7 +2,6 @@
#include <Nazara/Core/Endianness.hpp>
#include <Nazara/Network/ENetHost.hpp>
#include <Nazara/Network/NetPacket.hpp>
#include <iostream>
#include <Nazara/Network/Debug.hpp>
#define ENET_TIME_OVERFLOW 86400000