3 changed files with 423 additions and 0 deletions
@ -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
|
|||
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue