1
0
Fork 0

cProtocolRecognizer goes on a diet (#4770)

- Removed inheritance from cProtocol
This commit is contained in:
Tiger Wang 2020-07-17 18:46:50 +01:00 committed by GitHub
parent d8406c7c58
commit ff2c246de2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 247 additions and 1164 deletions

View File

@ -32,7 +32,7 @@
#include "Root.h"
#include "Protocol/Authenticator.h"
#include "Protocol/ProtocolRecognizer.h"
#include "Protocol/Protocol.h"
#include "CompositeChat.h"
#include "Items/ItemSword.h"
@ -100,8 +100,6 @@ cClientHandle::cClientHandle(const AString & a_IPString, int a_ViewDistance) :
m_LastPlacedSign(0, -1, 0),
m_ProtocolVersion(0)
{
m_Protocol = cpp14::make_unique<cProtocolRecognizer>(this);
s_ClientCount++; // Not protected by CS because clients are always constructed from the same thread
m_UniqueID = s_ClientCount;
m_PingStartTime = std::chrono::steady_clock::now();
@ -141,8 +139,6 @@ cClientHandle::~cClientHandle()
m_Player = nullptr;
}
m_Protocol.reset();
LOGD("ClientHandle at %p deleted", static_cast<void *>(this));
}
@ -2489,7 +2485,7 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ
return;
}
if (m_Protocol == nullptr)
if (!m_Protocol.VersionRecognitionSuccessful())
{
// TODO (#2588): investigate if and why this occurs
return;
@ -2542,7 +2538,7 @@ void cClientHandle::SendDisconnect(const AString & a_Reason)
if (!m_HasSentDC)
{
LOGD("Sending a DC: \"%s\"", StripColorCodes(a_Reason).c_str());
m_Protocol->SendDisconnect(a_Reason);
m_Protocol.SendDisconnect(*this, a_Reason);
m_HasSentDC = true;
// csKicked means m_Link will be shut down on the next tick. The
// disconnect packet data is sent in the tick thread so the connection
@ -3385,9 +3381,10 @@ void cClientHandle::ProcessProtocolInOut(void)
cCSLock Lock(m_CSIncomingData);
std::swap(IncomingData, m_IncomingData);
}
if (!IncomingData.empty())
{
m_Protocol->DataReceived(IncomingData.data(), IncomingData.size());
m_Protocol.HandleIncomingData(*this, IncomingData);
}
// Send any queued outgoing data:
@ -3396,10 +3393,13 @@ void cClientHandle::ProcessProtocolInOut(void)
cCSLock Lock(m_CSOutgoingData);
std::swap(OutgoingData, m_OutgoingData);
}
auto link = m_Link;
if ((link != nullptr) && !OutgoingData.empty())
// Capture the link to prevent it being reset between the null check and the Send:
auto Link = m_Link;
if ((Link != nullptr) && !OutgoingData.empty())
{
link->Send(OutgoingData.data(), OutgoingData.size());
Link->Send(OutgoingData.data(), OutgoingData.size());
}
}

View File

@ -17,6 +17,7 @@
#include "ChunkSender.h"
#include "EffectID.h"
#include "Protocol/ForgeHandshake.h"
#include "Protocol/ProtocolRecognizer.h"
#include "UUID.h"
@ -437,7 +438,7 @@ private:
std::unordered_set<cChunkCoords, cChunkCoordsHash> m_ChunksToSend; // Chunks that need to be sent to the player (queued because they weren't generated yet or there's not enough time to send them)
cChunkCoordsList m_SentChunks; // Chunks that are currently sent to the client
std::unique_ptr<cProtocol> m_Protocol;
cMultiVersionProtocol m_Protocol;
/** Protects m_IncomingData against multithreaded access. */
cCriticalSection m_CSIncomingData;

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,13 @@
#pragma once
#include "Protocol.h"
#include "../ByteBuffer.h"
// Adjust these if a new protocol is added or an old one is removed:
#define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x"
#define MCS_CLIENT_VERSIONS "1.8.x-1.12.x"
#define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340"
#define MCS_LATEST_PROTOCOL_VERSION 340
@ -18,12 +17,10 @@
/** Meta-protocol that recognizes multiple protocol versions, creates the specific
protocol version instance and redirects everything to it. */
class cProtocolRecognizer:
public cProtocol
class cMultiVersionProtocol
{
using Super = cProtocol;
public:
enum
{
PROTO_VERSION_1_8_0 = 47,
@ -40,132 +37,67 @@ public:
PROTO_VERSION_1_13 = 393
};
cProtocolRecognizer(cClientHandle * a_Client);
virtual ~cProtocolRecognizer() override {}
cMultiVersionProtocol();
/** Translates protocol version number into protocol version text: 49 -> "1.4.4" */
static AString GetVersionTextFromInt(int a_ProtocolVersion);
/** Called when client sends some data: */
virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/** Returns if we contain a concrete protocol corresponding to the client's protocol version. */
bool VersionRecognitionSuccessful()
{
return m_Protocol != nullptr;
}
/** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity & a_Vehicle) override;
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendCameraSetTo (const cEntity & a_Entity) override;
virtual void SendChat (const AString & a_Message, eChatType a_Type) override;
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override;
virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) override;
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override;
virtual void SendDisconnect (const AString & a_Reason) override;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) override;
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
virtual void SendEntityHeadLook (const cEntity & a_Entity) override;
virtual void SendEntityLook (const cEntity & a_Entity) override;
virtual void SendEntityMetadata (const cEntity & a_Entity) override;
virtual void SendEntityPosition (const cEntity & a_Entity) override;
virtual void SendEntityProperties (const cEntity & a_Entity) override;
virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
virtual void SendEntityVelocity (const cEntity & a_Entity) override;
virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
virtual void SendGameMode (eGameMode a_GameMode) override;
virtual void SendHealth (void) override;
virtual void SendHeldItemChange (int a_ItemIndex) override;
virtual void SendHideTitle (void) override;
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (UInt32 a_PingID) override;
virtual void SendLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendLoginSuccess (void) override;
virtual void SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) override;
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) override;
virtual void SendParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data) override;
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendPlayerAbilities (void) override;
virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override;
virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) override;
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override;
virtual void SendPlayerListUpdatePing (const cPlayer & a_Player) override;
virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override;
virtual void SendPlayerMaxSpeed (void) override;
virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
virtual void SendResetTitle (void) override;
virtual void SendResourcePack (const AString & a_ResourcePackUrl) override;
virtual void SendRespawn (eDimension a_Dimension) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
virtual void SendSetSubTitle (const cCompositeChat & a_SubTitle) override;
virtual void SendSetRawSubTitle (const AString & a_SubTitle) override;
virtual void SendSetTitle (const cCompositeChat & a_Title) override;
virtual void SendSetRawTitle (const AString & a_Title) override;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendSoundParticleEffect (const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnEntity (const cEntity & a_Entity) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override;
virtual void SendStatistics (const cStatManager & a_Manager) override;
virtual void SendTabCompletionResults (const AStringVector & a_Results) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendUnleashEntity (const cEntity & a_Entity) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendUnlockRecipe (UInt32 a_RecipeID) override;
virtual void SendInitRecipes (UInt32 a_RecipeID) override;
virtual void SendWeather (eWeather a_Weather) override;
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
virtual void SendWindowOpen (const cWindow & a_Window) override;
virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override;
/** Convenience overload to enable redirecting sends to the underlying implementation. */
auto & operator->()
{
return m_Protocol;
}
virtual AString GetAuthServerID(void) override;
/** The function that's responsible for processing incoming protocol data. */
std::function<void(cClientHandle &, std::string_view)> HandleIncomingData;
virtual void SendData(const char * a_Data, size_t a_Size) override;
/** Sends a disconnect to the client as a result of a recognition error.
This function can be used to disconnect before any protocol has been recognised. */
void SendDisconnect(cClientHandle & a_Client, const AString & a_Reason);
protected:
private:
/** The recognized protocol */
std::unique_ptr<cProtocol> m_Protocol;
/** Handles data reception in a newly-created client handle that doesn't yet have known protocol.
a_Data contains a view of data that were just received.
Calls TryRecognizeProtocol to populate m_Protocol, and transitions to another mode depending on success. */
void HandleIncomingDataInRecognitionStage(cClientHandle & a_Client, std::string_view a_Data);
/** Buffer for the incoming data until we recognize the protocol */
cByteBuffer m_Buffer;
/** Handles and responds to unsupported clients sending pings. */
void HandleIncomingDataInOldPingResponseStage(cClientHandle & a_Client, const std::string_view a_Data);
/** Is a server list ping for an unrecognized version currently occuring? */
bool m_InPingForUnrecognizedVersion;
/* Tries to recognize a protocol based on a_Data and m_Buffer contents.
a_Data is replaced with a sub-view, with handshake packet removed. */
void TryRecognizeProtocol(cClientHandle & a_Client, std::string_view & a_Data);
/** Tries to recognize a protocol in the lengthed family (1.7+), based on m_Buffer.
The packet length and type have already been read, type is 0.
Returns a cProtocol_XXX instance if recognized. */
std::unique_ptr<cProtocol> TryRecognizeLengthedProtocol(cClientHandle & a_Client, std::string_view & a_Data);
/** Sends one packet inside a cByteBuffer.
This is used only when handling an outdated server ping. */
static void SendPacket(cClientHandle & a_Client, cByteBuffer & a_OutPacketBuffer);
/** Returns the protocol-specific packet ID given the protocol-agnostic packet enum. */
virtual UInt32 GetPacketID(ePacketType a_PacketType) override;
static UInt32 GetPacketID(cProtocol::ePacketType a_PacketType);
// Packet handlers while in status state (m_InPingForUnrecognizedVersion == true)
void HandlePacketStatusRequest();
void HandlePacketStatusPing();
/* Status handler for unrecognised versions. */
void HandlePacketStatusRequest(cClientHandle & a_Client, cByteBuffer & a_Out);
/** Tries to recognize protocol based on m_Buffer contents; returns true if recognized */
bool TryRecognizeProtocol(void);
/* Ping handler for unrecognised versions. */
void HandlePacketStatusPing(cClientHandle & a_Client, cByteBuffer & a_Out);
/** Tries to recognize a protocol in the lengthed family (1.7+), based on m_Buffer; returns true if recognized.
The packet length and type have already been read, type is 0
The number of bytes remaining in the packet is passed as a_PacketLengthRemaining. */
bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining);
/** The actual protocol implementation.
Created when recognition of the client version succeeds with a version we support. */
std::unique_ptr<cProtocol> m_Protocol;
/** Buffer for received protocol data. */
cByteBuffer m_Buffer;
/** Sends a single packet contained within the cPacketizer class.
The cPacketizer's destructor calls this to send the contained packet; protocol may transform the data (compression in 1.8 etc). */
virtual void SendPacket(cPacketizer & a_Pkt) override;
} ;

View File

@ -619,7 +619,7 @@ void cProtocol_1_11_0::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.11";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_11_0;
Version["protocol"] = cMultiVersionProtocol::PROTO_VERSION_1_11_0;
// Players:
Json::Value Players;
@ -1241,7 +1241,7 @@ void cProtocol_1_11_1::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.11.1";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_11_1;
Version["protocol"] = cMultiVersionProtocol::PROTO_VERSION_1_11_1;
// Players:
Json::Value Players;

View File

@ -339,7 +339,7 @@ void cProtocol_1_12::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.12";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12;
Version["protocol"] = cMultiVersionProtocol::PROTO_VERSION_1_12;
// Players:
Json::Value Players;
@ -1217,7 +1217,7 @@ void cProtocol_1_12_1::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.12.1";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_1;
Version["protocol"] = cMultiVersionProtocol::PROTO_VERSION_1_12_1;
// Players:
Json::Value Players;
@ -1374,7 +1374,7 @@ void cProtocol_1_12_2::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.12.2";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_2;
Version["protocol"] = cMultiVersionProtocol::PROTO_VERSION_1_12_2;
// Players:
Json::Value Players;

View File

@ -231,7 +231,7 @@ void cProtocol_1_13::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.13";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_13;
Version["protocol"] = cMultiVersionProtocol::PROTO_VERSION_1_13;
// Players:
Json::Value Players;

View File

@ -62,8 +62,6 @@ public:
virtual void SendUnleashEntity (const cEntity & a_Entity) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual AString GetAuthServerID(void) override { return m_AuthServerID; }
protected:
/** The current teleport ID, and whether it has been confirmed by the client */

View File

@ -931,7 +931,7 @@ bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback a_Cal
AString cRoot::GetProtocolVersionTextFromInt(int a_ProtocolVersion)
{
return cProtocolRecognizer::GetVersionTextFromInt(a_ProtocolVersion);
return cMultiVersionProtocol::GetVersionTextFromInt(a_ProtocolVersion);
}

View File

@ -181,7 +181,7 @@ bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_Shoul
}
LOGINFO("Compatible clients: %s", MCS_CLIENT_VERSIONS);
LOGINFO("Compatible protocol versions %s", MCS_PROTOCOL_VERSIONS);
LOGD("Compatible protocol versions %s", MCS_PROTOCOL_VERSIONS);
m_Ports = ReadUpgradeIniPorts(a_Settings, "Server", "Ports", "Port", "PortsIPv6", "25565");