blob: c2a22cd677c5192e9f641b72a297e372e4d4f999 [file] [log] [blame]
// 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.
// Structured data for message types in draft-ietf-moq-transport-02.
#ifndef QUICHE_QUIC_MOQT_MOQT_MESSAGES_H_
#define QUICHE_QUIC_MOQT_MOQT_MESSAGES_H_
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_versions.h"
#include "quiche/common/platform/api/quiche_export.h"
namespace moqt {
inline constexpr quic::ParsedQuicVersionVector GetMoqtSupportedQuicVersions() {
return quic::ParsedQuicVersionVector{quic::ParsedQuicVersion::RFCv1()};
}
enum class MoqtVersion : uint64_t {
kDraft04 = 0xff000004,
kUnrecognizedVersionForTests = 0xfe0000ff,
};
struct QUICHE_EXPORT MoqtSessionParameters {
// TODO: support multiple versions.
// TODO: support roles other than PubSub.
MoqtVersion version;
quic::Perspective perspective;
bool using_webtrans;
std::string path;
bool deliver_partial_objects;
};
// The maximum length of a message, excluding any OBJECT payload. This prevents
// DoS attack via forcing the parser to buffer a large message (OBJECT payloads
// are not buffered by the parser).
inline constexpr size_t kMaxMessageHeaderSize = 2048;
enum class QUICHE_EXPORT MoqtMessageType : uint64_t {
kObjectStream = 0x00,
kObjectDatagram = 0x01,
kSubscribeUpdate = 0x02,
kSubscribe = 0x03,
kSubscribeOk = 0x04,
kSubscribeError = 0x05,
kAnnounce = 0x06,
kAnnounceOk = 0x7,
kAnnounceError = 0x08,
kUnannounce = 0x09,
kUnsubscribe = 0x0a,
kSubscribeDone = 0x0b,
kAnnounceCancel = 0x0c,
kTrackStatusRequest = 0x0d,
kTrackStatus = 0x0e,
kGoAway = 0x10,
kClientSetup = 0x40,
kServerSetup = 0x41,
kStreamHeaderTrack = 0x50,
kStreamHeaderGroup = 0x51,
};
enum class QUICHE_EXPORT MoqtError : uint64_t {
kNoError = 0x0,
kInternalError = 0x1,
kUnauthorized = 0x2,
kProtocolViolation = 0x3,
kDuplicateTrackAlias = 0x4,
kParameterLengthMismatch = 0x5,
kGoawayTimeout = 0x10,
};
enum class QUICHE_EXPORT MoqtRole : uint64_t {
kPublisher = 0x1,
kSubscriber = 0x2,
kPubSub = 0x3,
kRoleMax = 0x3,
};
enum class QUICHE_EXPORT MoqtSetupParameter : uint64_t {
kRole = 0x0,
kPath = 0x1,
};
enum class QUICHE_EXPORT MoqtTrackRequestParameter : uint64_t {
kAuthorizationInfo = 0x2,
};
// TODO: those are non-standard; add standard error codes once those exist, see
// <https://github.com/moq-wg/moq-transport/issues/393>.
enum class MoqtAnnounceErrorCode : uint64_t {
kInternalError = 0,
kAnnounceNotSupported = 1,
};
struct MoqtAnnounceErrorReason {
MoqtAnnounceErrorCode error_code;
std::string reason_phrase;
};
struct FullTrackName {
std::string track_namespace;
std::string track_name;
FullTrackName(absl::string_view ns, absl::string_view name)
: track_namespace(ns), track_name(name) {}
bool operator==(const FullTrackName& other) const {
return track_namespace == other.track_namespace &&
track_name == other.track_name;
}
bool operator<(const FullTrackName& other) const {
return track_namespace < other.track_namespace ||
(track_namespace == other.track_namespace &&
track_name < other.track_name);
}
FullTrackName& operator=(const FullTrackName& other) {
track_namespace = other.track_namespace;
track_name = other.track_name;
return *this;
}
template <typename H>
friend H AbslHashValue(H h, const FullTrackName& m);
};
template <typename H>
H AbslHashValue(H h, const FullTrackName& m) {
return H::combine(std::move(h), m.track_namespace, m.track_name);
}
// These are absolute sequence numbers.
struct FullSequence {
uint64_t group = 0;
uint64_t object = 0;
bool operator==(const FullSequence& other) const {
return group == other.group && object == other.object;
}
bool operator<(const FullSequence& other) const {
return group < other.group ||
(group == other.group && object < other.object);
}
bool operator<=(const FullSequence& other) const {
return (group < other.group ||
(group == other.group && object <= other.object));
}
FullSequence& operator=(FullSequence other) {
group = other.group;
object = other.object;
return *this;
}
FullSequence next() const { return FullSequence{group, object + 1}; }
template <typename H>
friend H AbslHashValue(H h, const FullSequence& m);
template <typename Sink>
friend void AbslStringify(Sink& sink, const FullSequence& sequence) {
absl::Format(&sink, "(%d; %d)", sequence.group, sequence.object);
}
};
template <typename H>
H AbslHashValue(H h, const FullSequence& m) {
return H::combine(std::move(h), m.group, m.object);
}
struct QUICHE_EXPORT MoqtClientSetup {
std::vector<MoqtVersion> supported_versions;
std::optional<MoqtRole> role;
std::optional<std::string> path;
};
struct QUICHE_EXPORT MoqtServerSetup {
MoqtVersion selected_version;
std::optional<MoqtRole> role;
};
// These codes do not appear on the wire.
enum class QUICHE_EXPORT MoqtForwardingPreference : uint8_t {
kTrack = 0x0,
kGroup = 0x1,
kObject = 0x2,
kDatagram = 0x3,
};
enum class QUICHE_EXPORT MoqtObjectStatus : uint64_t {
kNormal = 0x0,
kObjectDoesNotExist = 0x1,
kGroupDoesNotExist = 0x2,
kEndOfGroup = 0x3,
kEndOfTrack = 0x4,
kInvalidObjectStatus = 0x5,
};
MoqtObjectStatus IntegerToObjectStatus(uint64_t integer);
// The data contained in every Object message, although the message type
// implies some of the values. |payload_length| has no value if the length
// is unknown (because it runs to the end of the stream.)
struct QUICHE_EXPORT MoqtObject {
uint64_t subscribe_id;
uint64_t track_alias;
uint64_t group_id;
uint64_t object_id;
uint64_t object_send_order;
MoqtObjectStatus object_status;
MoqtForwardingPreference forwarding_preference;
std::optional<uint64_t> payload_length;
};
enum class QUICHE_EXPORT MoqtFilterType : uint64_t {
kNone = 0x0,
kLatestGroup = 0x1,
kLatestObject = 0x2,
kAbsoluteStart = 0x3,
kAbsoluteRange = 0x4,
};
struct QUICHE_EXPORT MoqtSubscribe {
uint64_t subscribe_id;
uint64_t track_alias;
std::string track_namespace;
std::string track_name;
// The combinations of these that have values indicate the filter type.
// SG: Start Group; SO: Start Object; EG: End Group; EO: End Object;
// (none): KLatestObject
// SO: kLatestGroup (must be zero)
// SG, SO: kAbsoluteStart
// SG, SO, EG, EO: kAbsoluteRange
// SG, SO, EG: kAbsoluteRange (request whole last group)
// All other combinations are invalid.
std::optional<uint64_t> start_group;
std::optional<uint64_t> start_object;
std::optional<uint64_t> end_group;
std::optional<uint64_t> end_object;
// If the mode is kNone, the these are std::nullopt.
std::optional<std::string> authorization_info;
};
// Deduce the filter type from the combination of group and object IDs. Returns
// kNone if the state of the subscribe is invalid.
MoqtFilterType GetFilterType(const MoqtSubscribe& message);
struct QUICHE_EXPORT MoqtSubscribeOk {
uint64_t subscribe_id;
// The message uses ms, but expires is in us.
quic::QuicTimeDelta expires = quic::QuicTimeDelta::FromMilliseconds(0);
// If ContextExists on the wire is zero, largest_id has no value.
std::optional<FullSequence> largest_id;
};
enum class QUICHE_EXPORT SubscribeErrorCode : uint64_t {
kInternalError = 0x0,
kInvalidRange = 0x1,
kRetryTrackAlias = 0x2,
};
struct QUICHE_EXPORT MoqtSubscribeError {
uint64_t subscribe_id;
SubscribeErrorCode error_code;
std::string reason_phrase;
uint64_t track_alias;
};
struct QUICHE_EXPORT MoqtUnsubscribe {
uint64_t subscribe_id;
};
enum class QUICHE_EXPORT SubscribeDoneCode : uint64_t {
kUnsubscribed = 0x0,
kInternalError = 0x1,
kUnauthorized = 0x2,
kTrackEnded = 0x3,
kSubscriptionEnded = 0x4,
kGoingAway = 0x5,
kExpired = 0x6,
};
struct QUICHE_EXPORT MoqtSubscribeDone {
uint64_t subscribe_id;
SubscribeDoneCode status_code;
std::string reason_phrase;
std::optional<FullSequence> final_id;
};
struct QUICHE_EXPORT MoqtSubscribeUpdate {
uint64_t subscribe_id;
uint64_t start_group;
uint64_t start_object;
std::optional<uint64_t> end_group;
std::optional<uint64_t> end_object;
std::optional<std::string> authorization_info;
};
struct QUICHE_EXPORT MoqtAnnounce {
std::string track_namespace;
std::optional<std::string> authorization_info;
};
struct QUICHE_EXPORT MoqtAnnounceOk {
std::string track_namespace;
};
struct QUICHE_EXPORT MoqtAnnounceError {
std::string track_namespace;
MoqtAnnounceErrorCode error_code;
std::string reason_phrase;
};
struct QUICHE_EXPORT MoqtUnannounce {
std::string track_namespace;
};
enum class QUICHE_EXPORT MoqtTrackStatusCode : uint64_t {
kInProgress = 0x0,
kDoesNotExist = 0x1,
kNotYetBegun = 0x2,
kFinished = 0x3,
kStatusNotAvailable = 0x4,
};
struct QUICHE_EXPORT MoqtTrackStatus {
std::string track_namespace;
std::string track_name;
MoqtTrackStatusCode status_code;
uint64_t last_group;
uint64_t last_object;
};
struct QUICHE_EXPORT MoqtAnnounceCancel {
std::string track_namespace;
};
struct QUICHE_EXPORT MoqtTrackStatusRequest {
std::string track_namespace;
std::string track_name;
};
struct QUICHE_EXPORT MoqtGoAway {
std::string new_session_uri;
};
std::string MoqtMessageTypeToString(MoqtMessageType message_type);
std::string MoqtForwardingPreferenceToString(
MoqtForwardingPreference preference);
MoqtForwardingPreference GetForwardingPreference(MoqtMessageType type);
MoqtMessageType GetMessageTypeForForwardingPreference(
MoqtForwardingPreference preference);
} // namespace moqt
#endif // QUICHE_QUIC_MOQT_MOQT_MESSAGES_H_