Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / net / udp_sim_sock.cpp
blobfabb037d386ce955e64b50fefdc4f4510f5c434e
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdnet.h"
19 #include "nel/misc/config_file.h"
21 #include "nel/net/udp_sock.h"
22 #include "nel/net/udp_sim_sock.h"
24 using namespace std;
25 using namespace NLMISC;
27 namespace NLNET {
30 // Class
33 struct CBufferizedOutPacket
35 CBufferizedOutPacket (CUdpSock *client, const uint8 *packet, uint32 packetSize, uint32 delay, const CInetAddress *addr):
36 Client(client), PacketSize(packetSize), Time(CTime::getLocalTime()+delay)
38 nlassert (packetSize > 0);
39 nlassert (packet != NULL);
40 nlassert (client != NULL);
42 Packet = new uint8[packetSize];
43 memcpy (Packet, packet, packetSize);
45 if (addr != NULL)
47 Addr = new CInetAddress;
48 *Addr = *addr;
50 else
52 Addr = NULL;
56 ~CBufferizedOutPacket ()
58 nlassert (Packet != NULL);
59 delete [] Packet;
60 Packet = NULL;
61 Client = NULL;
62 PacketSize = 0;
63 Time = 0;
64 if (Addr != NULL)
65 delete Addr;
68 CUdpSock *Client;
69 uint8 *Packet;
70 uint32 PacketSize;
71 TTime Time;
72 CInetAddress *Addr;
77 // Variables
80 //queue<CBufferizedOutPacket*> CUdpSimSock::BufferizedOutPackets;
81 //queue<CBufferizedOutPacket*> CUdpSimSock::BufferizedInPackets;
83 uint32 CUdpSimSock::_InLag = 0;
84 uint8 CUdpSimSock::_InPacketLoss = 0;
86 uint32 CUdpSimSock::_OutLag = 0;
87 uint8 CUdpSimSock::_OutPacketLoss = 0;
88 uint8 CUdpSimSock::_OutPacketDuplication = 0;
89 uint8 CUdpSimSock::_OutPacketDisordering = 0;
92 // Functions
95 void CUdpSimSock::sendUDPNow (const uint8 *buffer, uint32 len, const CInetAddress *addr)
97 if (addr == NULL)
98 UdpSock.send (buffer, len);
99 else
100 UdpSock.sendTo (buffer, len, *addr);
103 void CUdpSimSock::sendUDP (const uint8 *buffer, uint32& len, const CInetAddress *addr)
105 nlassert (buffer != NULL);
106 nlassert (len > 0);
108 if ((float)rand()/(float)(RAND_MAX)*100.0f >= _OutPacketLoss)
110 sint32 lag = _OutLag /*+ (rand()%40) - 20*/;// void disordering
112 if (lag > 100)
114 // send the packet later
116 CBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, lag, addr);
118 // duplicate the packet
119 if ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDisordering && !_BufferizedOutPackets.empty())
121 CBufferizedOutPacket *bp2 = _BufferizedOutPackets.back();
123 // exange the time
124 TTime t = bp->Time;
125 bp->Time = bp2->Time;
126 bp2->Time = t;
128 // exange packet in the buffer
129 _BufferizedOutPackets.back() = bp;
130 bp = bp2;
133 _BufferizedOutPackets.push (bp);
135 // duplicate the packet
136 if ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDuplication)
138 CBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, lag, addr);
139 _BufferizedOutPackets.push (bp);
142 else
144 // send the packet NOW
146 sendUDPNow (buffer, len, addr);
148 // duplicate the packet
149 if ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDuplication)
151 sendUDPNow (buffer, len, addr);
159 void CUdpSimSock::updateBufferizedPackets ()
161 TTime ct = CTime::getLocalTime ();
162 while (!_BufferizedOutPackets.empty())
164 CBufferizedOutPacket *bp = _BufferizedOutPackets.front ();
165 if (bp->Time <= ct)
167 // time to send the message
168 sendUDPNow (bp->Packet, bp->PacketSize, bp->Addr);
169 delete bp;
170 _BufferizedOutPackets.pop ();
172 else
174 break;
179 void cbSimVar (CConfigFile::CVar &var)
181 if (var.Name == "SimInLag") CUdpSimSock::_InLag = var.asInt ();
182 else if (var.Name == "SimInPacketLost") CUdpSimSock::_InPacketLoss = uint8(var.asInt ());
183 else if (var.Name == "SimOutLag") CUdpSimSock::_OutLag = var.asInt ();
184 else if (var.Name == "SimOutPacketLost") CUdpSimSock::_OutPacketLoss = uint8(var.asInt ());
185 else if (var.Name == "SimOutPacketDuplication") CUdpSimSock::_OutPacketDuplication = uint8(var.asInt ());
186 else if (var.Name == "SimOutPacketDisordering") CUdpSimSock::_OutPacketDisordering = uint8(var.asInt ());
187 else nlstop;
190 void CUdpSimSock::setSimValues (NLMISC::CConfigFile &cf)
192 cf.setCallback ("SimInLag", cbSimVar);
193 cf.setCallback ("SimInPacketLost", cbSimVar);
194 cf.setCallback ("SimOutLag", cbSimVar);
195 cf.setCallback ("SimOutPacketLost", cbSimVar);
196 cf.setCallback ("SimOutPacketDuplication", cbSimVar);
197 cf.setCallback ("SimOutPacketDisordering", cbSimVar);
199 CConfigFile::CVar *pv;
200 pv = cf.getVarPtr("SimInLag");
201 if( pv )
202 cbSimVar( *pv );
203 pv = cf.getVarPtr("SimInPacketLost");
204 if( pv )
205 cbSimVar( *pv );
206 pv = cf.getVarPtr("SimOutLag");
207 if( pv )
208 cbSimVar( *pv );
209 pv = cf.getVarPtr("SimOutPacketLost");
210 if( pv )
211 cbSimVar( *pv );
212 pv = cf.getVarPtr("SimOutPacketDuplication");
213 if( pv )
214 cbSimVar( *pv );
215 pv = cf.getVarPtr("SimOutPacketDisordering");
216 if( pv )
217 cbSimVar( *pv );
220 void CUdpSimSock::connect( const CInetAddress& addr )
222 UdpSock.connect (addr);
225 void CUdpSimSock::close()
227 UdpSock.close ();
230 uint8 buffer [10000];
232 bool CUdpSimSock::dataAvailable ()
234 updateBufferizedPackets ();
236 if (_InLag > 0)
238 while (UdpSock.dataAvailable ())
240 CInetAddress addr;
241 uint len = 10000;
242 UdpSock.receivedFrom (buffer, len, addr);
244 if ((float)rand()/(float)(RAND_MAX)*100.0f >= _InPacketLoss)
246 CBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, _InLag, &addr);
247 _BufferizedInPackets.push (bp);
251 TTime ct = CTime::getLocalTime ();
252 if (!_BufferizedInPackets.empty() && _BufferizedInPackets.front ()->Time <= ct)
253 return true;
254 else
255 return false;
257 else
259 if ((float)rand()/(float)(RAND_MAX)*100.0f >= _InPacketLoss)
261 return UdpSock.dataAvailable ();
263 else
265 // consume data
266 if (UdpSock.dataAvailable ())
268 CInetAddress addr;
269 uint len = 10000;
270 UdpSock.receivedFrom (buffer, len, addr);
273 // packet lost
274 return false;
279 bool CUdpSimSock::receive (uint8 *buffer, uint32& len, bool throw_exception)
281 if (_InLag> 0)
283 if (_BufferizedInPackets.empty())
285 if (throw_exception)
286 throw Exception ("no data available");
287 return false;
290 CBufferizedOutPacket *bp = _BufferizedInPackets.front ();
291 uint32 s = min (len, bp->PacketSize);
292 memcpy (buffer, bp->Packet, s);
293 len = s;
295 delete bp;
296 _BufferizedInPackets.pop ();
297 return true;
299 else
301 return UdpSock.receive(buffer, len, throw_exception);
305 CSock::TSockResult CUdpSimSock::send (const uint8 *buffer, uint32& len, bool /* throw_exception */)
307 sendUDP (buffer, len);
308 return CSock::Ok;
311 void CUdpSimSock::sendTo (const uint8 *buffer, uint32& len, const CInetAddress& addr)
313 sendUDP (buffer, len, &addr);
316 bool CUdpSimSock::connected()
318 return UdpSock.connected ();
321 } // NLNET