201 lines
4.4 KiB
C++
201 lines
4.4 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include <string>
|
|
#include <queue>
|
|
|
|
#include <nel/misc/types_nl.h>
|
|
#include <nel/misc/debug.h>
|
|
|
|
#include <nel/net/udp_sock.h>
|
|
|
|
//
|
|
// Using
|
|
//
|
|
|
|
using namespace std;
|
|
|
|
using namespace NLMISC;
|
|
using namespace NLNET;
|
|
|
|
//
|
|
// Variables
|
|
//
|
|
|
|
static uint32 Lag = 0;
|
|
static uint8 PacketLoss = 0;
|
|
static uint8 PacketDuplication = 0;
|
|
static uint8 PacketDisordering = 0;
|
|
|
|
//
|
|
// Class
|
|
//
|
|
|
|
struct CBufferizedPacket
|
|
{
|
|
CBufferizedPacket (CUdpSock *client, const uint8 *packet, uint32 packetSize, uint32 delay, const CInetAddress *addr):
|
|
Client(client), PacketSize(packetSize), Time(CTime::getLocalTime()+delay)
|
|
{
|
|
nlassert (packetSize > 0);
|
|
nlassert (packet != NULL);
|
|
nlassert (client != NULL);
|
|
|
|
Packet = new uint8[packetSize];
|
|
memcpy (Packet, packet, packetSize);
|
|
|
|
if (addr != NULL)
|
|
{
|
|
Addr = new CInetAddress;
|
|
*Addr = *addr;
|
|
}
|
|
else
|
|
{
|
|
Addr = NULL;
|
|
}
|
|
}
|
|
|
|
~CBufferizedPacket ()
|
|
{
|
|
nlassert (Packet != NULL);
|
|
delete [] Packet;
|
|
Packet = NULL;
|
|
Client = NULL;
|
|
PacketSize = 0;
|
|
Time = 0;
|
|
if (Addr != NULL)
|
|
delete Addr;
|
|
}
|
|
|
|
CUdpSock *Client;
|
|
uint8 *Packet;
|
|
uint32 PacketSize;
|
|
TTime Time;
|
|
CInetAddress *Addr;
|
|
};
|
|
|
|
//
|
|
// Variables
|
|
//
|
|
|
|
static queue<CBufferizedPacket*> BufferizedPackets;
|
|
|
|
//
|
|
// Prototypes
|
|
//
|
|
|
|
void sendUDPNow (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr);
|
|
|
|
//
|
|
// Functions
|
|
//
|
|
|
|
void updateBufferizedPackets ()
|
|
{
|
|
TTime ct = CTime::getLocalTime ();
|
|
while (!BufferizedPackets.empty())
|
|
{
|
|
CBufferizedPacket *bp = BufferizedPackets.front ();
|
|
if (bp->Time <= ct)
|
|
{
|
|
// time to send the message
|
|
sendUDPNow (bp->Client, bp->Packet, bp->PacketSize, bp->Addr);
|
|
delete bp;
|
|
BufferizedPackets.pop ();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void setSimlagValues (sint32 lag, sint8 packetLoss, sint8 packetDuplication, sint8 packetDisordering)
|
|
{
|
|
if (lag != -1) Lag = lag;
|
|
if (packetLoss != -1) PacketLoss = packetLoss;
|
|
if (packetDuplication != -1) PacketDuplication = packetDuplication;
|
|
if (packetDisordering != -1) PacketDisordering = packetDisordering;
|
|
}
|
|
|
|
void sendUDPNow (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr)
|
|
{
|
|
if (addr == NULL)
|
|
client->send (packet, packetSize);
|
|
else
|
|
client->sendTo (packet, packetSize, *addr);
|
|
|
|
uint32 packetNumber = *(uint32 *)packet;
|
|
// nlinfo ("time %" NL_I64 "u sending now packet %5u", CTime::getLocalTime (), packetNumber);
|
|
}
|
|
|
|
void sendUDP (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr)
|
|
{
|
|
nlassert (client != NULL);
|
|
nlassert (packet != NULL);
|
|
nlassert (packetSize > 0);
|
|
|
|
if ((float)rand()/(float)(RAND_MAX)*100.0f >= PacketLoss)
|
|
{
|
|
sint32 lag = Lag /*+ (rand()%40) - 20*/;// void disordering
|
|
|
|
if (lag > 100)
|
|
{
|
|
// send the packet later
|
|
|
|
CBufferizedPacket *bp = new CBufferizedPacket (client, packet, packetSize, lag, addr);
|
|
|
|
// duplicate the packet
|
|
if ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDisordering && BufferizedPackets.size() > 0)
|
|
{
|
|
CBufferizedPacket *bp2 = BufferizedPackets.back();
|
|
|
|
// exange the time
|
|
TTime t = bp->Time;
|
|
bp->Time = bp2->Time;
|
|
bp2->Time = t;
|
|
|
|
// exange packet in the buffer
|
|
BufferizedPackets.back() = bp;
|
|
bp = bp2;
|
|
}
|
|
|
|
BufferizedPackets.push (bp);
|
|
|
|
// duplicate the packet
|
|
if ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDuplication)
|
|
{
|
|
CBufferizedPacket *bp = new CBufferizedPacket (client, packet, packetSize, lag, addr);
|
|
BufferizedPackets.push (bp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// send the packet NOW
|
|
|
|
sendUDPNow (client, packet, packetSize, addr);
|
|
|
|
// duplicate the packet
|
|
if ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDuplication)
|
|
{
|
|
sendUDPNow (client, packet, packetSize, addr);
|
|
}
|
|
}
|
|
}
|
|
}
|