From 13579a2b6ba9d95c850dd7fffb5ef40ece8de8da Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Wed, 17 Jul 2024 23:33:25 +0200 Subject: [PATCH] Add --getProtocolVersionData and --getProtocolVersionHash arguments --- interface/src/main.cpp | 38 +++++++++++ .../networking/src/udt/PacketHeaders.cpp | 16 +++++ libraries/networking/src/udt/PacketHeaders.h | 66 ++++++++++++++++++- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 4de09fca1f..c1854de446 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -275,6 +275,14 @@ int main(int argc, const char* argv[]) { "abortAfterInit", "Debug option. Aborts after initialization, right before the program starts running the event loop." ); + QCommandLineOption getProtocolVersionHashOption( + "getProtocolVersionHash", + "Debug option. Returns the network protocol version MD5 hash." + ); + QCommandLineOption getProtocolVersionDataOption( + "getProtocolVersionData", + "Debug option. Returns the network protocol detailed data in JSON." + ); // "--qmljsdebugger", which appears in output from "--help-all". // Those below don't seem to be optional. @@ -321,6 +329,8 @@ int main(int argc, const char* argv[]) { parser.addOption(abortAfterStartupOption); parser.addOption(abortAfterInitOption); parser.addOption(getPluginsOption); + parser.addOption(getProtocolVersionHashOption); + parser.addOption(getProtocolVersionDataOption); QString applicationPath; @@ -455,6 +465,34 @@ int main(int argc, const char* argv[]) { return 1; } } + if (parser.isSet(getProtocolVersionHashOption)) { + std::cout << protocolVersionsSignatureHex().toStdString() << std::endl; + return 0; + } + if (parser.isSet(getProtocolVersionDataOption)) { + auto protocolMap = protocolVersionsSignatureMap(); + QMetaEnum packetMetaEnum = QMetaEnum::fromType(); + + QJsonArray packetTypesList; + auto keyList = protocolMap.keys(); + std::sort(keyList.begin(), keyList.end()); // Sort by numeric value + + for(const auto packet : keyList) { + QJsonObject data; + int intValue = static_cast(packet); + QString keyName = packetMetaEnum.valueToKey(intValue); + + data["name"] = keyName; + data["value"] = intValue; + data["version"] = versionForPacketType(packet); + + packetTypesList.append(data); + } + + std::cout << QJsonDocument(packetTypesList).toJson().toStdString() << std::endl; + return 0; + } + static const QString APPLICATION_CONFIG_FILENAME = "config.json"; QDir applicationDir(applicationPath); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e561bfe21e..2aafc5501e 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -130,6 +130,10 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion) { static QByteArray protocolVersionSignature; static QString protocolVersionSignatureBase64; +static QString protocolVersionSignatureHex; +static QMap protocolVersionMap; + + static void ensureProtocolVersionsSignature() { static std::once_flag once; std::call_once(once, [&] { @@ -139,12 +143,14 @@ static void ensureProtocolVersionsSignature() { stream << numberOfProtocols; for (uint8_t packetType = 0; packetType < numberOfProtocols; packetType++) { uint8_t packetTypeVersion = static_cast(versionForPacketType(static_cast(packetType))); + protocolVersionMap[static_cast(packetType)] = packetTypeVersion; stream << packetTypeVersion; } QCryptographicHash hash(QCryptographicHash::Md5); hash.addData(buffer); protocolVersionSignature = hash.result(); protocolVersionSignatureBase64 = protocolVersionSignature.toBase64(); + protocolVersionSignatureHex = protocolVersionSignature.toHex(0); }); } QByteArray protocolVersionsSignature() { @@ -161,3 +167,13 @@ QString protocolVersionsSignatureBase64() { ensureProtocolVersionsSignature(); return protocolVersionSignatureBase64; } + +QString protocolVersionsSignatureHex() { + ensureProtocolVersionsSignature(); + return protocolVersionSignatureHex; +} + +QMap protocolVersionsSignatureMap() { + ensureProtocolVersionsSignature(); + return protocolVersionMap; +} \ No newline at end of file diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3badfdf418..bc36d9444a 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -31,8 +31,15 @@ class PacketTypeEnum { Q_GADGET Q_ENUMS(Value) public: - // If adding a new packet packetType, you can replace one marked usable or add at the end. - // This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t + + /** + * @brief Packet type identifier + * + * Identifies the type of packet being sent. + * + * @note If adding a new packet packetType, you can replace one marked usable or add at the end. + * @note This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t + */ enum class Value : uint8_t { Unknown, DomainConnectRequestPending, @@ -143,6 +150,8 @@ public: NUM_PACKET_TYPE }; + Q_ENUM(Value) + const static QHash getReplicatedPacketMapping() { const static QHash REPLICATED_PACKET_MAPPING { { PacketTypeEnum::Value::MicrophoneAudioNoEcho, PacketTypeEnum::Value::ReplicatedMicrophoneAudioNoEcho }, @@ -219,10 +228,60 @@ const int NUM_BYTES_MD5_HASH = 16; // NOTE: There is a max limit of 255, hopefully we have a better way to manage this by then. typedef uint8_t PacketVersion; +/** + * @brief Returns the version number of the given packet type + * + * If the implementation of a packet type is modified in an incompatible way, the implementation + * of this function needs to be modified to return an incremented value. + * + * This is used to determine whether the protocol is compatible between client and server. + * + * @note Version is limited to a max of 255. + * + * @param packetType Type of packet + * @return PacketVersion Version + */ PacketVersion versionForPacketType(PacketType packetType); -QByteArray protocolVersionsSignature(); /// returns a unique signature for all the current protocols + +/** + * @brief Returns a unique signature for all the current protocols + * + * This computes a MD5 hash that expresses the state of the protocol's specification. The calculation + * is done in ensureProtocolVersionsSignature and accounts for the following: + * + * * Number of known packet types + * * versionForPacketType(type) for each packet type. + * + * There's no provision for backwards compatibility, anything that changes this calculation is a protocol break. + * + * @return QByteArray MD5 digest as a byte array + */ +QByteArray protocolVersionsSignature(); + +/*** + * @brief Returns a unique signature for all the current protocols + * + * Same as protocolVersionsSignature(), in base64. + */ QString protocolVersionsSignatureBase64(); +/*** + * @brief Returns a unique signature for all the current protocols + * + * Same as protocolVersionsSignature(), in hex; + */ +QString protocolVersionsSignatureHex(); + +/*** + * @brief Returns the data used to compute the protocol version + * + * The key is the packet type. The value is the version for that packet type. + * + * Used for aiding in development. + */ +QMap protocolVersionsSignatureMap(); + + #if (PR_BUILD || DEV_BUILD) void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debugging version negotiation #endif @@ -428,4 +487,5 @@ enum class AvatarQueryVersion : PacketVersion { ConicalFrustums = 22 }; + #endif // hifi_PacketHeaders_h