summaryrefslogtreecommitdiffstats
path: root/src/Protocol
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@outlook.com>2021-01-11 17:39:43 +0100
committerGitHub <noreply@github.com>2021-01-11 17:39:43 +0100
commiteeb63b8901a9c049f1bb594abb9ce9b4a9c47620 (patch)
treeb07daae788f918b83eeb0bdbd51e49292f1c8d88 /src/Protocol
parentFixed switch-ups regarding some slab and stair recipes (#5099) (diff)
downloadcuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.tar
cuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.tar.gz
cuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.tar.bz2
cuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.tar.lz
cuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.tar.xz
cuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.tar.zst
cuberite-eeb63b8901a9c049f1bb594abb9ce9b4a9c47620.zip
Diffstat (limited to 'src/Protocol')
-rw-r--r--src/Protocol/ChunkDataSerializer.cpp9
-rw-r--r--src/Protocol/ChunkDataSerializer.h14
-rw-r--r--src/Protocol/ForgeHandshake.cpp77
-rw-r--r--src/Protocol/ForgeHandshake.h10
-rw-r--r--src/Protocol/Packetizer.h4
-rw-r--r--src/Protocol/Protocol.h6
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp13
-rw-r--r--src/Protocol/Protocol_1_10.cpp2
-rw-r--r--src/Protocol/Protocol_1_11.cpp2
-rw-r--r--src/Protocol/Protocol_1_12.cpp4
-rw-r--r--src/Protocol/Protocol_1_13.cpp15
-rw-r--r--src/Protocol/Protocol_1_14.cpp3
-rw-r--r--src/Protocol/Protocol_1_8.cpp361
-rw-r--r--src/Protocol/Protocol_1_8.h22
-rw-r--r--src/Protocol/Protocol_1_9.cpp14
-rw-r--r--src/Protocol/Protocol_1_9.h2
16 files changed, 268 insertions, 290 deletions
diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp
index ac740a145..a16cce02b 100644
--- a/src/Protocol/ChunkDataSerializer.cpp
+++ b/src/Protocol/ChunkDataSerializer.cpp
@@ -1,6 +1,5 @@
#include "Globals.h"
#include "ChunkDataSerializer.h"
-#include "zlib/zlib.h"
#include "Protocol_1_8.h"
#include "Protocol_1_9.h"
#include "../ClientHandle.h"
@@ -543,14 +542,10 @@ inline void cChunkDataSerializer::WriteSectionDataSeamless(const cChunkData::sCh
inline void cChunkDataSerializer::CompressPacketInto(ChunkDataCache & a_Cache)
{
- m_Packet.ReadAll(a_Cache.PacketData);
+ m_Compressor.ReadFrom(m_Packet);
m_Packet.CommitRead();
- if (!cProtocol_1_8_0::CompressPacket(a_Cache.PacketData, a_Cache.ToSend))
- {
- ASSERT(!"Packet compression failed.");
- return;
- }
+ cProtocol_1_8_0::CompressPacket(m_Compressor, a_Cache.ToSend);
a_Cache.Engaged = true;
}
diff --git a/src/Protocol/ChunkDataSerializer.h b/src/Protocol/ChunkDataSerializer.h
index aeff7c356..ea0b0be11 100644
--- a/src/Protocol/ChunkDataSerializer.h
+++ b/src/Protocol/ChunkDataSerializer.h
@@ -3,6 +3,8 @@
#include "../ByteBuffer.h"
#include "../ChunkData.h"
#include "../Defines.h"
+#include "CircularBufferCompressor.h"
+#include "StringCompression.h"
@@ -37,8 +39,7 @@ class cChunkDataSerializer
/** A single cache entry containing the raw data, compressed data, and a validity flag. */
struct ChunkDataCache
{
- std::string PacketData;
- std::string ToSend;
+ ContiguousByteBuffer ToSend;
bool Engaged = false;
};
@@ -50,7 +51,7 @@ public:
Parameters are the coordinates of the chunk to serialise, and the data and biome data read from the chunk. */
void SendToClients(int a_ChunkX, int a_ChunkZ, const cChunkData & a_Data, const unsigned char * a_BiomeData, const ClientHandles & a_SendTo);
-protected:
+private:
/** Serialises the given chunk, storing the result into the given cache entry, and sends the data.
If the cache entry is already present, simply re-uses it. */
@@ -74,6 +75,9 @@ protected:
/** A staging area used to construct the chunk packet, persistent to avoid reallocating. */
cByteBuffer m_Packet;
+ /** A compressor used to compress the chunk data. */
+ CircularBufferCompressor m_Compressor;
+
/** The dimension for the World this Serializer is tied to. */
const eDimension m_Dimension;
@@ -81,7 +85,3 @@ protected:
It is used during a single invocation of SendToClients with more than one client. */
std::array<ChunkDataCache, static_cast<size_t>(CacheVersion::Last) + 1> m_Cache;
} ;
-
-
-
-
diff --git a/src/Protocol/ForgeHandshake.cpp b/src/Protocol/ForgeHandshake.cpp
index 8c16d4f0c..99b585894 100644
--- a/src/Protocol/ForgeHandshake.cpp
+++ b/src/Protocol/ForgeHandshake.cpp
@@ -36,8 +36,8 @@ namespace ClientPhase
/** Server handshake state phases. */
namespace ServerPhase
{
- static const Int8 WAITINGCACK = 2;
- static const Int8 COMPLETE = 3;
+ static const auto WAITINGCACK = std::byte(2);
+ static const auto COMPLETE = std::byte(3);
}
@@ -105,12 +105,12 @@ void cForgeHandshake::BeginForgeHandshake(const AString & a_Name, const cUUID &
m_UUID = a_UUID;
m_Properties = a_Properties;
- static const std::array<AString, 5> Channels{{ "FML|HS", "FML", "FML|MP", "FML", "FORGE" }};
- AString ChannelsString;
+ static const std::array<std::string_view, 5> Channels{{ "FML|HS", "FML", "FML|MP", "FML", "FORGE" }};
+ ContiguousByteBuffer ChannelsString;
for (auto & Channel: Channels)
{
- ChannelsString.append(Channel);
- ChannelsString.push_back('\0');
+ ChannelsString.append({ reinterpret_cast<const std::byte *>(Channel.data()), Channel.size() });
+ ChannelsString.push_back(std::byte(0));
}
m_Client->SendPluginMessage("REGISTER", ChannelsString);
@@ -123,7 +123,6 @@ void cForgeHandshake::BeginForgeHandshake(const AString & a_Name, const cUUID &
void cForgeHandshake::SendServerHello()
{
- AString Message;
cByteBuffer Buf(6);
// Discriminator | Byte | Always 0 for ServerHello
Buf.WriteBEInt8(Discriminator::ServerHello);
@@ -131,6 +130,8 @@ void cForgeHandshake::SendServerHello()
Buf.WriteBEInt8(2);
// Dimension TODO
Buf.WriteBEInt32(0);
+
+ ContiguousByteBuffer Message;
Buf.ReadAll(Message);
m_Client->SendPluginMessage("FML|HS", Message);
@@ -140,18 +141,18 @@ void cForgeHandshake::SendServerHello()
-AStringMap cForgeHandshake::ParseModList(const char * a_Data, size_t a_Size)
+AStringMap cForgeHandshake::ParseModList(const ContiguousByteBufferView a_Data)
{
AStringMap Mods;
- if (a_Size < 4)
+ if (a_Data.size() < 4)
{
- SetError(Printf("ParseModList invalid packet, missing length (size = %zu)", a_Size));
+ SetError(Printf("ParseModList invalid packet, missing length (size = %zu)", a_Data.size()));
return Mods;
}
- cByteBuffer Buf(a_Size);
- Buf.Write(a_Data, a_Size);
+ cByteBuffer Buf(a_Data.size());
+ Buf.Write(a_Data.data(), a_Data.size());
UInt32 NumMods;
if (!Buf.ReadVarInt32(NumMods))
{
@@ -182,11 +183,11 @@ AStringMap cForgeHandshake::ParseModList(const char * a_Data, size_t a_Size)
-void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
- if (a_Size == 2)
+ if (a_Data.size() == 2)
{
- int FmlProtocolVersion = a_Data[1];
+ const auto FmlProtocolVersion = static_cast<Int8>(a_Data[1]);
LOGD("Received ClientHello with FML protocol version %d", FmlProtocolVersion);
if (FmlProtocolVersion != 2)
{
@@ -195,7 +196,7 @@ void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const char * a
}
else
{
- SetError(Printf("Received unexpected length of ClientHello: %zu", a_Size));
+ SetError(Printf("Received unexpected length of ClientHello: %zu", a_Data.size()));
}
}
@@ -203,11 +204,11 @@ void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const char * a
-void cForgeHandshake::HandleModList(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::HandleModList(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
LOGD("Received ModList");
- auto ClientMods = ParseModList(a_Data + 1, a_Size - 1);
+ auto ClientMods = ParseModList(a_Data.substr(1));
AString ClientModsString;
for (auto & item: ClientMods)
{
@@ -241,7 +242,8 @@ void cForgeHandshake::HandleModList(cClientHandle * a_Client, const char * a_Dat
Buf.WriteVarUTF8String(item.first); // name
Buf.WriteVarUTF8String(item.second); // version
}
- AString ServerModList;
+
+ ContiguousByteBuffer ServerModList;
Buf.ReadAll(ServerModList);
m_Client->SendPluginMessage("FML|HS", ServerModList);
@@ -251,15 +253,15 @@ void cForgeHandshake::HandleModList(cClientHandle * a_Client, const char * a_Dat
-void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
- if (a_Size != 2)
+ if (a_Data.size() != 2)
{
- SetError(Printf("Unexpected HandshakeAck packet length: %zu", a_Size));
+ SetError(Printf("Unexpected HandshakeAck packet length: %zu", a_Data.size()));
return;
}
- auto Phase = a_Data[1];
+ const auto Phase = static_cast<Int8>(a_Data[1]);
LOGD("Received client HandshakeAck with phase = %d", Phase);
switch (Phase)
@@ -282,7 +284,7 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
Buf.WriteVarInt32(NumSubstitutions);
Buf.WriteVarInt32(NumDummies);
- AString RegistryData;
+ ContiguousByteBuffer RegistryData;
Buf.ReadAll(RegistryData);
m_Client->SendPluginMessage("FML|HS", RegistryData);
break;
@@ -292,8 +294,8 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
{
LOGD("Client finished receiving registry data; acknowledging");
- AString Ack;
- Ack.push_back(Discriminator::HandshakeAck);
+ ContiguousByteBuffer Ack;
+ Ack.push_back(std::byte(Discriminator::HandshakeAck));
Ack.push_back(ServerPhase::WAITINGCACK);
m_Client->SendPluginMessage("FML|HS", Ack);
break;
@@ -303,8 +305,8 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
{
LOGD("Client is pending completion; sending complete ack");
- AString Ack;
- Ack.push_back(Discriminator::HandshakeAck);
+ ContiguousByteBuffer Ack;
+ Ack.push_back(std::byte(Discriminator::HandshakeAck));
Ack.push_back(ServerPhase::COMPLETE);
m_Client->SendPluginMessage("FML|HS", Ack);
@@ -320,7 +322,7 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
default:
{
- SetError(Printf("Received unknown phase in Forge handshake acknowledgement: %d", Phase));
+ SetError(fmt::format("Received unknown phase in Forge handshake acknowledgement: {}", Phase));
break;
}
}
@@ -330,11 +332,11 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
-void cForgeHandshake::DataReceived(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::DataReceived(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
if (!m_IsForgeClient)
{
- SetError(Printf("Received unexpected Forge data from non-Forge client (%zu bytes)", a_Size));
+ SetError(Printf("Received unexpected Forge data from non-Forge client (%zu bytes)", a_Data.size()));
return;
}
if (m_Errored)
@@ -343,19 +345,18 @@ void cForgeHandshake::DataReceived(cClientHandle * a_Client, const char * a_Data
return;
}
- if (a_Size <= 1)
+ if (a_Data.size() <= 1)
{
- SetError(Printf("Received unexpectedly short Forge data (%zu bytes)", a_Size));
+ SetError(Printf("Received unexpectedly short Forge data (%zu bytes)", a_Data.size()));
return;
}
- auto Discriminator = a_Data[0];
-
+ const auto Discriminator = static_cast<Int8>(a_Data[0]);
switch (Discriminator)
{
- case Discriminator::ClientHello: HandleClientHello(a_Client, a_Data, a_Size); break;
- case Discriminator::ModList: HandleModList(a_Client, a_Data, a_Size); break;
- case Discriminator::HandshakeAck: HandleHandshakeAck(a_Client, a_Data, a_Size); break;
+ case Discriminator::ClientHello: HandleClientHello(a_Client, a_Data); break;
+ case Discriminator::ModList: HandleModList(a_Client, a_Data); break;
+ case Discriminator::HandshakeAck: HandleHandshakeAck(a_Client, a_Data); break;
default:
{
diff --git a/src/Protocol/ForgeHandshake.h b/src/Protocol/ForgeHandshake.h
index 46e0efaa6..061369c15 100644
--- a/src/Protocol/ForgeHandshake.h
+++ b/src/Protocol/ForgeHandshake.h
@@ -34,7 +34,7 @@ public:
void SendServerHello();
/** Process received data from the client advancing the Forge handshake. */
- void DataReceived(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
+ void DataReceived(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
private:
/** True if the Forge handshake is in an errored state. */
@@ -48,13 +48,13 @@ private:
cUUID m_UUID;
Json::Value m_Properties;
- void HandleClientHello(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
- void HandleModList(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
- void HandleHandshakeAck(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
+ void HandleClientHello(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
+ void HandleModList(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
+ void HandleHandshakeAck(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
/** Set errored state to prevent further handshake message processing. */
void SetError(const AString & message);
/** Parse the client ModList packet of installed Forge mods and versions. */
- AStringMap ParseModList(const char * a_Data, size_t a_Size);
+ AStringMap ParseModList(ContiguousByteBufferView a_Data);
};
diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h
index 4ece6e4fa..f4d632a27 100644
--- a/src/Protocol/Packetizer.h
+++ b/src/Protocol/Packetizer.h
@@ -119,9 +119,9 @@ public:
}
- inline void WriteBuf(const char * a_Data, size_t a_Size)
+ inline void WriteBuf(const ContiguousByteBufferView a_Data)
{
- VERIFY(m_Out.Write(a_Data, a_Size));
+ VERIFY(m_Out.Write(a_Data.data(), a_Data.size()));
}
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 5c9d5105f..341e0b0f4 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -365,7 +365,7 @@ public:
virtual void SendChat (const AString & a_Message, eChatType a_Type) = 0;
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) = 0;
virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) = 0;
- virtual void SendChunkData (const std::string_view a_ChunkData) = 0;
+ virtual void SendChunkData (ContiguousByteBufferView a_ChunkData) = 0;
virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) = 0;
virtual void SendDestroyEntity (const cEntity & a_Entity) = 0;
virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) = 0;
@@ -405,7 +405,7 @@ public:
virtual void SendPlayerMoveLook (void) = 0;
virtual void SendPlayerPosition (void) = 0;
virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;
- virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0;
+ virtual void SendPluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message) = 0;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0;
virtual void SendResetTitle (void) = 0;
virtual void SendResourcePack (const AString & a_ResourcePackUrl) = 0;
@@ -468,7 +468,7 @@ protected:
virtual Version GetProtocolVersion() = 0;
/** A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it. */
- virtual void SendData(const char * a_Data, size_t a_Size) = 0;
+ virtual void SendData(ContiguousByteBufferView a_Data) = 0;
/** 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). */
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 5d146c46a..dc6b93b01 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -123,11 +123,6 @@ void cMultiVersionProtocol::HandleIncomingDataInRecognitionStage(cClientHandle &
HandleIncomingDataInOldPingResponseStage(a_Clyent, a_In);
};
}
- catch (const std::exception & Oops)
- {
- a_Client.Kick(Oops.what());
- return;
- }
// Explicitly process any remaining data with the new handler:
HandleIncomingData(a_Client, a_Data);
@@ -341,15 +336,15 @@ void cMultiVersionProtocol::SendPacket(cClientHandle & a_Client, cByteBuffer & a
// Compression doesn't apply to this state, send raw data:
VERIFY(OutPacketLenBuffer.WriteVarInt32(PacketLen));
- AString LengthData;
+ ContiguousByteBuffer LengthData;
OutPacketLenBuffer.ReadAll(LengthData);
- a_Client.SendData(LengthData.data(), LengthData.size());
+ a_Client.SendData(LengthData);
// Send the packet's payload:
- AString PacketData;
+ ContiguousByteBuffer PacketData;
a_OutPacketBuffer.ReadAll(PacketData);
a_OutPacketBuffer.CommitRead();
- a_Client.SendData(PacketData.data(), PacketData.size());
+ a_Client.SendData(PacketData);
}
diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp
index 0efef360c..b3a3205d5 100644
--- a/src/Protocol/Protocol_1_10.cpp
+++ b/src/Protocol/Protocol_1_10.cpp
@@ -679,7 +679,7 @@ void cProtocol_1_10_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp
index 05bf35562..ff0c34223 100644
--- a/src/Protocol/Protocol_1_11.cpp
+++ b/src/Protocol/Protocol_1_11.cpp
@@ -520,7 +520,7 @@ void cProtocol_1_11_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index 93a1160ee..30a975d18 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -1045,7 +1045,7 @@ void cProtocol_1_12::HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer)
{
// TODO not yet used, not sure if it is needed
// https://wiki.vg/index.php?title=Protocol&oldid=14204#Crafting_Book_Data
- a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
+ a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace());
}
@@ -1054,7 +1054,7 @@ void cProtocol_1_12::HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer)
void cProtocol_1_12::HandlePacketAdvancementTab(cByteBuffer & a_ByteBuffer)
{
- a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
+ a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace());
m_Client->GetPlayer()->SendMessageInfo("The new advancements are not implemented.");
}
diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp
index 251f8cf55..4da065af7 100644
--- a/src/Protocol/Protocol_1_13.cpp
+++ b/src/Protocol/Protocol_1_13.cpp
@@ -298,13 +298,14 @@ void cProtocol_1_13::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
m_Client->SetClientBrand(Brand);
// Send back our brand, including the length:
- SendPluginMessage("minecraft:brand", "\x08""Cuberite");
+ m_Client->SendPluginMessage("minecraft:brand", "\x08""Cuberite");
return;
}
+ ContiguousByteBuffer Data;
+
// Read the plugin message and relay to clienthandle:
- AString Data;
- VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
+ VERIFY(a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace())); // Always succeeds
m_Client->HandlePluginMessage(Channel, Data);
}
@@ -694,8 +695,8 @@ bool cProtocol_1_13::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t
a_Item.Empty();
}
- AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
+ ContiguousByteBuffer Metadata;
+ if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
{
// No metadata
return true;
@@ -1423,8 +1424,8 @@ bool cProtocol_1_13_2::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size
a_Item.Empty();
}
- AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
+ ContiguousByteBuffer Metadata;
+ if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
{
// No metadata
return true;
diff --git a/src/Protocol/Protocol_1_14.cpp b/src/Protocol/Protocol_1_14.cpp
index e015c6cd1..bc0e68d94 100644
--- a/src/Protocol/Protocol_1_14.cpp
+++ b/src/Protocol/Protocol_1_14.cpp
@@ -231,8 +231,7 @@ bool cProtocol_1_14::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp
// Game
switch (a_PacketType)
{
- default: AString dum; a_ByteBuffer.ReadAll(dum); a_ByteBuffer.CommitRead(); a_ByteBuffer.Write(" ", 1);
- return true;
+ default: a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace()); a_ByteBuffer.CommitRead(); return true;
}
}
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index d9d18b41a..12e2d441c 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -85,7 +85,6 @@ Implements the 1.8 protocol classes:
const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
-const uLongf MAX_COMPRESSED_PACKET_LEN = 200 KiB; // Maximum size of compressed packets.
static const UInt32 CompressionThreshold = 256; // After how large a packet should we compress it.
@@ -178,7 +177,7 @@ void cProtocol_1_8_0::DataReceived(cByteBuffer & a_Buffer, const char * a_Data,
{
if (m_IsEncrypted)
{
- Byte Decrypted[512];
+ std::byte Decrypted[512];
while (a_Size > 0)
{
size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
@@ -320,12 +319,12 @@ void cProtocol_1_8_0::SendChatRaw(const AString & a_MessageRaw, eChatType a_Type
-void cProtocol_1_8_0::SendChunkData(const std::string_view a_ChunkData)
+void cProtocol_1_8_0::SendChunkData(const ContiguousByteBufferView a_ChunkData)
{
ASSERT(m_State == 3); // In game mode?
cCSLock Lock(m_CSPacket);
- SendData(a_ChunkData.data(), a_ChunkData.size());
+ SendData(a_ChunkData);
}
@@ -1143,13 +1142,13 @@ void cProtocol_1_8_0::SendPlayerSpawn(const cPlayer & a_Player)
-void cProtocol_1_8_0::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+void cProtocol_1_8_0::SendPluginMessage(const AString & a_Channel, const ContiguousByteBufferView a_Message)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, pktPluginMessage);
Pkt.WriteString(a_Channel);
- Pkt.WriteBuf(a_Message.data(), a_Message.size());
+ Pkt.WriteBuf(a_Message);
}
@@ -1717,11 +1716,11 @@ void cProtocol_1_8_0::SendWindowProperty(const cWindow & a_Window, size_t a_Prop
-bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_CompressedData)
+void cProtocol_1_8_0::CompressPacket(CircularBufferCompressor & a_Packet, ContiguousByteBuffer & a_CompressedData)
{
- const auto UncompressedSize = a_Packet.size();
+ const auto Uncompressed = a_Packet.GetView();
- if (UncompressedSize < CompressionThreshold)
+ if (Uncompressed.size() < CompressionThreshold)
{
/* Size doesn't reach threshold, not worth compressing.
@@ -1734,7 +1733,7 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
----------------------------------------------
*/
const UInt32 DataSize = 0;
- const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + UncompressedSize);
+ const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + Uncompressed.size());
cByteBuffer LengthHeaderBuffer(
cByteBuffer::GetVarIntSize(PacketSize) +
@@ -1744,14 +1743,14 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
LengthHeaderBuffer.WriteVarInt32(PacketSize);
LengthHeaderBuffer.WriteVarInt32(DataSize);
- AString LengthData;
+ ContiguousByteBuffer LengthData;
LengthHeaderBuffer.ReadAll(LengthData);
- a_CompressedData.reserve(LengthData.size() + UncompressedSize);
- a_CompressedData.assign(LengthData.data(), LengthData.size());
- a_CompressedData.append(a_Packet);
+ a_CompressedData.reserve(LengthData.size() + Uncompressed.size());
+ a_CompressedData = LengthData;
+ a_CompressedData += Uncompressed;
- return true;
+ return;
}
/* Definitely worth compressing.
@@ -1765,28 +1764,11 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
----------------------------------------------
*/
- // Compress the data:
- char CompressedData[MAX_COMPRESSED_PACKET_LEN];
-
- uLongf CompressedSize = compressBound(static_cast<uLongf>(a_Packet.size()));
- if (CompressedSize >= MAX_COMPRESSED_PACKET_LEN)
- {
- ASSERT(!"Too high packet size.");
- return false;
- }
-
- if (
- compress2(
- reinterpret_cast<Bytef *>(CompressedData), &CompressedSize,
- reinterpret_cast<const Bytef *>(a_Packet.data()), static_cast<uLongf>(a_Packet.size()), Z_DEFAULT_COMPRESSION
- ) != Z_OK
- )
- {
- return false;
- }
+ const auto CompressedData = a_Packet.Compress();
+ const auto Compressed = CompressedData.GetView();
- const UInt32 DataSize = static_cast<UInt32>(UncompressedSize);
- const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + CompressedSize);
+ const UInt32 DataSize = static_cast<UInt32>(Uncompressed.size());
+ const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + Compressed.size());
cByteBuffer LengthHeaderBuffer(
cByteBuffer::GetVarIntSize(PacketSize) +
@@ -1796,14 +1778,12 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
LengthHeaderBuffer.WriteVarInt32(PacketSize);
LengthHeaderBuffer.WriteVarInt32(DataSize);
- AString LengthData;
+ ContiguousByteBuffer LengthData;
LengthHeaderBuffer.ReadAll(LengthData);
- a_CompressedData.reserve(LengthData.size() + CompressedSize);
- a_CompressedData.assign(LengthData.data(), LengthData.size());
- a_CompressedData.append(CompressedData, CompressedSize);
-
- return true;
+ a_CompressedData.reserve(LengthData.size() + Compressed.size());
+ a_CompressedData = LengthData;
+ a_CompressedData += Compressed;
}
@@ -1947,7 +1927,7 @@ void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Dat
{
if (a_Buffer.GetReadableSpace() > 0)
{
- AString AllData;
+ ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
@@ -1992,12 +1972,11 @@ void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Dat
}
// Check packet for compression:
- UInt32 UncompressedSize = 0;
- AString UncompressedData;
if (m_State == 3)
{
UInt32 NumBytesRead = static_cast<UInt32>(a_Buffer.GetReadableSpace());
+ UInt32 UncompressedSize;
if (!a_Buffer.ReadVarInt(UncompressedSize))
{
m_Client->Kick("Compression packet incomplete");
@@ -2011,113 +1990,35 @@ void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Dat
if (UncompressedSize > 0)
{
// Decompress the data:
- AString CompressedData;
- VERIFY(a_Buffer.ReadString(CompressedData, PacketLen));
- if (InflateString(CompressedData.data(), PacketLen, UncompressedData) != Z_OK)
- {
- m_Client->Kick("Compression failure");
- return;
- }
- PacketLen = static_cast<UInt32>(UncompressedData.size());
- if (PacketLen != UncompressedSize)
- {
- m_Client->Kick("Wrong uncompressed packet size given");
- return;
- }
- }
- }
-
- // Move the packet payload to a separate cByteBuffer, bb:
- cByteBuffer bb(PacketLen + 1);
- if (UncompressedSize == 0)
- {
- // No compression was used, move directly
- VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
- }
- else
- {
- // Compression was used, move the uncompressed data:
- VERIFY(bb.Write(UncompressedData.data(), UncompressedData.size()));
- }
- a_Buffer.CommitRead();
+ m_Extractor.ReadFrom(a_Buffer, PacketLen);
+ a_Buffer.CommitRead();
- UInt32 PacketType;
- if (!bb.ReadVarInt(PacketType))
- {
- // Not enough data
- break;
- }
-
- // Write one NUL extra, so that we can detect over-reads
- bb.Write("\0", 1);
+ const auto UncompressedData = m_Extractor.Extract(UncompressedSize);
+ const auto Uncompressed = UncompressedData.GetView();
+ cByteBuffer bb(Uncompressed.size());
- // Log the packet info into the comm log file:
- if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
- {
- AString PacketData;
- bb.ReadAll(PacketData);
- bb.ResetRead();
- bb.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again
- ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read
- PacketData.resize(PacketData.size() - 1);
- AString PacketDataHex;
- CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16);
- m_CommLogFile.Printf("Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload:\n%s\n",
- PacketType, PacketType, PacketLen, PacketLen, m_State, PacketDataHex.c_str()
- );
- }
+ // Compression was used, move the uncompressed data:
+ VERIFY(bb.Write(Uncompressed.data(), Uncompressed.size()));
- if (!HandlePacket(bb, PacketType))
- {
- // Unknown packet, already been reported, but without the length. Log the length here:
- LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
-
- #ifdef _DEBUG
- // Dump the packet contents into the log:
- bb.ResetRead();
- AString Packet;
- bb.ReadAll(Packet);
- Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
- AString Out;
- CreateHexDump(Out, Packet.data(), Packet.size(), 24);
- LOGD("Packet contents:\n%s", Out.c_str());
- #endif // _DEBUG
-
- // Put a message in the comm log:
- if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
- {
- m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
+ HandlePacket(bb);
+ continue;
}
-
- return;
}
- // The packet should have 1 byte left in the buffer - the NUL we had added
- if (bb.GetReadableSpace() != 1)
- {
- // Read more or less than packet length, report as error
- LOGWARNING("Protocol 1.8: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes",
- PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
- );
+ // Move the packet payload to a separate cByteBuffer, bb:
+ cByteBuffer bb(PacketLen);
- // Put a message in the comm log:
- if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
- {
- m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %zu left) ^^^^^^\n\n\n",
- 1, bb.GetReadableSpace()
- );
- m_CommLogFile.Flush();
- }
+ // No compression was used, move directly:
+ VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
+ a_Buffer.CommitRead();
- ASSERT(!"Read wrong number of bytes!");
- m_Client->PacketError(PacketType);
- }
+ HandlePacket(bb);
} // for (ever)
// Log any leftover bytes into the logfile:
if (g_ShouldLogCommIn && (a_Buffer.GetReadableSpace() > 0) && m_CommLogFile.IsOpen())
{
- AString AllData;
+ ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
@@ -2367,8 +2268,8 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
{
return;
}
- AString EncKey;
- if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength))
+ ContiguousByteBuffer EncKey;
+ if (!a_ByteBuffer.ReadSome(EncKey, EncKeyLength))
{
return;
}
@@ -2376,8 +2277,8 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
{
return;
}
- AString EncNonce;
- if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength))
+ ContiguousByteBuffer EncNonce;
+ if (!a_ByteBuffer.ReadSome(EncNonce, EncNonceLength))
{
return;
}
@@ -2391,7 +2292,7 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
// Decrypt EncNonce using privkey
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
- int res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncNonce.data()), EncNonce.size(), reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
+ int res = rsaDecryptor.Decrypt(EncNonce, reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
if (res != 4)
{
LOGD("Bad nonce length: got %d, exp %d", res, 4);
@@ -2407,7 +2308,7 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
// Decrypt the symmetric encryption key using privkey:
Byte DecryptedKey[MAX_ENC_LEN];
- res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncKey.data()), EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
+ res = rsaDecryptor.Decrypt(EncKey, DecryptedKey, sizeof(DecryptedKey));
if (res != 16)
{
LOGD("Bad key length");
@@ -2416,7 +2317,7 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
}
StartEncryption(DecryptedKey);
- m_Client->HandleLogin(m_Client->GetUsername());
+ m_Client->HandleLogin();
}
@@ -2438,22 +2339,22 @@ void cProtocol_1_8_0::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
return;
}
- cServer * Server = cRoot::Get()->GetServer();
+ m_Client->SetUsername(std::move(Username));
+
// If auth is required, then send the encryption request:
- if (Server->ShouldAuthenticate())
+ if (const auto Server = cRoot::Get()->GetServer(); Server->ShouldAuthenticate())
{
cPacketizer Pkt(*this, pktEncryptionRequest);
Pkt.WriteString(Server->GetServerID());
- const AString & PubKeyDer = Server->GetPublicKeyDER();
+ const auto PubKeyDer = Server->GetPublicKeyDER();
Pkt.WriteVarInt32(static_cast<UInt32>(PubKeyDer.size()));
- Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
+ Pkt.WriteBuf(PubKeyDer);
Pkt.WriteVarInt32(4);
Pkt.WriteBEInt32(static_cast<int>(reinterpret_cast<intptr_t>(this))); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
- m_Client->SetUsername(Username);
return;
}
- m_Client->HandleLogin(Username);
+ m_Client->HandleLogin();
}
@@ -2704,20 +2605,20 @@ void cProtocol_1_8_0::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
HandleVanillaPluginMessage(a_ByteBuffer, Channel);
// Skip any unread data (vanilla sometimes sends garbage at the end of a packet; #1692):
- if (a_ByteBuffer.GetReadableSpace() > 1)
+ if (a_ByteBuffer.GetReadableSpace() > 0)
{
LOGD("Protocol 1.8: Skipping garbage data at the end of a vanilla PluginMessage packet, %u bytes",
- static_cast<unsigned>(a_ByteBuffer.GetReadableSpace() - 1)
+ static_cast<unsigned>(a_ByteBuffer.GetReadableSpace())
);
- a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
+ a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace());
}
return;
}
// Read the plugin message and relay to clienthandle:
- AString Data;
- VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
+ ContiguousByteBuffer Data;
+ VERIFY(a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace())); // Always succeeds
m_Client->HandlePluginMessage(Channel, Data);
}
@@ -2976,7 +2877,7 @@ void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, con
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand);
m_Client->SetClientBrand(Brand);
// Send back our brand, including the length:
- SendPluginMessage("MC|Brand", "\x08""Cuberite");
+ m_Client->SendPluginMessage("MC|Brand", "\x08""Cuberite");
return;
}
else if (a_Channel == "MC|Beacon")
@@ -3001,8 +2902,8 @@ void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, con
LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str());
// Read the payload and send it through to the clienthandle:
- AString Message;
- VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1));
+ ContiguousByteBuffer Message;
+ VERIFY(a_ByteBuffer.ReadSome(Message, a_ByteBuffer.GetReadableSpace() - 1));
m_Client->HandlePluginMessage(a_Channel, Message);
}
@@ -3010,23 +2911,24 @@ void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, con
-void cProtocol_1_8_0::SendData(const char * a_Data, size_t a_Size)
+void cProtocol_1_8_0::SendData(ContiguousByteBufferView a_Data)
{
if (m_IsEncrypted)
{
- Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
- while (a_Size > 0)
+ std::byte Encrypted[8 KiB]; // Larger buffer, we may be sending lots of data (chunks)
+
+ while (a_Data.size() > 0)
{
- size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
- m_Encryptor.ProcessData(Encrypted, reinterpret_cast<const Byte *>(a_Data), NumBytes);
- m_Client->SendData(reinterpret_cast<const char *>(Encrypted), NumBytes);
- a_Size -= NumBytes;
- a_Data += NumBytes;
+ const auto NumBytes = (a_Data.size() > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Data.size();
+ m_Encryptor.ProcessData(Encrypted, a_Data.data(), NumBytes);
+ m_Client->SendData({ Encrypted, NumBytes });
+
+ a_Data = a_Data.substr(NumBytes);
}
}
else
{
- m_Client->SendData(a_Data, a_Size);
+ m_Client->SendData(a_Data);
}
}
@@ -3054,8 +2956,8 @@ bool cProtocol_1_8_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_
a_Item.Empty();
}
- AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
+ ContiguousByteBuffer Metadata;
+ if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
{
// No metadata
return true;
@@ -3069,10 +2971,10 @@ bool cProtocol_1_8_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_
-void cProtocol_1_8_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
+void cProtocol_1_8_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata)
{
// Parse into NBT:
- cParsedNBT NBT(a_Metadata.data(), a_Metadata.size());
+ cParsedNBT NBT(a_Metadata);
if (!NBT.IsValid())
{
AString HexDump;
@@ -3189,33 +3091,34 @@ eBlockFace cProtocol_1_8_0::FaceIntToBlockFace(const Int32 a_BlockFace)
void cProtocol_1_8_0::SendPacket(cPacketizer & a_Pkt)
{
- UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace());
- AString PacketData, CompressedPacket;
- m_OutPacketBuffer.ReadAll(PacketData);
+ ASSERT(m_OutPacketBuffer.GetReadableSpace() == m_OutPacketBuffer.GetUsedSpace());
+
+ m_Compressor.ReadFrom(m_OutPacketBuffer);
m_OutPacketBuffer.CommitRead();
+ const auto PacketData = m_Compressor.GetView();
+
if (m_State == 3)
{
+ ContiguousByteBuffer CompressedPacket;
+
// Compress the packet payload:
- if (!cProtocol_1_8_0::CompressPacket(PacketData, CompressedPacket))
- {
- return;
- }
+ cProtocol_1_8_0::CompressPacket(m_Compressor, CompressedPacket);
// Send the packet's payload compressed:
- SendData(CompressedPacket.data(), CompressedPacket.size());
+ SendData(CompressedPacket);
}
else
{
// Compression doesn't apply to this state, send raw data:
- m_OutPacketLenBuffer.WriteVarInt32(PacketLen);
- AString LengthData;
+ m_OutPacketLenBuffer.WriteVarInt32(static_cast<UInt32>(PacketData.size()));
+ ContiguousByteBuffer LengthData;
m_OutPacketLenBuffer.ReadAll(LengthData);
- SendData(LengthData.data(), LengthData.size());
+ m_OutPacketLenBuffer.CommitRead();
+ SendData(LengthData);
// Send the packet's payload directly:
- m_OutPacketLenBuffer.CommitRead();
- SendData(PacketData.data(), PacketData.size());
+ SendData(PacketData);
}
// Log the comm into logfile:
@@ -3226,7 +3129,7 @@ void cProtocol_1_8_0::SendPacket(cPacketizer & a_Pkt)
CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16);
m_CommLogFile.Printf("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n",
cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()),
- PacketLen, PacketLen, m_State, Hex
+ PacketData.size(), PacketData.size(), m_State, Hex
);
/*
// Useful for debugging a new protocol:
@@ -3346,13 +3249,13 @@ void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
}
Writer.Finish();
- AString Result = Writer.GetResult();
- if (Result.size() == 0)
+ const auto Result = Writer.GetResult();
+ if (Result.empty())
{
a_Pkt.WriteBEInt8(0);
return;
}
- a_Pkt.WriteBuf(Result.data(), Result.size());
+ a_Pkt.WriteBuf(Result);
}
@@ -3479,7 +3382,7 @@ void cProtocol_1_8_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity &
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
@@ -3978,6 +3881,82 @@ void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity &
+void cProtocol_1_8_0::HandlePacket(cByteBuffer & a_Buffer)
+{
+ UInt32 PacketType;
+ if (!a_Buffer.ReadVarInt(PacketType))
+ {
+ // Not enough data
+ return;
+ }
+
+ // Log the packet info into the comm log file:
+ if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
+ {
+ ContiguousByteBuffer PacketData;
+ a_Buffer.ReadAll(PacketData);
+ a_Buffer.ResetRead();
+ a_Buffer.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again
+ ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read
+ PacketData.resize(PacketData.size() - 1);
+ AString PacketDataHex;
+ CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16);
+ m_CommLogFile.Printf("Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload:\n%s\n",
+ PacketType, PacketType, a_Buffer.GetUsedSpace(), a_Buffer.GetUsedSpace(), m_State, PacketDataHex.c_str()
+ );
+ }
+
+ if (!HandlePacket(a_Buffer, PacketType))
+ {
+ // Unknown packet, already been reported, but without the length. Log the length here:
+ LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, a_Buffer.GetUsedSpace());
+
+#ifdef _DEBUG
+ // Dump the packet contents into the log:
+ a_Buffer.ResetRead();
+ ContiguousByteBuffer Packet;
+ a_Buffer.ReadAll(Packet);
+ Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
+ AString Out;
+ CreateHexDump(Out, Packet.data(), Packet.size(), 24);
+ LOGD("Packet contents:\n%s", Out.c_str());
+#endif // _DEBUG
+
+ // Put a message in the comm log:
+ if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
+ {
+ m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
+ }
+
+ return;
+ }
+
+ // The packet should have nothing left in the buffer:
+ if (a_Buffer.GetReadableSpace() != 0)
+ {
+ // Read more or less than packet length, report as error
+ LOGWARNING("Protocol 1.8: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes",
+ PacketType, m_State, a_Buffer.GetUsedSpace() - a_Buffer.GetReadableSpace(), a_Buffer.GetUsedSpace()
+ );
+
+ // Put a message in the comm log:
+ if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
+ {
+ m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %zu left) ^^^^^^\n\n\n",
+ 1, a_Buffer.GetReadableSpace()
+ );
+ m_CommLogFile.Flush();
+ }
+
+ ASSERT(!"Read wrong number of bytes!");
+ m_Client->PacketError(PacketType);
+ }
+}
+
+
+
+
+
void cProtocol_1_8_0::SendEntityTeleport(const cEntity & a_Entity)
{
cPacketizer Pkt(*this, pktTeleportEntity);
diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h
index 44415758f..f5800cb21 100644
--- a/src/Protocol/Protocol_1_8.h
+++ b/src/Protocol/Protocol_1_8.h
@@ -20,6 +20,9 @@ Declares the 1.8 protocol classes:
#include "../mbedTLS++/AesCfb128Decryptor.h"
#include "../mbedTLS++/AesCfb128Encryptor.h"
+#include "CircularBufferCompressor.h"
+#include "StringCompression.h"
+
@@ -46,7 +49,7 @@ public:
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 (const std::string_view a_ChunkData) override;
+ virtual void SendChunkData (ContiguousByteBufferView a_ChunkData) 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;
@@ -88,7 +91,7 @@ public:
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 SendPluginMessage (const AString & a_Channel, ContiguousByteBufferView 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;
@@ -125,9 +128,8 @@ public:
virtual AString GetAuthServerID(void) override { return m_AuthServerID; }
/** Compress the packet. a_Packet must be without packet length.
- a_Compressed will be set to the compressed packet includes packet length and data length.
- If compression fails, the function returns false. */
- static bool CompressPacket(const AString & a_Packet, AString & a_Compressed);
+ a_Compressed will be set to the compressed packet includes packet length and data length. */
+ static void CompressPacket(CircularBufferCompressor & a_Packet, ContiguousByteBuffer & a_Compressed);
/** The 1.8 protocol use a particle id instead of a string. This function converts the name to the id. If the name is incorrect, it returns 0. */
static int GetParticleID(const AString & a_ParticleName);
@@ -194,7 +196,7 @@ protected:
virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel);
/** Sends the data to the client, encrypting them if needed. */
- virtual void SendData(const char * a_Data, size_t a_Size) override;
+ virtual void SendData(ContiguousByteBufferView a_Size) override;
/** Sends the packet to the client. Called by the cPacketizer's destructor. */
virtual void SendPacket(cPacketizer & a_Packet) override;
@@ -205,7 +207,7 @@ protected:
virtual bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes = 0);
/** Parses item metadata as read by ReadItem(), into the item enchantments. */
- virtual void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
+ virtual void ParseItemMetadata(cItem & a_Item, ContiguousByteBufferView a_Metadata);
virtual void StartEncryption(const Byte * a_Key);
@@ -242,9 +244,15 @@ private:
cAesCfb128Decryptor m_Decryptor;
cAesCfb128Encryptor m_Encryptor;
+ CircularBufferCompressor m_Compressor;
+ CircularBufferExtractor m_Extractor;
+
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;
+ /** Handle a complete packet stored in the given buffer. */
+ void HandlePacket(cByteBuffer & a_Buffer);
+
/** Sends an entity teleport packet.
Mitigates a 1.8 bug where the position in the entity spawn packet is ignored,
and so entities don't show up until a teleport is sent. */
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 72d3fd4b1..67e920925 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -1031,10 +1031,10 @@ void cProtocol_1_9_0::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
-void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
+void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata)
{
// Parse into NBT:
- cParsedNBT NBT(a_Metadata.data(), a_Metadata.size());
+ cParsedNBT NBT(a_Metadata);
if (!NBT.IsValid())
{
AString HexDump;
@@ -1438,13 +1438,13 @@ void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
Writer.Finish();
- AString Result = Writer.GetResult();
- if (Result.size() == 0)
+ const auto Result = Writer.GetResult();
+ if (Result.empty())
{
a_Pkt.WriteBEInt8(0);
return;
}
- a_Pkt.WriteBuf(Result.data(), Result.size());
+ a_Pkt.WriteBuf(Result);
}
@@ -1550,7 +1550,7 @@ void cProtocol_1_9_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity &
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
@@ -2289,7 +2289,7 @@ void cProtocol_1_9_4::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, c
Writer.AddString("Text4", JsonUtils::WriteFastString(Line4));
Writer.Finish();
- Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ Pkt.WriteBuf(Writer.GetResult());
}
diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h
index 0339ddeb3..27b005bd4 100644
--- a/src/Protocol/Protocol_1_9.h
+++ b/src/Protocol/Protocol_1_9.h
@@ -98,7 +98,7 @@ protected:
virtual void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer) override;
/** Parses item metadata as read by ReadItem(), into the item enchantments. */
- virtual void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) override;
+ virtual void ParseItemMetadata(cItem & a_Item, ContiguousByteBufferView a_Metadata) override;
/** Converts the hand parameter received by the protocol into eHand constants.
If the received value doesn't match any of the know value, raise an assertion fail or return hMain. */