diff --git a/common.c b/common.c index ade79e7..c4213e3 100644 --- a/common.c +++ b/common.c @@ -3,6 +3,15 @@ #include "common.h" +__declspec(naked) +void j__free(void *ptr) +{ + _asm { + mov eax, 0x49AAA8 + jmp eax + } +} + __declspec(naked) void * __stdcall Queue_AtPosition_QWORD(struct CQueue *queue, int position) { diff --git a/common.h b/common.h index f20056c..c4b9afb 100644 --- a/common.h +++ b/common.h @@ -7,6 +7,7 @@ #define EXPECT_SIZE(S,SIZE) STATIC_ASSERT(sizeof(S)==(SIZE)) #define DEFAULT_HAS_RECEIVED_PACKET_QUEUE_SIZE 0x200 +#define NUMBER_OF_ORDERED_STREAMS 0x20 #pragma pack(push, 1) struct PlayerID { @@ -39,6 +40,20 @@ struct CRangeNode_Short { }; EXPECT_SIZE(struct CRangeNode_Short, 0x4); +struct CListNode_DWORD { + void *value; + struct CListNode_DWORD *prev; + struct CListNode_DWORD *next; +}; +EXPECT_SIZE(struct CListNode_DWORD, 0xC); + +struct CCircularLinkedList { + unsigned int list_size; + void *root; + void *position; +}; +EXPECT_SIZE(struct CCircularLinkedList, 0xC); + struct CRaknetTimeNS { unsigned int lo32; unsigned int hi32; @@ -154,6 +169,7 @@ EXPECT_SIZE(struct CInternalPacket, 0x38); #define QUEUE_POP_IGNOREVALUE(X) \ (X.head = (X.head+1 == X.allocationSize) ? 0 : (X.head+1)) +void j__free(void *ptr); void * __stdcall Queue_AtPosition_QWORD(struct CQueue *queue, int position); void __stdcall Queue_Push_QWORD(struct CQueue *queue, void *value); void __stdcall Queue_Push_DWORD(struct CQueue *queue, void *value); diff --git a/reliability.c b/reliability.c index e683d8e..b5eada3 100644 --- a/reliability.c +++ b/reliability.c @@ -84,6 +84,8 @@ int HandlePacketHole( return 1; } + dprintf("packet hole is %d\n", holeSize); + if (holeSize > 0x8000) { /*? underflow apparently*/ this->statistics_duplicateMessagesReceived++; @@ -153,27 +155,123 @@ void CompressMessageHoleQueue(struct CReliabilityLayer *this) thiscall0((void*) 0x45B6C0, &this->hasReceivedPacketQueue); } +static +void DiscardPacket( + struct CReliabilityLayer *this, + struct CInternalPacket *packet) +{ + j__free(packet->pData); + thiscall1((void*) 0x44EBF0, &this->internalPacketPool, (int) packet); +} + static int HandleSequencedPacket( struct CReliabilityLayer *this, struct CInternalPacket *packet) { + char channel; + short waitingIndex; + short newIndex; + if (packet->packetReliability != RELIABLE_SEQUENCED || packet->packetReliability != UNRELIABLE_SEQUENCED) { return 0; } + + channel = packet->orderingChannel; + if (channel >= NUMBER_OF_ORDERED_STREAMS) { + DiscardPacket(this, packet); + return 1; + } + + waitingIndex = this->waitingForSequencedPacketReadIndex[channel]; + newIndex = packet->orderingIndex; + /*isOlderSequencedPacked*/ + if (thiscall2((void*) 0x45B3D0, this, newIndex, waitingIndex)) { + this->statistics_sequencedMessagesOutOfOrder++; + DiscardPacket(this, packet); + return 1; + } + this->statistics_sequencedMessagesInOrder++; + + /*ignoring split packet code @0x460098*/ + + this->waitingForSequencedPacketReadIndex[channel] = newIndex + 1; + Queue_Push_DWORD(&this->outputQueue, &packet); + return 1; } +static +void OutputNowInOrderPackets( + struct CReliabilityLayer *this, + struct CCircularLinkedList *orderingList, + short *waitingForIndex) +{ + struct CInternalPacket *packet; + struct CListNode_DWORD *node, *root; + int wasAtLeastOneRemoved; + + wasAtLeastOneRemoved = 1; + while (wasAtLeastOneRemoved && orderingList->list_size) { + wasAtLeastOneRemoved = 0; + root = node = orderingList->position = orderingList->root; + do { + packet = node->value; + if (packet->orderingIndex == *waitingForIndex) { + dprintf("popped out of order packet\n"); + Queue_Push_DWORD(&this->outputQueue, &packet); + /*CCircularLinkedList::PopCurrent_DWORD*/ + thiscall0((void*) 0x44E750, orderingList); + *waitingForIndex++; + wasAtLeastOneRemoved = 1; + break; + } + node = node->next; + } while (node != root); + } +} + static int HandleOrdenedPacket( struct CReliabilityLayer *this, struct CInternalPacket *packet) { + char channel; + short newIndex; + short *waitingForIndex; + struct CCircularLinkedList *orderingList; + if (packet->packetReliability != RELIABLE_ORDENED) { return 0; } + + channel = packet->orderingChannel; + if (channel >= NUMBER_OF_ORDERED_STREAMS) { + DiscardPacket(this, packet); + return 1; + } + + newIndex = packet->orderingIndex; + waitingForIndex = &this->waitingForOrderedPacketReadIndex[channel]; + if (newIndex != *waitingForIndex) { + /*not yet time to handle this one*/ + dprintf("out of order packet\n"); + /*do outOfOrderLimit here*/ + this->statistics_orderedMessagesOutOfOrder++; + /*ReliabilityLayer__AddToOrderingList*/ + thiscall1((void*) 0x45DEE0, this, (int) packet); + return 1; + } + this->statistics_orderedMessagesInOrder++; + + Queue_Push_DWORD(&this->outputQueue, &packet); + orderingList = thiscall1((void*) 0x45C4C0, this, channel); + if (orderingList == NULL) { + return 1; + } + OutputNowInOrderPackets(this, orderingList, waitingForIndex); return 1; } @@ -308,17 +406,17 @@ int HandleAcks( struct CRangeList incomingAcksList; struct CRangeNode_Short *ranges; int amountOfAckRanges, ackRangeIdx; - int containedValidAcks; + int numAcks, pos; short minMsg, maxMsg; - dprintf("reading ackslist, position is %d\n", bitStream->readOffset); + pos = bitStream->readOffset; RangeList__ctor(&incomingAcksList); if (!RangeList__Deserialize(&incomingAcksList, bitStream)) { dprintf("could not deserialize ackslist\n"); RangeList__dtor(&incomingAcksList); return 0; } - dprintf("position after reading is %d\n", bitStream->readOffset); + dprintf("read acks from %d to %d\n", pos, bitStream->readOffset); amountOfAckRanges = incomingAcksList._._.list_size; if (amountOfAckRanges == 0) { @@ -327,7 +425,7 @@ int HandleAcks( return 1; } - containedValidAcks = 0; + numAcks = 0; ranges = (struct CRangeNode_Short*) incomingAcksList._._.values; for (ackRangeIdx = 0; ackRangeIdx < amountOfAckRanges; ackRangeIdx++) { minMsg = ranges[ackRangeIdx].minIndex; @@ -338,14 +436,14 @@ int HandleAcks( continue; } - containedValidAcks = 1; + numAcks += maxMsg - minMsg + 1; HandleAcksForMessageRange(this, minMsg, maxMsg, timeNS); /*ackslimit checked here*/ } RangeList__dtor(&incomingAcksList); - return containedValidAcks; + return numAcks > 0; } /** @@ -397,6 +495,7 @@ int __stdcall ReliabilityLayer__HandleSocketReceiveFromConnectedPlayer( struct CRaknetTimeNS timeNS; char hasAcks, wereAcksHandled; int returnValue; + int packetCount; dprintf("HandleSocketReceiveFromConnectedPlayerStart\n"); @@ -415,21 +514,23 @@ int __stdcall ReliabilityLayer__HandleSocketReceiveFromConnectedPlayer( wereAcksHandled = 0; BitStream__Read(&bitStream, &hasAcks); if (hasAcks) { - dprintf("has acks\n"); wereAcksHandled = HandleAcks(this, &bitStream, timeNS); } returnValue = wereAcksHandled; + packetCount = 0; while (packet = ReliabilityLayer__CreateInternalPacketFromBitStream( this, &bitStream, timeNS)) { - returnValue = 1; + returnValue |= 0x10000000; + packetCount++; HandlePacket(this, packet, timeNS); } this->receivePacketCount++; BitStream__dtor(&bitStream); - dprintf("HandleSocketReceiveFromConnectedPlayerEnd\n"); + dprintf("HandleSocketReceiveFromConnectedPlayerEnd acks=%d packets=%d\n", + returnValue & 0xFFFFFFF, packetCount); return returnValue; #endif } diff --git a/uncompress.c b/uncompress.c index bc83b5e..8742323 100644 --- a/uncompress.c +++ b/uncompress.c @@ -1,7 +1,7 @@ /* vim: set filetype=c ts=8 noexpandtab: */ -#define COMPRESS_PRINT +//#define COMPRESS_PRINT #include "common.h" #include "uncompress.h"