Skip to content

Commit c6fd457

Browse files
committed
Fix WebTransport publish interop handling
1 parent ede6984 commit c6fd457

4 files changed

Lines changed: 329 additions & 144 deletions

File tree

src/transport/moqt_control_messages.cpp

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <array>
44
#include <cstddef>
5+
#include <limits>
56
#include <string>
67
#include <string_view>
78

@@ -226,6 +227,43 @@ void append_parameter(std::vector<std::uint8_t>& out,
226227
}
227228
}
228229

230+
void append_parameter_delta(std::vector<std::uint8_t>& out,
231+
std::uint64_t& previous_type,
232+
std::uint64_t type,
233+
std::span<const std::uint8_t> value) {
234+
const std::uint64_t delta = type - previous_type;
235+
append_varint(out, delta);
236+
if ((type & 0x1ULL) == 0) {
237+
out.insert(out.end(), value.begin(), value.end());
238+
} else {
239+
append_varint(out, value.size());
240+
out.insert(out.end(), value.begin(), value.end());
241+
}
242+
previous_type = type;
243+
}
244+
245+
bool decode_parameter_type(std::span<const std::uint8_t> bytes,
246+
std::size_t& offset,
247+
std::uint64_t& previous_type,
248+
bool delta_encoded,
249+
std::uint64_t& parameter_type) {
250+
std::uint64_t encoded_type = 0;
251+
if (!decode_varint_impl(bytes, offset, encoded_type)) {
252+
return false;
253+
}
254+
if (!delta_encoded) {
255+
parameter_type = encoded_type;
256+
previous_type = parameter_type;
257+
return true;
258+
}
259+
if (encoded_type > std::numeric_limits<std::uint64_t>::max() - previous_type) {
260+
return false;
261+
}
262+
parameter_type = previous_type + encoded_type;
263+
previous_type = parameter_type;
264+
return true;
265+
}
266+
229267
std::uint64_t draft_version_number(DraftVersion draft) {
230268
switch (draft) {
231269
case DraftVersion::kDraft14:
@@ -323,15 +361,28 @@ std::vector<std::uint8_t> encode_setup_message(const SetupMessage& message) {
323361

324362
const bool include_native_quic_location = message.transport == TransportKind::kRawQuic;
325363
append_varint(payload, include_native_quic_location ? 3 : 1);
364+
std::uint64_t previous_parameter_type = 0;
326365
if (include_native_quic_location) {
327-
const std::vector<std::uint8_t> authority = to_bytes(message.authority);
328366
const std::vector<std::uint8_t> path = to_bytes(message.path);
329-
append_parameter(payload, kSetupParamAuthority, authority);
330-
append_parameter(payload, kSetupParamPath, path);
367+
const std::vector<std::uint8_t> authority = to_bytes(message.authority);
368+
if (message.draft == DraftVersion::kDraft16) {
369+
append_parameter_delta(payload, previous_parameter_type, kSetupParamPath, path);
370+
} else {
371+
append_parameter(payload, kSetupParamAuthority, authority);
372+
append_parameter(payload, kSetupParamPath, path);
373+
}
331374
}
332375
std::vector<std::uint8_t> max_request_id;
333376
append_varint(max_request_id, message.max_request_id);
334-
append_parameter(payload, kSetupParamMaxRequestId, max_request_id);
377+
if (message.draft == DraftVersion::kDraft16) {
378+
append_parameter_delta(payload, previous_parameter_type, kSetupParamMaxRequestId, max_request_id);
379+
if (include_native_quic_location) {
380+
const std::vector<std::uint8_t> authority = to_bytes(message.authority);
381+
append_parameter_delta(payload, previous_parameter_type, kSetupParamAuthority, authority);
382+
}
383+
} else {
384+
append_parameter(payload, kSetupParamMaxRequestId, max_request_id);
385+
}
335386

336387
std::vector<std::uint8_t> message_bytes;
337388
append_varint(message_bytes, kClientSetupType);
@@ -366,10 +417,16 @@ bool decode_server_setup_message(std::span<const std::uint8_t> bytes, ServerSetu
366417
const std::uint8_t first_payload_byte = bytes[offset];
367418
if ((first_payload_byte & 0xc0) == 0xc0) {
368419
std::uint64_t selected_version = 0;
369-
if (!decode_varint_impl(payload_bytes, offset, selected_version) || selected_version != kDraft14Version) {
420+
if (!decode_varint_impl(payload_bytes, offset, selected_version)) {
421+
return false;
422+
}
423+
if (selected_version == kDraft14Version) {
424+
message.draft = DraftVersion::kDraft14;
425+
} else if (selected_version == kDraft16Version) {
426+
message.draft = DraftVersion::kDraft16;
427+
} else {
370428
return false;
371429
}
372-
message.draft = DraftVersion::kDraft14;
373430
} else {
374431
message.draft = DraftVersion::kDraft16;
375432
}
@@ -379,9 +436,11 @@ bool decode_server_setup_message(std::span<const std::uint8_t> bytes, ServerSetu
379436
return false;
380437
}
381438

439+
std::uint64_t previous_parameter_type = 0;
440+
const bool delta_encoded = message.draft == DraftVersion::kDraft16;
382441
for (std::uint64_t parameter_index = 0; parameter_index < parameter_count; ++parameter_index) {
383442
std::uint64_t parameter_type = 0;
384-
if (!decode_varint_impl(payload_bytes, offset, parameter_type)) {
443+
if (!decode_parameter_type(payload_bytes, offset, previous_parameter_type, delta_encoded, parameter_type)) {
385444
return false;
386445
}
387446

@@ -413,9 +472,14 @@ std::vector<std::uint8_t> encode_server_setup_message(const ServerSetupMessage&
413472
}
414473

415474
append_varint(payload, 1);
475+
std::uint64_t previous_parameter_type = 0;
416476
std::vector<std::uint8_t> max_request_id;
417477
append_varint(max_request_id, message.max_request_id);
418-
append_parameter(payload, kSetupParamMaxRequestId, max_request_id);
478+
if (message.draft == DraftVersion::kDraft16) {
479+
append_parameter_delta(payload, previous_parameter_type, kSetupParamMaxRequestId, max_request_id);
480+
} else {
481+
append_parameter(payload, kSetupParamMaxRequestId, max_request_id);
482+
}
419483

420484
std::vector<std::uint8_t> message_bytes;
421485
append_varint(message_bytes, kServerSetupType);

src/transport/moqt_session.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ bool trace_enabled() {
2323
return enabled;
2424
}
2525

26+
bool is_idle_subscribe_exit(std::string_view message) {
27+
return message == "timed out waiting for stream data" ||
28+
message == "no queued read for stream" ||
29+
message == "webtransport connection closed";
30+
}
31+
2632
std::string hex_dump(std::span<const std::uint8_t> bytes);
2733

2834
TransportStatus try_read_wt_session_stream(PublisherTransport& transport,
@@ -1049,6 +1055,9 @@ TransportStatus serve_subscriptions(PublisherTransport& transport,
10491055
std::vector<std::uint8_t> chunk;
10501056
const TransportStatus read_status = transport.read_stream(control_stream_id, chunk, fin, subscriber_timeout);
10511057
if (!read_status.ok) {
1058+
if (!served_any_subscription && is_idle_subscribe_exit(read_status.message)) {
1059+
break;
1060+
}
10521061
if (read_status.message == "timed out waiting for stream data" ||
10531062
read_status.message == "no queued read for stream") {
10541063
break;
@@ -1496,6 +1505,14 @@ TransportStatus MoqtSession::connect(const EndpointConfig& endpoint, const TlsCo
14961505
return status;
14971506
}
14981507

1508+
if (trace_enabled()) {
1509+
std::cerr << "[moqt-session] transport connected id=" << transport_.connection_id()
1510+
<< " transport="
1511+
<< (endpoint.transport == openmoq::publisher::transport::TransportKind::kWebTransport ? "webtransport"
1512+
: "raw")
1513+
<< std::endl;
1514+
}
1515+
14991516
return ensure_control_stream();
15001517
}
15011518

@@ -1506,6 +1523,9 @@ TransportStatus MoqtSession::publish(const openmoq::publisher::PublishPlan& plan
15061523

15071524
TransportStatus status = ensure_setup(plan.draft.version);
15081525
if (!status.ok) {
1526+
if (trace_enabled()) {
1527+
std::cerr << "[moqt-session] setup failed error=" << status.message << std::endl;
1528+
}
15091529
return status;
15101530
}
15111531
std::cout << "connection_id=" << transport_.connection_id() << '\n' << std::flush;

0 commit comments

Comments
 (0)