// NLPacketCodec.cpp #include "NLPacketCodec.hpp" #include #include #include #include namespace Overte { // Control bit masks for sequence number field static constexpr uint32_t CONTROL_BIT_MASK = 0x80000000; // Bit 31 static constexpr uint32_t RELIABLE_BIT_MASK = 0x40000000; // Bit 30 static constexpr uint32_t MESSAGE_BIT_MASK = 0x20000000; // Bit 29 static constexpr uint32_t OBFUSCATION_MASK = 0x18000000; // Bits 27-28 static constexpr uint32_t SEQUENCE_NUMBER_MASK = 0x07FFFFFF; // Bits 0-26 NLPacket::NLPacket(PacketType type, PacketVersion version, bool isReliable) : m_type(type) , m_version(version) , m_isReliable(isReliable) { // Determine header size (sourced packets have LocalID) m_isSourced = false; // Most client packets aren't sourced m_headerSize = m_isSourced ? SOURCED_HEADER_SIZE : BASE_HEADER_SIZE; // Reserve space for header m_data.resize(m_headerSize); writeHeader(); } void NLPacket::writeHeader() { size_t offset = 0; // Write sequence number and flags uint32_t seqAndFlags = m_sequenceNumber & SEQUENCE_NUMBER_MASK; if (m_isReliable) { seqAndFlags |= RELIABLE_BIT_MASK; } // Convert to network byte order uint32_t netSeqAndFlags = htonl(seqAndFlags); std::memcpy(m_data.data() + offset, &netSeqAndFlags, sizeof(uint32_t)); offset += sizeof(uint32_t); // Write packet type m_data[offset++] = static_cast(m_type); // Write version m_data[offset++] = m_version; // Write source ID if sourced if (m_isSourced) { uint16_t netSourceID = htons(m_sourceID); std::memcpy(m_data.data() + offset, &netSourceID, sizeof(uint16_t)); offset += sizeof(uint16_t); } } void NLPacket::write(const void* data, size_t size) { const uint8_t* bytes = static_cast(data); m_data.insert(m_data.end(), bytes, bytes + size); } void NLPacket::writeUInt8(uint8_t value) { m_data.push_back(value); } void NLPacket::writeUInt16(uint16_t value) { uint16_t netValue = htons(value); write(&netValue, sizeof(netValue)); } void NLPacket::writeUInt32(uint32_t value) { uint32_t netValue = htonl(value); write(&netValue, sizeof(netValue)); } void NLPacket::writeUInt64(uint64_t value) { // Network byte order for 64-bit (big-endian) uint64_t netValue = ((value & 0xFF00000000000000ULL) >> 56) | ((value & 0x00FF000000000000ULL) >> 40) | ((value & 0x0000FF0000000000ULL) >> 24) | ((value & 0x000000FF00000000ULL) >> 8) | ((value & 0x00000000FF000000ULL) << 8) | ((value & 0x0000000000FF0000ULL) << 24) | ((value & 0x000000000000FF00ULL) << 40) | ((value & 0x00000000000000FFULL) << 56); write(&netValue, sizeof(netValue)); } void NLPacket::writeString(const std::string& str, bool nullTerminated) { write(str.data(), str.size()); if (nullTerminated) { writeUInt8(0); } } void NLPacket::setSequenceNumber(SequenceNumber seq) { m_sequenceNumber = seq & SEQUENCE_NUMBER_MASK; writeHeader(); } void NLPacket::setSourceID(LocalID id) { m_sourceID = id; m_isSourced = true; // Resize if needed if (m_headerSize != SOURCED_HEADER_SIZE) { m_headerSize = SOURCED_HEADER_SIZE; m_data.resize(m_headerSize); } writeHeader(); } bool NLPacket::parseHeader(const uint8_t* data, size_t size, Header& header) { if (size < BASE_HEADER_SIZE) { return false; } size_t offset = 0; // Read sequence and flags uint32_t netSeqAndFlags; std::memcpy(&netSeqAndFlags, data + offset, sizeof(uint32_t)); header.sequenceAndFlags = ntohl(netSeqAndFlags); offset += sizeof(uint32_t); // Read packet type header.type = static_cast(data[offset++]); // Read version header.version = data[offset++]; // Read source ID if present (check if packet is sourced) if (size >= SOURCED_HEADER_SIZE) { uint16_t netSourceID; std::memcpy(&netSourceID, data + offset, sizeof(uint16_t)); header.sourceID = ntohs(netSourceID); } else { header.sourceID = NULL_LOCAL_ID; } return true; } PacketType NLPacket::getType(const uint8_t* data, size_t size) { if (size < sizeof(uint32_t) + 1) { return PacketType::Unknown; } return static_cast(data[sizeof(uint32_t)]); } uint8_t NLPacket::versionForPacketType(PacketType type) { // Based on Overte's PacketHeaders.cpp versionForPacketType() // Returns the protocol version for each packet type switch (type) { case PacketType::DomainConnectRequest: return PacketVersions::DomainConnectRequest_SocketTypes; case PacketType::DomainListRequest: return PacketVersions::DomainListRequest_SocketTypes; case PacketType::DomainList: return PacketVersions::DomainList_SocketTypes; case PacketType::Ping: return PacketVersions::Ping_IncludeConnectionID; case PacketType::DomainConnectionDenied: return 19; // IncludesExtraInfo case PacketType::DomainConnectRequestPending: return 17; case PacketType::PingReply: return 17; case PacketType::ICEServerPeerInformation: case PacketType::ICEServerQuery: return 17; case PacketType::NodeIgnoreRequest: return 18; case PacketType::DomainServerAddedNode: return 25; // SocketTypes // For other packet types, return a default version // In real Overte, each has a specific version default: return 23; // Default version for unspecified packets (matches Overte) } } std::vector NLPacket::computeProtocolVersionSignature() { // Compute MD5 hash of all packet type versions // This matches Overte's ensureProtocolVersionsSignature() function std::vector buffer; // Write number of packet types (256 max, but we'll use actual count) uint8_t numPacketTypes = 128; // Conservative estimate for now buffer.push_back(numPacketTypes); // Write version for each packet type for (uint8_t i = 0; i < numPacketTypes; i++) { PacketType type = static_cast(i); uint8_t version = versionForPacketType(type); buffer.push_back(version); } // Compute MD5 hash std::vector hash(MD5_DIGEST_LENGTH); MD5(buffer.data(), buffer.size(), hash.data()); return hash; } } // namespace Overte