Add length field to MoQT control messages.
PiperOrigin-RevId: 683174788
diff --git a/quiche/quic/moqt/moqt_framer.cc b/quiche/quic/moqt/moqt_framer.cc
index 074c2be..308a184 100644
--- a/quiche/quic/moqt/moqt_framer.cc
+++ b/quiche/quic/moqt/moqt_framer.cc
@@ -214,6 +214,31 @@
return *std::move(buffer);
}
+// Serializes data into buffer using the default allocator. Invokes QUICHE_BUG
+// on failure.
+template <typename... Ts>
+QuicheBuffer SerializeControlMessage(MoqtMessageType type, Ts... data) {
+ uint64_t message_type = static_cast<uint64_t>(type);
+ size_t payload_size = quiche::ComputeLengthOnWire(data...);
+ size_t buffer_size =
+ payload_size + quiche::ComputeLengthOnWire(WireVarInt62(message_type),
+ WireVarInt62(payload_size));
+ if (buffer_size == 0) {
+ return QuicheBuffer();
+ }
+
+ QuicheBuffer buffer(quiche::SimpleBufferAllocator::Get(), buffer_size);
+ quiche::QuicheDataWriter writer(buffer.size(), buffer.data());
+ absl::Status status = SerializeIntoWriter(
+ writer, WireVarInt62(message_type), WireVarInt62(payload_size), data...);
+ if (!status.ok() || writer.remaining() != 0) {
+ QUICHE_BUG(moqt_failed_serialization)
+ << "Failed to serialize MoQT frame: " << status;
+ return QuicheBuffer();
+ }
+ return buffer;
+}
+
WireUint8 WireDeliveryOrder(std::optional<MoqtDeliveryOrder> delivery_order) {
if (!delivery_order.has_value()) {
return WireUint8(0x00);
@@ -372,8 +397,8 @@
string_parameters.push_back(
StringParameter(MoqtSetupParameter::kPath, *message.path));
}
- return Serialize(
- WireVarInt62(MoqtMessageType::kClientSetup),
+ return SerializeControlMessage(
+ MoqtMessageType::kClientSetup,
WireVarInt62(message.supported_versions.size()),
WireSpan<WireVarInt62, MoqtVersion>(message.supported_versions),
WireVarInt62(string_parameters.size() + int_parameters.size()),
@@ -396,10 +421,10 @@
int_parameters.push_back(
IntParameter(MoqtSetupParameter::kSupportObjectAcks, 1u));
}
- return Serialize(WireVarInt62(MoqtMessageType::kServerSetup),
- WireVarInt62(message.selected_version),
- WireVarInt62(int_parameters.size()),
- WireSpan<WireIntParameter>(int_parameters));
+ return SerializeControlMessage(MoqtMessageType::kServerSetup,
+ WireVarInt62(message.selected_version),
+ WireVarInt62(int_parameters.size()),
+ WireSpan<WireIntParameter>(int_parameters));
}
quiche::QuicheBuffer MoqtFramer::SerializeSubscribe(
@@ -412,17 +437,17 @@
switch (filter_type) {
case MoqtFilterType::kLatestGroup:
case MoqtFilterType::kLatestObject:
- return Serialize(
- WireVarInt62(MoqtMessageType::kSubscribe),
- WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias),
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribe, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.track_alias),
WireFullTrackName(message.full_track_name, true),
WireUint8(message.subscriber_priority),
WireDeliveryOrder(message.group_order), WireVarInt62(filter_type),
WireSubscribeParameterList(message.parameters));
case MoqtFilterType::kAbsoluteStart:
- return Serialize(
- WireVarInt62(MoqtMessageType::kSubscribe),
- WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias),
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribe, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.track_alias),
WireFullTrackName(message.full_track_name, true),
WireUint8(message.subscriber_priority),
WireDeliveryOrder(message.group_order), WireVarInt62(filter_type),
@@ -430,9 +455,9 @@
WireVarInt62(*message.start_object),
WireSubscribeParameterList(message.parameters));
case MoqtFilterType::kAbsoluteRange:
- return Serialize(
- WireVarInt62(MoqtMessageType::kSubscribe),
- WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias),
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribe, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.track_alias),
WireFullTrackName(message.full_track_name, true),
WireUint8(message.subscriber_priority),
WireDeliveryOrder(message.group_order), WireVarInt62(filter_type),
@@ -454,49 +479,49 @@
<< "SUBSCRIBE_OK with delivery timeout";
}
if (message.largest_id.has_value()) {
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeOk),
- WireVarInt62(message.subscribe_id),
- WireVarInt62(message.expires.ToMilliseconds()),
- WireDeliveryOrder(message.group_order), WireUint8(1),
- WireVarInt62(message.largest_id->group),
- WireVarInt62(message.largest_id->object),
- WireSubscribeParameterList(message.parameters));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeOk, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.expires.ToMilliseconds()),
+ WireDeliveryOrder(message.group_order), WireUint8(1),
+ WireVarInt62(message.largest_id->group),
+ WireVarInt62(message.largest_id->object),
+ WireSubscribeParameterList(message.parameters));
}
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeOk),
- WireVarInt62(message.subscribe_id),
- WireVarInt62(message.expires.ToMilliseconds()),
- WireDeliveryOrder(message.group_order), WireUint8(0),
- WireSubscribeParameterList(message.parameters));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeOk, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.expires.ToMilliseconds()),
+ WireDeliveryOrder(message.group_order), WireUint8(0),
+ WireSubscribeParameterList(message.parameters));
}
quiche::QuicheBuffer MoqtFramer::SerializeSubscribeError(
const MoqtSubscribeError& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeError),
- WireVarInt62(message.subscribe_id),
- WireVarInt62(message.error_code),
- WireStringWithVarInt62Length(message.reason_phrase),
- WireVarInt62(message.track_alias));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeError, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.error_code),
+ WireStringWithVarInt62Length(message.reason_phrase),
+ WireVarInt62(message.track_alias));
}
quiche::QuicheBuffer MoqtFramer::SerializeUnsubscribe(
const MoqtUnsubscribe& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kUnsubscribe),
- WireVarInt62(message.subscribe_id));
+ return SerializeControlMessage(MoqtMessageType::kUnsubscribe,
+ WireVarInt62(message.subscribe_id));
}
quiche::QuicheBuffer MoqtFramer::SerializeSubscribeDone(
const MoqtSubscribeDone& message) {
if (message.final_id.has_value()) {
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeDone),
- WireVarInt62(message.subscribe_id),
- WireVarInt62(message.status_code),
- WireStringWithVarInt62Length(message.reason_phrase),
- WireUint8(1), WireVarInt62(message.final_id->group),
- WireVarInt62(message.final_id->object));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeDone, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.status_code),
+ WireStringWithVarInt62Length(message.reason_phrase), WireUint8(1),
+ WireVarInt62(message.final_id->group),
+ WireVarInt62(message.final_id->object));
}
- return Serialize(
- WireVarInt62(MoqtMessageType::kSubscribeDone),
- WireVarInt62(message.subscribe_id), WireVarInt62(message.status_code),
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeDone, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.status_code),
WireStringWithVarInt62Length(message.reason_phrase), WireUint8(0));
}
@@ -514,11 +539,11 @@
QUICHE_BUG(MoqtFramer_invalid_subscribe_update) << "Invalid object range";
return quiche::QuicheBuffer();
}
- return Serialize(
- WireVarInt62(MoqtMessageType::kSubscribeUpdate),
- WireVarInt62(message.subscribe_id), WireVarInt62(message.start_group),
- WireVarInt62(message.start_object), WireVarInt62(end_group),
- WireVarInt62(end_object), WireUint8(message.subscriber_priority),
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeUpdate, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.start_group), WireVarInt62(message.start_object),
+ WireVarInt62(end_group), WireVarInt62(end_object),
+ WireUint8(message.subscriber_priority),
WireSubscribeParameterList(message.parameters));
}
@@ -527,101 +552,110 @@
if (message.parameters.delivery_timeout.has_value()) {
QUICHE_BUG(MoqtFramer_invalid_announce) << "ANNOUNCE with delivery timeout";
}
- return Serialize(
- WireVarInt62(static_cast<uint64_t>(MoqtMessageType::kAnnounce)),
+ return SerializeControlMessage(
+ MoqtMessageType::kAnnounce,
WireFullTrackName(message.track_namespace, false),
WireSubscribeParameterList(message.parameters));
}
quiche::QuicheBuffer MoqtFramer::SerializeAnnounceOk(
const MoqtAnnounceOk& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kAnnounceOk),
- WireFullTrackName(message.track_namespace, false));
+ return SerializeControlMessage(
+ MoqtMessageType::kAnnounceOk,
+ WireFullTrackName(message.track_namespace, false));
}
quiche::QuicheBuffer MoqtFramer::SerializeAnnounceError(
const MoqtAnnounceError& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kAnnounceError),
- WireFullTrackName(message.track_namespace, false),
- WireVarInt62(message.error_code),
- WireStringWithVarInt62Length(message.reason_phrase));
+ return SerializeControlMessage(
+ MoqtMessageType::kAnnounceError,
+ WireFullTrackName(message.track_namespace, false),
+ WireVarInt62(message.error_code),
+ WireStringWithVarInt62Length(message.reason_phrase));
}
quiche::QuicheBuffer MoqtFramer::SerializeAnnounceCancel(
const MoqtAnnounceCancel& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kAnnounceCancel),
- WireFullTrackName(message.track_namespace, false),
- WireVarInt62(message.error_code),
- WireStringWithVarInt62Length(message.reason_phrase));
+ return SerializeControlMessage(
+ MoqtMessageType::kAnnounceCancel,
+ WireFullTrackName(message.track_namespace, false),
+ WireVarInt62(message.error_code),
+ WireStringWithVarInt62Length(message.reason_phrase));
}
quiche::QuicheBuffer MoqtFramer::SerializeTrackStatusRequest(
const MoqtTrackStatusRequest& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kTrackStatusRequest),
- WireFullTrackName(message.full_track_name, true));
+ return SerializeControlMessage(
+ MoqtMessageType::kTrackStatusRequest,
+ WireFullTrackName(message.full_track_name, true));
}
quiche::QuicheBuffer MoqtFramer::SerializeUnannounce(
const MoqtUnannounce& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kUnannounce),
- WireFullTrackName(message.track_namespace, false));
+ return SerializeControlMessage(
+ MoqtMessageType::kUnannounce,
+ WireFullTrackName(message.track_namespace, false));
}
quiche::QuicheBuffer MoqtFramer::SerializeTrackStatus(
const MoqtTrackStatus& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kTrackStatus),
- WireFullTrackName(message.full_track_name, true),
- WireVarInt62(message.status_code),
- WireVarInt62(message.last_group),
- WireVarInt62(message.last_object));
+ return SerializeControlMessage(
+ MoqtMessageType::kTrackStatus,
+ WireFullTrackName(message.full_track_name, true),
+ WireVarInt62(message.status_code), WireVarInt62(message.last_group),
+ WireVarInt62(message.last_object));
}
quiche::QuicheBuffer MoqtFramer::SerializeGoAway(const MoqtGoAway& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kGoAway),
- WireStringWithVarInt62Length(message.new_session_uri));
+ return SerializeControlMessage(
+ MoqtMessageType::kGoAway,
+ WireStringWithVarInt62Length(message.new_session_uri));
}
quiche::QuicheBuffer MoqtFramer::SerializeSubscribeNamespace(
const MoqtSubscribeNamespace& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeNamespace),
- WireFullTrackName(message.track_namespace, false),
- WireSubscribeParameterList(message.parameters));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeNamespace,
+ WireFullTrackName(message.track_namespace, false),
+ WireSubscribeParameterList(message.parameters));
}
quiche::QuicheBuffer MoqtFramer::SerializeSubscribeNamespaceOk(
const MoqtSubscribeNamespaceOk& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeNamespaceOk),
- WireFullTrackName(message.track_namespace, false));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeNamespaceOk,
+ WireFullTrackName(message.track_namespace, false));
}
quiche::QuicheBuffer MoqtFramer::SerializeSubscribeNamespaceError(
const MoqtSubscribeNamespaceError& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kSubscribeNamespaceError),
- WireFullTrackName(message.track_namespace, false),
- WireVarInt62(message.error_code),
- WireStringWithVarInt62Length(message.reason_phrase));
+ return SerializeControlMessage(
+ MoqtMessageType::kSubscribeNamespaceError,
+ WireFullTrackName(message.track_namespace, false),
+ WireVarInt62(message.error_code),
+ WireStringWithVarInt62Length(message.reason_phrase));
}
quiche::QuicheBuffer MoqtFramer::SerializeUnsubscribeNamespace(
const MoqtUnsubscribeNamespace& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kUnsubscribeNamespace),
- WireFullTrackName(message.track_namespace, false));
+ return SerializeControlMessage(
+ MoqtMessageType::kUnsubscribeNamespace,
+ WireFullTrackName(message.track_namespace, false));
}
quiche::QuicheBuffer MoqtFramer::SerializeMaxSubscribeId(
const MoqtMaxSubscribeId& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kMaxSubscribeId),
- WireVarInt62(message.max_subscribe_id));
+ return SerializeControlMessage(MoqtMessageType::kMaxSubscribeId,
+ WireVarInt62(message.max_subscribe_id));
}
quiche::QuicheBuffer MoqtFramer::SerializeObjectAck(
const MoqtObjectAck& message) {
- return Serialize(WireVarInt62(MoqtMessageType::kObjectAck),
- WireVarInt62(message.subscribe_id),
- WireVarInt62(message.group_id),
- WireVarInt62(message.object_id),
- WireVarInt62(SignedVarintSerializedForm(
- message.delta_from_deadline.ToMicroseconds())));
+ return SerializeControlMessage(
+ MoqtMessageType::kObjectAck, WireVarInt62(message.subscribe_id),
+ WireVarInt62(message.group_id), WireVarInt62(message.object_id),
+ WireVarInt62(SignedVarintSerializedForm(
+ message.delta_from_deadline.ToMicroseconds())));
}
// static
diff --git a/quiche/quic/moqt/moqt_framer_test.cc b/quiche/quic/moqt/moqt_framer_test.cc
index 5ed05c1..2446a8f 100644
--- a/quiche/quic/moqt/moqt_framer_test.cc
+++ b/quiche/quic/moqt/moqt_framer_test.cc
@@ -409,7 +409,7 @@
}
buffer = framer_.SerializeSubscribe(subscribe);
// Go to the filter type.
- const uint8_t* read = BufferAtOffset(buffer, 15);
+ const uint8_t* read = BufferAtOffset(buffer, 16);
EXPECT_EQ(static_cast<MoqtFilterType>(*read), expected_filter_type);
EXPECT_GT(buffer.size(), 0);
if (expected_filter_type == MoqtFilterType::kAbsoluteRange &&
@@ -480,7 +480,7 @@
quiche::QuicheBuffer buffer;
buffer = framer_.SerializeSubscribeUpdate(subscribe_update);
EXPECT_GT(buffer.size(), 0);
- const uint8_t* end_group = BufferAtOffset(buffer, 4);
+ const uint8_t* end_group = BufferAtOffset(buffer, 5);
EXPECT_EQ(*end_group, 5);
const uint8_t* end_object = end_group + 1;
EXPECT_EQ(*end_object, 0);
@@ -500,7 +500,7 @@
quiche::QuicheBuffer buffer;
buffer = framer_.SerializeSubscribeUpdate(subscribe_update);
EXPECT_GT(buffer.size(), 0);
- const uint8_t* end_group = BufferAtOffset(buffer, 4);
+ const uint8_t* end_group = BufferAtOffset(buffer, 5);
EXPECT_EQ(*end_group, 5);
const uint8_t* end_object = end_group + 1;
EXPECT_EQ(*end_object, 7);
diff --git a/quiche/quic/moqt/moqt_parser.cc b/quiche/quic/moqt/moqt_parser.cc
index 2140748..9fea89c 100644
--- a/quiche/quic/moqt/moqt_parser.cc
+++ b/quiche/quic/moqt/moqt_parser.cc
@@ -189,61 +189,94 @@
}
size_t MoqtControlParser::ProcessMessage(absl::string_view data) {
- uint64_t value;
+ uint64_t value, length;
quic::QuicDataReader reader(data);
- if (!reader.ReadVarInt62(&value)) {
+ if (!reader.ReadVarInt62(&value) || !reader.ReadVarInt62(&length)) {
+ return 0;
+ }
+ if (length > reader.BytesRemaining()) {
return 0;
}
auto type = static_cast<MoqtMessageType>(value);
+ size_t message_header_length = reader.PreviouslyReadPayload().length();
+ size_t bytes_read;
switch (type) {
case MoqtMessageType::kClientSetup:
- return ProcessClientSetup(reader);
+ bytes_read = ProcessClientSetup(reader);
+ break;
case MoqtMessageType::kServerSetup:
- return ProcessServerSetup(reader);
+ bytes_read = ProcessServerSetup(reader);
+ break;
case MoqtMessageType::kSubscribe:
- return ProcessSubscribe(reader);
+ bytes_read = ProcessSubscribe(reader);
+ break;
case MoqtMessageType::kSubscribeOk:
- return ProcessSubscribeOk(reader);
+ bytes_read = ProcessSubscribeOk(reader);
+ break;
case MoqtMessageType::kSubscribeError:
- return ProcessSubscribeError(reader);
+ bytes_read = ProcessSubscribeError(reader);
+ break;
case MoqtMessageType::kUnsubscribe:
- return ProcessUnsubscribe(reader);
+ bytes_read = ProcessUnsubscribe(reader);
+ break;
case MoqtMessageType::kSubscribeDone:
- return ProcessSubscribeDone(reader);
+ bytes_read = ProcessSubscribeDone(reader);
+ break;
case MoqtMessageType::kSubscribeUpdate:
- return ProcessSubscribeUpdate(reader);
+ bytes_read = ProcessSubscribeUpdate(reader);
+ break;
case MoqtMessageType::kAnnounce:
- return ProcessAnnounce(reader);
+ bytes_read = ProcessAnnounce(reader);
+ break;
case MoqtMessageType::kAnnounceOk:
- return ProcessAnnounceOk(reader);
+ bytes_read = ProcessAnnounceOk(reader);
+ break;
case MoqtMessageType::kAnnounceError:
- return ProcessAnnounceError(reader);
+ bytes_read = ProcessAnnounceError(reader);
+ break;
case MoqtMessageType::kAnnounceCancel:
- return ProcessAnnounceCancel(reader);
+ bytes_read = ProcessAnnounceCancel(reader);
+ break;
case MoqtMessageType::kTrackStatusRequest:
- return ProcessTrackStatusRequest(reader);
+ bytes_read = ProcessTrackStatusRequest(reader);
+ break;
case MoqtMessageType::kUnannounce:
- return ProcessUnannounce(reader);
+ bytes_read = ProcessUnannounce(reader);
+ break;
case MoqtMessageType::kTrackStatus:
- return ProcessTrackStatus(reader);
+ bytes_read = ProcessTrackStatus(reader);
+ break;
case MoqtMessageType::kGoAway:
- return ProcessGoAway(reader);
+ bytes_read = ProcessGoAway(reader);
+ break;
case MoqtMessageType::kSubscribeNamespace:
- return ProcessSubscribeNamespace(reader);
+ bytes_read = ProcessSubscribeNamespace(reader);
+ break;
case MoqtMessageType::kSubscribeNamespaceOk:
- return ProcessSubscribeNamespaceOk(reader);
+ bytes_read = ProcessSubscribeNamespaceOk(reader);
+ break;
case MoqtMessageType::kSubscribeNamespaceError:
- return ProcessSubscribeNamespaceError(reader);
+ bytes_read = ProcessSubscribeNamespaceError(reader);
+ break;
case MoqtMessageType::kUnsubscribeNamespace:
- return ProcessUnsubscribeNamespace(reader);
+ bytes_read = ProcessUnsubscribeNamespace(reader);
+ break;
case MoqtMessageType::kMaxSubscribeId:
- return ProcessMaxSubscribeId(reader);
+ bytes_read = ProcessMaxSubscribeId(reader);
+ break;
case moqt::MoqtMessageType::kObjectAck:
- return ProcessObjectAck(reader);
+ bytes_read = ProcessObjectAck(reader);
+ break;
default:
ParseError("Unknown message type");
+ bytes_read = 0;
+ break;
}
- return 0;
+ if ((bytes_read - message_header_length) != length) {
+ ParseError("Message length does not match payload length");
+ return 0;
+ }
+ return bytes_read;
}
size_t MoqtControlParser::ProcessClientSetup(quic::QuicDataReader& reader) {
diff --git a/quiche/quic/moqt/moqt_parser_test.cc b/quiche/quic/moqt/moqt_parser_test.cc
index 5c1d028..4cb7c3c 100644
--- a/quiche/quic/moqt/moqt_parser_test.cc
+++ b/quiche/quic/moqt/moqt_parser_test.cc
@@ -375,6 +375,31 @@
EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
}
+TEST_P(MoqtParserTest, PayloadLengthTooLong) {
+ if (IsDataStream()) {
+ return;
+ }
+ std::unique_ptr<TestMessageBase> message = MakeMessage();
+ message->IncreasePayloadLengthByOne();
+ ProcessData(message->PacketSample(), false);
+ // The parser will actually report a message, because it's all there.
+ EXPECT_EQ(visitor_.messages_received_, 1);
+ EXPECT_EQ(visitor_.parsing_error_,
+ "Message length does not match payload length");
+}
+
+TEST_P(MoqtParserTest, PayloadLengthTooShort) {
+ if (IsDataStream()) {
+ return;
+ }
+ std::unique_ptr<TestMessageBase> message = MakeMessage();
+ message->DecreasePayloadLengthByOne();
+ ProcessData(message->PacketSample(), false);
+ EXPECT_EQ(visitor_.messages_received_, 1);
+ EXPECT_EQ(visitor_.parsing_error_,
+ "Message length does not match payload length");
+}
+
// Tests for message-specific error cases, and behaviors for a single message
// type.
class MoqtMessageSpecificTest : public quic::test::QuicTest {
@@ -491,10 +516,10 @@
TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsInvalid) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions
- 0x03, // 3 params
- 0x00, 0x01, 0x04, // role = invalid
- 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
+ 0x40, 0x40, 0x0c, 0x02, 0x01, 0x02, // versions
+ 0x03, // 3 params
+ 0x00, 0x01, 0x04, // role = invalid
+ 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -506,7 +531,7 @@
TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsInvalid) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x41, 0x01,
+ 0x40, 0x41, 0x0a, 0x01,
0x01, // 1 param
0x00, 0x01, 0x04, // role = invalid
0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
@@ -521,11 +546,11 @@
TEST_F(MoqtMessageSpecificTest, SetupRoleAppearsTwice) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions
- 0x03, // 3 params
- 0x00, 0x01, 0x03, // role = PubSub
- 0x00, 0x01, 0x03, // role = PubSub
- 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
+ 0x40, 0x40, 0x0f, 0x02, 0x01, 0x02, // versions
+ 0x03, // 3 params
+ 0x00, 0x01, 0x03, // role = PubSub
+ 0x00, 0x01, 0x03, // role = PubSub
+ 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -537,9 +562,9 @@
TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsMissing) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
- 0x01, // 1 param
- 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
+ 0x40, 0x40, 0x09, 0x02, 0x01, 0x02, // versions = 1, 2
+ 0x01, // 1 param
+ 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -552,12 +577,12 @@
TEST_F(MoqtMessageSpecificTest, ClientSetupMaxSubscribeIdAppearsTwice) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions
- 0x04, // 4 params
- 0x00, 0x01, 0x03, // role = PubSub
- 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
- 0x02, 0x01, 0x32, // max_subscribe_id = 50
- 0x02, 0x01, 0x32, // max_subscribe_id = 50
+ 0x40, 0x40, 0x12, 0x02, 0x01, 0x02, // versions
+ 0x04, // 4 params
+ 0x00, 0x01, 0x03, // role = PubSub
+ 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
+ 0x02, 0x01, 0x32, // max_subscribe_id = 50
+ 0x02, 0x01, 0x32, // max_subscribe_id = 50
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -570,7 +595,7 @@
TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsMissing) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x41, 0x01, 0x00, // 1 param
+ 0x40, 0x41, 0x02, 0x01, 0x00, // 1 param
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -583,7 +608,7 @@
TEST_F(MoqtMessageSpecificTest, SetupRoleVarintLengthIsWrong) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, // type
+ 0x40, 0x40, 0x0c, // type
0x02, 0x01, 0x02, // versions
0x02, // 2 parameters
0x00, 0x02, 0x03, // role = PubSub, but length is 2
@@ -601,7 +626,7 @@
TEST_F(MoqtMessageSpecificTest, SetupPathFromServer) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x41,
+ 0x40, 0x41, 0x07,
0x01, // version = 1
0x01, // 1 param
0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
@@ -616,11 +641,11 @@
TEST_F(MoqtMessageSpecificTest, SetupPathAppearsTwice) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
- 0x03, // 3 params
- 0x00, 0x01, 0x03, // role = PubSub
- 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
- 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
+ 0x40, 0x40, 0x11, 0x02, 0x01, 0x02, // versions = 1, 2
+ 0x03, // 3 params
+ 0x00, 0x01, 0x03, // role = PubSub
+ 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
+ 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -633,10 +658,10 @@
TEST_F(MoqtMessageSpecificTest, SetupPathOverWebtrans) {
MoqtControlParser parser(kWebTrans, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
- 0x02, // 2 params
- 0x00, 0x01, 0x03, // role = PubSub
- 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
+ 0x40, 0x40, 0x0b, 0x02, 0x01, 0x02, // versions = 1, 2
+ 0x02, // 2 params
+ 0x00, 0x01, 0x03, // role = PubSub
+ 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -649,9 +674,9 @@
TEST_F(MoqtMessageSpecificTest, SetupPathMissing) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
- 0x01, // 1 param
- 0x00, 0x01, 0x03, // role = PubSub
+ 0x40, 0x40, 0x07, 0x02, 0x01, 0x02, // versions = 1, 2
+ 0x01, // 1 param
+ 0x00, 0x01, 0x03, // role = PubSub
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -664,12 +689,12 @@
TEST_F(MoqtMessageSpecificTest, ServerSetupMaxSubscribeIdAppearsTwice) {
MoqtControlParser parser(kRawQuic, visitor_);
char setup[] = {
- 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
- 0x04, // 4 params
- 0x00, 0x01, 0x03, // role = PubSub
- 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
- 0x02, 0x01, 0x32, // max_subscribe_id = 50
- 0x02, 0x01, 0x32, // max_subscribe_id = 50
+ 0x40, 0x40, 0x12, 0x02, 0x01, 0x02, // versions = 1, 2
+ 0x04, // 4 params
+ 0x00, 0x01, 0x03, // role = PubSub
+ 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
+ 0x02, 0x01, 0x32, // max_subscribe_id = 50
+ 0x02, 0x01, 0x32, // max_subscribe_id = 50
};
parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -682,8 +707,8 @@
TEST_F(MoqtMessageSpecificTest, SubscribeAuthorizationInfoTwice) {
MoqtControlParser parser(kWebTrans, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, 0x01, 0x03,
- 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x03, 0x1a, 0x01, 0x02, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
0x02, // filter_type = kLatestObject
@@ -701,8 +726,8 @@
TEST_F(MoqtMessageSpecificTest, SubscribeDeliveryTimeoutTwice) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, 0x01, 0x03,
- 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x03, 0x18, 0x01, 0x02, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
0x02, // filter_type = kLatestObject
@@ -720,8 +745,8 @@
TEST_F(MoqtMessageSpecificTest, SubscribeDeliveryTimeoutMalformed) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, 0x01, 0x03,
- 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x03, 0x14, 0x01, 0x02, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
0x02, // filter_type = kLatestObject
@@ -738,8 +763,8 @@
TEST_F(MoqtMessageSpecificTest, SubscribeMaxCacheDurationTwice) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, 0x01, 0x03,
- 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x03, 0x18, 0x01, 0x02, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
0x02, // filter_type = kLatestObject
@@ -757,8 +782,8 @@
TEST_F(MoqtMessageSpecificTest, SubscribeMaxCacheDurationMalformed) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, 0x01, 0x03,
- 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x03, 0x14, 0x01, 0x02, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
0x02, // filter_type = kLatestObject
@@ -775,7 +800,7 @@
TEST_F(MoqtMessageSpecificTest, SubscribeOkHasAuthorizationInfo) {
MoqtControlParser parser(kWebTrans, visitor_);
char subscribe_ok[] = {
- 0x04, 0x01, 0x03, // subscribe_id = 1, expires = 3
+ 0x04, 0x10, 0x01, 0x03, // subscribe_id = 1, expires = 3
0x02, 0x01, // group_order = 2, content exists
0x0c, 0x14, // largest_group_id = 12, largest_object_id = 20,
0x02, // 2 parameters
@@ -792,10 +817,10 @@
TEST_F(MoqtMessageSpecificTest, SubscribeUpdateHasAuthorizationInfo) {
MoqtControlParser parser(kWebTrans, visitor_);
char subscribe_update[] = {
- 0x02, 0x02, 0x03, 0x01, 0x05, 0x06, // start and end sequences
- 0xaa, // priority = 0xaa
- 0x01, // 1 parameter
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ 0x02, 0x0c, 0x02, 0x03, 0x01, 0x05, 0x06, // start and end sequences
+ 0xaa, // priority = 0xaa
+ 0x01, // 1 parameter
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
};
parser.ProcessData(
absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -807,10 +832,10 @@
TEST_F(MoqtMessageSpecificTest, AnnounceAuthorizationInfoTwice) {
MoqtControlParser parser(kWebTrans, visitor_);
char announce[] = {
- 0x06, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x02, // 2 params
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ 0x06, 0x10, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x02, // 2 params
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
};
parser.ProcessData(absl::string_view(announce, sizeof(announce)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -823,10 +848,10 @@
TEST_F(MoqtMessageSpecificTest, AnnounceHasDeliveryTimeout) {
MoqtControlParser parser(kWebTrans, visitor_);
char announce[] = {
- 0x06, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x02, // 2 params
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
- 0x03, 0x02, 0x67, 0x10, // delivery_timeout = 10000
+ 0x06, 0x0f, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x02, // 2 params
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ 0x03, 0x02, 0x67, 0x10, // delivery_timeout = 10000
};
parser.ProcessData(absl::string_view(announce, sizeof(announce)), false);
EXPECT_EQ(visitor_.messages_received_, 0);
@@ -888,6 +913,7 @@
char big_message[2 * kMaxMessageHeaderSize];
quic::QuicDataWriter writer(sizeof(big_message), big_message);
writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kServerSetup));
+ writer.WriteVarInt62(8 + kMaxMessageHeaderSize);
writer.WriteVarInt62(0x1); // version
writer.WriteVarInt62(0x1); // num_params
writer.WriteVarInt62(0xbeef); // unknown param
@@ -904,9 +930,11 @@
TEST_F(MoqtMessageSpecificTest, UnknownMessageType) {
MoqtControlParser parser(kRawQuic, visitor_);
- char message[4];
+ char message[6];
quic::QuicDataWriter writer(sizeof(message), message);
writer.WriteVarInt62(0xbeef); // unknown message type
+ writer.WriteVarInt62(0x1); // length
+ writer.WriteVarInt62(0x1); // payload
parser.ProcessData(absl::string_view(message, writer.length()), false);
EXPECT_EQ(visitor_.messages_received_, 0);
EXPECT_TRUE(visitor_.parsing_error_.has_value());
@@ -916,7 +944,7 @@
TEST_F(MoqtMessageSpecificTest, LatestGroup) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x15, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -938,10 +966,10 @@
TEST_F(MoqtMessageSpecificTest, LatestObject) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x15, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
- 0x20, 0x02, // priority = 0x20 descending
+ 0x20, 0x02, // priority = 0x20, group order descending
0x02, // filter_type = kLatestObject
0x01, // 1 parameter
0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
@@ -960,7 +988,7 @@
TEST_F(MoqtMessageSpecificTest, InvalidDeliveryOrder) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x15, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x08, // priority = 0x20 ???
@@ -976,7 +1004,7 @@
TEST_F(MoqtMessageSpecificTest, AbsoluteStart) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x17, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -1000,7 +1028,7 @@
TEST_F(MoqtMessageSpecificTest, AbsoluteRangeExplicitEndObject) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x19, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -1026,7 +1054,7 @@
TEST_F(MoqtMessageSpecificTest, AbsoluteRangeWholeEndGroup) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x19, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -1052,7 +1080,7 @@
TEST_F(MoqtMessageSpecificTest, AbsoluteRangeEndGroupTooLow) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x19, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -1073,7 +1101,7 @@
TEST_F(MoqtMessageSpecificTest, AbsoluteRangeExactlyOneObject) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x14, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -1091,9 +1119,9 @@
TEST_F(MoqtMessageSpecificTest, SubscribeUpdateExactlyOneObject) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe_update[] = {
- 0x02, 0x02, 0x03, 0x01, 0x04, 0x07, // start and end sequences
- 0x20, // priority
- 0x00, // No parameters
+ 0x02, 0x07, 0x02, 0x03, 0x01, 0x04, 0x07, // start and end sequences
+ 0x20, // priority
+ 0x00, // No parameters
};
parser.ProcessData(
absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1103,10 +1131,10 @@
TEST_F(MoqtMessageSpecificTest, SubscribeUpdateEndGroupTooLow) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe_update[] = {
- 0x02, 0x02, 0x03, 0x01, 0x03, 0x06, // start and end sequences
- 0x20, // priority
- 0x01, // 1 parameter
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ 0x02, 0x0c, 0x02, 0x03, 0x01, 0x03, 0x06, // start and end sequences
+ 0x20, // priority
+ 0x01, // 1 parameter
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
};
parser.ProcessData(
absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1118,7 +1146,7 @@
TEST_F(MoqtMessageSpecificTest, AbsoluteRangeEndObjectTooLow) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe[] = {
- 0x03, 0x01, 0x02, // id and alias
+ 0x03, 0x19, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, 0x02, // priority = 0x20 descending
@@ -1139,8 +1167,8 @@
TEST_F(MoqtMessageSpecificTest, SubscribeUpdateEndObjectTooLow) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe_update[] = {
- 0x02, 0x02, 0x03, 0x02, 0x04, 0x01, // start and end sequences
- 0xf0, 0x00, // priority, no parameter
+ 0x02, 0x07, 0x02, 0x03, 0x02, 0x04, 0x01, // start and end sequences
+ 0xf0, 0x00, // priority, no parameter
};
parser.ProcessData(
absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1152,9 +1180,9 @@
TEST_F(MoqtMessageSpecificTest, SubscribeUpdateNoEndGroup) {
MoqtControlParser parser(kRawQuic, visitor_);
char subscribe_update[] = {
- 0x02, 0x02, 0x03, 0x02, 0x00, 0x01, // start and end sequences
- 0x20, // priority
- 0x00, // No parameter
+ 0x02, 0x07, 0x02, 0x03, 0x02, 0x00, 0x01, // start and end sequences
+ 0x20, // priority
+ 0x00, // No parameter
};
parser.ProcessData(
absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1167,7 +1195,7 @@
TEST_F(MoqtMessageSpecificTest, ObjectAckNegativeDelta) {
MoqtControlParser parser(kRawQuic, visitor_);
char object_ack[] = {
- 0x71, 0x84, // type
+ 0x71, 0x84, 0x05, // type
0x01, 0x10, 0x20, // subscribe ID, group, object
0x40, 0x81, // -0x40 time delta
};
diff --git a/quiche/quic/moqt/test_tools/moqt_test_message.h b/quiche/quic/moqt/test_tools/moqt_test_message.h
index c694e8d..cc53381 100644
--- a/quiche/quic/moqt/test_tools/moqt_test_message.h
+++ b/quiche/quic/moqt/test_tools/moqt_test_message.h
@@ -63,6 +63,19 @@
// message has a different layout of varints.
virtual void ExpandVarints() = 0;
+ // This will cause a parsing error. Do not call this on Object Messages.
+ void DecreasePayloadLengthByOne() {
+ size_t length_offset =
+ 0x1 << ((static_cast<uint8_t>(wire_image_[0]) & 0xc0) >> 6);
+ wire_image_[length_offset]--;
+ }
+ void IncreasePayloadLengthByOne() {
+ size_t length_offset =
+ 0x1 << ((static_cast<uint8_t>(wire_image_[0]) & 0xc0) >> 6);
+ wire_image_[length_offset]++;
+ set_wire_image_size(wire_image_size_ + 1);
+ }
+
protected:
void SetWireImage(uint8_t* wire_image, size_t wire_image_size) {
memcpy(wire_image_, wire_image, wire_image_size);
@@ -74,13 +87,47 @@
// Each character in |varints| corresponds to a byte in the original message.
// If there is a 'v', it is a varint that should be expanded. If '-', skip
// to the next byte.
- void ExpandVarintsImpl(absl::string_view varints) {
+ // Always expand the message length field (if a control message) to 2 bytes,
+ // so it's a known length that is large enough to be safe. The second byte
+ // of |varints| does not matter.
+ void ExpandVarintsImpl(absl::string_view varints,
+ bool is_control_message = true) {
int next_varint_len = 2;
char new_wire_image[kMaxMessageHeaderSize + 1];
quic::QuicDataReader reader(
absl::string_view(wire_image_, wire_image_size_));
quic::QuicDataWriter writer(sizeof(new_wire_image), new_wire_image);
size_t i = 0;
+ size_t length_field = 0;
+ if (is_control_message) {
+ // the length will be a 16-bit varint.
+ bool nonvarint_type = false;
+ while (varints[i] == '-') {
+ ++i;
+ nonvarint_type = true;
+ uint8_t byte;
+ reader.ReadUInt8(&byte);
+ writer.WriteUInt8(byte);
+ }
+ uint64_t value;
+ if (!nonvarint_type) {
+ ++i;
+ reader.ReadVarInt62(&value);
+ writer.WriteVarInt62WithForcedLength(
+ value, static_cast<quiche::QuicheVariableLengthIntegerLength>(
+ next_varint_len));
+ next_varint_len *= 2;
+ if (next_varint_len == 16) {
+ next_varint_len = 2;
+ }
+ }
+ reader.ReadVarInt62(&value);
+ ++i;
+ length_field = writer.length();
+ // Write in current length as a 2B placeholder.
+ writer.WriteVarInt62WithForcedLength(
+ value, static_cast<quiche::QuicheVariableLengthIntegerLength>(2));
+ }
while (!reader.IsDoneReading()) {
if (i >= varints.length() || varints[i++] == '-') {
uint8_t byte;
@@ -100,6 +147,10 @@
}
memcpy(wire_image_, new_wire_image, writer.length());
wire_image_size_ = writer.length();
+ if (is_control_message) {
+ wire_image_[length_field + 1] =
+ static_cast<uint8_t>(writer.length() - length_field - 2);
+ }
}
private:
@@ -176,7 +227,7 @@
object_.forwarding_preference = MoqtForwardingPreference::kDatagram;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvvvv-v---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvvv-v---", false); }
private:
uint8_t raw_packet_[10] = {
@@ -196,7 +247,7 @@
object_.payload_length = 3;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv-vvv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvv-vvv", false); }
private:
// Some tests check that a FIN sent at the halfway point of a message results
@@ -222,7 +273,7 @@
object_.object_id = 10;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvv", false); }
private:
uint8_t raw_packet_[6] = {
@@ -239,7 +290,7 @@
object_.subgroup_id = 8;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvvvv-vv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvvv-vv", false); }
bool SetPayloadLength(uint8_t payload_length) {
if (payload_length > 63) {
@@ -271,7 +322,7 @@
object_.object_id = 9;
}
- void ExpandVarints() override { ExpandVarintsImpl("vv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vv", false); }
private:
uint8_t raw_packet_[5] = {
@@ -285,7 +336,8 @@
if (webtrans) {
// Should not send PATH.
client_setup_.path = std::nullopt;
- raw_packet_[5] = 0x02; // only two parameters
+ raw_packet_[2] = 0x0a; // adjust payload length (-5)
+ raw_packet_[6] = 0x02; // only two parameters
SetWireImage(raw_packet_, sizeof(raw_packet_) - 5);
} else {
SetWireImage(raw_packet_, sizeof(raw_packet_));
@@ -323,11 +375,11 @@
void ExpandVarints() override {
if (client_setup_.path.has_value()) {
- ExpandVarintsImpl("--vvvvvv-vv-vv---");
+ ExpandVarintsImpl("--vvvvvvv-vv-vv---");
// first two bytes are already a 2B varint. Also, don't expand parameter
// varints because that messes up the parameter length field.
} else {
- ExpandVarintsImpl("--vvvvvv-vv-");
+ ExpandVarintsImpl("--vvvvvvv-vv-");
}
}
@@ -336,8 +388,8 @@
}
private:
- uint8_t raw_packet_[17] = {
- 0x40, 0x40, // type
+ uint8_t raw_packet_[18] = {
+ 0x40, 0x40, 0x0f, // type
0x02, 0x01, 0x02, // versions
0x03, // 3 parameters
0x00, 0x01, 0x03, // role = PubSub
@@ -377,7 +429,8 @@
}
void ExpandVarints() override {
- ExpandVarintsImpl("--vvvv-vv-"); // first two bytes are already a 2b varint
+ ExpandVarintsImpl("--vvvvv-vv-"); // first two bytes are already a 2b
+ // varint
}
MessageStructuredData structured_data() const override {
@@ -385,8 +438,8 @@
}
private:
- uint8_t raw_packet_[10] = {
- 0x40, 0x41, // type
+ uint8_t raw_packet_[11] = {
+ 0x40, 0x41, 0x08, // type
0x01, 0x02, // version, two parameters
0x00, 0x01, 0x03, // role = PubSub
0x02, 0x01, 0x32, // max_subscribe_id = 50
@@ -450,7 +503,7 @@
}
void ExpandVarints() override {
- ExpandVarintsImpl("vvvvv---v------vvvvvv---vv--vv--");
+ ExpandVarintsImpl("vvvvvv---v------vvvvvv---vv--vv--");
}
MessageStructuredData structured_data() const override {
@@ -458,8 +511,8 @@
}
private:
- uint8_t raw_packet_[32] = {
- 0x03, 0x01, 0x02, // id and alias
+ uint8_t raw_packet_[33] = {
+ 0x03, 0x1f, 0x01, 0x02, // id and alias
0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x20, // subscriber priority = 0x20
@@ -522,25 +575,25 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv--vvvvv--vv--"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv--vvvvv--vv--"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_ok_);
}
void SetInvalidContentExists() {
- raw_packet_[4] = 0x02;
+ raw_packet_[5] = 0x02;
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
void SetInvalidDeliveryOrder() {
- raw_packet_[3] = 0x10;
+ raw_packet_[4] = 0x10;
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
private:
- uint8_t raw_packet_[16] = {
- 0x04, 0x01, 0x03, // subscribe_id = 1, expires = 3
+ uint8_t raw_packet_[17] = {
+ 0x04, 0x0f, 0x01, 0x03, // subscribe_id = 1, expires = 3
0x02, 0x01, // group_order = 2, content exists
0x0c, 0x14, // largest_group_id = 12, largest_object_id = 20,
0x02, // 2 parameters
@@ -587,15 +640,16 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvvv---v"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvvv---v"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_error_);
}
private:
- uint8_t raw_packet_[8] = {
- 0x05, 0x02, // subscribe_id = 2
+ uint8_t raw_packet_[9] = {
+ 0x05, 0x07,
+ 0x02, // subscribe_id = 2
0x01, // error_code = 2
0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
0x04, // track_alias = 4
@@ -624,15 +678,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(unsubscribe_);
}
private:
- uint8_t raw_packet_[2] = {
- 0x0a, 0x03, // subscribe_id = 3
+ uint8_t raw_packet_[3] = {
+ 0x0a, 0x01, 0x03, // subscribe_id = 3
};
MoqtUnsubscribe unsubscribe_ = {
@@ -667,22 +721,22 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvvv---vv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_done_);
}
void SetInvalidContentExists() {
- raw_packet_[6] = 0x02;
+ raw_packet_[7] = 0x02;
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
private:
- uint8_t raw_packet_[9] = {
- 0x0b, 0x02, 0x03, // subscribe_id = 2, error_code = 3,
- 0x02, 0x68, 0x69, // reason_phrase = "hi"
- 0x01, 0x08, 0x0c, // final_id = (8,12)
+ uint8_t raw_packet_[10] = {
+ 0x0b, 0x08, 0x02, 0x03, // subscribe_id = 2, error_code = 3,
+ 0x02, 0x68, 0x69, // reason_phrase = "hi"
+ 0x01, 0x08, 0x0c, // final_id = (8,12)
};
MoqtSubscribeDone subscribe_done_ = {
@@ -732,19 +786,19 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvvvvv-vvv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvvvvv-vvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_update_);
}
private:
- uint8_t raw_packet_[16] = {
- 0x02, 0x02, 0x03, 0x01, 0x05, 0x06, // start and end sequences
- 0xaa, // subscriber_priority
- 0x02, // 1 parameter
- 0x03, 0x02, 0x67, 0x10, // delivery_timeout = 10000
- 0x04, 0x02, 0x67, 0x10, // max_cache_duration = 10000
+ uint8_t raw_packet_[17] = {
+ 0x02, 0x0f, 0x02, 0x03, 0x01, 0x05, 0x06, // start and end sequences
+ 0xaa, // subscriber_priority
+ 0x02, // 1 parameter
+ 0x03, 0x02, 0x67, 0x10, // delivery_timeout = 10000
+ 0x04, 0x02, 0x67, 0x10, // max_cache_duration = 10000
};
MoqtSubscribeUpdate subscribe_update_ = {
@@ -780,18 +834,18 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---vvv---vv--"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---vvv---vv--"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_);
}
private:
- uint8_t raw_packet_[16] = {
- 0x06, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x02, // 2 parameters
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
- 0x04, 0x02, 0x67, 0x10, // max_cache_duration = 10000ms
+ uint8_t raw_packet_[17] = {
+ 0x06, 0x0f, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x02, // 2 parameters
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ 0x04, 0x02, 0x67, 0x10, // max_cache_duration = 10000ms
};
MoqtAnnounce announce_ = {
@@ -818,15 +872,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_ok_);
}
private:
- uint8_t raw_packet_[6] = {
- 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ uint8_t raw_packet_[7] = {
+ 0x07, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
};
MoqtAnnounceOk announce_ok_ = {
@@ -857,17 +911,17 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_error_);
}
private:
- uint8_t raw_packet_[11] = {
- 0x08, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x01, // error_code = 1
- 0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
+ uint8_t raw_packet_[12] = {
+ 0x08, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x01, // error_code = 1
+ 0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
};
MoqtAnnounceError announce_error_ = {
@@ -900,17 +954,17 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_cancel_);
}
private:
- uint8_t raw_packet_[11] = {
- 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x01, // error_code = 1
- 0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
+ uint8_t raw_packet_[12] = {
+ 0x0c, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x01, // error_code = 1
+ 0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
};
MoqtAnnounceCancel announce_cancel_ = {
@@ -935,16 +989,16 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---v----"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---v----"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(track_status_request_);
}
private:
- uint8_t raw_packet_[11] = {
- 0x0d, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
+ uint8_t raw_packet_[12] = {
+ 0x0d, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
};
MoqtTrackStatusRequest track_status_request_ = {
@@ -967,15 +1021,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(unannounce_);
}
private:
- uint8_t raw_packet_[6] = {
- 0x09, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace
+ uint8_t raw_packet_[7] = {
+ 0x09, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace
};
MoqtUnannounce unannounce_ = {
@@ -1010,17 +1064,17 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---v----vvv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---v----vvv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(track_status_);
}
private:
- uint8_t raw_packet_[14] = {
- 0x0e, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
- 0x00, 0x0c, 0x14, // status, last_group, last_object
+ uint8_t raw_packet_[15] = {
+ 0x0e, 0x0d, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
+ 0x00, 0x0c, 0x14, // status, last_group, last_object
};
MoqtTrackStatus track_status_ = {
@@ -1046,15 +1100,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(goaway_);
}
private:
- uint8_t raw_packet_[5] = {
- 0x10, 0x03, 0x66, 0x6f, 0x6f,
+ uint8_t raw_packet_[6] = {
+ 0x10, 0x04, 0x03, 0x66, 0x6f, 0x6f,
};
MoqtGoAway goaway_ = {
@@ -1081,17 +1135,17 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---vvv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---vvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_namespace_);
}
private:
- uint8_t raw_packet_[12] = {
- 0x11, 0x01, 0x03, 0x66, 0x6f, 0x6f, // namespace = "foo"
- 0x01, // 1 parameter
- 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
+ uint8_t raw_packet_[13] = {
+ 0x11, 0x0b, 0x01, 0x03, 0x66, 0x6f, 0x6f, // namespace = "foo"
+ 0x01, // 1 parameter
+ 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
};
MoqtSubscribeNamespace subscribe_namespace_ = {
@@ -1116,15 +1170,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_namespace_ok_);
}
private:
- uint8_t raw_packet_[6] = {
- 0x12, 0x01, 0x03, 0x66, 0x6f, 0x6f, // namespace = "foo"
+ uint8_t raw_packet_[7] = {
+ 0x12, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f, // namespace = "foo"
};
MoqtSubscribeNamespaceOk subscribe_namespace_ok_ = {
@@ -1155,17 +1209,17 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_namespace_error_);
}
private:
- uint8_t raw_packet_[11] = {
- 0x13, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
- 0x01, // error_code = 1
- 0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
+ uint8_t raw_packet_[12] = {
+ 0x13, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
+ 0x01, // error_code = 1
+ 0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
};
MoqtSubscribeNamespaceError subscribe_namespace_error_ = {
@@ -1190,15 +1244,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(unsubscribe_namespace_);
}
private:
- uint8_t raw_packet_[6] = {
- 0x14, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace
+ uint8_t raw_packet_[7] = {
+ 0x14, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f, // track_namespace
};
MoqtUnsubscribeNamespace unsubscribe_namespace_ = {
@@ -1221,15 +1275,16 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(max_subscribe_id_);
}
private:
- uint8_t raw_packet_[2] = {
+ uint8_t raw_packet_[3] = {
0x15,
+ 0x01,
0x0b,
};
@@ -1265,15 +1320,15 @@
return true;
}
- void ExpandVarints() override { ExpandVarintsImpl("vvvvv"); }
+ void ExpandVarints() override { ExpandVarintsImpl("vvvvvv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(object_ack_);
}
private:
- uint8_t raw_packet_[6] = {
- 0x71, 0x84, // type
+ uint8_t raw_packet_[7] = {
+ 0x71, 0x84, 0x04, // type
0x01, 0x10, 0x20, // subscribe ID, group, object
0x20, // 0x10 time delta
};