SabrehavenServer/src/networkmessage.h
2019-09-29 22:59:23 +03:00

175 lines
4.0 KiB
C++

/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef FS_NETWORKMESSAGE_H_B853CFED58D1413A87ACED07B2926E03
#define FS_NETWORKMESSAGE_H_B853CFED58D1413A87ACED07B2926E03
#include "const.h"
class Item;
class Creature;
class Player;
struct Position;
class RSA;
class NetworkMessage
{
public:
typedef uint16_t MsgSize_t;
// Headers:
// 2 bytes for unencrypted message size
// 2 bytes for encrypted message size
static constexpr MsgSize_t INITIAL_BUFFER_POSITION = 4;
enum { HEADER_LENGTH = 2 };
enum { CHECKSUM_LENGTH = 4 };
enum { XTEA_MULTIPLE = 8 };
enum { MAX_BODY_LENGTH = NETWORKMESSAGE_MAXSIZE - HEADER_LENGTH - XTEA_MULTIPLE };
enum { MAX_PROTOCOL_BODY_LENGTH = MAX_BODY_LENGTH - 10 };
NetworkMessage() = default;
void reset() {
info = {};
}
// simply read functions for incoming message
uint8_t getByte() {
if (!canRead(1)) {
return 0;
}
return buffer[info.position++];
}
uint8_t getPreviousByte() {
return buffer[--info.position];
}
template<typename T>
T get() {
if (!canRead(sizeof(T))) {
return 0;
}
T v;
memcpy(&v, buffer + info.position, sizeof(T));
info.position += sizeof(T);
return v;
}
std::string getString(uint16_t stringLen = 0);
Position getPosition();
// skips count unknown/unused bytes in an incoming message
void skipBytes(int16_t count) {
info.position += count;
}
// simply write functions for outgoing message
void addByte(uint8_t value) {
if (!canAdd(1)) {
return;
}
buffer[info.position++] = value;
info.length++;
}
template<typename T>
void add(T value) {
if (!canAdd(sizeof(T))) {
return;
}
memcpy(buffer + info.position, &value, sizeof(T));
info.position += sizeof(T);
info.length += sizeof(T);
}
void addBytes(const char* bytes, size_t size);
void addPaddingBytes(size_t n);
void addString(const std::string& value);
void addDouble(double value, uint8_t precision = 2);
// write functions for complex types
void addPosition(const Position& pos);
void addItem(uint16_t id, uint8_t count);
void addItem(const Item* item);
void addItemId(uint16_t itemId);
MsgSize_t getLength() const {
return info.length;
}
void setLength(MsgSize_t newLength) {
info.length = newLength;
}
MsgSize_t getBufferPosition() const {
return info.position;
}
uint16_t getLengthHeader() const {
return static_cast<uint16_t>(buffer[0] | buffer[1] << 8);
}
bool isOverrun() const {
return info.overrun;
}
uint8_t* getBuffer() {
return buffer;
}
const uint8_t* getBuffer() const {
return buffer;
}
uint8_t* getBodyBuffer() {
info.position = 2;
return buffer + HEADER_LENGTH;
}
protected:
inline bool canAdd(size_t size) const {
return (size + info.position) < MAX_BODY_LENGTH;
}
inline bool canRead(int32_t size) {
if ((info.position + size) > (info.length + 8) || size >= (NETWORKMESSAGE_MAXSIZE - info.position)) {
info.overrun = true;
return false;
}
return true;
}
struct NetworkMessageInfo {
MsgSize_t length = 0;
MsgSize_t position = INITIAL_BUFFER_POSITION;
bool overrun = false;
};
NetworkMessageInfo info;
uint8_t buffer[NETWORKMESSAGE_MAXSIZE];
};
#endif // #ifndef __NETWORK_MESSAGE_H__