mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-21 20:56:23 +00:00
feat(Core/Packets): Port packet handling from TrinityCore (#5617)
* feat(Core/Packets): Port packet handling from TrinityCore * 1 * 2 * 3 * 1 * 2 * #3670 * 3 * 1 * codestyle * fix msvc warnings
This commit is contained in:
37
src/server/game/Server/Packet.cpp
Normal file
37
src/server/game/Server/Packet.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#include "Packet.h"
|
||||
#include "Errors.h"
|
||||
|
||||
WorldPackets::Packet::Packet(WorldPacket&& worldPacket) : _worldPacket(std::move(worldPacket))
|
||||
{
|
||||
}
|
||||
|
||||
WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize /*= 200*/) : Packet(WorldPacket(opcode, initialSize))
|
||||
{
|
||||
}
|
||||
|
||||
void WorldPackets::ServerPacket::Read()
|
||||
{
|
||||
ASSERT(!"Read not implemented for server packets.");
|
||||
}
|
||||
|
||||
WorldPackets::ClientPacket::ClientPacket(OpcodeClient expectedOpcode, WorldPacket&& packet) : Packet(std::move(packet))
|
||||
{
|
||||
ASSERT(GetOpcode() == expectedOpcode);
|
||||
}
|
||||
|
||||
WorldPackets::ClientPacket::ClientPacket(WorldPacket&& packet)
|
||||
: Packet(std::move(packet))
|
||||
{
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::ClientPacket::Write()
|
||||
{
|
||||
ASSERT(!"Write not allowed for client packets.");
|
||||
// Shut up some compilers
|
||||
return nullptr;
|
||||
}
|
||||
59
src/server/game/Server/Packet.h
Normal file
59
src/server/game/Server/Packet.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef PacketBaseWorld_h__
|
||||
#define PacketBaseWorld_h__
|
||||
|
||||
#include "WorldPacket.h"
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
class AC_GAME_API Packet
|
||||
{
|
||||
public:
|
||||
Packet(WorldPacket&& worldPacket);
|
||||
|
||||
virtual ~Packet() = default;
|
||||
|
||||
Packet(Packet const& right) = delete;
|
||||
Packet& operator=(Packet const& right) = delete;
|
||||
|
||||
virtual WorldPacket const* Write() = 0;
|
||||
virtual void Read() = 0;
|
||||
|
||||
WorldPacket const* GetRawPacket() const { return &_worldPacket; }
|
||||
size_t GetSize() const { return _worldPacket.size(); }
|
||||
|
||||
protected:
|
||||
WorldPacket _worldPacket;
|
||||
};
|
||||
|
||||
class AC_GAME_API ServerPacket : public Packet
|
||||
{
|
||||
public:
|
||||
ServerPacket(OpcodeServer opcode, size_t initialSize = 200);
|
||||
|
||||
void Read() final;
|
||||
|
||||
void Clear() { _worldPacket.clear(); }
|
||||
WorldPacket&& Move() { return std::move(_worldPacket); }
|
||||
void ShrinkToFit() { _worldPacket.shrink_to_fit(); }
|
||||
|
||||
OpcodeServer GetOpcode() const { return OpcodeServer(_worldPacket.GetOpcode()); }
|
||||
};
|
||||
|
||||
class AC_GAME_API ClientPacket : public Packet
|
||||
{
|
||||
public:
|
||||
ClientPacket(WorldPacket&& packet);
|
||||
ClientPacket(OpcodeClient expectedOpcode, WorldPacket&& packet);
|
||||
|
||||
WorldPacket const* Write() final;
|
||||
|
||||
OpcodeClient GetOpcode() const { return OpcodeClient(_worldPacket.GetOpcode()); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // PacketBaseWorld_h__
|
||||
9
src/server/game/Server/Packets/AllPackets.h
Normal file
9
src/server/game/Server/Packets/AllPackets.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef AllPackets_h__
|
||||
#define AllPackets_h__
|
||||
|
||||
#endif // AllPackets_h__
|
||||
59
src/server/game/Server/Packets/PacketUtilities.cpp
Normal file
59
src/server/game/Server/Packets/PacketUtilities.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#include "PacketUtilities.h"
|
||||
//#include "Hyperlinks.h"
|
||||
#include "Errors.h"
|
||||
#include <utf8.h>
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
|
||||
WorldPackets::InvalidStringValueException::InvalidStringValueException(std::string const& value) :
|
||||
ByteBufferInvalidValueException("string", value.c_str()) { }
|
||||
|
||||
WorldPackets::InvalidUtf8ValueException::InvalidUtf8ValueException(std::string const& value) :
|
||||
InvalidStringValueException(value) { }
|
||||
|
||||
WorldPackets::InvalidHyperlinkException::InvalidHyperlinkException(std::string const& value) :
|
||||
InvalidStringValueException(value) { }
|
||||
|
||||
WorldPackets::IllegalHyperlinkException::IllegalHyperlinkException(std::string const& value) :
|
||||
InvalidStringValueException(value) { }
|
||||
|
||||
bool WorldPackets::Strings::Utf8::Validate(std::string const& value)
|
||||
{
|
||||
if (!utf8::is_valid(value.begin(), value.end()))
|
||||
throw InvalidUtf8ValueException(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool WorldPackets::Strings::Hyperlinks::Validate(std::string const& value)
|
||||
//{
|
||||
// if (!Warhead::Hyperlinks::CheckAllLinks(value))
|
||||
// throw InvalidHyperlinkException(value);
|
||||
//
|
||||
// return true;
|
||||
//}
|
||||
|
||||
bool WorldPackets::Strings::NoHyperlinks::Validate(std::string const& value)
|
||||
{
|
||||
if (value.find('|') != std::string::npos)
|
||||
throw IllegalHyperlinkException(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WorldPackets::PacketArrayMaxCapacityException::PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit)
|
||||
{
|
||||
std::ostringstream builder;
|
||||
builder << "Attempted to read more array elements from packet " << requestedSize << " than allowed " << sizeLimit;
|
||||
message().assign(builder.str());
|
||||
}
|
||||
|
||||
void WorldPackets::CheckCompactArrayMaskOverflow(std::size_t index, std::size_t limit)
|
||||
{
|
||||
ASSERT(index < limit, "Attempted to insert " SZFMTD " values into CompactArray but it can only hold " SZFMTD, index, limit);
|
||||
}
|
||||
286
src/server/game/Server/Packets/PacketUtilities.h
Normal file
286
src/server/game/Server/Packets/PacketUtilities.h
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef PacketUtilities_h__
|
||||
#define PacketUtilities_h__
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "Tuples.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
class InvalidStringValueException : public ByteBufferInvalidValueException
|
||||
{
|
||||
public:
|
||||
InvalidStringValueException(std::string const& value);
|
||||
|
||||
std::string const& GetInvalidValue() const { return _value; }
|
||||
|
||||
private:
|
||||
std::string _value;
|
||||
};
|
||||
|
||||
class InvalidUtf8ValueException : public InvalidStringValueException
|
||||
{
|
||||
public:
|
||||
InvalidUtf8ValueException(std::string const& value);
|
||||
};
|
||||
|
||||
class InvalidHyperlinkException : public InvalidStringValueException
|
||||
{
|
||||
public:
|
||||
InvalidHyperlinkException(std::string const& value);
|
||||
};
|
||||
|
||||
class IllegalHyperlinkException : public InvalidStringValueException
|
||||
{
|
||||
public:
|
||||
IllegalHyperlinkException(std::string const& value);
|
||||
};
|
||||
|
||||
namespace Strings
|
||||
{
|
||||
struct RawBytes { static bool Validate(std::string const& /*value*/) { return true; } };
|
||||
template<std::size_t MaxBytesWithoutNullTerminator>
|
||||
struct ByteSize { static bool Validate(std::string const& value) { return value.size() <= MaxBytesWithoutNullTerminator; } };
|
||||
struct Utf8 { static bool Validate(std::string const& value); };
|
||||
//struct Hyperlinks { static bool Validate(std::string const& value); };
|
||||
struct NoHyperlinks { static bool Validate(std::string const& value); };
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for automated prevention of invalid strings in client packets
|
||||
*/
|
||||
template<std::size_t MaxBytesWithoutNullTerminator, typename... Validators>
|
||||
class String
|
||||
{
|
||||
using ValidatorList = std::conditional_t<!acore::has_type<Strings::RawBytes, std::tuple<Validators...>>::value,
|
||||
std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Strings::Utf8, Validators...>,
|
||||
std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Validators...>>;
|
||||
|
||||
public:
|
||||
bool empty() const { return _storage.empty(); }
|
||||
char const* c_str() const { return _storage.c_str(); }
|
||||
|
||||
operator std::string_view() const { return _storage; }
|
||||
operator std::string&() { return _storage; }
|
||||
operator std::string const&() const { return _storage; }
|
||||
|
||||
std::string&& Move() { return std::move(_storage); }
|
||||
|
||||
friend ByteBuffer& operator>>(ByteBuffer& data, String& value)
|
||||
{
|
||||
value._storage = data.ReadCString(false);
|
||||
value.Validate();
|
||||
return data;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Validate() const
|
||||
{
|
||||
return ValidateNth(std::make_index_sequence<std::tuple_size_v<ValidatorList>>{});
|
||||
}
|
||||
|
||||
template<std::size_t... indexes>
|
||||
bool ValidateNth(std::index_sequence<indexes...>) const
|
||||
{
|
||||
return (std::tuple_element_t<indexes, ValidatorList>::Validate(_storage) && ...);
|
||||
}
|
||||
|
||||
std::string _storage;
|
||||
};
|
||||
|
||||
class PacketArrayMaxCapacityException : public ByteBufferException
|
||||
{
|
||||
public:
|
||||
PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit);
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility class for automated prevention of loop counter spoofing in client packets
|
||||
*/
|
||||
template<typename T, std::size_t N = 1000 /*select a sane default limit*/>
|
||||
class Array
|
||||
{
|
||||
typedef std::vector<T> storage_type;
|
||||
|
||||
typedef typename storage_type::value_type value_type;
|
||||
typedef typename storage_type::size_type size_type;
|
||||
typedef typename storage_type::reference reference;
|
||||
typedef typename storage_type::const_reference const_reference;
|
||||
typedef typename storage_type::iterator iterator;
|
||||
typedef typename storage_type::const_iterator const_iterator;
|
||||
|
||||
public:
|
||||
Array() : _limit(N) { }
|
||||
Array(size_type limit) : _limit(limit) { }
|
||||
|
||||
iterator begin() { return _storage.begin(); }
|
||||
const_iterator begin() const { return _storage.begin(); }
|
||||
|
||||
iterator end() { return _storage.end(); }
|
||||
const_iterator end() const { return _storage.end(); }
|
||||
|
||||
size_type size() const { return _storage.size(); }
|
||||
bool empty() const { return _storage.empty(); }
|
||||
|
||||
reference operator[](size_type i) { return _storage[i]; }
|
||||
const_reference operator[](size_type i) const { return _storage[i]; }
|
||||
|
||||
void resize(size_type newSize)
|
||||
{
|
||||
if (newSize > _limit)
|
||||
{
|
||||
throw PacketArrayMaxCapacityException(newSize, _limit);
|
||||
}
|
||||
|
||||
_storage.resize(newSize);
|
||||
}
|
||||
|
||||
void reserve(size_type newSize)
|
||||
{
|
||||
if (newSize > _limit)
|
||||
{
|
||||
throw PacketArrayMaxCapacityException(newSize, _limit);
|
||||
}
|
||||
|
||||
_storage.reserve(newSize);
|
||||
}
|
||||
|
||||
void push_back(value_type const& value)
|
||||
{
|
||||
if (_storage.size() >= _limit)
|
||||
{
|
||||
throw PacketArrayMaxCapacityException(_storage.size() + 1, _limit);
|
||||
}
|
||||
|
||||
_storage.push_back(value);
|
||||
}
|
||||
|
||||
void push_back(value_type&& value)
|
||||
{
|
||||
if (_storage.size() >= _limit)
|
||||
{
|
||||
throw PacketArrayMaxCapacityException(_storage.size() + 1, _limit);
|
||||
}
|
||||
|
||||
_storage.push_back(std::forward<value_type>(value));
|
||||
}
|
||||
|
||||
private:
|
||||
storage_type _storage;
|
||||
size_type _limit;
|
||||
};
|
||||
|
||||
void CheckCompactArrayMaskOverflow(std::size_t index, std::size_t limit);
|
||||
|
||||
template <typename T>
|
||||
class CompactArray
|
||||
{
|
||||
public:
|
||||
CompactArray() : _mask(0) { }
|
||||
|
||||
CompactArray(CompactArray const& right)
|
||||
: _mask(right._mask), _contents(right._contents) { }
|
||||
|
||||
CompactArray(CompactArray&& right)
|
||||
: _mask(right._mask), _contents(std::move(right._contents))
|
||||
{
|
||||
right._mask = 0;
|
||||
}
|
||||
|
||||
CompactArray& operator=(CompactArray const& right)
|
||||
{
|
||||
_mask = right._mask;
|
||||
_contents = right._contents;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompactArray& operator=(CompactArray&& right)
|
||||
{
|
||||
_mask = right._mask;
|
||||
right._mask = 0;
|
||||
_contents = std::move(right._contents);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32 GetMask() const { return _mask; }
|
||||
T const& operator[](std::size_t index) const { return _contents.at(index); }
|
||||
std::size_t GetSize() const { return _contents.size(); }
|
||||
|
||||
void Insert(std::size_t index, T const& value)
|
||||
{
|
||||
CheckCompactArrayMaskOverflow(index, sizeof(_mask) * 8);
|
||||
|
||||
_mask |= 1 << index;
|
||||
|
||||
if (_contents.size() <= index)
|
||||
{
|
||||
_contents.resize(index + 1);
|
||||
}
|
||||
|
||||
_contents[index] = value;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
_mask = 0;
|
||||
_contents.clear();
|
||||
}
|
||||
|
||||
bool operator==(CompactArray const& r) const
|
||||
{
|
||||
if (_mask != r._mask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _contents == r._contents;
|
||||
}
|
||||
|
||||
bool operator!=(CompactArray const& r) const { return !(*this == r); }
|
||||
|
||||
private:
|
||||
uint32 _mask;
|
||||
std::vector<T> _contents;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
ByteBuffer& operator<<(ByteBuffer& data, CompactArray<T> const& v)
|
||||
{
|
||||
uint32 mask = v.GetMask();
|
||||
data << uint32(mask);
|
||||
|
||||
for (std::size_t i = 0; i < v.GetSize(); ++i)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
data << v[i];
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ByteBuffer& operator>>(ByteBuffer& data, CompactArray<T>& v)
|
||||
{
|
||||
uint32 mask;
|
||||
data >> mask;
|
||||
|
||||
for (std::size_t index = 0; mask != 0; mask >>= 1, ++index)
|
||||
{
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
v.Insert(index, data.read<T>());
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PacketUtilities_h__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
/// \addtogroup u2w
|
||||
@@ -11,12 +10,12 @@
|
||||
#ifndef _OPCODES_H
|
||||
#define _OPCODES_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
|
||||
/// List of Opcodes
|
||||
enum Opcodes
|
||||
enum Opcodes : uint16
|
||||
{
|
||||
MSG_NULL_ACTION = 0x000,
|
||||
CMSG_BOOTME = 0x001,
|
||||
CMSG_DBLOOKUP = 0x002,
|
||||
SMSG_DBLOOKUP = 0x003,
|
||||
@@ -1330,6 +1329,15 @@ enum Opcodes
|
||||
NUM_MSG_TYPES = 0x51F
|
||||
};
|
||||
|
||||
enum OpcodeMisc : uint16
|
||||
{
|
||||
NUM_OPCODE_HANDLERS = NUM_MSG_TYPES,
|
||||
NULL_OPCODE = 0x0000
|
||||
};
|
||||
|
||||
typedef Opcodes OpcodeClient;
|
||||
typedef Opcodes OpcodeServer;
|
||||
|
||||
/// Player state
|
||||
enum SessionStatus
|
||||
{
|
||||
@@ -1350,34 +1358,63 @@ enum PacketProcessing
|
||||
class WorldSession;
|
||||
class WorldPacket;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct OpcodeHandler
|
||||
class OpcodeHandler
|
||||
{
|
||||
char const* name;
|
||||
SessionStatus status;
|
||||
PacketProcessing packetProcessing;
|
||||
void (WorldSession::*handler)(WorldPacket& recvPacket);
|
||||
public:
|
||||
OpcodeHandler(char const* name, SessionStatus status) : Name(name), Status(status) { }
|
||||
virtual ~OpcodeHandler() { }
|
||||
|
||||
char const* Name;
|
||||
SessionStatus Status;
|
||||
};
|
||||
|
||||
extern OpcodeHandler opcodeTable[NUM_MSG_TYPES];
|
||||
class ClientOpcodeHandler : public OpcodeHandler
|
||||
{
|
||||
public:
|
||||
ClientOpcodeHandler(char const* name, SessionStatus status, PacketProcessing processing)
|
||||
: OpcodeHandler(name, status), ProcessingPlace(processing) { }
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
virtual void Call(WorldSession* session, WorldPacket& packet) const = 0;
|
||||
|
||||
PacketProcessing ProcessingPlace;
|
||||
};
|
||||
|
||||
class ServerOpcodeHandler : public OpcodeHandler
|
||||
{
|
||||
public:
|
||||
ServerOpcodeHandler(char const* name, SessionStatus status)
|
||||
: OpcodeHandler(name, status) { }
|
||||
};
|
||||
|
||||
class OpcodeTable
|
||||
{
|
||||
public:
|
||||
OpcodeTable();
|
||||
|
||||
OpcodeTable(OpcodeTable const&) = delete;
|
||||
OpcodeTable& operator=(OpcodeTable const&) = delete;
|
||||
|
||||
~OpcodeTable();
|
||||
|
||||
void Initialize();
|
||||
|
||||
ClientOpcodeHandler const* operator[](Opcodes index) const
|
||||
{
|
||||
return _internalTableClient[index];
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Handler, Handler HandlerFunction>
|
||||
void ValidateAndSetClientOpcode(OpcodeClient opcode, char const* name, SessionStatus status, PacketProcessing processing);
|
||||
|
||||
void ValidateAndSetServerOpcode(OpcodeServer opcode, char const* name, SessionStatus status);
|
||||
|
||||
ClientOpcodeHandler* _internalTableClient[NUM_OPCODE_HANDLERS];
|
||||
};
|
||||
|
||||
extern OpcodeTable opcodeTable;
|
||||
|
||||
/// Lookup opcode name for human understandable logging
|
||||
inline const char* LookupOpcodeName(uint16 id)
|
||||
{
|
||||
if (id >= NUM_MSG_TYPES)
|
||||
return "Received unknown opcode, it's more than max!";
|
||||
return opcodeTable[id].name;
|
||||
}
|
||||
std::string GetOpcodeNameForLogging(Opcodes opcode);
|
||||
|
||||
#endif
|
||||
/// @}
|
||||
|
||||
74
src/server/game/Server/WorldPacket.h
Normal file
74
src/server/game/Server/WorldPacket.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef _WORLDPACKET_H_
|
||||
#define _WORLDPACKET_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Duration.h"
|
||||
|
||||
class WorldPacket : public ByteBuffer
|
||||
{
|
||||
public:
|
||||
// just container for later use
|
||||
WorldPacket() : ByteBuffer(0), m_opcode(NULL_OPCODE) { }
|
||||
|
||||
explicit WorldPacket(uint16 opcode, size_t res = 200) :
|
||||
ByteBuffer(res), m_opcode(opcode) { }
|
||||
|
||||
WorldPacket(WorldPacket&& packet) noexcept :
|
||||
ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode) { }
|
||||
|
||||
WorldPacket(WorldPacket&& packet, TimePoint receivedTime) :
|
||||
ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode), m_receivedTime(receivedTime) { }
|
||||
|
||||
WorldPacket(WorldPacket const& right) :
|
||||
ByteBuffer(right), m_opcode(right.m_opcode) { }
|
||||
|
||||
WorldPacket& operator=(WorldPacket const& right)
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
m_opcode = right.m_opcode;
|
||||
ByteBuffer::operator=(right);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
WorldPacket& operator=(WorldPacket&& right) noexcept
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
m_opcode = right.m_opcode;
|
||||
ByteBuffer::operator=(std::move(right));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
WorldPacket(uint16 opcode, MessageBuffer&& buffer) :
|
||||
ByteBuffer(std::move(buffer)), m_opcode(opcode) { }
|
||||
|
||||
void Initialize(uint16 opcode, size_t newres = 200)
|
||||
{
|
||||
clear();
|
||||
_storage.reserve(newres);
|
||||
m_opcode = opcode;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16 GetOpcode() const { return m_opcode; }
|
||||
void SetOpcode(uint16 opcode) { m_opcode = opcode; }
|
||||
|
||||
[[nodiscard]] TimePoint GetReceivedTime() const { return m_receivedTime; }
|
||||
|
||||
protected:
|
||||
uint16 m_opcode;
|
||||
TimePoint m_receivedTime; // only set for a specific set of opcodes, for performance reasons.
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
#include "PacketUtilities.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "SavingSystem.h"
|
||||
@@ -42,48 +43,49 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::string const DefaultPlayerName = "<none>";
|
||||
|
||||
} // namespace
|
||||
}
|
||||
|
||||
bool MapSessionFilter::Process(WorldPacket* packet)
|
||||
{
|
||||
if (packet->GetOpcode() >= NUM_MSG_TYPES)
|
||||
ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())];
|
||||
|
||||
//let's check if our opcode can be really processed in Map::Update()
|
||||
if (opHandle->ProcessingPlace == PROCESS_INPLACE)
|
||||
return true;
|
||||
|
||||
OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];
|
||||
|
||||
if (opHandle.packetProcessing == PROCESS_INPLACE)
|
||||
return true;
|
||||
|
||||
if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
|
||||
//we do not process thread-unsafe packets
|
||||
if (opHandle->ProcessingPlace == PROCESS_THREADUNSAFE)
|
||||
return false;
|
||||
|
||||
Player* player = m_pSession->GetPlayer();
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
//in Map::Update() we do not process packets where player is not in world!
|
||||
return player->IsInWorld();
|
||||
}
|
||||
|
||||
//we should process ALL packets when player is not in world/logged in
|
||||
//OR packet handler is not thread-safe!
|
||||
bool WorldSessionFilter::Process(WorldPacket* packet)
|
||||
{
|
||||
if (packet->GetOpcode() >= NUM_MSG_TYPES)
|
||||
ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())];
|
||||
|
||||
//check if packet handler is supposed to be safe
|
||||
if (opHandle->ProcessingPlace == PROCESS_INPLACE)
|
||||
return true;
|
||||
|
||||
OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];
|
||||
|
||||
if (opHandle.packetProcessing == PROCESS_INPLACE)
|
||||
return true;
|
||||
|
||||
if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
|
||||
//thread-unsafe packets should be processed in World::UpdateSessions()
|
||||
if (opHandle->ProcessingPlace == PROCESS_THREADUNSAFE)
|
||||
return true;
|
||||
|
||||
//no player attached? -> our client! ^^
|
||||
Player* player = m_pSession->GetPlayer();
|
||||
if (!player)
|
||||
return true;
|
||||
|
||||
//lets process all packets for non-in-the-world player
|
||||
return (player->IsInWorld() == false);
|
||||
}
|
||||
|
||||
@@ -198,6 +200,8 @@ ObjectGuid::LowType WorldSession::GetGuidLow() const
|
||||
/// Send a packet to the client
|
||||
void WorldSession::SendPacket(WorldPacket const* packet)
|
||||
{
|
||||
ASSERT(packet->GetOpcode() != NULL_OPCODE);
|
||||
|
||||
if (!m_Socket)
|
||||
return;
|
||||
|
||||
@@ -254,6 +258,25 @@ void WorldSession::QueuePacket(WorldPacket* new_packet)
|
||||
_recvQueue.add(new_packet);
|
||||
}
|
||||
|
||||
/// Logging helper for unexpected opcodes
|
||||
void WorldSession::LogUnexpectedOpcode(WorldPacket* packet, char const* status, const char* reason)
|
||||
{
|
||||
LOG_ERROR("network.opcode", "Received unexpected opcode %s Status: %s Reason: %s from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), status, reason, GetPlayerInfo().c_str());
|
||||
}
|
||||
|
||||
/// Logging helper for unexpected opcodes
|
||||
void WorldSession::LogUnprocessedTail(WorldPacket* packet)
|
||||
{
|
||||
if (!sLog->ShouldLog("network.opcode", LogLevel::LOG_LEVEL_TRACE) || packet->rpos() >= packet->wpos())
|
||||
return;
|
||||
|
||||
LOG_TRACE("network.opcode", "Unprocessed tail data (read stop at %u from %u) Opcode %s from %s",
|
||||
uint32(packet->rpos()), uint32(packet->wpos()), GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
|
||||
packet->print_storage();
|
||||
}
|
||||
|
||||
/// Update the WorldSession (triggered by World update)
|
||||
bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
{
|
||||
@@ -271,7 +294,6 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
|
||||
uint32 _startMSTime = getMSTime();
|
||||
WorldPacket* packet = nullptr;
|
||||
WorldPacket* movementPacket = nullptr;
|
||||
bool deletePacket = true;
|
||||
WorldPacket* firstDelayedPacket = nullptr;
|
||||
uint32 processedPackets = 0;
|
||||
@@ -279,96 +301,92 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
|
||||
while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater))
|
||||
{
|
||||
if (packet->GetOpcode() >= NUM_MSG_TYPES)
|
||||
OpcodeClient opcode = static_cast<OpcodeClient>(packet->GetOpcode());
|
||||
ClientOpcodeHandler const* opHandle = opcodeTable[opcode];
|
||||
|
||||
try
|
||||
{
|
||||
LOG_ERROR("server", "WorldSession Packet filter: received non-existent opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
|
||||
}
|
||||
else
|
||||
{
|
||||
OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()];
|
||||
try
|
||||
switch (opHandle->Status)
|
||||
{
|
||||
switch (opHandle.status)
|
||||
case STATUS_LOGGEDIN:
|
||||
if (!_player)
|
||||
{
|
||||
case STATUS_LOGGEDIN:
|
||||
if (!_player)
|
||||
{
|
||||
// pussywizard: such packets were sent to do something for a character that has already logged out, skip them
|
||||
}
|
||||
else if (!_player->IsInWorld())
|
||||
{
|
||||
// pussywizard: such packets may do something important and the player is just being teleported, move to the end of the queue
|
||||
// pussywizard: previously such were skipped, so leave it as it is xD proper code below if we wish to change that
|
||||
|
||||
// pussywizard: requeue only important packets not related to maps (PROCESS_THREADUNSAFE)
|
||||
/*if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
|
||||
{
|
||||
if (!firstDelayedPacket)
|
||||
firstDelayedPacket = packet;
|
||||
deletePacket = false;
|
||||
QueuePacket(packet);
|
||||
}*/
|
||||
}
|
||||
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (movementPacket)
|
||||
{
|
||||
HandleMovementOpcodes(*movementPacket);
|
||||
delete movementPacket;
|
||||
movementPacket = nullptr;
|
||||
}
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_TRANSFER:
|
||||
if (_player && !_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (movementPacket)
|
||||
{
|
||||
delete movementPacket;
|
||||
movementPacket = nullptr;
|
||||
}
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_AUTHED:
|
||||
if (m_inQueue) // prevent cheating
|
||||
break;
|
||||
|
||||
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_NEVER:
|
||||
break;
|
||||
case STATUS_UNHANDLED:
|
||||
break;
|
||||
// pussywizard: such packets were sent to do something for a character that has already logged out, skip them
|
||||
}
|
||||
else if (!_player->IsInWorld())
|
||||
{
|
||||
// pussywizard: such packets may do something important and the player is just being teleported, move to the end of the queue
|
||||
// pussywizard: previously such were skipped, so leave it as it is xD proper code below if we wish to change that
|
||||
|
||||
// pussywizard: requeue only important packets not related to maps (PROCESS_THREADUNSAFE)
|
||||
/*if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
|
||||
{
|
||||
if (!firstDelayedPacket)
|
||||
firstDelayedPacket = packet;
|
||||
deletePacket = false;
|
||||
QueuePacket(packet);
|
||||
}*/
|
||||
}
|
||||
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
opHandle->Call(this, *packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_TRANSFER:
|
||||
if (_player && !_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
opHandle->Call(this, *packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_AUTHED:
|
||||
if (m_inQueue) // prevent cheating
|
||||
break;
|
||||
|
||||
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
opHandle->Call(this, *packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_NEVER:
|
||||
LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
break;
|
||||
case STATUS_UNHANDLED:
|
||||
LOG_DEBUG("network.opcode", "Received not handled opcode %s from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
break;
|
||||
}
|
||||
catch (ByteBufferException const&)
|
||||
}
|
||||
catch (WorldPackets::PacketArrayMaxCapacityException const& pamce)
|
||||
{
|
||||
LOG_ERROR("network", "PacketArrayMaxCapacityException: %s while parsing %s from %s.",
|
||||
pamce.what(), GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
}
|
||||
catch (ByteBufferException const&)
|
||||
{
|
||||
LOG_ERROR("server", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
|
||||
if (sLog->ShouldLog("network", LogLevel::LOG_LEVEL_DEBUG))
|
||||
{
|
||||
LOG_ERROR("server", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
|
||||
if (sLog->ShouldLog("network", LogLevel::LOG_LEVEL_DEBUG))
|
||||
{
|
||||
LOG_DEBUG("network", "Dumping error causing packet:");
|
||||
packet->hexlike();
|
||||
}
|
||||
LOG_DEBUG("network", "Dumping error causing packet:");
|
||||
packet->hexlike();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,20 +395,18 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
|
||||
deletePacket = true;
|
||||
|
||||
if (++processedPackets >= 150) // limit (by count) packets processed in one update, prevent DDoS
|
||||
#define MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE 100
|
||||
processedPackets++;
|
||||
|
||||
//process only a max amout of packets in 1 Update() call.
|
||||
//Any leftover will be processed in next update
|
||||
if (processedPackets > MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE)
|
||||
break;
|
||||
|
||||
if (getMSTimeDiff(_startMSTime, getMSTime()) >= 3) // limit (by time) packets processed in one update, prevent DDoS
|
||||
break;
|
||||
}
|
||||
|
||||
if (movementPacket)
|
||||
{
|
||||
if (_player && _player->IsInWorld())
|
||||
HandleMovementOpcodes(*movementPacket);
|
||||
delete movementPacket;
|
||||
}
|
||||
|
||||
if (m_Socket && !m_Socket->IsClosed())
|
||||
ProcessQueryCallbacks();
|
||||
|
||||
@@ -464,7 +480,7 @@ void WorldSession::HandleTeleportTimeout(bool updateInSessions)
|
||||
{
|
||||
if (GetPlayer()->IsBeingTeleportedFar() && GetPlayer()->GetSemaphoreTeleportFar() + sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_FAR) < currTime)
|
||||
while (GetPlayer() && GetPlayer()->IsBeingTeleportedFar())
|
||||
HandleMoveWorldportAckOpcode();
|
||||
HandleMoveWorldportAck();
|
||||
}
|
||||
else // session update from Map::Update
|
||||
{
|
||||
@@ -489,7 +505,7 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
{
|
||||
// finish pending transfers before starting the logout
|
||||
while (_player && _player->IsBeingTeleportedFar())
|
||||
HandleMoveWorldportAckOpcode();
|
||||
HandleMoveWorldportAck();
|
||||
|
||||
m_playerLogout = true;
|
||||
m_playerSave = save;
|
||||
@@ -577,7 +593,7 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
// Repop at GraveYard or other player far teleport will prevent saving player because of not present map
|
||||
// Teleport player immediately for correct player save
|
||||
while (_player && _player->IsBeingTeleportedFar())
|
||||
HandleMoveWorldportAckOpcode();
|
||||
HandleMoveWorldportAck();
|
||||
|
||||
///- empty buyback items and save the player in the database
|
||||
// some save parts only correctly work in case player present in map/player_lists (pets, etc)
|
||||
@@ -703,24 +719,28 @@ char const* WorldSession::GetAcoreString(uint32 entry) const
|
||||
return sObjectMgr->GetAcoreString(entry, GetSessionDbLocaleIndex());
|
||||
}
|
||||
|
||||
void WorldSession::Handle_NULL(WorldPacket& recvPacket)
|
||||
void WorldSession::Handle_NULL(WorldPacket& null)
|
||||
{
|
||||
LOG_ERROR("server", "SESSION: received unhandled opcode %s (0x%.4X)", LookupOpcodeName(recvPacket.GetOpcode()), recvPacket.GetOpcode());
|
||||
LOG_ERROR("network.opcode", "Received unhandled opcode %s from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeClient>(null.GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
}
|
||||
|
||||
void WorldSession::Handle_EarlyProccess(WorldPacket& recvPacket)
|
||||
{
|
||||
LOG_ERROR("server", "SESSION: received opcode %s (0x%.4X) that must be processed in WorldSocket::OnRead", LookupOpcodeName(recvPacket.GetOpcode()), recvPacket.GetOpcode());
|
||||
LOG_ERROR("network.opcode", "Received opcode %s that must be processed in WorldSocket::ReadDataHandler from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeClient>(recvPacket.GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
}
|
||||
|
||||
void WorldSession::Handle_ServerSide(WorldPacket& recvPacket)
|
||||
{
|
||||
LOG_ERROR("server", "SESSION: received server-side opcode %s (0x%.4X)", LookupOpcodeName(recvPacket.GetOpcode()), recvPacket.GetOpcode());
|
||||
LOG_ERROR("network.opcode", "Received server-side opcode %s from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeServer>(recvPacket.GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
}
|
||||
|
||||
void WorldSession::Handle_Deprecated(WorldPacket& recvPacket)
|
||||
{
|
||||
LOG_ERROR("server", "SESSION: received deprecated opcode %s (0x%.4X)", LookupOpcodeName(recvPacket.GetOpcode()), recvPacket.GetOpcode());
|
||||
LOG_ERROR("network.opcode", "Received deprecated opcode %s from %s",
|
||||
GetOpcodeNameForLogging(static_cast<OpcodeClient>(recvPacket.GetOpcode())).c_str(), GetPlayerInfo().c_str());
|
||||
}
|
||||
|
||||
void WorldSession::SendAuthWaitQue(uint32 position)
|
||||
@@ -1392,9 +1412,9 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
|
||||
if (++packetCounter.amountCounter <= maxPacketCounterAllowed)
|
||||
return true;
|
||||
|
||||
LOG_INFO("server", "AntiDOS: Account %u, IP: %s, Ping: %u, Character %s, flooding packet (opc: %s (0x%X), count: %u)",
|
||||
Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(),
|
||||
Session->GetPlayerName().c_str(), opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter);
|
||||
LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)",
|
||||
Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(),
|
||||
opcodeTable[static_cast<OpcodeClient>(p.GetOpcode())]->Name, p.GetOpcode(), packetCounter.amountCounter);
|
||||
|
||||
switch (_policy)
|
||||
{
|
||||
@@ -1402,7 +1422,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
|
||||
return true;
|
||||
case POLICY_KICK:
|
||||
{
|
||||
LOG_INFO("server", "AntiDOS: Player %s kicked!", Session->GetPlayerName().c_str());
|
||||
LOG_INFO("network", "AntiDOS: Player %s kicked!", Session->GetPlayerName().c_str());
|
||||
Session->KickPlayer();
|
||||
return false;
|
||||
}
|
||||
@@ -1423,7 +1443,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_INFO("server", "AntiDOS: Player automatically banned for %u seconds.", duration);
|
||||
LOG_INFO("network", "AntiDOS: Player automatically banned for %u seconds.", duration);
|
||||
return false;
|
||||
}
|
||||
default: // invalid policy
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GossipDef.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Packet.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
@@ -59,6 +58,10 @@ namespace lfg
|
||||
struct LfgUpdateData;
|
||||
}
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
}
|
||||
|
||||
enum AccountDataType
|
||||
{
|
||||
GLOBAL_CONFIG_CACHE = 0, // 0x01 g
|
||||
@@ -392,7 +395,7 @@ public:
|
||||
void ResetTimeSync();
|
||||
void SendTimeSync();
|
||||
public: // opcodes handlers
|
||||
void Handle_NULL(WorldPacket& recvPacket); // not used
|
||||
void Handle_NULL(WorldPacket& null); // not used
|
||||
void Handle_EarlyProccess(WorldPacket& recvPacket); // just mark packets processed in WorldSocket::OnRead
|
||||
void Handle_ServerSide(WorldPacket& recvPacket); // sever side only, can't be accepted from client
|
||||
void Handle_Deprecated(WorldPacket& recvPacket); // never used anymore by client
|
||||
@@ -501,7 +504,7 @@ public: // opcodes handlers
|
||||
void HandleGameObjectQueryOpcode(WorldPacket& recvPacket);
|
||||
|
||||
void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket);
|
||||
void HandleMoveWorldportAckOpcode(); // for server-side calls
|
||||
void HandleMoveWorldportAck(); // for server-side calls
|
||||
|
||||
void HandleMovementOpcodes(WorldPacket& recvPacket);
|
||||
void HandleSetActiveMoverOpcode(WorldPacket& recvData);
|
||||
@@ -998,6 +1001,10 @@ private:
|
||||
|
||||
bool recoveryItem(Item* pItem);
|
||||
|
||||
// logging helper
|
||||
void LogUnexpectedOpcode(WorldPacket* packet, char const* status, const char* reason);
|
||||
void LogUnprocessedTail(WorldPacket* packet);
|
||||
|
||||
// EnumData helpers
|
||||
bool IsLegitCharacterForAccount(ObjectGuid guid)
|
||||
{
|
||||
|
||||
@@ -527,11 +527,10 @@ int WorldSocket::handle_input_header(void)
|
||||
EndianConvertReverse(header.size);
|
||||
EndianConvert(header.cmd);
|
||||
|
||||
if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240))
|
||||
if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240))
|
||||
{
|
||||
Player* _player = m_Session ? m_Session->GetPlayer() : nullptr;
|
||||
LOG_ERROR("server", "WorldSocket::handle_input_header(): client (account: %u, char [%s, name: %s]) sent malformed packet (size: %d, cmd: %d)",
|
||||
m_Session ? m_Session->GetAccountId() : 0, _player ? _player->GetGUID().ToString().c_str() : "", _player ? _player->GetName().c_str() : "<none>", header.size, header.cmd);
|
||||
LOG_ERROR("server", "WorldSocket::handle_input_header(): client (%s) sent malformed packet (size: %hd, cmd: %d)",
|
||||
GetRemoteAddress().c_str(), header.size, header.cmd);
|
||||
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -706,9 +705,9 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
ASSERT(new_pct);
|
||||
|
||||
// manage memory ;)
|
||||
std::unique_ptr<WorldPacket> aptr (new_pct);
|
||||
std::unique_ptr<WorldPacket> aptr(new_pct);
|
||||
|
||||
const uint16 opcode = new_pct->GetOpcode();
|
||||
OpcodeClient opcode = static_cast<OpcodeClient>(aptr->GetOpcode());
|
||||
|
||||
if (closing_)
|
||||
return -1;
|
||||
@@ -749,7 +748,9 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
}
|
||||
catch (ByteBufferException const&)
|
||||
{
|
||||
LOG_ERROR("server", "WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.", opcode, GetRemoteAddress().c_str(), m_Session ? m_Session->GetAccountId() : -1);
|
||||
LOG_ERROR("server", "WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%u. Disconnected client.",
|
||||
aptr->GetOpcode(), GetRemoteAddress().c_str(), m_Session ? m_Session->GetAccountId() : 0);
|
||||
|
||||
if (sLog->ShouldLog("network", LogLevel::LOG_LEVEL_DEBUG))
|
||||
{
|
||||
LOG_DEBUG("network", "Dumping error causing packet:");
|
||||
@@ -761,6 +762,13 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
|
||||
std::lock_guard<std::mutex> guard(m_SessionLock);
|
||||
|
||||
OpcodeHandler const* handler = opcodeTable[opcode];
|
||||
if (!handler)
|
||||
{
|
||||
LOG_ERROR("network.opcode", "No defined handler for opcode %s sent by %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(aptr->GetOpcode())).c_str(), m_Session->GetPlayerInfo().c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (m_Session != nullptr)
|
||||
{
|
||||
// Our Idle timer will reset on any non PING or TIME_SYNC opcodes.
|
||||
@@ -776,7 +784,7 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_ERROR("server", "WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
|
||||
LOG_ERROR("server", "WorldSocket::ProcessIncoming: Client not authed opcode = %u", aptr->GetOpcode());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,11 @@ class ACE_Message_Block;
|
||||
class WorldPacket;
|
||||
class WorldSession;
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
class ServerPacket;
|
||||
}
|
||||
|
||||
/// Handler that can communicate over stream sockets.
|
||||
typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> WorldHandler;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user