1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
19 #include "nel/misc/config_file.h"
21 #include "nel/net/udp_sock.h"
22 #include "nel/net/udp_sim_sock.h"
25 using namespace NLMISC
;
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
);
47 Addr
= new CInetAddress
;
56 ~CBufferizedOutPacket ()
58 nlassert (Packet
!= NULL
);
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;
95 void CUdpSimSock::sendUDPNow (const uint8
*buffer
, uint32 len
, const CInetAddress
*addr
)
98 UdpSock
.send (buffer
, len
);
100 UdpSock
.sendTo (buffer
, len
, *addr
);
103 void CUdpSimSock::sendUDP (const uint8
*buffer
, uint32
& len
, const CInetAddress
*addr
)
105 nlassert (buffer
!= NULL
);
108 if ((float)rand()/(float)(RAND_MAX
)*100.0f
>= _OutPacketLoss
)
110 sint32 lag
= _OutLag
/*+ (rand()%40) - 20*/;// void disordering
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();
125 bp
->Time
= bp2
->Time
;
128 // exange packet in the buffer
129 _BufferizedOutPackets
.back() = bp
;
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
);
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 ();
167 // time to send the message
168 sendUDPNow (bp
->Packet
, bp
->PacketSize
, bp
->Addr
);
170 _BufferizedOutPackets
.pop ();
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 ());
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");
203 pv
= cf
.getVarPtr("SimInPacketLost");
206 pv
= cf
.getVarPtr("SimOutLag");
209 pv
= cf
.getVarPtr("SimOutPacketLost");
212 pv
= cf
.getVarPtr("SimOutPacketDuplication");
215 pv
= cf
.getVarPtr("SimOutPacketDisordering");
220 void CUdpSimSock::connect( const CInetAddress
& addr
)
222 UdpSock
.connect (addr
);
225 void CUdpSimSock::close()
230 uint8 buffer
[10000];
232 bool CUdpSimSock::dataAvailable ()
234 updateBufferizedPackets ();
238 while (UdpSock
.dataAvailable ())
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
)
259 if ((float)rand()/(float)(RAND_MAX
)*100.0f
>= _InPacketLoss
)
261 return UdpSock
.dataAvailable ();
266 if (UdpSock
.dataAvailable ())
270 UdpSock
.receivedFrom (buffer
, len
, addr
);
279 bool CUdpSimSock::receive (uint8
*buffer
, uint32
& len
, bool throw_exception
)
283 if (_BufferizedInPackets
.empty())
286 throw Exception ("no data available");
290 CBufferizedOutPacket
*bp
= _BufferizedInPackets
.front ();
291 uint32 s
= min (len
, bp
->PacketSize
);
292 memcpy (buffer
, bp
->Packet
, s
);
296 _BufferizedInPackets
.pop ();
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
);
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 ();