1
0
cuberite-2a/src/Protocol/ProtocolRecognizer.h
Tiger Wang 49ef21d650 MultiVersionProtocol: fix two crashes
First one: add missing exception handler in ProcessProtocolIn

Second: remove faulty logic dealing with incomplete packets.

`a_Data = a_Data.substr(m_Buffer.GetUsedSpace() - m_Buffer.GetReadableSpace());`

was incorrect; it attempted to apply a length derived from m_Buffer to an unrelated a_Data. Its purpose was to give cProtocol the data the client sent, minus initial handshake bytes. However, we can use the knowledge that during initial handshake, there is no encryption and every byte can be written unchanged into m_Buffer, to just call cProtocol with a data length of zero. This will cause it to parse from m_Buffer - wherein we have already written everything the client sent - with no a_Data manipulation needed.

Additionally, removed UnsupportedButPingableProtocolException (use of exception as control flow) and encode this state as m_Protocol == nullptr, id est "no protocol for this unsupported version", which is then handled by cMultiVersionProtocol itself.
2021-01-19 09:54:58 +00:00

83 lines
2.9 KiB
C++

#pragma once
#include "Protocol.h"
// Adjust these if a new protocol is added or an old one is removed:
#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
/** Meta-protocol that recognizes multiple protocol versions, creates the specific
protocol version instance and redirects everything to it. */
class cMultiVersionProtocol
{
public:
cMultiVersionProtocol();
/** Translates protocol version number into protocol version text: 49 -> "1.4.4" */
static AString GetVersionTextFromInt(cProtocol::Version a_ProtocolVersion);
/** Returns if we contain a concrete protocol corresponding to the client's protocol version. */
bool VersionRecognitionSuccessful()
{
return m_Protocol != nullptr;
}
/** Convenience overload to enable redirecting sends to the underlying implementation. */
auto & operator->()
{
return m_Protocol;
}
/** The function that's responsible for processing incoming protocol data. */
std::function<void(cClientHandle &, std::string_view)> HandleIncomingData;
/** 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);
private:
/** Handles data reception in a newly-created client handle that doesn't yet have a known protocol.
a_Data contains a view of data that were just received.
Tries to recognize a protocol, populate m_Protocol, and transitions to another mode depending on success. */
void HandleIncomingDataInRecognitionStage(cClientHandle & a_Client, std::string_view a_Data);
/** Handles and responds to unsupported clients sending pings. */
void HandleIncomingDataInOldPingResponseStage(cClientHandle & a_Client, std::string_view a_Data);
/** Tries to recognize a protocol in the lengthed family (1.7+), based on m_Buffer.
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. */
static UInt32 GetPacketID(cProtocol::ePacketType a_PacketType);
/* Status handler for unrecognised versions. */
void HandlePacketStatusRequest(cClientHandle & a_Client, cByteBuffer & a_Out);
/* Ping handler for unrecognised versions. */
void HandlePacketStatusPing(cClientHandle & a_Client, cByteBuffer & a_Out);
/** 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;
} ;