fix(master): a cut password skips what it cut, and a starting private instance answers once ready

A capped string now skips the characters it cut, so what follows it is read from the
right place. A request to join a private instance that is still starting is answered
once its world server is ready, instead of at once with an address nothing listens
on yet.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-11-10 18:37:35 -06:00
parent 37cc844562
commit 11a70ad870
3 changed files with 29 additions and 1 deletions

View File

@@ -918,6 +918,12 @@ namespace {
return;
}
// Still starting (asked for right after it was created): answered when its world server is ready
if (!instance->GetIsReady()) {
instance->GetPendingRequests().push_back({ requestID, static_cast<bool>(mythranShift), sysAddr, {} });
return;
}
const auto& zone = instance->GetZoneID();
RequestZoneTransferResponse response;

View File

@@ -16,7 +16,12 @@ namespace {
uint32_t length{};
VALIDATE_READ(bitStream.Read(length));
value.resize(std::min(length, maxLength));
return value.empty() || bitStream.ReadBits(reinterpret_cast<unsigned char*>(value.data()), BYTES_TO_BITS(value.size()), true);
if (!value.empty() && !bitStream.ReadBits(reinterpret_cast<unsigned char*>(value.data()), BYTES_TO_BITS(value.size()), true)) return false;
const uint32_t rest = length - static_cast<uint32_t>(value.size());
if (rest == 0) return true;
if (BITS_TO_BYTES(bitStream.GetNumberOfUnreadBits()) < rest) return false;
bitStream.IgnoreBits(BYTES_TO_BITS(rest));
return true;
}
}

View File

@@ -720,3 +720,20 @@ TEST(MasterPacketsTests, ServerListWithoutOutdatedFlags) {
ASSERT_TRUE(withFlag.Deserialize(again));
EXPECT_EQ(withFlag.instances[0].outdated, 1);
}
// A password longer than master keeps is cut, and the characters cut are skipped: nothing of it is left to be read
// as what follows
TEST(MasterPacketsTests, CappedPasswordSkipsWhatItCut) {
for (const auto& password : g_Strings) {
MasterPackets::CreatePrivateZone sent;
sent.zoneID = 1100;
sent.cloneID = 7;
sent.password = password;
RakNet::BitStream stream;
LoadPayload(stream, sent);
MasterPackets::CreatePrivateZone read;
ASSERT_TRUE(read.Deserialize(stream));
EXPECT_EQ(read.password, password.substr(0, MasterPackets::CreatePrivateZone::MAX_PASSWORD_LENGTH));
EXPECT_EQ(stream.GetNumberOfUnreadBits(), 0u);
}
}