diff options
author | Pokechu22 <Pokechu22@users.noreply.github.com> | 2016-05-14 21:12:42 +0200 |
---|---|---|
committer | Alexander Harkness <me@bearbin.net> | 2016-05-14 21:12:42 +0200 |
commit | a4f327118b06ced1cd4510b7d20d34da83aa78a3 (patch) | |
tree | d6dbd41cfbec99f2598fb51907b86d9cbe0e8a05 /src/Protocol/ProtocolRecognizer.cpp | |
parent | Fixed death on teleportation or leaving Minecart (#3181) (diff) | |
download | cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.tar cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.tar.gz cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.tar.bz2 cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.tar.lz cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.tar.xz cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.tar.zst cuberite-a4f327118b06ced1cd4510b7d20d34da83aa78a3.zip |
Diffstat (limited to '')
-rw-r--r-- | src/Protocol/ProtocolRecognizer.cpp | 240 |
1 files changed, 175 insertions, 65 deletions
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index fff55b6e9..3977183e9 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -9,6 +9,8 @@ #include "ProtocolRecognizer.h" #include "Protocol17x.h" #include "Protocol18x.h" +#include "Protocol19x.h" +#include "Packetizer.h" #include "../ClientHandle.h" #include "../Root.h" #include "../Server.h" @@ -23,7 +25,8 @@ cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) : super(a_Client), m_Protocol(nullptr), - m_Buffer(8192) // We need a larger buffer to support BungeeCord - it sends one huge packet at the start + m_Buffer(8192), // We need a larger buffer to support BungeeCord - it sends one huge packet at the start + m_InPingForUnrecognizedVersion(false) { } @@ -48,6 +51,10 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) case PROTO_VERSION_1_7_2: return "1.7.2"; case PROTO_VERSION_1_7_6: return "1.7.6"; case PROTO_VERSION_1_8_0: return "1.8"; + case PROTO_VERSION_1_9_0: return "1.9"; + case PROTO_VERSION_1_9_1: return "1.9.1"; + case PROTO_VERSION_1_9_2: return "1.9.2"; + case PROTO_VERSION_1_9_4: return "1.9.4"; } ASSERT(!"Unknown protocol version"); return Printf("Unknown protocol (%d)", a_ProtocolVersion); @@ -67,6 +74,33 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size) return; } + if (m_InPingForUnrecognizedVersion) + { + // We already know the verison; handle it here. + UInt32 PacketLen; + UInt32 PacketID; + if (!m_Buffer.ReadVarInt32(PacketLen)) + { + return; + } + if (!m_Buffer.ReadVarInt32(PacketID)) + { + return; + } + ASSERT(PacketID == 0x01); // Ping packet + ASSERT(PacketLen == 9); // Payload of the packet ID and a UInt64 + + Int64 Data; + if (!m_Buffer.ReadBEInt64(Data)) + { + return; + } + + cPacketizer Pkt(*this, 0x01); // Pong packet + Pkt.WriteBEInt64(Data); + return; + } + if (!TryRecognizeProtocol()) { return; @@ -88,7 +122,7 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size) -void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) { ASSERT(m_Protocol != nullptr); m_Protocol->SendAttachEntity(a_Entity, a_Vehicle); @@ -188,6 +222,16 @@ void cProtocolRecognizer::SendDestroyEntity(const cEntity & a_Entity) +void cProtocolRecognizer::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendDetachEntity(a_Entity, a_PreviousVehicle); +} + + + + + void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) { if (m_Protocol != nullptr) @@ -196,14 +240,9 @@ void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) } else { - // This is used when the client sends a server-ping, respond with the default packet: - static const int Packet = 0xff; // PACKET_DISCONNECT - SendData(reinterpret_cast<const char *>(&Packet), 1); // WriteByte() - - auto UTF16 = UTF8ToRawBEUTF16(a_Reason); - static const u_short Size = htons(static_cast<u_short>(UTF16.size())); - SendData(reinterpret_cast<const char *>(&Size), 2); // WriteShort() - SendData(reinterpret_cast<const char *>(UTF16.data()), UTF16.size() * sizeof(char16_t)); // WriteString() + AString Message = Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()); + cPacketizer Pkt(*this, 0x00); // Disconnect packet (in login state) + Pkt.WriteString(Message); } } @@ -967,88 +1006,159 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema return false; } m_Client->SetProtocolVersion(ProtocolVersion); + AString ServerAddress; + UInt16 ServerPort; + UInt32 NextState; + if (!m_Buffer.ReadVarUTF8String(ServerAddress)) + { + return false; + } + if (!m_Buffer.ReadBEUInt16(ServerPort)) + { + return false; + } + if (!m_Buffer.ReadVarInt(NextState)) + { + return false; + } + m_Buffer.CommitRead(); switch (ProtocolVersion) { case PROTO_VERSION_1_7_2: { - AString ServerAddress; - UInt16 ServerPort; - UInt32 NextState; - if (!m_Buffer.ReadVarUTF8String(ServerAddress)) - { - break; - } - if (!m_Buffer.ReadBEUInt16(ServerPort)) - { - break; - } - if (!m_Buffer.ReadVarInt(NextState)) - { - break; - } - m_Buffer.CommitRead(); m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState); return true; } case PROTO_VERSION_1_7_6: { - AString ServerAddress; - UInt16 ServerPort; - UInt32 NextState; - if (!m_Buffer.ReadVarUTF8String(ServerAddress)) - { - break; - } - if (!m_Buffer.ReadBEUInt16(ServerPort)) - { - break; - } - if (!m_Buffer.ReadVarInt(NextState)) - { - break; - } - m_Buffer.CommitRead(); m_Protocol = new cProtocol176(m_Client, ServerAddress, ServerPort, NextState); return true; } case PROTO_VERSION_1_8_0: { - AString ServerAddress; - UInt16 ServerPort; - UInt32 NextState; - if (!m_Buffer.ReadVarUTF8String(ServerAddress)) - { - break; - } - if (!m_Buffer.ReadBEUInt16(ServerPort)) + m_Buffer.CommitRead(); + m_Protocol = new cProtocol180(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + case PROTO_VERSION_1_9_0: + { + m_Protocol = new cProtocol190(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + case PROTO_VERSION_1_9_1: + { + m_Protocol = new cProtocol191(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + case PROTO_VERSION_1_9_2: + { + m_Protocol = new cProtocol192(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + case PROTO_VERSION_1_9_4: + { + m_Protocol = new cProtocol194(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + default: + { + LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))", + m_Client->GetIPString().c_str(), ProtocolVersion, ProtocolVersion + ); + if (NextState != 1) { - break; + m_Client->Kick(Printf("Unsupported protocol version %u, please use one of these versions:\n" MCS_CLIENT_VERSIONS, ProtocolVersion)); + return false; } - if (!m_Buffer.ReadVarInt(NextState)) + else { - break; + m_InPingForUnrecognizedVersion = true; + + UInt32 PacketLen; + UInt32 PacketID; + if (!m_Buffer.ReadVarInt32(PacketLen)) + { + return false; + } + if (!m_Buffer.ReadVarInt32(PacketID)) + { + return false; + } + ASSERT(PacketID == 0x00); // Request packet + ASSERT(PacketLen == 1); // No payload except for packet ID + SendPingStatusResponse(); } - m_Buffer.CommitRead(); - m_Protocol = new cProtocol180(m_Client, ServerAddress, ServerPort, NextState); - return true; + return false; } } - LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))", - m_Client->GetIPString().c_str(), ProtocolVersion, ProtocolVersion - ); - m_Client->Kick("Unsupported protocol version"); - return false; } + void cProtocolRecognizer::SendPacket(cPacketizer & a_Pkt) { - // This function should never be called - it needs to exists so that cProtocolRecognizer can be instantiated, - // but the actual sending is done by the internal m_Protocol itself. - LOGWARNING("%s: This function shouldn't ever be called.", __FUNCTION__); - ASSERT(!"Function not to be called"); + // Writes out the packet normally. + UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace()); + AString PacketData, CompressedPacket; + m_OutPacketBuffer.ReadAll(PacketData); + m_OutPacketBuffer.CommitRead(); + + // Compression doesn't apply to this state, send raw data: + m_OutPacketLenBuffer.WriteVarInt32(PacketLen); + AString LengthData; + m_OutPacketLenBuffer.ReadAll(LengthData); + SendData(LengthData.data(), LengthData.size()); + + // Send the packet's payload + m_OutPacketLenBuffer.CommitRead(); + SendData(PacketData.data(), PacketData.size()); +} + + + + + +void cProtocolRecognizer::SendPingStatusResponse(void) +{ + cServer * Server = cRoot::Get()->GetServer(); + AString ServerDescription = Server->GetDescription(); + int NumPlayers = Server->GetNumPlayers(); + int MaxPlayers = Server->GetMaxPlayers(); + AString Favicon = Server->GetFaviconData(); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); + + // Version: + Json::Value Version; + Version["name"] = "Cuberite " MCS_CLIENT_VERSIONS; + Version["protocol"] = 0; // Force client to think this is an invalid version (no other good default) + + // Players: + Json::Value Players; + Players["online"] = NumPlayers; + Players["max"] = MaxPlayers; + // TODO: Add "sample" + + // Description: + Json::Value Description; + Description["text"] = ServerDescription.c_str(); + + // Create the response: + Json::Value ResponseValue; + ResponseValue["version"] = Version; + ResponseValue["players"] = Players; + ResponseValue["description"] = Description; + if (!Favicon.empty()) + { + ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); + } + + Json::StyledWriter Writer; + AString Response = Writer.write(ResponseValue); + + cPacketizer Pkt(*this, 0x00); // Response packet + Pkt.WriteString(Response); } |