13 #include <source_location>
79 const std::source_location location = std::source_location::current())
80 : std::runtime_error(
"Protocol violation: " +
reason +
" (line " + std::to_string(location.line()) +
81 ", file " + location.file_name() +
")")
173 std::uint64_t
object{ 0 };
179 if (
const auto cmp = group <=> other.
group; cmp != 0) {
182 return object <=> other.
object;
210 std::optional<std::uint64_t>
220 std::same_as<T, std::uint64_t> || (std::is_enum_v<T> && std::same_as<std::underlying_type_t<T>, std::uint64_t>);
241 std::size_t
Size(
const T prev_type)
const
243 std::size_t size = 0;
244 const auto type_value =
static_cast<std::uint64_t
>(
type);
245 const auto prev_type_value =
static_cast<std::uint64_t
>(prev_type);
246 const auto delta = type_value - prev_type_value;
249 if (type_value % 2 == 0) {
251 if (
value.size() >
sizeof(std::uint64_t)) {
252 throw std::invalid_argument(
"Value too large to encode as uint64_t.");
254 std::uint64_t val = 0;
255 std::memcpy(&val,
value.data(),
value.size());
260 size +=
value.size();
277 if (
static_cast<std::uint64_t
>(
type) % 2 != 0) {
283 if (
value.size() >
sizeof(std::uint64_t) || other.
value.size() >
sizeof(std::uint64_t)) {
284 throw std::invalid_argument(
"Even KVPs must be <= 8 bytes");
288 const auto smaller = std::min(
value.size(), other.
value.size());
289 if (memcmp(
value.data(), other.
value.data(), smaller) != 0) {
294 const auto larger = std::max(
value.size(), other.
value.size());
295 if (larger == smaller) {
301 const auto remaining = larger - smaller;
302 static constexpr std::uint8_t kZero[
sizeof(std::uint64_t)] = { 0 };
303 return memcmp(longer.data() + smaller, kZero, remaining) == 0;
317 return buffer << UintVar(static_cast<std::uint64_t>(value));
330 std::uint64_t uvalue;
331 buffer = buffer >> uvalue;
332 value =
static_cast<T
>(uvalue);
348 const auto type_value =
static_cast<std::uint64_t
>(kvp.
type);
349 const auto prev_type_value =
static_cast<std::uint64_t
>(prev_type);
350 const auto delta = type_value - prev_type_value;
353 if (type_value % 2 != 0) {
358 if (kvp.
value.size() >
sizeof(std::uint64_t)) {
359 throw std::invalid_argument(
"Value too large to encode as uint64_t.");
361 std::uint64_t val = 0;
362 std::memcpy(&val, kvp.
value.data(), kvp.
value.size());
379 const auto prev_type_value =
static_cast<std::uint64_t
>(prev_type);
381 buffer = buffer >> delta;
382 if (delta > std::numeric_limits<std::uint64_t>::max() - prev_type_value) {
385 const auto type_value = prev_type_value + delta;
386 kvp.
type =
static_cast<T
>(type_value);
388 if (type_value % 2 != 0) {
390 buffer = buffer >> kvp.
value;
394 buffer = buffer.subspan(uvar.
size());
395 std::uint64_t val(uvar);
396 const auto* p =
reinterpret_cast<const std::uint8_t*
>(&val);
397 kvp.
value.assign(p, p +
sizeof(val));
461 buffer << UintVar(static_cast<std::uint64_t>(token.
alias_type));
493 std::uint64_t alias_type = 0;
494 buffer = buffer >> alias_type;
500 std::uint64_t alias = 0;
501 buffer = buffer >> alias;
506 std::uint64_t alias = 0;
507 std::uint64_t type = 0;
508 buffer = buffer >> alias;
509 buffer = buffer >> type;
512 token.
token_value.assign(buffer.begin(), buffer.end());
513 buffer = buffer.subspan(buffer.size());
517 std::uint64_t type = 0;
518 buffer = buffer >> type;
520 token.
token_value.assign(buffer.begin(), buffer.end());
521 buffer = buffer.subspan(buffer.size());
582 bytes << UintVar(static_cast<std::uint64_t>(filter.
type));
583 switch (filter.
type) {
611 std::uint64_t type = 0;
612 bytes = bytes >> type;
614 switch (filter.
type) {
671 bytes = bytes >> filter.
timeout;
677 using Filter = std::variant<std::monostate, SubscriptionFilter, TrackFilter>;
685 using T = std::decay_t<decltype(f)>;
686 if constexpr (std::is_same_v<std::monostate, T>) {
688 }
else if constexpr (std::is_same_v<SubscriptionFilter, T>) {
690 }
else if constexpr (std::is_same_v<TrackFilter, T>) {
707 using T = std::decay_t<decltype(f)>;
708 if constexpr (!std::is_same_v<std::monostate, T>) {
722 throw std::runtime_error(
"parsing a non specific filter is impossible, stream to a more specific filter type");
734 switch (filter_type) {
737 bytes = bytes >> filter;
738 if (!bytes.empty()) {
745 bytes = bytes >> filter;
749 return std::monostate{};
752 return std::monostate{};
871 { bytes << value } -> std::same_as<Bytes&>;
872 {
BytesSpan{} >> value } -> std::same_as<BytesSpan>;
881 (std::is_enum_v<T> && std::same_as<std::underlying_type_t<T>, std::uint8_t>);
904 template<
typename T, KeyType K>
907 const auto type_value =
static_cast<std::uint64_t
>(type);
908 pairs_[type_value] =
EncodeValue(type_value, value);
919 template<
typename T, KeyType K>
920 std::optional<T>
Get(K type)
const
922 const auto it = pairs_.find(
static_cast<std::uint64_t
>(type));
923 if (it == pairs_.end()) {
926 const auto& bytes = it->second;
927 if constexpr (std::is_arithmetic_v<T>) {
928 if (
static_cast<std::uint64_t
>(type) % 2 == 0) {
929 std::uint64_t val = 0;
930 std::memcpy(&val, bytes.data(), std::min(bytes.size(),
sizeof(val)));
931 return static_cast<T
>(val);
935 if constexpr (HasByteStreamOperators<T>) {
941 return FromBytes<T>(bytes);
946 bool Contains(std::uint64_t type)
const {
return pairs_.contains(type); }
949 auto begin() const noexcept {
return pairs_.begin(); }
952 auto end() const noexcept {
return pairs_.end(); }
955 const std::map<std::uint64_t, Bytes>&
Pairs() const noexcept {
return pairs_; }
967 if constexpr (std::is_arithmetic_v<T> || std::is_enum_v<T>) {
969 const std::uint64_t val =
static_cast<std::uint64_t
>(value);
970 auto* val_bytes =
reinterpret_cast<const std::uint8_t*
>(&val);
971 return Bytes{ val_bytes, val_bytes +
sizeof(val) };
975 if constexpr (HasByteStreamOperators<T>) {
985 std::map<std::uint64_t, Bytes> pairs_;
1026 template<
typename T>
1030 throw std::invalid_argument(
"ExtensionType::kImmutable should not be used directly, use AddImmutable "
1031 "with the keytype you want to use");
1034 extensions[
static_cast<std::uint64_t
>(type)] =
1047 template<
typename T>
1050 if (value.has_value()) {
1051 Add<T>(type, value.value());
1063 template<
typename T>
1077 template<
typename T>
1080 if (!
extensions.contains(
static_cast<std::uint64_t
>(type))) {
1081 return std::nullopt;
1083 if constexpr (std::is_arithmetic_v<T>) {
1084 if (
static_cast<std::uint64_t
>(type) % 2 == 0) {
1085 std::uint64_t val = 0;
1086 const auto& bytes =
extensions.at(
static_cast<std::uint64_t
>(type));
1087 std::memcpy(&val, bytes.data(), std::min(bytes.size(),
sizeof(val)));
1088 return static_cast<T
>(val);
1092 if constexpr (HasByteStreamOperators<T>) {
1094 extensions.at(
static_cast<std::uint64_t
>(type)) >> result;
1098 return FromBytes<T>(
extensions.at(
static_cast<std::uint64_t
>(type)));
1107 template<
typename T>
1111 return std::nullopt;
1113 if constexpr (std::is_arithmetic_v<T>) {
1114 if (
static_cast<std::uint64_t
>(type) % 2 == 0) {
1115 std::uint64_t val = 0;
1117 std::memcpy(&val, bytes.data(), std::min(bytes.size(),
sizeof(val)));
1118 return static_cast<T
>(val);
1122 if constexpr (HasByteStreamOperators<T>) {
An N-tuple representation of a MOQ namespace.
Definition: track_name.h:22
constexpr std::size_t size() const noexcept
Definition: uintvar.h:160
Draft 18 flat key-value pairs: a bounded, sorted KVP sequence without a leading count.
Definition: ctrl_message_types.h:885
const std::map< std::uint64_t, Bytes > & Pairs() const noexcept
Definition: ctrl_message_types.h:955
bool Contains(std::uint64_t type) const
Definition: ctrl_message_types.h:946
KeyValuePairs()=default
Creates an empty sequence.
static Bytes EncodeValue(std::uint64_t type, const T &value)
Definition: ctrl_message_types.h:965
std::optional< T > Get(K type) const
Definition: ctrl_message_types.h:920
auto end() const noexcept
Definition: ctrl_message_types.h:952
auto begin() const noexcept
Definition: ctrl_message_types.h:949
KeyValuePairs & Add(K type, const T &value)
Definition: ctrl_message_types.h:905
KeyValuePairs(const std::map< std::uint64_t, Bytes > &pairs)
Definition: ctrl_message_types.h:891
Mutable and immutable track-scoped extension maps.
Definition: ctrl_message_types.h:1006
TrackExtensions & AddImmutable(ExtensionType type, const T &value)
Definition: ctrl_message_types.h:1064
TrackExtensions(const std::map< std::uint64_t, Bytes > &ext)
Definition: ctrl_message_types.h:1012
TrackExtensions()=default
Creates empty extension maps.
std::optional< T > GetImmutable(ExtensionType type) const
Definition: ctrl_message_types.h:1108
auto end() const noexcept
Definition: ctrl_message_types.h:1135
TrackExtensions & Add(ExtensionType type, const T &value)
Definition: ctrl_message_types.h:1027
std::map< std::uint64_t, Bytes > extensions
Mutable extensions keyed by absolute type.
Definition: ctrl_message_types.h:1137
std::optional< T > Get(ExtensionType type) const
Definition: ctrl_message_types.h:1078
auto begin() const noexcept
Definition: ctrl_message_types.h:1132
TrackExtensions & AddOptional(ExtensionType type, const std::optional< T > &value)
Definition: ctrl_message_types.h:1048
std::map< std::uint64_t, Bytes > immutable_extensions
Immutable nested extensions keyed by absolute type.
Definition: ctrl_message_types.h:1138
Definition: ctrl_message_types.h:38
TerminationReason
Session termination reason codes.
Definition: ctrl_message_types.h:812
@ kMalformedAuthority
Authority encoding is malformed.
@ kGoawayTimeout
GOAWAY timed out.
@ kKeyValueFormattingError
Malformed key/value sequence.
@ kInvalidAuthority
Authority is invalid.
@ kUnauthorized
Authorization failure.
@ kMalformedPath
Path encoding is malformed.
@ kExpiredAuthToken
Authorization token expired.
@ kDuplicateTrackAlias
Track alias was reused.
@ kMalformedAuthToken
Authorization token is malformed.
@ kDataStreamTimeout
Data-stream timeout.
@ kProtocolViolation
Peer violated the protocol.
@ kInvalidPath
Path is invalid.
@ kUnknownAuthTokenAlias
Authorization-token alias is unknown.
@ kControlMessageTimeout
Control-message timeout.
@ kVersionNegotiationFailed
No mutually supported version.
@ kTooManyRequests
Request limit exceeded.
@ kDuplicateAuthTokenAlias
Authorization-token alias was reused.
@ kAuthTokenCacheOverflow
Authorization-token cache is full.
@ kInvalidRequestId
Invalid request identifier.
@ kNoError
Clean termination.
@ kInternalError
Internal endpoint failure.
concept HasByteStreamOperators
Definition: ctrl_message_types.h:870
void SerializeKvp(Bytes &buffer, const KeyValuePair< T > &kvp, const T prev_type)
Definition: ctrl_message_types.h:345
PublishDoneStatusCode
Publish-done status codes.
Definition: ctrl_message_types.h:757
@ kUnauthorized
Authorization failed.
@ kGoingAway
Endpoint is going away.
@ kSubscriptionEnded
Subscription ended.
@ kTrackEnded
Track ended.
@ kTooFarBehind
Consumer fell too far behind.
@ kInternalError
Internal error.
Bytes & operator<<(Bytes &buffer, const Bytes &bytes)
Filter DeserializeFilter(FilterType filter_type, BytesSpan bytes)
Definition: ctrl_message_types.h:732
concept KeyType
Definition: ctrl_message_types.h:219
concept ByteParameter
Definition: ctrl_message_types.h:880
SetupOptionType
SETUP option type codes.
Definition: ctrl_message_types.h:403
@ kMaxAuthTokenCacheSize
Maximum authorization-token alias cache size.
@ kMoqtImplementation
Implementation identification bytes.
@ kPath
Request path bytes.
@ kAuthorizationToken
Sensitive opaque authorization token; never log its bytes.
@ kAuthority
Authority bytes.
@ kEndpointId
Internal endpoint identifier.
@ kInvalid
Internal invalid sentinel.
FilterType GetFilterType(const Filter &filter)
Definition: ctrl_message_types.h:681
ExtensionType
Known track/object extension type codes.
Definition: ctrl_message_types.h:849
@ kDefaultPublisherPriority
Default publisher priority.
@ kPriorObjectIdGap
Gap from the prior object identifier.
@ kDefaultPublisherGroupOrder
Default publisher group order.
@ kPriorGroupIdGap
Gap from the prior group identifier.
@ kDeliveryTimeout
Delivery timeout.
@ kImmutable
Container for immutable nested extension KVPs.
@ kDynamicGroups
Dynamic-groups flag.
@ kMaxCacheDuration
Maximum cache duration.
BytesSpan operator>>(BytesSpan buffer, Bytes &value)
std::variant< std::monostate, SubscriptionFilter, TrackFilter > Filter
Any supported filter representation; monostate means no/unsupported filter.
Definition: ctrl_message_types.h:677
FetchType
FETCH request form.
Definition: ctrl_message_types.h:788
@ kRelativeJoiningFetch
Joining fetch relative to a subscription.
@ kAbsoluteJoiningFetch
Joining fetch with absolute bounds.
@ kStandalone
Independent fetch.
void ParseKvp(BytesSpan &buffer, KeyValuePair< T > &kvp, const T prev_type)
Definition: ctrl_message_types.h:376
ControlMessageType
MoQ control-message wire type codes.
Definition: ctrl_message_types.h:42
@ kPublishBlocked
PUBLISH_BLOCKED.
@ kRequestUpdate
REQUEST_UPDATE.
@ kMaxRequestId
MAX_REQUEST_ID.
@ kPublishNamespaceDone
PUBLISH_NAMESPACE_DONE.
@ kUnsubscribe
UNSUBSCRIBE.
@ kRequestsBlocked
REQUESTS_BLOCKED.
@ kSubscribeOk
SUBSCRIBE_OK.
@ kRequestError
REQUEST_ERROR.
@ kSubscribeTracks
SUBSCRIBE_TRACKS.
@ kFetchCancel
FETCH_CANCEL.
@ kPublishDone
PUBLISH_DONE.
@ kPublishNamespace
PUBLISH_NAMESPACE.
@ kPublishNamespaceCancel
PUBLISH_NAMESPACE_CANCEL.
@ kSubscribeNamespace
SUBSCRIBE_NAMESPACE.
@ kTrackStatus
TRACK_STATUS.
@ kNamespaceDone
NAMESPACE_DONE.
FilterType
In-memory filter discriminator.
Definition: ctrl_message_types.h:546
@ kTrackFilter
Track-selection constraints.
@ kSubscriptionFilter
Location/subscription filter.
GroupOrder
Requested group traversal order.
Definition: ctrl_message_types.h:532
@ kAscending
Increasing group identifiers.
@ kDescending
Decreasing group identifiers.
StreamResetError
Data-stream reset error codes.
Definition: ctrl_message_types.h:838
@ kUnknownObjectStatus
Unknown object status.
@ kDeliveryTimeout
Delivery timed out.
@ kCancelled
Delivery was cancelled.
@ kSessionClosed
Session closed.
@ kMalformedTrack
Track data is malformed.
@ kInternalError
Internal failure.
SubscriptionFilterType
Subscription-filter form.
Definition: ctrl_message_types.h:554
@ kLargestObject
Start at the largest object.
@ kAbsoluteStart
Start at an absolute location.
@ kAbsoluteRange
Select an absolute range.
@ kNextGroupStart
Start at the next group.
Definition: attributes.h:13
Bytes & operator<<(Bytes &buffer, const TrackNamespace &msg)
std::vector< Byte > Bytes
Owning contiguous byte buffer.
Definition: bytes.h:18
std::span< const Byte > BytesSpan
Non-owning, read-only view of contiguous bytes.
Definition: bytes.h:21
requires std::is_standard_layout_v< T > std::is_same_v< std::decay_t< T >, std::string > Bytes AsOwnedBytes(const T &value)
Copies a value's native object representation into an owning byte buffer.
Definition: bytes.h:60
void AppendBytes(Bytes &buffer, BytesSpan bytes)
Appends bytes to an owning buffer.
Definition: bytes.h:99
BytesSpan operator>>(BytesSpan buffer, TrackNamespace &msg)
Inclusive terminal location for a fetch range.
Definition: ctrl_message_types.h:208
std::uint64_t group
The group ID of the fetch's end location (inclusive).
Definition: ctrl_message_types.h:209
std::optional< std::uint64_t > object
The object ID of the fetch's end location (inclusive), or null for the whole group.
Definition: ctrl_message_types.h:211
Definition: ctrl_message_types.h:231
Bytes value
Opaque odd-key bytes or host-order integer bytes for an even key.
Definition: ctrl_message_types.h:233
bool operator==(const KeyValuePair< T > &other) const
Definition: ctrl_message_types.h:271
std::size_t Size(const T prev_type) const
Definition: ctrl_message_types.h:241
T type
Absolute key type.
Definition: ctrl_message_types.h:232
Absolute group/object location ordered lexicographically by group then object.
Definition: ctrl_message_types.h:171
std::uint64_t object
Object identifier within the group.
Definition: ctrl_message_types.h:173
auto operator<=>(const Location &other) const
Definition: ctrl_message_types.h:177
std::uint64_t group
Group identifier.
Definition: ctrl_message_types.h:172
bool operator==(const Location &other) const =default
Exception indicating that received or constructed data violates the MoQ protocol.
Definition: ctrl_message_types.h:71
const std::string reason
Unformatted protocol-violation reason.
Definition: ctrl_message_types.h:72
ProtocolViolationException(const std::string &reason, const std::source_location location=std::source_location::current())
Definition: ctrl_message_types.h:78
Definition: ctrl_message_types.h:566
std::uint64_t end_group_delta
Inclusive end-group offset from start_location.group for kAbsoluteRange.
Definition: ctrl_message_types.h:574
SubscriptionFilterType type
Wire-format filter form.
Definition: ctrl_message_types.h:568
auto operator<=>(const SubscriptionFilter &) const noexcept=default
Location start_location
Absolute starting group and object for kAbsoluteStart and kAbsoluteRange.
Definition: ctrl_message_types.h:571
Definition: ctrl_message_types.h:425
std::optional< std::uint64_t > token_alias
Alias required for delete, register, and use-alias operations.
Definition: ctrl_message_types.h:438
AliasType
Operation encoded at the beginning of an authorization-token value.
Definition: ctrl_message_types.h:428
@ kRegister
Register alias, token type, and token value.
@ kUseAlias
Refer to a previously registered alias.
@ kUseValue
Carry a token type and token value directly.
@ kDelete
Delete the specified cached alias.
bool operator==(const Token &other) const =default
std::optional< std::uint64_t > token_type
Application-defined token type required when a value is present.
Definition: ctrl_message_types.h:441
AliasType alias_type
Alias operation.
Definition: ctrl_message_types.h:435
Bytes token_value
Sensitive opaque token bytes; never log this field.
Definition: ctrl_message_types.h:444
Selects tracks by property, count, and timeout constraints.
Definition: ctrl_message_types.h:635
constexpr auto operator<=>(const TrackFilter &other) const noexcept=default
std::uint64_t max_tracks_selected
Maximum number of selected tracks.
Definition: ctrl_message_types.h:637
std::uint64_t property_type
Property type used for selection.
Definition: ctrl_message_types.h:636
std::uint64_t timeout
Selection timeout.
Definition: ctrl_message_types.h:638