1 /////////////////////////////////////////
2 //
3 // OpenLieroX
4 //
5 // work by JasonB
6 // code under LGPL
7 // enhanced by Dark Charlie and Albert Zeyer
8 //
9 //
10 /////////////////////////////////////////
11
12
13 // Network Channel class
14 // Created 16/6/01
15 // Jason Boettcher
16
17
18 #include <map>
19
20 #include "LieroX.h"
21 #include "Debug.h"
22 #include "CChannel.h"
23 #include "StringUtils.h"
24 #include "Timer.h"
25 #include "MathLib.h"
26
27
28
29 // default max size for UDP packets for windows is 1280
30 // only a size of 512 is guaranteed
31 enum {
32 MAX_PACKET_SIZE = 512,
33 RELIABLE_HEADER_LEN = 8 // Only for CChannel_056b
34 };
35
Clear()36 void CChannel::Clear()
37 {
38 Socket = NULL;
39 iPacketsDropped = 0;
40 iPacketsGood = 0;
41 cIncomingRate.clear();
42 cOutgoingRate.clear();
43 iOutgoingBytes = 0;
44 iIncomingBytes = 0;
45 iPing = 0;
46 fLastSent = fLastPckRecvd = fLastPingSent = AbsTime();
47 iCurrentIncomingBytes = 0;
48 iCurrentOutgoingBytes = 0;
49 Messages.clear();
50
51 ReliableStreamBandwidthCounter = 0.0f;
52 ReliableStreamLastSentTime = tLX->currentTime;
53 ReliableStreamBandwidthCounterLastUpdate = tLX->currentTime;
54 LimitReliableStreamBandwidth( -1.0f, 5.0f, 1024.0f );
55 }
56
57 ///////////////////
58 // Setup the channel
Create(const NetworkAddr & _adr,const SmartPointer<NetworkSocket> & _sock)59 void CChannel::Create(const NetworkAddr& _adr, const SmartPointer<NetworkSocket>& _sock)
60 {
61 Clear();
62 RemoteAddr = _adr;
63 fLastPckRecvd = tLX->currentTime;
64 Socket = _sock;
65 fLastSent = AbsTime();
66 fLastPingSent = fLastSent;
67 iPing = 0;
68 }
69
70 ////////////////////
71 // Adds a packet to reliable queue
AddReliablePacketToSend(CBytestream & bs)72 void CChannel::AddReliablePacketToSend(CBytestream& bs)
73 {
74 if (bs.GetLength() > MAX_PACKET_SIZE - RELIABLE_HEADER_LEN) {
75 warnings
76 << "trying to send a reliable packet of size " << bs.GetLength()
77 << " which is bigger than allowed size (" << (MAX_PACKET_SIZE - RELIABLE_HEADER_LEN)
78 << "), packet might not be sent at all!" << endl;
79 Messages.push_back(bs); // Try to send it anyway, perhaps we're lucky...
80 return;
81 }
82
83 if(bs.GetLength() == 0)
84 return;
85
86 Messages.push_back(bs);
87 // The messages are joined in Transmit() in one bigger packet, until it will hit bandwidth limit
88 }
89
UpdateTransmitStatistics(int sentDataSize)90 void CChannel::UpdateTransmitStatistics( int sentDataSize )
91 {
92 // Update statistics
93 iOutgoingBytes += sentDataSize;
94 iCurrentOutgoingBytes += sentDataSize;
95 fLastSent = tLX->currentTime;
96
97 // Calculate the bytes per second
98 cOutgoingRate.addData( tLX->currentTime, sentDataSize );
99 }
100
UpdateReceiveStatistics(int receivedDataSize)101 void CChannel::UpdateReceiveStatistics( int receivedDataSize )
102 {
103 // Got a packet (good or bad), update the received time
104 fLastPckRecvd = tLX->currentTime;
105
106 // Update statistics - calculate the bytes per second
107 // TODO: it was Bytestream->GetRestLen() before for iIncomingBytes and iCurrentIncomingBytes,
108 // so skipped packet header, I think it's not that important, check this Albert and remove this TODO
109 iIncomingBytes += receivedDataSize;
110 iCurrentIncomingBytes += receivedDataSize;
111 cIncomingRate.addData( tLX->currentTime, receivedDataSize );
112 }
113
LimitReliableStreamBandwidth(float BandwidthLimit,float MaxPacketRate,float BandwidthCounterMaxValue)114 void CChannel::LimitReliableStreamBandwidth( float BandwidthLimit, float MaxPacketRate, float BandwidthCounterMaxValue )
115 {
116 ReliableStreamBandwidthLimit = BandwidthLimit;
117 ReliableStreamMaxPacketRate = MaxPacketRate;
118 ReliableStreamBandwidthCounterMaxValue = BandwidthCounterMaxValue;
119 // That's all, we won't reset ReliableStreamBandwidthCounter here
120 }
121
UpdateReliableStreamBandwidthCounter()122 void CChannel::UpdateReliableStreamBandwidthCounter()
123 {
124 ReliableStreamBandwidthCounter +=
125 ( tLX->currentTime - ReliableStreamBandwidthCounterLastUpdate ).seconds() *
126 ReliableStreamBandwidthLimit;
127
128 ReliableStreamBandwidthCounterLastUpdate = tLX->currentTime;
129
130 if( ReliableStreamBandwidthCounter > ReliableStreamBandwidthCounterMaxValue )
131 ReliableStreamBandwidthCounter = ReliableStreamBandwidthCounterMaxValue;
132 }
133
CheckReliableStreamBandwidthLimit(float dataSizeToSend)134 bool CChannel::CheckReliableStreamBandwidthLimit( float dataSizeToSend )
135 {
136 if( ReliableStreamBandwidthLimit <= 0 ) // No bandwidth limit
137 return true;
138
139 if( ReliableStreamBandwidthCounter >= dataSizeToSend ||
140 // Allow sending packets that exceed MaxValue, if Counter == MaxValue, then Counter will become negative
141 ReliableStreamBandwidthCounter >= ReliableStreamBandwidthCounterMaxValue )
142 {
143 ReliableStreamBandwidthCounter -= dataSizeToSend;
144 ReliableStreamLastSentTime = tLX->currentTime;
145 return true;
146 }
147
148 return false;
149 }
150
ReliableStreamBandwidthLimitHit()151 bool CChannel::ReliableStreamBandwidthLimitHit()
152 {
153 if( ReliableStreamBandwidthLimit <= 0 ||
154 ReliableStreamBandwidthCounter >= ReliableStreamBandwidthCounterMaxValue / 2.0f ||
155 ReliableStreamLastSentTime + 1.0f / ReliableStreamMaxPacketRate <= tLX->currentTime )
156 return false;
157 return true;
158 }
159
160 ///////////////////
161 // CChannel for LX 0.56b implementation - LOSES PACKETS, and that cannot be fixed.
162
Clear()163 void CChannel_056b::Clear()
164 {
165 CChannel::Clear();
166 iOutgoingSequence = 0;
167 iReliableSequence = 0;
168 iLast_ReliableSequence = 0;
169 iIncoming_ReliableSequence = 0;
170 iIncomingSequence = 0;
171 iIncomingAcknowledged = 0;
172 iOutgoingBytes = 0;
173 iIncomingBytes = 0;
174 fLastSent = AbsTime();
175 bNewReliablePacket = false;
176 iPongSequence = -1;
177 Reliable.Clear();
178 }
179
Create(const NetworkAddr & _adr,const SmartPointer<NetworkSocket> & _sock)180 void CChannel_056b::Create(const NetworkAddr& _adr, const SmartPointer<NetworkSocket>& _sock)
181 {
182 Clear();
183 CChannel::Create( _adr, _sock );
184 }
185
186 ///////////////////
187 // Transmitt data, as well as handling reliable packets
Transmit(CBytestream * bs)188 void CChannel_056b::Transmit( CBytestream *bs )
189 {
190 UpdateReliableStreamBandwidthCounter();
191
192 CBytestream outpack;
193 Uint32 SendReliable = 0;
194 ulong r1,r2;
195
196 // If the remote side dropped the last reliable packet, re-send it
197 if( iIncomingAcknowledged > iLast_ReliableSequence &&
198 iIncoming_ReliableAcknowledged != iReliableSequence &&
199 CheckReliableStreamBandwidthLimit( (float)Reliable.GetLength() ) )
200 {
201 //hints << "Remote side dropped a reliable packet, resending..." << endl;
202 SendReliable = 1;
203 }
204
205
206 // We send reliable message in these cases:
207 // 1. The reliable buffer is empty, we copy the reliable message into it and send it
208 // 2. We need to refresh ping
209 if( Reliable.GetLength() == 0 &&
210 ! ReliableStreamBandwidthLimitHit() &&
211 ( !Messages.empty() || (tLX->currentTime >= fLastPingSent + 1.0f && iPongSequence == -1)))
212 {
213 while( ! Messages.empty() &&
214 Reliable.GetLength() + Messages.front().GetLength() <= MAX_PACKET_SIZE - RELIABLE_HEADER_LEN &&
215 CheckReliableStreamBandwidthLimit( (float)Messages.front().GetLength() ) )
216 {
217 Reliable.Append( & Messages.front() );
218 Messages.pop_front();
219 }
220
221 // XOR the reliable sequence
222 iReliableSequence ^= 1;
223
224 // We got a reliable packet to send
225 SendReliable = 1;
226 }
227
228 // Create the reliable packet header
229 r1 = iOutgoingSequence | (SendReliable << 31);
230 r2 = iIncomingSequence | (iIncoming_ReliableSequence << 31);
231
232 iOutgoingSequence++;
233
234 outpack.writeInt(r1,4);
235 outpack.writeInt(r2,4);
236
237
238 // If were sending a reliable message, send it first
239 if(SendReliable) {
240 outpack.Append(&Reliable);
241 iLast_ReliableSequence = iOutgoingSequence - 1;
242
243 // If we are sending a reliable message, remember this time and use it for ping calculations
244 if (iPongSequence == -1) {
245 iPongSequence = iOutgoingSequence - 1;
246 fLastPingSent = tLX->currentTime; //GetTime();
247 }
248
249 }
250
251 // And add on the un reliable data if room in the packet struct
252 if(bs) {
253 if(outpack.GetLength() + bs->GetLength() < 4096) // Backward compatibility, the old bytestream has a fixed buffer of 4096 bytes
254 outpack.Append(bs);
255 else
256 hints << "Not adding unrealiable data to avoid too big packets" << endl;
257 }
258
259
260 // Send the packet
261 Socket->setRemoteAddress(RemoteAddr);
262 outpack.Send(Socket.get());
263
264 UpdateTransmitStatistics( outpack.GetLength() );
265 }
266
267
268 ///////////////////
269 // Process channel (after receiving data)
Process(CBytestream * bs)270 bool CChannel_056b::Process(CBytestream *bs)
271 {
272 Uint32 Sequence, SequenceAck;
273 Uint32 ReliableAck, ReliableMessage;
274 int drop;
275
276 // Start from the beginning of the packet
277 bs->ResetPosToBegin();
278 if( bs->GetLength() == 0 )
279 return false;
280
281 UpdateReceiveStatistics( bs->GetLength() );
282
283 // Read the reliable packet header
284 Sequence = bs->readInt(4);
285 SequenceAck = bs->readInt(4);
286
287 // Get the reliable bits
288 ReliableMessage = Sequence >> 31;
289 ReliableAck = SequenceAck >> 31;
290
291 // Get rid of the reliable bits
292 Sequence &= ~(1<<31);
293 SequenceAck &= ~(1<<31);
294
295 // Get rid of the old packets
296 // Small hack: there's a bug in old clients causing the first packet being ignored and resent later
297 // It caused a delay when joining (especially on high-ping servers), this hack improves it
298 if((Sequence <= iIncomingSequence) && (Sequence != 0 && iIncomingSequence != 0)) {
299 // warnings << "Packet dropped" << endl;
300 // bs->Dump();
301 /*
302 If we didn't ignore it here, we would become it
303 again (the remote side will resend it because it thinks we've dropped
304 the packet) and then parse it again => doubled text etc */
305 // see GameServer::ReadPackets and CClient::ReadPackets
306 // or perhaps it's ok to return true here but we should change the behaviour in *::ReadPackets
307 return false;
308 }
309
310
311 // Check for dropped packets
312 drop = Sequence - (iIncomingSequence+1);
313 if(drop>0)
314 // Update statistics
315 iPacketsDropped++;
316
317
318 // If the outgoing reliable message has been acknowledged, clear it for more reliable messages
319 if(ReliableAck == iReliableSequence)
320 Reliable.Clear();
321
322 // Check if pong has been acknowledged
323 if(SequenceAck >= (size_t)iPongSequence) {
324 iPongSequence = -1; // Ready for new pinging
325 iPing = (int)((tLX->currentTime - fLastPingSent).milliseconds());
326 }
327
328
329 // If this packet contained a reliable message, update the sequences
330 iIncomingSequence = Sequence;
331 iIncomingAcknowledged = SequenceAck;
332 iIncoming_ReliableAcknowledged = ReliableAck;
333 if(ReliableMessage) {
334 iIncoming_ReliableSequence ^= 1;
335 bNewReliablePacket = true;
336 } else
337 bNewReliablePacket = false;
338
339
340 // Update the statistics
341 iPacketsGood++;
342
343
344 return true;
345 }
346
347
recheckSeqs()348 void CChannel_056b::recheckSeqs() {
349 // Ensure the incoming sequence matchs the outgoing sequence
350 if (this->getInSeq() >= this->getOutSeq()) {
351 //if (chan->getInSeq() != chan->getOutSeq())
352 // warnings << cl->getWorm(0)->getName() << ": sequences not same (IN: " << chan->getInSeq() << ", OUT: " << chan->getOutSeq() << ")" << endl;
353 //else
354 // hints << cl->getWorm(0)->getName() << ": sequences match!! (" << chan->getInSeq() << ")" << endl;*/
355 this->setOutSeq(this->getInSeq());
356 } else {
357 // Sequences have slipped
358 // Karel said: it's bullshit from JasonB, so we can ignore this warning :)
359 //warnings << cl->getWorm(0)->getName() << ": sequences have slipped (IN: " << chan->getInSeq() << ", OUT: " << chan->getOutSeq() << ")" << endl;
360 // TODO: Set the player's send_data property to false
361 }
362 }
363
364
365 ///////////////////
366 // Reliable CChannel implementation by pelya ( I hope it's less messy, though it has more code ).
367
368 /*
369 There are logical packets, each has it's own sequence number,
370 multiple logical packets can be transmitted in single net packet.
371 CChannel2::Process(CBytestream *) will return the logical packets one by one,
372 without merging them in one packet, to increase robustness.
373 It will modify CBytestream * argument for that.
374 The net packet format is:
375 Acknowledged Packet Index 1 - 2 bytes, highest bit = 1
376 ...
377 Acknowledged Packet Index N - 2 bytes, highest bit = 1
378 Last Acknowledged Packet Index - 2 bytes, highest bit = 0 (marks end of acknowledged packets list) -
379 should be the lowest acknowledged sequence, all packets with lower
380 sequences are considered acknowledged.
381 Packet Index 1 - 2 bytes, highest bit = 1
382 Packet Size 1 - 2 bytes
383 ...
384 Packet Index N - 2 bytes, highest bit = 1
385 Packet Size N - 2 bytes
386 Last Packet Index - 2 bytes, highest bit = 0 (marks end of packets list)
387 Last Packet Size - 2 bytes, if we don't have reliable packet then Last Packet Size == 0, Last Packet Index ignored.
388 Packets data
389 Non-reliable packet data
390
391 Only Last Acknowledged Packet Index and Last Packet Index are mandatory -
392 then CChannel will act like old CChannel_056b, when only one packet is allowed
393 to be flying through network at any time.
394 */
395
396 enum {
397
398 // SEQUENCE_WRAPAROUND is where sequence wraps to zero - sequence range is from 0 to SEQUENCE_WRAPAROUND-1.
399 // All sequences (or packet indexes) used are wrapping around at this number
400 // We cannot allow four leadinf 0xFF bytes in reliable packet, so SEQUENCE_WRAPAROUND
401 // is slightly less than 0x7FFF.
402 SEQUENCE_WRAPAROUND = 32766,
403
404 // SEQUENCE_SAFE_DIST is the max distance between two sequences when packets will get ignored as erroneous ones.
405 SEQUENCE_SAFE_DIST = 100,
406
407 // MAX_NON_ACKNOWLEDGED_PACKETS is max amount of packets that can be flying through the net at the same time.
408 MAX_NON_ACKNOWLEDGED_PACKETS = 3, // 1 is minimum - it behaves like old CChannel then.
409
410 // SEQUENCE_HIGHEST_BIT is highest bit in a 2-byte int, for convenience.
411 SEQUENCE_HIGHEST_BIT = 0x8000
412 };
413
414 // How much to wait before sending another empty keep-alive packet, sec.
415 const float KEEP_ALIVE_PACKET_TIMEOUT = 1.0f;
416
417 // How much to wait before sending data packet again, sec -
418 // if packets rarely get lost over net it will decrease bandwidth dramatically, for little lag tradeoff.
419 // Set to 0 to flood net with packets instantly as in CChannel_056b.
420 // If any new data available to send, or unreliable data present, packet is sent anyway.
421 // This is only inital value, it will get changed with time according to ping.
422 const float DATA_PACKET_TIMEOUT = 0.2f;
423
424 // DataPacketTimeout = ping / DATA_PACKET_TIMEOUT_PING_COEFF,
425 // the bigger that value is, the more often channel will re-send data delayed in network.
426 const float DATA_PACKET_TIMEOUT_PING_COEFF = 1.5f;
427
428 #ifdef DEBUG
429 const float DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY = 0.0f; // Self-explanatory
430 #endif
431
432 // Do not check "if( sequence1 < sequence2 )", use this function instead, it will handle wraparound issues.
433 // SequenceDiff( 32765, 32764 ) equals to SequenceDiff( 0, 32765 ) equals to SequenceDiff( 1, 0 ) equals to 1.
SequenceDiff(int s1,int s2)434 int SequenceDiff( int s1, int s2 )
435 {
436 int diff = s1 - s2;
437 while( diff > SEQUENCE_WRAPAROUND / 2 - 1 )
438 diff -= SEQUENCE_WRAPAROUND;
439 while( diff < - (SEQUENCE_WRAPAROUND / 2) )
440 diff += SEQUENCE_WRAPAROUND;
441 return diff;
442 }
443
Clear()444 void CChannel2::Clear()
445 {
446 CChannel::Clear();
447 Messages.clear();
448 ReliableOut.clear();
449 ReliableIn.clear();
450 LastReliableOut = 0;
451 LastAddedToOut = 0;
452 LastReliableIn = 0;
453 PongSequence = -1;
454 LastReliablePacketSent = SEQUENCE_WRAPAROUND - 1;
455 NextReliablePacketToSend = 0;
456 LastReliableIn_SentWithLastPacket = SEQUENCE_WRAPAROUND - 1;
457
458 KeepAlivePacketTimeout = KEEP_ALIVE_PACKET_TIMEOUT;
459 DataPacketTimeout = DATA_PACKET_TIMEOUT;
460 MaxNonAcknowledgedPackets = MAX_NON_ACKNOWLEDGED_PACKETS;
461
462 #ifdef DEBUG
463 DebugSimulateLaggyConnectionSendDelay = tLX->currentTime;
464 #endif
465 };
466
Create(const NetworkAddr & _adr,const SmartPointer<NetworkSocket> & _sock)467 void CChannel2::Create(const NetworkAddr& _adr, const SmartPointer<NetworkSocket>& _sock)
468 {
469 Clear();
470 CChannel::Create( _adr, _sock );
471 }
472
473 // Get reliable packet from local buffer
GetPacketFromBuffer(CBytestream * bs)474 bool CChannel2::GetPacketFromBuffer(CBytestream *bs)
475 {
476 if( ReliableIn.size() == 0 )
477 return false;
478
479 int seqMin = LastReliableIn;
480 PacketList_t::iterator itMin = ReliableIn.end();
481 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end(); it++ )
482 {
483 if( SequenceDiff( seqMin, it->second ) >= 0 )
484 {
485 seqMin = it->second;
486 itMin = it;
487 };
488 };
489 if( itMin != ReliableIn.end() )
490 {
491 *bs = itMin->first;
492 ReliableIn.erase(itMin);
493 return true;
494 };
495 return false;
496 }
497
498 // This function will first return non-reliable data,
499 // and then one or many reliable packets - it will modify bs for that,
500 // so you should call it in a loop, clearing bs after each call.
Process(CBytestream * bs)501 bool CChannel2::Process(CBytestream *bs)
502 {
503 bs->ResetPosToBegin();
504 if( bs->GetLength() == 0 )
505 return GetPacketFromBuffer(bs);
506
507 UpdateReceiveStatistics( bs->GetLength() );
508
509 // Acknowledged packets info processing
510
511 // Read acknowledged packets indexes
512 unsigned seqAck = bs->readInt(2);
513 std::vector< int > seqAckList;
514 while( seqAck & SEQUENCE_HIGHEST_BIT )
515 {
516 seqAckList.push_back( seqAck & ~ SEQUENCE_HIGHEST_BIT );
517 seqAck = bs->readInt(2);
518 };
519 if( SequenceDiff( seqAck, LastReliableOut ) < 0 || SequenceDiff( seqAck, LastReliableOut ) > SEQUENCE_SAFE_DIST )
520 {
521 iPacketsDropped++; // Update statistics
522 return GetPacketFromBuffer(bs); // Packet from the past or from too distant future - ignore it.
523 };
524
525 LastReliableOut = seqAck;
526
527 iPacketsGood++; // Update statistics
528
529 // Delete acknowledged packets from buffer
530 for( PacketList_t::iterator it = ReliableOut.begin(); it != ReliableOut.end(); )
531 {
532 bool erase = false;
533 if( SequenceDiff( LastReliableOut, it->second ) >= 0 )
534 erase = true;
535 for( unsigned f=0; f<seqAckList.size(); f++ )
536 if( seqAckList[f] == it->second )
537 erase = true;
538 if(erase)
539 it = ReliableOut.erase(it);
540 else
541 it++;
542 }
543
544 // Calculate ping ( with LastReliableOut, not with last packet - should be fair enough )
545 if( PongSequence != -1 && SequenceDiff( LastReliableOut, PongSequence ) >= 0 )
546 {
547 iPing = (int) ((tLX->currentTime - fLastPingSent).milliseconds());
548 PongSequence = -1;
549 // Traffic shaping occurs here - change DataPacketTimeout according to received ping
550 // Change the value slowly, to avoid peaks
551 // TODO: I haven't really tested it this thing does any good, but it seems to work okay.
552 DataPacketTimeout = ( iPing/1000.0f/DATA_PACKET_TIMEOUT_PING_COEFF + DataPacketTimeout*9.0f ) / 10.0f;
553 };
554
555 // Processing of arrived data packets
556
557 // Read packets info
558 std::vector< int > seqList;
559 std::vector< int > seqSizeList;
560 unsigned seq = bs->readInt(2);
561 while( seq & SEQUENCE_HIGHEST_BIT )
562 {
563 seqList.push_back( seq & ~ SEQUENCE_HIGHEST_BIT );
564 seqSizeList.push_back( bs->readInt(2) );
565 seq = bs->readInt(2);
566 };
567 seqList.push_back( seq );
568 seqSizeList.push_back( bs->readInt(2) );
569
570 // Put packets in buffer
571 for( unsigned f=0; f<seqList.size(); f++ )
572 {
573 if( seqSizeList[f] == 0 ) // Last reliable packet may have size 0, if we're received non-reliable-only net packet
574 continue; // Just skip it, it's fake packet
575
576 bool addPacket = true;
577 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end() && addPacket; it++ )
578 if( it->second == seqList[f] )
579 addPacket = false;
580 if( addPacket && SequenceDiff( seqList[f], LastReliableIn ) > 0 ) // Do not add packets from the past
581 { // Packet not in buffer yet - add it
582 CBytestream bs1;
583 bs1.writeData( bs->readData(seqSizeList[f]) );
584 ReliableIn.push_back( std::make_pair( bs1, seqList[f] ) );
585 }
586 else // Packet is in buffer already
587 {
588 // We may check here if arrived packet is the same as packet in buffer, and print errors.
589 bs->Skip( seqSizeList[f] );
590 };
591 }
592
593 // Increase LastReliableIn until the first packet that is missing from sequence
594 while( true ) // I just love such constructs :P don't worry, I've put "break" inside the loop.
595 {
596 bool nextPacketFound = false;
597 int LastReliableInInc = LastReliableIn + 1; // Next value of LastReliableIn
598 if( LastReliableInInc >= SEQUENCE_WRAPAROUND )
599 LastReliableInInc = 0;
600 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end() && !nextPacketFound; it++ )
601 if( it->second == LastReliableInInc )
602 nextPacketFound = true;
603 if( nextPacketFound )
604 LastReliableIn = LastReliableInInc;
605 else
606 break;
607 };
608
609 if( bs->GetRestLen() > 0 ) // Non-reliable data left in this packet
610 return true; // Do not modify bs, allow user to read non-reliable data at the end of bs
611
612 if( GetPacketFromBuffer(bs) ) // We can return some reliable packet
613 return true;
614
615 // We've got valid empty packet, or packet from future, return empty packet - bs->GetRestLen() == 0 here.
616 // It is required to update server statistics, so clients that don't send packets won't timeout.
617 return true;
618 };
619
Transmit(CBytestream * unreliableData)620 void CChannel2::Transmit(CBytestream *unreliableData)
621 {
622 UpdateReliableStreamBandwidthCounter();
623
624 #ifdef DEBUG
625 // Very simple laggy connection emulation - send next packet once per DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY
626 if( DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY > 0.0f )
627 {
628 if( DebugSimulateLaggyConnectionSendDelay > tLX->currentTime )
629 return;
630 DebugSimulateLaggyConnectionSendDelay = tLX->currentTime + DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY;
631 }
632 #endif
633
634 CBytestream bs;
635 // Add acknowledged packets indexes
636
637 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end(); it++ )
638 if( SequenceDiff( it->second, LastReliableIn ) > 0 ) // Packets out of sequence
639 bs.writeInt( it->second | SEQUENCE_HIGHEST_BIT, 2 );
640
641 bs.writeInt( LastReliableIn, 2 );
642
643 // Add reliable packet to ReliableOut buffer
644 while( (int)ReliableOut.size() < MaxNonAcknowledgedPackets && ! Messages.empty() && ! ReliableStreamBandwidthLimitHit() )
645 {
646 LastAddedToOut ++ ;
647 if( LastAddedToOut >= SEQUENCE_WRAPAROUND )
648 LastAddedToOut = 0;
649
650 ReliableOut.push_back( std::make_pair( Messages.front(), LastAddedToOut ) );
651 Messages.pop_front();
652
653 while( ! Messages.empty() &&
654 ReliableOut.back().first.GetLength() + Messages.front().GetLength() <= MAX_PACKET_SIZE - RELIABLE_HEADER_LEN )
655 {
656 ReliableOut.back().first.Append( & Messages.front() );
657 Messages.pop_front();
658 }
659 };
660
661 // Check if other side acknowledged packets with indexes bigger than NextReliablePacketToSend,
662 // and roll NextReliablePacketToSend back to LastReliableOut.
663 if( ! ReliableOut.empty() )
664 {
665 for( PacketList_t::iterator it = ReliableOut.begin(), it1 = it++; it != ReliableOut.end(); it1 = it++ )
666 {
667 if( SequenceDiff( it->second, it1->second ) != 1 )
668 NextReliablePacketToSend = LastReliableOut;
669 };
670 if( ReliableOut.back().second != LastAddedToOut )
671 NextReliablePacketToSend = LastReliableOut;
672 };
673
674 // Timeout occured - other side didn't acknowledge our packets in time - re-send all of them from the first one.
675 if( LastReliablePacketSent == LastAddedToOut &&
676 SequenceDiff( LastReliablePacketSent, LastReliableOut ) >= MaxNonAcknowledgedPackets &&
677 tLX->currentTime - fLastSent >= DataPacketTimeout )
678 {
679 NextReliablePacketToSend = LastReliableOut;
680 }
681
682 // Add packet headers and data - send all packets with indexes from NextReliablePacketToSend and up.
683 // Add older packets to the output first.
684 // NextReliablePacketToSend points to the last packet.
685 CBytestream packetData;
686 bool unreliableOnly = true;
687 bool firstPacket = true; // Always send first packet, even if it bigger than MAX_PACKET_SIZE
688 int packetIndex = LastReliableOut;
689 int packetSize = 0;
690
691 for( PacketList_t::iterator it = ReliableOut.begin(); it != ReliableOut.end(); it++ )
692 {
693 if( SequenceDiff( it->second, NextReliablePacketToSend ) >= 0 )
694 {
695 if( ! CheckReliableStreamBandwidthLimit( (float)(it->first.GetLength() + 4) ) ||
696 ( bs.GetLength() + 4 + packetData.GetLength() + it->first.GetLength() > MAX_PACKET_SIZE && ! firstPacket ) )
697 break;
698
699 if( !firstPacket )
700 {
701 bs.writeInt( packetIndex | SEQUENCE_HIGHEST_BIT, 2 );
702 bs.writeInt( packetSize, 2 );
703 };
704 packetIndex = it->second;
705 packetSize = it->first.GetLength();
706
707 firstPacket = false;
708 unreliableOnly = false;
709 NextReliablePacketToSend = it->second;
710
711 packetData.Append( &it->first );
712 };
713 };
714
715 bs.writeInt( packetIndex, 2 );
716 bs.writeInt( packetSize, 2 );
717
718 bs.Append( &packetData );
719
720 if( unreliableOnly )
721 bs.Append(unreliableData);
722 else
723 {
724 if( bs.GetLength() + unreliableData->GetLength() <= MAX_PACKET_SIZE )
725 bs.Append(unreliableData);
726
727 // If we are sending a reliable message, remember this time and use it for ping calculations
728 if (PongSequence == -1)
729 {
730 PongSequence = NextReliablePacketToSend;
731 fLastPingSent = tLX->currentTime;
732 };
733 };
734
735 if( unreliableData->GetLength() == 0 &&
736 LastReliablePacketSent == LastAddedToOut &&
737 tLX->currentTime - fLastSent < DataPacketTimeout )
738 {
739 // No unreliable data to send, and we've just sent the same packet -
740 // send it again after some timeout, don't flood net.
741 return;
742 };
743
744 if( unreliableData->GetLength() == 0 && packetData.GetLength() == 0 &&
745 LastReliableIn == LastReliableIn_SentWithLastPacket &&
746 tLX->currentTime - fLastSent < KeepAlivePacketTimeout )
747 {
748 // Nothing to send really, send one empty packet per halfsecond so we won't timeout,
749 // but always send first packet with acknowledges, or other side will flood
750 // non-acknowledged packets for halfsecond.
751 // CChannel_056b will always send packet on each frame, so we're conserving bandwidth compared to it, hehe.
752
753 cOutgoingRate.addData( tLX->currentTime, 0 );
754 return;
755 }
756
757 // Send the packet
758 Socket->setRemoteAddress(RemoteAddr);
759 bs.Send(Socket.get());
760
761 LastReliableIn_SentWithLastPacket = LastReliableIn;
762 LastReliablePacketSent = NextReliablePacketToSend;
763
764 UpdateTransmitStatistics( bs.GetLength() );
765 }
766
767
768 ///////////////////
769 // Robustness test for CChannel
770
printBinary(const std::string & s)771 std::string printBinary(const std::string & s)
772 {
773 std::string r;
774 char buf[10];
775 for(size_t f=0; f<s.size(); f++)
776 {
777 sprintf( buf, "%02X ", (unsigned)( (unsigned char)s[f] ) );
778 r += buf;
779 }
780 return r;
781 }
782
TestCChannelRobustness()783 void TestCChannelRobustness()
784 {
785 notes << "Testing CBytestream" << endl;
786 CBytestream bsTest;
787 bsTest.Test();
788 notes << "\n\n\n\nTesting CChannel robustness" << endl;
789 int lagMin = 50;
790 int lagMax = 400;
791 int packetLoss = 15; // In percents
792 float packetsPerSecond1 = 10.0f; // One channel sends faster than another
793 float packetsPerSecond2 = 0.2f;
794 int packetExtraData = 8192; // Extra data in bytes to add to packet to check buffer overflows
795
796 CChannel3 c1, c2; //CChannel_056b c1, c2;
797 SmartPointer<NetworkSocket> s1 = new NetworkSocket(); s1->OpenUnreliable(0);
798 SmartPointer<NetworkSocket> s2 = new NetworkSocket(); s2->OpenUnreliable(0);
799 SmartPointer<NetworkSocket> s1lag = new NetworkSocket(); s1lag->OpenUnreliable(0);
800 SmartPointer<NetworkSocket> s2lag = new NetworkSocket(); s2lag->OpenUnreliable(0);
801 NetworkAddr a1, a2, a1lag, a2lag;
802 a1 = s1->localAddress();
803 a2 = s2->localAddress();
804 a1lag = s1lag->localAddress();
805 a2lag = s2lag->localAddress();
806 c1.Create( a1lag, s1 );
807 c2.Create( a2lag, s2 );
808 s1lag->setRemoteAddress( a2 );
809 s2lag->setRemoteAddress( a1 );
810
811 std::multimap< int, CBytestream > s1buf, s2buf;
812
813 int i1=0, i2=0, i1r=0, i2r=0;
814 float packetDelay1 = 10000000;
815 if( packetsPerSecond1 > 0 )
816 packetDelay1 = 1000.0f / packetsPerSecond1;
817 float packetDelay2 = 10000000;
818 if( packetsPerSecond2 > 0 )
819 packetDelay2 = 1000.0f / packetsPerSecond2;
820 float nextPacket1 = 0;
821 float nextPacket2 = 0;
822 for( int testtime=0; testtime < 100000; testtime+= 10, nextPacket1 += 10, nextPacket2 += 10 )
823 {
824 tLX->currentTime = AbsTime(testtime);
825
826 // Transmit number sequence and some unreliable info
827 CBytestream b1, b2, b1u, b2u;
828
829 if( nextPacket1 >= packetDelay1 )
830 {
831 nextPacket1 = 0;
832 i1++;
833 b1.writeInt(i1, 4);
834 for( int f=0; f<packetExtraData; f++ )
835 b1.writeByte(0xff);
836 c1.AddReliablePacketToSend(b1);
837 }
838
839 if( nextPacket2 >= packetDelay2 )
840 {
841 nextPacket2 = 0;
842 i2++;
843 b2.writeInt(i2, 4);
844 for( int f=0; f<packetExtraData; f++ )
845 b2.writeByte(0xff);
846 c2.AddReliablePacketToSend(b2);
847 }
848
849
850 c1.Transmit( &b1u );
851 c2.Transmit( &b2u );
852
853 b1.Clear();
854 b2.Clear();
855
856 b1.Read(s1lag.get());
857 b2.Read(s2lag.get());
858 b1.ResetPosToBegin();
859 b2.ResetPosToBegin();
860
861 // Add the lag
862 if( b1.GetLength() != 0 )
863 {
864 if( GetRandomInt(100) + 1 < packetLoss )
865 notes << testtime << ": c1 sent packet - lost (" << c1.Messages.size() <<
866 " in buf): " << printBinary(b1.readData()) << endl;
867 else
868 {
869 int lag = ((testtime + lagMin + GetRandomInt(lagMax-lagMin)) / 10)*10; // Round to 10
870 s1buf.insert( std::make_pair( lag, b1 ) );
871 notes<< testtime << ": c1 sent packet - lag " << lag << " size " << b1.GetLength() << " (" << c1.Messages.size() <<
872 " in buf): " << printBinary(b1.readData()) << endl;
873 }
874 }
875
876 for( std::multimap< int, CBytestream > :: iterator it = s1buf.lower_bound(testtime);
877 it != s1buf.upper_bound(testtime); it++ )
878 {
879 it->second.ResetPosToBegin();
880 it->second.ResetPosToBegin();
881 it->second.Send(s1lag.get());
882 }
883
884 if( b2.GetLength() != 0 )
885 {
886 if( GetRandomInt(100) + 1 < packetLoss )
887 notes << testtime << ": c2 sent packet - lost (" << c2.Messages.size() <<
888 " in buf): " << printBinary(b2.readData()) << endl;
889 else
890 {
891 int lag = ((testtime + lagMin + GetRandomInt(lagMax-lagMin)) / 10)*10; // Round to 10
892 s2buf.insert( std::make_pair( lag, b2 ) );
893 notes << testtime << ": c2 sent packet - lag " << lag << " size " << b2.GetLength() << " (" << c2.Messages.size() <<
894 " in buf): " << printBinary(b2.readData()) << endl;
895 }
896 }
897
898 for( std::multimap< int, CBytestream > :: iterator it = s2buf.lower_bound(testtime);
899 it != s2buf.upper_bound(testtime); it++ )
900 {
901 it->second.ResetPosToBegin();
902 it->second.ResetPosToBegin();
903 it->second.Send(s2lag.get());
904 }
905
906 // Receive and check number sequence and unreliable info
907 b1.Clear();
908 b2.Clear();
909
910 b1.Read(s1.get());
911 b2.Read(s2.get());
912 b1.ResetPosToBegin();
913 b2.ResetPosToBegin();
914
915 if( b1.GetLength() != 0 )
916 {
917 notes << testtime << ": c1 recv packet (ping " << c1.getPing() << "): " << printBinary(b1.readData()) << endl;
918 b1.ResetPosToBegin();
919 while( c1.Process( &b1 ) )
920 {
921 while( b1.GetRestLen() != 0 )
922 {
923 int i1rr = b1.readInt(4);
924 notes << testtime << ": c1 reliable packet, data " << hex(i1rr) <<
925 " expected " << i1r+1 << " - " << (i1rr == i1r+1 ? "good" : "ERROR!") << endl;
926 i1r = i1rr;
927 for( int f=0; f<packetExtraData; f++ )
928 b1.readByte();
929 }
930 b1.Clear();
931 }
932 }
933
934 if( b2.GetLength() != 0 )
935 {
936 notes << testtime << ": c2 recv packet (ping " << c2.getPing() << "): " << printBinary(b2.readData()) << endl;
937 b2.ResetPosToBegin();
938 while( c2.Process( &b2 ) )
939 {
940 while( b2.GetRestLen() != 0 )
941 {
942 int i2rr = b2.readInt(4);
943 notes << testtime << ": c2 reliable packet, data " << hex(i2rr) <<
944 " expected " << i2r+1 << " - " << (i2rr == i2r+1 ? "good" : "ERROR!") << endl;
945 i2r = i2rr;
946 for( int f=0; f<packetExtraData; f++ )
947 b2.readByte();
948 }
949 b2.Clear();
950 }
951 }
952
953 }
954 }
955
956 /*
957 The format for packet is the same as with CChannel2, but with CRC16 added at the beginning,
958 and with indicator that packet is split into several smaller packets.
959 Packet won't contain four leading 0xFF because of CRC16, because two other bytes are acknowledged packet index.
960
961 In case Packet Size highest bit = 1 ( SEQUENCE_HIGHEST_BIT ) that means we're transmitting big packet
962 split into several smaller packets. Sequence of packets with Packet Size highest bit = 1 and
963 one packet with Packet Size highest bit = 0 following it is assembled into one big logical packet for user.
964 */
965
966 enum {
967 MAX_FRAGMENTED_PACKET_SIZE = MAX_PACKET_SIZE - 24 // Actually 12 bytes are enough, but I want to have safety bound.
968 };
969
970 Uint16 crc16(const char * buffer, size_t len, Uint16 crc = 0xffff); // Default non-zero value
971
operator <(const Packet_t & p) const972 bool CChannel3::Packet_t::operator < ( const Packet_t & p ) const
973 {
974 return SequenceDiff( idx, p.idx ) < 0;
975 };
976
Clear()977 void CChannel3::Clear()
978 {
979 CChannel::Clear();
980 Messages.clear();
981 ReliableOut.clear();
982 ReliableIn.clear();
983 LastReliableOut = 0;
984 LastAddedToOut = 0;
985 LastReliableIn = 0;
986 PongSequence = -1;
987 LastReliablePacketSent = SEQUENCE_WRAPAROUND - 1;
988 NextReliablePacketToSend = 0;
989 LastReliableIn_SentWithLastPacket = SEQUENCE_WRAPAROUND - 1;
990
991 KeepAlivePacketTimeout = KEEP_ALIVE_PACKET_TIMEOUT;
992 DataPacketTimeout = DATA_PACKET_TIMEOUT;
993 MaxNonAcknowledgedPackets = MAX_NON_ACKNOWLEDGED_PACKETS;
994
995 #ifdef DEBUG
996 DebugSimulateLaggyConnectionSendDelay = tLX->currentTime;
997 #endif
998 }
999
Create(const NetworkAddr & _adr,const SmartPointer<NetworkSocket> & _sock)1000 void CChannel3::Create(const NetworkAddr& _adr, const SmartPointer<NetworkSocket>& _sock)
1001 {
1002 Clear();
1003 CChannel::Create( _adr, _sock );
1004 }
1005
1006 // Get reliable packet from local buffer (merge fragmented packet)
GetPacketFromBuffer(CBytestream * bs)1007 bool CChannel3::GetPacketFromBuffer(CBytestream *bs)
1008 {
1009 if( ReliableIn.size() == 0 )
1010 return false;
1011
1012 bs->Clear();
1013 PacketList_t::iterator it = ReliableIn.begin();
1014 while( it != ReliableIn.end() && it->fragmented )
1015 {
1016 bs->Append( & it->data );
1017 it++;
1018 };
1019 if( it != ReliableIn.end() && it->idx <= LastReliableIn )
1020 {
1021 bs->Append( & it->data );
1022 it++;
1023 ReliableIn.erase( ReliableIn.begin(), it );
1024 return true;
1025 }
1026 bs->Clear();
1027 return false;
1028 }
1029
1030 // This function will first return non-reliable data,
1031 // and then one or many reliable packets - it will modify bs for that,
1032 // so you should call it in a loop, clearing bs after each call.
Process(CBytestream * bs)1033 bool CChannel3::Process(CBytestream *bs)
1034 {
1035 bs->ResetPosToBegin();
1036 if( bs->GetLength() == 0 )
1037 return GetPacketFromBuffer(bs);
1038
1039 UpdateReceiveStatistics( bs->GetLength() );
1040
1041 // CRC16 check
1042
1043 unsigned crc = bs->readInt(2);
1044 if( crc != crc16( bs->peekData( bs->GetRestLen() ).c_str(), bs->GetRestLen() ) )
1045 {
1046 iPacketsDropped++; // Update statistics
1047 return GetPacketFromBuffer(bs); // Packet from the past or from too distant future - ignore it.
1048 }
1049
1050 // Acknowledged packets info processing
1051
1052 // Read acknowledged packets indexes
1053 unsigned seqAck = bs->readInt(2);
1054 std::vector< int > seqAckList;
1055 while( seqAck & SEQUENCE_HIGHEST_BIT )
1056 {
1057 seqAckList.push_back( seqAck & ~ SEQUENCE_HIGHEST_BIT );
1058 seqAck = bs->readInt(2);
1059 }
1060 if( SequenceDiff( seqAck, LastReliableOut ) < 0 || SequenceDiff( seqAck, LastReliableOut ) > SEQUENCE_SAFE_DIST )
1061 {
1062 iPacketsDropped++; // Update statistics
1063 return GetPacketFromBuffer(bs); // Packet from the past or from too distant future - ignore it.
1064 }
1065
1066 LastReliableOut = seqAck;
1067
1068 iPacketsGood++; // Update statistics
1069
1070 // Delete acknowledged packets from buffer
1071 for( PacketList_t::iterator it = ReliableOut.begin(); it != ReliableOut.end(); )
1072 {
1073 bool erase = false;
1074 if( SequenceDiff( LastReliableOut, it->idx ) >= 0 )
1075 erase = true;
1076 for( unsigned f=0; f<seqAckList.size(); f++ )
1077 if( seqAckList[f] == it->idx )
1078 erase = true;
1079 if(erase)
1080 it = ReliableOut.erase(it);
1081 else
1082 it++;
1083 }
1084
1085 // Calculate ping ( with LastReliableOut, not with last packet - should be fair enough )
1086 if( PongSequence != -1 && SequenceDiff( LastReliableOut, PongSequence ) >= 0 )
1087 {
1088 iPing = (int) ((tLX->currentTime - fLastPingSent).milliseconds());
1089 PongSequence = -1;
1090 // Traffic shaping occurs here - change DataPacketTimeout according to received ping
1091 // Change the value slowly, to avoid peaks
1092 DataPacketTimeout = ( iPing/1000.0f/DATA_PACKET_TIMEOUT_PING_COEFF + DataPacketTimeout*9.0f ) / 10.0f;
1093 };
1094
1095 // Processing of arrived data packets
1096
1097 // Read packets info
1098 std::vector< int > seqList;
1099 std::vector< int > seqSizeList;
1100 unsigned seq = bs->readInt(2);
1101 while( seq & SEQUENCE_HIGHEST_BIT )
1102 {
1103 seqList.push_back( seq & ~ SEQUENCE_HIGHEST_BIT );
1104 seqSizeList.push_back( bs->readInt(2) );
1105 seq = bs->readInt(2);
1106 }
1107 seqList.push_back( seq );
1108 seqSizeList.push_back( bs->readInt(2) );
1109
1110 // Put packets in buffer
1111 for( unsigned f=0; f<seqList.size(); f++ )
1112 {
1113 if( seqSizeList[f] == 0 ) // Last reliable packet may have size 0, if we're received non-reliable-only net packet
1114 continue; // Just skip it, it's fake packet
1115
1116 bool addPacket = true;
1117 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end() && addPacket; it++ )
1118 if( it->idx == seqList[f] )
1119 addPacket = false;
1120 if( addPacket && SequenceDiff( seqList[f], LastReliableIn ) > 0 ) // Do not add packets from the past
1121 { // Packet not in buffer yet - add it
1122 CBytestream bs1;
1123 bs1.writeData( bs->readData( seqSizeList[f] & ~ SEQUENCE_HIGHEST_BIT ) );
1124 ReliableIn.push_back( Packet_t( bs1, seqList[f], (seqSizeList[f] & SEQUENCE_HIGHEST_BIT) != 0 ) );
1125 }
1126 else // Packet is in buffer already
1127 {
1128 // We may check here if arrived packet is the same as packet in buffer, and print errors.
1129 bs->Skip( seqSizeList[f] & ~ SEQUENCE_HIGHEST_BIT );
1130 };
1131 }
1132
1133 // Increase LastReliableIn until the first packet that is missing from sequence
1134 while( true ) // I just love such constructs :P don't worry, I've put "break" inside the loop.
1135 {
1136 bool nextPacketFound = false;
1137 int LastReliableInInc = LastReliableIn + 1; // Next value of LastReliableIn
1138 if( LastReliableInInc >= SEQUENCE_WRAPAROUND )
1139 LastReliableInInc = 0;
1140 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end() && !nextPacketFound; it++ )
1141 if( it->idx == LastReliableInInc )
1142 nextPacketFound = true;
1143 if( nextPacketFound )
1144 LastReliableIn = LastReliableInInc;
1145 else
1146 break;
1147 }
1148
1149 // The ReliableIn list updated - sort it
1150 ReliableIn.sort();
1151
1152 if( bs->GetRestLen() > 0 ) // Non-reliable data left in this packet
1153 return true; // Do not modify bs, allow user to read non-reliable data at the end of bs
1154
1155 if( GetPacketFromBuffer(bs) ) // We can return some reliable packet
1156 return true;
1157
1158 // We've got valid empty packet, or packet from future, return empty packet - bs->GetRestLen() == 0 here.
1159 // It is required to update server statistics, so clients that don't send packets won't timeout.
1160 return true;
1161 }
1162
Transmit(CBytestream * unreliableData)1163 void CChannel3::Transmit(CBytestream *unreliableData)
1164 {
1165 UpdateReliableStreamBandwidthCounter();
1166
1167 #ifdef DEBUG
1168 // Very simple laggy connection emulation - send next packet once per DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY
1169 if( DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY > 0.0f )
1170 {
1171 if( DebugSimulateLaggyConnectionSendDelay > tLX->currentTime )
1172 return;
1173 DebugSimulateLaggyConnectionSendDelay = tLX->currentTime + DEBUG_SIMULATE_LAGGY_CONNECTION_SEND_DELAY;
1174 }
1175 #endif
1176
1177 CBytestream bs;
1178 // Add acknowledged packets indexes
1179
1180 for( PacketList_t::iterator it = ReliableIn.begin(); it != ReliableIn.end(); it++ )
1181 if( SequenceDiff( it->idx, LastReliableIn ) > 0 ) // Packets out of sequence
1182 bs.writeInt( it->idx | SEQUENCE_HIGHEST_BIT, 2 );
1183
1184 bs.writeInt( LastReliableIn, 2 );
1185
1186 // Add reliable packet to ReliableOut buffer
1187 while( (int)ReliableOut.size() < MaxNonAcknowledgedPackets && !Messages.empty() && ! ReliableStreamBandwidthLimitHit() )
1188 {
1189 LastAddedToOut ++ ;
1190 if( LastAddedToOut >= SEQUENCE_WRAPAROUND )
1191 LastAddedToOut = 0;
1192
1193 if( Messages.front().GetLength() > MAX_FRAGMENTED_PACKET_SIZE )
1194 {
1195 // Fragment the packet
1196 Messages.front().ResetPosToBegin();
1197 CBytestream bs;
1198 bs.writeData( Messages.front().readData( MAX_FRAGMENTED_PACKET_SIZE ) );
1199 ReliableOut.push_back( Packet_t( bs, LastAddedToOut, true ) );
1200 bs.Clear();
1201 bs.writeData( Messages.front().readData() );
1202 Messages.front() = bs;
1203 }
1204 else
1205 {
1206 ReliableOut.push_back( Packet_t( Messages.front(), LastAddedToOut, false ) );
1207 Messages.pop_front();
1208 while( ! Messages.empty() &&
1209 ReliableOut.back().data.GetLength() + Messages.front().GetLength() <= MAX_FRAGMENTED_PACKET_SIZE )
1210 {
1211 ReliableOut.back().data.Append( & Messages.front() );
1212 Messages.pop_front();
1213 }
1214 }
1215 }
1216
1217 // Check if other side acknowledged packets with indexes bigger than NextReliablePacketToSend,
1218 // and roll NextReliablePacketToSend back to LastReliableOut.
1219 if( ! ReliableOut.empty() )
1220 {
1221 for( PacketList_t::iterator it = ReliableOut.begin(), it1 = it++; it != ReliableOut.end(); it1 = it++ )
1222 {
1223 if( SequenceDiff( it->idx, it1->idx ) != 1 )
1224 NextReliablePacketToSend = LastReliableOut;
1225 }
1226 if( ReliableOut.back().idx != LastAddedToOut )
1227 NextReliablePacketToSend = LastReliableOut;
1228 }
1229
1230 // Timeout occured - other side didn't acknowledge our packets in time - re-send all of them from the first one.
1231 if( LastReliablePacketSent == LastAddedToOut &&
1232 SequenceDiff( LastReliablePacketSent, LastReliableOut ) >= MaxNonAcknowledgedPackets &&
1233 tLX->currentTime - fLastSent >= DataPacketTimeout )
1234 {
1235 NextReliablePacketToSend = LastReliableOut;
1236 }
1237
1238 // Add packet headers and data - send all packets with indexes from NextReliablePacketToSend and up.
1239 // Add older packets to the output first.
1240 // NextReliablePacketToSend points to the last packet.
1241 CBytestream packetData;
1242 bool unreliableOnly = true;
1243 bool firstPacket = true; // Always send first packet, even if it bigger than MAX_PACKET_SIZE
1244 // This should not occur when packets are fragmented
1245 int packetIndex = LastReliableOut;
1246 int packetSize = 0;
1247
1248 for( PacketList_t::iterator it = ReliableOut.begin(); it != ReliableOut.end(); it++ )
1249 {
1250 if( SequenceDiff( it->idx, NextReliablePacketToSend ) >= 0 )
1251 {
1252 if( ! CheckReliableStreamBandwidthLimit( (float)(it->data.GetLength() + 4) ) ||
1253 ( bs.GetLength() + 4 + packetData.GetLength() + it->data.GetLength() > MAX_PACKET_SIZE-2 && !firstPacket ) ) // Substract CRC16 size
1254 break;
1255
1256 if( !firstPacket )
1257 {
1258 bs.writeInt( packetIndex | SEQUENCE_HIGHEST_BIT, 2 );
1259 bs.writeInt( packetSize, 2 );
1260 };
1261 packetIndex = it->idx;
1262 packetSize = it->data.GetLength();
1263 if( it->fragmented )
1264 packetSize |= SEQUENCE_HIGHEST_BIT;
1265
1266 firstPacket = false;
1267 unreliableOnly = false;
1268 NextReliablePacketToSend = it->idx;
1269
1270 packetData.Append( &it->data );
1271 }
1272 }
1273
1274 bs.writeInt( packetIndex, 2 );
1275 bs.writeInt( packetSize, 2 );
1276
1277 bs.Append( &packetData );
1278
1279 if( unreliableOnly )
1280 bs.Append(unreliableData);
1281 else
1282 {
1283 if( bs.GetLength() + unreliableData->GetLength() <= MAX_PACKET_SIZE-2 ) // Substract CRC16 size
1284 bs.Append(unreliableData);
1285
1286 // If we are sending a reliable message, remember this time and use it for ping calculations
1287 if (PongSequence == -1)
1288 {
1289 PongSequence = NextReliablePacketToSend;
1290 fLastPingSent = tLX->currentTime;
1291 }
1292 }
1293
1294 if( unreliableData->GetLength() == 0 &&
1295 LastReliablePacketSent == LastAddedToOut &&
1296 tLX->currentTime - fLastSent < DataPacketTimeout )
1297 {
1298 // No unreliable data to send, and we've just sent the same packet -
1299 // send it again after some timeout, don't flood net.
1300 return;
1301 }
1302
1303 if( unreliableData->GetLength() == 0 && packetData.GetLength() == 0 &&
1304 LastReliableIn == LastReliableIn_SentWithLastPacket &&
1305 tLX->currentTime - fLastSent < KeepAlivePacketTimeout )
1306 {
1307 // Nothing to send really, send one empty packet per halfsecond so we won't timeout,
1308 // but always send first packet with acknowledges, or other side will flood
1309 // non-acknowledged packets for halfsecond.
1310 // CChannel_056b will always send packet on each frame, so we're conserving bandwidth compared to it, hehe.
1311
1312 cOutgoingRate.addData( tLX->currentTime, 0 );
1313 return;
1314 }
1315
1316 // Add CRC16
1317
1318 CBytestream bs1;
1319 bs1.writeInt( crc16( bs.peekData( bs.GetLength() ).c_str(), bs.GetLength() ), 2);
1320 bs1.Append(&bs);
1321
1322 // Send the packet
1323 Socket->setRemoteAddress(RemoteAddr);
1324 bs1.Send(Socket.get());
1325
1326 LastReliableIn_SentWithLastPacket = LastReliableIn;
1327 LastReliablePacketSent = NextReliablePacketToSend;
1328
1329 UpdateTransmitStatistics( bs1.GetLength() );
1330 }
1331
AddReliablePacketToSend(CBytestream & bs)1332 void CChannel3::AddReliablePacketToSend(CBytestream& bs) // The same as in CChannel but without error msg
1333 {
1334 if(bs.GetLength() == 0)
1335 return;
1336
1337 Messages.push_back(bs);
1338 // The messages are joined in Transmit() in one bigger packet, until it will hit bandwidth limit
1339 }
1340
1341
1342 // CRC16 stolen from Linux kernel sources
1343 /** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
1344 Uint16 const crc16_table[256] = {
1345 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
1346 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
1347 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
1348 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
1349 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
1350 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
1351 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
1352 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
1353 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
1354 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
1355 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
1356 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
1357 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
1358 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
1359 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
1360 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
1361 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
1362 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
1363 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
1364 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
1365 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
1366 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
1367 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
1368 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
1369 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
1370 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
1371 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
1372 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
1373 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
1374 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
1375 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
1376 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
1377 };
1378
crc16_byte(Uint16 crc,const Uint8 data)1379 inline Uint16 crc16_byte(Uint16 crc, const Uint8 data)
1380 {
1381 return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
1382 }
1383
1384 /**
1385 * Compute the CRC-16 for the data buffer
1386 *
1387 * @param crc previous CRC value
1388 * @param buffer data pointer
1389 * @param len number of bytes in the buffer
1390 * @return the updated CRC value
1391 */
crc16(const char * buffer,size_t len,Uint16 crc)1392 Uint16 crc16(const char * buffer, size_t len, Uint16 crc )
1393 {
1394 while (len--)
1395 {
1396 crc = crc16_byte(crc, (Uint8)*buffer);
1397 ++buffer;
1398 }
1399 return crc;
1400 }
1401
1402