00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "stdnet.h"
00028
00029 #include <queue>
00030
00031 #include "nel/misc/config_file.h"
00032
00033 #include "nel/net/udp_sock.h"
00034 #include "nel/net/udp_sim_sock.h"
00035
00036 using namespace std;
00037 using namespace NLMISC;
00038
00039 namespace NLNET {
00040
00041
00042
00043
00044
00045 struct CBufferizedOutPacket
00046 {
00047 CBufferizedOutPacket (CUdpSock *client, const uint8 *packet, uint32 packetSize, uint32 delay, const CInetAddress *addr):
00048 Client(client), PacketSize(packetSize), Time(CTime::getLocalTime()+delay)
00049 {
00050 nlassert (packetSize > 0);
00051 nlassert (packet != NULL);
00052 nlassert (client != NULL);
00053
00054 Packet = new uint8[packetSize];
00055 memcpy (Packet, packet, packetSize);
00056
00057 if (addr != NULL)
00058 {
00059 Addr = new CInetAddress;
00060 *Addr = *addr;
00061 }
00062 else
00063 {
00064 Addr = NULL;
00065 }
00066 }
00067
00068 ~CBufferizedOutPacket ()
00069 {
00070 nlassert (Packet != NULL);
00071 delete [] Packet;
00072 Packet = NULL;
00073 Client = NULL;
00074 PacketSize = 0;
00075 Time = 0;
00076 if (Addr != NULL)
00077 delete Addr;
00078 }
00079
00080 CUdpSock *Client;
00081 uint8 *Packet;
00082 uint32 PacketSize;
00083 TTime Time;
00084 CInetAddress *Addr;
00085 };
00086
00087
00088
00089
00090
00091
00092 static queue<CBufferizedOutPacket*> BufferizedOutPackets;
00093 static queue<CBufferizedOutPacket*> BufferizedInPackets;
00094
00095 uint32 CUdpSimSock::_InLag = 0;
00096 uint8 CUdpSimSock::_InPacketLoss = 0;
00097
00098 uint32 CUdpSimSock::_OutLag = 0;
00099 uint8 CUdpSimSock::_OutPacketLoss = 0;
00100 uint8 CUdpSimSock::_OutPacketDuplication = 0;
00101 uint8 CUdpSimSock::_OutPacketDisordering = 0;
00102
00103
00104
00105
00106
00107 void CUdpSimSock::sendUDPNow (const uint8 *buffer, uint32 len, const CInetAddress *addr)
00108 {
00109 if (addr == NULL)
00110 UdpSock.send (buffer, len);
00111 else
00112 UdpSock.sendTo (buffer, len, *addr);
00113 }
00114
00115 void CUdpSimSock::sendUDP (const uint8 *buffer, uint32& len, const CInetAddress *addr)
00116 {
00117 nlassert (buffer != NULL);
00118 nlassert (len > 0);
00119
00120 if ((float)rand()/(float)(RAND_MAX)*100.0f >= _OutPacketLoss)
00121 {
00122 sint32 lag = _OutLag ;
00123
00124 if (lag > 100)
00125 {
00126
00127
00128 CBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, lag, addr);
00129
00130
00131 if ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDisordering && BufferizedOutPackets.size() > 0)
00132 {
00133 CBufferizedOutPacket *bp2 = BufferizedOutPackets.back();
00134
00135
00136 TTime t = bp->Time;
00137 bp->Time = bp2->Time;
00138 bp2->Time = t;
00139
00140
00141 BufferizedOutPackets.back() = bp;
00142 bp = bp2;
00143 }
00144
00145 BufferizedOutPackets.push (bp);
00146
00147
00148 if ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDuplication)
00149 {
00150 CBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, lag, addr);
00151 BufferizedOutPackets.push (bp);
00152 }
00153 }
00154 else
00155 {
00156
00157
00158 sendUDPNow (buffer, len, addr);
00159
00160
00161 if ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDuplication)
00162 {
00163 sendUDPNow (buffer, len, addr);
00164 }
00165 }
00166 }
00167 }
00168
00169
00170
00171 void CUdpSimSock::updateBufferizedPackets ()
00172 {
00173 TTime ct = CTime::getLocalTime ();
00174 while (!BufferizedOutPackets.empty())
00175 {
00176 CBufferizedOutPacket *bp = BufferizedOutPackets.front ();
00177 if (bp->Time <= ct)
00178 {
00179
00180 sendUDPNow (bp->Packet, bp->PacketSize, bp->Addr);
00181 delete bp;
00182 BufferizedOutPackets.pop ();
00183 }
00184 else
00185 {
00186 break;
00187 }
00188 }
00189 }
00190
00191 void cbSimVar (CConfigFile::CVar &var)
00192 {
00193 if (var.Name == "SimInLag") CUdpSimSock::_InLag = var.asInt ();
00194 else if (var.Name == "SimInPacketLost") CUdpSimSock::_InPacketLoss = var.asInt ();
00195 else if (var.Name == "SimOutLag") CUdpSimSock::_OutLag = var.asInt ();
00196 else if (var.Name == "SimOutPacketLost") CUdpSimSock::_OutPacketLoss = var.asInt ();
00197 else if (var.Name == "SimOutPacketDuplication") CUdpSimSock::_OutPacketDuplication = var.asInt ();
00198 else if (var.Name == "SimOutPacketDisordering") CUdpSimSock::_OutPacketDisordering = var.asInt ();
00199 else nlstop;
00200 }
00201
00202 void CUdpSimSock::setSimValues (NLMISC::CConfigFile &cf)
00203 {
00204 cf.setCallback ("SimInLag", cbSimVar);
00205 cf.setCallback ("SimInPacketLost", cbSimVar);
00206 cf.setCallback ("SimOutLag", cbSimVar);
00207 cf.setCallback ("SimOutPacketLost", cbSimVar);
00208 cf.setCallback ("SimOutPacketDuplication", cbSimVar);
00209 cf.setCallback ("SimOutPacketDisordering", cbSimVar);
00210
00211 try
00212 {
00213 cbSimVar (cf.getVar("SimInLag"));
00214 cbSimVar (cf.getVar("SimInPacketLost"));
00215 cbSimVar (cf.getVar("SimOutLag"));
00216 cbSimVar (cf.getVar("SimOutPacketLost"));
00217 cbSimVar (cf.getVar("SimOutPacketDuplication"));
00218 cbSimVar (cf.getVar("SimOutPacketDisordering"));
00219 }
00220 catch (Exception &e)
00221 {
00222 nlwarning ("Problem during getting Sim values from config file: %s", e.what());
00223 }
00224 }
00225
00226 void CUdpSimSock::connect( const CInetAddress& addr )
00227 {
00228 UdpSock.connect (addr);
00229 }
00230
00231 void CUdpSimSock::close()
00232 {
00233 UdpSock.close ();
00234 }
00235
00236 uint8 buffer [10000];
00237
00238 bool CUdpSimSock::dataAvailable ()
00239 {
00240 updateBufferizedPackets ();
00241
00242 if (_InLag > 0)
00243 {
00244 while (UdpSock.dataAvailable ())
00245 {
00246 CInetAddress addr;
00247 uint len = 10000;
00248 UdpSock.receivedFrom (buffer, len, addr);
00249
00250 if ((float)rand()/(float)(RAND_MAX)*100.0f >= _InPacketLoss)
00251 {
00252 CBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, _InLag, &addr);
00253 BufferizedInPackets.push (bp);
00254 }
00255 }
00256
00257 TTime ct = CTime::getLocalTime ();
00258 if (!BufferizedInPackets.empty() && BufferizedInPackets.front ()->Time <= ct)
00259 return true;
00260 else
00261 return false;
00262 }
00263 else
00264 {
00265 return UdpSock.dataAvailable ();
00266 }
00267 }
00268
00269 bool CUdpSimSock::receive (uint8 *buffer, uint32& len, bool throw_exception)
00270 {
00271 if (_InLag> 0)
00272 {
00273 if (BufferizedInPackets.empty())
00274 {
00275 if (throw_exception)
00276 throw Exception ("no data available");
00277 return false;
00278 }
00279
00280 CBufferizedOutPacket *bp = BufferizedInPackets.front ();
00281 uint32 s = min (len, bp->PacketSize);
00282 memcpy (buffer, bp->Packet, s);
00283 len = s;
00284
00285 delete bp;
00286 BufferizedInPackets.pop ();
00287 return true;
00288 }
00289 else
00290 {
00291 return UdpSock.receive(buffer, len, throw_exception);
00292 }
00293 }
00294
00295 CSock::TSockResult CUdpSimSock::send (const uint8 *buffer, uint32& len, bool throw_exception)
00296 {
00297 sendUDP (buffer, len);
00298 return CSock::Ok;
00299 }
00300
00301 void CUdpSimSock::sendTo (const uint8 *buffer, uint32& len, const CInetAddress& addr)
00302 {
00303 sendUDP (buffer, len, &addr);
00304 }
00305
00306 bool CUdpSimSock::connected()
00307 {
00308 return UdpSock.connected ();
00309 }
00310
00311 }