mirror of
https://github.com/tswow/tswow
synced 2026-08-14 20:29:06 -04:00
139 lines
3.4 KiB
C++
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();
|
|
}
|