MoQT Framer. Turns structured message data into the wire image. PiperOrigin-RevId: 569530523
diff --git a/build/source_list.bzl b/build/source_list.bzl index 964887a..89f45e2 100644 --- a/build/source_list.bzl +++ b/build/source_list.bzl
@@ -1476,11 +1476,14 @@ "quic/load_balancer/load_balancer_server_id_test.cc", ] moqt_hdrs = [ + "quic/moqt/moqt_framer.h", "quic/moqt/moqt_messages.h", "quic/moqt/moqt_parser.h", "quic/moqt/test_tools/moqt_test_message.h", ] moqt_srcs = [ + "quic/moqt/moqt_framer.cc", + "quic/moqt/moqt_framer_test.cc", "quic/moqt/moqt_messages.cc", "quic/moqt/moqt_parser.cc", "quic/moqt/moqt_parser_test.cc",
diff --git a/build/source_list.gni b/build/source_list.gni index e02373f..da834ac 100644 --- a/build/source_list.gni +++ b/build/source_list.gni
@@ -1480,11 +1480,14 @@ "src/quiche/quic/load_balancer/load_balancer_server_id_test.cc", ] moqt_hdrs = [ + "src/quiche/quic/moqt/moqt_framer.h", "src/quiche/quic/moqt/moqt_messages.h", "src/quiche/quic/moqt/moqt_parser.h", "src/quiche/quic/moqt/test_tools/moqt_test_message.h", ] moqt_srcs = [ + "src/quiche/quic/moqt/moqt_framer.cc", + "src/quiche/quic/moqt/moqt_framer_test.cc", "src/quiche/quic/moqt/moqt_messages.cc", "src/quiche/quic/moqt/moqt_parser.cc", "src/quiche/quic/moqt/moqt_parser_test.cc",
diff --git a/build/source_list.json b/build/source_list.json index 4db9bc0..fdff71e 100644 --- a/build/source_list.json +++ b/build/source_list.json
@@ -1479,11 +1479,14 @@ "quiche/quic/load_balancer/load_balancer_server_id_test.cc" ], "moqt_hdrs": [ + "quiche/quic/moqt/moqt_framer.h", "quiche/quic/moqt/moqt_messages.h", "quiche/quic/moqt/moqt_parser.h", "quiche/quic/moqt/test_tools/moqt_test_message.h" ], "moqt_srcs": [ + "quiche/quic/moqt/moqt_framer.cc", + "quiche/quic/moqt/moqt_framer_test.cc", "quiche/quic/moqt/moqt_messages.cc", "quiche/quic/moqt/moqt_parser.cc", "quiche/quic/moqt/moqt_parser_test.cc"
diff --git a/quiche/quic/moqt/moqt_framer.cc b/quiche/quic/moqt/moqt_framer.cc new file mode 100644 index 0000000..986e1ae --- /dev/null +++ b/quiche/quic/moqt/moqt_framer.cc
@@ -0,0 +1,297 @@ +// Copyright (c) 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "quiche/quic/moqt/moqt_framer.h" + +#include <cstddef> +#include <cstdint> + +#include "absl/strings/string_view.h" +#include "quiche/quic/core/quic_data_writer.h" +#include "quiche/quic/core/quic_time.h" +#include "quiche/quic/core/quic_types.h" +#include "quiche/quic/moqt/moqt_messages.h" +#include "quiche/common/quiche_buffer_allocator.h" + +namespace moqt { + +namespace { + +inline size_t NeededVarIntLen(uint64_t value) { + return static_cast<size_t>(quic::QuicDataWriter::GetVarInt62Len(value)); +} +inline size_t ParameterLen(uint64_t type, uint64_t value_len) { + return NeededVarIntLen(type) + NeededVarIntLen(value_len) + value_len; +} + +// This only supports values up to UINT8_MAX, as that's all that exists in the +// standard. +inline bool WriteIntParameter(quic::QuicDataWriter& writer, uint64_t type, + uint8_t value) { + if (!writer.WriteVarInt62(type)) { + return false; + } + if (!writer.WriteVarInt62(1)) { + return false; + } + return writer.WriteUInt8(value); +} + +inline bool WriteStringParameter(quic::QuicDataWriter& writer, uint64_t type, + absl::string_view value) { + if (!writer.WriteVarInt62(type)) { + return false; + } + return writer.WriteStringPieceVarInt62(value); +} + +} // namespace + +quiche::QuicheBuffer MoqtFramer::SerializeObject( + const MoqtObject& message, const absl::string_view payload, + const size_t known_payload_size) { + if (known_payload_size > 0 && known_payload_size < payload.length()) { + return quiche::QuicheBuffer(); + } + size_t varint_len = NeededVarIntLen(message.track_id) + + NeededVarIntLen(message.group_sequence) + + NeededVarIntLen(message.object_sequence) + + NeededVarIntLen(message.object_send_order); + size_t message_len = + known_payload_size == 0 ? 0 : (known_payload_size + varint_len); + size_t buffer_size = + varint_len + payload.length() + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kObject)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kObject)); + writer.WriteVarInt62(message_len); + writer.WriteVarInt62(message.track_id); + writer.WriteVarInt62(message.group_sequence); + writer.WriteVarInt62(message.object_sequence); + writer.WriteVarInt62(message.object_send_order); + writer.WriteStringPiece(payload); + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeObjectPayload( + const absl::string_view payload) { + quiche::QuicheBuffer buffer(allocator_, payload.length()); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteStringPiece(payload); + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeSetup(const MoqtSetup& message) { + size_t message_len; + if (perspective_ == quic::Perspective::IS_CLIENT) { + message_len = NeededVarIntLen(message.number_of_supported_versions); + for (uint64_t i : message.supported_versions) { + message_len += NeededVarIntLen(i); + } + if (message.role.has_value()) { + message_len += + ParameterLen(static_cast<uint64_t>(MoqtSetupParameter::kRole), 1); + } + if (!using_webtrans_ && message.path.has_value()) { + message_len += + ParameterLen(static_cast<uint64_t>(MoqtSetupParameter::kPath), + message.path->length()); + } + } else { + message_len = NeededVarIntLen(message.supported_versions[0]); + } + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kSetup)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kSetup)); + writer.WriteVarInt62(message_len); + if (perspective_ == quic::Perspective::IS_SERVER) { + writer.WriteVarInt62(message.supported_versions[0]); + return buffer; + } + writer.WriteVarInt62(message.number_of_supported_versions); + for (uint64_t i : message.supported_versions) { + writer.WriteVarInt62(i); + } + if (message.role.has_value()) { + WriteIntParameter(writer, static_cast<uint64_t>(MoqtSetupParameter::kRole), + static_cast<uint8_t>(message.role.value())); + } + if (!using_webtrans_ && message.path.has_value()) { + WriteStringParameter(writer, + static_cast<uint64_t>(MoqtSetupParameter::kPath), + message.path.value()); + } + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeSubscribeRequest( + const MoqtSubscribeRequest& message) { + size_t message_len = NeededVarIntLen(message.full_track_name.length()) + + message.full_track_name.length(); + if (message.group_sequence.has_value()) { + message_len += ParameterLen( + static_cast<uint64_t>(MoqtTrackRequestParameter::kGroupSequence), 1); + } + if (message.object_sequence.has_value()) { + message_len += ParameterLen( + static_cast<uint64_t>(MoqtTrackRequestParameter::kObjectSequence), 1); + } + if (message.authorization_info.has_value()) { + message_len += ParameterLen( + static_cast<uint64_t>(MoqtTrackRequestParameter::kAuthorizationInfo), + message.authorization_info->length()); + } + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kObject)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62( + static_cast<uint64_t>(MoqtMessageType::kSubscribeRequest)); + writer.WriteVarInt62(message_len); + writer.WriteStringPieceVarInt62(message.full_track_name); + if (message.group_sequence.has_value()) { + WriteIntParameter( + writer, + static_cast<uint64_t>(MoqtTrackRequestParameter::kGroupSequence), + message.group_sequence.value()); + } + if (message.object_sequence.has_value()) { + WriteIntParameter( + writer, + static_cast<uint64_t>(MoqtTrackRequestParameter::kObjectSequence), + message.object_sequence.value()); + } + if (message.authorization_info.has_value()) { + WriteStringParameter( + writer, + static_cast<uint64_t>(MoqtTrackRequestParameter::kAuthorizationInfo), + message.authorization_info.value()); + } + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeSubscribeOk( + const MoqtSubscribeOk& message) { + size_t message_len = NeededVarIntLen(message.full_track_name.length()) + + message.full_track_name.length() + + NeededVarIntLen(message.track_id) + + NeededVarIntLen(message.expires.ToMilliseconds()); + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kSubscribeOk)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kSubscribeOk)); + writer.WriteVarInt62(message_len); + writer.WriteStringPieceVarInt62(message.full_track_name); + writer.WriteVarInt62(message.track_id); + writer.WriteVarInt62(message.expires.ToMilliseconds()); + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeSubscribeError( + const MoqtSubscribeError& message) { + size_t message_len = NeededVarIntLen(message.full_track_name.length()) + + message.full_track_name.length() + + NeededVarIntLen(message.error_code) + + NeededVarIntLen(message.reason_phrase.length()) + + message.reason_phrase.length(); + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kSubscribeError)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kSubscribeError)); + writer.WriteVarInt62(message_len); + writer.WriteStringPieceVarInt62(message.full_track_name); + writer.WriteVarInt62(message.error_code); + writer.WriteStringPieceVarInt62(message.reason_phrase); + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeAnnounce( + const MoqtAnnounce& message) { + size_t message_len = NeededVarIntLen(message.track_namespace.length()) + + message.track_namespace.length(); + if (message.authorization_info.has_value()) { + message_len += ParameterLen( + static_cast<uint64_t>(MoqtTrackRequestParameter::kAuthorizationInfo), + message.authorization_info->length()); + } + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kAnnounce)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kAnnounce)); + writer.WriteVarInt62(message_len); + writer.WriteStringPieceVarInt62(message.track_namespace); + if (message.authorization_info.has_value()) { + WriteStringParameter( + writer, + static_cast<uint64_t>(MoqtTrackRequestParameter::kAuthorizationInfo), + message.authorization_info.value()); + } + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeAnnounceOk( + const MoqtAnnounceOk& message) { + size_t message_len = message.track_namespace.length(); + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kAnnounceOk)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kAnnounceOk)); + writer.WriteVarInt62(message_len); + writer.WriteStringPiece(message.track_namespace); + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeAnnounceError( + const MoqtAnnounceError& message) { + size_t message_len = NeededVarIntLen(message.track_namespace.length()) + + message.track_namespace.length() + + NeededVarIntLen(message.error_code) + + NeededVarIntLen(message.reason_phrase.length()) + + message.reason_phrase.length(); + size_t buffer_size = + message_len + + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kAnnounceError)) + + NeededVarIntLen(message_len); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kAnnounceError)); + writer.WriteVarInt62(message_len); + writer.WriteStringPieceVarInt62(message.track_namespace); + writer.WriteVarInt62(message.error_code); + writer.WriteStringPieceVarInt62(message.reason_phrase); + return buffer; +} + +quiche::QuicheBuffer MoqtFramer::SerializeGoAway() { + size_t buffer_size = + NeededVarIntLen(static_cast<uint64_t>(MoqtMessageType::kGoAway)) + + NeededVarIntLen(0); + quiche::QuicheBuffer buffer(allocator_, buffer_size); + quic::QuicDataWriter writer(buffer.size(), buffer.data()); + writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kGoAway)); + writer.WriteVarInt62(0); + return buffer; +} + +} // namespace moqt
diff --git a/quiche/quic/moqt/moqt_framer.h b/quiche/quic/moqt/moqt_framer.h new file mode 100644 index 0000000..ba194a6 --- /dev/null +++ b/quiche/quic/moqt/moqt_framer.h
@@ -0,0 +1,65 @@ +// Copyright (c) 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_MOQT_MOQT_FRAMER_H_ +#define QUICHE_QUIC_MOQT_MOQT_FRAMER_H_ + +#include <cstddef> + +#include "absl/strings/string_view.h" +#include "quiche/quic/core/quic_types.h" +#include "quiche/quic/moqt/moqt_messages.h" +#include "quiche/common/platform/api/quiche_export.h" +#include "quiche/common/quiche_buffer_allocator.h" + +namespace moqt { + +// Serialize structured message data into a wire image. When the message format +// is different per |perspective| or |using_webtrans|, it will omit unnecessary +// fields. However, it does not enforce the presence of parameters that are +// required for a particular mode. +// +// There can be one instance of this per session. This framer does not enforce +// that these Serialize() calls are made in a logical order, as they can be on +// different streams. +class QUICHE_EXPORT MoqtFramer { + public: + MoqtFramer(quiche::QuicheBufferAllocator* allocator, + quic::Perspective perspective, bool using_webtrans) + : allocator_(allocator), + perspective_(perspective), + using_webtrans_(using_webtrans) {} + + // Serialize functions. Takes structured data and serializes it into a + // QuicheBuffer for delivery to the stream. + + // SerializeObject also takes a payload. |known_payload_size| is used in + // encoding the message length. If zero, the message length as also encoded as + // zero to indicate the message ends with the stream. If nonzero, and too + // small to fit the varints and the provided payload, returns an empty buffer. + quiche::QuicheBuffer SerializeObject(const MoqtObject& message, + absl::string_view payload, + size_t known_payload_size); + // Build a buffer for additional payload data. + quiche::QuicheBuffer SerializeObjectPayload(absl::string_view payload); + quiche::QuicheBuffer SerializeSetup(const MoqtSetup& message); + quiche::QuicheBuffer SerializeSubscribeRequest( + const MoqtSubscribeRequest& message); + quiche::QuicheBuffer SerializeSubscribeOk(const MoqtSubscribeOk& message); + quiche::QuicheBuffer SerializeSubscribeError( + const MoqtSubscribeError& message); + quiche::QuicheBuffer SerializeAnnounce(const MoqtAnnounce& message); + quiche::QuicheBuffer SerializeAnnounceOk(const MoqtAnnounceOk& message); + quiche::QuicheBuffer SerializeAnnounceError(const MoqtAnnounceError& message); + quiche::QuicheBuffer SerializeGoAway(); + + private: + quiche::QuicheBufferAllocator* allocator_; + quic::Perspective perspective_; + bool using_webtrans_; +}; + +} // namespace moqt + +#endif // QUICHE_QUIC_MOQT_MOQT_FRAMER_H_
diff --git a/quiche/quic/moqt/moqt_framer_test.cc b/quiche/quic/moqt/moqt_framer_test.cc new file mode 100644 index 0000000..dd3cad4 --- /dev/null +++ b/quiche/quic/moqt/moqt_framer_test.cc
@@ -0,0 +1,170 @@ +// Copyright (c) 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "quiche/quic/moqt/moqt_framer.h" + +#include <memory> +#include <string> +#include <vector> + +#include "quiche/quic/core/quic_types.h" +#include "quiche/quic/moqt/moqt_messages.h" +#include "quiche/quic/moqt/test_tools/moqt_test_message.h" +#include "quiche/quic/platform/api/quic_test.h" +#include "quiche/common/quiche_buffer_allocator.h" +#include "quiche/common/simple_buffer_allocator.h" + +namespace moqt::test { + +struct MoqtFramerTestParams { + MoqtFramerTestParams(MoqtMessageType message_type, + quic::Perspective perspective, bool uses_web_transport) + : message_type(message_type), + perspective(perspective), + uses_web_transport(uses_web_transport) {} + MoqtMessageType message_type; + quic::Perspective perspective; + bool uses_web_transport; +}; + +std::vector<MoqtFramerTestParams> GetMoqtFramerTestParams() { + std::vector<MoqtFramerTestParams> params; + std::vector<MoqtMessageType> message_types = { + MoqtMessageType::kObject, MoqtMessageType::kSetup, + MoqtMessageType::kSubscribeRequest, MoqtMessageType::kSubscribeOk, + MoqtMessageType::kSubscribeError, MoqtMessageType::kAnnounce, + MoqtMessageType::kAnnounceOk, MoqtMessageType::kAnnounceError, + MoqtMessageType::kGoAway, + }; + std::vector<quic::Perspective> perspectives = { + quic::Perspective::IS_SERVER, + quic::Perspective::IS_CLIENT, + }; + std::vector<bool> uses_web_transport_bool = { + false, + true, + }; + for (const MoqtMessageType message_type : message_types) { + if (message_type == MoqtMessageType::kSetup) { + for (const quic::Perspective perspective : perspectives) { + for (const bool uses_web_transport : uses_web_transport_bool) { + params.push_back(MoqtFramerTestParams(message_type, perspective, + uses_web_transport)); + } + } + } else { + // All other types are processed the same for either perspective or + // transport. + params.push_back(MoqtFramerTestParams( + message_type, quic::Perspective::IS_SERVER, true)); + } + } + return params; +} + +std::string ParamNameFormatter( + const testing::TestParamInfo<MoqtFramerTestParams>& info) { + return MoqtMessageTypeToString(info.param.message_type) + "_" + + (info.param.perspective == quic::Perspective::IS_SERVER ? "Server" + : "Client") + + "_" + (info.param.uses_web_transport ? "WebTransport" : "QUIC"); +} + +class MoqtFramerTest + : public quic::test::QuicTestWithParam<MoqtFramerTestParams> { + public: + MoqtFramerTest() + : message_type_(GetParam().message_type), + is_client_(GetParam().perspective == quic::Perspective::IS_CLIENT), + webtrans_(GetParam().uses_web_transport), + buffer_allocator_(quiche::SimpleBufferAllocator::Get()), + framer_(buffer_allocator_, GetParam().perspective, + GetParam().uses_web_transport) {} + + std::unique_ptr<TestMessageBase> MakeMessage(MoqtMessageType message_type) { + switch (message_type) { + case MoqtMessageType::kObject: + return std::make_unique<ObjectMessage>(); + case MoqtMessageType::kSetup: + return std::make_unique<SetupMessage>(!is_client_, webtrans_); + case MoqtMessageType::kSubscribeRequest: + return std::make_unique<SubscribeRequestMessage>(); + case MoqtMessageType::kSubscribeOk: + return std::make_unique<SubscribeOkMessage>(); + case MoqtMessageType::kSubscribeError: + return std::make_unique<SubscribeErrorMessage>(); + case MoqtMessageType::kAnnounce: + return std::make_unique<AnnounceMessage>(); + case moqt::MoqtMessageType::kAnnounceOk: + return std::make_unique<AnnounceOkMessage>(); + case moqt::MoqtMessageType::kAnnounceError: + return std::make_unique<AnnounceErrorMessage>(); + case moqt::MoqtMessageType::kGoAway: + return std::make_unique<GoAwayMessage>(); + default: + return nullptr; + } + } + + quiche::QuicheBuffer SerializeMessage( + TestMessageBase::MessageStructuredData& structured_data) { + switch (message_type_) { + case MoqtMessageType::kObject: { + auto data = std::get<MoqtObject>(structured_data); + return framer_.SerializeObject(data, "foo", 3); + } + case MoqtMessageType::kSetup: { + auto data = std::get<MoqtSetup>(structured_data); + return framer_.SerializeSetup(data); + } + case MoqtMessageType::kSubscribeRequest: { + auto data = std::get<MoqtSubscribeRequest>(structured_data); + return framer_.SerializeSubscribeRequest(data); + } + case MoqtMessageType::kSubscribeOk: { + auto data = std::get<MoqtSubscribeOk>(structured_data); + return framer_.SerializeSubscribeOk(data); + } + case MoqtMessageType::kSubscribeError: { + auto data = std::get<MoqtSubscribeError>(structured_data); + return framer_.SerializeSubscribeError(data); + } + case MoqtMessageType::kAnnounce: { + auto data = std::get<MoqtAnnounce>(structured_data); + return framer_.SerializeAnnounce(data); + } + case moqt::MoqtMessageType::kAnnounceOk: { + auto data = std::get<MoqtAnnounceOk>(structured_data); + return framer_.SerializeAnnounceOk(data); + } + case moqt::MoqtMessageType::kAnnounceError: { + auto data = std::get<MoqtAnnounceError>(structured_data); + return framer_.SerializeAnnounceError(data); + } + case moqt::MoqtMessageType::kGoAway: { + return framer_.SerializeGoAway(); + } + } + } + + MoqtMessageType message_type_; + bool is_client_; + bool webtrans_; + quiche::SimpleBufferAllocator* buffer_allocator_; + MoqtFramer framer_; +}; + +INSTANTIATE_TEST_SUITE_P(MoqtFramerTests, MoqtFramerTest, + testing::ValuesIn(GetMoqtFramerTestParams()), + ParamNameFormatter); + +TEST_P(MoqtFramerTest, OneMessage) { + auto message = MakeMessage(message_type_); + auto structured_data = message->structured_data(); + auto buffer = SerializeMessage(structured_data); + EXPECT_EQ(buffer.size(), message->total_message_size()); + EXPECT_EQ(buffer.AsStringView(), message->PacketSample()); +} + +} // namespace moqt::test
diff --git a/quiche/quic/moqt/test_tools/moqt_test_message.h b/quiche/quic/moqt/test_tools/moqt_test_message.h index aa4c8c0..5d1ac90 100644 --- a/quiche/quic/moqt/test_tools/moqt_test_message.h +++ b/quiche/quic/moqt/test_tools/moqt_test_message.h
@@ -63,6 +63,9 @@ wire_image_size_ = wire_image_size; } + // Returns a copy of the structured data for the message. + virtual MessageStructuredData structured_data() const = 0; + // Sets the message length field. If |message_size| == 0, just change the // field in the wire image. If another value, this will either truncate the // message or increase its length (which adds uninitialized bytes). This can @@ -194,6 +197,10 @@ ExpandVarintsImpl("vvvvvv"); // first six fields are varints } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(object_); + } + private: uint8_t raw_packet_[9] = { 0x00, 0x07, 0x04, 0x05, 0x06, 0x07, // varints @@ -257,6 +264,13 @@ } } + MessageStructuredData structured_data() const override { + if (client_) { + return TestMessageBase::MessageStructuredData(server_setup_); + } + return TestMessageBase::MessageStructuredData(client_setup_); + } + private: bool client_; uint8_t client_raw_packet_[13] = { @@ -312,6 +326,10 @@ void ExpandVarints() override { ExpandVarintsImpl("vvv---vv-vv-vv"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(subscribe_request_); + } + private: uint8_t raw_packet_[17] = { 0x03, 0x0f, 0x03, 0x66, 0x6f, 0x6f, // track_name = "foo" @@ -350,6 +368,10 @@ void ExpandVarints() override { ExpandVarintsImpl("vvv---vv"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(subscribe_ok_); + } + private: uint8_t raw_packet_[8] = { 0x04, 0x06, 0x03, 0x66, 0x6f, 0x6f, // track_name = "foo" @@ -389,6 +411,10 @@ void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(subscribe_error_); + } + private: uint8_t raw_packet_[11] = { 0x05, 0x09, 0x03, 0x66, 0x6f, 0x6f, // track_name = "foo" @@ -424,6 +450,10 @@ void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(announce_); + } + private: uint8_t raw_packet_[11] = { 0x06, 0x09, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo" @@ -453,6 +483,10 @@ void ExpandVarints() override { ExpandVarintsImpl("vv---"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(announce_ok_); + } + private: uint8_t raw_packet_[5] = { 0x07, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo" @@ -488,6 +522,10 @@ void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(announce_error_); + } + private: uint8_t raw_packet_[11] = { 0x08, 0x09, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo" @@ -514,11 +552,17 @@ void ExpandVarints() override { ExpandVarintsImpl("vv"); } + MessageStructuredData structured_data() const override { + return TestMessageBase::MessageStructuredData(goaway_); + } + private: uint8_t raw_packet_[2] = { 0x10, 0x00, }; + + MoqtGoAway goaway_ = {}; }; } // namespace moqt::test