summaryrefslogtreecommitdiffstats
path: root/src/Protocol/ProtocolRecognizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp120
1 files changed, 47 insertions, 73 deletions
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index dc6b93b01..3af4f9654 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -25,18 +25,6 @@
-struct UnsupportedButPingableProtocolException : public std::runtime_error
-{
- explicit UnsupportedButPingableProtocolException() :
- std::runtime_error("")
- {
- }
-};
-
-
-
-
-
struct TriedToJoinWithUnsupportedProtocolException : public std::runtime_error
{
explicit TriedToJoinWithUnsupportedProtocolException(const std::string & a_Message) :
@@ -90,31 +78,44 @@ AString cMultiVersionProtocol::GetVersionTextFromInt(cProtocol::Version a_Protoc
void cMultiVersionProtocol::HandleIncomingDataInRecognitionStage(cClientHandle & a_Client, std::string_view a_Data)
{
- // We read more than the handshake packet here, oh well.
+ // NOTE: If a new protocol is added or an old one is removed, adjust MCS_CLIENT_VERSIONS and MCS_PROTOCOL_VERSIONS macros in the header file
+
+ /* Write all incoming data unmodified into m_Buffer.
+ Writing everything is always okay to do:
+ 1. We can be sure protocol encryption hasn't started yet since m_Protocol hasn't been called, hence no decryption needs to take place
+ 2. The extra data are processed at the end of this function */
if (!m_Buffer.Write(a_Data.data(), a_Data.size()))
{
- a_Client.Kick("Your client sent too much data; please try again later.");
+ a_Client.PacketBufferFull();
return;
}
- try
- {
- // Note that a_Data is assigned to a subview containing the data to pass to m_Protocol or UnsupportedPing
+ // TODO: recover from git history
+ // Unlengthed protocol, ...
- TryRecognizeProtocol(a_Client, a_Data);
- if (m_Protocol == nullptr)
- {
- m_Buffer.ResetRead();
- return;
- }
+ // Lengthed protocol, try if it has the entire initial handshake packet:
+ if (
+ UInt32 PacketLen;
- // The protocol recogniser succesfully identified, switch mode:
- HandleIncomingData = [this](cClientHandle &, const std::string_view a_In)
- {
- m_Protocol->DataReceived(m_Buffer, a_In.data(), a_In.size());
- };
+ // If not enough bytes for the packet length, keep waiting
+ !m_Buffer.ReadVarInt(PacketLen) ||
+
+ // If not enough bytes for the packet, keep waiting
+ // (More of a sanity check to make sure no one tries anything funny, since ReadXXX can wait for data themselves)
+ !m_Buffer.CanReadBytes(PacketLen)
+ )
+ {
+ m_Buffer.ResetRead();
+ return;
}
- catch (const UnsupportedButPingableProtocolException &)
+
+ /* Figure out the client's version.
+ 1. m_Protocol != nullptr: the protocol is supported and we have a handler
+ 2. m_Protocol == nullptr: the protocol is unsupported, handling is a special case done by ourselves
+ 3. Exception: the data sent were garbage, the client handle deals with it by disconnecting */
+ m_Protocol = TryRecognizeLengthedProtocol(a_Client, a_Data);
+
+ if (m_Protocol == nullptr)
{
// Got a server list ping for an unrecognised version,
// switch into responding to unknown protocols mode:
@@ -123,9 +124,17 @@ void cMultiVersionProtocol::HandleIncomingDataInRecognitionStage(cClientHandle &
HandleIncomingDataInOldPingResponseStage(a_Clyent, a_In);
};
}
+ else
+ {
+ // The protocol recogniser succesfully identified, switch mode:
+ HandleIncomingData = [this](cClientHandle &, const std::string_view a_In)
+ {
+ m_Protocol->DataReceived(m_Buffer, a_In.data(), a_In.size());
+ };
+ }
- // Explicitly process any remaining data with the new handler:
- HandleIncomingData(a_Client, a_Data);
+ // Explicitly process any remaining data (already written to m_Buffer) with the new handler:
+ HandleIncomingData(a_Client, {});
}
@@ -136,7 +145,7 @@ void cMultiVersionProtocol::HandleIncomingDataInOldPingResponseStage(cClientHand
{
if (!m_Buffer.Write(a_Data.data(), a_Data.size()))
{
- a_Client.Kick("Server list ping failed, too much data.");
+ a_Client.PacketBufferFull();
return;
}
@@ -170,7 +179,7 @@ void cMultiVersionProtocol::HandleIncomingDataInOldPingResponseStage(cClientHand
}
else
{
- a_Client.Kick("Server list ping failed, unrecognized packet.");
+ a_Client.PacketUnknown(PacketID);
return;
}
@@ -206,34 +215,7 @@ void cMultiVersionProtocol::SendDisconnect(cClientHandle & a_Client, const AStri
-void cMultiVersionProtocol::TryRecognizeProtocol(cClientHandle & a_Client, std::string_view & a_Data)
-{
- // NOTE: If a new protocol is added or an old one is removed, adjust MCS_CLIENT_VERSIONS and MCS_PROTOCOL_VERSIONS macros in the header file
-
- // Lengthed protocol, try if it has the entire initial handshake packet:
- UInt32 PacketLen;
- if (!m_Buffer.ReadVarInt(PacketLen))
- {
- // Not enough bytes for the packet length, keep waiting
- return;
- }
-
- if (!m_Buffer.CanReadBytes(PacketLen))
- {
- // Not enough bytes for the packet, keep waiting
- // More of a sanity check to make sure no one tries anything funny (since ReadXXX can wait for data themselves):
- return;
- }
-
- m_Protocol = TryRecognizeLengthedProtocol(a_Client, a_Data);
- ASSERT(m_Protocol != nullptr);
-}
-
-
-
-
-
-std::unique_ptr<cProtocol> cMultiVersionProtocol::TryRecognizeLengthedProtocol(cClientHandle & a_Client, std::string_view & a_Data)
+std::unique_ptr<cProtocol> cMultiVersionProtocol::TryRecognizeLengthedProtocol(cClientHandle & a_Client, const std::string_view a_Data)
{
UInt32 PacketType;
UInt32 ProtocolVersion;
@@ -243,8 +225,8 @@ std::unique_ptr<cProtocol> cMultiVersionProtocol::TryRecognizeLengthedProtocol(c
if (!m_Buffer.ReadVarInt(PacketType) || (PacketType != 0x00))
{
- // Not an initial handshake packet, we don't know how to talk to them
- LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, initial packet %u)",
+ // Not an initial handshake packet, we don't know how to talk to them:
+ LOGD("Client \"%s\" uses an unsupported protocol (lengthed, initial packet %u)",
a_Client.GetIPString().c_str(), PacketType
);
@@ -277,15 +259,6 @@ std::unique_ptr<cProtocol> cMultiVersionProtocol::TryRecognizeLengthedProtocol(c
// TODO: this should be a protocol property, not ClientHandle:
a_Client.SetProtocolVersion(ProtocolVersion);
- // The protocol has just been recognized, advance data start
- // to after the handshake and leave the rest to the protocol:
- a_Data = a_Data.substr(m_Buffer.GetUsedSpace() - m_Buffer.GetReadableSpace());
-
- // We read more than we can handle, purge the rest:
- [[maybe_unused]] const bool Success =
- m_Buffer.SkipRead(m_Buffer.GetReadableSpace());
- ASSERT(Success);
-
// All good, eat up the data:
m_Buffer.CommitRead();
@@ -319,7 +292,8 @@ std::unique_ptr<cProtocol> cMultiVersionProtocol::TryRecognizeLengthedProtocol(c
);
}
- throw UnsupportedButPingableProtocolException();
+ // No cProtocol can handle the client:
+ return nullptr;
}
}
}