Network: Added Packet class for serialization
This commit is contained in:
parent
589dc083a5
commit
7d9b7394dd
|
@ -1,11 +1,13 @@
|
||||||
set(SRCS
|
set(SRCS
|
||||||
network.cpp
|
network.cpp
|
||||||
|
packet.cpp
|
||||||
room.cpp
|
room.cpp
|
||||||
room_member.cpp
|
room_member.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
network.h
|
network.h
|
||||||
|
packet.h
|
||||||
room.h
|
room.h
|
||||||
room_member.h
|
room_member.h
|
||||||
)
|
)
|
||||||
|
|
229
src/network/packet.cpp
Normal file
229
src/network/packet.cpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include "network/packet.h"
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
Packet::Packet() : read_pos(0), is_valid(true) {}
|
||||||
|
|
||||||
|
Packet::~Packet() {}
|
||||||
|
|
||||||
|
void Packet::Append(const void* in_data, std::size_t size_in_bytes) {
|
||||||
|
if (in_data && (size_in_bytes > 0)) {
|
||||||
|
std::size_t start = data.size();
|
||||||
|
data.resize(start + size_in_bytes);
|
||||||
|
std::memcpy(&data[start], in_data, size_in_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::Read(void* out_data, std::size_t size_in_bytes) {
|
||||||
|
if (out_data && CheckSize(size_in_bytes)) {
|
||||||
|
std::memcpy(out_data, &data[read_pos], size_in_bytes);
|
||||||
|
read_pos += size_in_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::Clear() {
|
||||||
|
data.clear();
|
||||||
|
read_pos = 0;
|
||||||
|
is_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* Packet::GetData() const {
|
||||||
|
return !data.empty() ? &data[0] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::IgnoreBytes(u32 length) {
|
||||||
|
read_pos += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t Packet::GetDataSize() const {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::EndOfPacket() const {
|
||||||
|
return read_pos >= data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::operator BoolType() const {
|
||||||
|
return is_valid ? &Packet::CheckSize : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(bool& out_data) {
|
||||||
|
u8 value;
|
||||||
|
if (*this >> value) {
|
||||||
|
out_data = (value != 0);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(s8& out_data) {
|
||||||
|
Read(&out_data, sizeof(out_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(u8& out_data) {
|
||||||
|
Read(&out_data, sizeof(out_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(s16& out_data) {
|
||||||
|
s16 value;
|
||||||
|
Read(&value, sizeof(value));
|
||||||
|
out_data = ntohs(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(u16& out_data) {
|
||||||
|
u16 value;
|
||||||
|
Read(&value, sizeof(value));
|
||||||
|
out_data = ntohs(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(s32& out_data) {
|
||||||
|
s32 value;
|
||||||
|
Read(&value, sizeof(value));
|
||||||
|
out_data = ntohl(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(u32& out_data) {
|
||||||
|
u32 value;
|
||||||
|
Read(&value, sizeof(value));
|
||||||
|
out_data = ntohl(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(float& out_data) {
|
||||||
|
Read(&out_data, sizeof(out_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(double& out_data) {
|
||||||
|
Read(&out_data, sizeof(out_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(char* out_data) {
|
||||||
|
// First extract string length
|
||||||
|
u32 length = 0;
|
||||||
|
*this >> length;
|
||||||
|
|
||||||
|
if ((length > 0) && CheckSize(length)) {
|
||||||
|
// Then extract characters
|
||||||
|
std::memcpy(out_data, &data[read_pos], length);
|
||||||
|
out_data[length] = '\0';
|
||||||
|
|
||||||
|
// Update reading position
|
||||||
|
read_pos += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator>>(std::string& out_data) {
|
||||||
|
// First extract string length
|
||||||
|
u32 length = 0;
|
||||||
|
*this >> length;
|
||||||
|
|
||||||
|
out_data.clear();
|
||||||
|
if ((length > 0) && CheckSize(length)) {
|
||||||
|
// Then extract characters
|
||||||
|
out_data.assign(&data[read_pos], length);
|
||||||
|
|
||||||
|
// Update reading position
|
||||||
|
read_pos += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(bool in_data) {
|
||||||
|
*this << static_cast<u8>(in_data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(s8 in_data) {
|
||||||
|
Append(&in_data, sizeof(in_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(u8 in_data) {
|
||||||
|
Append(&in_data, sizeof(in_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(s16 in_data) {
|
||||||
|
s16 toWrite = htons(in_data);
|
||||||
|
Append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(u16 in_data) {
|
||||||
|
u16 toWrite = htons(in_data);
|
||||||
|
Append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(s32 in_data) {
|
||||||
|
s32 toWrite = htonl(in_data);
|
||||||
|
Append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(u32 in_data) {
|
||||||
|
u32 toWrite = htonl(in_data);
|
||||||
|
Append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(float in_data) {
|
||||||
|
Append(&in_data, sizeof(in_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(double in_data) {
|
||||||
|
Append(&in_data, sizeof(in_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(const char* in_data) {
|
||||||
|
// First insert string length
|
||||||
|
u32 length = std::strlen(in_data);
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
Append(in_data, length * sizeof(char));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator<<(const std::string& in_data) {
|
||||||
|
// First insert string length
|
||||||
|
u32 length = static_cast<u32>(in_data.size());
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
if (length > 0)
|
||||||
|
Append(in_data.c_str(), length * sizeof(std::string::value_type));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::CheckSize(std::size_t size) {
|
||||||
|
is_valid = is_valid && (read_pos + size <= data.size());
|
||||||
|
|
||||||
|
return is_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
192
src/network/packet.h
Normal file
192
src/network/packet.h
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
/// A class for serialize data for network transfer. It also handles endianess
|
||||||
|
class Packet {
|
||||||
|
/// A bool-like type that cannot be converted to integer or pointer types
|
||||||
|
typedef bool (Packet::*BoolType)(std::size_t);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Packet();
|
||||||
|
~Packet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append data to the end of the packet
|
||||||
|
* @param data Pointer to the sequence of bytes to append
|
||||||
|
* @param size_in_bytes Number of bytes to append
|
||||||
|
*/
|
||||||
|
void Append(const void* data, std::size_t size_in_bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads data from the current read position of the packet
|
||||||
|
* @param out_data Pointer where the data should get written to
|
||||||
|
* @param size_in_bytes Number of bytes to read
|
||||||
|
*/
|
||||||
|
void Read(void* out_data, std::size_t size_in_bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the packet
|
||||||
|
* After calling Clear, the packet is empty.
|
||||||
|
*/
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignores bytes while reading
|
||||||
|
* @param length THe number of bytes to ignore
|
||||||
|
*/
|
||||||
|
void IgnoreBytes(u32 length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a pointer to the data contained in the packet
|
||||||
|
* @return Pointer to the data
|
||||||
|
*/
|
||||||
|
const void* GetData() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the number of bytes pointed to by
|
||||||
|
* what getData returns.
|
||||||
|
* @return Data size, in bytes
|
||||||
|
*/
|
||||||
|
std::size_t GetDataSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is useful to know if there is some data
|
||||||
|
* left to be read, without actually reading it.
|
||||||
|
* @return True if all data was read, false otherwise
|
||||||
|
*/
|
||||||
|
bool EndOfPacket() const;
|
||||||
|
/**
|
||||||
|
* Test the validity of the packet, for reading
|
||||||
|
* This operator allows to test the packet as a boolean
|
||||||
|
* variable, to check if a reading operation was successful.
|
||||||
|
*
|
||||||
|
* A packet will be in an invalid state if it has no more
|
||||||
|
* data to read.
|
||||||
|
*
|
||||||
|
* This behaviour is the same as standard C++ streams.
|
||||||
|
*
|
||||||
|
* Usage example:
|
||||||
|
* @code
|
||||||
|
* float x;
|
||||||
|
* packet >> x;
|
||||||
|
* if (packet)
|
||||||
|
* {
|
||||||
|
* // ok, x was extracted successfully
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // -- or --
|
||||||
|
*
|
||||||
|
* float x;
|
||||||
|
* if (packet >> x)
|
||||||
|
* {
|
||||||
|
* // ok, x was extracted successfully
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* Don't focus on the return type, it's equivalent to bool but
|
||||||
|
* it disallows unwanted implicit conversions to integer or
|
||||||
|
* pointer types.
|
||||||
|
*
|
||||||
|
* @return True if last data extraction from packet was successful
|
||||||
|
*/
|
||||||
|
operator BoolType() const;
|
||||||
|
|
||||||
|
/// Overloads of operator >> to read data from the packet
|
||||||
|
Packet& operator>>(bool& out_data);
|
||||||
|
Packet& operator>>(s8& out_data);
|
||||||
|
Packet& operator>>(u8& out_data);
|
||||||
|
Packet& operator>>(s16& out_data);
|
||||||
|
Packet& operator>>(u16& out_data);
|
||||||
|
Packet& operator>>(s32& out_data);
|
||||||
|
Packet& operator>>(u32& out_data);
|
||||||
|
Packet& operator>>(float& out_data);
|
||||||
|
Packet& operator>>(double& out_data);
|
||||||
|
Packet& operator>>(char* out_data);
|
||||||
|
Packet& operator>>(std::string& out_data);
|
||||||
|
template <typename T>
|
||||||
|
Packet& operator>>(std::vector<T>& out_data);
|
||||||
|
template <typename T, std::size_t S>
|
||||||
|
Packet& operator>>(std::array<T, S>& out_data);
|
||||||
|
|
||||||
|
/// Overloads of operator << to write data into the packet
|
||||||
|
Packet& operator<<(bool in_data);
|
||||||
|
Packet& operator<<(s8 in_data);
|
||||||
|
Packet& operator<<(u8 in_data);
|
||||||
|
Packet& operator<<(s16 in_data);
|
||||||
|
Packet& operator<<(u16 in_data);
|
||||||
|
Packet& operator<<(s32 in_data);
|
||||||
|
Packet& operator<<(u32 in_data);
|
||||||
|
Packet& operator<<(float in_data);
|
||||||
|
Packet& operator<<(double in_data);
|
||||||
|
Packet& operator<<(const char* in_data);
|
||||||
|
Packet& operator<<(const std::string& in_data);
|
||||||
|
template <typename T>
|
||||||
|
Packet& operator<<(const std::vector<T>& in_data);
|
||||||
|
template <typename T, std::size_t S>
|
||||||
|
Packet& operator<<(const std::array<T, S>& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Disallow comparisons between packets
|
||||||
|
bool operator==(const Packet& right) const;
|
||||||
|
bool operator!=(const Packet& right) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the packet can extract a given number of bytes
|
||||||
|
* This function updates accordingly the state of the packet.
|
||||||
|
* @param size Size to check
|
||||||
|
* @return True if size bytes can be read from the packet
|
||||||
|
*/
|
||||||
|
bool CheckSize(std::size_t size);
|
||||||
|
|
||||||
|
// Member data
|
||||||
|
std::vector<char> data; ///< Data stored in the packet
|
||||||
|
std::size_t read_pos; ///< Current reading position in the packet
|
||||||
|
bool is_valid; ///< Reading state of the packet
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Packet& Packet::operator>>(std::vector<T>& out_data) {
|
||||||
|
for (u32 i = 0; i < out_data.size(); ++i) {
|
||||||
|
T character = 0;
|
||||||
|
*this >> character;
|
||||||
|
out_data[i] = character;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t S>
|
||||||
|
Packet& Packet::operator>>(std::array<T, S>& out_data) {
|
||||||
|
for (u32 i = 0; i < out_data.size(); ++i) {
|
||||||
|
T character = 0;
|
||||||
|
*this >> character;
|
||||||
|
out_data[i] = character;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Packet& Packet::operator<<(const std::vector<T>& in_data) {
|
||||||
|
for (u32 i = 0; i < in_data.size(); ++i) {
|
||||||
|
*this << in_data[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t S>
|
||||||
|
Packet& Packet::operator<<(const std::array<T, S>& in_data) {
|
||||||
|
for (u32 i = 0; i < in_data.size(); ++i) {
|
||||||
|
*this << in_data[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
Loading…
Reference in a new issue