warzone2100/lib/netplay/netqueue.cpp

257 lines
8.2 KiB
C++

#include "netqueue.h"
#include "lib/framework/frame.h"
// See comments in netqueue.h.
// Byte n is the final byte, iff it is less than 256-a[n].
// Some possible values of table_uint32_t_a[n], such that the maximum encodable value is 0xFFFFFFFF, satisfying the assertion below:
// ASSERT(0xFFFFFFFF == 255*(1 + a[0]*(1 + a[1]*(1 + a[2]*(1 + a[3]*(1 + a[4]))))), "Maximum encodable value not 0xFFFFFFFF.");
//static const unsigned table_uint32_t_a[5] = {14, 127, 74, 127, 0}, table_uint32_t_m[5] = {1, 14, 1778, 131572, 16709644}; // <242: 1 byte, <2048: 2 bytes, <325644: 3 bytes, <17298432: 4 bytes, <4294967296: 5 bytes
static const unsigned table_uint32_t_a[5] = {78, 95, 32, 70, 0}, table_uint32_t_m[5] = {1, 78, 7410, 237120, 16598400}; // <178: 1 byte, <12736: 2 bytes, <1672576: 3 bytes, <45776896: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {78, 95, 71, 31, 0}, table_uint32_t_m[5] = {1, 78, 7410, 526110, 16309410}; // <178: 1 byte, <12736: 2 bytes, <1383586: 3 bytes, <119758336: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 19, 119, 0}, table_uint32_t_m[5] = {1, 104, 7384, 140296, 16695224}; // <152: 1 byte, <19392: 2 bytes, <1769400: 3 bytes, <20989952: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 20, 113, 0}, table_uint32_t_m[5] = {1, 104, 7384, 147680, 16687840}; // <152: 1 byte, <19392: 2 bytes, <1762016: 3 bytes, <22880256: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 24, 94, 0}, table_uint32_t_m[5] = {1, 104, 7384, 177216, 16658304}; // <152: 1 byte, <19392: 2 bytes, <1732480: 3 bytes, <30441472: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 30, 75, 0}, table_uint32_t_m[5] = {1, 104, 7384, 221520, 16614000}; // <152: 1 byte, <19392: 2 bytes, <1688176: 3 bytes, <41783296: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 38, 59, 0}, table_uint32_t_m[5] = {1, 104, 7384, 280592, 16554928}; // <152: 1 byte, <19392: 2 bytes, <1629104: 3 bytes, <56905728: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 40, 56, 0}, table_uint32_t_m[5] = {1, 104, 7384, 295360, 16540160}; // <152: 1 byte, <19392: 2 bytes, <1614336: 3 bytes, <60686336: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 57, 39, 0}, table_uint32_t_m[5] = {1, 104, 7384, 420888, 16414632}; // <152: 1 byte, <19392: 2 bytes, <1488808: 3 bytes, <92821504: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 60, 37, 0}, table_uint32_t_m[5] = {1, 104, 7384, 443040, 16392480}; // <152: 1 byte, <19392: 2 bytes, <1466656: 3 bytes, <98492416: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 76, 29, 0}, table_uint32_t_m[5] = {1, 104, 7384, 561184, 16274336}; // <152: 1 byte, <19392: 2 bytes, <1348512: 3 bytes, <128737280: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 95, 23, 0}, table_uint32_t_m[5] = {1, 104, 7384, 701480, 16134040}; // <152: 1 byte, <19392: 2 bytes, <1208216: 3 bytes, <164653056: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 114, 19, 0}, table_uint32_t_m[5] = {1, 104, 7384, 841776, 15993744}; // <152: 1 byte, <19392: 2 bytes, <1067920: 3 bytes, <200568832: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_a[5] = {104, 71, 120, 18, 0}, table_uint32_t_m[5] = {1, 104, 7384, 886080, 15949440}; // <152: 1 byte, <19392: 2 bytes, <1023616: 3 bytes, <211910656: 4 bytes, <4294967296: 5 bytes
//static const unsigned table_uint32_t_m[5] = {1, a[0], a[0]*a[1], a[0]*a[1]*a[2], a[0]*a[1]*a[2]*a[3]};
unsigned encodedlength_uint32_t(uint32_t v)
{
for (unsigned n = 0;; ++n)
{
const unsigned a = table_uint32_t_a[n];
const unsigned m = table_uint32_t_m[n];
const unsigned possibleValues = (256 - a)*m; // Number of values which encode to n + 1 bytes.
if (v < possibleValues)
{
return n + 1;
}
v -= possibleValues;
}
}
bool encode_uint32_t(uint8_t &b, uint32_t &v, unsigned n)
{
const unsigned a = table_uint32_t_a[n];
bool isLastByte = v < 256 - a;
if (isLastByte)
{
b = v;
}
else
{
v -= 256 - a;
b = 255 - v%a;
v /= a;
}
return !isLastByte;
}
bool decode_uint32_t(uint8_t b, uint32_t &v, unsigned n)
{
const unsigned a = table_uint32_t_a[n];
const unsigned m = table_uint32_t_m[n];
bool isLastByte = b < 256 - a;
if (isLastByte)
{
v += b*m;
}
else
{
v += (256 - a + 255 - b)*m;
}
return !isLastByte;
}
uint8_t *NetMessage::rawDataDup() const
{
unsigned encodedLengthOfSize = encodedlength_uint32_t(data.size());
uint8_t *ret = new uint8_t[1 + encodedLengthOfSize + data.size()];
ret[0] = type;
uint32_t len = data.size();
for (unsigned n = 0; n < encodedLengthOfSize; ++n)
{
encode_uint32_t(ret[n + 1], len, n);
}
std::copy(data.begin(), data.end(), ret + 1 + encodedLengthOfSize);
return ret;
}
size_t NetMessage::rawLen() const
{
return 1 + encodedlength_uint32_t(data.size()) + data.size();
}
NetQueue::NetQueue()
: canGetMessagesForNet(true)
, canGetMessages(true)
{
dataPos = messages.end();
messagePos = messages.end();
}
void NetQueue::writeRawData(const uint8_t *netData, size_t netLen)
{
size_t used = 0;
std::vector<uint8_t> &buffer = incompleteReceivedMessageData; // Short alias.
// Insert the data.
buffer.insert(buffer.end(), netData, netData + netLen);
// Extract the messages.
while (buffer.size() - used > 1)
{
uint8_t type = buffer[used];
uint32_t len = 0;
bool moreBytes = true;
unsigned n;
for (n = 0; moreBytes && buffer.size() - used > 1 + n; ++n)
{
moreBytes = decode_uint32_t(buffer[used + 1 + n], len, n);
}
unsigned headerLen = 1 + n;
ASSERT(len < 40000000, "Trying to write a very large packet (%u bytes) to the queue.", len);
if (buffer.size() - used - headerLen < len)
{
break; // Don't have a whole message ready yet.
}
messages.push_front(NetMessage(type));
messages.front().data.assign(buffer.begin() + used + headerLen, buffer.begin() + used + headerLen + len);
used += headerLen + len;
}
// Recycle old data.
buffer.erase(buffer.begin(), buffer.begin() + used);
}
void NetQueue::setWillNeverGetMessagesForNet()
{
canGetMessagesForNet = false;
}
unsigned NetQueue::numMessagesForNet() const
{
unsigned count = 0;
if (canGetMessagesForNet)
{
for (List::iterator i = dataPos; i != messages.begin(); --i)
{
++count;
}
}
return count;
}
const NetMessage &NetQueue::getMessageForNet() const
{
ASSERT(canGetMessagesForNet, "Wrong NetQueue type for getMessageForNet.");
ASSERT(dataPos != messages.begin(), "No message to get!");
// Return the message.
List::iterator i = dataPos;
--i;
return *i;
}
void NetQueue::popMessageForNet()
{
ASSERT(canGetMessagesForNet, "Wrong NetQueue type for popMessageForNet.");
ASSERT(dataPos != messages.begin(), "No message to pop!");
// Pop the message.
--dataPos;
// Recycle old data.
popOldMessages();
}
void NetQueue::pushMessage(const NetMessage &message)
{
messages.push_front(message);
}
void NetQueue::setWillNeverGetMessages()
{
canGetMessages = false;
}
bool NetQueue::haveMessage() const
{
ASSERT(canGetMessages, "Wrong NetQueue type for haveMessage.");
return messagePos != messages.begin();
}
const NetMessage &NetQueue::getMessage() const
{
ASSERT(canGetMessages, "Wrong NetQueue type for getMessage.");
ASSERT(messagePos != messages.begin(), "No message to get!");
// Return the message.
List::iterator i = messagePos;
--i;
return *i;
}
void NetQueue::popMessage()
{
ASSERT(canGetMessages, "Wrong NetQueue type for popMessage.");
ASSERT(messagePos != messages.begin(), "No message to pop!");
// Pop the message.
--messagePos;
// Recycle old data.
popOldMessages();
}
void NetQueue::popOldMessages()
{
if (!canGetMessagesForNet)
{
dataPos = messages.begin();
}
if (!canGetMessages)
{
messagePos = messages.begin();
}
List::iterator i = messages.end();
while (i != dataPos && i != messagePos)
{
--i;
}
if (i == dataPos)
{
dataPos = messages.end(); // Old iterator will become invalid.
}
if (i == messagePos)
{
messagePos = messages.end(); // Old iterator will become invalid.
}
messages.erase(i, messages.end());
}