2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "MsgChannel.h"
39 4 bytes outgoing sequence. high bit will be set if this is a fragmented message.
40 2 bytes optional fragment start byte if fragment bit is set.
41 2 bytes optional fragment length if fragment bit is set. if < FRAGMENT_SIZE, this is the last fragment.
43 If the id is -1, the packet should be handled as an out-of-band
44 message instead of as part of the message channel.
46 All fragments will have the same sequence numbers.
51 #define MAX_PACKETLEN 1400 // max size of a network packet
52 #define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
53 #define FRAGMENT_BIT (1<<31)
55 idCVar net_channelShowPackets( "net_channelShowPackets", "0", CVAR_SYSTEM | CVAR_BOOL, "show all packets" );
56 idCVar net_channelShowDrop( "net_channelShowDrop", "0", CVAR_SYSTEM | CVAR_BOOL, "show dropped packets" );
60 idMsgQueue::idMsgQueue
63 idMsgQueue::idMsgQueue( void ) {
72 void idMsgQueue::Init( int sequence ) {
73 first = last = sequence;
74 startIndex = endIndex = 0;
82 bool idMsgQueue::Add( const byte *data, const int size ) {
83 if ( GetSpaceLeft() < size + 8 ) {
88 WriteLong( sequence );
89 WriteData( data, size );
99 bool idMsgQueue::Get( byte *data, int &size ) {
100 if ( first == last ) {
106 sequence = ReadLong();
107 ReadData( data, size );
108 assert( sequence == first );
115 idMsgQueue::GetTotalSize
118 int idMsgQueue::GetTotalSize( void ) const {
119 if ( startIndex <= endIndex ) {
120 return ( endIndex - startIndex );
122 return ( sizeof( buffer ) - startIndex + endIndex );
128 idMsgQueue::GetSpaceLeft
131 int idMsgQueue::GetSpaceLeft( void ) const {
132 if ( startIndex <= endIndex ) {
133 return sizeof( buffer ) - ( endIndex - startIndex ) - 1;
135 return ( startIndex - endIndex ) - 1;
141 idMsgQueue::CopyToBuffer
144 void idMsgQueue::CopyToBuffer( byte *buf ) const {
145 if ( startIndex <= endIndex ) {
146 memcpy( buf, buffer + startIndex, endIndex - startIndex );
148 memcpy( buf, buffer + startIndex, sizeof( buffer ) - startIndex );
149 memcpy( buf + sizeof( buffer ) - startIndex, buffer, endIndex );
155 idMsgQueue::WriteByte
158 void idMsgQueue::WriteByte( byte b ) {
159 buffer[endIndex] = b;
160 endIndex = ( endIndex + 1 ) & ( MAX_MSG_QUEUE_SIZE - 1 );
168 byte idMsgQueue::ReadByte( void ) {
169 byte b = buffer[startIndex];
170 startIndex = ( startIndex + 1 ) & ( MAX_MSG_QUEUE_SIZE - 1 );
176 idMsgQueue::WriteShort
179 void idMsgQueue::WriteShort( int s ) {
180 WriteByte( ( s >> 0 ) & 255 );
181 WriteByte( ( s >> 8 ) & 255 );
186 idMsgQueue::ReadShort
189 int idMsgQueue::ReadShort( void ) {
190 return ReadByte() | ( ReadByte() << 8 );
195 idMsgQueue::WriteLong
198 void idMsgQueue::WriteLong( int l ) {
199 WriteByte( ( l >> 0 ) & 255 );
200 WriteByte( ( l >> 8 ) & 255 );
201 WriteByte( ( l >> 16 ) & 255 );
202 WriteByte( ( l >> 24 ) & 255 );
210 int idMsgQueue::ReadLong( void ) {
211 return ReadByte() | ( ReadByte() << 8 ) | ( ReadByte() << 16 ) | ( ReadByte() << 24 );
216 idMsgQueue::WriteData
219 void idMsgQueue::WriteData( const byte *data, const int size ) {
220 for ( int i = 0; i < size; i++ ) {
221 WriteByte( data[i] );
230 void idMsgQueue::ReadData( byte *data, const int size ) {
232 for ( int i = 0; i < size; i++ ) {
233 data[i] = ReadByte();
236 for ( int i = 0; i < size; i++ ) {
245 idMsgChannel::idMsgChannel
248 idMsgChannel::idMsgChannel() {
256 Opens a channel to a remote system.
259 void idMsgChannel::Init( const netadr_t adr, const int id ) {
260 this->remoteAddress = adr;
262 this->maxRate = 50000;
263 this->compressor = idCompressor::AllocRunLength_ZeroBased();
267 outgoingRateTime = 0;
268 outgoingRateBytes = 0;
269 incomingRateTime = 0;
270 incomingRateBytes = 0;
271 incomingReceivedPackets = 0.0f;
272 incomingDroppedPackets = 0.0f;
273 incomingPacketLossTime = 0;
274 outgoingCompression = 0.0f;
275 incomingCompression = 0.0f;
276 outgoingSequence = 1;
277 incomingSequence = 0;
278 unsentFragments = false;
279 unsentFragmentStart = 0;
280 fragmentSequence = 0;
282 reliableSend.Init( 1 );
283 reliableReceive.Init( 0 );
288 idMsgChannel::Shutdown
291 void idMsgChannel::Shutdown( void ) {
298 idMsgChannel::ResetRate
301 void idMsgChannel::ResetRate( void ) {
304 outgoingRateTime = 0;
305 outgoingRateBytes = 0;
306 incomingRateTime = 0;
307 incomingRateBytes = 0;
312 idMsgChannel::ReadyToSend
315 bool idMsgChannel::ReadyToSend( const int time ) const {
321 deltaTime = time - lastSendTime;
322 if ( deltaTime > 1000 ) {
325 return ( ( lastDataBytes - ( deltaTime * maxRate ) / 1000 ) <= 0 );
330 idMsgChannel::WriteMessageData
333 void idMsgChannel::WriteMessageData( idBitMsg &out, const idBitMsg &msg ) {
335 byte tmpBuf[MAX_MESSAGE_SIZE];
337 tmp.Init( tmpBuf, sizeof( tmpBuf ) );
339 // write acknowledgement of last received reliable message
340 tmp.WriteLong( reliableReceive.GetLast() );
342 // write reliable messages
343 reliableSend.CopyToBuffer( tmp.GetData() + tmp.GetSize() );
344 tmp.SetSize( tmp.GetSize() + reliableSend.GetTotalSize() );
348 tmp.WriteData( msg.GetData(), msg.GetSize() );
350 // write message size
351 out.WriteShort( tmp.GetSize() );
354 idFile_BitMsg file( out );
355 compressor->Init( &file, true, 3 );
356 compressor->Write( tmp.GetData(), tmp.GetSize() );
357 compressor->FinishCompress();
358 outgoingCompression = compressor->GetCompressionRatio();
363 idMsgChannel::ReadMessageData
366 bool idMsgChannel::ReadMessageData( idBitMsg &out, const idBitMsg &msg ) {
367 int reliableAcknowledge, reliableMessageSize, reliableSequence;
370 out.SetSize( msg.ReadShort() );
372 // decompress message
373 idFile_BitMsg file( msg );
374 compressor->Init( &file, false, 3 );
375 compressor->Read( out.GetData(), out.GetSize() );
376 incomingCompression = compressor->GetCompressionRatio();
379 // read acknowledgement of sent reliable messages
380 reliableAcknowledge = out.ReadLong();
382 // remove acknowledged reliable messages
383 while( reliableSend.GetFirst() <= reliableAcknowledge ) {
384 if ( !reliableSend.Get( NULL, reliableMessageSize ) ) {
389 // read reliable messages
390 reliableMessageSize = out.ReadShort();
391 while( reliableMessageSize != 0 ) {
392 if ( reliableMessageSize <= 0 || reliableMessageSize > out.GetSize() - out.GetReadCount() ) {
393 common->Printf( "%s: bad reliable message\n", Sys_NetAdrToString( remoteAddress ) );
396 reliableSequence = out.ReadLong();
397 if ( reliableSequence == reliableReceive.GetLast() + 1 ) {
398 reliableReceive.Add( out.GetData() + out.GetReadCount(), reliableMessageSize );
400 out.ReadData( NULL, reliableMessageSize );
401 reliableMessageSize = out.ReadShort();
409 idMsgChannel::SendNextFragment
411 Sends one fragment of the current message.
414 void idMsgChannel::SendNextFragment( idPort &port, const int time ) {
416 byte msgBuf[MAX_PACKETLEN];
419 if ( remoteAddress.type == NA_BAD ) {
423 if ( !unsentFragments ) {
428 msg.Init( msgBuf, sizeof( msgBuf ) );
429 msg.WriteShort( id );
430 msg.WriteLong( outgoingSequence | FRAGMENT_BIT );
432 fragLength = FRAGMENT_SIZE;
433 if ( unsentFragmentStart + fragLength > unsentMsg.GetSize() ) {
434 fragLength = unsentMsg.GetSize() - unsentFragmentStart;
437 msg.WriteShort( unsentFragmentStart );
438 msg.WriteShort( fragLength );
439 msg.WriteData( unsentMsg.GetData() + unsentFragmentStart, fragLength );
442 port.SendPacket( remoteAddress, msg.GetData(), msg.GetSize() );
444 // update rate control variables
445 UpdateOutgoingRate( time, msg.GetSize() );
447 if ( net_channelShowPackets.GetBool() ) {
448 common->Printf( "%d send %4i : s = %i fragment = %i,%i\n", id, msg.GetSize(), outgoingSequence - 1, unsentFragmentStart, fragLength );
451 unsentFragmentStart += fragLength;
453 // this exit condition is a little tricky, because a packet
454 // that is exactly the fragment length still needs to send
455 // a second packet of zero length so that the other side
456 // can tell there aren't more to follow
457 if ( unsentFragmentStart == unsentMsg.GetSize() && fragLength != FRAGMENT_SIZE ) {
459 unsentFragments = false;
465 idMsgChannel::SendMessage
467 Sends a message to a connection, fragmenting if necessary
468 A 0 length will still generate a packet.
471 int idMsgChannel::SendMessage( idPort &port, const int time, const idBitMsg &msg ) {
474 if ( remoteAddress.type == NA_BAD ) {
478 if ( unsentFragments ) {
479 common->Error( "idMsgChannel::SendMessage: called with unsent fragments left" );
483 totalLength = 4 + reliableSend.GetTotalSize() + 4 + msg.GetSize();
485 if ( totalLength > MAX_MESSAGE_SIZE ) {
486 common->Printf( "idMsgChannel::SendMessage: message too large, length = %i\n", totalLength );
490 unsentMsg.Init( unsentBuffer, sizeof( unsentBuffer ) );
491 unsentMsg.BeginWriting();
493 // fragment large messages
494 if ( totalLength >= FRAGMENT_SIZE ) {
495 unsentFragments = true;
496 unsentFragmentStart = 0;
498 // write out the message data
499 WriteMessageData( unsentMsg, msg );
501 // send the first fragment now
502 SendNextFragment( port, time );
504 return outgoingSequence;
508 unsentMsg.WriteShort( id );
509 unsentMsg.WriteLong( outgoingSequence );
511 // write out the message data
512 WriteMessageData( unsentMsg, msg );
515 port.SendPacket( remoteAddress, unsentMsg.GetData(), unsentMsg.GetSize() );
517 // update rate control variables
518 UpdateOutgoingRate( time, unsentMsg.GetSize() );
520 if ( net_channelShowPackets.GetBool() ) {
521 common->Printf( "%d send %4i : s = %i ack = %i\n", id, unsentMsg.GetSize(), outgoingSequence - 1, incomingSequence );
526 return ( outgoingSequence - 1 );
531 idMsgChannel::Process
533 Returns false if the message should not be processed due to being out of order or a fragment.
535 msg must be large enough to hold MAX_MESSAGE_SIZE, because if this is the final
536 fragment of a multi-part message, the entire thing will be copied out.
539 bool idMsgChannel::Process( const netadr_t from, int time, idBitMsg &msg, int &sequence ) {
540 int fragStart, fragLength, dropped;
544 // the IP port can't be used to differentiate them, because
545 // some address translating routers periodically change UDP
547 if ( remoteAddress.port != from.port ) {
548 common->Printf( "idMsgChannel::Process: fixing up a translated port\n" );
549 remoteAddress.port = from.port;
552 // update incoming rate
553 UpdateIncomingRate( time, msg.GetSize() );
555 // get sequence numbers
556 sequence = msg.ReadLong();
558 // check for fragment information
559 if ( sequence & FRAGMENT_BIT ) {
560 sequence &= ~FRAGMENT_BIT;
566 // read the fragment information
568 fragStart = msg.ReadShort();
569 fragLength = msg.ReadShort();
571 fragStart = 0; // stop warning message
575 if ( net_channelShowPackets.GetBool() ) {
577 common->Printf( "%d recv %4i : s = %i fragment = %i,%i\n", id, msg.GetSize(), sequence, fragStart, fragLength );
579 common->Printf( "%d recv %4i : s = %i\n", id, msg.GetSize(), sequence );
584 // discard out of order or duplicated packets
586 if ( sequence <= incomingSequence ) {
587 if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
588 common->Printf( "%s: out of order packet %i at %i\n", Sys_NetAdrToString( remoteAddress ), sequence, incomingSequence );
594 // dropped packets don't keep this message from being used
596 dropped = sequence - (incomingSequence+1);
598 if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
599 common->Printf( "%s: dropped %i packets at %i\n", Sys_NetAdrToString( remoteAddress ), dropped, sequence );
601 UpdatePacketLoss( time, 0, dropped );
605 // if the message is fragmented
608 // make sure we have the correct sequence number
609 if ( sequence != fragmentSequence ) {
610 fragmentSequence = sequence;
614 // if we missed a fragment, dump the message
615 if ( fragStart != fragmentLength ) {
616 if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
617 common->Printf( "%s: dropped a message fragment at seq %d\n", Sys_NetAdrToString( remoteAddress ), sequence );
619 // we can still keep the part that we have so far,
620 // so we don't need to clear fragmentLength
621 UpdatePacketLoss( time, 0, 1 );
625 // copy the fragment to the fragment buffer
626 if ( fragLength < 0 || fragLength > msg.GetRemaingData() || fragmentLength + fragLength > sizeof( fragmentBuffer ) ) {
627 if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
628 common->Printf( "%s: illegal fragment length\n", Sys_NetAdrToString( remoteAddress ) );
630 UpdatePacketLoss( time, 0, 1 );
634 memcpy( fragmentBuffer + fragmentLength, msg.GetData() + msg.GetReadCount(), fragLength );
636 fragmentLength += fragLength;
638 UpdatePacketLoss( time, 1, 0 );
640 // if this wasn't the last fragment, don't process anything
641 if ( fragLength == FRAGMENT_SIZE ) {
646 memcpy( fragmentBuffer, msg.GetData() + msg.GetReadCount(), msg.GetRemaingData() );
647 fragmentLength = msg.GetRemaingData();
648 UpdatePacketLoss( time, 1, 0 );
651 fragMsg.Init( fragmentBuffer, fragmentLength );
652 fragMsg.SetSize( fragmentLength );
653 fragMsg.BeginReading();
655 incomingSequence = sequence;
657 // read the message data
658 if ( !ReadMessageData( msg, fragMsg ) ) {
667 idMsgChannel::SendReliableMessage
670 bool idMsgChannel::SendReliableMessage( const idBitMsg &msg ) {
673 assert( remoteAddress.type != NA_BAD );
674 if ( remoteAddress.type == NA_BAD ) {
677 result = reliableSend.Add( msg.GetData(), msg.GetSize() );
679 common->Warning( "idMsgChannel::SendReliableMessage: overflowed" );
687 idMsgChannel::GetReliableMessage
690 bool idMsgChannel::GetReliableMessage( idBitMsg &msg ) {
694 result = reliableReceive.Get( msg.GetData(), size );
702 idMsgChannel::ClearReliableMessages
705 void idMsgChannel::ClearReliableMessages( void ) {
706 reliableSend.Init( 1 );
707 reliableReceive.Init( 0 );
712 idMsgChannel::UpdateOutgoingRate
715 void idMsgChannel::UpdateOutgoingRate( const int time, const int size ) {
716 // update the outgoing rate control variables
717 int deltaTime = time - lastSendTime;
718 if ( deltaTime > 1000 ) {
721 lastDataBytes -= ( deltaTime * maxRate ) / 1000;
722 if ( lastDataBytes < 0 ) {
726 lastDataBytes += size;
729 // update outgoing rate variables
730 if ( time - outgoingRateTime > 1000 ) {
731 outgoingRateBytes -= outgoingRateBytes * ( time - outgoingRateTime - 1000 ) / 1000;
732 if ( outgoingRateBytes < 0 ) {
733 outgoingRateBytes = 0;
736 outgoingRateTime = time - 1000;
737 outgoingRateBytes += size;
742 idMsgChannel::UpdateIncomingRate
745 void idMsgChannel::UpdateIncomingRate( const int time, const int size ) {
746 // update incoming rate variables
747 if ( time - incomingRateTime > 1000 ) {
748 incomingRateBytes -= incomingRateBytes * ( time - incomingRateTime - 1000 ) / 1000;
749 if ( incomingRateBytes < 0 ) {
750 incomingRateBytes = 0;
753 incomingRateTime = time - 1000;
754 incomingRateBytes += size;
759 idMsgChannel::UpdatePacketLoss
762 void idMsgChannel::UpdatePacketLoss( const int time, const int numReceived, const int numDropped ) {
763 // update incoming packet loss variables
764 if ( time - incomingPacketLossTime > 5000 ) {
765 float scale = ( time - incomingPacketLossTime - 5000 ) * ( 1.0f / 5000.0f );
766 incomingReceivedPackets -= incomingReceivedPackets * scale;
767 if ( incomingReceivedPackets < 0.0f ) {
768 incomingReceivedPackets = 0.0f;
770 incomingDroppedPackets -= incomingDroppedPackets * scale;
771 if ( incomingDroppedPackets < 0.0f ) {
772 incomingDroppedPackets = 0.0f;
775 incomingPacketLossTime = time - 5000;
776 incomingReceivedPackets += numReceived;
777 incomingDroppedPackets += numDropped;
782 idMsgChannel::GetIncomingPacketLoss
785 float idMsgChannel::GetIncomingPacketLoss( void ) const {
786 if ( incomingReceivedPackets == 0.0f && incomingDroppedPackets == 0.0f ) {
789 return incomingDroppedPackets * 100.0f / ( incomingReceivedPackets + incomingDroppedPackets );