mirror of
https://github.com/solemnwarning/directplay-lite
synced 2024-12-30 16:45:37 +01:00
Implement low-level packet (de)serialisation code.
The protocol is going to use TLV messages, containing zero or more fields represented using the same TLV header. Functions for (de)serialising DirectPlay message structures will be built on top of these classes.
This commit is contained in:
parent
c865ecb1f7
commit
971119edae
13
Makefile
13
Makefile
@ -5,12 +5,23 @@ TEST_CXXFLAGS := $(CXXFLAGS) -I./googletest/include/
|
||||
|
||||
all: dpnet.dll
|
||||
|
||||
dpnet.dll: src/dpnet.o src/dpnet.def src/DirectPlay8Address.o src/DirectPlay8Peer.o src/network.o
|
||||
check: tests/all-tests.exe
|
||||
wine tests/all-tests.exe
|
||||
|
||||
dpnet.dll: src/dpnet.o src/dpnet.def src/DirectPlay8Address.o src/DirectPlay8Peer.o src/network.o src/packet.o
|
||||
$(CXX) $(CXXFLAGS) -Wl,--enable-stdcall-fixup -shared -o $@ $^ -ldxguid -lws2_32 -static-libstdc++ -static-libgcc
|
||||
|
||||
tests/DirectPlay8Address.exe: tests/DirectPlay8Address.o src/DirectPlay8Address.o googletest/src/gtest-all.o googletest/src/gtest_main.o
|
||||
$(CXX) $(TEST_CXXFLAGS) -o $@ $^ -ldxguid -lole32 -static-libstdc++ -static-libgcc
|
||||
|
||||
tests/PacketSerialiser.exe: tests/PacketSerialiser.o src/packet.o googletest/src/gtest-all.o googletest/src/gtest_main.o
|
||||
$(CXX) $(TEST_CXXFLAGS) -o $@ $^ -ldxguid -lole32 -static-libstdc++ -static-libgcc
|
||||
|
||||
tests/all-tests.exe: tests/DirectPlay8Address.o src/DirectPlay8Address.o \
|
||||
tests/PacketSerialiser.o tests/PacketDeserialiser.o src/packet.o \
|
||||
googletest/src/gtest-all.o googletest/src/gtest_main.o
|
||||
$(CXX) $(TEST_CXXFLAGS) -o $@ $^ -ldxguid -lole32 -static-libstdc++ -static-libgcc
|
||||
|
||||
src/%.o: src/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
|
181
src/packet.cpp
Normal file
181
src/packet.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <windows.h>
|
||||
|
||||
#include "packet.hpp"
|
||||
|
||||
const uint32_t FIELD_TYPE_NULL = 0;
|
||||
const uint32_t FIELD_TYPE_DWORD = 1;
|
||||
const uint32_t FIELD_TYPE_DATA = 2;
|
||||
const uint32_t FIELD_TYPE_WSTRING = 3;
|
||||
|
||||
PacketSerialiser::PacketSerialiser(uint32_t type)
|
||||
{
|
||||
/* Avoid reallocations during packet construction unless we get given a lot of data. */
|
||||
sbuf.reserve(4096);
|
||||
|
||||
TLVChunk header;
|
||||
header.type = type;
|
||||
header.value_length = 0;
|
||||
|
||||
sbuf.insert(sbuf.begin(), (unsigned char*)(&header), (unsigned char*)(&header + 1));
|
||||
}
|
||||
|
||||
std::pair<const void*, size_t> PacketSerialiser::raw_packet()
|
||||
{
|
||||
return std::make_pair<const void*, size_t>(sbuf.data(), sbuf.size());
|
||||
}
|
||||
|
||||
void PacketSerialiser::append_null()
|
||||
{
|
||||
TLVChunk header;
|
||||
header.type = FIELD_TYPE_NULL;
|
||||
header.value_length = 0;
|
||||
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1));
|
||||
|
||||
((TLVChunk*)(sbuf.data()))->value_length += sizeof(header);
|
||||
}
|
||||
|
||||
void PacketSerialiser::append_dword(DWORD value)
|
||||
{
|
||||
TLVChunk header;
|
||||
header.type = FIELD_TYPE_DWORD;
|
||||
header.value_length = sizeof(DWORD);
|
||||
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1));
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(&value), (unsigned char*)(&value + 1));
|
||||
|
||||
((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + sizeof(value);
|
||||
}
|
||||
|
||||
void PacketSerialiser::append_data(const void *data, size_t size)
|
||||
{
|
||||
TLVChunk header;
|
||||
header.type = FIELD_TYPE_DATA;
|
||||
header.value_length = size;
|
||||
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1));
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(data), (unsigned char*)(data) + size);
|
||||
|
||||
((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + size;
|
||||
}
|
||||
|
||||
void PacketSerialiser::append_wstring(const std::wstring &string)
|
||||
{
|
||||
size_t string_bytes = string.length() * sizeof(wchar_t);
|
||||
|
||||
TLVChunk header;
|
||||
header.type = FIELD_TYPE_WSTRING;
|
||||
header.value_length = string_bytes;
|
||||
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1));
|
||||
sbuf.insert(sbuf.end(), (unsigned char*)(string.data()), (unsigned char*)(string.data()) + string_bytes);
|
||||
|
||||
((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + string_bytes;
|
||||
}
|
||||
|
||||
PacketDeserialiser::PacketDeserialiser(const void *serialised_packet, size_t packet_size)
|
||||
{
|
||||
header = (const TLVChunk*)(serialised_packet);
|
||||
|
||||
if(packet_size < sizeof(TLVChunk) || packet_size < sizeof(TLVChunk) + header->value_length)
|
||||
{
|
||||
throw Error::Incomplete();
|
||||
}
|
||||
|
||||
const unsigned char *at = header->value;
|
||||
size_t value_remain = header->value_length;
|
||||
|
||||
while(value_remain > 0)
|
||||
{
|
||||
const TLVChunk *field = (TLVChunk*)(at);
|
||||
|
||||
if(value_remain < sizeof(TLVChunk) || value_remain < sizeof(TLVChunk) + field->value_length)
|
||||
{
|
||||
throw Error::Malformed();
|
||||
}
|
||||
|
||||
fields.push_back(field);
|
||||
|
||||
at += sizeof(TLVChunk) + field->value_length;
|
||||
value_remain -= sizeof(TLVChunk) + field->value_length;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PacketDeserialiser::packet_type()
|
||||
{
|
||||
return header->type;
|
||||
}
|
||||
|
||||
size_t PacketDeserialiser::num_fields()
|
||||
{
|
||||
return fields.size();
|
||||
}
|
||||
|
||||
bool PacketDeserialiser::is_null(size_t index)
|
||||
{
|
||||
if(fields.size() <= index)
|
||||
{
|
||||
throw Error::MissingField();
|
||||
}
|
||||
|
||||
return (fields[index]->type == FIELD_TYPE_NULL);
|
||||
}
|
||||
|
||||
DWORD PacketDeserialiser::get_dword(size_t index)
|
||||
{
|
||||
if(fields.size() <= index)
|
||||
{
|
||||
throw Error::MissingField();
|
||||
}
|
||||
|
||||
if(fields[index]->type != FIELD_TYPE_DWORD)
|
||||
{
|
||||
throw Error::TypeMismatch();
|
||||
}
|
||||
|
||||
if(fields[index]->value_length != sizeof(DWORD))
|
||||
{
|
||||
throw Error::Malformed();
|
||||
}
|
||||
|
||||
return *(DWORD*)(fields[index]->value);
|
||||
}
|
||||
|
||||
std::pair<const void*,size_t> PacketDeserialiser::get_data(size_t index)
|
||||
{
|
||||
if(fields.size() <= index)
|
||||
{
|
||||
throw Error::MissingField();
|
||||
}
|
||||
|
||||
if(fields[index]->type != FIELD_TYPE_DATA)
|
||||
{
|
||||
throw Error::TypeMismatch();
|
||||
}
|
||||
|
||||
return std::make_pair<const void*, size_t>((const void*)(fields[index]->value), (size_t)(fields[index]->value_length));
|
||||
}
|
||||
|
||||
std::wstring PacketDeserialiser::get_wstring(size_t index)
|
||||
{
|
||||
if(fields.size() <= index)
|
||||
{
|
||||
throw Error::MissingField();
|
||||
}
|
||||
|
||||
if(fields[index]->type != FIELD_TYPE_WSTRING)
|
||||
{
|
||||
throw Error::TypeMismatch();
|
||||
}
|
||||
|
||||
if((fields[index]->value_length % sizeof(wchar_t)) != 0)
|
||||
{
|
||||
throw Error::Malformed();
|
||||
}
|
||||
|
||||
return std::wstring((const wchar_t*)(fields[index]->value), (fields[index]->value_length / sizeof(wchar_t)));
|
||||
}
|
89
src/packet.hpp
Normal file
89
src/packet.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef DPLITE_PACKET_HPP
|
||||
#define DPLITE_PACKET_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
struct TLVChunk
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t value_length;
|
||||
unsigned char value[0];
|
||||
};
|
||||
|
||||
class PacketSerialiser
|
||||
{
|
||||
private:
|
||||
std::vector<unsigned char> sbuf;
|
||||
|
||||
public:
|
||||
PacketSerialiser(uint32_t type);
|
||||
|
||||
std::pair<const void*, size_t> raw_packet();
|
||||
|
||||
void append_null();
|
||||
void append_dword(DWORD value);
|
||||
void append_data(const void *data, size_t size);
|
||||
void append_wstring(const std::wstring &string);
|
||||
};
|
||||
|
||||
class PacketDeserialiser
|
||||
{
|
||||
private:
|
||||
const TLVChunk *header;
|
||||
std::vector<const TLVChunk*> fields;
|
||||
|
||||
public:
|
||||
class Error: public std::runtime_error
|
||||
{
|
||||
protected:
|
||||
Error(const std::string &what): runtime_error(what) {}
|
||||
|
||||
public:
|
||||
class Incomplete;
|
||||
class Malformed;
|
||||
class MissingField;
|
||||
class TypeMismatch;
|
||||
};
|
||||
|
||||
PacketDeserialiser(const void *serialised_packet, size_t packet_size);
|
||||
|
||||
uint32_t packet_type();
|
||||
size_t num_fields();
|
||||
|
||||
bool is_null(size_t index);
|
||||
DWORD get_dword(size_t index);
|
||||
std::pair<const void*,size_t> get_data(size_t index);
|
||||
std::wstring get_wstring(size_t index);
|
||||
};
|
||||
|
||||
class PacketDeserialiser::Error::Incomplete: public Error
|
||||
{
|
||||
public:
|
||||
Incomplete(const std::string &what = "Incomplete packet"): Error(what) {}
|
||||
};
|
||||
|
||||
class PacketDeserialiser::Error::Malformed: public Error
|
||||
{
|
||||
public:
|
||||
Malformed(const std::string &what = "Malformed packet"): Error(what) {}
|
||||
};
|
||||
|
||||
class PacketDeserialiser::Error::MissingField: public Error
|
||||
{
|
||||
public:
|
||||
MissingField(const std::string &what = "Missing field in packet"): Error(what) {}
|
||||
};
|
||||
|
||||
class PacketDeserialiser::Error::TypeMismatch: public Error
|
||||
{
|
||||
public:
|
||||
TypeMismatch(const std::string &what = "Incorrect field type in packet"): Error(what) {}
|
||||
};
|
||||
|
||||
#endif /* !DPLITE_PACKET_HPP */
|
560
tests/PacketDeserialiser.cpp
Normal file
560
tests/PacketDeserialiser.cpp
Normal file
@ -0,0 +1,560 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../src/packet.hpp"
|
||||
|
||||
class PacketDeserialiserTest: public ::testing::Test {
|
||||
protected:
|
||||
PacketDeserialiser *pd;
|
||||
|
||||
PacketDeserialiserTest(): pd(NULL) {}
|
||||
|
||||
virtual ~PacketDeserialiserTest()
|
||||
{
|
||||
delete pd;
|
||||
}
|
||||
};
|
||||
|
||||
class PacketDeserialiserEmpty: public PacketDeserialiserTest {
|
||||
protected:
|
||||
virtual void SetUp() override
|
||||
{
|
||||
static const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00, /* type */
|
||||
0x00, 0x00, 0x00, 0x00, /* value_length */
|
||||
};
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PacketDeserialiserEmpty, Type)
|
||||
{
|
||||
EXPECT_EQ(pd->packet_type(), (uint32_t)(1));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserEmpty, NumFields)
|
||||
{
|
||||
EXPECT_EQ(pd->num_fields(), (size_t)(0));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserEmpty, IsNull)
|
||||
{
|
||||
EXPECT_THROW({ pd->is_null(0); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserEmpty, GetDWORD)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserEmpty, GetData)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_data(0); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserEmpty, GetWString)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_wstring(0); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
class PacketDeserialiserNull: public PacketDeserialiserTest {
|
||||
protected:
|
||||
virtual void SetUp() override
|
||||
{
|
||||
static const unsigned char RAW[] = {
|
||||
0x02, 0x00, 0x00, 0x00, /* type */
|
||||
0x08, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, /* type */
|
||||
0x00, 0x00, 0x00, 0x00, /* value_length */
|
||||
};
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PacketDeserialiserNull, Type)
|
||||
{
|
||||
EXPECT_EQ(pd->packet_type(), (uint32_t)(2));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNull, NumFields)
|
||||
{
|
||||
EXPECT_EQ(pd->num_fields(), (size_t)(1));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNull, IsNull)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(0), true); });
|
||||
EXPECT_THROW({ pd->is_null(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNull, GetDWORD)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_dword(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNull, GetData)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_data(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_data(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNull, GetWString)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_wstring(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_wstring(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
class PacketDeserialiserDWORD: public PacketDeserialiserTest {
|
||||
protected:
|
||||
virtual void SetUp() override
|
||||
{
|
||||
static const unsigned char RAW[] = {
|
||||
0x03, 0x00, 0x00, 0x00, /* type */
|
||||
0x0C, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x01, 0x00, 0x00, 0x00, /* type */
|
||||
0x04, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x01, 0x23, 0x45, 0x67, /* value */
|
||||
};
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PacketDeserialiserDWORD, Type)
|
||||
{
|
||||
EXPECT_EQ(pd->packet_type(), (uint32_t)(3));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserDWORD, NumFields)
|
||||
{
|
||||
EXPECT_EQ(pd->num_fields(), (size_t)(1));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserDWORD, IsNull)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(0), false); });
|
||||
EXPECT_THROW({ pd->is_null(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserDWORD, GetDWORD)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->get_dword(0), (DWORD)(0x67452301)); });
|
||||
EXPECT_THROW({ pd->get_dword(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserDWORD, GetData)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_data(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_data(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserDWORD, GetWString)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_wstring(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_wstring(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
class PacketDeserialiserData: public PacketDeserialiserTest {
|
||||
protected:
|
||||
virtual void SetUp() override
|
||||
{
|
||||
static const unsigned char RAW[] = {
|
||||
0x04, 0x00, 0x00, 0x00, /* type */
|
||||
0x0E, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x02, 0x00, 0x00, 0x00, /* type */
|
||||
0x06, 0x00, 0x00, 0x00, /* value_length */
|
||||
0xFE, 0xED, 0xBE, 0xEF, /* value */
|
||||
0xAA, 0xAA,
|
||||
};
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PacketDeserialiserData, Type)
|
||||
{
|
||||
EXPECT_EQ(pd->packet_type(), (uint32_t)(4));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserData, NumFields)
|
||||
{
|
||||
EXPECT_EQ(pd->num_fields(), (size_t)(1));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserData, IsNull)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(0), false); });
|
||||
EXPECT_THROW({ pd->is_null(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserData, GetDWORD)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_dword(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserData, GetData)
|
||||
{
|
||||
const unsigned char EXPECT[] = { 0xFE, 0xED, 0xBE, 0xEF, 0xAA, 0xAA };
|
||||
std::pair<const void*, size_t> got;
|
||||
|
||||
ASSERT_NO_THROW({ got = pd->get_data(0); });
|
||||
|
||||
std::vector<unsigned char> got_data ((const unsigned char*)(got.first), (const unsigned char*)(got.first) + got.second);
|
||||
std::vector<unsigned char> expect_data(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
EXPECT_EQ(got_data, expect_data);
|
||||
|
||||
EXPECT_THROW({ pd->get_data(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserData, GetWString)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_wstring(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_wstring(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
class PacketDeserialiserWString: public PacketDeserialiserTest {
|
||||
protected:
|
||||
virtual void SetUp() override
|
||||
{
|
||||
static const unsigned char RAW[] = {
|
||||
0x05, 0x00, 0x00, 0x00, /* type */
|
||||
0x12, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x03, 0x00, 0x00, 0x00, /* type */
|
||||
0x0A, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x48, 0x00, 0x65, 0x00, /* value */
|
||||
0x6C, 0x00, 0x6C, 0x00,
|
||||
0x6F, 0x00,
|
||||
};
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PacketDeserialiserWString, Type)
|
||||
{
|
||||
EXPECT_EQ(pd->packet_type(), (uint32_t)(5));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserWString, NumFields)
|
||||
{
|
||||
EXPECT_EQ(pd->num_fields(), (size_t)(1));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserWString, IsNull)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(0), false); });
|
||||
EXPECT_THROW({ pd->is_null(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserWString, GetDWORD)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_dword(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserWString, GetData)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_data(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_data(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserWString, GetWString)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->get_wstring(0), L"Hello"); });
|
||||
EXPECT_THROW({ pd->get_wstring(1); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
class PacketDeserialiserNullDWORDDataWString: public PacketDeserialiserTest {
|
||||
protected:
|
||||
virtual void SetUp() override
|
||||
{
|
||||
static const unsigned char RAW[] = {
|
||||
0x34, 0x12, 0x00, 0x00, /* type */
|
||||
0x31, 0x00, 0x00, 0x00, /* value_length (49) */
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, /* type */
|
||||
0x00, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x01, 0x00, 0x00, 0x00, /* type */
|
||||
0x04, 0x00, 0x00, 0x00, /* value_length */
|
||||
0xFE, 0xED, 0x00, 0x00, /* value */
|
||||
|
||||
0x02, 0x00, 0x00, 0x00, /* type */
|
||||
0x05, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x01, 0x23, 0x45, 0x67, /* value */
|
||||
0x89,
|
||||
|
||||
0x03, 0x00, 0x00, 0x00, /* type */
|
||||
0x08, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x57, 0x00, 0x53, 0x00, /* value */
|
||||
0x74, 0x00, 0x72, 0x00,
|
||||
};
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PacketDeserialiserNullDWORDDataWString, Type)
|
||||
{
|
||||
EXPECT_EQ(pd->packet_type(), (uint32_t)(0x1234));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNullDWORDDataWString, NumFields)
|
||||
{
|
||||
EXPECT_EQ(pd->num_fields(), (size_t)(4));
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNullDWORDDataWString, IsNull)
|
||||
{
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(0), true); });
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(1), false); });
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(2), false); });
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->is_null(3), false); });
|
||||
|
||||
EXPECT_THROW({ pd->is_null(4); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNullDWORDDataWString, GetDWORD)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->get_dword(1), (DWORD)(0xEDFE)); });
|
||||
EXPECT_THROW({ pd->get_dword(2); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_dword(3); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_dword(4); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNullDWORDDataWString, GetData)
|
||||
{
|
||||
const unsigned char EXPECT[] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
|
||||
std::pair<const void*, size_t> got;
|
||||
|
||||
ASSERT_NO_THROW({ got = pd->get_data(2); });
|
||||
|
||||
std::vector<unsigned char> got_data ((const unsigned char*)(got.first), (const unsigned char*)(got.first) + got.second);
|
||||
std::vector<unsigned char> expect_data(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
EXPECT_EQ(got_data, expect_data);
|
||||
|
||||
EXPECT_THROW({ pd->get_data(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_data(1); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_data(3); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_data(4); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST_F(PacketDeserialiserNullDWORDDataWString, GetWString)
|
||||
{
|
||||
EXPECT_THROW({ pd->get_wstring(0); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_wstring(1); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_THROW({ pd->get_wstring(2); }, PacketDeserialiser::Error::TypeMismatch);
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->get_wstring(3), L"WStr"); });
|
||||
EXPECT_THROW({ pd->get_wstring(4); }, PacketDeserialiser::Error::MissingField);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, NoData)
|
||||
{
|
||||
EXPECT_THROW({ PacketDeserialiser p(NULL, 0); }, PacketDeserialiser::Error::Incomplete);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, PartialHeader)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
EXPECT_THROW({ PacketDeserialiser p(RAW, sizeof(RAW)); }, PacketDeserialiser::Error::Incomplete);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, PartialData)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
EXPECT_THROW({ PacketDeserialiser p(RAW, sizeof(RAW)); }, PacketDeserialiser::Error::Incomplete);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, ExtraData)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
EXPECT_NO_THROW({ PacketDeserialiser p(RAW, sizeof(RAW)); });
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, FieldShortHeader)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
EXPECT_THROW({ PacketDeserialiser p(RAW, sizeof(RAW)); }, PacketDeserialiser::Error::Malformed);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, FieldTooShort)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00,
|
||||
};
|
||||
|
||||
EXPECT_THROW({ PacketDeserialiser p(RAW, sizeof(RAW)); }, PacketDeserialiser::Error::Malformed);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, FieldTooLong)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00,
|
||||
};
|
||||
|
||||
EXPECT_THROW({ PacketDeserialiser p(RAW, sizeof(RAW)); }, PacketDeserialiser::Error::Malformed);
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, ZeroLengthDWORD)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00,
|
||||
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
PacketDeserialiser *pd = NULL;
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::Malformed);
|
||||
|
||||
delete pd;
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, UndersizeDWORD)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x0B, 0x00, 0x00, 0x00,
|
||||
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
PacketDeserialiser *pd = NULL;
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::Malformed);
|
||||
|
||||
delete pd;
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, OversizeDWORD)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x0D, 0x00, 0x00, 0x00,
|
||||
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
};
|
||||
|
||||
PacketDeserialiser *pd = NULL;
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
EXPECT_THROW({ pd->get_dword(0); }, PacketDeserialiser::Error::Malformed);
|
||||
|
||||
delete pd;
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, ZeroLengthData)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00,
|
||||
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
PacketDeserialiser *pd = NULL;
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
|
||||
EXPECT_NO_THROW({
|
||||
auto data = pd->get_data(0);
|
||||
EXPECT_EQ(data.second, (size_t)(0));
|
||||
});
|
||||
|
||||
delete pd;
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, ZeroLengthWString)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00,
|
||||
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
PacketDeserialiser *pd = NULL;
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
EXPECT_NO_THROW({ EXPECT_EQ(pd->get_wstring(0), L""); });
|
||||
|
||||
delete pd;
|
||||
}
|
||||
|
||||
TEST(PacketDeserialiser, OneByteWString)
|
||||
{
|
||||
const unsigned char RAW[] = {
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00,
|
||||
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
PacketDeserialiser *pd = NULL;
|
||||
|
||||
ASSERT_NO_THROW({ pd = new PacketDeserialiser(RAW, sizeof(RAW)); });
|
||||
EXPECT_THROW({ pd->get_wstring(0); }, PacketDeserialiser::Error::Malformed);
|
||||
|
||||
delete pd;
|
||||
}
|
167
tests/PacketSerialiser.cpp
Normal file
167
tests/PacketSerialiser.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../src/packet.hpp"
|
||||
|
||||
TEST(PacketSerialiser, Empty)
|
||||
{
|
||||
PacketSerialiser p(0xAA);
|
||||
|
||||
std::pair<const void*, size_t> raw = p.raw_packet();
|
||||
|
||||
const unsigned char EXPECT[] = {
|
||||
0xAA, 0x00, 0x00, 0x00, /* type */
|
||||
0x00, 0x00, 0x00, 0x00, /* value_length */
|
||||
};
|
||||
|
||||
std::vector<unsigned char> got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second);
|
||||
std::vector<unsigned char> expect(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
ASSERT_EQ(got, expect);
|
||||
}
|
||||
|
||||
TEST(PacketSerialiser, Null)
|
||||
{
|
||||
PacketSerialiser p(0xBB);
|
||||
p.append_null();
|
||||
|
||||
std::pair<const void*, size_t> raw = p.raw_packet();
|
||||
|
||||
const unsigned char EXPECT[] = {
|
||||
0xBB, 0x00, 0x00, 0x00, /* type */
|
||||
0x08, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, /* type */
|
||||
0x00, 0x00, 0x00, 0x00, /* value_length */
|
||||
};
|
||||
|
||||
std::vector<unsigned char> got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second);
|
||||
std::vector<unsigned char> expect(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
ASSERT_EQ(got, expect);
|
||||
}
|
||||
|
||||
TEST(PacketSerialiser, DWORD)
|
||||
{
|
||||
PacketSerialiser p(0xAABBCCDD);
|
||||
p.append_dword(0xFFEEDDCC);
|
||||
|
||||
std::pair<const void*, size_t> raw = p.raw_packet();
|
||||
|
||||
const unsigned char EXPECT[] = {
|
||||
0xDD, 0xCC, 0xBB, 0xAA, /* type */
|
||||
0x0C, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x01, 0x00, 0x00, 0x00, /* type */
|
||||
0x04, 0x00, 0x00, 0x00, /* value_length */
|
||||
0xCC, 0xDD, 0xEE, 0xFF, /* value */
|
||||
};
|
||||
|
||||
std::vector<unsigned char> got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second);
|
||||
std::vector<unsigned char> expect(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
ASSERT_EQ(got, expect);
|
||||
}
|
||||
|
||||
TEST(PacketSerialiser, Data)
|
||||
{
|
||||
PacketSerialiser p(0x1234);
|
||||
|
||||
const unsigned char DATA[] = {
|
||||
0x01, 0x23, 0x45, 0x67,
|
||||
0x89, 0xAB, 0xCD, 0xEF,
|
||||
};
|
||||
|
||||
p.append_data(DATA, sizeof(DATA));
|
||||
|
||||
std::pair<const void*, size_t> raw = p.raw_packet();
|
||||
|
||||
const unsigned char EXPECT[] = {
|
||||
0x34, 0x12, 0x00, 0x00, /* type */
|
||||
0x10, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x02, 0x00, 0x00, 0x00, /* type */
|
||||
0x08, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x01, 0x23, 0x45, 0x67, /* value */
|
||||
0x89, 0xAB, 0xCD, 0xEF,
|
||||
};
|
||||
|
||||
std::vector<unsigned char> got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second);
|
||||
std::vector<unsigned char> expect(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
ASSERT_EQ(got, expect);
|
||||
}
|
||||
|
||||
TEST(PacketSerialiser, WString)
|
||||
{
|
||||
PacketSerialiser p(0x1234);
|
||||
|
||||
p.append_wstring(L"Hello, I'm Gabe Newell");
|
||||
|
||||
std::pair<const void*, size_t> raw = p.raw_packet();
|
||||
|
||||
const unsigned char EXPECT[] = {
|
||||
0x34, 0x12, 0x00, 0x00, /* type */
|
||||
0x34, 0x00, 0x00, 0x00, /* value_length (52) */
|
||||
|
||||
0x03, 0x00, 0x00, 0x00, /* type */
|
||||
0x2C, 0x00, 0x00, 0x00, /* value_length (44) */
|
||||
0x48, 0x00, 0x65, 0x00, /* value */
|
||||
0x6C, 0x00, 0x6C, 0x00,
|
||||
0x6F, 0x00, 0x2C, 0x00,
|
||||
0x20, 0x00, 0x49, 0x00,
|
||||
0x27, 0x00, 0x6D, 0x00,
|
||||
0x20, 0x00, 0x47, 0x00,
|
||||
0x61, 0x00, 0x62, 0x00,
|
||||
0x65, 0x00, 0x20, 0x00,
|
||||
0x4E, 0x00, 0x65, 0x00,
|
||||
0x77, 0x00, 0x65, 0x00,
|
||||
0x6C, 0x00, 0x6C, 0x00
|
||||
};
|
||||
|
||||
std::vector<unsigned char> got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second);
|
||||
std::vector<unsigned char> expect(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
ASSERT_EQ(got, expect);
|
||||
}
|
||||
|
||||
TEST(PacketSerialiser, NullDWORDDataWString)
|
||||
{
|
||||
PacketSerialiser p(0x1234);
|
||||
|
||||
p.append_null();
|
||||
p.append_dword(0xEDFE);
|
||||
|
||||
const unsigned char DATA[] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
|
||||
p.append_data(DATA, sizeof(DATA));
|
||||
|
||||
p.append_wstring(L"WStr");
|
||||
|
||||
std::pair<const void*, size_t> raw = p.raw_packet();
|
||||
|
||||
const unsigned char EXPECT[] = {
|
||||
0x34, 0x12, 0x00, 0x00, /* type */
|
||||
0x31, 0x00, 0x00, 0x00, /* value_length (49) */
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, /* type */
|
||||
0x00, 0x00, 0x00, 0x00, /* value_length */
|
||||
|
||||
0x01, 0x00, 0x00, 0x00, /* type */
|
||||
0x04, 0x00, 0x00, 0x00, /* value_length */
|
||||
0xFE, 0xED, 0x00, 0x00, /* value */
|
||||
|
||||
0x02, 0x00, 0x00, 0x00, /* type */
|
||||
0x05, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x01, 0x23, 0x45, 0x67, /* value */
|
||||
0x89,
|
||||
|
||||
0x03, 0x00, 0x00, 0x00, /* type */
|
||||
0x08, 0x00, 0x00, 0x00, /* value_length */
|
||||
0x57, 0x00, 0x53, 0x00, /* value */
|
||||
0x74, 0x00, 0x72, 0x00,
|
||||
};
|
||||
|
||||
std::vector<unsigned char> got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second);
|
||||
std::vector<unsigned char> expect(EXPECT, EXPECT + sizeof(EXPECT));
|
||||
|
||||
ASSERT_EQ(got, expect);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user