Network: Added Packet class for serialization
This commit is contained in:
		
							parent
							
								
									589dc083a5
								
							
						
					
					
						commit
						7d9b7394dd
					
				@ -1,11 +1,13 @@
 | 
			
		||||
set(SRCS
 | 
			
		||||
            network.cpp
 | 
			
		||||
            packet.cpp
 | 
			
		||||
            room.cpp
 | 
			
		||||
            room_member.cpp
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
set(HEADERS
 | 
			
		||||
            network.h
 | 
			
		||||
            packet.h
 | 
			
		||||
            room.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 New Issue
	
	Block a user