tswow/misc/client-extensions/CustomPackets/CustomPacketBuffer.cpp

139 lines
3.4 KiB
C++

#include "CustomPacketBuffer.h"
CustomPacketBuffer::CustomPacketBuffer(
chunkSize_t minFragmentSize
, totalSize_t quota
, chunkSize_t bufferSize
)
: m_minFragmentSize(minFragmentSize)
, m_maxFragmentSize(bufferSize)
, m_quota(quota)
, m_cur(0,bufferSize)
{}
CustomPacketBuffer::~CustomPacketBuffer()
{
// needed on server
m_cur.Destroy();
}
CustomPacketResult CustomPacketBuffer::ReceivePacket(chunkSize_t size, char* data)
{
// Check sizes
if (size <= CustomHeaderSize)
{
return _onError(CustomPacketResult::NO_HEADER, data);
}
if (size > m_maxFragmentSize)
{
return _onError(CustomPacketResult::TOO_BIG_FRAGMENT, data);
}
if (size + m_cur.Size() > m_quota)
{
m_cur.Destroy();
return _onError(CustomPacketResult::OUT_OF_SPACE, data);
}
CustomPacketChunk chnk(size, data);
CustomPacketHeader* hdr = chnk.Header();
switch (hdr->totalFrags)
{
case 0:
return _onError(CustomPacketResult::INVALID_FRAG_COUNT, data);
case 1:
AppendFragment(chnk, true);
return _onSuccess();
default:
if (m_cur.ChunkCount() == 0)
{
if (hdr->fragmentId != 0)
{
return _onError(CustomPacketResult::INVALID_FIRST_FRAG, data);
}
if (size < m_minFragmentSize)
{
return _onError(CustomPacketResult::TOO_SMALL_FRAGMENT, data);
}
AppendFragment(chnk, false);
return CustomPacketResult::HANDLED_FRAGMENT;
}
else
{
CustomPacketHeader* lastH = m_cur->Chunk(m_cur->ChunkCount() - 1)->Header();
if (lastH->totalFrags != hdr->totalFrags)
{
return _onError(CustomPacketResult::HEADER_MISMATCH, data);
}
if (hdr->fragmentId != lastH->fragmentId + 1)
{
return _onError(CustomPacketResult::INVALID_FRAG_ID, data);
}
}
if (
m_cur.ChunkCount() > 0
&& hdr->fragmentId == m_cur.Chunk(0)->Header()->totalFrags - 1
) {
AppendFragment(chnk, true);
return _onSuccess();
}
else
{
// small fragments only apply to
if (size < m_minFragmentSize)
{
return _onError(CustomPacketResult::TOO_SMALL_FRAGMENT, data);
}
AppendFragment(chnk, false);
return CustomPacketResult::HANDLED_FRAGMENT;
}
}
}
CustomPacketResult CustomPacketBuffer::_onError(CustomPacketResult error, char* data)
{
OnError(error);
m_cur.Destroy();
return error;
}
CustomPacketResult CustomPacketBuffer::_onSuccess()
{
OnPacket(&m_cur);
// destroy all but the last fragment, since it's not a copy
for (chunkCount_t i = 0; i < m_cur.m_chunks.size() - 1; ++i)
{
m_cur.m_chunks[i].Destroy();
}
m_cur.Clear();
return CustomPacketResult::HANDLED_MESSAGE;
}
void CustomPacketBuffer::AppendFragment(CustomPacketChunk & chunk, bool isLast)
{
// buffer entries need to be made persistent
if (isLast)
{
// todo: probably should happen elsewhere
m_cur->m_opcode = chunk.Header()->opcode;
m_cur.Push(chunk);
}
else
{
CustomPacketChunk cpy(chunk);
cpy.Copy();
m_cur.Push(cpy);
}
}
totalSize_t CustomPacketBuffer::Size()
{
return m_cur.Size();
}