From ae5b4aa79682393fa8328b8ac8766f8a3a3a6481 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 3 Mar 2026 10:38:43 +0100 Subject: [PATCH 01/30] Updated CHANGELOG --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83d5f68..7d9485f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file. -## [v0.0.1] - 2024-XX-XX +## [v0.0.1] - 2026-03-03 -- First alpha release +- First alpha release (homemade QUIC stack) + +## [v0.0.2] - XXXX-XX-XX + +- Switched to picoquic as the underlying QUIC stack +- Added support for external logging functions From b40d343d355883550d0f3974aa83018f4bf5bc54 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 3 Mar 2026 13:06:18 +0100 Subject: [PATCH 02/30] Advertise MoQ v17 support --- src/imquic-moq.c | 8 ++++++-- src/imquic/moq.h | 12 +++++++----- src/moq.c | 2 ++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 3b8029d..c586148 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -812,8 +812,10 @@ const char *imquic_moq_version_str(imquic_moq_version version) { return "draft-ietf-moq-transport-15"; case IMQUIC_MOQ_VERSION_16: return "draft-ietf-moq-transport-16"; + case IMQUIC_MOQ_VERSION_17: + return "draft-ietf-moq-transport-17"; case IMQUIC_MOQ_VERSION_ANY: - return "draft-ietf-moq-transport-XX(-from--11-to-16)"; + return "draft-ietf-moq-transport-XX(-from--11-to-17)"; case IMQUIC_MOQ_VERSION_ANY_LEGACY: return "draft-ietf-moq-transport-XX(-from-11-to-14)"; default: break; @@ -835,8 +837,10 @@ static const char *imquic_moq_version_alpn(imquic_moq_version version) { return "moq-15"; case IMQUIC_MOQ_VERSION_16: return "moq-16"; + case IMQUIC_MOQ_VERSION_17: + return "moq-17"; case IMQUIC_MOQ_VERSION_ANY: - return "moq-16,moq-15,moq-14,moq-13,moq-12,moq-11,moq-00"; + return "moq-17,moq-16,moq-15,moq-14,moq-13,moq-12,moq-11,moq-00"; case IMQUIC_MOQ_VERSION_ANY_LEGACY: return "moq-14,moq-13,moq-12,moq-11,moq-00"; default: break; diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 585fa14..cdf68a1 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -39,8 +39,8 @@ * The reason for this separation of version negotiation in different * groups is due to the incompatibility in the messaging on the wire, which * saw a few breaking changes. At the time of writing, this stack - * supports MoQ versions from v11 (\ref IMQUIC_MOQ_VERSION_11) up to v16 - * (\ref IMQUIC_MOQ_VERSION_16), but not all versions will be supported + * supports MoQ versions from v11 (\ref IMQUIC_MOQ_VERSION_11) up to v17 + * (\ref IMQUIC_MOQ_VERSION_17), but not all versions will be supported * forever. It should also be pointed out that not all features of all * versions are currently supported, so there may be some missing functionality * depending on which version you decide to negotiate. The \ref IMQUIC_MOQ_VERSION_MIN @@ -763,7 +763,7 @@ const char *imquic_moq_reset_stream_code_str(imquic_moq_reset_stream_code code); IMQUIC_CONFIG_TLS_PASSWORD, cert_pwd, IMQUIC_CONFIG_LOCAL_PORT, 9000, IMQUIC_CONFIG_WEBTRANSPORT, TRUE, - IMQUIC_CONFIG_MOQ_VERSION, IMQUIC_MOQ_VERSION_16, + IMQUIC_CONFIG_MOQ_VERSION, IMQUIC_MOQ_VERSION_17, IMQUIC_CONFIG_DONE, NULL); \endverbatim * to create a QUIC server that will automatically negotiate MoQ over @@ -796,7 +796,7 @@ imquic_server *imquic_create_moq_server(const char *name, ...); IMQUIC_CONFIG_REMOTE_HOST, "127.0.0.1", IMQUIC_CONFIG_REMOTE_PORT, 9000, IMQUIC_CONFIG_WEBTRANSPORT, TRUE, - IMQUIC_CONFIG_MOQ_VERSION, IMQUIC_MOQ_VERSION_16, + IMQUIC_CONFIG_MOQ_VERSION, IMQUIC_MOQ_VERSION_17, IMQUIC_CONFIG_HTTP3_PATH, "/moq", IMQUIC_CONFIG_DONE, NULL); @@ -1080,7 +1080,9 @@ typedef enum imquic_moq_version { IMQUIC_MOQ_VERSION_15 = 0xff00000F, /* Draft version -16 */ IMQUIC_MOQ_VERSION_16 = 0xff000010, - IMQUIC_MOQ_VERSION_MAX = IMQUIC_MOQ_VERSION_16, + /* Draft version -17 */ + IMQUIC_MOQ_VERSION_17 = 0xff000011, + IMQUIC_MOQ_VERSION_MAX = IMQUIC_MOQ_VERSION_17, /* Any version starting from v15: for client, it means offer all supported versions; * for servers, it means accept the first supported offered version */ IMQUIC_MOQ_VERSION_ANY = 0xff0000ff, diff --git a/src/moq.c b/src/moq.c index 6f3fe4b..0aac633 100644 --- a/src/moq.c +++ b/src/moq.c @@ -56,6 +56,8 @@ static imquic_moq_version imquic_moq_version_from_alpn(const char *alpn, imquic_ return fallback; if(!strcasecmp(alpn, "moq-00")) return IMQUIC_MOQ_VERSION_ANY_LEGACY; + else if(!strcasecmp(alpn, "moq-17")) + return IMQUIC_MOQ_VERSION_17; else if(!strcasecmp(alpn, "moq-16")) return IMQUIC_MOQ_VERSION_16; else if(!strcasecmp(alpn, "moq-15")) From 876d09ccc13a54d4c0802c3778fdcc73ff59ef8d Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 3 Mar 2026 18:56:43 +0100 Subject: [PATCH 03/30] Added methods for reading and writing MoQ varints --- src/moq.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/moq.c b/src/moq.c index 0aac633..006a05d 100644 --- a/src/moq.c +++ b/src/moq.c @@ -35,6 +35,10 @@ static GHashTable *moq_sessions = NULL; static imquic_mutex moq_mutex = IMQUIC_MUTEX_INITIALIZER; +/* MoQ's flavour of varint (introduced in v17) */ +uint64_t imquic_read_moqint(uint8_t *bytes, size_t blen, uint8_t *length); +uint8_t imquic_write_moqint(uint64_t number, uint8_t *bytes, size_t blen); + /* Initialization */ static void imquic_moq_context_destroy(imquic_moq_context *moq); static void imquic_moq_context_free(const imquic_refcount *moq_ref); @@ -8424,6 +8428,140 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { return 0; } +/* Reading and writing MoQ's flavour of variable size integers */ +uint64_t imquic_read_moqint(uint8_t *bytes, size_t blen, uint8_t *length) { + if(length) + *length = 0; + if(bytes == NULL || blen == 0) + return 0; + if(bytes[0] == 0xFC) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "Invalid moqint code point\n"); + return 0; + } + /* Check how many bytes we need */ + uint8_t len = 0; + uint64_t res = 0; + if((bytes[0] >> 7) == 0) { + len = 1; + res = bytes[0]; + goto done; + } else if((bytes[0] >> 6) == 0x02) { + len = 2; + } else if((bytes[0] >> 5) == 0x06) { + len = 3; + } else if((bytes[0] >> 4) == 0x0E) { + len = 4; + } else if((bytes[0] >> 3) == 0x1E) { + len = 5; + } else if((bytes[0] >> 2) == 0x3E) { + len = 6; + } else if((bytes[0]) == 0xFE) { + len = 8; + } else if((bytes[0]) == 0xFF) { + len = 9; + } + if(len == 0 || len > blen) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "Invalid moqint (%"SCNu8" > %zu)\n", len, blen); + return 0; + } + if(len < 8) { + uint8_t temp = bytes[0] << len; + res = temp >> len; + } + for(uint8_t i=1; i Date: Wed, 4 Mar 2026 14:46:00 +0100 Subject: [PATCH 04/30] Removed support for all MoQ versions older than v16 (only leaves v16 and v17) --- examples/moq-interop-test.c | 12 +- examples/moq-pub-options.c | 2 +- examples/moq-pub.c | 35 +- examples/moq-relay-options.c | 2 +- examples/moq-relay.c | 113 +- examples/moq-sub-options.c | 2 +- examples/moq-sub.c | 101 +- examples/moq-test-options.c | 2 +- examples/moq-test.c | 32 +- examples/moq-utils.c | 75 +- src/imquic-moq.c | 36 +- src/imquic/moq.h | 133 +- src/internal/moq.h | 155 +- src/moq.c | 3256 +++++----------------------------- 14 files changed, 624 insertions(+), 3332 deletions(-) diff --git a/examples/moq-interop-test.c b/examples/moq-interop-test.c index 7cd9d6a..5f427a9 100644 --- a/examples/moq-interop-test.c +++ b/examples/moq-interop-test.c @@ -143,11 +143,11 @@ static void imquic_moq_interop_publish_namespace_accepted(imquic_connection *con static void imquic_moq_interop_publish_namespace_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); + imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); static void imquic_moq_interop_subscribe_accepted(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); static void imquic_moq_interop_subscribe_error(imquic_connection *conn, uint64_t request_id, - imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval); + imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); static void imquic_moq_interop_connection_gone(imquic_connection *conn); /* Main */ @@ -541,7 +541,7 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { .buffer = (uint8_t *)"test-track", .length = strlen("test-track") }; - imquic_moq_subscribe(conn, imquic_moq_get_next_request_id(conn), 0, &tns[0], &tn, NULL); + imquic_moq_subscribe(conn, imquic_moq_get_next_request_id(conn), &tns[0], &tn, NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("subscriber subscribed to non-existing track")); } else if((test->name == IMQUIC_INTEROP_ANNOUNCE_SUBSCRIBE || @@ -558,7 +558,7 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { .buffer = (uint8_t *)"test-track", .length = strlen("test-track") }; - imquic_moq_subscribe(conn, imquic_moq_get_next_request_id(conn), 0, &tns[0], &tn, NULL); + imquic_moq_subscribe(conn, imquic_moq_get_next_request_id(conn), &tns[0], &tn, NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("subscriber subscribed to track")); if(test->name == IMQUIC_INTEROP_SUBSCRIBE_BEFORE_ANNOUNCE) { @@ -630,7 +630,7 @@ static void imquic_moq_interop_publish_namespace_error(imquic_connection *conn, } static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { + imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { /* Depending on the test, we may or may not be done */ imquic_mutex_lock(&mutex); imquic_moq_interop_client *client = (imquic_moq_interop_client *)g_hash_table_lookup(connections, conn); @@ -672,7 +672,7 @@ static void imquic_moq_interop_subscribe_accepted(imquic_connection *conn, uint6 } static void imquic_moq_interop_subscribe_error(imquic_connection *conn, uint64_t request_id, - imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval) { + imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval) { /* Depending on the test, we may or may not be done */ imquic_mutex_lock(&mutex); imquic_moq_interop_client *client = (imquic_moq_interop_client *)g_hash_table_lookup(connections, conn); diff --git a/examples/moq-pub-options.c b/examples/moq-pub-options.c index 8e8a517..e7055f6 100644 --- a/examples/moq-pub-options.c +++ b/examples/moq-pub-options.c @@ -15,7 +15,7 @@ static GOptionContext *opts = NULL; gboolean demo_options_parse(demo_options *options, int argc, char *argv[]) { /* Supported command-line arguments */ GOptionEntry opt_entries[] = { - { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any|legacy" }, + { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any" }, { "track-namespace", 'n', 0, G_OPTION_ARG_STRING_ARRAY, &options->track_namespace, "MoQ track namespace to publish (can be called multiple times to create a tuple; default=none)", "namespace" }, { "track-name", 'N', 0, G_OPTION_ARG_STRING, &options->track_name, "MoQ track name to publish (default=none)", "name" }, { "first-group", 'f', 0, G_OPTION_ARG_INT64, &options->first_group, "First group ID to send (default=0; sends 'Prior Group ID Gap' extension for the first sent object in that group, if set))", "group_id" }, diff --git a/examples/moq-pub.c b/examples/moq-pub.c index 7c90cf2..5ae13cb 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -122,12 +122,6 @@ static void imquic_demo_ready(imquic_connection *conn) { imquic_moq_publish_namespace(conn, imquic_moq_get_next_request_id(conn), &tns[0], ¶ms); } else { /* We use PUBLISH */ - if(moq_version < IMQUIC_MOQ_VERSION_12) { - /* Version is too old, we can't: stop here */ - IMQUIC_LOG(IMQUIC_LOG_FATAL, "PUBLISH only supported starting from version 12\n"); - g_atomic_int_inc(&stop); - return; - } IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publishing namespace/track '%s--%s'\n", imquic_get_connection_name(conn), pub_tns, pub_tn); moq_request_id = imquic_moq_get_next_request_id(conn); gboolean forward = FALSE; @@ -192,29 +186,23 @@ static void imquic_demo_publish_error(imquic_connection *conn, uint64_t request_ g_atomic_int_inc(&stop); } -static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, +static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); const char *name = imquic_moq_track_str(tn, tn_buffer, sizeof(tn_buffer)); - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ expect the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64"/%"SCNu64")\n", - imquic_get_connection_name(conn), ns, name, request_id, track_alias); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64")\n", - imquic_get_connection_name(conn), ns, name, request_id); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64")\n", + imquic_get_connection_name(conn), ns, name, request_id); if(pub_tns == NULL || strcasecmp(ns, pub_tns) || strcasecmp(name, pub_tn)) { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Unknown namespace or track\n", imquic_get_connection_name(conn)); - imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DOES_NOT_EXIST, "Unknown namespace or track", track_alias, 0); + imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DOES_NOT_EXIST, "Unknown namespace or track", 0); return; } if(options.publish || g_atomic_int_get(&send_objects)) { /* FIXME In this demo, we only allow one subscriber at a time, * as we expect a relay to mediate between us and subscribers */ IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] We already have a subscriber\n", imquic_get_connection_name(conn)); - imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DUPLICATE_SUBSCRIPTION, "We already have a subscriber", track_alias, 0); + imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DUPLICATE_SUBSCRIPTION, "We already have a subscriber", 0); return; } /* TODO Check if it matches our published namespace */ @@ -256,8 +244,6 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req } /* Accept the subscription */ moq_request_id = request_id; - if(moq_version < IMQUIC_MOQ_VERSION_12) - moq_track_alias = track_alias; imquic_moq_request_parameters rparams; imquic_moq_request_parameters_init_defaults(&rparams); rparams.expires_set = TRUE; @@ -453,11 +439,9 @@ int main(int argc, char *argv[]) { IMQUIC_LOG(IMQUIC_LOG_INFO, "Early data support enabled (ticket file '%s')\n", options.ticket_file); if(options.moq_version != NULL) { if(!strcasecmp(options.moq_version, "any")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 11 and %d\n", IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); + IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between %d and %d\n", + IMQUIC_MOQ_VERSION_MIN - IMQUIC_MOQ_VERSION_BASE, IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); moq_version = IMQUIC_MOQ_VERSION_ANY; - } else if(!strcasecmp(options.moq_version, "legacy")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 6 and 10\n"); - moq_version = IMQUIC_MOQ_VERSION_ANY_LEGACY; } else { moq_version = IMQUIC_MOQ_VERSION_BASE + atoi(options.moq_version); if(moq_version < IMQUIC_MOQ_VERSION_MIN || moq_version > IMQUIC_MOQ_VERSION_MAX) { @@ -495,11 +479,6 @@ int main(int argc, char *argv[]) { IMQUIC_LOG(IMQUIC_LOG_INFO, "First object: %"SCNu64" (will send the 'Prior Object ID Gap' extension)\n", options.first_object); if(options.publish) { IMQUIC_LOG(IMQUIC_LOG_INFO, "Will use PUBLISH instead of PUBLISH_NAMESPACE + SUBSCRIBE\n"); - if(moq_version > IMQUIC_MOQ_VERSION_MIN && moq_version < IMQUIC_MOQ_VERSION_12) { - IMQUIC_LOG(IMQUIC_LOG_FATAL, "PUBLISH only supported starting from version 12\n"); - ret = 1; - goto done; - } } IMQUIC_LOG(IMQUIC_LOG_INFO, "Will use track_alias=%"SCNu64", if a version higher or equal than 12 is negotiated\n", options.track_alias); diff --git a/examples/moq-relay-options.c b/examples/moq-relay-options.c index d841cb9..37f9e04 100644 --- a/examples/moq-relay-options.c +++ b/examples/moq-relay-options.c @@ -15,7 +15,7 @@ static GOptionContext *opts = NULL; gboolean demo_options_parse(demo_options *options, int argc, char *argv[]) { /* Supported command-line arguments */ GOptionEntry opt_entries[] = { - { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any|legacy" }, + { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any" }, { "auth-info", 'a', 0, G_OPTION_ARG_STRING, &options->auth_info, "Auth info required to connect to this relay, if any (default=none)", "string" }, { "subscribe-auth-info", 'A', 0, G_OPTION_ARG_STRING, &options->sub_auth_info, "Auth info required to subscribe to feeds in this relay, if any (default=none)", "string" }, { "bind", 'b', 0, G_OPTION_ARG_STRING, &options->ip, "Local IP address to bind to (default=all interfaces)", "IP" }, diff --git a/examples/moq-relay.c b/examples/moq-relay.c index 8f0e684..f8f24dd 100644 --- a/examples/moq-relay.c +++ b/examples/moq-relay.c @@ -357,28 +357,16 @@ static void imquic_demo_alert_monitors(imquic_demo_moq_published_namespace *annc if(annc->announced && (mon->subscribe_options == IMQUIC_MOQ_WANT_NAMESPACE || mon->subscribe_options == IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE)) { /* The subscriber wants to be notified about new namespaces */ if(!done && !mon->published) { - /* Send a PUBLISH_NAMESPACE or a NAMESPACE, depending on the version */ + /* Send a NAMESPACE: we pass the full track namespace, + * the stack will automatically get the suffix for us */ mon->published = TRUE; - if(imquic_moq_get_version(mon->conn) <= IMQUIC_MOQ_VERSION_15) { - /* Use the legacy PUBLISH_NAMESPACE */ - uint64_t request_id = imquic_moq_get_next_request_id(mon->conn); - imquic_moq_publish_namespace(mon->conn, request_id, tns, NULL); - } else { - /* Use the new NAMESPACE: we pass the full track namespace, - * the stack will automatically get the suffix for us */ - imquic_moq_notify_namespace(mon->conn, mon->request_id, tns); - } + imquic_moq_notify_namespace(mon->conn, mon->request_id, tns); } else if(done && mon->published) { /* Send a PUBLISH_NAMESPACE_DONE or a NAMESPACE_DONE, depending on the version */ mon->published = FALSE; - if(imquic_moq_get_version(mon->conn) <= IMQUIC_MOQ_VERSION_15) { - /* Use the legacy PUBLISH_NAMESPACE */ - imquic_moq_publish_namespace_done(mon->conn, tns); - } else { - /* Use the new NAMESPACE_DONE: we pass the full track namespace, - * the stack will automatically get the suffix for us */ - imquic_moq_notify_namespace_done(mon->conn, mon->request_id, tns); - } + /* Send a NAMESPACE_DONE: we pass the full track namespace, + * the stack will automatically get the suffix for us */ + imquic_moq_notify_namespace_done(mon->conn, mon->request_id, tns); } } if(mon->subscribe_options != IMQUIC_MOQ_WANT_PUBLISH && mon->subscribe_options != IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE) { @@ -598,7 +586,7 @@ static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t reque g_hash_table_insert(publishers, conn, pub); } /* Let's keep track of it */ - annc = imquic_demo_moq_published_namespace_create(pub, ns, tns, (imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_16)); + annc = imquic_demo_moq_published_namespace_create(pub, ns, tns, FALSE); g_hash_table_insert(pub->namespaces, g_strdup(ns), annc); g_hash_table_insert(namespaces, g_strdup(ns), annc); } @@ -775,8 +763,6 @@ static void imquic_demo_incoming_track_status(imquic_connection *conn, uint64_t } imquic_mutex_unlock(&track->mutex); imquic_mutex_unlock(&mutex); - /* TODO We should make the track_alias mapping persistent for this subscriber */ - uint64_t track_alias = track->track_alias; imquic_moq_request_parameters rparams; imquic_moq_request_parameters_init_defaults(&rparams); rparams.expires_set = TRUE; @@ -787,30 +773,24 @@ static void imquic_demo_incoming_track_status(imquic_connection *conn, uint64_t rparams.largest_object_set = TRUE; rparams.largest_object = start; } - imquic_moq_accept_track_status(conn, request_id, track_alias, &rparams); + imquic_moq_accept_track_status(conn, request_id, &rparams); } -static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, +static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { /* We received a subscribe */ char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); const char *name = imquic_moq_track_str(tn, tn_buffer, sizeof(tn_buffer)); - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ expect the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64"/%"SCNu64")\n", - imquic_get_connection_name(conn), ns, name, request_id, track_alias); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64")\n", - imquic_get_connection_name(conn), ns, name, request_id); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64")\n", + imquic_get_connection_name(conn), ns, name, request_id); if(parameters->auth_token_set) imquic_moq_print_auth_info(conn, parameters->auth_token, parameters->auth_token_len); if(!imquic_moq_check_auth_info(conn, options.sub_auth_info, parameters->auth_token_set ? parameters->auth_token : NULL, parameters->auth_token_set ? parameters->auth_token_len : 0)) { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Incorrect authorization info provided\n", imquic_get_connection_name(conn)); - imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_UNAUTHORIZED, "Unauthorized access", track_alias, 0); + imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_UNAUTHORIZED, "Unauthorized access", 0); return; } if(name == NULL || strlen(name) == 0) @@ -822,7 +802,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req imquic_mutex_unlock(&mutex); IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Namespace not found\n", imquic_get_connection_name(conn)); - imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DOES_NOT_EXIST, "Namespace not found", track_alias, 0); + imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DOES_NOT_EXIST, "Namespace not found", 0); return; } /* Do we know this track already? */ @@ -846,15 +826,12 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req /* FIXME Should we return an error? */ imquic_mutex_unlock(&mutex); IMQUIC_LOG(IMQUIC_LOG_WARN, "Already subscribed with ID %"SCNu64"\n", request_id); - imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DUPLICATE_SUBSCRIPTION, "Already subscribed", track_alias, 0); + imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_DUPLICATE_SUBSCRIPTION, "Already subscribed", 0); return; } - if(imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_12) { - /* Starting from v12, the publisher (in this case the relay, since - * track_alias is handled hop-by-hop) always chooses the track_alias */ - track_alias = sub->relay_track_alias; - sub->relay_track_alias++; - } + /* Generate a track_alias */ + uint64_t track_alias = sub->relay_track_alias; + sub->relay_track_alias++; /* Create a subscription to this track */ imquic_demo_moq_subscription *s = imquic_demo_moq_subscription_create(sub, track, request_id, track_alias); g_hash_table_insert(sub->subscriptions_by_id, imquic_uint64_dup(request_id), s); @@ -914,12 +891,6 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req if(new_track) { track->request_id = imquic_moq_get_next_request_id(annc->pub->conn); g_hash_table_insert(annc->pub->subscriptions_by_id, imquic_uint64_dup(track->request_id), track); - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - track->track_alias = annc->pub->relay_track_alias; - track->track_alias_valid = TRUE; - annc->pub->relay_track_alias++; - g_hash_table_insert(annc->pub->subscriptions, imquic_uint64_dup(track->track_alias), track); - } /* We send a 'Largest Object' filter to the subscriber, we'll filter ourselves in case */ imquic_moq_request_parameters params; imquic_moq_request_parameters_init_defaults(¶ms); @@ -931,7 +902,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req params.forward = TRUE; params.subscription_filter_set = TRUE; params.subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - imquic_moq_subscribe(annc->pub->conn, track->request_id, track->track_alias, tns, tn, ¶ms); + imquic_moq_subscribe(annc->pub->conn, track->request_id, tns, tn, ¶ms); } imquic_mutex_unlock(&mutex); } @@ -962,12 +933,10 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req IMQUIC_LOG(IMQUIC_LOG_WARN, "No track found for that subscription\n"); return; } - if(imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_12) { - /* Starting from v12, the publisher always chooses the track_alias */ - track->track_alias = track_alias; - track->track_alias_valid = TRUE; - g_hash_table_insert(pub->subscriptions, imquic_uint64_dup(track->track_alias), track); - } + /* Keep track of the track_alias chosen by the publisher */ + track->track_alias = track_alias; + track->track_alias_valid = TRUE; + g_hash_table_insert(pub->subscriptions, imquic_uint64_dup(track->track_alias), track); track->extensions = imquic_moq_object_extensions_duplicate(track_extensions); /* Send a SUBSCRIBE_OK to all subscribers */ imquic_mutex_lock(&track->mutex); @@ -988,16 +957,10 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req imquic_mutex_unlock(&mutex); } -static void imquic_demo_subscribe_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval) { +static void imquic_demo_subscribe_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval) { /* Our subscription to a publisher was rejected */ - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ passed the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got an error subscribing to ID %"SCNu64"/%"SCNu64": error %d (%s)\n", - imquic_get_connection_name(conn), request_id, track_alias, error_code, reason); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got an error subscribing via ID %"SCNu64": error %d (%s)\n", - imquic_get_connection_name(conn), request_id, error_code, reason); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got an error subscribing via ID %"SCNu64": error %d (%s)\n", + imquic_get_connection_name(conn), request_id, error_code, reason); /* Find the track associated to this subscription */ imquic_mutex_lock(&mutex); imquic_demo_moq_publisher *pub = g_hash_table_lookup(publishers, conn); @@ -1018,7 +981,7 @@ static void imquic_demo_subscribe_error(imquic_connection *conn, uint64_t reques while(temp) { imquic_demo_moq_subscription *s = (imquic_demo_moq_subscription *)temp->data; if(s && s->sub && s->sub->conn) - imquic_moq_reject_subscribe(s->sub->conn, s->request_id, error_code, reason, s->track_alias, 0); + imquic_moq_reject_subscribe(s->sub->conn, s->request_id, error_code, reason, 0); temp = temp->next; } imquic_mutex_unlock(&track->mutex); @@ -1044,8 +1007,7 @@ static void imquic_demo_request_updated(imquic_connection *conn, uint64_t reques return; } /* Update the subscription */ - imquic_demo_moq_subscription *s = g_hash_table_lookup(sub->subscriptions_by_id, - imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_14 ? &sub_request_id : &request_id); + imquic_demo_moq_subscription *s = g_hash_table_lookup(sub->subscriptions_by_id, &sub_request_id); if(s == NULL) { imquic_mutex_unlock(&mutex); IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Subscriber not found\n", @@ -1161,24 +1123,15 @@ static void imquic_demo_incoming_subscribe_namespace(imquic_connection *conn, ui static void imquic_demo_incoming_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns) { /* We received an unsubscribe */ - char tns_buffer[256]; - const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); - uint32_t conn_moq_version = imquic_moq_get_version(conn); - if(conn_moq_version <= IMQUIC_MOQ_VERSION_14) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming unsubscribe for namespace prefix '%s'\n", - imquic_get_connection_name(conn), ns); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming unsubscribe for namespace via ID %"SCNu64"\n", - imquic_get_connection_name(conn), request_id); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming unsubscribe for namespace via ID %"SCNu64"\n", + imquic_get_connection_name(conn), request_id); /* FIXME Get rid of the associated monitor */ imquic_demo_moq_monitor *mon = NULL; imquic_mutex_lock(&mutex); GList *temp = monitors; while(temp) { mon = (imquic_demo_moq_monitor *)temp->data; - if(conn == mon->conn && ((conn_moq_version <= IMQUIC_MOQ_VERSION_14 && !strcasecmp(ns, mon->ns)) || - (conn_moq_version >= IMQUIC_MOQ_VERSION_15 && request_id == mon->request_id))) { + if(conn == mon->conn && request_id == mon->request_id) { monitors = g_list_delete_link(monitors, temp); imquic_demo_moq_monitor_destroy(mon); break; @@ -1519,11 +1472,9 @@ int main(int argc, char *argv[]) { if(options.moq_version != NULL) { if(!strcasecmp(options.moq_version, "any")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 11 and %d\n", IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); + IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between %d and %d\n", + IMQUIC_MOQ_VERSION_MIN - IMQUIC_MOQ_VERSION_BASE, IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); moq_version = IMQUIC_MOQ_VERSION_ANY; - } else if(!strcasecmp(options.moq_version, "legacy")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 6 and 10\n"); - moq_version = IMQUIC_MOQ_VERSION_ANY_LEGACY; } else { moq_version = IMQUIC_MOQ_VERSION_BASE + atoi(options.moq_version); if(moq_version < IMQUIC_MOQ_VERSION_MIN || moq_version > IMQUIC_MOQ_VERSION_MAX) { diff --git a/examples/moq-sub-options.c b/examples/moq-sub-options.c index 0b8ce70..4ce618a 100644 --- a/examples/moq-sub-options.c +++ b/examples/moq-sub-options.c @@ -15,7 +15,7 @@ static GOptionContext *opts = NULL; gboolean demo_options_parse(demo_options *options, int argc, char *argv[]) { /* Supported command-line arguments */ GOptionEntry opt_entries[] = { - { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any|legacy" }, + { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any" }, { "track-namespace", 'n', 0, G_OPTION_ARG_STRING_ARRAY, &options->track_namespace, "MoQ track namespace to subscribe to (can be called multiple times to create a tuple; default=none)", "namespace" }, { "track-name", 'N', 0, G_OPTION_ARG_STRING_ARRAY, &options->track_name, "MoQ track name to subscribe to (can be called multiple times to subscribe to multiple tracks; default=none)", "name" }, { "relay-auth-info", 'a', 0, G_OPTION_ARG_STRING, &options->relay_auth_info, "Auth info required to connect to the relay, if any (default=none)", "string" }, diff --git a/examples/moq-sub.c b/examples/moq-sub.c index 3bb16f1..ebd692f 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -166,7 +166,6 @@ static void imquic_demo_ready(imquic_connection *conn) { /* Let's subscribe to the provided namespace/name(s) */ int i = 0; uint64_t request_id = 0; - uint64_t track_alias = 0; imquic_moq_namespace tns[32]; /* FIXME */ while(options.track_namespace[i] != NULL) { const char *track_namespace = options.track_namespace[i]; @@ -193,24 +192,12 @@ static void imquic_demo_ready(imquic_connection *conn) { if(options.subscribe_namespace) { /* Only send a SUBSCRIBE_NAMESPACE: the relay will send us a * PUBLISH request when there's something we can subscribe to */ - if(moq_version < IMQUIC_MOQ_VERSION_12) { - /* Version is too old, we can't: stop here */ - IMQUIC_LOG(IMQUIC_LOG_FATAL, "PUBLISH only supported starting from version 12\n"); - g_atomic_int_inc(&stop); - return; - } - /* Check if we need to request forwarding right away, or if we'll ask send an update later */ params.forward_set = TRUE; params.forward = TRUE; - if(options.update_subscribe > 0 && imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_11 && (options.fetch == NULL || options.join_offset >= 0)) + if(options.update_subscribe > 0 && (options.fetch == NULL || options.join_offset >= 0)) params.forward = FALSE; imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), tns, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); return; - } else if(options.track_status && moq_version < IMQUIC_MOQ_VERSION_13) { - /* Version is too old, we can't: stop here */ - IMQUIC_LOG(IMQUIC_LOG_FATAL, "TRACK_STATUS only supported starting from version 13\n"); - g_atomic_int_inc(&stop); - return; } /* Parameters in case we need to FETCH */ imquic_moq_request_parameters fparams = params; @@ -223,7 +210,7 @@ static void imquic_demo_ready(imquic_connection *conn) { /* Check if we need to request forwarding right away, or if we'll ask send an update later */ params.forward_set = TRUE; params.forward = TRUE; - if(options.update_subscribe > 0 && imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_11 && (options.fetch == NULL || options.join_offset >= 0)) + if(options.update_subscribe > 0 && (options.fetch == NULL || options.join_offset >= 0)) params.forward = FALSE; params.subscriber_priority_set = TRUE; params.subscriber_priority = 128; @@ -239,18 +226,10 @@ static void imquic_demo_ready(imquic_connection *conn) { while(options.track_name[i] != NULL) { request_id = imquic_moq_get_next_request_id(conn); const char *track_name = options.track_name[i]; - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ passed the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] %s to '%s--%s' (%s), using ID %"SCNu64"/%"SCNu64"\n", - imquic_get_connection_name(conn), - ((options.fetch != NULL && options.join_offset < 0) ? "Fetching" : "Subscribing"), - ns, track_name, imquic_demo_payload_type_str(payload_type), request_id, track_alias); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] %s to '%s--%s' (%s), using ID %"SCNu64"\n", - imquic_get_connection_name(conn), - ((options.fetch != NULL && options.join_offset < 0) ? "Fetching" : "Subscribing"), - ns, track_name, imquic_demo_payload_type_str(payload_type), request_id); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] %s to '%s--%s' (%s), using ID %"SCNu64"\n", + imquic_get_connection_name(conn), + ((options.fetch != NULL && options.join_offset < 0) ? "Fetching" : "Subscribing"), + ns, track_name, imquic_demo_payload_type_str(payload_type), request_id); imquic_moq_name tn = { .buffer = (uint8_t *)track_name, .length = strlen(track_name) @@ -258,7 +237,7 @@ static void imquic_demo_ready(imquic_connection *conn) { if(options.fetch == NULL) { if(!options.track_status) { /* Send a SUBSCRIBE */ - imquic_moq_subscribe(conn, request_id, track_alias, &tns[0], &tn, ¶ms); + imquic_moq_subscribe(conn, request_id, &tns[0], &tn, ¶ms); if(!params.forward) request_ids = g_list_append(request_ids, imquic_uint64_dup(request_id)); } else { @@ -276,13 +255,12 @@ static void imquic_demo_ready(imquic_connection *conn) { imquic_moq_standalone_fetch(conn, request_id, &tns[0], &tn, &range, &fparams); } else { /* Send a SUBSCRIBE first, we'll send the joining FETCH when the subscription is accepted */ - imquic_moq_subscribe(conn, request_id, track_alias, &tns[0], &tn, ¶ms); + imquic_moq_subscribe(conn, request_id, &tns[0], &tn, ¶ms); if(!params.forward) request_ids = g_list_append(request_ids, imquic_uint64_dup(request_id)); } } i++; - track_alias++; } if(!params.forward) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Scheduling a REQUEST_UPDATE in %d seconds\n", @@ -325,14 +303,10 @@ static void imquic_demo_incoming_namespace_done(imquic_connection *conn, uint64_ imquic_get_connection_name(conn), ns); } -static void imquic_demo_track_status_accepted(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters) { +static void imquic_demo_track_status_accepted(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Track status %"SCNu64" accepted (expires=%"SCNu64"; %s order)\n", imquic_get_connection_name(conn), request_id, parameters->expires, imquic_moq_group_order_str(parameters->group_order)); - if(imquic_moq_get_version(conn) <= IMQUIC_MOQ_VERSION_14) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Track Alias: %"SCNu64"\n", - imquic_get_connection_name(conn), track_alias); - } if(parameters->largest_object_set) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Largest Location: %"SCNu64"/%"SCNu64"\n", imquic_get_connection_name(conn), @@ -355,11 +329,8 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req imquic_get_connection_name(conn), request_id, parameters->expires, imquic_moq_group_order_str(parameters->group_order), g_list_length(track_extensions)); - if(imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_12) { - /* Starting from v12, the publisher always chooses the track_alias */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Track Alias: %"SCNu64"\n", - imquic_get_connection_name(conn), track_alias); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Track Alias: %"SCNu64"\n", + imquic_get_connection_name(conn), track_alias); if(parameters->largest_object_set) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Largest Location: %"SCNu64"/%"SCNu64"\n", imquic_get_connection_name(conn), @@ -406,15 +377,9 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req } } -static void imquic_demo_subscribe_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval) { - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ passed the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got an error subscribing to ID %"SCNu64"/%"SCNu64": error %d (%s)\n", - imquic_get_connection_name(conn), request_id, track_alias, error_code, reason); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got an error subscribing via ID %"SCNu64": error %d (%s)\n", - imquic_get_connection_name(conn), request_id, error_code, reason); - } +static void imquic_demo_subscribe_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval) { + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got an error subscribing via ID %"SCNu64": error %d (%s)\n", + imquic_get_connection_name(conn), request_id, error_code, reason); /* Stop here */ g_atomic_int_inc(&stop); } @@ -469,7 +434,7 @@ static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t reque rparams.subscription_filter.type = filter_type; rparams.subscription_filter.start_location = start_location; rparams.subscription_filter.end_group = end_location_sub.group; - if(options.update_subscribe > 0 && imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_11 && (options.fetch == NULL || options.join_offset >= 0)) { + if(options.update_subscribe > 0 && (options.fetch == NULL || options.join_offset >= 0)) { rparams.forward = FALSE; IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Scheduling a REQUEST_UPDATE in %d seconds\n", imquic_get_connection_name(conn), options.update_subscribe); @@ -671,7 +636,6 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje } else if(object->request_id == 0 && payload_type == DEMO_TYPE_MP4) { /* FIXME Ugly hack: if this is mp4, and our response to request ID 0, subscribe to another track */ uint64_t request_id = 1; - uint64_t track_alias = 1; const char *track_name = "1.m4s"; imquic_moq_namespace tns[32]; /* FIXME */ int i = 0; @@ -684,14 +648,8 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje } char tns_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ passed the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscribing to %s/%s (%s), using ID %"SCNu64"/%"SCNu64"\n", - imquic_get_connection_name(conn), ns, track_name, imquic_demo_payload_type_str(payload_type), request_id, track_alias); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscribing to %s/%s (%s), using ID %"SCNu64"\n", - imquic_get_connection_name(conn), ns, track_name, imquic_demo_payload_type_str(payload_type), request_id); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscribing to %s/%s (%s), using ID %"SCNu64"\n", + imquic_get_connection_name(conn), ns, track_name, imquic_demo_payload_type_str(payload_type), request_id); imquic_moq_name tn = { .buffer = (uint8_t *)track_name, .length = strlen(track_name) @@ -718,7 +676,7 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje params.subscription_filter.type = filter_type; params.subscription_filter.start_location = start_location; params.subscription_filter.end_group = end_location_sub.group; - imquic_moq_subscribe(conn, request_id, track_alias, &tns[0], &tn, ¶ms); + imquic_moq_subscribe(conn, request_id, &tns[0], &tn, ¶ms); } if(object->end_of_stream) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Stream closed (status '%s' and eos=%d)\n", @@ -802,11 +760,9 @@ int main(int argc, char *argv[]) { IMQUIC_LOG(IMQUIC_LOG_INFO, "Early data support enabled (ticket file '%s')\n", options.ticket_file); if(options.moq_version != NULL) { if(!strcasecmp(options.moq_version, "any")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 11 and %d\n", IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); + IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between %d and %d\n", + IMQUIC_MOQ_VERSION_MIN - IMQUIC_MOQ_VERSION_BASE, IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); moq_version = IMQUIC_MOQ_VERSION_ANY; - } else if(!strcasecmp(options.moq_version, "legacy")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 6 and 10\n"); - moq_version = IMQUIC_MOQ_VERSION_ANY_LEGACY; } else { moq_version = IMQUIC_MOQ_VERSION_BASE + atoi(options.moq_version); if(moq_version < IMQUIC_MOQ_VERSION_MIN || moq_version > IMQUIC_MOQ_VERSION_MAX) { @@ -833,20 +789,8 @@ int main(int argc, char *argv[]) { goto done; } } else if(options.subscribe_namespace) { - if(moq_version > IMQUIC_MOQ_VERSION_MIN && moq_version < IMQUIC_MOQ_VERSION_12) { - /* Version is too old, we can't: stop here */ - IMQUIC_LOG(IMQUIC_LOG_FATAL, "PUBLISH only supported starting from version 12\n"); - ret = 1; - goto done; - } IMQUIC_LOG(IMQUIC_LOG_INFO, "Using a SUBSCRIBE_NAMESPACE and incoming PUBLISH for the subscription\n"); } else if(options.track_status) { - if(moq_version > IMQUIC_MOQ_VERSION_MIN && moq_version < IMQUIC_MOQ_VERSION_13) { - /* Version is too old, we can't: stop here */ - IMQUIC_LOG(IMQUIC_LOG_FATAL, "TRACK_STATUS only supported starting from version 13\n"); - ret = 1; - goto done; - } IMQUIC_LOG(IMQUIC_LOG_INFO, "Using a TRACK_STATUS for simulating the subscription\n"); } else { IMQUIC_LOG(IMQUIC_LOG_INFO, "Using a SUBSCRIBE for the subscription\n"); @@ -1057,9 +1001,8 @@ int main(int argc, char *argv[]) { params.subscription_filter.type = filter_type; params.subscription_filter.start_location = start_location; params.subscription_filter.end_group = end_location_sub.group; - uint64_t request_id = *rid, sub_request_id = request_id; - if(imquic_moq_get_version(moq_conn) >= IMQUIC_MOQ_VERSION_14) - request_id = imquic_moq_get_next_request_id(moq_conn); + uint64_t request_id = imquic_moq_get_next_request_id(moq_conn), + sub_request_id = request_id; IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Sending a REQUEST_UPDATE for ID %"SCNu64" (ID %"SCNu64")\n", imquic_get_connection_name(moq_conn), *rid, request_id); imquic_moq_update_request(moq_conn, request_id, sub_request_id, ¶ms); diff --git a/examples/moq-test-options.c b/examples/moq-test-options.c index cd846bc..0486f96 100644 --- a/examples/moq-test-options.c +++ b/examples/moq-test-options.c @@ -15,7 +15,7 @@ static GOptionContext *opts = NULL; gboolean demo_options_parse(demo_options *options, int argc, char *argv[]) { /* Supported command-line arguments */ GOptionEntry opt_entries[] = { - { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any|legacy" }, + { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any" }, { "bind", 'b', 0, G_OPTION_ARG_STRING, &options->ip, "Local IP address to bind to (default=all interfaces)", "IP" }, { "port", 'p', 0, G_OPTION_ARG_INT, &options->port, "Local port to bind to (default=0, random)", "port" }, { "raw-quic", 'q', 0, G_OPTION_ARG_NONE, &options->raw_quic, "Whether raw QUIC should be offered for MoQ connections or not (default=no)", NULL }, diff --git a/examples/moq-test.c b/examples/moq-test.c index 6677425..780c96b 100644 --- a/examples/moq-test.c +++ b/examples/moq-test.c @@ -43,6 +43,7 @@ static imquic_moq_version moq_version = IMQUIC_MOQ_VERSION_ANY; static GMutex mutex; static GHashTable *connections = NULL, *subscribers = NULL; static void *imquic_demo_tester_thread(void *data); +static uint64_t moq_track_alias = 0; /* Namespace tuple fields */ typedef enum imquic_demo_tuple_field { @@ -306,20 +307,14 @@ static void imquic_demo_ready(imquic_connection *conn) { peer ? peer : "unknown implementation"); } -static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, +static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { /* We received a subscribe */ char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); const char *name = imquic_moq_track_str(tn, tn_buffer, sizeof(tn_buffer)); - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_12) { - /* Older versions of MoQ expect the track alias in the SUBSCRIBE */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64"/%"SCNu64")\n", - imquic_get_connection_name(conn), ns, name, request_id, track_alias); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64")\n", - imquic_get_connection_name(conn), ns, name, request_id); - } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming subscribe for '%s--%s' (ID %"SCNu64")\n", + imquic_get_connection_name(conn), ns, name, request_id); if(parameters->auth_token_set) imquic_moq_print_auth_info(conn, parameters->auth_token, parameters->auth_token_len); /* Parse the namespace tuple to a test profile */ @@ -327,7 +322,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req char err[256]; int res = imquic_demo_tuple_to_test(conn, tns, test, err, sizeof(err)); if(res != 0) { - imquic_moq_reject_subscribe(conn, request_id, res, err, track_alias, 0); + imquic_moq_reject_subscribe(conn, request_id, res, err, 0); return; } g_mutex_lock(&mutex); @@ -346,11 +341,13 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req return; } /* Create a subscription to this track */ - imquic_demo_moq_subscription *s = imquic_demo_moq_subscription_create(sub, request_id, track_alias); + uint64_t new_track_alias = moq_track_alias; + moq_track_alias++; + imquic_demo_moq_subscription *s = imquic_demo_moq_subscription_create(sub, request_id, new_track_alias); memcpy(s->test, test, sizeof(test)); s->forward = parameters->forward; g_hash_table_insert(sub->subscriptions_by_id, imquic_uint64_dup(request_id), s); - g_hash_table_insert(sub->subscriptions, imquic_uint64_dup(track_alias), s); + g_hash_table_insert(sub->subscriptions, imquic_uint64_dup(new_track_alias), s); g_mutex_unlock(&mutex); /* Check the filter */ uint64_t filter_type = parameters->subscription_filter_set ? @@ -387,7 +384,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req rparams.expires = 0; rparams.group_order_set = TRUE; rparams.group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - imquic_moq_accept_subscribe(conn, request_id, track_alias, &rparams, NULL); + imquic_moq_accept_subscribe(conn, request_id, new_track_alias, &rparams, NULL); /* Spawn thread to send objects */ GError *error = NULL; s->thread = g_thread_try_new("moq-test", &imquic_demo_tester_thread, s, &error); @@ -411,8 +408,7 @@ static void imquic_demo_request_updated(imquic_connection *conn, uint64_t reques return; } /* Update the subscription */ - imquic_demo_moq_subscription *s = g_hash_table_lookup(sub->subscriptions_by_id, - imquic_moq_get_version(conn) >= IMQUIC_MOQ_VERSION_14 ? &sub_request_id : &request_id); + imquic_demo_moq_subscription *s = g_hash_table_lookup(sub->subscriptions_by_id, &sub_request_id); if(s && !s->fetch && parameters->forward_set) { /* TODO Update start location and end group too */ s->forward = parameters->forward; @@ -827,11 +823,9 @@ int main(int argc, char *argv[]) { if(options.moq_version != NULL) { if(!strcasecmp(options.moq_version, "any")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 11 and %d\n", IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); + IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between %d and %d\n", + IMQUIC_MOQ_VERSION_MIN - IMQUIC_MOQ_VERSION_BASE, IMQUIC_MOQ_VERSION_MAX - IMQUIC_MOQ_VERSION_BASE); moq_version = IMQUIC_MOQ_VERSION_ANY; - } else if(!strcasecmp(options.moq_version, "legacy")) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "Negotiating version of MoQ between 6 and 10\n"); - moq_version = IMQUIC_MOQ_VERSION_ANY_LEGACY; } else { moq_version = IMQUIC_MOQ_VERSION_BASE + atoi(options.moq_version); if(moq_version < IMQUIC_MOQ_VERSION_MIN || moq_version > IMQUIC_MOQ_VERSION_MAX) { diff --git a/examples/moq-utils.c b/examples/moq-utils.c index 2f8acfc..2db6e6e 100644 --- a/examples/moq-utils.c +++ b/examples/moq-utils.c @@ -74,41 +74,29 @@ void imquic_moq_object_extension_cleanup(imquic_moq_object_extension *extension) int imquic_moq_auth_info_to_bytes(imquic_connection *conn, const char *auth_info, uint8_t *auth, size_t *authlen) { if(conn == NULL || auth_info == NULL || auth == NULL || authlen == 0) return -1; - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_11) { - /* Just copy the string to the buffer */ - *authlen = strlen(auth_info); - memcpy(auth, auth_info, *authlen); - } else { - /* Serialize the token using the USE_VALUE alias type */ - imquic_moq_auth_token token = { 0 }; - token.alias_type = IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE; - token.token_type_set = TRUE; - token.token_type = 0; /* FIXME */ - token.token_value.buffer = (uint8_t *)auth_info; - token.token_value.length = strlen(auth_info); - size_t offset = imquic_moq_build_auth_token(&token, auth, *authlen); - if(offset == 0) - return -1; - *authlen = offset; - } + /* Serialize the token using the USE_VALUE alias type */ + imquic_moq_auth_token token = { 0 }; + token.alias_type = IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE; + token.token_type_set = TRUE; + token.token_type = 0; /* FIXME */ + token.token_value.buffer = (uint8_t *)auth_info; + token.token_value.length = strlen(auth_info); + size_t offset = imquic_moq_build_auth_token(&token, auth, *authlen); + if(offset == 0) + return -1; + *authlen = offset; return 0; } void imquic_moq_print_auth_info(imquic_connection *conn, uint8_t *auth, size_t authlen) { if(conn == NULL || auth == NULL || authlen == 0) return; - if(imquic_moq_get_version(conn) < IMQUIC_MOQ_VERSION_11) { - /* String */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Authorization info: %.*s\n", - imquic_get_connection_name(conn), (int)authlen, auth); - } else { - /* Data (hex) */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Authorization info: ", - imquic_get_connection_name(conn)); - for(size_t i=0; iprotocol != IMQUIC_MOQ) { @@ -530,7 +530,7 @@ void imquic_set_subscribe_accepted_cb(imquic_endpoint *endpoint, } void imquic_set_subscribe_error_cb(imquic_endpoint *endpoint, - void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_codes, const char *reason, uint64_t track_alias, uint64_t retry_interval)) { + void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_codes, const char *reason, uint64_t retry_interval)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -743,7 +743,7 @@ void imquic_set_incoming_track_status_cb(imquic_endpoint *endpoint, } void imquic_set_track_status_accepted_cb(imquic_endpoint *endpoint, - void (* track_status_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters)) { + void (* track_status_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -800,24 +800,12 @@ void imquic_set_moq_connection_gone_cb(imquic_endpoint *endpoint, /* Versions */ const char *imquic_moq_version_str(imquic_moq_version version) { switch(version) { - case IMQUIC_MOQ_VERSION_11: - return "draft-ietf-moq-transport-11"; - case IMQUIC_MOQ_VERSION_12: - return "draft-ietf-moq-transport-12"; - case IMQUIC_MOQ_VERSION_13: - return "draft-ietf-moq-transport-13"; - case IMQUIC_MOQ_VERSION_14: - return "draft-ietf-moq-transport-14"; - case IMQUIC_MOQ_VERSION_15: - return "draft-ietf-moq-transport-15"; case IMQUIC_MOQ_VERSION_16: return "draft-ietf-moq-transport-16"; case IMQUIC_MOQ_VERSION_17: return "draft-ietf-moq-transport-17"; case IMQUIC_MOQ_VERSION_ANY: - return "draft-ietf-moq-transport-XX(-from--11-to-17)"; - case IMQUIC_MOQ_VERSION_ANY_LEGACY: - return "draft-ietf-moq-transport-XX(-from-11-to-14)"; + return "draft-ietf-moq-transport-XX(-from--16-to-17)"; default: break; } return NULL; @@ -825,24 +813,12 @@ const char *imquic_moq_version_str(imquic_moq_version version) { static const char *imquic_moq_version_alpn(imquic_moq_version version) { switch(version) { - case IMQUIC_MOQ_VERSION_11: - return "moq-11,moq-00"; - case IMQUIC_MOQ_VERSION_12: - return "moq-12,moq-00"; - case IMQUIC_MOQ_VERSION_13: - return "moq-13,moq-00"; - case IMQUIC_MOQ_VERSION_14: - return "moq-14,moq-00"; - case IMQUIC_MOQ_VERSION_15: - return "moq-15"; case IMQUIC_MOQ_VERSION_16: return "moq-16"; case IMQUIC_MOQ_VERSION_17: return "moq-17"; case IMQUIC_MOQ_VERSION_ANY: - return "moq-17,moq-16,moq-15,moq-14,moq-13,moq-12,moq-11,moq-00"; - case IMQUIC_MOQ_VERSION_ANY_LEGACY: - return "moq-14,moq-13,moq-12,moq-11,moq-00"; + return "moq-17,moq-16"; default: break; } return NULL; @@ -867,8 +843,6 @@ const char *imquic_moq_object_status_str(imquic_moq_object_status status) { switch(status) { case IMQUIC_MOQ_NORMAL_OBJECT: return "NORMAL_OBJECT"; - case IMQUIC_MOQ_OBJECT_DOESNT_EXIST: - return "OBJECT_DOESNT_EXIST"; case IMQUIC_MOQ_END_OF_GROUP: return "END_OF_GROUP"; case IMQUIC_MOQ_END_OF_TRACK: diff --git a/src/imquic/moq.h b/src/imquic/moq.h index cdf68a1..9174f24 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -34,12 +34,8 @@ * \ref IMQUIC_MOQ_VERSION_ANY , which means that for clients it will offer * all supported versions, while for servers it will accept the first * offered among the supported ones, when negotiared via ALPN or - * WebTransort protocol; a "legacy" version called \ref IMQUIC_MOQ_VERSION_ANY_LEGACY - * is available, to negotiate any supported version between v11 and v14. - * The reason for this separation of version negotiation in different - * groups is due to the incompatibility in the messaging on the wire, which - * saw a few breaking changes. At the time of writing, this stack - * supports MoQ versions from v11 (\ref IMQUIC_MOQ_VERSION_11) up to v17 + * WebTransort protocol. At the time of writing, this stack + * supports MoQ versions from v16 (\ref IMQUIC_MOQ_VERSION_16) up to v17 * (\ref IMQUIC_MOQ_VERSION_17), but not all versions will be supported * forever. It should also be pointed out that not all features of all * versions are currently supported, so there may be some missing functionality @@ -410,8 +406,7 @@ typedef struct imquic_moq_subscription_filter { uint64_t end_group; } imquic_moq_subscription_filter; -/*! \brief Subscribe options for namespaces - * \note Only supported since version -16 of the protocol */ +/*! \brief Subscribe options for namespaces */ typedef enum imquic_moq_subscribe_namespace_options { IMQUIC_MOQ_WANT_PUBLISH = 0x0, IMQUIC_MOQ_WANT_NAMESPACE = 0x1, @@ -423,10 +418,7 @@ typedef enum imquic_moq_subscribe_namespace_options { const char *imquic_moq_subscribe_namespace_options_str(imquic_moq_subscribe_namespace_options type); /*! \brief MoQ request parameters - * \note This struct is used in the MoQ API signatures even when the - * negotiated version of MoQ is lower than v15, that is when most of - * the properties below were fields in the messages themselves, rather - * than parameters as they are now. The library takes care of the + * \note The library takes care of the * serialization/deserialization process automatically, so you can * refer to this struct from an application perspective, and the * library will take care of the rest. Notice that not all of these @@ -444,18 +436,6 @@ typedef struct imquic_moq_request_parameters { gboolean delivery_timeout_set; /*! \brief Value of the DELIVERY_TIMEOUT parameter */ uint64_t delivery_timeout; - /*! \brief Whether the MAX_CACHE_DURATION parameter is set - * \note Deprecated in v16, and moved to Track Extensions */ - gboolean max_cache_duration_set; - /*! \brief Value of the MAX_CACHE_DURATION parameter - * \note Deprecated in v16, and moved to Track Extensions */ - uint64_t max_cache_duration; - /*! \brief Whether the PUBLISHER_PRIORITY parameter is set - * \note Deprecated in v16, and moved to Track Extensions */ - gboolean publisher_priority_set; - /*! \brief Value of the PUBLISHER_PRIORITY parameter - * \note Deprecated in v16, and moved to Track Extensions */ - uint8_t publisher_priority; /*! \brief Whether the SUBSCRIBER_PRIORITY parameter is set */ gboolean subscriber_priority_set; /*! \brief Value of the SUBSCRIBER_PRIORITY parameter */ @@ -480,12 +460,6 @@ typedef struct imquic_moq_request_parameters { gboolean forward_set; /*! \brief Value of the FORWARD parameter */ gboolean forward; - /*! \brief Whether the DYNAMIC_GROUPS parameter is set - * \note Deprecated in v16, and moved to Track Extensions */ - gboolean dynamic_groups_set; - /*! \brief Value of the DYNAMIC_GROUPS parameter - * \note Deprecated in v16, and moved to Track Extensions */ - gboolean dynamic_groups; /*! \brief Whether the NEW_GROUP_REQUEST parameter is set */ gboolean new_group_request_set; /*! \brief Value of the NEW_GROUP_REQUEST parameter */ @@ -519,8 +493,6 @@ const char *imquic_moq_delivery_str(imquic_moq_delivery type); typedef enum imquic_moq_object_status { /*! \brief Normal object */ IMQUIC_MOQ_NORMAL_OBJECT = 0x0, - /*! \brief Object doesn't exist (deprecated in v16) */ - IMQUIC_MOQ_OBJECT_DOESNT_EXIST = 0x1, /*! \brief End of group */ IMQUIC_MOQ_END_OF_GROUP = 0x3, /*! \brief End of track */ @@ -553,15 +525,15 @@ typedef struct imquic_moq_object_extension { * \note The library will not try to interpret extensions and their * payload: this is always left up to applications */ typedef enum imquic_moq_extension_type { - /* Delivery Timeout (added in v16) */ + /* Delivery Timeout */ IMQUIC_MOQ_EXT_DELIVERY_TIMEOUT = 0x02, - /* Max Cache Duration (added in v16) */ + /* Max Cache Duration */ IMQUIC_MOQ_EXT_MAX_CACHE_DURATION = 0x04, - /* Default Publisher Priority (added in v16) */ + /* Default Publisher Priority */ IMQUIC_MOQ_EXT_DEFAULT_PUBLISHER_PRIORITY = 0x0E, - /* Default Group Order (added in v16) */ + /* Default Group Order */ IMQUIC_MOQ_EXT_DEFAULT_GROUP_ORDER = 0x22, - /* Dynamic Groups (added in v16) */ + /* Dynamic Groups */ IMQUIC_MOQ_EXT_DYNAMIC_GROUPS = 0x30, /* Prior Group ID Gap */ IMQUIC_MOQ_EXT_PRIOR_GROUP_ID_GAP = 0x3C, @@ -709,7 +681,6 @@ typedef enum imquic_moq_request_error_code { /* Others */ IMQUIC_MOQ_REQERR_PREFIX_OVERLAP = 0x30, IMQUIC_MOQ_REQERR_INVALID_JOINING_REQUEST_ID = 0x32, - IMQUIC_MOQ_REQERR_UNKNOWN_STATUS_IN_RANGE = 0x33, /* Deprecated in v16 */ } imquic_moq_request_error_code; /*! \brief Helper function to serialize to string the name of a imquic_moq_request_error_code value. * @param code The imquic_moq_request_error_code value @@ -902,7 +873,7 @@ void imquic_set_publish_error_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_subscribe Pointer to the function that will handle the incoming \c SUBSCRIBE */ void imquic_set_incoming_subscribe_cb(imquic_endpoint *endpoint, - void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, + void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when a * \c SUBSCRIBE we previously sent was accepted @@ -915,7 +886,7 @@ void imquic_set_subscribe_accepted_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param subscribe_error Pointer to the function that will fire when a \c SUBSCRIBE is rejected */ void imquic_set_subscribe_error_cb(imquic_endpoint *endpoint, - void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval)); + void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval)); /*! \brief Configure the callback function to be notified when an update * is received for a request (e.g., a \c SUBSCRIBE ) we previously sent * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -924,7 +895,6 @@ void imquic_set_request_updated_cb(imquic_endpoint *endpoint, void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when an OK * is received for a \c REQUEST_UPDATE we previously sent - * @note This was only added in v15, and so will never be fired on older versions. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param request_update_accepted Pointer to the function that will fire when a \c REQUEST_UPDATE is acknowledged */ void imquic_set_request_update_accepted_cb(imquic_endpoint *endpoint, @@ -1035,7 +1005,7 @@ void imquic_set_incoming_track_status_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param track_status_accepted Pointer to the function that will fire when a \c TRACK_STATUS is accepted */ void imquic_set_track_status_accepted_cb(imquic_endpoint *endpoint, - void (* track_status_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters)); + void (* track_status_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when a * \c TRACK_STATUS we previously sent was rejected with an error * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -1067,18 +1037,8 @@ void imquic_set_moq_connection_gone_cb(imquic_endpoint *endpoint, typedef enum imquic_moq_version { /* Base */ IMQUIC_MOQ_VERSION_BASE = 0xff000000, - /* Draft version -11 */ - IMQUIC_MOQ_VERSION_MIN = 0xff00000B, - IMQUIC_MOQ_VERSION_11 = 0xff00000B, - /* Draft version -12 */ - IMQUIC_MOQ_VERSION_12 = 0xff00000C, - /* Draft version -13 */ - IMQUIC_MOQ_VERSION_13 = 0xff00000D, - /* Draft version -14 */ - IMQUIC_MOQ_VERSION_14 = 0xff00000E, - /* Draft version -15 */ - IMQUIC_MOQ_VERSION_15 = 0xff00000F, /* Draft version -16 */ + IMQUIC_MOQ_VERSION_MIN = 0xff000010, IMQUIC_MOQ_VERSION_16 = 0xff000010, /* Draft version -17 */ IMQUIC_MOQ_VERSION_17 = 0xff000011, @@ -1086,9 +1046,6 @@ typedef enum imquic_moq_version { /* Any version starting from v15: for client, it means offer all supported versions; * for servers, it means accept the first supported offered version */ IMQUIC_MOQ_VERSION_ANY = 0xff0000ff, - /* Any version between v11 and v14: for client, it means offer all those versions; - * for servers, it means accept the first supported offered version */ - IMQUIC_MOQ_VERSION_ANY_LEGACY = 0xff0000fe } imquic_moq_version; /*! \brief Helper function to serialize to string the name of a imquic_moq_version property. * @param version The imquic_moq_version property @@ -1150,7 +1107,7 @@ int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, i /*! \brief Function to accept an incoming \c PUBLISH_NAMESPACE request * @param conn The imquic_connection to send the request on * @param request_id The request ID of the original \c PUBLISH_NAMESPACE request - * @param parameters The parameters to add to the request (ignored before v15) + * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_publish_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); @@ -1159,7 +1116,7 @@ int imquic_moq_accept_publish_namespace(imquic_connection *conn, uint64_t reques * @param request_id The request ID of the original \c PUBLISH_NAMESPACE request * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_publish_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); @@ -1175,7 +1132,7 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, imquic_moq_namesp * @param tn The imquic_moq_name track name to publish to * @param track_alias A unique numeric identifier to associate to the track in this subscription * @param parameters The parameters to add to the request - * @param track_extensions List of track extensions to add, if any (added in v16) + * @param track_extensions List of track extensions to add, if any * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, @@ -1191,26 +1148,25 @@ int imquic_moq_accept_publish(imquic_connection *conn, uint64_t request_id, imqu * @param request_id The unique \c request_id value associated to the subscription to reject * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Function to send a \c SUBSCRIBE request * @param conn The imquic_connection to send the request on * @param request_id A unique request ID to associate to this subscription - * @param track_alias A unique numeric identifier to associate to the track in this subscription (ignored starting from v12) * @param tns The imquic_moq_namespace namespace the track to subscribe to belongs to * @param tn The imquic_moq_name track name to subscribe to * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, +int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c SUBSCRIBE request * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to accept - * @param track_alias The unique \c track_alias value associated to the subscription to accept (ignored before v12) + * @param track_alias The unique \c track_alias value associated to the subscription to accept * @param parameters The parameters to add to the request - * @param track_extensions List of track extensions to add, if any (added in v16) + * @param track_extensions List of track extensions to add, if any * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); @@ -1219,24 +1175,19 @@ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, * @param request_id The unique \c request_id value associated to the subscription to reject * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param track_alias The unique \c track_alias value associated to the subscription to reject (ignored starting from v12) - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, - imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval); + imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Function to send a \c REQUEST_UPDATE request - * \note Version 14 of the draft introduced a new "Subscription Request ID", which means - * the meaning of \c request_id will change depending on which version the connection is using. * @param conn The imquic_connection to send the request on * @param request_id Unique \c request_id value (before v14, this is associated to the subscription to update) - * @param sub_request_id Unique \c request_id value associated to the subscription to update (ignored before v14) + * @param sub_request_id Unique \c request_id value associated to the subscription to update * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c REQUEST_UPDATE request - * \note This acknowledgement was only added in v15, which means it will - * be a no-action if you try to send it when negotiating an older version * @param conn The imquic_connection to send the request on * @param request_id The request ID of the original \c REQUEST_UPDATE request * @param parameters The parameters to add to the request @@ -1244,13 +1195,11 @@ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, int imquic_moq_accept_request_update(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Function to reject an incoming \c REQUEST_UPDATE request - * \note This error response was only added in v15, which means it will - * be a no-action if you try to send it when negotiating an older version * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to reject * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_request_update(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); @@ -1272,7 +1221,7 @@ int imquic_moq_unsubscribe(imquic_connection *conn, uint64_t request_id); * @param conn The imquic_connection to send the request on * @param request_id A unique request ID * @param tns The imquic_moq_namespace namespace the track to subscribe to belongs to - * @param subscribe_options The subscribe options to add to the request (added in v16, ignored otherwise) + * @param subscribe_options The subscribe options to add to the request * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, @@ -1280,7 +1229,7 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, /*! \brief Function to accept an incoming \c SUBSCRIBE_NAMESPACE request * @param conn The imquic_connection to send the request on * @param request_id The request ID of the original \c SUBSCRIBE_NAMESPACE request - * @param parameters The parameters to add to the request (ignored before v15) + * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_subscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); @@ -1289,7 +1238,7 @@ int imquic_moq_accept_subscribe_namespace(imquic_connection *conn, uint64_t requ * @param request_id The request ID of the original \c SUBSCRIBE_NAMESPACE request * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); @@ -1297,13 +1246,12 @@ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t requ * \note Starting in v16, this doesn't actually send a request, but simply * closes the bidirectional STREAM that was created for the subscription * @param conn The imquic_connection to send the request on - * @param request_id The request ID of the original \c SUBSCRIBE_NAMESPACE request (added in v15, ignored otherwise) - * @param tns The imquic_moq_namespace namespace to unsubscribe notifications from (deprecated in v15) + * @param request_id The request ID of the original \c SUBSCRIBE_NAMESPACE request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); +int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id); /*! \brief Function to send a \c NAMESPACE request - * \note This was added in v16, and while the request itself doesn't contain - * the request ID, we use it to find the subscription and use the right STREAM + * \note While the request itself doesn't contain the request ID, we use + * it to find the subscription and use the right STREAM. * Notice the method expects the full track namespace: the stack will strip * the prefix itself, before sending the actual message. * @param conn The imquic_connection to send the request on @@ -1312,8 +1260,8 @@ int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_i * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); /*! \brief Function to send a \c NAMESPACE_DONE request - * \note This was added in v16, and while the request itself doesn't contain - * the request ID, we use it to find the subscription and use the right STREAM. + * \note While the request itself doesn't contain the request ID, we use + * it to find the subscription and use the right STREAM. * Notice the method expects the full track namespace: the stack will strip * the prefix itself, before sending the actual message. * @param conn The imquic_connection to send the request on @@ -1348,7 +1296,7 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 * @param request_id The unique \c request_id value associated to the subscription to accept * @param largest The largest group/object IDs * @param parameters The parameters to add to the request - * @param track_extensions List of track extensions to add, if any (added in v16) + * @param track_extensions List of track extensions to add, if any * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_extensions); @@ -1357,7 +1305,7 @@ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, * @param request_id The unique \c request_id value associated to the subscription to reject * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); @@ -1367,8 +1315,6 @@ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_cancel_fetch(imquic_connection *conn, uint64_t request_id); /*! \brief Function to send a \c TRACK_STATUS request - * \note Due to considerable changes between v12 and v13 on \c TRACK_STATUS , - * support for this request is disabled in versions earlier than v13. * @param conn The imquic_connection to send the request on * @param request_id A unique request ID to associate to this request * @param tns The imquic_moq_namespace namespace the track to track_status to belongs to @@ -1378,23 +1324,18 @@ int imquic_moq_cancel_fetch(imquic_connection *conn, uint64_t request_id); int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c TRACK_STATUS request - * \note Due to considerable changes between v12 and v13 on \c TRACK_STATUS , - * support for this request is disabled in versions earlier than v13. * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to query - * @param track_alias The unique \c track_alias value associated to the subscription to query (ignored after v15) * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_track_status(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters); + imquic_moq_request_parameters *parameters); /*! \brief Function to reject an incoming \c TRACK_STATUS request - * @note Due to considerable changes between v12 and v13 on \c TRACK_STATUS , - * support for this request is disabled in versions earlier than v13 * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to reject * @param error_code The error code to send back * @param reason A string representation of the error, if needed - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_track_status(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); diff --git a/src/internal/moq.h b/src/internal/moq.h index 9403510..0ffcffb 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -4,7 +4,7 @@ * \brief Media Over QUIC (MoQ) stack (headers) * \details Implementation of the Media Over QUIC (MoQ) stack as part * of the library itself. At the time of writing, this implements (most - * of) versions from -06 to to -12 of the protocol. + * of) versions from -16 to to -17 of the protocol. * * \note This is the internal implementation of MoQ in the library. You're * still free to only use imquic as the underlying QUIC/WebTransport library, @@ -39,40 +39,30 @@ void imquic_moq_deinit(void); /*! \brief MoQ messages */ typedef enum imquic_moq_message_type { - IMQUIC_MOQ_REQUEST_OK = 0x5, /* Added in v15 */ - IMQUIC_MOQ_REQUEST_ERROR = 0x7, /* Added in v15 */ + IMQUIC_MOQ_REQUEST_OK = 0x5, + IMQUIC_MOQ_REQUEST_ERROR = 0x7, IMQUIC_MOQ_REQUEST_UPDATE = 0x2, IMQUIC_MOQ_SUBSCRIBE = 0x3, IMQUIC_MOQ_SUBSCRIBE_OK = 0x4, - IMQUIC_MOQ_SUBSCRIBE_ERROR = 0x5, /* Deprecated in v15 */ IMQUIC_MOQ_PUBLISH_NAMESPACE = 0x6, - IMQUIC_MOQ_PUBLISH_NAMESPACE_OK = 0x7, /* Deprecated in v15 */ - IMQUIC_MOQ_PUBLISH_NAMESPACE_ERROR = 0x8, /* Deprecated in v15 */ IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE = 0x9, IMQUIC_MOQ_UNSUBSCRIBE = 0xa, IMQUIC_MOQ_PUBLISH_DONE = 0xb, IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL = 0xc, IMQUIC_MOQ_TRACK_STATUS = 0xd, - IMQUIC_MOQ_TRACK_STATUS_OK = 0xe, /* Deprecated in v15 */ - IMQUIC_MOQ_TRACK_STATUS_ERROR = 0xf, /* Deprecated in v15 */ IMQUIC_MOQ_GOAWAY = 0x10, IMQUIC_MOQ_SUBSCRIBE_NAMESPACE = 0x11, - IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_OK = 0x12, /* Deprecated in v15 */ - IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_ERROR = 0x13, /* Deprecated in v15 */ - IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE = 0x14, /* Deprecated in v16 */ - IMQUIC_MOQ_NAMESPACE = 0x8, /* Added in v16 */ - IMQUIC_MOQ_NAMESPACE_DONE = 0xe, /* Added in v16 */ + IMQUIC_MOQ_NAMESPACE = 0x8, + IMQUIC_MOQ_NAMESPACE_DONE = 0xe, IMQUIC_MOQ_MAX_REQUEST_ID = 0x15, IMQUIC_MOQ_REQUESTS_BLOCKED = 0x1A, IMQUIC_MOQ_FETCH = 0x16, IMQUIC_MOQ_FETCH_CANCEL = 0x17, IMQUIC_MOQ_FETCH_OK = 0x18, - IMQUIC_MOQ_FETCH_ERROR = 0x19, /* Deprecated in v15 */ IMQUIC_MOQ_CLIENT_SETUP = 0x20, IMQUIC_MOQ_SERVER_SETUP = 0x21, IMQUIC_MOQ_PUBLISH = 0x1D, IMQUIC_MOQ_PUBLISH_OK = 0x1E, - IMQUIC_MOQ_PUBLISH_ERROR = 0x1F, /* Deprecated in v15 */ } imquic_moq_message_type; /*! \brief Helper function to serialize to string the name of a imquic_moq_message_type value. * @param type The imquic_moq_message_type value @@ -98,8 +88,8 @@ gboolean imquic_moq_is_datagram_message_type_valid(imquic_moq_version version, u * @param payload Whether there is a payload * @param ext Whether there are extensions * @param eog Whether there is an End of Group - * @param oid Whether there is an Object ID (ignored before v14) - * @param priority Whether there is a Publisher Priority (ignored before v15) + * @param oid Whether there is an Object ID + * @param priority Whether there is a Publisher Priority * @returns The type as a bitmask flag */ uint8_t imquic_moq_datagram_message_type_return(imquic_moq_version version, gboolean payload, gboolean ext, gboolean eog, gboolean oid, gboolean priority); @@ -110,8 +100,8 @@ uint8_t imquic_moq_datagram_message_type_return(imquic_moq_version version, * @param[out] payload Output variable to write whether there is a payload * @param[out] ext Output variable to write whether there are extensions * @param[out] eog Output variable to write whether there is an End of Group - * @param[out] oid Output variable to write whether there is an Object ID (ignored before v14) - * @param[out] priority Output variable to write whether there is a Publisher Priority (added in v15) + * @param[out] oid Output variable to write whether there is an Object ID + * @param[out] priority Output variable to write whether there is a Publisher Priority * @param[out] violation Whether the type has bits set that really shouldn't */ void imquic_moq_datagram_message_type_parse(imquic_moq_version version, uint8_t type, gboolean *payload, gboolean *ext, gboolean *eog, gboolean *oid, gboolean *priority, gboolean *violation); @@ -124,19 +114,11 @@ const char *imquic_moq_datagram_message_type_str(uint8_t type, imquic_moq_versio /*! \brief MoQ \c STREAM data messages */ typedef enum imquic_moq_data_message_type { /* IMQUIC_MOQ_SUBGROUP_HEADER_XXX */ - /* v11 */ - IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_NOEXT_v11 = 0x8, /* Deprecated in v12 */ - IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11 = 0x9, /* Deprecated in v12 */ - IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_NOEXT_v11 = 0xA, /* Deprecated in v12 */ - IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_v11 = 0xB, /* Deprecated in v12 */ - IMQUIC_MOQ_SUBGROUP_HEADER_NOEXT_v11 = 0xC, /* Deprecated in v12 */ - IMQUIC_MOQ_SUBGROUP_HEADER_v11 = 0xD, /* Deprecated in v12 */ - /* v12 and beyond */ - IMQUIC_MOQ_SUBGROUP_HEADER = 0x10, - IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN = 0x10, - IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX = 0x1D, - IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN = 0x30, - IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX = 0x3D, + IMQUIC_MOQ_SUBGROUP_HEADER = 0x10, + IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN = 0x10, + IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX = 0x1D, + IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN = 0x30, + IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX = 0x3D, /* IMQUIC_MOQ_FETCH_HEADER */ IMQUIC_MOQ_FETCH_HEADER = 0x5, } imquic_moq_data_message_type; @@ -151,7 +133,7 @@ gboolean imquic_moq_is_data_message_type_valid(imquic_moq_version version, uint8 * @param[in] sgid0 Whether the default value of Subgroup ID is 0, in case the field is missing * @param[in] ext Whether there are extensions * @param[in] eog Whether there is an End of Group - * @param[in] priority Whether there is a Publisher Priority (added in v15) + * @param[in] priority Whether there is a Publisher Priority * @returns The type as a bitmask flag */ uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version version, gboolean subgroup, gboolean sgid0, gboolean ext, gboolean eog, gboolean priority); @@ -162,7 +144,7 @@ uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version ver * @param[out] sgid0 Output variable to write whether the default value of Subgroup ID is 0, in case the field is missing * @param[out] ext Output variable to write whether there are extensions * @param[out] eog Output variable to write whether there is an End of Group - * @param[out] priority Output variable to write whether there is a Publisher Priority (added in v15) + * @param[out] priority Output variable to write whether there is a Publisher Priority * @param[out] violation Whether the type has bits set that really shouldn't */ void imquic_moq_data_message_type_to_subgroup_header(imquic_moq_version version, uint8_t type, gboolean *subgroup, gboolean *sgid0, gboolean *ext, gboolean *eog, gboolean *priority, gboolean *violation); @@ -210,7 +192,7 @@ uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version versio * @param[out] subgroup Output variable to write the type of subgroup * @param[out] oid Output variable to write whether the Object ID field is present * @param[out] group Output variable to write whether the Group ID field is present - * @param[out] priority Output variable to write whether there is a Publisher Priority (added in v15) + * @param[out] priority Output variable to write whether there is a Publisher Priority * @param[out] ext Output variable to write whether there are extensions * @param[out] datagram Output variable to write whether the forwarding preference is Datagram * @param[out] end_ne_range Output variable to write whether this is the end of a non-existent range @@ -236,18 +218,14 @@ const char *imquic_moq_setup_parameter_type_str(imquic_moq_setup_parameter_type /*! \brief MoQ request parameter types */ typedef enum imquic_moq_request_parameter_type { - IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN_v11 = 0x01, /* Deprecated in v12 */ IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN = 0x03, IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT = 0x02, - IMQUIC_MOQ_REQUEST_PARAM_MAX_CACHE_DURATION = 0x04, /* Deprecated in v16 */ - IMQUIC_MOQ_REQUEST_PARAM_PUBLISHER_PRIORITY = 0x0E, /* Deprecated in v16 */ IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY = 0x20, IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER = 0x22, IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER = 0x21, IMQUIC_MOQ_REQUEST_PARAM_EXPIRES = 0x8, IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT = 0x9, IMQUIC_MOQ_REQUEST_PARAM_FORWARD = 0x10, - IMQUIC_MOQ_REQUEST_PARAM_DYNAMIC_GROUPS = 0x30, /* Deprecated in v16 */ IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST = 0x32, } imquic_moq_request_parameter_type; /*! \brief Helper function to serialize to string the name of a imquic_moq_request_parameter_type value. @@ -314,34 +292,6 @@ typedef enum imquic_moq_fetch_type { * @returns The type name as a string, if valid, or NULL otherwise */ const char *imquic_moq_fetch_type_str(imquic_moq_fetch_type type); -/*! \brief MoQ legacy (pre-v15) error codes and translation to/from new ones */ -typedef enum imquic_moq_legacy_error_code { - IMQUIC_MOQ_OLDERR_INTERNAL_ERROR = 0x0, - IMQUIC_MOQ_OLDERR_UNAUTHORIZED = 0x1, - IMQUIC_MOQ_OLDERR_TIMEOUT = 0x2, - IMQUIC_MOQ_OLDERR_NOT_SUPPORTED = 0x3, - IMQUIC_MOQ_OLDERR_UNINTERESTED = 0x4, - IMQUIC_MOQ_OLDERR_TRACK_DOES_NOT_EXIST = 0x4, - IMQUIC_MOQ_OLDERR_INVALID_RANGE = 0x5, - IMQUIC_MOQ_OLDERR_INVALID_JOINING_REQUEST_ID = 0x7, - IMQUIC_MOQ_OLDERR_UNKNOWN_STATUS_IN_RANGE = 0x8, - IMQUIC_MOQ_OLDERR_MALFORMED_TRACK = 0x9, - IMQUIC_MOQ_OLDERR_MALFORMED_AUTH_TOKEN = 0x10, - IMQUIC_MOQ_OLDERR_EXPIRED_AUTH_TOKEN = 0x12, -} imquic_moq_legacy_error_code; -/*! \brief Helper to translate a new request error code passed by the - * user to a legacy error code, if serializing on an old version of MoQ - * @param version The version this connection is using - * @param code The new request error code - * @returns The associated legacy error code, if available, or a generic internal error otherwise */ -imquic_moq_legacy_error_code imquic_moq_request_error_code_to_legacy(imquic_moq_version version, imquic_moq_request_error_code code); -/*! \brief Helper to translate a legacy error code parsed by the stack - * to a new request error code, if receiving from an old version of MoQ - * @param version The version this connection is using - * @param code The legacy error code - * @returns The associated new request error code, if available, or a generic internal error otherwise */ -imquic_moq_request_error_code imquic_moq_request_error_code_from_legacy(imquic_moq_version version, imquic_moq_legacy_error_code code); - /*! \brief MoQ context */ typedef struct imquic_moq_context { /*! \brief Associated QUIC connection */ @@ -512,22 +462,16 @@ size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c REQUEST_OK message - * \note This message was only added in v15, and consolidates most OK - * messages that existed until then. It will automatically trigger the - * right callback, by checking what the original request was for * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] moq_stream The imquic_moq_stream instance the message came from (ignored before v16, only needed for namespaces) + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c REQUEST_ERROR message - * \note This message was only added in v15, and consolidates all error - * messages that existed until then. It will automatically trigger the - * right callback, by checking what the original request was for * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] moq_stream The imquic_moq_stream instance the message came from (ignored before v16, only needed for namespaces) + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors @@ -540,20 +484,6 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c PUBLISH_NAMESPACE_OK message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c PUBLISH_NAMESPACE_ERROR message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_NAMESPACE_DONE message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse @@ -633,7 +563,7 @@ size_t imquic_moq_parse_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, siz size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c SUBSCRIBE_NAMESPACE message * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] moq_stream The imquic_moq_stream instance the message came from (ignored before v16) + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors @@ -661,7 +591,6 @@ size_t imquic_moq_parse_subscribe_namespace_error(imquic_moq_context *moq, uint8 * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c NAMESPACE message - * \note This method was added in v16, to notify namespaces on a dedicated STREAM * @param[in] moq The imquic_moq_context instance the message is for * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse @@ -670,7 +599,6 @@ size_t imquic_moq_parse_unsubscribe_namespace(imquic_moq_context *moq, uint8_t * * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c NAMESPACE_DONE message - * \note This method was added in v16, to notify namespaces on a dedicated STREAM * @param[in] moq The imquic_moq_context instance the message is for * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse @@ -794,20 +722,18 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param supported_versions List of supported versions * @param parameters The setup parameters to send * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - GList *supported_versions, imquic_moq_setup_parameters *parameters); + imquic_moq_setup_parameters *parameters); /*! \brief Helper method to add a \c SERVER_SETUP message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param version Negotiated version * @param parameters The setup parameters to send * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint32_t version, imquic_moq_setup_parameters *parameters); + imquic_moq_setup_parameters *parameters); /*! \brief Helper method to add a \c MAX_REQUEST_ID message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -823,8 +749,6 @@ size_t imquic_moq_add_max_request_id(imquic_moq_context *moq, uint8_t *bytes, si * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t max_request_id); /*! \brief Helper method to add a \c REQUEST_OK message to a buffer - * \note This message was only added in v15, and consolidates most OK - * messages that existed until then * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to @@ -835,8 +759,6 @@ size_t imquic_moq_add_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c REQUEST_ERROR message to a buffer - * \note This message was only added in v15, and consolidates all - * error messages that existed until then * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to @@ -844,7 +766,7 @@ size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq * @param request_id The request ID to put in the message * @param error Error code associated to the message * @param reason Verbose description of the error, if any - * @param retry_interval Retry interval in ms (added in v16, ignored otherwise) + * @param retry_interval Retry interval in ms * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t error, const char *reason, uint64_t retry_interval); @@ -901,7 +823,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t * @param track_name The track name to put in the message * @param track_alias The track alias to put in the message * @param parameters The parameters to add, if any - * @param track_extensions List of track extensions to add, if any (added in v16) + * @param track_extensions List of track extensions to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, @@ -930,19 +852,18 @@ size_t imquic_moq_add_publish_error(imquic_moq_context *moq, uint8_t *bytes, siz * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message - * @param track_alias The track alias to put in the message * @param track_namespace The namespace to put in the message * @param track_name The track name to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, +size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c REQUEST_UPDATE message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message - * @param sub_request_id The subscription request ID to put in the message (ignored before v14) + * @param sub_request_id The subscription request ID to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, size_t blen, @@ -952,9 +873,9 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message - * @param track_alias The track alias to put in the message (ignored before v12) + * @param track_alias The track alias to put in the message * @param parameters The parameters to add, if any - * @param track_extensions List of track extensions to add, if any (added in v16) + * @param track_extensions List of track extensions to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); @@ -965,10 +886,9 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size * @param request_id The request ID to put in the message * @param error Error code associated to the message * @param reason Verbose description of the error, if any - * @param track_alias The track alias to put in the message (ignored starting from v12) * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_error_code error, const char *reason, uint64_t track_alias); + imquic_moq_request_error_code error, const char *reason); /*! \brief Helper method to add an \c UNSUBSCRIBE message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -994,7 +914,7 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size * @param blen The size of the buffer * @param request_id The request ID to put in the message * @param track_namespace The namespace to put in the message - * @param subscribe_options The subscribe options to put in the message (added in v16) + * @param subscribe_options The subscribe options to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, @@ -1020,10 +940,9 @@ size_t imquic_moq_add_subscribe_namespace_error(imquic_moq_context *moq, uint8_t * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param request_id The request ID to put in the message (added in v15) - * @param track_namespace The namespace to put in the message (ignored starting from v15) + * @param request_id The request ID to put in the message * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace); +size_t imquic_moq_add_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); /*! \brief Helper method to add a \c NAMESPACE_DONE message to a buffer * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for @@ -1074,7 +993,7 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size * @param end_of_track Whether all objects have been published * @param end_location End location to add to the message, if needed * @param parameters The parameters to add, if any - * @param track_extensions List of track extensions to add, if any (added in v16) + * @param track_extensions List of track extensions to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_extensions); @@ -1208,7 +1127,7 @@ size_t imquic_moq_add_fetch_header(imquic_moq_context *moq, uint8_t *bytes, size * @param moq The imquic_moq_context generating the object * @param bytes The buffer to add the object to * @param blen The size of the buffer - * @param flags The serialization flags (added in v15) + * @param flags The serialization flags * @param group_id The group ID * @param subgroup_id The subgroup ID * @param object_id The object ID @@ -1331,12 +1250,12 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming \c PUBLISH_ERROR messages */ void (* publish_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE messages */ - void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, + void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_ACCEPTED messages */ void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_ERROR messages */ - void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval); + void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c REQUEST_UPDATE messages */ void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about an ACK to a previously sent \c REQUEST_UPDATE message */ @@ -1377,7 +1296,7 @@ typedef struct imquic_moq_callbacks { void (* incoming_track_status)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c TRACK_STATUS_ACCEPTED messages */ - void (* track_status_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters); + void (* track_status_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c TRACK_STATUS_ERROR messages */ void (* track_status_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming MoQ objects */ diff --git a/src/moq.c b/src/moq.c index 006a05d..f238b48 100644 --- a/src/moq.c +++ b/src/moq.c @@ -4,7 +4,7 @@ * \brief Media Over QUIC (MoQ) stack * \details Implementation of the Media Over QUIC (MoQ) stack as part * of the library itself. At the time of writing, this implements (most - * of) versions from -06 to to -14 of the protocol. + * of) versions from -16 to to -17 of the protocol. * * \note This is the internal implementation of MoQ in the library. You're * still free to only use imquic as the underlying QUIC/WebTransport library, @@ -58,22 +58,10 @@ void imquic_moq_deinit(void) { static imquic_moq_version imquic_moq_version_from_alpn(const char *alpn, imquic_moq_version fallback) { if(alpn == NULL) return fallback; - if(!strcasecmp(alpn, "moq-00")) - return IMQUIC_MOQ_VERSION_ANY_LEGACY; - else if(!strcasecmp(alpn, "moq-17")) + if(!strcasecmp(alpn, "moq-17")) return IMQUIC_MOQ_VERSION_17; else if(!strcasecmp(alpn, "moq-16")) return IMQUIC_MOQ_VERSION_16; - else if(!strcasecmp(alpn, "moq-15")) - return IMQUIC_MOQ_VERSION_15; - else if(!strcasecmp(alpn, "moq-14")) - return IMQUIC_MOQ_VERSION_14; - else if(!strcasecmp(alpn, "moq-13")) - return IMQUIC_MOQ_VERSION_13; - else if(!strcasecmp(alpn, "moq-12")) - return IMQUIC_MOQ_VERSION_12; - else if(!strcasecmp(alpn, "moq-11")) - return IMQUIC_MOQ_VERSION_11; /* If we got here, there was no specific ALPN negotiation */ return fallback; } @@ -134,8 +122,6 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { const char *alpn = imquic_is_connection_webtransport(conn) ? imquic_get_connection_wt_protocol(conn) : imquic_get_connection_alpn(conn); moq->version = imquic_moq_version_from_alpn(alpn, conn->socket->moq_version); - if(alpn == NULL && moq->version == IMQUIC_MOQ_VERSION_ANY) - moq->version = IMQUIC_MOQ_VERSION_ANY_LEGACY; IMQUIC_LOG(IMQUIC_LOG_VERB, "[%s][MoQ] MoQ version: %s (%s)\n", imquic_get_connection_name(conn), imquic_moq_version_str(moq->version), alpn); moq->streams = g_hash_table_new_full(g_int64_hash, g_int64_equal, @@ -190,32 +176,14 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { memcpy(parameters.auth_token, moq->auth, moq->authlen); parameters.auth_token_len = moq->authlen; } - if((moq->version >= IMQUIC_MOQ_VERSION_14 && moq->version <= IMQUIC_MOQ_VERSION_MAX) || - moq->version == IMQUIC_MOQ_VERSION_ANY) { - /* FIXME */ - parameters.moqt_implementation_set = TRUE; - g_snprintf(parameters.moqt_implementation, sizeof(parameters.moqt_implementation), "imquic %s", imquic_version_string_full); - } + /* Add the implementation */ + parameters.moqt_implementation_set = TRUE; + g_snprintf(parameters.moqt_implementation, sizeof(parameters.moqt_implementation), "imquic %s", imquic_version_string_full); /* TODO For raw quic connections, we should expose ways to * fill in and use the PATH and ATTRIBUTE parameters as well */ - /* Version is only negotiated here for versions of the draft older than v15 */ - GList *versions = NULL; - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) { - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY) { - /* Offer all newer supported versions */ - versions = g_list_append(versions, GUINT_TO_POINTER(IMQUIC_MOQ_VERSION_14)); - versions = g_list_append(versions, GUINT_TO_POINTER(IMQUIC_MOQ_VERSION_13)); - versions = g_list_append(versions, GUINT_TO_POINTER(IMQUIC_MOQ_VERSION_12)); - versions = g_list_append(versions, GUINT_TO_POINTER(IMQUIC_MOQ_VERSION_11)); - } else { - /* Offer a specific version */ - versions = g_list_append(versions, GUINT_TO_POINTER(moq->version)); - } - } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t cs_len = imquic_moq_add_client_setup(moq, buffer, blen, versions, ¶meters); - g_list_free(versions); + size_t cs_len = imquic_moq_add_client_setup(moq, buffer, blen, ¶meters); imquic_connection_send_on_stream(moq->conn, moq->control_stream_id, buffer, cs_len, FALSE); } @@ -284,7 +252,7 @@ void imquic_moq_reset_stream_incoming(imquic_connection *conn, uint64_t stream_i } IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Got RESET_STREAM for STREAM %"SCNu64": %"SCNu64" (%s)\n", imquic_get_connection_name(conn), stream_id, error_code, imquic_moq_reset_stream_code_str(error_code)); - if(moq->version < IMQUIC_MOQ_VERSION_16 || !moq_stream->subscribe_namespace) { + if(!moq_stream->subscribe_namespace) { /* FIXME Not the SUBSCRIBE_NAMESPACE stream, we ignore it for now */ imquic_mutex_unlock(&moq->mutex); return; @@ -427,88 +395,11 @@ const char *imquic_moq_request_error_code_str(imquic_moq_request_error_code code return "PREFIX_OVERLAP"; case IMQUIC_MOQ_REQERR_INVALID_JOINING_REQUEST_ID: return "INVALID_JOINING_REQUEST_ID"; - case IMQUIC_MOQ_REQERR_UNKNOWN_STATUS_IN_RANGE: - return "UNKNOWN_STATUS_IN_RANGE"; default: break; } return NULL; } -imquic_moq_legacy_error_code imquic_moq_request_error_code_to_legacy(imquic_moq_version version, imquic_moq_request_error_code code) { - if(version >= IMQUIC_MOQ_VERSION_15) - return (imquic_moq_legacy_error_code)code; - switch(code) { - /* Same code */ - case IMQUIC_MOQ_REQERR_INTERNAL_ERROR: - case IMQUIC_MOQ_REQERR_UNAUTHORIZED: - case IMQUIC_MOQ_REQERR_TIMEOUT: - case IMQUIC_MOQ_REQERR_NOT_SUPPORTED: - return (imquic_moq_legacy_error_code)code; - /* Error code was different up to v14 */ - case IMQUIC_MOQ_REQERR_MALFORMED_AUTH_TOKEN: - return IMQUIC_MOQ_OLDERR_MALFORMED_AUTH_TOKEN; - case IMQUIC_MOQ_REQERR_EXPIRED_AUTH_TOKEN: - return IMQUIC_MOQ_OLDERR_EXPIRED_AUTH_TOKEN; - case IMQUIC_MOQ_REQERR_DOES_NOT_EXIST: - return IMQUIC_MOQ_OLDERR_TRACK_DOES_NOT_EXIST; - case IMQUIC_MOQ_REQERR_INVALID_RANGE: - return IMQUIC_MOQ_OLDERR_INVALID_RANGE; - case IMQUIC_MOQ_REQERR_MALFORMED_TRACK: - return IMQUIC_MOQ_OLDERR_MALFORMED_TRACK; - case IMQUIC_MOQ_REQERR_UNINTERESTED: - return IMQUIC_MOQ_OLDERR_UNINTERESTED; - case IMQUIC_MOQ_REQERR_INVALID_JOINING_REQUEST_ID: - return IMQUIC_MOQ_OLDERR_INVALID_JOINING_REQUEST_ID; - case IMQUIC_MOQ_REQERR_UNKNOWN_STATUS_IN_RANGE: - return IMQUIC_MOQ_OLDERR_UNKNOWN_STATUS_IN_RANGE; - /* New error codes with no mapping to old ones */ - case IMQUIC_MOQ_REQERR_PREFIX_OVERLAP: - case IMQUIC_MOQ_REQERR_DUPLICATE_SUBSCRIPTION: - default: - IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't translate new error code %s (%s) to old error code\n", - imquic_moq_request_error_code_str(code), imquic_moq_version_str(version)); - break; - } - /* As a fallback, we return a generic internal error */ - return IMQUIC_MOQ_OLDERR_INTERNAL_ERROR; -} - -imquic_moq_request_error_code imquic_moq_request_error_code_from_legacy(imquic_moq_version version, imquic_moq_legacy_error_code code) { - if(version >= IMQUIC_MOQ_VERSION_15) - return (imquic_moq_request_error_code)code; - switch(code) { - /* Same code */ - case IMQUIC_MOQ_OLDERR_INTERNAL_ERROR: - case IMQUIC_MOQ_OLDERR_UNAUTHORIZED: - case IMQUIC_MOQ_OLDERR_TIMEOUT: - case IMQUIC_MOQ_OLDERR_NOT_SUPPORTED: - return (imquic_moq_request_error_code)code; - case IMQUIC_MOQ_OLDERR_TRACK_DOES_NOT_EXIST: - /* Note: there's actually a conflit here (it's also the - * old UNINTERESTED), but this is more common/important */ - return IMQUIC_MOQ_REQERR_DOES_NOT_EXIST; - case IMQUIC_MOQ_OLDERR_INVALID_RANGE: - return IMQUIC_MOQ_REQERR_INVALID_RANGE; - case IMQUIC_MOQ_OLDERR_INVALID_JOINING_REQUEST_ID: - return IMQUIC_MOQ_REQERR_INVALID_JOINING_REQUEST_ID; - case IMQUIC_MOQ_OLDERR_UNKNOWN_STATUS_IN_RANGE: - return IMQUIC_MOQ_REQERR_UNKNOWN_STATUS_IN_RANGE; - case IMQUIC_MOQ_OLDERR_MALFORMED_TRACK: - return IMQUIC_MOQ_REQERR_MALFORMED_TRACK; - case IMQUIC_MOQ_OLDERR_MALFORMED_AUTH_TOKEN: - return IMQUIC_MOQ_REQERR_MALFORMED_AUTH_TOKEN; - case IMQUIC_MOQ_OLDERR_EXPIRED_AUTH_TOKEN: - return IMQUIC_MOQ_REQERR_EXPIRED_AUTH_TOKEN; - /* No mapping or multiple (ambiguous) mappings */ - default: - IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't translate (%s) old error code '%02x' to new request error codes\n", - imquic_moq_version_str(version), code); - break; - } - /* As a fallback, we return a generic internal error */ - return IMQUIC_MOQ_REQERR_INTERNAL_ERROR; -} - const char *imquic_moq_pub_done_code_str(imquic_moq_pub_done_code code) { switch(code) { case IMQUIC_MOQ_PUBDONE_INTERNAL_ERROR: @@ -554,22 +445,20 @@ const char *imquic_moq_reset_stream_code_str(imquic_moq_reset_stream_code code) } const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq_version version) { - if(version <= IMQUIC_MOQ_VERSION_14) { + if(version <= IMQUIC_MOQ_VERSION_16) { switch(type) { + case IMQUIC_MOQ_REQUEST_OK: + return "REQUEST_OK"; + case IMQUIC_MOQ_REQUEST_ERROR: + return "REQUEST_ERROR"; case IMQUIC_MOQ_SUBSCRIBE: return "SUBSCRIBE"; case IMQUIC_MOQ_SUBSCRIBE_OK: return "SUBSCRIBE_OK"; - case IMQUIC_MOQ_SUBSCRIBE_ERROR: - return "SUBSCRIBE_ERROR"; case IMQUIC_MOQ_REQUEST_UPDATE: - return "SUBSCRIBE_UPDATE"; + return "REQUEST_UPDATE"; case IMQUIC_MOQ_PUBLISH_NAMESPACE: return "PUBLISH_NAMESPACE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE_OK: - return "PUBLISH_NAMESPACE_OK"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE_ERROR: - return "PUBLISH_NAMESPACE_ERROR"; case IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE: return "PUBLISH_NAMESPACE_DONE"; case IMQUIC_MOQ_UNSUBSCRIBE: @@ -580,20 +469,14 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "PUBLISH_NAMESPACE_CANCEL"; case IMQUIC_MOQ_TRACK_STATUS: return "TRACK_STATUS"; - case IMQUIC_MOQ_TRACK_STATUS_OK: - return "TRACK_STATUS_OK"; - case IMQUIC_MOQ_TRACK_STATUS_ERROR: - return "TRACK_STATUS_ERROR"; case IMQUIC_MOQ_GOAWAY: return "GOAWAY"; case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE: return "SUBSCRIBE_NAMESPACE"; - case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_OK: - return "SUBSCRIBE_NAMESPACE_OK"; - case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_ERROR: - return "SUBSCRIBE_NAMESPACE_ERROR"; - case IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE: - return "UNSUBSCRIBE_NAMESPACE"; + case IMQUIC_MOQ_NAMESPACE: + return "NAMESPACE"; + case IMQUIC_MOQ_NAMESPACE_DONE: + return "NAMESPACE_DONE"; case IMQUIC_MOQ_MAX_REQUEST_ID: return "MAX_REQUEST_ID"; case IMQUIC_MOQ_REQUESTS_BLOCKED: @@ -604,8 +487,6 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "FETCH_CANCEL"; case IMQUIC_MOQ_FETCH_OK: return "FETCH_OK"; - case IMQUIC_MOQ_FETCH_ERROR: - return "FETCH_ERROR"; case IMQUIC_MOQ_CLIENT_SETUP: return "CLIENT_SETUP"; case IMQUIC_MOQ_SERVER_SETUP: @@ -614,11 +495,10 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "PUBLISH"; case IMQUIC_MOQ_PUBLISH_OK: return "PUBLISH_OK"; - case IMQUIC_MOQ_PUBLISH_ERROR: - return "PUBLISH_ERROR"; default: break; } } else { + /* TODO New messages in v17 */ switch(type) { case IMQUIC_MOQ_REQUEST_OK: return "REQUEST_OK"; @@ -629,7 +509,7 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq case IMQUIC_MOQ_SUBSCRIBE_OK: return "SUBSCRIBE_OK"; case IMQUIC_MOQ_REQUEST_UPDATE: - return (version == IMQUIC_MOQ_VERSION_15 ? "SUBSCRIBE_UPDATE" : "REQUEST_UPDATE"); + return "REQUEST_UPDATE"; case IMQUIC_MOQ_PUBLISH_NAMESPACE: return "PUBLISH_NAMESPACE"; case IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE: @@ -646,12 +526,10 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "GOAWAY"; case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE: return "SUBSCRIBE_NAMESPACE"; - case IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE: - return "UNSUBSCRIBE_NAMESPACE"; case IMQUIC_MOQ_NAMESPACE: - return (version >= IMQUIC_MOQ_VERSION_16 ? "NAMESPACE" : NULL); + return "NAMESPACE"; case IMQUIC_MOQ_NAMESPACE_DONE: - return (version >= IMQUIC_MOQ_VERSION_16 ? "NAMESPACE_DONE" : NULL); + return "NAMESPACE_DONE"; case IMQUIC_MOQ_MAX_REQUEST_ID: return "MAX_REQUEST_ID"; case IMQUIC_MOQ_REQUESTS_BLOCKED: @@ -677,67 +555,23 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq } gboolean imquic_moq_is_datagram_message_type_valid(imquic_moq_version version, uint8_t type) { - if(version == IMQUIC_MOQ_VERSION_11) { - return (type <= 0x03); - } else if(version == IMQUIC_MOQ_VERSION_12 || version == IMQUIC_MOQ_VERSION_13) { - return (type <= 0x05); - } else if(version == IMQUIC_MOQ_VERSION_14) { - return (type <= 0x07 || type == 0x20 || type == 0x21); - } else { - return (type <= 0x0F || (type >= 0x20 && type <= 0x2D)); - } - return FALSE; + return (type <= 0x0F || (type >= 0x20 && type <= 0x2D)); } uint8_t imquic_moq_datagram_message_type_return(imquic_moq_version version, gboolean payload, gboolean ext, gboolean eog, gboolean oid, gboolean priority) { - if(version == IMQUIC_MOQ_VERSION_11) { - /* v11 */ - if(payload) - return ext ? 0x01 : 0x00; - else - return ext ? 0x03 : 0x02; - } else if(version == IMQUIC_MOQ_VERSION_12 || version == IMQUIC_MOQ_VERSION_13) { - /* v12 and v13 */ - if(payload) { - uint8_t type = 0x00; - if(eog) - type |= 0x02; - if(ext) - type |= 0x01; - return type; - } else { - return ext ? 0x05 : 0x04; - } - } else if(version == IMQUIC_MOQ_VERSION_14) { - /* v14 */ - if(payload) { - uint8_t type = 0x00; - if(eog) - type |= 0x02; - if(ext) - type |= 0x01; - if(!oid) - type |= 0x04; - return type; - } else { - return ext ? 0x21 : 0x20; - } - } else { - /* v15 and later */ - uint8_t type = payload ? 0x00 : 0x20; - if(!payload) - eog = FALSE; - if(eog) - type |= 0x02; - if(ext) - type |= 0x01; - if(!oid) - type |= 0x04; - if(!priority) - type |= 0x08; - return type; - } + uint8_t type = payload ? 0x00 : 0x20; + if(!payload) + eog = FALSE; + if(eog) + type |= 0x02; + if(ext) + type |= 0x01; + if(!oid) + type |= 0x04; + if(!priority) + type |= 0x08; + return type; } void imquic_moq_datagram_message_type_parse(imquic_moq_version version, uint8_t type, @@ -746,111 +580,40 @@ void imquic_moq_datagram_message_type_parse(imquic_moq_version version, uint8_t *oid = TRUE; if(priority) *priority = TRUE; - if(version == IMQUIC_MOQ_VERSION_11) { - /* v11 */ - if(payload) - *payload = (type == 0x00 || type == 0x01); - if(ext) - *ext = (type == 0x01 || type == 0x03); - if(violation) - *violation = (type > 0x03); - } else if(version == IMQUIC_MOQ_VERSION_12 || version == IMQUIC_MOQ_VERSION_13) { - /* v12 and v13 */ - if(payload) - *payload = (type <= 0x03); - if(ext) - *ext = (type & 0x01); - if(eog) - *eog = (type & 0x02); - if(violation) - *violation = (type > 0x05); - } else if(version == IMQUIC_MOQ_VERSION_14) { - /* v14 */ - if(payload) - *payload = (type <= 0x07); - if(ext) - *ext = (type & 0x01); - if(eog) - *eog = (type & 0x02); - if(oid) - *oid = !(type & 0x04); - if(violation) - *violation = ((type > 0x05 && type < 0x20) || (type > 0x21)); - } else { - /* v15 and later */ - if(payload) - *payload = !(type & 0x20); - if(ext) - *ext = (type & 0x01); - if(eog) - *eog = (type & 0x02); - if(oid) - *oid = !(type & 0x04); - if(priority) - *priority = !(type & 0x08); - if(violation) - *violation = ((type > 0x0F && type < 0x20) || type > 0x2D || (type >= 0x20 && (type & 0x02))); - } + /* v15 and later */ + if(payload) + *payload = !(type & 0x20); + if(ext) + *ext = (type & 0x01); + if(eog) + *eog = (type & 0x02); + if(oid) + *oid = !(type & 0x04); + if(priority) + *priority = !(type & 0x08); + if(violation) + *violation = ((type > 0x0F && type < 0x20) || type > 0x2D || (type >= 0x20 && (type & 0x02))); } const char *imquic_moq_datagram_message_type_str(uint8_t type, imquic_moq_version version) { - if(version == IMQUIC_MOQ_VERSION_11) { - if(type == 0x00 || type == 0x01) - return "OBJECT_DATAGRAM"; - else if(type == 0x02 || type == 0x03) - return "OBJECT_DATAGRAM_STATUS"; - } else if(version == IMQUIC_MOQ_VERSION_12 || version == IMQUIC_MOQ_VERSION_13) { - if(type <= 0x03) - return "OBJECT_DATAGRAM"; - else if(type == 0x04 || type == 0x05) - return "OBJECT_DATAGRAM_STATUS"; - } else if(version == IMQUIC_MOQ_VERSION_14) { - if(type <= 0x07) - return "OBJECT_DATAGRAM"; - else if(type == 0x20 || type == 0x21) - return "OBJECT_DATAGRAM_STATUS"; - } else { - if(type <= 0x0F) - return "OBJECT_DATAGRAM"; - else if(type >= 0x20 && type <= 0x2D) - return "OBJECT_DATAGRAM_STATUS"; - } + if(type <= 0x0F) + return "OBJECT_DATAGRAM"; + else if(type >= 0x20 && type <= 0x2D) + return "OBJECT_DATAGRAM_STATUS"; return NULL; } gboolean imquic_moq_is_data_message_type_valid(imquic_moq_version version, uint8_t type) { if(type == IMQUIC_MOQ_FETCH_HEADER) return TRUE; - if(version == IMQUIC_MOQ_VERSION_11) { - if(type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_NOEXT_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11 || - type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_NOEXT_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_v11 || - type == IMQUIC_MOQ_SUBGROUP_HEADER_NOEXT_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_v11) - return TRUE; - } else { - if((type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) || - (version >= IMQUIC_MOQ_VERSION_15 && (type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX))) - return TRUE; - } + if((type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) || + (type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX)) + return TRUE; return FALSE; } uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version version, gboolean subgroup, gboolean sgid0, gboolean ext, gboolean eog, gboolean priority) { - if(version == IMQUIC_MOQ_VERSION_11) { - /* v11 */ - if(!subgroup && sgid0 && !ext) - return IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_NOEXT_v11; - else if(!subgroup && sgid0 && ext) - return IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11; - else if(!subgroup && !sgid0 && !ext) - return IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_NOEXT_v11; - else if(!subgroup && !sgid0 && ext) - return IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_v11; - else if(subgroup && !ext) - return IMQUIC_MOQ_SUBGROUP_HEADER_NOEXT_v11; - return IMQUIC_MOQ_SUBGROUP_HEADER_v11; - } - /* If we're here, we're on v12 or later */ uint8_t type = 0; if(subgroup) { sgid0 = FALSE; @@ -862,114 +625,58 @@ uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version ver type |= 0x01; if(eog) type |= 0x08; - if(version >= IMQUIC_MOQ_VERSION_15) - priority = TRUE; type |= (priority ? 0x10 : 0x30); return type; } void imquic_moq_data_message_type_to_subgroup_header(imquic_moq_version version, uint8_t type, gboolean *subgroup, gboolean *sgid0, gboolean *ext, gboolean *eog, gboolean *priority, gboolean *violation) { - if(version == IMQUIC_MOQ_VERSION_11) { - /* v11 */ - if(subgroup) - *subgroup = (type == IMQUIC_MOQ_SUBGROUP_HEADER_NOEXT_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_v11); - if(sgid0) - *sgid0 = (type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_NOEXT_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11); - if(ext) - *ext = (type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_v11 || type == IMQUIC_MOQ_SUBGROUP_HEADER_v11); - if(priority) - *priority = TRUE; - } else { - /* v12 and later */ - uint8_t base = 0x10; - if(type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) { - base = 0x10; - } else if(type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX) { - if(version < IMQUIC_MOQ_VERSION_15) { - /* This range is only allowed starting from v15 */ - if(violation) - *violation = TRUE; - return; - } - base = 0x30; - } - uint8_t bitmask = type - base; - if(bitmask == 0x06 || bitmask == 0x07) { - /* If these bits are set, it's a protocol violation */ - if(violation) - *violation = TRUE; - return; - } - if(priority) - *priority = (base == 0x10); - if(subgroup) - *subgroup = (bitmask & 0x04); - if(sgid0) - *sgid0 = (bitmask & 0x02); - if(ext) - *ext = (bitmask & 0x01); - if(eog) - *eog = (bitmask & 0x08); + uint8_t base = 0x10; + if(type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) { + base = 0x10; + } else if(type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX) { + base = 0x30; + } + uint8_t bitmask = type - base; + if(bitmask == 0x06 || bitmask == 0x07) { + /* If these bits are set, it's a protocol violation */ + if(violation) + *violation = TRUE; + return; } + if(priority) + *priority = (base == 0x10); + if(subgroup) + *subgroup = (bitmask & 0x04); + if(sgid0) + *sgid0 = (bitmask & 0x02); + if(ext) + *ext = (bitmask & 0x01); + if(eog) + *eog = (bitmask & 0x08); } const char *imquic_moq_data_message_type_str(imquic_moq_data_message_type type, imquic_moq_version version) { - if(version == IMQUIC_MOQ_VERSION_11) { - switch(type) { - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_NOEXT_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_NOEXT_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOEXT_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_v11: - return "SUBGROUP_HEADER"; - case IMQUIC_MOQ_FETCH_HEADER: - return "FETCH_HEADER"; - default: break; - } - } else { - if(type == IMQUIC_MOQ_FETCH_HEADER) - return "FETCH_HEADER"; - else if(imquic_moq_is_data_message_type_valid(version, type)) - return "SUBGROUP_HEADER"; - } + if(type == IMQUIC_MOQ_FETCH_HEADER) + return "FETCH_HEADER"; + else if(imquic_moq_is_data_message_type_valid(version, type)) + return "SUBGROUP_HEADER"; return NULL; } imquic_moq_delivery imquic_moq_data_message_type_to_delivery(imquic_moq_data_message_type type, imquic_moq_version version) { - if(version == IMQUIC_MOQ_VERSION_11) { - switch(type) { - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_NOEXT_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID0_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_NOEXT_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOSGID_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_NOEXT_v11: - case IMQUIC_MOQ_SUBGROUP_HEADER_v11: - return IMQUIC_MOQ_USE_SUBGROUP; - case IMQUIC_MOQ_FETCH_HEADER: - return IMQUIC_MOQ_USE_FETCH; - default: break; - } - } else { - if(type == IMQUIC_MOQ_FETCH_HEADER) - return IMQUIC_MOQ_USE_FETCH; - else if((type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) || - (version >= IMQUIC_MOQ_VERSION_15 && (type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX))) - return IMQUIC_MOQ_USE_SUBGROUP; - } + if(type == IMQUIC_MOQ_FETCH_HEADER) + return IMQUIC_MOQ_USE_FETCH; + else if((type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) || + (type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE2_MAX)) + return IMQUIC_MOQ_USE_SUBGROUP; return -1; } gboolean imquic_moq_is_fetch_serialization_flags_valid(imquic_moq_version version, uint64_t flags) { - if(version == IMQUIC_MOQ_VERSION_15) { - return (flags < 0x40); - } else if(version >= IMQUIC_MOQ_VERSION_16) { - if(flags > 128 && flags != (uint64_t)0x8C && flags != (uint64_t)0x10C) - return FALSE; - return TRUE; - } - return FALSE; + if(flags > 128 && flags != (uint64_t)0x8C && flags != (uint64_t)0x10C) + return FALSE; + return TRUE; } uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version version, @@ -1000,20 +707,6 @@ uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version versio void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint64_t flags, imquic_moq_fetch_subgroup_type *subgroup, gboolean *oid, gboolean *group, gboolean *priority, gboolean *ext, gboolean *datagram, gboolean *end_ne_range, gboolean *end_uk_range, gboolean *violation) { - /* For versions previous than v15, we return some defaults */ - if(version < IMQUIC_MOQ_VERSION_15) { - if(subgroup) - *subgroup = IMQUIC_MOQ_FETCH_SUBGROUP_ID; - if(oid) - *oid = TRUE; - if(group) - *group = TRUE; - if(priority) - *priority = TRUE; - if(ext) - *ext = TRUE; - return; - } /* Make sure the provided flags are valid, or return a protocol violation */ if(!imquic_moq_is_fetch_serialization_flags_valid(version, flags)) { if(*violation) @@ -1074,18 +767,10 @@ const char *imquic_moq_setup_parameter_type_str(imquic_moq_setup_parameter_type const char *imquic_moq_request_parameter_type_str(imquic_moq_request_parameter_type type, imquic_moq_version version) { switch(type) { - case IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN_v11: - if(version < IMQUIC_MOQ_VERSION_12) - return "AUTHORIZATION_TOKEN"; - break; case IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT: return "DELIVERY_TIMEOUT"; case IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN: return "AUTHORIZATION_TOKEN"; - case IMQUIC_MOQ_REQUEST_PARAM_MAX_CACHE_DURATION: - return "MAX_CACHE_DURATION"; - case IMQUIC_MOQ_REQUEST_PARAM_PUBLISHER_PRIORITY: - return "PUBLISHER_PRIORITY"; case IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY: return "SUBSCRIBER_PRIORITY"; case IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER: @@ -1098,8 +783,6 @@ const char *imquic_moq_request_parameter_type_str(imquic_moq_request_parameter_t return "LARGEST_OBJECT"; case IMQUIC_MOQ_REQUEST_PARAM_FORWARD: return "FORWARD"; - case IMQUIC_MOQ_REQUEST_PARAM_DYNAMIC_GROUPS: - return "DYNAMIC_GROUPS"; case IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST: return "NEW_GROUP_REQUEST"; default: break; @@ -1199,17 +882,16 @@ size_t imquic_moq_setup_parameters_serialize(imquic_moq_context *moq, list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID)); if(parameters->max_auth_token_cache_size_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE)); - if(moq->version >= IMQUIC_MOQ_VERSION_12 && parameters->auth_token_set) + if(parameters->auth_token_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN)); - if(moq->version >= IMQUIC_MOQ_VERSION_14 && parameters->authority_set) + if(parameters->authority_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_AUTHORITY)); - if(moq->version >= IMQUIC_MOQ_VERSION_14 && parameters->moqt_implementation_set) + if(parameters->moqt_implementation_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION)); *params_num = g_list_length(list); offset += imquic_write_varint(*params_num, &bytes[offset], blen-offset); if(list != NULL) { - if(moq->version >= IMQUIC_MOQ_VERSION_16) - list = g_list_sort(list, imquic_moq_compare_types); + list = g_list_sort(list, imquic_moq_compare_types); GList *temp = list; while(temp) { new_id = GPOINTER_TO_UINT(temp->data); @@ -1251,7 +933,6 @@ void imquic_moq_request_parameters_init_defaults(imquic_moq_request_parameters * if(parameters == NULL) return; memset(parameters, 0, sizeof(imquic_moq_request_parameters)); - parameters->publisher_priority = 128; parameters->subscriber_priority = 128; parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; parameters->forward = TRUE; @@ -1270,39 +951,31 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, uint64_t new_id = 0, last_id = 0; GList *list = NULL; if(parameters->auth_token_set) - list = g_list_append(list, GUINT_TO_POINTER((moq->version >= IMQUIC_MOQ_VERSION_12 ? - IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN : IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN_v11))); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN)); if(parameters->delivery_timeout_set && parameters->delivery_timeout > 0) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT)); - if(parameters->max_cache_duration_set && moq->version <= IMQUIC_MOQ_VERSION_15) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_MAX_CACHE_DURATION)); - if(moq->version == IMQUIC_MOQ_VERSION_15 && parameters->publisher_priority_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_PUBLISHER_PRIORITY)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->subscriber_priority_set) + if(parameters->subscriber_priority_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->group_order_set) + if(parameters->group_order_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->subscription_filter_set) + if(parameters->subscription_filter_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->expires_set) + if(parameters->expires_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_EXPIRES)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->largest_object_set) + if(parameters->largest_object_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->forward_set) + if(parameters->forward_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_FORWARD)); - if(moq->version == IMQUIC_MOQ_VERSION_15 && parameters->dynamic_groups_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_DYNAMIC_GROUPS)); - if(moq->version >= IMQUIC_MOQ_VERSION_15 && parameters->new_group_request_set) + if(parameters->new_group_request_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST)); *params_num = g_list_length(list); offset += imquic_write_varint(*params_num, &bytes[offset], blen-offset); if(list != NULL) { - if(moq->version >= IMQUIC_MOQ_VERSION_16) - list = g_list_sort(list, imquic_moq_compare_types); + list = g_list_sort(list, imquic_moq_compare_types); GList *temp = list; while(temp) { new_id = GPOINTER_TO_UINT(temp->data); - if(new_id == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN || new_id == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN_v11) { + if(new_id == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, parameters->auth_token, parameters->auth_token_len); @@ -1310,14 +983,6 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, parameters->delivery_timeout); - } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_MAX_CACHE_DURATION) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, - new_id, last_id, - parameters->max_cache_duration); - } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_PUBLISHER_PRIORITY) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, - new_id, last_id, - (uint64_t)parameters->publisher_priority); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY) { offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, @@ -1356,10 +1021,6 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, (uint64_t)parameters->forward); - } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_DYNAMIC_GROUPS) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, - new_id, last_id, - (uint64_t)parameters->dynamic_groups); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST) { offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, @@ -1574,7 +1235,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ gboolean bidirectional = FALSE; imquic_parse_stream_id(stream_id, NULL, NULL, &bidirectional); imquic_moq_data_message_type dtype = (imquic_moq_data_message_type)type; - if(bidirectional && type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && moq->version >= IMQUIC_MOQ_VERSION_16) { + if(bidirectional && type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { /* Create a new MoQ stream for namespaces and track it */ IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Stream %"SCNu64" will be used for namespaces\n", imquic_get_connection_name(moq->conn), stream_id); @@ -1607,26 +1268,22 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ if(stream_id == moq->control_stream_id) { /* Control message */ size_t plen = blen-offset; - if((moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_MAX) || - moq->version == IMQUIC_MOQ_VERSION_ANY || moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY) { - /* Versions 11 and beyond require a 16 bit integer */ - tlen = 2; - if(blen - offset < tlen) { - /* Try again later */ - IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ] Not enough bytes available to get the length of the control message (%"SCNu8" > %zu), waiting for more data\n", - imquic_get_connection_name(moq->conn), tlen, blen-offset); - goto done; - } - uint16_t clen = 0; - memcpy(&clen, &bytes[offset], tlen); - plen = ntohs(clen); - offset += tlen; - if(plen > blen-offset) { - /* Try again later */ - IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ] Not enough bytes available to parse this message (%zu > %zu), waiting for more data\n", - imquic_get_connection_name(moq->conn), plen, blen-offset); - goto done; - } + tlen = 2; + if(blen - offset < tlen) { + /* Try again later */ + IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ] Not enough bytes available to get the length of the control message (%"SCNu8" > %zu), waiting for more data\n", + imquic_get_connection_name(moq->conn), tlen, blen-offset); + goto done; + } + uint16_t clen = 0; + memcpy(&clen, &bytes[offset], tlen); + plen = ntohs(clen); + offset += tlen; + if(plen > blen-offset) { + /* Try again later */ + IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ] Not enough bytes available to parse this message (%zu > %zu), waiting for more data\n", + imquic_get_connection_name(moq->conn), plen, blen-offset); + goto done; } if(type == IMQUIC_MOQ_CLIENT_SETUP) { /* Parse this CLIENT_SETUP message */ @@ -1640,21 +1297,15 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } else if(type == IMQUIC_MOQ_REQUESTS_BLOCKED) { /* Parse this REQUESTS_BLOCKED message */ parsed = imquic_moq_parse_requests_blocked(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_REQUEST_OK && moq->version >= IMQUIC_MOQ_VERSION_15 && moq->version <= IMQUIC_MOQ_VERSION_MAX) { + } else if(type == IMQUIC_MOQ_REQUEST_OK) { /* Parse this REQUEST_OK message */ parsed = imquic_moq_parse_request_ok(moq, NULL, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_REQUEST_ERROR && moq->version >= IMQUIC_MOQ_VERSION_15 && moq->version <= IMQUIC_MOQ_VERSION_MAX) { + } else if(type == IMQUIC_MOQ_REQUEST_ERROR) { /* Parse this REQUEST_ERROR message */ parsed = imquic_moq_parse_request_error(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE) { /* Parse this PUBLISH_NAMESPACE message */ parsed = imquic_moq_parse_publish_namespace(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE_OK && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this PUBLISH_NAMESPACE_OK message */ - parsed = imquic_moq_parse_publish_namespace_ok(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE_ERROR && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this PUBLISH_NAMESPACE_ERROR message */ - parsed = imquic_moq_parse_publish_namespace_error(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE) { /* Parse this PUBLISH_NAMESPACE_DONE message */ parsed = imquic_moq_parse_publish_namespace_done(moq, &bytes[offset], plen, &error); @@ -1667,9 +1318,6 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } else if(type == IMQUIC_MOQ_PUBLISH_OK) { /* Parse this PUBLISH_OK message */ parsed = imquic_moq_parse_publish_ok(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_PUBLISH_ERROR && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this PUBLISH_ERROR message */ - parsed = imquic_moq_parse_publish_error(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_SUBSCRIBE) { /* Parse this SUBSCRIBE message */ parsed = imquic_moq_parse_subscribe(moq, &bytes[offset], plen, &error); @@ -1679,27 +1327,12 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } else if(type == IMQUIC_MOQ_SUBSCRIBE_OK) { /* Parse this SUBSCRIBE_OK message */ parsed = imquic_moq_parse_subscribe_ok(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_SUBSCRIBE_ERROR && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this SUBSCRIBE_ERROR message */ - parsed = imquic_moq_parse_subscribe_error(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_UNSUBSCRIBE) { /* Parse this UNSUBSCRIBE message */ parsed = imquic_moq_parse_unsubscribe(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_DONE) { /* Parse this PUBLISH_DONE message */ parsed = imquic_moq_parse_publish_done(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_15) { - /* Parse this SUBSCRIBE_NAMESPACE message */ - parsed = imquic_moq_parse_subscribe_namespace(moq, NULL, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_OK && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this SUBSCRIBE_NAMESPACE_OK message */ - parsed = imquic_moq_parse_subscribe_namespace_ok(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_ERROR && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this SUBSCRIBE_NAMESPACE_ERROR message */ - parsed = imquic_moq_parse_subscribe_namespace_error(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_15) { - /* Parse this UNSUBSCRIBE_NAMESPACE message */ - parsed = imquic_moq_parse_unsubscribe_namespace(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_FETCH) { /* Parse this FETCH message */ parsed = imquic_moq_parse_fetch(moq, &bytes[offset], plen, &error); @@ -1709,18 +1342,9 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } else if(type == IMQUIC_MOQ_FETCH_OK) { /* Parse this FETCH_OK message */ parsed = imquic_moq_parse_fetch_ok(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_FETCH_ERROR && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this FETCH_ERROR message */ - parsed = imquic_moq_parse_fetch_error(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_TRACK_STATUS) { /* Parse this TRACK_STATUS message */ parsed = imquic_moq_parse_track_status(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_TRACK_STATUS_OK && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this TRACK_STATUS_OK message */ - parsed = imquic_moq_parse_track_status_ok(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_TRACK_STATUS_ERROR && moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14) { - /* Parse this TRACK_STATUS_ERROR message */ - parsed = imquic_moq_parse_track_status_error(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_GOAWAY) { /* Parse this GOAWAY message */ parsed = imquic_moq_parse_goaway(moq, &bytes[offset], plen, &error); @@ -1939,45 +1563,6 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si } size_t offset = 0; uint8_t length = 0; - /* Version is only negotiated here for versions up to v14 */ - uint64_t supported_vers = 0, i = 0; - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) { - supported_vers = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken CLIENT_SETUP"); - offset += length; - uint64_t version = 0; - gboolean version_set = FALSE; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- %"SCNu64" supported versions:\n", - imquic_get_connection_name(moq->conn), supported_vers); - g_list_free(moq->supported_versions); - moq->supported_versions = NULL; - for(i = 0; i= blen-offset, NULL, 0, 0, "Broken CLIENT_SETUP"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- %"SCNu64" (expected %"SCNu32" -- %"SCNu32")\n", - imquic_get_connection_name(moq->conn), version, IMQUIC_MOQ_VERSION_MIN, IMQUIC_MOQ_VERSION_MAX); - if(!version_set) { - if(version == moq->version && moq->version <= IMQUIC_MOQ_VERSION_MAX) { - version_set = TRUE; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- Selected version %"SCNu32"\n", - imquic_get_connection_name(moq->conn), moq->version); - } else if((version >= IMQUIC_MOQ_VERSION_MIN && version <= IMQUIC_MOQ_VERSION_14) && moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY) { - moq->version = version; - version_set = TRUE; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- Selected version %"SCNu32"\n", - imquic_get_connection_name(moq->conn), moq->version); - } else { - /* Keep looking */ - version = 0; - } - } - uint32_t v = version; - moq->supported_versions = g_list_prepend(moq->supported_versions, GUINT_TO_POINTER(v)); - offset += length; - } - moq->supported_versions = g_list_reverse(moq->supported_versions); - IMQUIC_MOQ_CHECK_ERR(version == 0, error, IMQUIC_MOQ_VERSION_NEGOTIATION_FAILED, 0, "No supported version"); - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); @@ -1985,7 +1570,7 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- %"SCNu64" parameters:\n", imquic_get_connection_name(moq->conn), params_num); imquic_moq_setup_parameters parameters = { 0 }; - uint64_t param = 0; + uint64_t param = 0, i = 0; for(i = 0; imax_auth_token_cache_size = parameters.max_auth_token_cache_size; } - if(parameters.moqt_implementation_set && moq->version >= IMQUIC_MOQ_VERSION_14) { + if(parameters.moqt_implementation_set) { /* Take note of the implemntation */ g_free(moq->peer_implementation); moq->peer_implementation = NULL; @@ -2023,16 +1608,6 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("client_setup"); - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) { - json_object_set_new(message, "number_of_supported_versions", json_integer(supported_vers)); - json_t *versions = json_array(); - GList *temp = moq->supported_versions; - while(temp) { - json_array_append_new(versions, json_integer(GPOINTER_TO_UINT(temp->data))); - temp = temp->next; - } - json_object_set_new(message, "supported_versions", versions); - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_setup_parameters(message, ¶meters, "setup_parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); @@ -2056,14 +1631,12 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si s_parameters.max_auth_token_cache_size_set = TRUE; s_parameters.max_auth_token_cache_size = moq->local_max_auth_token_cache_size; } - if(moq->version >= IMQUIC_MOQ_VERSION_14) { - /* FIXME */ - s_parameters.moqt_implementation_set = TRUE; - g_snprintf(s_parameters.moqt_implementation, sizeof(s_parameters.moqt_implementation), "imquic %s", imquic_version_string_full); - } + /* Add the implementation */ + s_parameters.moqt_implementation_set = TRUE; + g_snprintf(s_parameters.moqt_implementation, sizeof(s_parameters.moqt_implementation), "imquic %s", imquic_version_string_full); uint8_t buffer[200]; size_t buflen = sizeof(buffer); - size_t ss_len = imquic_moq_add_server_setup(moq, buffer, buflen, moq->version, &s_parameters); + size_t ss_len = imquic_moq_add_server_setup(moq, buffer, buflen, &s_parameters); imquic_connection_send_on_stream(moq->conn, moq->control_stream_id, buffer, ss_len, FALSE); g_atomic_int_set(&moq->connected, 1); @@ -2083,27 +1656,6 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - /* Version is only negotiated here for versions up to v14 */ - uint64_t version = 0; - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) { - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Supported version:\n", - imquic_get_connection_name(moq->conn)); - version = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SERVER_SETUP"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- %"SCNu64" (expected %"SCNu32" -- %"SCNu32")\n", - imquic_get_connection_name(moq->conn), version, IMQUIC_MOQ_VERSION_MIN, IMQUIC_MOQ_VERSION_MAX); - if(version == moq->version && moq->version <= IMQUIC_MOQ_VERSION_MAX) { - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Selected version %"SCNu32"\n", - imquic_get_connection_name(moq->conn), moq->version); - } else if((version >= IMQUIC_MOQ_VERSION_MIN && version <= IMQUIC_MOQ_VERSION_14) && moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY) { - moq->version = version; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Selected version %"SCNu32"\n", - imquic_get_connection_name(moq->conn), moq->version); - } else { - IMQUIC_MOQ_CHECK_ERR(version == 0, error, IMQUIC_MOQ_VERSION_NEGOTIATION_FAILED, 0, "No supported version"); - } - offset += length; - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); @@ -2125,7 +1677,7 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si /* Update the value we have */ moq->max_auth_token_cache_size = parameters.max_auth_token_cache_size; } - if(parameters.moqt_implementation_set && moq->version >= IMQUIC_MOQ_VERSION_14) { + if(parameters.moqt_implementation_set) { /* Take note of the implemntation */ g_free(moq->peer_implementation); moq->peer_implementation = NULL; @@ -2134,11 +1686,11 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si } if(parameters.path_set) { /* Servers can't use PATH */ - IMQUIC_MOQ_CHECK_ERR(version == 0, error, IMQUIC_MOQ_INVALID_PATH, 0, "PATH received from a server"); + IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_INVALID_PATH, 0, "PATH received from a server"); } if(parameters.authority_set) { /* Servers can't use AUTHORITY */ - IMQUIC_MOQ_CHECK_ERR(version == 0, error, IMQUIC_MOQ_INVALID_PATH, 0, "AUTHORITY received from a server"); + IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_INVALID_PATH, 0, "AUTHORITY received from a server"); } if(moq->max_request_id == 0) { IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] No Max Request ID parameter received, setting it to 1\n", @@ -2148,8 +1700,6 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("server_setup"); - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) - json_object_set_new(message, "selected_version", json_integer(version)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_setup_parameters(message, ¶meters, "setup_parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); @@ -2223,7 +1773,7 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_16 && moq_stream != NULL && + IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && (moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2))), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK for SUBSCRIBE_NAMESPACE"); size_t offset = 0; @@ -2276,7 +1826,7 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m break; case IMQUIC_MOQ_TRACK_STATUS: if(moq->conn->socket && moq->conn->socket->callbacks.moq.track_status_accepted) - moq->conn->socket->callbacks.moq.track_status_accepted(moq->conn, request_id, 0, ¶meters); + moq->conn->socket->callbacks.moq.track_status_accepted(moq->conn, request_id, ¶meters); break; default: IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Couldn't find a request associated to ID %"SCNu64" (type %d), can't notify success\n", @@ -2293,7 +1843,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_16 && moq_stream != NULL && + IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && (moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2))), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR for SUBSCRIBE_NAMESPACE"); size_t offset = 0; @@ -2308,14 +1858,11 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_error_code_str(error_code), error_code); - uint64_t retry_interval = 0; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - retry_interval = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Retry Interval: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), retry_interval); - } + uint64_t retry_interval = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Retry Interval: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), retry_interval); uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); offset += length; @@ -2337,8 +1884,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream json_t *message = imquic_qlog_moq_message_prepare("request_error"); json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "error_code", json_integer(error_code)); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - json_object_set_new(message, "retry_interval", json_integer(retry_interval)); + json_object_set_new(message, "retry_interval", json_integer(retry_interval)); if(reason_str != NULL) json_object_set_new(message, "reason", json_string(reason_str)); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, @@ -2365,7 +1911,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream break; case IMQUIC_MOQ_SUBSCRIBE: if(moq->conn->socket && moq->conn->socket->callbacks.moq.subscribe_error) - moq->conn->socket->callbacks.moq.subscribe_error(moq->conn, request_id, error_code, reason_str, 0, retry_interval); + moq->conn->socket->callbacks.moq.subscribe_error(moq->conn, request_id, error_code, reason_str, retry_interval); break; case IMQUIC_MOQ_REQUEST_UPDATE: if(moq->conn->socket && moq->conn->socket->callbacks.moq.request_update_error) @@ -2443,89 +1989,6 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *byte return offset; } -size_t imquic_moq_parse_publish_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_ok" : "publish_namespace_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.publish_namespace_accepted) { - imquic_moq_request_parameters params; - imquic_moq_request_parameters_init_defaults(¶ms); - moq->conn->socket->callbacks.moq.publish_namespace_accepted(moq->conn, request_id, ¶ms); - } - if(error) - *error = 0; - return offset; -} - -size_t imquic_moq_parse_publish_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_error_code_str(error_code), error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_ERROR"); - offset += length; - char reason[1024], *reason_str = NULL; - if(rs_len > 0) { - IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_ERROR"); - IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); - int reason_len = (int)rs_len; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Reason Phrase: %.*s\n", - imquic_get_connection_name(moq->conn), reason_len, &bytes[offset]); - if(reason_len > 0) { - g_snprintf(reason, sizeof(reason), "%.*s", reason_len, &bytes[offset]); - reason_str = reason; - } - offset += reason_len; - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "publish_namespace_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error_code)); - if(reason_str != NULL) - json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.publish_namespace_error) { - moq->conn->socket->callbacks.moq.publish_namespace_error(moq->conn, - request_id, error_code, reason_str, 0); - } - if(error) - *error = 0; - return offset; -} - size_t imquic_moq_parse_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; @@ -2626,48 +2089,8 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", imquic_get_connection_name(moq->conn), track_alias); - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(group_order > IMQUIC_MOQ_ORDERING_DESCENDING, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken PUBLISH"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - uint8_t content_exists = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(content_exists > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Content Exists value"); - IMQUIC_MOQ_CHECK_ERR(content_exists && blen-offset == 0, NULL, 0, 0, "Broken PUBLISH"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Content Exists: %"SCNu8"\n", - imquic_get_connection_name(moq->conn), content_exists); - if(content_exists > 0) { - parameters.largest_object_set = TRUE; - parameters.largest_object.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Group ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.largest_object.group); - parameters.largest_object.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Object ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.largest_object.object); - } - uint8_t forward = bytes[offset]; - IMQUIC_MOQ_CHECK_ERR(forward > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Forward value"); - parameters.forward_set = TRUE; - parameters.forward = (forward > 0); - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken PUBLISH"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Forward: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.forward); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken PUBLISH"); - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken PUBLISH"); @@ -2682,17 +2105,14 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t } /* v16 added support for Track Extensions */ size_t ext_offset = 0, ext_len = 0; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* The message contains extensions */ - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken PUBLISH"); - offset += ext_len; - } + ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), ext_len); + ext_offset = offset; + IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken PUBLISH"); + offset += ext_len; GList *track_extensions = NULL; if(ext_offset > 0 && ext_len > 0) { /* TODO Check Protocol Violation cases */ @@ -2705,19 +2125,9 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "track_alias", json_integer(track_alias)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - json_object_set_new(message, "content_exists", json_integer(parameters.largest_object_set)); - if(parameters.largest_object_set) { - json_object_set_new(message, "largest_group_id", json_integer(parameters.largest_object.group)); - json_object_set_new(message, "largest_object_id", json_integer(parameters.largest_object.object)); - } - json_object_set_new(message, "forward", json_integer(parameters.forward)); - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -2750,61 +2160,8 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - uint8_t forward = bytes[offset]; - IMQUIC_MOQ_CHECK_ERR(forward > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Forward value"); - parameters.forward_set = TRUE; - parameters.forward = (forward > 0); - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken PUBLISH_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Forward: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.forward); - parameters.subscriber_priority_set = TRUE; - parameters.subscriber_priority = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken PUBLISH_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Subscriber Priority: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.subscriber_priority); - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR((group_order > IMQUIC_MOQ_ORDERING_DESCENDING), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken PUBLISH_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - uint64_t filter = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_OK"); - IMQUIC_MOQ_CHECK_ERR((filter < 0x1 || filter > 0x4), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Filter type"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Filter type: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_filter_type_str(filter), filter); - parameters.subscription_filter_set = TRUE; - parameters.subscription_filter.type = filter; - if(filter == IMQUIC_MOQ_FILTER_ABSOLUTE_START || filter == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - parameters.subscription_filter.start_location.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.group); - parameters.subscription_filter.start_location.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Object: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.object); - } - if(filter == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - parameters.subscription_filter.end_group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.end_group); - } - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken PUBLISH_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken PUBLISH_OK"); @@ -2821,18 +2178,6 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_ok"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "forward", json_integer(parameters.forward)); - json_object_set_new(message, "subscriber_priority", json_integer(parameters.subscriber_priority)); - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - json_object_set_new(message, "filter_type", json_integer(parameters.subscription_filter.type)); - if(parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - json_object_set_new(message, "start_group", json_integer(parameters.subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters.subscription_filter.start_location.object)); - } - if(parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - json_object_set_new(message, "end_group", json_integer(parameters.subscription_filter.end_group)); - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); @@ -2846,7 +2191,7 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size return offset; } -size_t imquic_moq_parse_publish_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) @@ -2854,134 +2199,19 @@ size_t imquic_moq_parse_publish_error(imquic_moq_context *moq, uint8_t *bytes, s size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_ERROR"); - offset += length; - uint64_t recvd_error_code = error_code; - if(moq->version < IMQUIC_MOQ_VERSION_15) - error_code = imquic_moq_request_error_code_from_legacy(moq->version, error_code); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_request_error_code_str(error_code), recvd_error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH_ERROR"); - offset += length; - char reason[1024], *reason_str = NULL; - if(rs_len > 0) { - IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken PUBLISH_ERROR"); - IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); - int reason_len = (int)rs_len; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Reason Phrase: %.*s\n", - imquic_get_connection_name(moq->conn), reason_len, &bytes[offset]); - if(reason_len > 0) { - g_snprintf(reason, sizeof(reason), "%.*s", reason_len, &bytes[offset]); - reason_str = reason; - } - offset += reason_len; - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "publish_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(recvd_error_code)); - if(reason_str != NULL) - json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.publish_error) - moq->conn->socket->callbacks.moq.publish_error(moq->conn, request_id, error_code, reason_str, 0); - if(error) - *error = 0; - return offset; -} - -size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); /* Move on */ - uint64_t track_alias = 0; - if(moq->version < IMQUIC_MOQ_VERSION_12) { - track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), track_alias); - } imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE, tns_num, i, "Broken SUBSCRIBE", FALSE); imquic_moq_name tn = { 0 }; IMQUIC_MOQ_PARSE_TRACKNAME("Broken SUBSCRIBE", FALSE); - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - parameters.subscriber_priority_set = TRUE; - parameters.subscriber_priority = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Subscriber Priority: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.subscriber_priority); - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR((group_order > IMQUIC_MOQ_ORDERING_DESCENDING), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - uint8_t forward = bytes[offset]; - IMQUIC_MOQ_CHECK_ERR(forward > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Forward value"); - parameters.forward_set = TRUE; - parameters.forward = (forward > 0); - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Forward: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), forward); - uint64_t filter = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); - IMQUIC_MOQ_CHECK_ERR((filter < 0x1 || filter > 0x4), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Filter type"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Filter type: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_filter_type_str(filter), filter); - parameters.subscription_filter_set = TRUE; - parameters.subscription_filter.type = filter; - if(filter == IMQUIC_MOQ_FILTER_ABSOLUTE_START || filter == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - parameters.subscription_filter.start_location.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.group); - parameters.subscription_filter.start_location.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Object: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.object); - } - if(filter == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - parameters.subscription_filter.end_group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.end_group); - } - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SUBSCRIBE"); @@ -2998,22 +2228,8 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("subscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version < IMQUIC_MOQ_VERSION_12) - json_object_set_new(message, "track_alias", json_integer(track_alias)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "subscriber_priority", json_integer(parameters.subscriber_priority)); - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - json_object_set_new(message, "forward", json_integer(parameters.forward)); - json_object_set_new(message, "filter_type", json_integer(parameters.subscription_filter.type)); - if(parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - json_object_set_new(message, "start_group", json_integer(parameters.subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters.subscription_filter.start_location.object)); - } - if(parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - json_object_set_new(message, "end_group", json_integer(parameters.subscription_filter.end_group)); - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); @@ -3023,19 +2239,17 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; /* Track this subscription */ - imquic_moq_subscription *moq_sub = imquic_moq_subscription_create(request_id, track_alias); + imquic_moq_subscription *moq_sub = imquic_moq_subscription_create(request_id, 0); imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->subscriptions_by_id, imquic_dup_uint64(request_id), moq_sub); - if(moq->version < IMQUIC_MOQ_VERSION_12) - g_hash_table_insert(moq->subscriptions, imquic_dup_uint64(track_alias), moq_sub); imquic_mutex_unlock(&moq->mutex); /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_subscribe) { moq->conn->socket->callbacks.moq.incoming_subscribe(moq->conn, - request_id, track_alias, &tns[0], &tn, ¶meters); + request_id, &tns[0], &tn, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ - imquic_moq_reject_subscribe(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", track_alias, 0); + imquic_moq_reject_subscribe(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); } if(error) *error = 0; @@ -3054,51 +2268,13 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t sub_request_id = 0; - if(moq->version >= IMQUIC_MOQ_VERSION_14) { - sub_request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Subscription Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), sub_request_id); - } - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ + uint64_t sub_request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Subscription Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), sub_request_id); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - parameters.subscription_filter_set = TRUE; - parameters.subscription_filter.type = IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE; /* FIXME */ - parameters.subscription_filter.start_location.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.group); - parameters.subscription_filter.start_location.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Object: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.object); - parameters.subscription_filter.end_group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.end_group); - parameters.subscriber_priority_set = TRUE; - parameters.subscriber_priority = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken REQUEST_UPDATE"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Subscriber Priority: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.subscriber_priority); - uint8_t forward = bytes[offset]; - IMQUIC_MOQ_CHECK_ERR(forward > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Forward value"); - parameters.forward_set = TRUE; - parameters.forward = (forward > 0); - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken REQUEST_UPDATE"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Forward: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), forward); - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken REQUEST_UPDATE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken REQUEST_UPDATE"); @@ -3115,30 +2291,19 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_update"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version >= IMQUIC_MOQ_VERSION_14) - json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "start_group", json_integer(parameters.subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters.subscription_filter.start_location.object)); - json_object_set_new(message, "end_group", json_integer(parameters.subscription_filter.end_group)); - json_object_set_new(message, "subscriber_priority", json_integer(parameters.subscriber_priority)); - json_object_set_new(message, "forward", json_integer(parameters.forward)); - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - } + json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif - if(moq->version >= IMQUIC_MOQ_VERSION_14) { - /* Make sure this is in line with the expected request ID */ - IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); - moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; - } + /* Make sure this is in line with the expected request ID */ + IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); + moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.request_updated) { moq->conn->socket->callbacks.moq.request_updated(moq->conn, request_id, sub_request_id, ¶meters); - } else if(moq->version != IMQUIC_MOQ_VERSION_15) { + } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_request_update(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); } @@ -3159,55 +2324,13 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t track_alias = 0; - if(moq->version >= IMQUIC_MOQ_VERSION_12) { - track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), track_alias); - } - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ + uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), track_alias); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - parameters.expires_set = TRUE; - parameters.expires = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Expires: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.expires); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR((group_order > IMQUIC_MOQ_ORDERING_DESCENDING), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - uint8_t content_exists = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(content_exists > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Content Exists value"); - IMQUIC_MOQ_CHECK_ERR(content_exists && blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Content Exists: %"SCNu8"\n", - imquic_get_connection_name(moq->conn), content_exists); - if(content_exists > 0) { - parameters.largest_object_set = TRUE; - parameters.largest_object.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Group ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.largest_object.group); - parameters.largest_object.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Object ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.largest_object.object); - } - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); @@ -3222,17 +2345,14 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si } /* v16 added support for Track Extensions */ size_t ext_offset = 0, ext_len = 0; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* The message contains extensions */ - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += ext_len; - } + ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), ext_len); + ext_offset = offset; + IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); + offset += ext_len; GList *track_extensions = NULL; if(ext_offset > 0 && ext_len > 0) { /* TODO Check Protocol Violation cases */ @@ -3242,21 +2362,10 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("subscribe_ok"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version >= IMQUIC_MOQ_VERSION_12) - json_object_set_new(message, "track_alias", json_integer(track_alias)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "expires", json_integer(parameters.expires)); - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - json_object_set_new(message, "content_exists", json_integer(parameters.largest_object_set)); - if(parameters.largest_object_set) { - json_object_set_new(message, "largest_group_id", json_integer(parameters.largest_object.group)); - json_object_set_new(message, "largest_object_id", json_integer(parameters.largest_object.object)); - } - } + json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -3271,73 +2380,6 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si return offset; } -size_t imquic_moq_parse_subscribe_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_ERROR"); - offset += length; - uint64_t recvd_error_code = error_code; - if(moq->version < IMQUIC_MOQ_VERSION_15) - error_code = imquic_moq_request_error_code_from_legacy(moq->version, error_code); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_request_error_code_str(error_code), recvd_error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_ERROR"); - offset += length; - char reason[1024], *reason_str = NULL; - if(rs_len > 0) { - IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_ERROR"); - IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); - int reason_len = (int)rs_len; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Reason Phrase: %.*s\n", - imquic_get_connection_name(moq->conn), reason_len, &bytes[offset]); - if(reason_len > 0) { - g_snprintf(reason, sizeof(reason), "%.*s", reason_len, &bytes[offset]); - reason_str = reason; - } - offset += reason_len; - } - uint64_t track_alias = 0; - if(moq->version < IMQUIC_MOQ_VERSION_12) { - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken SUBSCRIBE_ERROR"); - track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), track_alias); - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "subscribe_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version < IMQUIC_MOQ_VERSION_12) - json_object_set_new(message, "track_alias", json_integer(track_alias)); - json_object_set_new(message, "error_code", json_integer(recvd_error_code)); - if(reason_str != NULL) - json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.subscribe_error) { - moq->conn->socket->callbacks.moq.subscribe_error(moq->conn, - request_id, error_code, reason_str, track_alias, 0); - } - if(error) - *error = 0; - return offset; -} - size_t imquic_moq_parse_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; @@ -3437,8 +2479,8 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_16 && (moq_stream == NULL || - !moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 0, 1))), + IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || + !moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 0, 1)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_NAMESPACE"); size_t offset = 0; uint8_t length = 0; @@ -3451,12 +2493,9 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE, tns_num, i, "Broken SUBSCRIBE_NAMESPACE", FALSE); - imquic_moq_subscribe_namespace_options subscribe_options = IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - subscribe_options = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset || subscribe_options > IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); - offset += length; - } + imquic_moq_subscribe_namespace_options subscribe_options = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset || subscribe_options > IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); + offset += length; uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); @@ -3472,13 +2511,12 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - if(moq->version >= IMQUIC_MOQ_VERSION_16 && moq_stream != NULL) + if(moq_stream != NULL) imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe_namespace"); json_t *message = imquic_qlog_moq_message_prepare("subscribe_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace_prefix"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); + json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, @@ -3489,7 +2527,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; /* If we're on a recent version of MoQ, track this subscription via its request ID */ - if(moq->version >= IMQUIC_MOQ_VERSION_16 && moq_stream != NULL) { + if(moq_stream != NULL) { moq_stream->request_id = request_id; moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); while(moq_stream->last_tuple->next != NULL) @@ -3512,124 +2550,6 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ return offset; } -size_t imquic_moq_parse_subscribe_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_ok" : "subscribe_namespace_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.subscribe_namespace_accepted) { - imquic_moq_request_parameters params; - imquic_moq_request_parameters_init_defaults(¶ms); - moq->conn->socket->callbacks.moq.subscribe_namespace_accepted(moq->conn, request_id, ¶ms); - } - if(error) - *error = 0; - return offset; -} - -size_t imquic_moq_parse_subscribe_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_error_code_str(error_code), error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE_ERROR"); - offset += length; - char reason[1024], *reason_str = NULL; - if(rs_len > 0) { - IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE_ERROR"); - IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); - int reason_len = (int)rs_len; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Reason Phrase: %.*s\n", - imquic_get_connection_name(moq->conn), reason_len, &bytes[offset]); - if(reason_len > 0) { - g_snprintf(reason, sizeof(reason), "%.*s", reason_len, &bytes[offset]); - reason_str = reason; - } - offset += reason_len; - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "subscribe_namespace_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error_code)); - if(reason_str != NULL) - json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.subscribe_namespace_error) - moq->conn->socket->callbacks.moq.subscribe_namespace_error(moq->conn, request_id, error_code, reason_str, 0); - if(error) - *error = 0; - return offset; -} - -size_t imquic_moq_parse_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - imquic_moq_namespace tns[32]; - memset(&tns, 0, sizeof(tns)); - uint64_t tns_num = 0, i = 0; - uint64_t request_id = 0; - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken UNSUBSCRIBE_NAMESPACE"); - offset += length; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE, tns_num, i, "Broken UNSUBSCRIBE_NAMESPACE", TRUE); - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare("unsubscribe_namespace"); - if(moq->version >= IMQUIC_MOQ_VERSION_15) - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) - imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace) - moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace(moq->conn, request_id, &tns[0]); - if(error) - *error = 0; - return offset; -} - size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; @@ -3710,26 +2630,6 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); imquic_moq_name tn = { 0 }; - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ - imquic_moq_request_parameters parameters; - imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - parameters.subscriber_priority_set = TRUE; - parameters.subscriber_priority = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken FETCH"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Subscriber Priority: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.subscriber_priority); - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(group_order > IMQUIC_MOQ_ORDERING_DESCENDING, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken FETCH"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - } imquic_moq_fetch_type type = IMQUIC_MOQ_FETCH_STANDALONE; imquic_moq_location_range range = { 0 }; uint64_t joining_request_id = 0, joining_start = 0; @@ -3772,6 +2672,8 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl imquic_get_connection_name(moq->conn), type); return 0; } + imquic_moq_request_parameters parameters; + imquic_moq_request_parameters_init_defaults(¶meters); uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken FETCH"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken FETCH"); @@ -3788,10 +2690,6 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "subscriber_priority", json_integer(parameters.subscriber_priority)); - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - } json_object_set_new(message, "fetch_type", json_integer(type)); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); @@ -3893,20 +2791,6 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken FETCH_OK"); - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ - imquic_moq_request_parameters parameters; - imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(group_order > IMQUIC_MOQ_ORDERING_DESCENDING, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken FETCH_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - } uint8_t end_of_track = bytes[offset]; offset++; IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken FETCH_OK"); @@ -3923,6 +2807,8 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Object ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), largest.object); + imquic_moq_request_parameters parameters; + imquic_moq_request_parameters_init_defaults(¶meters); uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken FETCH_OK"); @@ -3932,22 +2818,19 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t uint64_t i = 0, param = 0; for(i = 0; iversion >= IMQUIC_MOQ_VERSION_16) { - /* The message contains extensions */ - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken FETCH_OK"); - offset += ext_len; + offset += imquic_moq_parse_request_parameter(moq, &bytes[offset], blen-offset, ¶meters, ¶m, error); + IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken FETCH_OK"); } + /* v16 added support for Track Extensions */ + size_t ext_offset = 0, ext_len = 0; + ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), ext_len); + ext_offset = offset; + IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken FETCH_OK"); + offset += ext_len; GList *track_extensions = NULL; if(ext_offset > 0 && ext_len > 0) { /* TODO Check Protocol Violation cases */ @@ -3957,15 +2840,12 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch_ok"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); json_object_set_new(message, "end_of_track", json_integer(end_of_track)); json_object_set_new(message, "largest_group_id", json_integer(largest.group)); json_object_set_new(message, "largest_object_id", json_integer(largest.object)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -3978,72 +2858,11 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t return offset; } -size_t imquic_moq_parse_fetch_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH_ERROR"); - offset += length; - uint64_t recvd_error_code = error_code; - if(moq->version < IMQUIC_MOQ_VERSION_15) - error_code = imquic_moq_request_error_code_from_legacy(moq->version, error_code); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_request_error_code_str(error_code), recvd_error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken FETCH_ERROR"); - offset += length; - char reason[1024], *reason_str = NULL; - if(rs_len > 0) { - IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken FETCH_ERROR"); - IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); - int reason_len = (int)rs_len; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Reason Phrase: %.*s\n", - imquic_get_connection_name(moq->conn), reason_len, &bytes[offset]); - if(reason_len > 0) { - g_snprintf(reason, sizeof(reason), "%.*s", reason_len, &bytes[offset]); - reason_str = reason; - } - offset += reason_len; - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "fetch_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(recvd_error_code)); - if(reason_str != NULL) - json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.fetch_error) - moq->conn->socket->callbacks.moq.fetch_error(moq->conn, request_id, error_code, reason_str, 0); - if(error) - *error = 0; - return offset; -} - size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - if(moq->version < IMQUIC_MOQ_VERSION_13) { - /* Since the format changed too much, we ignored it on versions older than v13 */ - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Ignoring %s on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS, moq->version), - imquic_moq_version_str(moq->version)); - return blen; - } size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); @@ -4058,61 +2877,8 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_TRACK_STATUS, tns_num, i, "Broken TRACK_STATUS", FALSE); imquic_moq_name tn = { 0 }; IMQUIC_MOQ_PARSE_TRACKNAME("Broken TRACK_STATUS", FALSE); - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - parameters.subscriber_priority_set = TRUE; - parameters.subscriber_priority = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Subscriber Priority: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.subscriber_priority); - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(group_order > IMQUIC_MOQ_ORDERING_DESCENDING, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - uint8_t forward = bytes[offset]; - IMQUIC_MOQ_CHECK_ERR(forward > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Forward value"); - parameters.forward_set = TRUE; - parameters.forward = (forward > 0); - offset++; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Forward: %"SCNu8")\n", - imquic_get_connection_name(moq->conn), parameters.forward); - uint64_t filter = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS"); - IMQUIC_MOQ_CHECK_ERR((filter < 0x1 || filter > 0x4), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Filter type"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Filter type: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_filter_type_str(filter), filter); - parameters.subscription_filter_set = TRUE; - parameters.subscription_filter.type = filter; - if(filter == IMQUIC_MOQ_FILTER_ABSOLUTE_START || filter == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - parameters.subscription_filter.start_location.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.group); - parameters.subscription_filter.start_location.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Object: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.start_location.object); - } - if(filter == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - parameters.subscription_filter.end_group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Group: %"SCNu64")\n", - imquic_get_connection_name(moq->conn), parameters.subscription_filter.end_group); - } - } uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken TRACK_STATUS"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken TRACK_STATUS"); @@ -4131,18 +2897,6 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "subscriber_priority", json_integer(parameters.subscriber_priority)); - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - json_object_set_new(message, "forward", json_integer(parameters.forward)); - json_object_set_new(message, "filter_type", json_integer(parameters.subscription_filter.type)); - if(parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - json_object_set_new(message, "start_group", json_integer(parameters.subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters.subscription_filter.start_location.object)); - } - if(parameters.subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - json_object_set_new(message, "end_group", json_integer(parameters.subscription_filter.end_group)); - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); @@ -4164,172 +2918,6 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si return offset; } -size_t imquic_moq_parse_track_status_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - if(moq->version < IMQUIC_MOQ_VERSION_13) { - /* Since the format changed too much, we ignored it on versions older than v13 */ - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Ignoring %s on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS, moq->version), - imquic_moq_version_str(moq->version)); - return blen; - } - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t track_alias = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), track_alias); - } - /* For versions older than v15, we need to parse some attributes manually, - * but we'll add them to the parameters object for the application anyway */ - imquic_moq_request_parameters parameters; - imquic_moq_request_parameters_init_defaults(¶meters); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - parameters.expires_set = TRUE; - parameters.expires = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Expires: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.expires); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - uint8_t group_order = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(group_order > IMQUIC_MOQ_ORDERING_DESCENDING, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Group Order value"); - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Group Order: %"SCNu8" (%s)\n", - imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); - parameters.group_order_set = TRUE; - parameters.group_order = group_order; - uint8_t content_exists = bytes[offset]; - offset++; - IMQUIC_MOQ_CHECK_ERR(content_exists > 1, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Content Exists value"); - IMQUIC_MOQ_CHECK_ERR(content_exists && blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Content Exists: %"SCNu8"\n", - imquic_get_connection_name(moq->conn), content_exists); - if(content_exists > 0) { - parameters.largest_object_set = TRUE; - parameters.largest_object.group = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Group ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.largest_object.group); - parameters.largest_object.object = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Object ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), parameters.largest_object.object); - } - } - uint64_t params_num = 0; - IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken TRACK_STATUS_OK"); - params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken TRACK_STATUS_OK"); - IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken TRACK_STATUS_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- %"SCNu64" parameters:\n", - imquic_get_connection_name(moq->conn), params_num); - uint64_t i = 0, param = 0; - for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_ok" : "track_status_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "track_alias", json_integer(track_alias)); - json_object_set_new(message, "expires", json_integer(parameters.expires)); - json_object_set_new(message, "group_order", json_integer(parameters.group_order)); - json_object_set_new(message, "content_exists", json_integer(parameters.largest_object_set)); - if(parameters.largest_object_set) { - json_object_set_new(message, "largest_group_id", json_integer(parameters.largest_object.group)); - json_object_set_new(message, "largest_object_id", json_integer(parameters.largest_object.object)); - } - } - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.track_status_accepted) { - moq->conn->socket->callbacks.moq.track_status_accepted(moq->conn, - request_id, track_alias, ¶meters); - } - if(error) - *error = 0; - return offset; -} - -size_t imquic_moq_parse_track_status_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { - if(error) - *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 1) - return 0; - if(moq->version < IMQUIC_MOQ_VERSION_13) - return 0; - size_t offset = 0; - uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_ERROR"); - offset += length; - uint64_t recvd_error_code = error_code; - if(moq->version < IMQUIC_MOQ_VERSION_15) - error_code = imquic_moq_request_error_code_from_legacy(moq->version, error_code); - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_request_error_code_str(error_code), recvd_error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_ERROR"); - offset += length; - char reason[1024], *reason_str = NULL; - if(rs_len > 0) { - IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken TRACK_STATUS_ERROR"); - IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); - int reason_len = (int)rs_len; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Reason Phrase: %.*s\n", - imquic_get_connection_name(moq->conn), reason_len, &bytes[offset]); - if(reason_len > 0) { - g_snprintf(reason, sizeof(reason), "%.*s", reason_len, &bytes[offset]); - reason_str = reason; - } - offset += reason_len; - } -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "track_status_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(recvd_error_code)); - if(reason_str != NULL) - json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); - } -#endif - /* Notify the application */ - if(moq->conn->socket && moq->conn->socket->callbacks.moq.track_status_error) - moq->conn->socket->callbacks.moq.track_status_error(moq->conn, request_id, error_code, reason_str, 0); - if(error) - *error = 0; - return offset; -} - size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_datagram_message_type dtype, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; @@ -4468,7 +3056,6 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t uint64_t object_status = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); IMQUIC_MOQ_CHECK_ERR(object_status > IMQUIC_MOQ_END_OF_TRACK, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid object status"); - IMQUIC_MOQ_CHECK_ERR(object_status == IMQUIC_MOQ_OBJECT_DOESNT_EXIST && ext_len > 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Extensions received in object with status 'Does Not Exist'"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Object Status: %"SCNu64"\n", imquic_get_connection_name(moq->conn), object_status); @@ -4622,12 +3209,10 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ * is set to the first object we receive in the sequence */ moq_stream->subgroup_id = object_id; } - if(moq->version >= IMQUIC_MOQ_VERSION_14) { - /* Object IDs are a delta, starting from v14 */ - object_id += moq_stream->last_object_id; - if(moq_stream->got_objects) - object_id++; - } + /* Object IDs are a delta */ + object_id += moq_stream->last_object_id; + if(moq_stream->got_objects) + object_id++; if(!moq_stream->got_objects) moq_stream->got_objects = TRUE; moq_stream->last_object_id = object_id; @@ -4706,16 +3291,10 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str uint8_t length = 0; /* Since v15, FETCH objects are prefixed by serialization flags * that are supposed to optimize what will and will not be there */ - uint64_t flags = 0; - if(moq->version == IMQUIC_MOQ_VERSION_15) { - flags = bytes[offset]; - offset++; - } else if(moq->version >= IMQUIC_MOQ_VERSION_16) { - flags = imquic_read_varint(&bytes[offset], blen-offset, &length); - if(length == 0 || length >= blen-offset) - return -1; /* Not enough data, try again later */ - offset += length; - } + uint64_t flags = imquic_read_varint(&bytes[offset], blen-offset, &length); + if(length == 0 || length >= blen-offset) + return -1; /* Not enough data, try again later */ + offset += length; if(length >= blen-offset) return -1; /* Not enough data, try again later */ imquic_moq_fetch_subgroup_type subgroup_type = IMQUIC_MOQ_FETCH_SUBGROUP_ID; @@ -4895,43 +3474,20 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b /* Message building */ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - GList *supported_versions, imquic_moq_setup_parameters *parameters) { - if(bytes == NULL || blen < 4 || (g_list_length(supported_versions) < 1 && - (moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)))) { + imquic_moq_setup_parameters *parameters) { + if(bytes == NULL || blen < 2) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_CLIENT_SETUP, moq->version)); return 0; } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_CLIENT_SETUP); - /* Version is only negotiated here for versions up to v14 */ - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) { - offset += imquic_write_varint(g_list_length(supported_versions), &bytes[offset], blen-offset); - GList *temp = supported_versions; - while(temp) { - uint32_t version = GPOINTER_TO_UINT(temp->data); - offset += imquic_write_varint(version, &bytes[offset], blen-offset); - temp = temp->next; - } - } uint8_t params_num = 0; offset += imquic_moq_setup_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("client_setup"); - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) { - json_object_set_new(message, "number_of_supported_versions", json_integer(g_list_length(supported_versions))); - json_t *versions = json_array(); - GList *temp = supported_versions; - temp = supported_versions; - while(temp) { - uint32_t version = GPOINTER_TO_UINT(temp->data); - json_array_append_new(versions, json_integer(version)); - temp = temp->next; - } - json_object_set_new(message, "supported_versions", versions); - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_setup_parameters(message, parameters, "setup_parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); @@ -4941,25 +3497,20 @@ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size } size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint32_t version, imquic_moq_setup_parameters *parameters) { - if(bytes == NULL || blen < 1) { + imquic_moq_setup_parameters *parameters) { + if(bytes == NULL || blen < 2) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SERVER_SETUP, moq->version)); return 0; } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SERVER_SETUP); - /* Version is only negotiated here for versions up to v14 */ - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) - offset += imquic_write_varint(version, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_setup_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("server_setup"); - if(moq->version == IMQUIC_MOQ_VERSION_ANY_LEGACY || (moq->version >= IMQUIC_MOQ_VERSION_MIN && moq->version <= IMQUIC_MOQ_VERSION_14)) - json_object_set_new(message, "selected_version", json_integer(version)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_setup_parameters(message, parameters, "setup_parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); @@ -5045,8 +3596,7 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_ERROR); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); offset += imquic_write_varint(error, &bytes[offset], blen-offset); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - offset += imquic_write_varint(retry_interval, &bytes[offset], blen-offset); + offset += imquic_write_varint(retry_interval, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); if(reason_len > 0) { @@ -5059,8 +3609,7 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * json_t *message = imquic_qlog_moq_message_prepare("request_error"); json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "error_code", json_integer(error)); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - json_object_set_new(message, "retry_interval", json_integer(retry_interval)); + json_object_set_new(message, "retry_interval", json_integer(retry_interval)); if(reason != NULL) json_object_set_new(message, "reason", json_string(reason)); imquic_moq_qlog_control_message_created(moq->conn->qlog, @@ -5097,59 +3646,6 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, return offset; } -size_t imquic_moq_add_publish_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id) { - if(bytes == NULL || blen < 1) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE_OK, moq->version)); - return 0; - } - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_ok" : "publish_namespace_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_publish_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE_ERROR, moq->version)); - return 0; - } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE_ERROR); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); - if(reason_len > 0) { - memcpy(&bytes[offset], reason, reason_len); - offset += reason_len; - } - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "publish_namespace_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error)); - if(reason != NULL) - json_object_set_new(message, "reason", json_string(reason)); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace) { if(bytes == NULL || blen < 1 || track_namespace == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", @@ -5177,8 +3673,6 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL, moq->version)); return 0; } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL); @@ -5206,8 +3700,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { if(bytes == NULL || blen < 1 || track_namespace == NULL || - track_name == NULL || (track_name->buffer == NULL && track_name->length > 0) || - (moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL)) { + track_name == NULL || (track_name->buffer == NULL && track_name->length > 0)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH, moq->version)); return 0; @@ -5218,29 +3711,13 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_PUBLISH); offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - bytes[offset] = parameters->group_order; - offset++; - bytes[offset] = parameters->largest_object_set; - offset++; - if(parameters->largest_object_set) { - offset += imquic_write_varint(parameters->largest_object.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->largest_object.object, &bytes[offset], blen-offset); - } - bytes[offset] = parameters->forward; - offset++; - } uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are extensions to encode */ - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - uint8_t extensions[256]; - size_t extensions_len = 0; - extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); - } + uint8_t extensions[256]; + size_t extensions_len = 0; + extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); + offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -5248,115 +3725,42 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); - json_object_set_new(message, "track_alias", json_integer(track_alias)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - json_object_set_new(message, "content_exists", json_integer(parameters->largest_object_set)); - if(parameters->largest_object_set) { - json_object_set_new(message, "largest_group_id", json_integer(parameters->largest_object.group)); - json_object_set_new(message, "largest_object_id", json_integer(parameters->largest_object.object)); - } - json_object_set_new(message, "forward", json_integer(parameters->forward)); - } - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1 || (moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH, moq->version)); - return 0; - } - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - bytes[offset] = parameters->forward; - offset++; - bytes[offset] = parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128; - offset++; - bytes[offset] = parameters->group_order; - offset++; - offset += imquic_write_varint(parameters->subscription_filter.type, &bytes[offset], blen-offset); - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || - parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - offset += imquic_write_varint(parameters->subscription_filter.start_location.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->subscription_filter.start_location.object, &bytes[offset], blen-offset); - } - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - offset += imquic_write_varint(parameters->subscription_filter.end_group, &bytes[offset], blen-offset); - } - uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare("publish_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "forward", json_integer(parameters->forward)); - json_object_set_new(message, "subscriber_priority", json_integer(parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128)); - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - json_object_set_new(message, "filter_type", json_integer(parameters->subscription_filter.type)); - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - json_object_set_new(message, "start_group", json_integer(parameters->subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters->subscription_filter.start_location.object)); - } - } + json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); + imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_publish_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { +size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, + imquic_moq_request_parameters *parameters) { + if(bytes == NULL || blen < 2) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_ERROR, moq->version)); + imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH, moq->version)); return 0; } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_ERROR); + IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_OK); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); - if(reason_len > 0) { - memcpy(&bytes[offset], reason, reason_len); - offset += reason_len; - } + uint8_t params_num = 0; + offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "subscribe_error"); + json_t *message = imquic_qlog_moq_message_prepare("publish_ok"); json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error)); - if(reason != NULL) - json_object_set_new(message, "reason", json_string(reason)); + json_object_set_new(message, "number_of_parameters", json_integer(params_num)); + imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, +size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || track_namespace == NULL || track_name == NULL || (track_name->buffer == NULL && track_name->length > 0)) { @@ -5367,29 +3771,8 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - if(moq->version < IMQUIC_MOQ_VERSION_12) - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_SUBSCRIBE); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - bytes[offset] = parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128; - offset++; - bytes[offset] = parameters->group_order; - offset++; - bytes[offset] = parameters->forward; - offset++; - offset += imquic_write_varint(parameters->subscription_filter.type, &bytes[offset], blen-offset); - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || - parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - offset += imquic_write_varint(parameters->subscription_filter.start_location.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->subscription_filter.start_location.object, &bytes[offset], blen-offset); - } - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - offset += imquic_write_varint(parameters->subscription_filter.end_group, &bytes[offset], blen-offset); - } uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -5397,21 +3780,8 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("subscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version < IMQUIC_MOQ_VERSION_12) - json_object_set_new(message, "track_alias", json_integer(track_alias)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "subscriber_priority", json_integer(parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128)); - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - json_object_set_new(message, "forward", json_integer(parameters->forward)); - json_object_set_new(message, "filter_type", json_integer(parameters->subscription_filter.type)); - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - json_object_set_new(message, "start_group", json_integer(parameters->subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters->subscription_filter.start_location.object)); - } - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); @@ -5430,20 +3800,7 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_UPDATE); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - if(moq->version >= IMQUIC_MOQ_VERSION_14) - offset += imquic_write_varint(sub_request_id, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - offset += imquic_write_varint(parameters->subscription_filter.start_location.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->subscription_filter.start_location.object, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->subscription_filter.end_group, &bytes[offset], blen-offset); - bytes[offset] = parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128; - offset++; - bytes[offset] = parameters->forward; - offset++; - } + offset += imquic_write_varint(sub_request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -5451,16 +3808,7 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_update"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version >= IMQUIC_MOQ_VERSION_14) - json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "start_group", json_integer(parameters->subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters->subscription_filter.start_location.object)); - json_object_set_new(message, "end_group", json_integer(parameters->subscription_filter.end_group)); - json_object_set_new(message, "subscriber_priority", json_integer(parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128)); - json_object_set_new(message, "forward", json_integer(parameters->forward)); - } + json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } @@ -5478,87 +3826,23 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_OK); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - if(moq->version >= IMQUIC_MOQ_VERSION_12) - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - offset += imquic_write_varint(parameters->expires, &bytes[offset], blen-offset); - bytes[offset] = parameters->group_order; - offset++; - bytes[offset] = parameters->largest_object_set; - offset++; - if(parameters->largest_object_set) { - offset += imquic_write_varint(parameters->largest_object.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->largest_object.object, &bytes[offset], blen-offset); - } - } + offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are extensions to encode */ - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - uint8_t extensions[256]; - size_t extensions_len = 0; - extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); - } + uint8_t extensions[256]; + size_t extensions_len = 0; + extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); + offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("subscribe_ok"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version >= IMQUIC_MOQ_VERSION_12) - json_object_set_new(message, "track_alias", json_integer(track_alias)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "expires", json_integer(parameters->expires)); - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - json_object_set_new(message, "content_exists", json_integer(parameters->largest_object_set)); - if(parameters->largest_object_set) { - json_object_set_new(message, "largest_group_id", json_integer(parameters->largest_object.group)); - json_object_set_new(message, "largest_object_id", json_integer(parameters->largest_object.object)); - } - } + json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_subscribe_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason, uint64_t track_alias) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_ERROR, moq->version)); - return 0; - } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_ERROR); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); - if(reason_len > 0) { - memcpy(&bytes[offset], reason, reason_len); - offset += reason_len; - } - if(moq->version < IMQUIC_MOQ_VERSION_12) - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "subscribe_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version < IMQUIC_MOQ_VERSION_12) - json_object_set_new(message, "track_alias", json_integer(track_alias)); - json_object_set_new(message, "error_code", json_integer(error)); - if(reason != NULL) - json_object_set_new(message, "reason", json_string(reason)); + imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -5621,8 +3905,7 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1 || track_namespace == NULL || - (moq->version >= IMQUIC_MOQ_VERSION_16 && moq_stream == NULL)) { + if(bytes == NULL || blen < 1 || track_namespace == NULL || moq_stream == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE, moq->version)); return 0; @@ -5631,20 +3914,17 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - offset += imquic_write_varint(subscribe_options, &bytes[offset], blen-offset); + offset += imquic_write_varint(subscribe_options, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe_namespace"); + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe_namespace"); json_t *message = imquic_qlog_moq_message_prepare("subscribe_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace_prefix"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); + json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, @@ -5700,86 +3980,6 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream return offset; } -size_t imquic_moq_add_subscribe_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id) { - if(bytes == NULL || blen < 1) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_OK, moq->version)); - return 0; - } - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_ok" : "subscribe_namespace_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_subscribe_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_ERROR, moq->version)); - return 0; - } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE_ERROR); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); - if(reason_len > 0) { - memcpy(&bytes[offset], reason, reason_len); - offset += reason_len; - } - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "subscribe_namespace_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error)); - if(reason != NULL) - json_object_set_new(message, "reason", json_string(reason)); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace) { - if(bytes == NULL || blen < 1 || (moq->version <= IMQUIC_MOQ_VERSION_14 && track_namespace == NULL)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE, moq->version)); - return 0; - } - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE); - if(moq->version >= IMQUIC_MOQ_VERSION_15) - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_UNSUBSCRIBE_NAMESPACE); - } - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare("unsubscribe_namespace"); - if(moq->version >= IMQUIC_MOQ_VERSION_15) - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) - imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, uint64_t request_id, uint64_t joining_request_id, uint64_t preceding_group_offset, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, @@ -5803,15 +4003,6 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - bytes[offset] = parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128; - offset++; - bytes[offset] = parameters->group_order; - offset++; - } offset += imquic_write_varint(type, &bytes[offset], blen-offset); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_FETCH); @@ -5831,11 +4022,6 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "subscriber_priority", json_integer(parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128)); - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - } if(type == IMQUIC_MOQ_FETCH_STANDALONE) { imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); @@ -5885,12 +4071,6 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH_OK); offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - bytes[offset] = parameters->group_order; - offset++; - } bytes[offset] = end_of_track; offset++; offset += imquic_write_varint(end_location->group, &bytes[offset], blen-offset); @@ -5898,60 +4078,21 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are extensions to encode */ - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - uint8_t extensions[256]; - size_t extensions_len = 0; - extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); - } + uint8_t extensions[256]; + size_t extensions_len = 0; + extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); + offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch_ok"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - } json_object_set_new(message, "end_of_track", json_integer(end_of_track)); json_object_set_new(message, "largest_group_id", json_integer(end_location->group)); json_object_set_new(message, "largest_object_id", json_integer(end_location->object)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - if(moq->version >= IMQUIC_MOQ_VERSION_16) - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_fetch_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_FETCH_ERROR, moq->version)); - return 0; - } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH_ERROR); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); - if(reason_len > 0) { - memcpy(&bytes[offset], reason, reason_len); - offset += reason_len; - } - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "fetch_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error)); - if(reason != NULL) - json_object_set_new(message, "reason", json_string(reason)); + imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -5971,25 +4112,6 @@ size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_TRACK_STATUS); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_TRACK_STATUS); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - bytes[offset] = parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128; - offset++; - bytes[offset] = parameters->group_order; - offset++; - bytes[offset] = parameters->forward; - offset++; - offset += imquic_write_varint(parameters->subscription_filter.type, &bytes[offset], blen-offset); - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || - parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - offset += imquic_write_varint(parameters->subscription_filter.start_location.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->subscription_filter.start_location.object, &bytes[offset], blen-offset); - } - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - offset += imquic_write_varint(parameters->subscription_filter.end_group, &bytes[offset], blen-offset); - } uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -5999,68 +4121,6 @@ size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "subscriber_priority", json_integer(parameters->subscriber_priority_set ? - parameters->subscriber_priority : 128)); - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - json_object_set_new(message, "forward", json_integer(parameters->forward)); - json_object_set_new(message, "filter_type", json_integer(parameters->subscription_filter.type)); - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - json_object_set_new(message, "start_group", json_integer(parameters->subscription_filter.start_location.group)); - json_object_set_new(message, "start_object", json_integer(parameters->subscription_filter.start_location.object)); - } - } - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - -size_t imquic_moq_add_track_status_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS_OK, moq->version)); - return 0; - } - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_TRACK_STATUS_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - if(moq->version <= IMQUIC_MOQ_VERSION_14) - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - /* For versions older than v15, we need to add some attributes manually, - * but we'll read them from the parameters object the application passed */ - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - offset += imquic_write_varint(parameters->expires, &bytes[offset], blen-offset); - bytes[offset] = parameters->group_order; - offset++; - bytes[offset] = parameters->largest_object_set; - offset++; - if(parameters->largest_object_set) { - offset += imquic_write_varint(parameters->largest_object.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(parameters->largest_object.object, &bytes[offset], blen-offset); - } - } - uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_ok" : "track_status_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) - json_object_set_new(message, "track_alias", json_integer(track_alias)); - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - json_object_set_new(message, "expires", json_integer(parameters->expires)); - json_object_set_new(message, "group_order", json_integer(parameters->group_order)); - json_object_set_new(message, "content_exists", json_integer(parameters->largest_object_set)); - if(parameters->largest_object_set) { - json_object_set_new(message, "largest_group_id", json_integer(parameters->largest_object.group)); - json_object_set_new(message, "largest_object_id", json_integer(parameters->largest_object.object)); - } - } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); @@ -6069,39 +4129,6 @@ size_t imquic_moq_add_track_status_ok(imquic_moq_context *moq, uint8_t *bytes, s return offset; } -size_t imquic_moq_add_track_status_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS_ERROR, moq->version)); - return 0; - } - if(moq->version < IMQUIC_MOQ_VERSION_15) - error = (imquic_moq_request_error_code)imquic_moq_request_error_code_to_legacy(moq->version, error); - size_t offset = 0, len_offset = 0; - IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_TRACK_STATUS_ERROR); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); - if(reason_len > 0) { - memcpy(&bytes[offset], reason, reason_len); - offset += reason_len; - } - IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); -#ifdef HAVE_QLOG - if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare(moq->version >= IMQUIC_MOQ_VERSION_15 ? "request_error" : "track_status_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "error_code", json_integer(error)); - if(reason != NULL) - json_object_set_new(message, "reason", json_string(reason)); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); - } -#endif - return offset; -} - size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t blen, const char *new_session_uri) { if(bytes == NULL || blen < 1 || (new_session_uri && strlen(new_session_uri) > 8192)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", @@ -6142,8 +4169,7 @@ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, s } /* TODO Involve EOG */ gboolean has_ext = (extensions != NULL && elen > 0), is_eog = FALSE; - gboolean has_oid = (moq->version < IMQUIC_MOQ_VERSION_14 || - (moq->version >= IMQUIC_MOQ_VERSION_14 && object_id != 0)); + gboolean has_oid = (object_id != 0); gboolean has_priority = TRUE; /* FIXME */ imquic_moq_datagram_message_type dtype = imquic_moq_datagram_message_type_return(moq->version, TRUE, /* Payload */ @@ -6154,7 +4180,7 @@ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, s size_t offset = imquic_write_varint(dtype, bytes, blen); offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); - if(moq->version < IMQUIC_MOQ_VERSION_14 || has_oid) + if(has_oid) offset += imquic_write_varint(object_id, &bytes[offset], blen-offset); if(has_priority) { bytes[offset] = priority; @@ -6178,8 +4204,7 @@ size_t imquic_moq_add_object_datagram_status(imquic_moq_context *moq, uint8_t *b return 0; } gboolean has_ext = (extensions != NULL && elen > 0); - gboolean has_oid = (moq->version < IMQUIC_MOQ_VERSION_14 || - (moq->version >= IMQUIC_MOQ_VERSION_14 && object_id != 0)); + gboolean has_oid = (object_id != 0); gboolean has_priority = TRUE; /* FIXME */ imquic_moq_datagram_message_type dtype = imquic_moq_datagram_message_type_return(moq->version, FALSE, /* Status */ @@ -6276,12 +4301,7 @@ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *byte gboolean has_oid = FALSE, has_group = FALSE, has_priority = FALSE, has_ext = FALSE, is_datagram = FALSE; imquic_moq_parse_fetch_serialization_flags(moq->version, flags, &subgroup_type, &has_oid, &has_group, &has_priority, &has_ext, &is_datagram, NULL, NULL, NULL); - if(moq->version == IMQUIC_MOQ_VERSION_15) { - bytes[offset] = flags; - offset++; - } else if(moq->version >= IMQUIC_MOQ_VERSION_16) { - offset += imquic_write_varint(flags, &bytes[offset], blen-offset); - } + offset += imquic_write_varint(flags, &bytes[offset], blen-offset); if(has_group) offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); if(subgroup_type == IMQUIC_MOQ_FETCH_SUBGROUP_ID && !is_datagram) @@ -6339,14 +4359,12 @@ size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, siz imquic_get_connection_name(moq->conn), param); return 0; } - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - if(prev > param) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", - imquic_get_connection_name(moq->conn), param, prev); - return 0; - } - param -= prev; + if(prev > param) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + imquic_get_connection_name(moq->conn), param, prev); + return 0; } + param -= prev; size_t offset = imquic_write_varint(param, &bytes[0], blen); offset += imquic_write_varint(number, &bytes[offset], blen-offset); return offset; @@ -6364,14 +4382,12 @@ size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, si imquic_get_connection_name(moq->conn), param); return 0; } - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - if(prev > param) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", - imquic_get_connection_name(moq->conn), param, prev); - return 0; - } - param -= prev; + if(prev > param) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + imquic_get_connection_name(moq->conn), param, prev); + return 0; } + param -= prev; size_t offset = imquic_write_varint(param, &bytes[0], blen); offset += imquic_write_varint(buflen, &bytes[offset], blen); if(buflen > 0) { @@ -6395,8 +4411,7 @@ size_t imquic_moq_parse_setup_parameter(imquic_moq_context *moq, uint8_t *bytes, uint64_t type = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); offset += length; - if(moq->version >= IMQUIC_MOQ_VERSION_16) - type += *param_type; + type += *param_type; *param_type = type; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_setup_parameter_type_str(type), type); @@ -6428,7 +4443,7 @@ size_t imquic_moq_parse_setup_parameter(imquic_moq_context *moq, uint8_t *bytes, IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->max_request_id); len = length; - } else if(type == IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN && moq->version >= IMQUIC_MOQ_VERSION_12) { + } else if(type == IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN) { params->auth_token_set = TRUE; size_t auth_len = len; if(auth_len > sizeof(params->auth_token)) { @@ -6441,13 +4456,13 @@ size_t imquic_moq_parse_setup_parameter(imquic_moq_context *moq, uint8_t *bytes, char ai_str[513]; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %s\n", imquic_get_connection_name(moq->conn), imquic_hex_str(&bytes[offset], auth_len, ai_str, sizeof(ai_str))); - } else if(type == IMQUIC_MOQ_SETUP_PARAM_AUTHORITY && moq->version >= IMQUIC_MOQ_VERSION_14) { + } else if(type == IMQUIC_MOQ_SETUP_PARAM_AUTHORITY) { params->authority_set = TRUE; if(len > 0) g_snprintf(params->authority, sizeof(params->authority), "%.*s", (int)len, &bytes[offset]); IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- '%s'\n", imquic_get_connection_name(moq->conn), params->authority); - } else if(type == IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION && moq->version >= IMQUIC_MOQ_VERSION_14) { + } else if(type == IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION) { params->moqt_implementation_set = TRUE; if(len > 0) g_snprintf(params->moqt_implementation, sizeof(params->moqt_implementation), "%.*s", (int)len, &bytes[offset]); @@ -6480,8 +4495,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte uint64_t type = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken MoQ request parameter"); offset += length; - if(moq->version >= IMQUIC_MOQ_VERSION_16) - type += *param_type; + type += *param_type; *param_type = type; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_request_parameter_type_str(type, moq->version), type); @@ -6493,8 +4507,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_MOQ_CHECK_ERR(len > blen-offset, NULL, 0, 0, "Broken MoQ request parameter"); } /* Update the parsed parameter */ - if((moq->version >= IMQUIC_MOQ_VERSION_12 && type == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN) || - (moq->version == IMQUIC_MOQ_VERSION_11 && type == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN_v11)) { + if(type == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN) { params->auth_token_set = TRUE; size_t auth_len = len; if(auth_len > sizeof(params->auth_token)) { @@ -6514,22 +4527,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->delivery_timeout); len = length; - } else if(type == IMQUIC_MOQ_REQUEST_PARAM_MAX_CACHE_DURATION && moq->version <= IMQUIC_MOQ_VERSION_15) { - params->max_cache_duration = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); - params->max_cache_duration_set = TRUE; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", - imquic_get_connection_name(moq->conn), params->max_cache_duration); - len = length; - } else if(moq->version == IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_PUBLISHER_PRIORITY) { - uint64_t publisher_priority = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || publisher_priority > 255, NULL, 0, 0, "Broken MoQ request parameter"); - params->publisher_priority = publisher_priority; - params->publisher_priority_set = TRUE; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu8"\n", - imquic_get_connection_name(moq->conn), params->publisher_priority); - len = length; - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY) { uint64_t subscriber_priority = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || subscriber_priority > 255, NULL, 0, 0, "Broken MoQ request parameter"); params->subscriber_priority = subscriber_priority; @@ -6537,7 +4535,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu8"\n", imquic_get_connection_name(moq->conn), params->subscriber_priority); len = length; - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER) { uint64_t group_order = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || group_order > IMQUIC_MOQ_ORDERING_DESCENDING, NULL, 0, 0, "Broken MoQ request parameter"); params->group_order = group_order; @@ -6545,7 +4543,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64" (%s)\n", imquic_get_connection_name(moq->conn), group_order, imquic_moq_group_order_str(group_order)); len = length; - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER) { uint8_t *tmp = &bytes[offset]; size_t toffset = 0, tlen = len; params->subscription_filter.type = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); @@ -6567,14 +4565,14 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte params->subscription_filter_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %d\n", imquic_get_connection_name(moq->conn), params->subscription_filter.type); - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_EXPIRES) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_EXPIRES) { params->expires = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); params->expires_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->expires); len = length; - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT) { uint8_t *tmp = &bytes[offset]; size_t toffset = 0, tlen = len; params->largest_object.group = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); @@ -6585,7 +4583,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte params->largest_object_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64" / %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->largest_object.group, params->largest_object.object); - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_FORWARD) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_FORWARD) { uint64_t forward = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || forward > 1, NULL, 0, 0, "Broken MoQ request parameter"); params->forward = (forward > 0); @@ -6593,15 +4591,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu8"\n", imquic_get_connection_name(moq->conn), params->forward); len = length; - } else if(moq->version == IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_DYNAMIC_GROUPS) { - uint64_t dynamic_groups = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || dynamic_groups > 2, NULL, 0, 0, "Broken MoQ request parameter"); - params->dynamic_groups = (dynamic_groups > 0); - params->dynamic_groups_set = TRUE; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu8"\n", - imquic_get_connection_name(moq->conn), params->dynamic_groups); - len = length; - } else if(moq->version >= IMQUIC_MOQ_VERSION_15 && type == IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST) { + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST) { params->new_group_request = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); params->new_group_request_set = TRUE; @@ -6727,8 +4717,7 @@ GList *imquic_moq_parse_object_extensions(imquic_moq_version version, uint8_t *e g_list_free_full(exts, (GDestroyNotify)imquic_moq_object_extension_free); return 0; } - if(version >= IMQUIC_MOQ_VERSION_16) - ext_type += last_id; + ext_type += last_id; last_id = ext_type; offset += length; if(ext_type % 2 == 0) { @@ -6785,14 +4774,12 @@ size_t imquic_moq_build_object_extensions(imquic_moq_version version, GList *ext size_t offset = 0; /* Starting from v16, extensions are encoded with the type delta-encoded, * which means we need to sort them all in increasing type order */ - GList *ordered = (version >= IMQUIC_MOQ_VERSION_16) ? - g_list_sort(g_list_copy(extensions), (GCompareFunc)imquic_moq_extension_type_sort) : extensions; + GList *ordered = g_list_sort(g_list_copy(extensions), (GCompareFunc)imquic_moq_extension_type_sort); GList *temp = ordered; uint64_t last_id = 0; while(temp) { imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - offset += imquic_write_varint((version >= IMQUIC_MOQ_VERSION_16 ? (ext->id - last_id) : ext->id), - &bytes[offset], blen-offset); + offset += imquic_write_varint((ext->id - last_id), &bytes[offset], blen-offset); last_id = ext->id; if(ext->id % 2 == 0) { offset += imquic_write_varint(ext->value.number, &bytes[offset], blen-offset); @@ -6805,8 +4792,7 @@ size_t imquic_moq_build_object_extensions(imquic_moq_version version, GList *ext } temp = temp->next; } - if(ordered != extensions) - g_list_free(ordered); + g_list_free(ordered); return offset; } @@ -6895,14 +4881,11 @@ int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, i moq->next_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if this namespace exists and was publish_namespaced here */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_PUBLISH_NAMESPACE)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_PUBLISH_NAMESPACE)); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t ann_len = imquic_moq_add_publish_namespace(moq, buffer, blen, request_id, tns, parameters); @@ -6928,12 +4911,7 @@ int imquic_moq_accept_publish_namespace(imquic_connection *conn, uint64_t reques /* TODO Check if this namespace exists and was publish_namespaced here */ uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t ann_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - ann_len = imquic_moq_add_publish_namespace_ok(moq, buffer, blen, request_id); - } else { - ann_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); - } + size_t ann_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, ann_len, FALSE); /* Done */ @@ -6956,13 +4934,8 @@ int imquic_moq_reject_publish_namespace(imquic_connection *conn, uint64_t reques /* TODO Check if the request ID exists */ /* TODO Check if this namespace exists and was publish_namespaced here */ uint8_t buffer[200]; - size_t blen = sizeof(buffer); - size_t ann_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - ann_len = imquic_moq_add_publish_namespace_error(moq, buffer, blen, request_id, error_code, reason); - } else { - ann_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - } + size_t blen = sizeof(buffer); + size_t ann_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, ann_len, FALSE); /* Done */ @@ -7003,23 +4976,6 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_ imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version < IMQUIC_MOQ_VERSION_12) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Publishing not supported on a connection using %s\n", - imquic_get_connection_name(conn), imquic_moq_version_str(moq->version)); - imquic_refcount_decrease(&moq->ref); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } /* Make sure we can send this */ if(!moq_is_request_id_valid(moq, request_id, TRUE)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid Request ID\n", imquic_get_connection_name(conn)); @@ -7035,14 +4991,11 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_ g_hash_table_insert(moq->subscriptions_by_id, imquic_dup_uint64(request_id), moq_sub); g_hash_table_insert(moq->subscriptions, imquic_dup_uint64(track_alias), moq_sub); imquic_mutex_unlock(&moq->mutex); - /* Send the request */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_PUBLISH)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_PUBLISH)); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; @@ -7064,40 +5017,8 @@ int imquic_moq_accept_publish(imquic_connection *conn, uint64_t request_id, imqu imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->forward_set) { - /* Force some defaults */ - parameters->forward_set = TRUE; - parameters->forward = TRUE; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscriber_priority_set) { - /* Force some defaults */ - parameters->subscriber_priority_set = TRUE; - parameters->subscriber_priority = 128; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscription_filter_set) { - /* Force some defaults */ - parameters->subscription_filter_set = TRUE; - parameters->subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - if(moq->version < IMQUIC_MOQ_VERSION_12) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Publishing not supported on a connection using %s\n", - imquic_get_connection_name(conn), imquic_moq_version_str(moq->version)); - imquic_refcount_decrease(&moq->ref); - return -1; - } if(parameters && parameters->subscription_filter_set && parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE && parameters->subscription_filter.end_group > 0 && parameters->subscription_filter.start_location.group > parameters->subscription_filter.end_group) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] End group is lower than start location group (%"SCNu64" < %"SCNu64")\n", @@ -7131,21 +5052,10 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - if(moq->version < IMQUIC_MOQ_VERSION_12) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Publishing not supported on a connection using %s\n", - imquic_get_connection_name(conn), imquic_moq_version_str(moq->version)); - imquic_refcount_decrease(&moq->ref); - return -1; - } /* TODO Check if we were subscribed */ uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - sb_len = imquic_moq_add_publish_error(moq, buffer, blen, request_id, error_code, reason); - } else { - sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - } + size_t sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ @@ -7153,7 +5063,7 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, return 0; } -int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, +int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); @@ -7164,32 +5074,6 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->forward_set) { - /* Force some defaults */ - parameters->forward_set = TRUE; - parameters->forward = TRUE; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscriber_priority_set) { - /* Force some defaults */ - parameters->subscriber_priority_set = TRUE; - parameters->subscriber_priority = 128; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscription_filter_set) { - /* Force some defaults */ - parameters->subscription_filter_set = TRUE; - parameters->subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - } if(parameters && parameters->subscription_filter_set && parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE && parameters->subscription_filter.end_group > 0 && parameters->subscription_filter.start_location.group > parameters->subscription_filter.end_group) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] End group is lower than start location group (%"SCNu64" < %"SCNu64")\n", @@ -7208,19 +5092,16 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t moq->next_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* Send the request */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_SUBSCRIBE)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_SUBSCRIBE)); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; sb_len = imquic_moq_add_subscribe(moq, buffer, blen, - request_id, track_alias, tns, tn, parameters); + request_id, tns, tn, parameters); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ @@ -7238,35 +5119,17 @@ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, ui imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->expires_set) { - /* Force some defaults */ - parameters->expires_set = TRUE; - parameters->expires = 0; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); /* TODO Check if we were subscribed */ - if(moq->version >= IMQUIC_MOQ_VERSION_12) { - imquic_mutex_lock(&moq->mutex); - imquic_moq_subscription *moq_sub = g_hash_table_lookup(moq->subscriptions_by_id, &request_id); - if(moq_sub != NULL) { - /* Track this subscription */ - moq_sub->track_alias = track_alias; - g_hash_table_insert(moq->subscriptions, imquic_dup_uint64(track_alias), moq_sub); - } - imquic_mutex_unlock(&moq->mutex); + imquic_mutex_lock(&moq->mutex); + imquic_moq_subscription *moq_sub = g_hash_table_lookup(moq->subscriptions_by_id, &request_id); + if(moq_sub != NULL) { + /* Track this subscription */ + moq_sub->track_alias = track_alias; + g_hash_table_insert(moq->subscriptions, imquic_dup_uint64(track_alias), moq_sub); } + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = imquic_moq_add_subscribe_ok(moq, buffer, blen, @@ -7279,7 +5142,7 @@ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, ui } int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, - imquic_moq_request_error_code error_code, const char *reason, uint64_t track_alias, uint64_t retry_interval) { + imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL || (reason && strlen(reason) > 1024)) { @@ -7293,12 +5156,7 @@ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, /* TODO Check if we were subscribed */ uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - sb_len = imquic_moq_add_subscribe_error(moq, buffer, blen, request_id, error_code, reason, track_alias); - } else { - sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - } + size_t sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ @@ -7315,27 +5173,6 @@ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->forward_set) { - /* Force some defaults */ - parameters->forward_set = TRUE; - parameters->forward = TRUE; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscriber_priority_set) { - /* Force some defaults */ - parameters->subscriber_priority_set = TRUE; - parameters->subscriber_priority = 128; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscription_filter_set) { - /* Force some defaults */ - parameters->subscription_filter_set = TRUE; - parameters->subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); if(parameters && parameters->subscription_filter_set && parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE && @@ -7347,14 +5184,11 @@ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint imquic_refcount_decrease(&moq->ref); return -1; } - /* TODO Check if we were subscribed */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_UPDATE)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_UPDATE)); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t su_len = imquic_moq_add_request_update(moq, buffer, blen, @@ -7375,13 +5209,6 @@ int imquic_moq_accept_request_update(imquic_connection *conn, uint64_t request_i imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version < IMQUIC_MOQ_VERSION_15) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't send %s acknowledgements on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUEST_UPDATE, moq->version), - imquic_moq_version_str(moq->version)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); /* TODO Check if the request ID exists */ @@ -7406,13 +5233,6 @@ int imquic_moq_reject_request_update(imquic_connection *conn, uint64_t request_i imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version < IMQUIC_MOQ_VERSION_15) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't send %s errors on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUEST_UPDATE, moq->version), - imquic_moq_version_str(moq->version)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); /* TODO Check if we were subscribed */ @@ -7514,47 +5334,35 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, moq->next_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* Send the request */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callback if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE)); - imquic_mutex_unlock(&moq->mutex); - } - imquic_moq_stream *moq_stream = NULL; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated bidirectional STREAM */ - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); - imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); - moq_stream->subscribe_namespace = TRUE; - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callback if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE)); + imquic_mutex_unlock(&moq->mutex); + /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->subscribe_namespace = TRUE; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; sb_len = imquic_moq_add_subscribe_namespace(moq, moq_stream, buffer, blen, request_id, tns, subscribe_options, parameters); - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* Track the request, and map it to the dedicated bidirectional STREAM */ - g_atomic_int_set(&moq_stream->subscribe_namespace_state, 1); - moq_stream->request_id = request_id; - moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); - while(moq_stream->last_tuple->next != NULL) - moq_stream->last_tuple = moq_stream->last_tuple->next; - moq_stream->namespace_prefix_size = tns_num; - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->tns_subscriptions_by_id, imquic_dup_uint64(request_id), moq_stream); - imquic_mutex_unlock(&moq->mutex); - /* Send on the dedicated bidirectional STREAM */ - imquic_connection_send_on_stream(conn, moq_stream->stream_id, - buffer, sb_len, FALSE); - } else { - /* Older MoQ version, use the control stream */ - imquic_connection_send_on_stream(conn, moq->control_stream_id, - buffer, sb_len, FALSE); - } + /* Track the request, and map it to the dedicated bidirectional STREAM */ + g_atomic_int_set(&moq_stream->subscribe_namespace_state, 1); + moq_stream->request_id = request_id; + moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); + while(moq_stream->last_tuple->next != NULL) + moq_stream->last_tuple = moq_stream->last_tuple->next; + moq_stream->namespace_prefix_size = tns_num; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->tns_subscriptions_by_id, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + /* Send on the dedicated bidirectional STREAM */ + imquic_connection_send_on_stream(conn, moq_stream->stream_id, + buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); return 0; @@ -7571,40 +5379,25 @@ int imquic_moq_accept_subscribe_namespace(imquic_connection *conn, uint64_t requ } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* Check if the request ID exists */ - imquic_moq_stream *moq_stream = NULL; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated - * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ - imquic_mutex_lock(&moq->mutex); - moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || - !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { - imquic_mutex_unlock(&moq->mutex); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } + /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated + * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); + if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || + !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { imquic_mutex_unlock(&moq->mutex); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + imquic_mutex_unlock(&moq_mutex); + return -1; } + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - sb_len = imquic_moq_add_subscribe_namespace_ok(moq, buffer, blen, request_id); - } else { - sb_len = imquic_moq_add_request_ok(moq, moq_stream, buffer, blen, request_id, parameters); - } - if(moq_stream != NULL) { - /* Send on the dedicated bidirectional STREAM */ - imquic_connection_send_on_stream(conn, moq_stream->stream_id, - buffer, sb_len, FALSE); - } else { - /* Older MoQ version, use the control stream */ - imquic_connection_send_on_stream(conn, moq->control_stream_id, - buffer, sb_len, FALSE); - } + size_t sb_len = imquic_moq_add_request_ok(moq, moq_stream, buffer, blen, request_id, parameters); + /* Send on the dedicated bidirectional STREAM */ + imquic_connection_send_on_stream(conn, moq_stream->stream_id, + buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); return 0; @@ -7622,49 +5415,34 @@ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t requ } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* Check if the request ID exists */ - imquic_moq_stream *moq_stream = NULL; - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated - * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ - imquic_mutex_lock(&moq->mutex); - moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || - !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { - imquic_mutex_unlock(&moq->mutex); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } + /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated + * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); + if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || + !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { imquic_mutex_unlock(&moq->mutex); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + imquic_mutex_unlock(&moq_mutex); + return -1; } + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - sb_len = imquic_moq_add_subscribe_namespace_error(moq, buffer, blen, request_id, error_code, reason); - } else { - sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); - } - if(moq_stream != NULL) { - /* Send on the dedicated bidirectional STREAM */ - imquic_connection_send_on_stream(conn, moq_stream->stream_id, - buffer, sb_len, FALSE); - } else { - /* Older MoQ version, use the control stream */ - imquic_connection_send_on_stream(conn, moq->control_stream_id, - buffer, sb_len, FALSE); - } + size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); + /* Send on the dedicated bidirectional STREAM */ + imquic_connection_send_on_stream(conn, moq_stream->stream_id, + buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); return 0; } -int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns) { +int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL || (moq->version <= IMQUIC_MOQ_VERSION_14 && (tns == NULL || tns->buffer == 0 || tns->length == 0))) { + if(moq == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq_mutex); @@ -7672,35 +5450,23 @@ int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_i } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* Check if we were subscribed */ - if(moq->version >= IMQUIC_MOQ_VERSION_16) { - /* On newer versions of MoQ, SUBSCRIBE_NAMESPACE uses a dedicated - * bidirectional STREAM, so unsubscribing is done without sending - * any actual message: we simply close the STREAM */ - imquic_mutex_lock(&moq->mutex); - imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments: no such subscription\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq->mutex); - imquic_refcount_decrease(&moq->ref); - return -1; - } - /* Reset the STREAM */ - imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); - g_hash_table_remove(moq->tns_subscriptions_by_id, &request_id); - g_hash_table_remove(moq->streams, &moq_stream->stream_id); + /* On newer versions of MoQ, SUBSCRIBE_NAMESPACE uses a dedicated + * bidirectional STREAM, so unsubscribing is done without sending + * any actual message: we simply close the STREAM */ + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); + if(moq_stream == NULL) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments: no such subscription\n", + imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - return 0; + return -1; } - /* If we're here, we're sending the legacy UNSUBSCRIBE_NAMESPACE */ - uint8_t buffer[200]; - size_t blen = sizeof(buffer); - size_t sb_len = imquic_moq_add_unsubscribe_namespace(moq, buffer, blen, request_id, tns); - imquic_connection_send_on_stream(conn, moq->control_stream_id, - buffer, sb_len, FALSE); - /* Done */ + /* Reset the STREAM */ + imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); + g_hash_table_remove(moq->tns_subscriptions_by_id, &request_id); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); return 0; } @@ -7708,7 +5474,7 @@ int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_i int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL || moq->version < IMQUIC_MOQ_VERSION_16 || tns == NULL || tns->buffer == 0 || tns->length == 0) { + if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq_mutex); @@ -7747,7 +5513,7 @@ int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, im int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL || moq->version < IMQUIC_MOQ_VERSION_16 || tns == NULL || tns->buffer == 0 || tns->length == 0) { + if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq_mutex); @@ -7794,22 +5560,6 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscriber_priority_set) { - /* Force some defaults */ - parameters->subscriber_priority_set = TRUE; - parameters->subscriber_priority = 128; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } /* Make sure we can send this */ if(!moq_is_request_id_valid(moq, request_id, TRUE)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid Request ID\n", imquic_get_connection_name(conn)); @@ -7819,15 +5569,11 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, moq->next_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if this namespace exists and was publish_namespaced here */ - /* TODO Track subscription and track alias */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_FETCH)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_FETCH)); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t f_len = 0; @@ -7854,22 +5600,6 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscriber_priority_set) { - /* Force some defaults */ - parameters->subscriber_priority_set = TRUE; - parameters->subscriber_priority = 128; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } /* Make sure we can send this */ if(!moq_is_request_id_valid(moq, request_id, TRUE)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid Request ID\n", imquic_get_connection_name(conn)); @@ -7879,15 +5609,11 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 moq->next_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if this namespace exists and was publish_namespaced here */ - /* TODO Track subscription and track alias */ - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_FETCH)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_FETCH)); + imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t f_len = 0; @@ -7914,17 +5640,6 @@ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, imquic imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); /* TODO Check if we were fetched */ @@ -7958,12 +5673,7 @@ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, /* TODO Check if we were fetched */ uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t f_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - f_len = imquic_moq_add_fetch_error(moq, buffer, blen, request_id, error_code, reason); - } else { - f_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - } + size_t f_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, f_len, FALSE); /* Done */ @@ -8004,39 +5714,6 @@ int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && parameters == NULL) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->forward_set) { - /* Force some defaults */ - parameters->forward_set = TRUE; - parameters->forward = TRUE; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscriber_priority_set) { - /* Force some defaults */ - parameters->subscriber_priority_set = TRUE; - parameters->subscriber_priority = 128; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->subscription_filter_set) { - /* Force some defaults */ - parameters->subscription_filter_set = TRUE; - parameters->subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - } - if(moq->version < IMQUIC_MOQ_VERSION_13) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't send %s on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS, moq->version), - imquic_moq_version_str(moq->version)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } if(parameters && parameters->subscription_filter_set && parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE && parameters->subscription_filter.end_group > 0 && parameters->subscription_filter.start_location.group > parameters->subscription_filter.end_group) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] End group is lower than start location group (%"SCNu64" < %"SCNu64")\n", @@ -8055,13 +5732,11 @@ int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, moq->next_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - if(moq->version >= IMQUIC_MOQ_VERSION_15) { - /* Map this request ID to this message type, so that we can trigger - * the right application callbac if/when we get a response later on */ - imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_TRACK_STATUS)); - imquic_mutex_unlock(&moq->mutex); - } + /* Map this request ID to this message type, so that we can trigger + * the right application callbac if/when we get a response later on */ + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_TRACK_STATUS)); + imquic_mutex_unlock(&moq->mutex); /* Send the request */ uint8_t buffer[200]; size_t blen = sizeof(buffer); @@ -8076,7 +5751,7 @@ int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, } int imquic_moq_accept_track_status(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters) { + imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL) { @@ -8085,46 +5760,11 @@ int imquic_moq_accept_track_status(imquic_connection *conn, uint64_t request_id, imquic_mutex_unlock(&moq_mutex); return -1; } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && (parameters == NULL || !parameters->expires_set || - !parameters->group_order_set || !parameters->largest_object_set)) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments (missing mandatory parameters)\n", - imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); - return -1; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->expires_set) { - /* Force some defaults */ - parameters->expires_set = TRUE; - parameters->expires = 0; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->group_order_set) { - /* Force some defaults */ - parameters->group_order_set = TRUE; - parameters->group_order = IMQUIC_MOQ_ORDERING_ASCENDING; - } - if(moq->version <= IMQUIC_MOQ_VERSION_14 && !parameters->largest_object_set) { - /* Force some defaults */ - parameters->largest_object_set = TRUE; - parameters->largest_object.group = 0; - parameters->largest_object.object = 0; - } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - if(moq->version < IMQUIC_MOQ_VERSION_13) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't send %s on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS_OK, moq->version), - imquic_moq_version_str(moq->version)); - return -1; - } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t tso_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - tso_len = imquic_moq_add_track_status_ok(moq, buffer, blen, - request_id, track_alias, parameters); - } else { - tso_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); - } + size_t tso_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, tso_len, FALSE); /* Done */ @@ -8144,20 +5784,9 @@ int imquic_moq_reject_track_status(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - if(moq->version < IMQUIC_MOQ_VERSION_13) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't send %s on a connection using %s\n", - imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS_ERROR, moq->version), - imquic_moq_version_str(moq->version)); - return -1; - } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t tsr_len = 0; - if(moq->version <= IMQUIC_MOQ_VERSION_14) { - tsr_len = imquic_moq_add_track_status_error(moq, buffer, blen, request_id, error_code, reason); - } else { - tsr_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - } + size_t tsr_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, tsr_len, FALSE); /* Done */ @@ -8208,8 +5837,7 @@ int imquic_moq_goaway(imquic_connection *conn, const char *uri) { } int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { - if(object == NULL || object->object_status > IMQUIC_MOQ_END_OF_TRACK || - (object->object_status == IMQUIC_MOQ_OBJECT_DOESNT_EXIST && object->extensions != NULL)) { + if(object == NULL || object->object_status > IMQUIC_MOQ_END_OF_TRACK) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); return -1; @@ -8317,21 +5945,19 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { size_t shgo_len = 0; if(valid_pkt) { uint64_t object_id = object->object_id; - if(moq->version >= IMQUIC_MOQ_VERSION_14) { - /* Object IDs are a delta, starting from v14 */ - if(moq_stream->got_objects && object_id <= moq_stream->last_object_id) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't send older object on this subgroup (%"SCNu64" <= %"SCNu64")\n", - imquic_get_connection_name(conn), object_id, moq_stream->last_object_id); - imquic_refcount_decrease(&moq->ref); - g_free(buffer); - return -1; - } - object_id -= moq_stream->last_object_id; - if(moq_stream->got_objects) - object_id--; - moq_stream->got_objects = TRUE; - moq_stream->last_object_id = object->object_id; + /* Object IDs are a delta */ + if(moq_stream->got_objects && object_id <= moq_stream->last_object_id) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't send older object on this subgroup (%"SCNu64" <= %"SCNu64")\n", + imquic_get_connection_name(conn), object_id, moq_stream->last_object_id); + imquic_refcount_decrease(&moq->ref); + g_free(buffer); + return -1; } + object_id -= moq_stream->last_object_id; + if(moq_stream->got_objects) + object_id--; + moq_stream->got_objects = TRUE; + moq_stream->last_object_id = object->object_id; shgo_len = imquic_moq_add_subgroup_header_object(moq, moq_stream, buffer, bufsize, object_id, object->object_status, object->payload, object->payload_len, extensions, extensions_len); @@ -8665,31 +6291,19 @@ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_ json_object_set_new(delivery_timeout, "value", json_integer(parameters->delivery_timeout)); json_array_append_new(params, delivery_timeout); } - if(parameters->max_cache_duration_set) { - json_t *max_cache_duration = json_object(); - json_object_set_new(max_cache_duration, "name", json_string("max_cache_duration")); - json_object_set_new(max_cache_duration, "value", json_integer(parameters->max_cache_duration)); - json_array_append_new(params, max_cache_duration); - } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->publisher_priority_set) { - json_t *publisher_priority = json_object(); - json_object_set_new(publisher_priority, "name", json_string("publisher_priority")); - json_object_set_new(publisher_priority, "value", json_integer(parameters->publisher_priority)); - json_array_append_new(params, publisher_priority); - } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->subscriber_priority_set) { + if(parameters->subscriber_priority_set) { json_t *subscriber_priority = json_object(); json_object_set_new(subscriber_priority, "name", json_string("subscriber_priority")); json_object_set_new(subscriber_priority, "value", json_integer(parameters->subscriber_priority)); json_array_append_new(params, subscriber_priority); } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->group_order_set) { + if(parameters->group_order_set) { json_t *group_order = json_object(); json_object_set_new(group_order, "name", json_string("group_order")); json_object_set_new(group_order, "value", json_integer(parameters->group_order)); json_array_append_new(params, group_order); } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->subscription_filter_set) { + if(parameters->subscription_filter_set) { json_t *subscription_filter = json_object(); json_object_set_new(subscription_filter, "name", json_string("subscription_filter")); /* FIXME */ @@ -8707,13 +6321,13 @@ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_ json_object_set_new(subscription_filter, "value", sf); json_array_append_new(params, subscription_filter); } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->expires_set) { + if(parameters->expires_set) { json_t *expires = json_object(); json_object_set_new(expires, "name", json_string("expires")); json_object_set_new(expires, "value", json_integer(parameters->expires)); json_array_append_new(params, expires); } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->largest_object_set) { + if(parameters->largest_object_set) { json_t *largest_object = json_object(); json_object_set_new(largest_object, "name", json_string("largest_object")); /* FIXME */ @@ -8723,19 +6337,13 @@ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_ json_object_set_new(largest_object, "value", lo); json_array_append_new(params, largest_object); } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->forward_set) { + if(parameters->forward_set) { json_t *forward = json_object(); json_object_set_new(forward, "name", json_string("forward")); json_object_set_new(forward, "value", json_integer(parameters->forward)); json_array_append_new(params, forward); } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->dynamic_groups_set) { - json_t *dynamic_groups = json_object(); - json_object_set_new(dynamic_groups, "name", json_string("dynamic_groups")); - json_object_set_new(dynamic_groups, "value", json_integer(parameters->dynamic_groups)); - json_array_append_new(params, dynamic_groups); - } - if(version >= IMQUIC_MOQ_VERSION_15 && parameters->new_group_request_set) { + if(parameters->new_group_request_set) { json_t *new_group_request = json_object(); json_object_set_new(new_group_request, "name", json_string("new_group_request")); json_object_set_new(new_group_request, "value", json_integer(parameters->new_group_request)); From 5d80d6a82835a82c522f5a65568f26b5a57a5413 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 4 Mar 2026 15:02:19 +0100 Subject: [PATCH 05/30] Renamed Setup Parameters to Setup Options --- src/internal/moq.h | 40 ++++----- src/moq.c | 214 ++++++++++++++++++++++----------------------- 2 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/internal/moq.h b/src/internal/moq.h index 0ffcffb..7a2e94d 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -203,18 +203,18 @@ void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint gboolean *datagram, gboolean *end_ne_range, gboolean *end_uk_range, gboolean *violation); /*! \brief MoQ setup parameter types */ -typedef enum imquic_moq_setup_parameter_type { +typedef enum imquic_moq_setup_option_type { IMQUIC_MOQ_SETUP_PARAM_PATH = 0x01, IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID = 0x02, IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN = 0x03, IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE = 0x04, IMQUIC_MOQ_SETUP_PARAM_AUTHORITY = 0x05, IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION = 0x07, -} imquic_moq_setup_parameter_type; -/*! \brief Helper function to serialize to string the name of a imquic_moq_setup_parameter_type value. - * @param type The imquic_moq_setup_parameter_type value +} imquic_moq_setup_option_type; +/*! \brief Helper function to serialize to string the name of a imquic_moq_setup_option_type value. + * @param type The imquic_moq_setup_option_type value * @returns The type name as a string, if valid, or NULL otherwise */ -const char *imquic_moq_setup_parameter_type_str(imquic_moq_setup_parameter_type type); +const char *imquic_moq_setup_option_type_str(imquic_moq_setup_option_type type); /*! \brief MoQ request parameter types */ typedef enum imquic_moq_request_parameter_type { @@ -235,7 +235,7 @@ typedef enum imquic_moq_request_parameter_type { const char *imquic_moq_request_parameter_type_str(imquic_moq_request_parameter_type type, imquic_moq_version version); /*! \brief MoQ setup parameters */ -typedef struct imquic_moq_setup_parameters { +typedef struct imquic_moq_setup_options { /*! \brief Whether the PATH parameter is set */ gboolean path_set; /*! \brief Value of the PATH parameter */ @@ -264,7 +264,7 @@ typedef struct imquic_moq_setup_parameters { char moqt_implementation[256]; /*! \brief Whether there's unknown parameters */ gboolean unknown; -} imquic_moq_setup_parameters; +} imquic_moq_setup_options; /*! \brief Helper mode to parse an extensions buffer to a GList of imquic_moq_object_extension * \note The caller owns the list, and is responsible of freeing it and its content @@ -722,18 +722,18 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param parameters The setup parameters to send + * @param options The setup options to send * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_setup_parameters *parameters); + imquic_moq_setup_options *options); /*! \brief Helper method to add a \c SERVER_SETUP message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param parameters The setup parameters to send + * @param options The setup options to send * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_setup_parameters *parameters); + imquic_moq_setup_options *options); /*! \brief Helper method to add a \c MAX_REQUEST_ID message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -1160,12 +1160,12 @@ size_t imquic_moq_add_object_extensions(imquic_moq_context *moq, uint8_t *bytes, * @param[in] moq The imquic_moq_context instance to update with the new parameter * @param[in] bytes Buffer containing the parameter to parse * @param[in] blen Size of the buffer to parse - * @param[out] params imquic_moq_setup_parameters instance to put the parsed parameter in + * @param[out] params imquic_moq_setup_options instance to put the parsed parameter in * @param[out] param_type Type of the parsed parameter, needed for delta-decoding * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parameter, if successful, or 0 otherwise */ -size_t imquic_moq_parse_setup_parameter(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_setup_parameters *params, uint64_t *param_type, uint8_t *error); +size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + imquic_moq_setup_options *params, uint64_t *param_type, uint8_t *error); /*! \brief Helper method to parse a MoQ subscribe parameter * @note This method does nothing at the moment * @param[in] moq The imquic_moq_context instance to update with the new parameter @@ -1198,15 +1198,15 @@ size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, siz * @returns The size of the parameter, if successful, or 0 otherwise */ size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t param, uint64_t prev, uint8_t *buf, size_t buflen); -/*! \brief Helper to serialize a imquic_moq_setup_parameters set to a buffer +/*! \brief Helper to serialize a imquic_moq_setup_options set to a buffer * @param[in] moq The imquic_moq_context instance the parameter is for - * @param[in] parameters The imquic_moq_setup_parameters to serialize + * @param[in] parameters The imquic_moq_setup_options to serialize * @param[out] bytes The buffer to add paramerers to * @param[in] blen The size of the buffer * @param[out] params_num The number of parameters added to the buffer * @returns The size of the serialized parameters, if successful, or 0 otherwise */ -size_t imquic_moq_setup_parameters_serialize(imquic_moq_context *moq, - imquic_moq_setup_parameters *parameters, +size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, + imquic_moq_setup_options *options, uint8_t *bytes, size_t blen, uint8_t *params_num); /*! \brief Helper to serialize a imquic_moq_request_parameters set to a buffer @@ -1361,9 +1361,9 @@ void imquic_qlog_moq_message_add_track(json_t *message, imquic_moq_name *track_n /*! \brief Helper to add a stringified array of setup parameters to a message * @note This automatically fills in a property with the specified name * @param message The message object to update - * @param parameters The setup parameters to convert + * @param options The setup options to convert * @param name The name the array should have in the message object */ -void imquic_qlog_moq_message_add_setup_parameters(json_t *message, imquic_moq_setup_parameters *parameters, const char *name); +void imquic_qlog_moq_message_add_setup_options(json_t *message, imquic_moq_setup_options *options, const char *name); /*! \brief Helper to add a stringified array of subscribe parameters to a message * @note This automatically fills in a property with the specified name * @param message The message object to update diff --git a/src/moq.c b/src/moq.c index f238b48..94bc253 100644 --- a/src/moq.c +++ b/src/moq.c @@ -157,7 +157,7 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { /* After the function returns, check if we can do something */ if(!moq->is_server) { /* Generate a CLIENT_SETUP */ - imquic_moq_setup_parameters parameters = { 0 }; + imquic_moq_setup_options parameters = { 0 }; if(moq->local_max_request_id > 0) { parameters.max_request_id_set = TRUE; parameters.max_request_id = moq->local_max_request_id; @@ -746,7 +746,7 @@ void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint } -const char *imquic_moq_setup_parameter_type_str(imquic_moq_setup_parameter_type type) { +const char *imquic_moq_setup_option_type_str(imquic_moq_setup_option_type type) { switch(type) { case IMQUIC_MOQ_SETUP_PARAM_PATH: return "PATH"; @@ -859,34 +859,34 @@ const char *imquic_moq_auth_token_alias_type_str(imquic_moq_auth_token_alias_typ return NULL; } -/* MoQ parameters */ +/* MoQ options and parameters */ static int imquic_moq_compare_types(const void *a, const void *b) { return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b); } -size_t imquic_moq_setup_parameters_serialize(imquic_moq_context *moq, - imquic_moq_setup_parameters *parameters, +size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, + imquic_moq_setup_options *options, uint8_t *bytes, size_t blen, uint8_t *params_num) { *params_num = 0; if(bytes == NULL || blen == 0) return 0; size_t offset = 0; - if(parameters == NULL) { - /* No parameters */ + if(options == NULL) { + /* No options */ offset += imquic_write_varint(0, &bytes[offset], blen-offset); } else { uint64_t new_id = 0, last_id = 0; GList *list = NULL; - if(parameters->path_set) + if(options->path_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_PATH)); - if(parameters->max_request_id_set) + if(options->max_request_id_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID)); - if(parameters->max_auth_token_cache_size_set) + if(options->max_auth_token_cache_size_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE)); - if(parameters->auth_token_set) + if(options->auth_token_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN)); - if(parameters->authority_set) + if(options->authority_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_AUTHORITY)); - if(parameters->moqt_implementation_set) + if(options->moqt_implementation_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION)); *params_num = g_list_length(list); offset += imquic_write_varint(*params_num, &bytes[offset], blen-offset); @@ -898,27 +898,27 @@ size_t imquic_moq_setup_parameters_serialize(imquic_moq_context *moq, if(new_id == IMQUIC_MOQ_SETUP_PARAM_PATH) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, - (uint8_t *)parameters->path, strlen(parameters->path)); + (uint8_t *)options->path, strlen(options->path)); } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID) { offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, - parameters->max_request_id); + options->max_request_id); } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE) { offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, - parameters->max_auth_token_cache_size); + options->max_auth_token_cache_size); } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, - parameters->auth_token, parameters->auth_token_len); + options->auth_token, options->auth_token_len); } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_AUTHORITY) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, - (uint8_t *)parameters->authority, strlen(parameters->authority)); + (uint8_t *)options->authority, strlen(options->authority)); } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, - (uint8_t *)parameters->moqt_implementation, strlen(parameters->moqt_implementation)); + (uint8_t *)options->moqt_implementation, strlen(options->moqt_implementation)); } last_id = new_id; temp = temp->next; @@ -1563,53 +1563,53 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si } size_t offset = 0; uint8_t length = 0; - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); - IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); + uint64_t opts_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(opts_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); + IMQUIC_MOQ_CHECK_ERR(opts_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- %"SCNu64" parameters:\n", - imquic_get_connection_name(moq->conn), params_num); - imquic_moq_setup_parameters parameters = { 0 }; - uint64_t param = 0, i = 0; - for(i = 0; iconn), opts_num); + imquic_moq_setup_options options = { 0 }; + uint64_t opt = 0, i = 0; + for(i = 0; imax_request_id = parameters.max_request_id; + moq->max_request_id = options.max_request_id; } - if(parameters.max_auth_token_cache_size) { + if(options.max_auth_token_cache_size) { /* Update the value we have */ - moq->max_auth_token_cache_size = parameters.max_auth_token_cache_size; + moq->max_auth_token_cache_size = options.max_auth_token_cache_size; } - if(parameters.moqt_implementation_set) { + if(options.moqt_implementation_set) { /* Take note of the implemntation */ g_free(moq->peer_implementation); moq->peer_implementation = NULL; - if(strlen(parameters.moqt_implementation) > 0) - moq->peer_implementation = g_strdup(parameters.moqt_implementation); + if(strlen(options.moqt_implementation) > 0) + moq->peer_implementation = g_strdup(options.moqt_implementation); } - if(parameters.path_set) { + if(options.path_set) { /* TODO Handle and validate */ if(moq->conn->http3 != NULL && moq->conn->http3->webtransport) IMQUIC_MOQ_CHECK_ERR(TRUE, error, IMQUIC_MOQ_INVALID_PATH, 0, "PATH received on a WebTransport"); } - if(parameters.authority_set) { + if(options.authority_set) { /* TODO Handle and validate */ if(moq->conn->http3 != NULL && moq->conn->http3->webtransport) IMQUIC_MOQ_CHECK_ERR(TRUE, error, IMQUIC_MOQ_INVALID_PATH, 0, "AUTHORITY received on a WebTransport"); } if(moq->max_request_id == 0) { - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] No Max Request ID parameter received, setting it to 1\n", + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] No Max Request ID option received, setting it to 1\n", imquic_get_connection_name(moq->conn)); moq->max_request_id = 1; } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("client_setup"); - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_setup_parameters(message, ¶meters, "setup_parameters"); + json_object_set_new(message, "number_of_options", json_integer(opts_num)); + imquic_qlog_moq_message_add_setup_options(message, &options, "setup_options"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -1617,26 +1617,26 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si uint64_t error_code = 0; if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_moq_connection) { error_code = moq->conn->socket->callbacks.moq.incoming_moq_connection(moq->conn, - (parameters.auth_token_set ? parameters.auth_token : NULL), - (parameters.auth_token_set ? parameters.auth_token_len : 0)); + (options.auth_token_set ? options.auth_token : NULL), + (options.auth_token_set ? options.auth_token_len : 0)); } IMQUIC_MOQ_CHECK_ERR(error_code > 0, error, error_code, 0, "CLIENT_SETUP rejected by application"); /* If we got here, generate a SERVER_SETUP to send back */ - imquic_moq_setup_parameters s_parameters = { 0 }; + imquic_moq_setup_options s_options = { 0 }; if(moq->local_max_request_id > 0) { - s_parameters.max_request_id_set = TRUE; - s_parameters.max_request_id = moq->local_max_request_id; + s_options.max_request_id_set = TRUE; + s_options.max_request_id = moq->local_max_request_id; } if(moq->local_max_auth_token_cache_size > 0) { - s_parameters.max_auth_token_cache_size_set = TRUE; - s_parameters.max_auth_token_cache_size = moq->local_max_auth_token_cache_size; + s_options.max_auth_token_cache_size_set = TRUE; + s_options.max_auth_token_cache_size = moq->local_max_auth_token_cache_size; } /* Add the implementation */ - s_parameters.moqt_implementation_set = TRUE; - g_snprintf(s_parameters.moqt_implementation, sizeof(s_parameters.moqt_implementation), "imquic %s", imquic_version_string_full); + s_options.moqt_implementation_set = TRUE; + g_snprintf(s_options.moqt_implementation, sizeof(s_options.moqt_implementation), "imquic %s", imquic_version_string_full); uint8_t buffer[200]; size_t buflen = sizeof(buffer); - size_t ss_len = imquic_moq_add_server_setup(moq, buffer, buflen, &s_parameters); + size_t ss_len = imquic_moq_add_server_setup(moq, buffer, buflen, &s_options); imquic_connection_send_on_stream(moq->conn, moq->control_stream_id, buffer, ss_len, FALSE); g_atomic_int_set(&moq->connected, 1); @@ -1656,52 +1656,52 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); - IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); + uint64_t opts_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(opts_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); + IMQUIC_MOQ_CHECK_ERR(opts_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- %"SCNu64" parameters:\n", - imquic_get_connection_name(moq->conn), params_num); + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- %"SCNu64" options:\n", + imquic_get_connection_name(moq->conn), opts_num); uint64_t i = 0; - imquic_moq_setup_parameters parameters = { 0 }; - uint64_t param = 0; - for(i = 0; imax_request_id = parameters.max_request_id; + moq->max_request_id = options.max_request_id; } - if(parameters.max_auth_token_cache_size_set) { + if(options.max_auth_token_cache_size_set) { /* Update the value we have */ - moq->max_auth_token_cache_size = parameters.max_auth_token_cache_size; + moq->max_auth_token_cache_size = options.max_auth_token_cache_size; } - if(parameters.moqt_implementation_set) { + if(options.moqt_implementation_set) { /* Take note of the implemntation */ g_free(moq->peer_implementation); moq->peer_implementation = NULL; - if(strlen(parameters.moqt_implementation) > 0) - moq->peer_implementation = g_strdup(parameters.moqt_implementation); + if(strlen(options.moqt_implementation) > 0) + moq->peer_implementation = g_strdup(options.moqt_implementation); } - if(parameters.path_set) { + if(options.path_set) { /* Servers can't use PATH */ IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_INVALID_PATH, 0, "PATH received from a server"); } - if(parameters.authority_set) { + if(options.authority_set) { /* Servers can't use AUTHORITY */ IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_INVALID_PATH, 0, "AUTHORITY received from a server"); } if(moq->max_request_id == 0) { - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] No Max Request ID parameter received, setting it to 1\n", + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] No Max Request ID option received, setting it to 1\n", imquic_get_connection_name(moq->conn)); moq->max_request_id = 1; } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("server_setup"); - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_setup_parameters(message, ¶meters, "setup_parameters"); + json_object_set_new(message, "number_of_options", json_integer(opts_num)); + imquic_qlog_moq_message_add_setup_options(message, &options, "setup_options"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -3474,7 +3474,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b /* Message building */ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_setup_parameters *parameters) { + imquic_moq_setup_options *options) { if(bytes == NULL || blen < 2) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_CLIENT_SETUP, moq->version)); @@ -3482,14 +3482,14 @@ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_CLIENT_SETUP); - uint8_t params_num = 0; - offset += imquic_moq_setup_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + uint8_t opts_num = 0; + offset += imquic_moq_setup_options_serialize(moq, options, &bytes[offset], blen-offset, &opts_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("client_setup"); - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_setup_parameters(message, parameters, "setup_parameters"); + json_object_set_new(message, "number_of_options", json_integer(opts_num)); + imquic_qlog_moq_message_add_setup_options(message, options, "setup_options"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -3497,7 +3497,7 @@ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size } size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_setup_parameters *parameters) { + imquic_moq_setup_options *options) { if(bytes == NULL || blen < 2) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SERVER_SETUP, moq->version)); @@ -3505,14 +3505,14 @@ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SERVER_SETUP); - uint8_t params_num = 0; - offset += imquic_moq_setup_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + uint8_t opts_num = 0; + offset += imquic_moq_setup_options_serialize(moq, options, &bytes[offset], blen-offset, &opts_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("server_setup"); - json_object_set_new(message, "number_of_parameters", json_integer(params_num)); - imquic_qlog_moq_message_add_setup_parameters(message, parameters, "setup_parameters"); + json_object_set_new(message, "number_of_options", json_integer(opts_num)); + imquic_qlog_moq_message_add_setup_options(message, options, "setup_options"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -4397,8 +4397,8 @@ size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, si return offset; } -size_t imquic_moq_parse_setup_parameter(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_setup_parameters *params, uint64_t *param_type, uint8_t *error) { +size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + imquic_moq_setup_options *params, uint64_t *param_type, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) { @@ -4414,7 +4414,7 @@ size_t imquic_moq_parse_setup_parameter(imquic_moq_context *moq, uint8_t *bytes, type += *param_type; *param_type = type; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- %s (%"SCNu64")\n", - imquic_get_connection_name(moq->conn), imquic_moq_setup_parameter_type_str(type), type); + imquic_get_connection_name(moq->conn), imquic_moq_setup_option_type_str(type), type); uint64_t len = 0; if(type % 2 == 1) { len = imquic_read_varint(&bytes[offset], blen-offset, &length); @@ -6225,53 +6225,53 @@ void imquic_qlog_moq_message_add_track(json_t *message, imquic_moq_name *track_n json_object_set_new(message, "track_name", tn); } -void imquic_qlog_moq_message_add_setup_parameters(json_t *message, imquic_moq_setup_parameters *parameters, const char *name) { - if(message == NULL || parameters == NULL || name == NULL) +void imquic_qlog_moq_message_add_setup_options(json_t *message, imquic_moq_setup_options *options, const char *name) { + if(message == NULL || options == NULL || name == NULL) return; - json_t *params = json_array(); - if(parameters->path_set) { + json_t *opts = json_array(); + if(options->path_set) { json_t *path = json_object(); json_object_set_new(path, "name", json_string("path")); - json_object_set_new(path, "value", json_string(parameters->path)); - json_array_append_new(params, path); + json_object_set_new(path, "value", json_string(options->path)); + json_array_append_new(opts, path); } - if(parameters->max_request_id_set) { + if(options->max_request_id_set) { json_t *max_request_id = json_object(); json_object_set_new(max_request_id, "name", json_string("max_request_id")); - json_object_set_new(max_request_id, "value", json_integer(parameters->max_request_id)); - json_array_append_new(params, max_request_id); + json_object_set_new(max_request_id, "value", json_integer(options->max_request_id)); + json_array_append_new(opts, max_request_id); } - if(parameters->max_auth_token_cache_size_set) { + if(options->max_auth_token_cache_size_set) { json_t *max_auth_token_cache_size = json_object(); json_object_set_new(max_auth_token_cache_size, "name", json_string("max_auth_token_cache_size")); - json_object_set_new(max_auth_token_cache_size, "value", json_integer(parameters->max_auth_token_cache_size)); - json_array_append_new(params, max_auth_token_cache_size); + json_object_set_new(max_auth_token_cache_size, "value", json_integer(options->max_auth_token_cache_size)); + json_array_append_new(opts, max_auth_token_cache_size); } - if(parameters->auth_token_set && parameters->auth_token_len > 0) { + if(options->auth_token_set && options->auth_token_len > 0) { json_t *auth_token = json_object(); json_object_set_new(auth_token, "name", json_string("authorization_token")); char ai_str[513]; - json_object_set_new(auth_token, "value", json_string(imquic_hex_str(parameters->auth_token, parameters->auth_token_len, ai_str, sizeof(ai_str)))); - json_array_append_new(params, auth_token); + json_object_set_new(auth_token, "value", json_string(imquic_hex_str(options->auth_token, options->auth_token_len, ai_str, sizeof(ai_str)))); + json_array_append_new(opts, auth_token); } - if(parameters->authority_set) { + if(options->authority_set) { json_t *authority = json_object(); json_object_set_new(authority, "name", json_string("authority")); - json_object_set_new(authority, "value", json_string(parameters->authority)); - json_array_append_new(params, authority); + json_object_set_new(authority, "value", json_string(options->authority)); + json_array_append_new(opts, authority); } - if(parameters->moqt_implementation_set) { + if(options->moqt_implementation_set) { json_t *moqt_implementation = json_object(); json_object_set_new(moqt_implementation, "name", json_string("moqt_implementation")); - json_object_set_new(moqt_implementation, "value", json_string(parameters->moqt_implementation)); - json_array_append_new(params, moqt_implementation); + json_object_set_new(moqt_implementation, "value", json_string(options->moqt_implementation)); + json_array_append_new(opts, moqt_implementation); } - if(parameters->unknown) { + if(options->unknown) { json_t *unknown = json_object(); json_object_set_new(unknown, "name", json_string("unknown")); - json_array_append_new(params, unknown); + json_array_append_new(opts, unknown); } - json_object_set_new(message, name, params); + json_object_set_new(message, name, opts); } void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_version version, imquic_moq_request_parameters *parameters, const char *name) { From 02b8455669fce7cadbd778b5b1bc9a13bfc31a34 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 4 Mar 2026 16:45:45 +0100 Subject: [PATCH 06/30] Renamed Extension headers to Properties --- examples/moq-interop-test.c | 4 +- examples/moq-pub-options.c | 6 +- examples/moq-pub-options.h | 2 +- examples/moq-pub.c | 90 +++--- examples/moq-relay.c | 36 +-- examples/moq-sub.c | 138 +++------ examples/moq-test.c | 44 +-- examples/moq-utils.c | 67 ++-- examples/moq-utils.h | 10 +- src/imquic-moq.c | 26 +- src/imquic/moq.h | 68 ++--- src/internal/moq.h | 116 +++---- src/moq.c | 591 ++++++++++++++++++------------------ 13 files changed, 570 insertions(+), 628 deletions(-) diff --git a/examples/moq-interop-test.c b/examples/moq-interop-test.c index 5f427a9..0ff7fd3 100644 --- a/examples/moq-interop-test.c +++ b/examples/moq-interop-test.c @@ -145,7 +145,7 @@ static void imquic_moq_interop_publish_namespace_error(imquic_connection *conn, static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); static void imquic_moq_interop_subscribe_accepted(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); static void imquic_moq_interop_subscribe_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); static void imquic_moq_interop_connection_gone(imquic_connection *conn); @@ -647,7 +647,7 @@ static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint6 } static void imquic_moq_interop_subscribe_accepted(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { /* Depending on the test, we may or may not be done */ imquic_mutex_lock(&mutex); imquic_moq_interop_client *client = (imquic_moq_interop_client *)g_hash_table_lookup(connections, conn); diff --git a/examples/moq-pub-options.c b/examples/moq-pub-options.c index e7055f6..1cd875e 100644 --- a/examples/moq-pub-options.c +++ b/examples/moq-pub-options.c @@ -18,14 +18,14 @@ gboolean demo_options_parse(demo_options *options, int argc, char *argv[]) { { "moq-draft-version", 'M', 0, G_OPTION_ARG_STRING, &options->moq_version, "MoQ draft version number to negotiate (default=any)", "|any" }, { "track-namespace", 'n', 0, G_OPTION_ARG_STRING_ARRAY, &options->track_namespace, "MoQ track namespace to publish (can be called multiple times to create a tuple; default=none)", "namespace" }, { "track-name", 'N', 0, G_OPTION_ARG_STRING, &options->track_name, "MoQ track name to publish (default=none)", "name" }, - { "first-group", 'f', 0, G_OPTION_ARG_INT64, &options->first_group, "First group ID to send (default=0; sends 'Prior Group ID Gap' extension for the first sent object in that group, if set))", "group_id" }, - { "first-object", 'F', 0, G_OPTION_ARG_INT64, &options->first_object, "First object ID to send (default=0; sends 'Prior Object ID Gap' extension for the first sent object in that group, if set))", "object_id" }, + { "first-group", 'f', 0, G_OPTION_ARG_INT64, &options->first_group, "First group ID to send (default=0; sends 'Prior Group ID Gap' property for the first sent object in that group, if set))", "group_id" }, + { "first-object", 'F', 0, G_OPTION_ARG_INT64, &options->first_object, "First object ID to send (default=0; sends 'Prior Object ID Gap' property for the first sent object in that group, if set))", "object_id" }, { "relay-auth-info", 'a', 0, G_OPTION_ARG_STRING, &options->relay_auth_info, "Auth info required to connect to the relay, if any (default=none)", "string" }, { "auth-info", 'A', 0, G_OPTION_ARG_STRING, &options->auth_info, "Auth info to publish_namespace/publish, if needed (default=none)", "string" }, { "delivery", 'D', 0, G_OPTION_ARG_STRING, &options->delivery, "How MoQ objects should be sent (default=subgroup; supported=datagram,subgroup)", "type" }, { "publish", 'X', 0, G_OPTION_ARG_NONE, &options->publish, "Use a PUBLISH right away instead of waiting for a SUBSCRIBE (default=no; only supported for v12 and later)", NULL }, { "track-alias", 't', 0, G_OPTION_ARG_INT64, &options->track_alias, "Track alias to use for subscriptions (default=0; only supported for v12 and later)", NULL }, - { "extensions", 'x', 0, G_OPTION_ARG_NONE, &options->extensions, "Send some extensions along objects (default=no)", NULL }, + { "properties", 'x', 0, G_OPTION_ARG_NONE, &options->properties, "Send some properties along objects (default=no)", NULL }, { "bind", 'b', 0, G_OPTION_ARG_STRING, &options->ip, "Local IP address to bind to (default=all interfaces)", "IP" }, { "port", 'p', 0, G_OPTION_ARG_INT, &options->port, "Local port to bind to (default=0, random)", "port" }, { "remote-host", 'r', 0, G_OPTION_ARG_STRING, &options->remote_host, "QUIC server to connect to (default=none)", "IP" }, diff --git a/examples/moq-pub-options.h b/examples/moq-pub-options.h index 5c8c83a..3807a1a 100644 --- a/examples/moq-pub-options.h +++ b/examples/moq-pub-options.h @@ -27,7 +27,7 @@ typedef struct demo_options { const char *delivery; gboolean publish; uint64_t track_alias; - gboolean extensions; + gboolean properties; const char *ip; int port; const char *remote_host; diff --git a/examples/moq-pub.c b/examples/moq-pub.c index 5ae13cb..f97951c 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -141,18 +141,7 @@ static void imquic_demo_ready(imquic_connection *conn) { imquic_get_connection_name(conn)); } } - /* Add a couple of track extensions too (will be ignored on versions older than v16) */ - GList *exts = NULL; - imquic_moq_object_extension default_priority = { 0 }; - default_priority.id = IMQUIC_MOQ_EXT_DEFAULT_PUBLISHER_PRIORITY; - default_priority.value.number = 128; - exts = g_list_append(exts, &default_priority); - imquic_moq_object_extension default_order = { 0 }; - default_order.id = IMQUIC_MOQ_EXT_DEFAULT_GROUP_ORDER; - default_order.value.number = IMQUIC_MOQ_ORDERING_ASCENDING; - exts = g_list_append(exts, &default_order); - imquic_moq_publish(conn, moq_request_id, &tns[0], &tn, moq_track_alias, ¶ms, exts); - g_list_free(exts); + imquic_moq_publish(conn, moq_request_id, &tns[0], &tn, moq_track_alias, ¶ms, NULL); } } @@ -254,18 +243,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req rparams.largest_object_set = TRUE; rparams.largest_object = sub_start; } - /* Add a couple of track extensions too (will be ignored on versions older than v16) */ - GList *exts = NULL; - imquic_moq_object_extension default_priority = { 0 }; - default_priority.id = IMQUIC_MOQ_EXT_DEFAULT_PUBLISHER_PRIORITY; - default_priority.value.number = 128; - exts = g_list_append(exts, &default_priority); - imquic_moq_object_extension default_order = { 0 }; - default_order.id = IMQUIC_MOQ_EXT_DEFAULT_GROUP_ORDER; - default_order.value.number = IMQUIC_MOQ_ORDERING_ASCENDING; - exts = g_list_append(exts, &default_order); - imquic_moq_accept_subscribe(conn, moq_request_id, moq_track_alias, &rparams, exts); - g_list_free(exts); + imquic_moq_accept_subscribe(conn, moq_request_id, moq_track_alias, &rparams, NULL); /* Start sending objects */ IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Starting delivery of objects: [%"SCNu64"/%"SCNu64"] --> [%"SCNu64"/%"SCNu64"]\n", imquic_get_connection_name(conn), sub_start.group, sub_start.object, sub_end.group, sub_end.object); @@ -303,43 +281,43 @@ static void imquic_demo_connection_gone(imquic_connection *conn) { } static void imquic_demo_send_data(char *text, gboolean first, gboolean last) { - GList *exts = NULL; - imquic_moq_object_extension pgidext = { 0 }; - imquic_moq_object_extension poidext = { 0 }; - imquic_moq_object_extension numext = { 0 }; - imquic_moq_object_extension dataext = { 0 }; + GList *props = NULL; + imquic_moq_property pgidprop = { 0 }; + imquic_moq_property poidprop = { 0 }; + imquic_moq_property numprop = { 0 }; + imquic_moq_property dataprop = { 0 }; if((first && options.first_group > 0 && group_id == options.first_group) || (first && options.first_object > 0 && object_id == options.first_object) || - options.extensions) { - /* We have extensions to add to the object */ + options.properties) { + /* We have properties to add to the object */ if(first && options.first_group > 0 && group_id == options.first_group) { - /* Add the Prior Group ID Gap extension */ - pgidext.id = IMQUIC_MOQ_EXT_PRIOR_GROUP_ID_GAP; - pgidext.value.number = options.first_group; - exts = g_list_append(exts, &pgidext); + /* Add the Prior Group ID Gap property */ + pgidprop.id = IMQUIC_MOQ_PROPERTY_PRIOR_GROUP_ID_GAP; + pgidprop.value.number = options.first_group; + props = g_list_append(props, &pgidprop); } if(first && options.first_object > 0 && object_id == options.first_object) { - /* Add the Prior Object ID Gap extension */ - poidext.id = IMQUIC_MOQ_EXT_PRIOR_OBJECT_ID_GAP; - poidext.value.number = options.first_object; - exts = g_list_append(exts, &poidext); + /* Add the Prior Object ID Gap property */ + poidprop.id = IMQUIC_MOQ_PROPERTY_PRIOR_OBJECT_ID_GAP; + poidprop.value.number = options.first_object; + props = g_list_append(props, &poidprop); } - if(options.extensions) { - /* Just for fun, we add a couple of fake extensions to the object: a numeric - * extension set to the length of the text, and a data extension with a fixed string */ - numext.id = 0x6; /* FIXME */ - numext.value.number = strlen(text); - exts = g_list_append(exts, &numext); - dataext.id = 0x7; /* FIXME */ - dataext.value.data.buffer = (uint8_t *)"lminiero"; - dataext.value.data.length = strlen("lminiero"); - exts = g_list_append(exts, &dataext); + if(options.properties) { + /* Just for fun, we add a couple of fake properties to the object: a numeric + * property set to the length of the text, and a data property with a fixed string */ + numprop.id = 0x6; /* FIXME */ + numprop.value.number = strlen(text); + props = g_list_append(props, &numprop); + dataprop.id = 0x7; /* FIXME */ + dataprop.value.data.buffer = (uint8_t *)"lminiero"; + dataprop.value.data.length = strlen("lminiero"); + props = g_list_append(props, &dataprop); } } /* Check if it matches the filter */ if(group_id < sub_start.group || (group_id == sub_start.group && object_id < sub_start.object)) { /* Not the time to send the object yet */ - g_list_free(exts); + g_list_free(props); return; } if(group_id > sub_end.group || (group_id == sub_end.group && object_id > sub_end.object)) { @@ -351,7 +329,7 @@ static void imquic_demo_send_data(char *text, gboolean first, gboolean last) { g_atomic_int_set(&done_sent, 1); moq_request_id = 0; g_atomic_int_set(&send_objects, 0); - g_list_free(exts); + g_list_free(props); return; } else if(group_id == sub_end.group && object_id == sub_end.object) { last = TRUE; @@ -366,19 +344,19 @@ static void imquic_demo_send_data(char *text, gboolean first, gboolean last) { .object_status = 0, .payload = (uint8_t *)text, .payload_len = strlen(text), - .extensions = exts, + .properties = props, .delivery = delivery, .end_of_stream = FALSE }; imquic_moq_send_object(moq_conn, &object); - g_list_free(exts); + g_list_free(props); if(last && delivery == IMQUIC_MOQ_USE_SUBGROUP) { /* Send an empty object with status "end of X" */ object.object_id++; object.object_status = IMQUIC_MOQ_END_OF_GROUP; object.payload_len = 0; object.payload = NULL; - object.extensions = NULL; + object.properties = NULL; object.end_of_stream = TRUE; imquic_moq_send_object(moq_conn, &object); } @@ -474,9 +452,9 @@ int main(int argc, char *argv[]) { } } if(options.first_group > 0) - IMQUIC_LOG(IMQUIC_LOG_INFO, "First group: %"SCNu64" (will send the 'Prior Group ID Gap' extension)\n", options.first_group); + IMQUIC_LOG(IMQUIC_LOG_INFO, "First group: %"SCNu64" (will send the 'Prior Group ID Gap' property)\n", options.first_group); if(options.first_object > 0) - IMQUIC_LOG(IMQUIC_LOG_INFO, "First object: %"SCNu64" (will send the 'Prior Object ID Gap' extension)\n", options.first_object); + IMQUIC_LOG(IMQUIC_LOG_INFO, "First object: %"SCNu64" (will send the 'Prior Object ID Gap' property)\n", options.first_object); if(options.publish) { IMQUIC_LOG(IMQUIC_LOG_INFO, "Will use PUBLISH instead of PUBLISH_NAMESPACE + SUBSCRIBE\n"); } diff --git a/examples/moq-relay.c b/examples/moq-relay.c index f8f24dd..519fc74 100644 --- a/examples/moq-relay.c +++ b/examples/moq-relay.c @@ -79,7 +79,7 @@ typedef struct imquic_demo_moq_track { gboolean pending; GList *subscriptions; GList *objects; - GList *extensions; + GList *properties; imquic_mutex mutex; } imquic_demo_moq_track; static imquic_demo_moq_track *imquic_demo_moq_track_create(imquic_demo_moq_published_namespace *annc, const char *track_name); @@ -236,8 +236,8 @@ static void imquic_demo_moq_track_destroy(imquic_demo_moq_track *t) { t->subscriptions = NULL; g_list_free_full(t->objects, (GDestroyNotify)imquic_moq_object_cleanup); t->objects = NULL; - g_list_free_full(t->extensions, (GDestroyNotify)imquic_moq_object_extension_cleanup); - t->extensions = NULL; + g_list_free_full(t->properties, (GDestroyNotify)imquic_moq_property_cleanup); + t->properties = NULL; imquic_mutex_unlock(&t->mutex); imquic_mutex_destroy(&t->mutex); g_free(t); @@ -406,7 +406,7 @@ static void imquic_demo_alert_monitors(imquic_demo_moq_published_namespace *annc }; imquic_moq_request_parameters params; imquic_moq_request_parameters_init_defaults(¶ms); - imquic_moq_publish(mon->conn, relay_request_id, tns, &tn, relay_track_alias, ¶ms, track->extensions); + imquic_moq_publish(mon->conn, relay_request_id, tns, &tn, relay_track_alias, ¶ms, track->properties); } temp = temp->next; } @@ -561,13 +561,13 @@ static void imquic_demo_publish_namespace_done(imquic_connection *conn, imquic_m } static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { /* We received a publish */ char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); const char *name = imquic_moq_track_str(tn, tn_buffer, sizeof(tn_buffer)); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming publish for '%s--%s' (ID %"SCNu64"/%"SCNu64"; %d extensions)\n", - imquic_get_connection_name(conn), ns, name, request_id, track_alias, g_list_length(track_extensions)); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming publish for '%s--%s' (ID %"SCNu64"/%"SCNu64"; %d properties)\n", + imquic_get_connection_name(conn), ns, name, request_id, track_alias, g_list_length(track_properties)); if(parameters->auth_token_set) imquic_moq_print_auth_info(conn, parameters->auth_token, parameters->auth_token_len); if(name == NULL || strlen(name) == 0) @@ -603,7 +603,7 @@ static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t reque track->published = TRUE; track->pending = FALSE; track->track_alias_valid = TRUE; - track->extensions = imquic_moq_object_extensions_duplicate(track_extensions); + track->properties = imquic_moq_properties_duplicate(track_properties); g_hash_table_insert(annc->tracks, g_strdup(name), track); g_hash_table_insert(annc->pub->subscriptions_by_id, imquic_uint64_dup(track->request_id), track); g_hash_table_insert(annc->pub->subscriptions, imquic_uint64_dup(track->track_alias), track); @@ -885,7 +885,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req rparams.largest_object_set = TRUE; rparams.largest_object = s->sub_start; } - imquic_moq_accept_subscribe(conn, request_id, track_alias, &rparams, track->extensions); + imquic_moq_accept_subscribe(conn, request_id, track_alias, &rparams, track->properties); } /* If we just created a placeholder track, forward the subscribe to the publisher */ if(new_track) { @@ -908,12 +908,12 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req } static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, - imquic_moq_request_parameters *parameters, GList *track_extensions) { + imquic_moq_request_parameters *parameters, GList *track_properties) { /* Our subscription to a publisher was accepted */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscription %"SCNu64" accepted (expires=%"SCNu64"; %s order; %d extensions)\n", + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscription %"SCNu64" accepted (expires=%"SCNu64"; %s order; %d properties)\n", imquic_get_connection_name(conn), request_id, parameters->expires, imquic_moq_group_order_str(parameters->group_order), - g_list_length(track_extensions)); + g_list_length(track_properties)); if(parameters->largest_object_set) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Largest Location: %"SCNu64"/%"SCNu64"\n", imquic_get_connection_name(conn), @@ -937,7 +937,7 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req track->track_alias = track_alias; track->track_alias_valid = TRUE; g_hash_table_insert(pub->subscriptions, imquic_uint64_dup(track->track_alias), track); - track->extensions = imquic_moq_object_extensions_duplicate(track_extensions); + track->properties = imquic_moq_properties_duplicate(track_properties); /* Send a SUBSCRIBE_OK to all subscribers */ imquic_mutex_lock(&track->mutex); GList *temp = track->subscriptions; @@ -945,7 +945,7 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req imquic_demo_moq_subscription *s = (imquic_demo_moq_subscription *)temp->data; if(s && s->sub && s->sub->conn) { s->active = TRUE; - imquic_moq_accept_subscribe(s->sub->conn, s->request_id, s->track_alias, parameters, track->extensions); + imquic_moq_accept_subscribe(s->sub->conn, s->request_id, s->track_alias, parameters, track->properties); } temp = temp->next; } @@ -1226,7 +1226,7 @@ static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint6 imquic_moq_request_parameters_init_defaults(&rparams); rparams.group_order_set = parameters->group_order_set; rparams.group_order = parameters->group_order; - imquic_moq_accept_fetch(conn, request_id, &largest, &rparams, track->extensions); + imquic_moq_accept_fetch(conn, request_id, &largest, &rparams, track->properties); imquic_mutex_unlock(&mutex); } @@ -1300,7 +1300,7 @@ static void imquic_demo_incoming_joining_fetch(imquic_connection *conn, uint64_t imquic_moq_request_parameters_init_defaults(&rparams); rparams.group_order_set = parameters->group_order_set; rparams.group_order = parameters->group_order; - imquic_moq_accept_fetch(conn, request_id, &largest, &rparams, track->extensions); + imquic_moq_accept_fetch(conn, request_id, &largest, &rparams, track->properties); imquic_mutex_unlock(&mutex); } @@ -1324,10 +1324,10 @@ static void imquic_demo_incoming_fetch_cancel(imquic_connection *conn, uint64_t static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_object *object) { /* We received an object */ if(!options.quiet) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming object: reqid=%"SCNu64", alias=%"SCNu64", group=%"SCNu64", subgroup=%"SCNu64", id=%"SCNu64", payload=%zu bytes, extensions=%d, delivery=%s, status=%s, eos=%d\n", + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming object: reqid=%"SCNu64", alias=%"SCNu64", group=%"SCNu64", subgroup=%"SCNu64", id=%"SCNu64", payload=%zu bytes, properties=%d, delivery=%s, status=%s, eos=%d\n", imquic_get_connection_name(conn), object->request_id, object->track_alias, object->group_id, object->subgroup_id, object->object_id, - object->payload_len, g_list_length(object->extensions), imquic_moq_delivery_str(object->delivery), + object->payload_len, g_list_length(object->properties), imquic_moq_delivery_str(object->delivery), imquic_moq_object_status_str(object->object_status), object->end_of_stream); } /* Find the track associated to this subscription */ diff --git a/examples/moq-sub.c b/examples/moq-sub.c index ebd692f..2bf2571 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -101,17 +101,17 @@ static const char *imquic_demo_media_type_str(imquic_demo_media_type type) { return NULL; } -typedef enum imquic_demo_loc_extension { - DEMO_LOC_MEDIA_TYPE = 0x0A, /* Media type header extension */ +typedef enum imquic_demo_loc_property { + DEMO_LOC_MEDIA_TYPE = 0x0A, /* Media type header property */ DEMO_LOC_H264_HEADER = 0x0B, /* Video H264 in AVCC metadata (TODO change to 0x15) */ DEMO_LOC_H264_EXTRADATA = 0x0D, /* Video H264 in AVCC extradata */ DEMO_LOC_OPUS_HEADER = 0x0F, /* Audio Opus bitstream data */ DEMO_LOC_AAC_HEADER = 0x13, /* Audio AAC-LC in MPEG4 bitstream data */ -} imquic_demo_loc_extension; -static const char *imquic_demo_loc_extension_str(imquic_demo_loc_extension type) { +} imquic_demo_loc_property; +static const char *imquic_demo_loc_property_str(imquic_demo_loc_property type) { switch(type) { case DEMO_LOC_MEDIA_TYPE: - return "Media type header extension"; + return "Media type property"; case DEMO_LOC_H264_HEADER: return "Video H264 in AVCC metadata"; case DEMO_LOC_H264_EXTRADATA: @@ -324,11 +324,11 @@ static void imquic_demo_track_status_error(imquic_connection *conn, uint64_t req } static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, - imquic_moq_request_parameters *parameters, GList *track_extensions) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscription %"SCNu64" accepted (expires=%"SCNu64"; %s order, %d extensions)\n", + imquic_moq_request_parameters *parameters, GList *track_properties) { + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Subscription %"SCNu64" accepted (expires=%"SCNu64"; %s order, %d properties)\n", imquic_get_connection_name(conn), request_id, parameters->expires, imquic_moq_group_order_str(parameters->group_order), - g_list_length(track_extensions)); + g_list_length(track_properties)); IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] -- Track Alias: %"SCNu64"\n", imquic_get_connection_name(conn), track_alias); if(parameters->largest_object_set) { @@ -336,21 +336,8 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req imquic_get_connection_name(conn), parameters->largest_object.group, parameters->largest_object.object); } - if(track_extensions != NULL) { - GList *temp = track_extensions; - while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - const char *ext_name = imquic_moq_extension_type_str(ext->id); - if(ext->id % 2 == 0) { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %"SCNu64"\n", - ext->id, (ext_name ? ext_name : "unknown"), ext->value.number); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %.*s\n", - ext->id, (ext_name ? ext_name : "unknown"), (int)ext->value.data.length, ext->value.data.buffer); - } - temp = temp->next; - } - } + if(track_properties != NULL) + imquic_moq_properties_print(track_properties); if(options.fetch != NULL && options.join_offset >= 0) { /* Send a Joining Fetch referencing this subscription */ imquic_moq_request_parameters fparams; @@ -395,32 +382,19 @@ static void imquic_demo_request_update_error(imquic_connection *conn, uint64_t r } static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { /* We received a publish */ char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); const char *name = imquic_moq_track_str(tn, tn_buffer, sizeof(tn_buffer)); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming publish for '%s--%s' (ID %"SCNu64"/%"SCNu64"; %d extensions)\n", - imquic_get_connection_name(conn), ns, name, request_id, track_alias, g_list_length(track_extensions)); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming publish for '%s--%s' (ID %"SCNu64"/%"SCNu64"; %d properties)\n", + imquic_get_connection_name(conn), ns, name, request_id, track_alias, g_list_length(track_properties)); if(parameters->auth_token_set) imquic_moq_print_auth_info(conn, parameters->auth_token, parameters->auth_token_len); if(name == NULL || strlen(name) == 0) name = "temp"; - if(track_extensions != NULL) { - GList *temp = track_extensions; - while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - const char *ext_name = imquic_moq_extension_type_str(ext->id); - if(ext->id % 2 == 0) { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %"SCNu64"\n", - ext->id, (ext_name ? ext_name : "unknown"), ext->value.number); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %.*s\n", - ext->id, (ext_name ? ext_name : "unknown"), (int)ext->value.data.length, ext->value.data.buffer); - } - temp = temp->next; - } - } + if(track_properties != NULL) + imquic_moq_properties_print(track_properties); /* Done */ imquic_moq_request_parameters rparams; imquic_moq_request_parameters_init_defaults(&rparams); @@ -453,26 +427,13 @@ static void imquic_demo_publish_done(imquic_connection *conn, uint64_t request_i } static void imquic_demo_fetch_accepted(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, - imquic_moq_request_parameters *parameters, GList *track_extensions) { - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Fetch %"SCNu64" accepted (%s order; largest group/object %"SCNu64"/%"SCNu64"; %d extensions)\n", + imquic_moq_request_parameters *parameters, GList *track_properties) { + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Fetch %"SCNu64" accepted (%s order; largest group/object %"SCNu64"/%"SCNu64"; %d properties)\n", imquic_get_connection_name(conn), request_id, imquic_moq_group_order_str(parameters->group_order), - largest->group, largest->object, g_list_length(track_extensions)); - if(track_extensions != NULL) { - GList *temp = track_extensions; - while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - const char *ext_name = imquic_moq_extension_type_str(ext->id); - if(ext->id % 2 == 0) { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %"SCNu64"\n", - ext->id, (ext_name ? ext_name : "unknown"), ext->value.number); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %.*s\n", - ext->id, (ext_name ? ext_name : "unknown"), (int)ext->value.data.length, ext->value.data.buffer); - } - temp = temp->next; - } - } + largest->group, largest->object, g_list_length(track_properties)); + if(track_properties != NULL) + imquic_moq_properties_print(track_properties); } static void imquic_demo_fetch_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval) { @@ -497,10 +458,10 @@ static void imquic_demo_subscribe_namespace_error(imquic_connection *conn, uint6 static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_object *object) { /* We received an object */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming object: reqid=%"SCNu64", alias=%"SCNu64", group=%"SCNu64", subgroup=%"SCNu64", id=%"SCNu64", payload=%zu bytes, extensions=%d, delivery=%s, status=%s, eos=%d\n", + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming object: reqid=%"SCNu64", alias=%"SCNu64", group=%"SCNu64", subgroup=%"SCNu64", id=%"SCNu64", payload=%zu bytes, properties=%d, delivery=%s, status=%s, eos=%d\n", imquic_get_connection_name(conn), object->request_id, object->track_alias, object->group_id, object->subgroup_id, object->object_id, - object->payload_len, g_list_length(object->extensions), imquic_moq_delivery_str(object->delivery), + object->payload_len, g_list_length(object->properties), imquic_moq_delivery_str(object->delivery), imquic_moq_object_status_str(object->object_status), object->end_of_stream); if(object->payload == NULL || object->payload_len == 0) { if(object->end_of_stream) { @@ -513,21 +474,8 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje } return; } - if(object->extensions != NULL) { - GList *temp = object->extensions; - while(payload_type != DEMO_TYPE_LOC && temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - const char *ext_name = imquic_moq_extension_type_str(ext->id); - if(ext->id % 2 == 0) { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %"SCNu64"\n", - ext->id, (ext_name ? ext_name : "unknown"), ext->value.number); - } else { - IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Extension '%"SCNu32"' (%s) = %.*s\n", - ext->id, (ext_name ? ext_name : "unknown"), (int)ext->value.data.length, ext->value.data.buffer); - } - temp = temp->next; - } - } + if(object->properties != NULL) + imquic_moq_properties_print(object->properties); if(file != NULL) fwrite(object->payload, 1, object->payload_len, file); if(payload_type == DEMO_TYPE_TEXT) { @@ -540,54 +488,54 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje } else if(payload_type == DEMO_TYPE_LOC) { /* FIXME Assuming LOC from https://github.com/facebookexperimental/moq-encoder-player/ * which uses the MoQ-MI draft: https://datatracker.ietf.org/doc/html/draft-cenzano-moq-media-interop */ - if(object->extensions == NULL) { - IMQUIC_LOG(IMQUIC_LOG_WARN, " -- No extensions, missing LOC info?\n"); + if(object->properties == NULL) { + IMQUIC_LOG(IMQUIC_LOG_WARN, " -- No properties, missing LOC info?\n"); } else { - /* Parse the extensions to get access to the LOC info */ - IMQUIC_LOG(IMQUIC_LOG_INFO, " -- %d extensions\n", g_list_length(object->extensions)); + /* Parse the properties to get access to the LOC info */ + IMQUIC_LOG(IMQUIC_LOG_INFO, " -- %d properties\n", g_list_length(object->properties)); imquic_demo_media_type media_type = DEMO_MEDIA_NONE; - struct imquic_moq_object_extension_data *loc_header = NULL, *loc_extradata = NULL; - GList *temp = object->extensions; + struct imquic_moq_property_data *loc_header = NULL, *loc_extradata = NULL; + GList *temp = object->properties; while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - switch(ext->id) { + imquic_moq_property *prop = (imquic_moq_property *)temp->data; + switch(prop->id) { case DEMO_LOC_MEDIA_TYPE: { - media_type = ext->value.number; + media_type = prop->value.number; IMQUIC_LOG(IMQUIC_LOG_INFO, " -- -- %s: %s\n", - imquic_demo_loc_extension_str(ext->id), + imquic_demo_loc_property_str(prop->id), imquic_demo_media_type_str(media_type)); break; } case DEMO_LOC_H264_HEADER: { - loc_header = &ext->value.data; + loc_header = &prop->value.data; IMQUIC_LOG(IMQUIC_LOG_INFO, " -- -- %s: %zu bytes\n", - imquic_demo_loc_extension_str(ext->id), + imquic_demo_loc_property_str(prop->id), loc_header->length); break; } case DEMO_LOC_H264_EXTRADATA: { - loc_extradata = &ext->value.data; + loc_extradata = &prop->value.data; IMQUIC_LOG(IMQUIC_LOG_INFO, " -- -- %s: %zu bytes\n", - imquic_demo_loc_extension_str(ext->id), + imquic_demo_loc_property_str(prop->id), loc_extradata->length); break; } case DEMO_LOC_OPUS_HEADER: { - loc_header = &ext->value.data; + loc_header = &prop->value.data; IMQUIC_LOG(IMQUIC_LOG_INFO, " -- -- %s: %zu bytes\n", - imquic_demo_loc_extension_str(ext->id), + imquic_demo_loc_property_str(prop->id), loc_header->length); break; } case DEMO_LOC_AAC_HEADER: { - loc_header = &ext->value.data; + loc_header = &prop->value.data; IMQUIC_LOG(IMQUIC_LOG_INFO, " -- -- %s: %zu bytes\n", - imquic_demo_loc_extension_str(ext->id), + imquic_demo_loc_property_str(prop->id), loc_header->length); break; } default: { - IMQUIC_LOG(IMQUIC_LOG_WARN, " -- -- Unknown extension '%"SCNu32"'\n", ext->id); + IMQUIC_LOG(IMQUIC_LOG_WARN, " -- -- Unknown property '%"SCNu32"'\n", prop->id); break; } } diff --git a/examples/moq-test.c b/examples/moq-test.c index 780c96b..31a615a 100644 --- a/examples/moq-test.c +++ b/examples/moq-test.c @@ -95,9 +95,9 @@ static const char *imquic_demo_tuple_field_str(imquic_demo_tuple_field field) { case TUPLE_FIELD_SEND_EOG: return "Send End of Group Markers"; case TUPLE_FIELD_EXT_INT: - return "Test Integer Extension"; + return "Test Integer Property"; case TUPLE_FIELD_EXT_VAR: - return "Test Variable Extension"; + return "Test Variable Property"; case TUPLE_FIELD_TIMEOUT: return "Publisher Delivery Timeout"; default: @@ -603,11 +603,11 @@ static void *imquic_demo_tester_thread(void *data) { uint8_t *obj_p = s->test[TUPLE_FIELD_OBJS_SIZE] ? g_malloc(s->test[TUPLE_FIELD_OBJS_SIZE]) : NULL; if(obj_p) memset(obj_p, 't', s->test[TUPLE_FIELD_OBJS_SIZE]); - size_t extensions_count = 0; + size_t properties_count = 0; if(s->test[TUPLE_FIELD_EXT_INT] >= 0) - extensions_count++; + properties_count++; if(s->test[TUPLE_FIELD_EXT_VAR] >= 0) - extensions_count++; + properties_count++; /* Timers */ int64_t frequency = s->test[TUPLE_FIELD_OBJS_FREQ] * 1000; int64_t sleep_time = frequency/2; @@ -658,21 +658,21 @@ static void *imquic_demo_tester_thread(void *data) { (s->descending && (object_id == 0 || (group_id == (uint64_t)s->test[TUPLE_FIELD_START_GROUP] && object_id <= (uint64_t)s->test[TUPLE_FIELD_START_OBJECT])))) last_object = TRUE; } - GList *exts = NULL; - if(extensions_count > 0) { - imquic_moq_object_extension numext = { 0 }, dataext = { 0 }; + GList *props = NULL; + if(properties_count > 0) { + imquic_moq_property numprop = { 0 }, dataprop = { 0 }; if(s->test[TUPLE_FIELD_EXT_INT] >= 0) { - /* Add a numeric extension */ - numext.id = 2 * s->test[TUPLE_FIELD_EXT_INT]; - numext.value.number = g_random_int(); - exts = g_list_append(exts, &numext); + /* Add a numeric property */ + numprop.id = 2 * s->test[TUPLE_FIELD_EXT_INT]; + numprop.value.number = g_random_int(); + props = g_list_append(props, &numprop); } if(s->test[TUPLE_FIELD_EXT_VAR] >= 0) { - /* Add a data extension */ - dataext.id = 2 * s->test[TUPLE_FIELD_EXT_VAR] + 1; - dataext.value.data.buffer = (uint8_t *)"moq-test"; - dataext.value.data.length = strlen("moq-test"); - exts = g_list_append(exts, &dataext); + /* Add a data property */ + dataprop.id = 2 * s->test[TUPLE_FIELD_EXT_VAR] + 1; + dataprop.value.data.buffer = (uint8_t *)"moq-test"; + dataprop.value.data.length = strlen("moq-test"); + props = g_list_append(props, &dataprop); } } imquic_moq_object object = { @@ -684,7 +684,7 @@ static void *imquic_demo_tester_thread(void *data) { .object_status = 0, .payload = (num_objects == 0) ? obj0_p : obj_p, .payload_len = (num_objects == 0) ? s->test[TUPLE_FIELD_OBJ0_SIZE] : s->test[TUPLE_FIELD_OBJS_SIZE], - .extensions = exts, + .properties = props, .delivery = delivery, .end_of_stream = (last_object || (!s->fetch && num_objects == (s->test[TUPLE_FIELD_OBJS_x_GROUP] - 1) && !s->test[TUPLE_FIELD_SEND_EOG])) }; @@ -694,7 +694,7 @@ static void *imquic_demo_tester_thread(void *data) { last_subgroup_id = object.subgroup_id; last_object_id = object.object_id; } - g_list_free(exts); + g_list_free(props); /* Update IDs for the next object */ num_objects++; next_group = (num_objects == s->test[TUPLE_FIELD_OBJS_x_GROUP]); @@ -711,7 +711,7 @@ static void *imquic_demo_tester_thread(void *data) { object.object_status = last_object ? IMQUIC_MOQ_END_OF_TRACK : IMQUIC_MOQ_END_OF_GROUP; object.payload_len = 0; object.payload = NULL; - object.extensions = NULL; + object.properties = NULL; object.end_of_stream = TRUE; if(send_object || last_object) imquic_moq_send_object(conn, &object); @@ -934,8 +934,8 @@ int main(int argc, char *argv[]) { default_test[TUPLE_FIELD_GROUP_INC] = 1; default_test[TUPLE_FIELD_OBJ_INC] = 1; default_test[TUPLE_FIELD_SEND_EOG] = 0; - default_test[TUPLE_FIELD_EXT_INT] = -1; /* Don't add any numeric extension by default */ - default_test[TUPLE_FIELD_EXT_VAR] = -1; /* Don't add any variable extension by default */ + default_test[TUPLE_FIELD_EXT_INT] = -1; /* Don't add any numeric property by default */ + default_test[TUPLE_FIELD_EXT_VAR] = -1; /* Don't add any variable property by default */ default_test[TUPLE_FIELD_TIMEOUT] = -1; /* No delivery timeout by default */ /* Initialize the resources we'll need */ diff --git a/examples/moq-utils.c b/examples/moq-utils.c index 2db6e6e..7874a1c 100644 --- a/examples/moq-utils.c +++ b/examples/moq-utils.c @@ -22,51 +22,68 @@ imquic_moq_object *imquic_moq_object_duplicate(imquic_moq_object *object) { new_obj->payload = g_malloc(object->payload_len); memcpy(new_obj->payload, object->payload, object->payload_len); } - new_obj->extensions = imquic_moq_object_extensions_duplicate(object->extensions); + new_obj->properties = imquic_moq_properties_duplicate(object->properties); return new_obj; } -/* Helper to duplicate a list of extensions */ -GList *imquic_moq_object_extensions_duplicate(GList *extensions) { - if(extensions == NULL) +/* Helper to print a list of properties */ +void imquic_moq_properties_print(GList *properties) { + GList *temp = properties; + while(temp) { + imquic_moq_property *prop = (imquic_moq_property *)temp->data; + const char *prop_name = imquic_moq_property_type_str(prop->id); + if(prop->id % 2 == 0) { + IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Property '%"SCNu32"' (%s) = %"SCNu64"\n", + prop->id, (prop_name ? prop_name : "unknown"), prop->value.number); + } else { + IMQUIC_LOG(IMQUIC_LOG_INFO, " >> Property '%"SCNu32"' (%s) = %.*s\n", + prop->id, (prop_name ? prop_name : "unknown"), (int)prop->value.data.length, prop->value.data.buffer); + } + temp = temp->next; + } +} + +/* Helper to duplicate a list of properties */ +GList *imquic_moq_properties_duplicate(GList *properties) { + if(properties == NULL) return NULL; - GList *new_extensions = NULL; - GList *temp = extensions; + GList *new_properties = NULL; + GList *temp = properties; while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - imquic_moq_object_extension *new_ext = g_malloc0(sizeof(imquic_moq_object_extension)); - new_ext->id = ext->id; - if(ext->id % 2 == 0) { - new_ext->value.number = ext->value.number; + imquic_moq_property *prop = (imquic_moq_property *)temp->data; + imquic_moq_property *new_prop = g_malloc0(sizeof(imquic_moq_property)); + new_prop->id = prop->id; + if(prop->id % 2 == 0) { + new_prop->value.number = prop->value.number; } else { - new_ext->value.data.length = ext->value.data.length; - if(ext->value.data.length > 0) { - new_ext->value.data.buffer = g_malloc(ext->value.data.length); - memcpy(new_ext->value.data.buffer, ext->value.data.buffer, ext->value.data.length); + new_prop->value.data.length = prop->value.data.length; + if(prop->value.data.length > 0) { + new_prop->value.data.buffer = g_malloc(prop->value.data.length); + memcpy(new_prop->value.data.buffer, prop->value.data.buffer, prop->value.data.length); } } - new_extensions = g_list_prepend(new_extensions, new_ext); + new_properties = g_list_prepend(new_properties, new_prop); temp = temp->next; } - new_extensions = g_list_reverse(new_extensions); - return new_extensions; + new_properties = g_list_reverse(new_properties); + return new_properties; } /* Helper to destroy a duplicated object */ void imquic_moq_object_cleanup(imquic_moq_object *object) { if(object) { g_free(object->payload); - g_list_free_full(object->extensions, (GDestroyNotify)(imquic_moq_object_extension_cleanup)); + g_list_free_full(object->properties, (GDestroyNotify)(imquic_moq_property_cleanup)); g_free(object); } } -/* Helper to destroy an object extension */ -void imquic_moq_object_extension_cleanup(imquic_moq_object_extension *extension) { - if(extension != NULL) { - if(extension->value.data.buffer != NULL) - g_free(extension->value.data.buffer); - g_free(extension); +/* Helper to destroy an object propertie */ +void imquic_moq_property_cleanup(imquic_moq_property *property) { + if(property != NULL) { + if(property->value.data.buffer != NULL) + g_free(property->value.data.buffer); + g_free(property); } } diff --git a/examples/moq-utils.h b/examples/moq-utils.h index 75b2d8b..1b28769 100644 --- a/examples/moq-utils.h +++ b/examples/moq-utils.h @@ -21,10 +21,12 @@ imquic_moq_object *imquic_moq_object_duplicate(imquic_moq_object *object); /* Helper to destroy a duplicated object */ void imquic_moq_object_cleanup(imquic_moq_object *object); -/* Helper to duplicate a list of extensions */ -GList *imquic_moq_object_extensions_duplicate(GList *extensions); -/* Helper to destroy an object extension */ -void imquic_moq_object_extension_cleanup(imquic_moq_object_extension *extension); +/* Helper to print a list of properties */ +void imquic_moq_properties_print(GList *properties); +/* Helper to duplicate a list of properties */ +GList *imquic_moq_properties_duplicate(GList *properties); +/* Helper to destroy an object property */ +void imquic_moq_property_cleanup(imquic_moq_property *property); /* Helpers to deal with auth info */ int imquic_moq_auth_info_to_bytes(imquic_connection *conn, const char *auth_info, uint8_t *auth, size_t *authlen); diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 0f98786..39c02ec 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -474,7 +474,7 @@ void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, void imquic_set_incoming_publish_cb(imquic_endpoint *endpoint, void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions)) { + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -519,7 +519,7 @@ void imquic_set_incoming_subscribe_cb(imquic_endpoint *endpoint, } void imquic_set_subscribe_accepted_cb(imquic_endpoint *endpoint, - void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions)) { + void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -709,7 +709,7 @@ void imquic_set_incoming_fetch_cancel_cb(imquic_endpoint *endpoint, } void imquic_set_fetch_accepted_cb(imquic_endpoint *endpoint, - void (* fetch_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_extensions)) { + void (* fetch_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_properties)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -852,24 +852,24 @@ const char *imquic_moq_object_status_str(imquic_moq_object_status status) { return NULL; } -/* Extension header types */ -const char *imquic_moq_extension_type_str(imquic_moq_extension_type type) { +/* Property types */ +const char *imquic_moq_property_type_str(imquic_moq_property_type type) { switch(type) { - case IMQUIC_MOQ_EXT_DELIVERY_TIMEOUT: + case IMQUIC_MOQ_PROPERTY_DELIVERY_TIMEOUT: return "Delivery Timeout"; - case IMQUIC_MOQ_EXT_MAX_CACHE_DURATION: + case IMQUIC_MOQ_PROPERTY_MAX_CACHE_DURATION: return "Max Cache Duration"; - case IMQUIC_MOQ_EXT_DEFAULT_PUBLISHER_PRIORITY: + case IMQUIC_MOQ_PROPERTY_DEFAULT_PUBLISHER_PRIORITY: return "Default Publisher Priority"; - case IMQUIC_MOQ_EXT_DEFAULT_GROUP_ORDER: + case IMQUIC_MOQ_PROPERTY_DEFAULT_GROUP_ORDER: return "Default Group Order"; - case IMQUIC_MOQ_EXT_DYNAMIC_GROUPS: + case IMQUIC_MOQ_PROPERTY_DYNAMIC_GROUPS: return "Dynamic Groups"; - case IMQUIC_MOQ_EXT_PRIOR_GROUP_ID_GAP: + case IMQUIC_MOQ_PROPERTY_PRIOR_GROUP_ID_GAP: return "Prior Group ID Gap"; - case IMQUIC_MOQ_EXT_PRIOR_OBJECT_ID_GAP: + case IMQUIC_MOQ_PROPERTY_PRIOR_OBJECT_ID_GAP: return "Prior Object ID Gap"; - case IMQUIC_MOQ_EXT_IMMUTABLE_EXTENSIONS: + case IMQUIC_MOQ_PROPERTY_IMMUTABLE_PROPERTIES: return "Immutable Extensions"; default: break; } diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 9174f24..9cac788 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -503,49 +503,49 @@ typedef enum imquic_moq_object_status { * @returns The type name as a string, if valid, or NULL otherwise */ const char *imquic_moq_object_status_str(imquic_moq_object_status status); -/*! \brief MoQ Object Extension +/*! \brief MoQ Property * \note This may contain info related to different MoQ versions, and so * should be considered a higher level abstraction that the internal * MoQ stack may (and often will) use and notify differently */ -typedef struct imquic_moq_object_extension { - /*! \brief MoQ extension ID */ +typedef struct imquic_moq_property { + /*! \brief MoQ Property ID */ uint32_t id; - /*! \brief Extension value, which could be either a number (even - * extension ID) or an octet of data with length (odd extension ID) */ + /*! \brief Property value, which could be either a number (even + * property ID) or an octet of data with length (odd property ID) */ union { uint64_t number; - struct imquic_moq_object_extension_data { + struct imquic_moq_property_data { uint64_t length; uint8_t *buffer; } data; } value; -} imquic_moq_object_extension; +} imquic_moq_property; -/*! \brief Known MoQ Object Extension header types - * \note The library will not try to interpret extensions and their +/*! \brief Known MoQ Property types + * \note The library will not try to interpret properties and their * payload: this is always left up to applications */ -typedef enum imquic_moq_extension_type { +typedef enum imquic_moq_property_type { /* Delivery Timeout */ - IMQUIC_MOQ_EXT_DELIVERY_TIMEOUT = 0x02, + IMQUIC_MOQ_PROPERTY_DELIVERY_TIMEOUT = 0x02, /* Max Cache Duration */ - IMQUIC_MOQ_EXT_MAX_CACHE_DURATION = 0x04, + IMQUIC_MOQ_PROPERTY_MAX_CACHE_DURATION = 0x04, /* Default Publisher Priority */ - IMQUIC_MOQ_EXT_DEFAULT_PUBLISHER_PRIORITY = 0x0E, + IMQUIC_MOQ_PROPERTY_DEFAULT_PUBLISHER_PRIORITY = 0x0E, /* Default Group Order */ - IMQUIC_MOQ_EXT_DEFAULT_GROUP_ORDER = 0x22, + IMQUIC_MOQ_PROPERTY_DEFAULT_GROUP_ORDER = 0x22, /* Dynamic Groups */ - IMQUIC_MOQ_EXT_DYNAMIC_GROUPS = 0x30, + IMQUIC_MOQ_PROPERTY_DYNAMIC_GROUPS = 0x30, /* Prior Group ID Gap */ - IMQUIC_MOQ_EXT_PRIOR_GROUP_ID_GAP = 0x3C, + IMQUIC_MOQ_PROPERTY_PRIOR_GROUP_ID_GAP = 0x3C, /* Prior Object ID Gap */ - IMQUIC_MOQ_EXT_PRIOR_OBJECT_ID_GAP = 0x3E, - /* Immutable Extensions */ - IMQUIC_MOQ_EXT_IMMUTABLE_EXTENSIONS = 0xB, -} imquic_moq_extension_type; -/*! \brief Helper function to serialize to string the name of a imquic_moq_extension_type value. - * @param type The imquic_moq_extension_type value + IMQUIC_MOQ_PROPERTY_PRIOR_OBJECT_ID_GAP = 0x3E, + /* Immutable Properties */ + IMQUIC_MOQ_PROPERTY_IMMUTABLE_PROPERTIES = 0xB, +} imquic_moq_property_type; +/*! \brief Helper function to serialize to string the name of a imquic_moq_property_type value. + * @param type The imquic_moq_property_type value * @returns The type name as a string, if valid, or NULL otherwise */ -const char *imquic_moq_extension_type_str(imquic_moq_extension_type type); +const char *imquic_moq_property_type_str(imquic_moq_property_type type); /*! \brief MoQ Object * \note This may contain info related to different MoQ versions, and so @@ -570,8 +570,8 @@ typedef struct imquic_moq_object { uint8_t *payload; /*! \brief Size of the MoQ object payload */ size_t payload_len; - /*! \brief MoQ object extensions, if any */ - GList *extensions; + /*! \brief MoQ properties, if any */ + GList *properties; /*! \brief How to send this object (or how it was received) */ imquic_moq_delivery delivery; /*! \brief Whether this signals the end of the stream */ @@ -855,7 +855,7 @@ void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, * @param incoming_publish Pointer to the function that will handle the incoming \c PUBLISH */ void imquic_set_incoming_publish_cb(imquic_endpoint *endpoint, void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions)); + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties)); /*! \brief Configure the callback function to be notified when a * \c PUBLISH we previously sent was accepted * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -880,7 +880,7 @@ void imquic_set_incoming_subscribe_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param subscribe_accepted Pointer to the function that will fire when a \c SUBSCRIBE is accepted */ void imquic_set_subscribe_accepted_cb(imquic_endpoint *endpoint, - void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions)); + void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties)); /*! \brief Configure the callback function to be notified when a * \c SUBSCRIBE we previously sent was rejected with an error * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -986,7 +986,7 @@ void imquic_set_incoming_fetch_cancel_cb(imquic_endpoint *endpoint, * @param fetch_accepted Pointer to the function that will fire when an \c FETCH is accepted */ void imquic_set_fetch_accepted_cb(imquic_endpoint *endpoint, void (* fetch_accepted)(imquic_connection *conn, uint64_t request_id, - imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_extensions)); + imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_properties)); /*! \brief Configure the callback function to be notified when an * \c FETCH we previously sent was rejected with an error * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -1132,11 +1132,11 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, imquic_moq_namesp * @param tn The imquic_moq_name track name to publish to * @param track_alias A unique numeric identifier to associate to the track in this subscription * @param parameters The parameters to add to the request - * @param track_extensions List of track extensions to add, if any + * @param track_properties List of track properties to add, if any * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Function to accept an incoming \c PUBLISH request * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to accept @@ -1166,10 +1166,10 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, * @param request_id The unique \c request_id value associated to the subscription to accept * @param track_alias The unique \c track_alias value associated to the subscription to accept * @param parameters The parameters to add to the request - * @param track_extensions List of track extensions to add, if any + * @param track_properties List of track properties to add, if any * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Function to reject an incoming \c SUBSCRIBE request * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to reject @@ -1296,10 +1296,10 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 * @param request_id The unique \c request_id value associated to the subscription to accept * @param largest The largest group/object IDs * @param parameters The parameters to add to the request - * @param track_extensions List of track extensions to add, if any + * @param track_properties List of track properties to add, if any * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, - imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_extensions); + imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Function to reject an incoming \c FETCH request * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to reject diff --git a/src/internal/moq.h b/src/internal/moq.h index 7a2e94d..9454abc 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -86,25 +86,25 @@ gboolean imquic_moq_is_datagram_message_type_valid(imquic_moq_version version, u * for \c OBJECT_DATAGRAM or \c OBJECT_DATAGRAM_STATUS out of the individual properties. * @param version The version of the connection * @param payload Whether there is a payload - * @param ext Whether there are extensions + * @param prop Whether there are properties * @param eog Whether there is an End of Group * @param oid Whether there is an Object ID * @param priority Whether there is a Publisher Priority * @returns The type as a bitmask flag */ uint8_t imquic_moq_datagram_message_type_return(imquic_moq_version version, - gboolean payload, gboolean ext, gboolean eog, gboolean oid, gboolean priority); + gboolean payload, gboolean prop, gboolean eog, gboolean oid, gboolean priority); /*! \brief Helper function to parse a imquic_moq_datagram_message_type value * for \c OBJECT_DATAGRAM or \c OBJECT_DATAGRAM_STATUS to the individual properties. * @param[in] version The version of the connection * @param[in] type The type to parse * @param[out] payload Output variable to write whether there is a payload - * @param[out] ext Output variable to write whether there are extensions + * @param[out] prop Output variable to write whether there are properties * @param[out] eog Output variable to write whether there is an End of Group * @param[out] oid Output variable to write whether there is an Object ID * @param[out] priority Output variable to write whether there is a Publisher Priority * @param[out] violation Whether the type has bits set that really shouldn't */ void imquic_moq_datagram_message_type_parse(imquic_moq_version version, uint8_t type, - gboolean *payload, gboolean *ext, gboolean *eog, gboolean *oid, gboolean *priority, gboolean *violation); + gboolean *payload, gboolean *prop, gboolean *eog, gboolean *oid, gboolean *priority, gboolean *violation); /*! \brief Helper function to serialize to string the name of a imquic_moq_datagram_message_type value. * @param type The type value * @param version The version of the connection @@ -131,23 +131,23 @@ gboolean imquic_moq_is_data_message_type_valid(imquic_moq_version version, uint8 * @param[in] version The version of the connection * @param[in] subgroup Whether the Subgroup ID field is present * @param[in] sgid0 Whether the default value of Subgroup ID is 0, in case the field is missing - * @param[in] ext Whether there are extensions + * @param[in] prop Whether there are properties * @param[in] eog Whether there is an End of Group * @param[in] priority Whether there is a Publisher Priority * @returns The type as a bitmask flag */ uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version version, - gboolean subgroup, gboolean sgid0, gboolean ext, gboolean eog, gboolean priority); + gboolean subgroup, gboolean sgid0, gboolean prop, gboolean eog, gboolean priority); /*! \brief Helper function to parse a type value for \c SUBRGOUP_HEADER to the individual properties. * @param[in] version The version of the connection * @param[in] type The type to parse * @param[out] subgroup Output variable to write whether the Subgroup ID field is present * @param[out] sgid0 Output variable to write whether the default value of Subgroup ID is 0, in case the field is missing - * @param[out] ext Output variable to write whether there are extensions + * @param[out] prop Output variable to write whether there are properties * @param[out] eog Output variable to write whether there is an End of Group * @param[out] priority Output variable to write whether there is a Publisher Priority * @param[out] violation Whether the type has bits set that really shouldn't */ void imquic_moq_data_message_type_to_subgroup_header(imquic_moq_version version, uint8_t type, - gboolean *subgroup, gboolean *sgid0, gboolean *ext, gboolean *eog, gboolean *priority, gboolean *violation); + gboolean *subgroup, gboolean *sgid0, gboolean *prop, gboolean *eog, gboolean *priority, gboolean *violation); /*! \brief Helper function to serialize to string the name of a imquic_moq_data_message_type value. * @param type The imquic_data_moq_message_type value * @param version The version of the connection @@ -178,13 +178,13 @@ gboolean imquic_moq_is_fetch_serialization_flags_valid(imquic_moq_version versio * @param[in] oid Whether the Object ID field is present * @param[in] group Whether the Group ID field is present * @param[in] priority Whether the Publisher field is present - * @param[in] ext Whether there are extensions + * @param[in] prop Whether there are properties * @param[in] datagram Whether the forwarding preference is Datagram * @param[in] end_ne_range Whether this is the end of a non-existent range (ignores all other properties) * @param[in] end_uk_range Whether this is the end of an unknown range (ignores all other properties) * @returns The serialization flags as an integer */ uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version version, - imquic_moq_fetch_subgroup_type subgroup, gboolean oid, gboolean group, gboolean priority, gboolean ext, + imquic_moq_fetch_subgroup_type subgroup, gboolean oid, gboolean group, gboolean priority, gboolean prop, gboolean datagram, gboolean end_ne_range, gboolean end_uk_range); /*! \brief Helper function to parse serialozation flags for \c FETCH to the individual properties. * @param[in] version The version of the connection @@ -193,23 +193,23 @@ uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version versio * @param[out] oid Output variable to write whether the Object ID field is present * @param[out] group Output variable to write whether the Group ID field is present * @param[out] priority Output variable to write whether there is a Publisher Priority - * @param[out] ext Output variable to write whether there are extensions + * @param[out] prop Output variable to write whether there are properties * @param[out] datagram Output variable to write whether the forwarding preference is Datagram * @param[out] end_ne_range Output variable to write whether this is the end of a non-existent range * @param[out] end_uk_range Output variable to write whether this is the end of an unknown range * @param[out] violation Whether the type has bits set that really shouldn't */ void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint64_t flags, - imquic_moq_fetch_subgroup_type *subgroup, gboolean *oid, gboolean *group, gboolean *priority, gboolean *ext, + imquic_moq_fetch_subgroup_type *subgroup, gboolean *oid, gboolean *group, gboolean *priority, gboolean *prop, gboolean *datagram, gboolean *end_ne_range, gboolean *end_uk_range, gboolean *violation); /*! \brief MoQ setup parameter types */ typedef enum imquic_moq_setup_option_type { - IMQUIC_MOQ_SETUP_PARAM_PATH = 0x01, - IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID = 0x02, - IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN = 0x03, - IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE = 0x04, - IMQUIC_MOQ_SETUP_PARAM_AUTHORITY = 0x05, - IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION = 0x07, + IMQUIC_MOQ_SETUP_OPTION_PATH = 0x01, + IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID = 0x02, + IMQUIC_MOQ_SETUP_OPTION_AUTHORIZATION_TOKEN = 0x03, + IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE = 0x04, + IMQUIC_MOQ_SETUP_OPTION_AUTHORITY = 0x05, + IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION = 0x07, } imquic_moq_setup_option_type; /*! \brief Helper function to serialize to string the name of a imquic_moq_setup_option_type value. * @param type The imquic_moq_setup_option_type value @@ -266,20 +266,20 @@ typedef struct imquic_moq_setup_options { gboolean unknown; } imquic_moq_setup_options; -/*! \brief Helper mode to parse an extensions buffer to a GList of imquic_moq_object_extension +/*! \brief Helper mode to parse a properties buffer to a GList of imquic_moq_property * \note The caller owns the list, and is responsible of freeing it and its content * @param version The version of the connection - * @param extensions The buffer containing the extensions data - * @param elen The size of the buffer containing the extensions data - * @returns A GList instance containing a set of imquic_moq_object_extension, if successful, or NULL if no extensions were found */ -GList *imquic_moq_parse_object_extensions(imquic_moq_version version, uint8_t *extensions, size_t elen); -/*! \brief Helper mode to craft an extensions buffer out of a GList of imquic_moq_object_extension + * @param properties The buffer containing the properties data + * @param plen The size of the buffer containing the properties data + * @returns A GList instance containing a set of imquic_moq_property, if successful, or NULL if no properties were found */ +GList *imquic_moq_parse_properties(imquic_moq_version version, uint8_t *properties, size_t plen); +/*! \brief Helper mode to craft a properties buffer out of a GList of imquic_moq_property * @param[in] version The version of the connection - * @param[in] extensions The list of extensions to serialize - * @param[out] bytes The buffer to write the extensions data to + * @param[in] properties The list of properties to serialize + * @param[out] bytes The buffer to write the properties data to * @param[in] blen The size of the buffer to write to * @returns How many bytes were written, if successful */ -size_t imquic_moq_build_object_extensions(imquic_moq_version version, GList *extensions, uint8_t *bytes, size_t blen); +size_t imquic_moq_build_properties(imquic_moq_version version, GList *properties, uint8_t *bytes, size_t blen); /*! \brief MoQ FETCH types */ typedef enum imquic_moq_fetch_type { @@ -823,11 +823,11 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t * @param track_name The track name to put in the message * @param track_alias The track alias to put in the message * @param parameters The parameters to add, if any - * @param track_extensions List of track extensions to add, if any + * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, - imquic_moq_request_parameters *parameters, GList *track_extensions); + imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper method to add a \c PUBLISH_OK message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -875,10 +875,10 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si * @param request_id The request ID to put in the message * @param track_alias The track alias to put in the message * @param parameters The parameters to add, if any - * @param track_extensions List of track extensions to add, if any + * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper method to add a \c SUBSCRIBE_ERRROR message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -993,10 +993,10 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size * @param end_of_track Whether all objects have been published * @param end_location End location to add to the message, if needed * @param parameters The parameters to add, if any - * @param track_extensions List of track extensions to add, if any + * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_extensions); + uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper method to add a \c FETCH_ERRROR message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -1058,12 +1058,12 @@ size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t ble * @param priority The publisher priority to put in the message * @param payload The buffer containing the payload of the object * @param plen The size of the payload buffer - * @param extensions The buffer containing the object extensions, if any - * @param elen The size of the object extensions buffer + * @param properties The buffer containing the properties, if any + * @param prlen The size of the properties buffer * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, uint64_t group_id, uint64_t object_id, uint64_t object_status, uint8_t priority, - uint8_t *payload, size_t plen, uint8_t *extensions, size_t elen); + uint8_t *payload, size_t plen, uint8_t *properties, size_t prlen); /*! \brief Helper to add an \c OBJECT_DATAGRAM_STATUS message to a buffer * @note This assumes the connection negotiated \c DATAGRAM support * @param moq The imquic_moq_context generating the message @@ -1074,12 +1074,12 @@ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, s * @param object_id The object ID to put in the message * @param priority The publisher priority to put in the message * @param object_status The object status (only added if the payload length is 0) - * @param extensions The buffer containing the object extensions, if any - * @param elen The size of the object extensions buffer + * @param properties The buffer containing the properties, if any + * @param prlen The size of the properties buffer * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_object_datagram_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t track_alias, uint64_t group_id, uint64_t object_id, uint8_t priority, - uint64_t object_status, uint8_t *extensions, size_t elen); + uint64_t object_status, uint8_t *properties, size_t prlen); /*! \brief Helper to add a \c SUBGROUP_HEADER message to a buffer * @note This will create a new \c STREAM and send the header: after * that, imquic_moq_add_stream_header_subgroup_object is used to send @@ -1106,12 +1106,12 @@ size_t imquic_moq_add_subgroup_header(imquic_moq_context *moq, imquic_moq_stream * @param object_status The object status (only added if the payload length is 0) * @param payload The buffer containing the payload of the object * @param plen The size of the payload buffer - * @param extensions The buffer containing the object extensions, if any - * @param elen The size of the object extensions buffer + * @param properties The buffer containing the properties, if any + * @param prlen The size of the properties buffer * @returns The size of the generated object, if successful, or 0 otherwise */ size_t imquic_moq_add_subgroup_header_object(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t object_id, uint64_t object_status, - uint8_t *payload, size_t plen, uint8_t *extensions, size_t elen); + uint8_t *payload, size_t plen, uint8_t *properties, size_t prlen); /*! \brief Helper to add a \c FETCH_HEADER message to a buffer * @note This will create a new \c STREAM and send the header: after * that, imquic_moq_add_fetch_header_object is used to send @@ -1135,21 +1135,21 @@ size_t imquic_moq_add_fetch_header(imquic_moq_context *moq, uint8_t *bytes, size * @param object_status The object status (only added if the payload length is 0) * @param payload The buffer containing the payload of the object * @param plen The size of the payload buffer - * @param extensions The buffer containing the object extensions, if any - * @param elen The size of the object extensions buffer + * @param properties The buffer containing the properties, if any + * @param prlen The size of the properties buffer * @returns The size of the generated object, if successful, or 0 otherwise */ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t flags, uint64_t group_id, uint64_t subgroup_id, uint64_t object_id, uint8_t priority, - uint64_t object_status, uint8_t *payload, size_t plen, uint8_t *extensions, size_t elen); -/*! \brief Helper method to add object extensions to a buffer + uint64_t object_status, uint8_t *payload, size_t plen, uint8_t *properties, size_t prlen); +/*! \brief Helper method to add properties to a buffer * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the extensions to + * @param bytes The buffer to add the properties to * @param blen The size of the buffer - * @param extensions The buffer containing the object extensions, if any - * @param elen The size of the object extensions buffer - * @returns The size of the generated extensions block, if successful, or 0 otherwise */ -size_t imquic_moq_add_object_extensions(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint8_t *extensions, size_t elen); + * @param properties The buffer containing the properties, if any + * @param prlen The size of the properties buffer + * @returns The size of the generated properties block, if successful, or 0 otherwise */ +size_t imquic_moq_add_properties(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint8_t *properties, size_t prlen); ///@} /** @name Parsing and building MoQ parameters @@ -1244,7 +1244,7 @@ typedef struct imquic_moq_callbacks { void (* publish_namespace_done)(imquic_connection *conn, imquic_moq_namespace *tns); /*! \brief Callback function to be notified about incoming \c PUBLISH messages */ void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Callback function to be notified about incoming \c PUBLISH_ACCEPTED messages */ void (* publish_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c PUBLISH_ERROR messages */ @@ -1253,7 +1253,7 @@ typedef struct imquic_moq_callbacks { void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_ACCEPTED messages */ - void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions); + void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_ERROR messages */ void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c REQUEST_UPDATE messages */ @@ -1289,7 +1289,7 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming \c FETCH_CANCEL messages */ void (* incoming_fetch_cancel)(imquic_connection *conn, uint64_t request_id); /*! \brief Callback function to be notified about incoming \c FETCH_ACCEPTED messages */ - void (* fetch_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_extensions); + void (* fetch_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Callback function to be notified about incoming \c FETCH_ERROR messages */ void (* fetch_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c TRACK_STATUS messages */ @@ -1372,11 +1372,11 @@ void imquic_qlog_moq_message_add_setup_options(json_t *message, imquic_moq_setup * @param name The name the array should have in the message object */ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_version version, imquic_moq_request_parameters *parameters, const char *name); -/*! \brief Helper to add a stringified array of extension headers to a message +/*! \brief Helper to add a stringified array of propertie headers to a message * @param message The message object to update - * @param extensions The list of extensions to convert + * @param properties The list of properties to convert * @param name The name the array should have in the message object */ -void imquic_qlog_moq_message_add_extensions(json_t *message, GList *extensions, const char *name); +void imquic_qlog_moq_message_add_properties(json_t *message, GList *properties, const char *name); /*! \brief Add a \c control_message_created event * @param qlog The imquic_qlog instance to add the event to * @param stream_id The Stream ID used for this message diff --git a/src/moq.c b/src/moq.c index 94bc253..d2550a9 100644 --- a/src/moq.c +++ b/src/moq.c @@ -307,11 +307,11 @@ static void imquic_moq_context_free(const imquic_refcount *moq_ref) { g_free(moq); } -static void imquic_moq_object_extension_free(imquic_moq_object_extension *extension) { - if(extension != NULL) { - if(extension->value.data.buffer != NULL) - g_free(extension->value.data.buffer); - g_free(extension); +static void imquic_moq_property_free(imquic_moq_property *property) { + if(property != NULL) { + if(property->value.data.buffer != NULL) + g_free(property->value.data.buffer); + g_free(property); } } @@ -559,13 +559,13 @@ gboolean imquic_moq_is_datagram_message_type_valid(imquic_moq_version version, u } uint8_t imquic_moq_datagram_message_type_return(imquic_moq_version version, - gboolean payload, gboolean ext, gboolean eog, gboolean oid, gboolean priority) { + gboolean payload, gboolean prop, gboolean eog, gboolean oid, gboolean priority) { uint8_t type = payload ? 0x00 : 0x20; if(!payload) eog = FALSE; if(eog) type |= 0x02; - if(ext) + if(prop) type |= 0x01; if(!oid) type |= 0x04; @@ -575,7 +575,7 @@ uint8_t imquic_moq_datagram_message_type_return(imquic_moq_version version, } void imquic_moq_datagram_message_type_parse(imquic_moq_version version, uint8_t type, - gboolean *payload, gboolean *ext, gboolean *eog, gboolean *oid, gboolean *priority, gboolean *violation) { + gboolean *payload, gboolean *prop, gboolean *eog, gboolean *oid, gboolean *priority, gboolean *violation) { if(oid) *oid = TRUE; if(priority) @@ -583,8 +583,8 @@ void imquic_moq_datagram_message_type_parse(imquic_moq_version version, uint8_t /* v15 and later */ if(payload) *payload = !(type & 0x20); - if(ext) - *ext = (type & 0x01); + if(prop) + *prop = (type & 0x01); if(eog) *eog = (type & 0x02); if(oid) @@ -613,7 +613,7 @@ gboolean imquic_moq_is_data_message_type_valid(imquic_moq_version version, uint8 } uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version version, - gboolean subgroup, gboolean sgid0, gboolean ext, gboolean eog, gboolean priority) { + gboolean subgroup, gboolean sgid0, gboolean prop, gboolean eog, gboolean priority) { uint8_t type = 0; if(subgroup) { sgid0 = FALSE; @@ -621,7 +621,7 @@ uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version ver } if(sgid0) type |= 0x02; - if(ext) + if(prop) type |= 0x01; if(eog) type |= 0x08; @@ -630,7 +630,7 @@ uint8_t imquic_moq_data_message_type_from_subgroup_header(imquic_moq_version ver } void imquic_moq_data_message_type_to_subgroup_header(imquic_moq_version version, uint8_t type, - gboolean *subgroup, gboolean *sgid0, gboolean *ext, gboolean *eog, gboolean *priority, gboolean *violation) { + gboolean *subgroup, gboolean *sgid0, gboolean *prop, gboolean *eog, gboolean *priority, gboolean *violation) { uint8_t base = 0x10; if(type >= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MIN && type <= IMQUIC_MOQ_SUBGROUP_HEADER_RANGE1_MAX) { base = 0x10; @@ -650,8 +650,8 @@ void imquic_moq_data_message_type_to_subgroup_header(imquic_moq_version version, *subgroup = (bitmask & 0x04); if(sgid0) *sgid0 = (bitmask & 0x02); - if(ext) - *ext = (bitmask & 0x01); + if(prop) + *prop = (bitmask & 0x01); if(eog) *eog = (bitmask & 0x08); } @@ -680,7 +680,7 @@ gboolean imquic_moq_is_fetch_serialization_flags_valid(imquic_moq_version versio } uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version version, - imquic_moq_fetch_subgroup_type subgroup, gboolean oid, gboolean group, gboolean priority, gboolean ext, + imquic_moq_fetch_subgroup_type subgroup, gboolean oid, gboolean group, gboolean priority, gboolean prop, gboolean datagram, gboolean end_ne_range, gboolean end_uk_range) { if(end_ne_range) { /* Ignore everything else */ @@ -697,7 +697,7 @@ uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version versio flags |= 0x08; if(priority) flags |= 0x10; - if(ext) + if(prop) flags |= 0x20; if(datagram) flags |= 0x40; @@ -705,7 +705,7 @@ uint64_t imquic_moq_generate_fetch_serialization_flags(imquic_moq_version versio } void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint64_t flags, - imquic_moq_fetch_subgroup_type *subgroup, gboolean *oid, gboolean *group, gboolean *priority, gboolean *ext, + imquic_moq_fetch_subgroup_type *subgroup, gboolean *oid, gboolean *group, gboolean *priority, gboolean *prop, gboolean *datagram, gboolean *end_ne_range, gboolean *end_uk_range, gboolean *violation) { /* Make sure the provided flags are valid, or return a protocol violation */ if(!imquic_moq_is_fetch_serialization_flags_valid(version, flags)) { @@ -739,8 +739,8 @@ void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint *group = (flags8 & 0x08); if(priority) *priority = (flags8 & 0x10); - if(ext) - *ext = (flags8 & 0x20); + if(prop) + *prop = (flags8 & 0x20); if(datagram) *datagram = (flags8 & 0x40); } @@ -748,17 +748,17 @@ void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint const char *imquic_moq_setup_option_type_str(imquic_moq_setup_option_type type) { switch(type) { - case IMQUIC_MOQ_SETUP_PARAM_PATH: + case IMQUIC_MOQ_SETUP_OPTION_PATH: return "PATH"; - case IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID: + case IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID: return "MAX_REQUEST_ID"; - case IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN: + case IMQUIC_MOQ_SETUP_OPTION_AUTHORIZATION_TOKEN: return "AUTHORIZATION_TOKEN"; - case IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE: + case IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE: return "MAX_AUTH_TOKEN_CACHE_SIZE"; - case IMQUIC_MOQ_SETUP_PARAM_AUTHORITY: + case IMQUIC_MOQ_SETUP_OPTION_AUTHORITY: return "AUTHORITY"; - case IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION: + case IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION: return "MOQT_IMPLEMENTATION"; default: break; } @@ -877,17 +877,17 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, uint64_t new_id = 0, last_id = 0; GList *list = NULL; if(options->path_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_PATH)); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_PATH)); if(options->max_request_id_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID)); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID)); if(options->max_auth_token_cache_size_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE)); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE)); if(options->auth_token_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN)); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_AUTHORIZATION_TOKEN)); if(options->authority_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_AUTHORITY)); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_AUTHORITY)); if(options->moqt_implementation_set) - list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION)); + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION)); *params_num = g_list_length(list); offset += imquic_write_varint(*params_num, &bytes[offset], blen-offset); if(list != NULL) { @@ -895,27 +895,27 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, GList *temp = list; while(temp) { new_id = GPOINTER_TO_UINT(temp->data); - if(new_id == IMQUIC_MOQ_SETUP_PARAM_PATH) { + if(new_id == IMQUIC_MOQ_SETUP_OPTION_PATH) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->path, strlen(options->path)); - } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID) { + } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID) { offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, options->max_request_id); - } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE) { + } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE) { offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, options->max_auth_token_cache_size); - } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN) { + } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_AUTHORIZATION_TOKEN) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, options->auth_token, options->auth_token_len); - } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_AUTHORITY) { + } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_AUTHORITY) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->authority, strlen(options->authority)); - } else if(new_id == IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION) { + } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION) { offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->moqt_implementation, strlen(options->moqt_implementation)); @@ -2103,20 +2103,19 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t offset += imquic_moq_parse_request_parameter(moq, &bytes[offset], blen-offset, ¶meters, ¶m, error); IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken PUBLISH"); } - /* v16 added support for Track Extensions */ - size_t ext_offset = 0, ext_len = 0; - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); + size_t prop_offset = 0, prop_len = 0; + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || (prop_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken PUBLISH"); - offset += ext_len; - GList *track_extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + IMQUIC_MOQ_CHECK_ERR(prop_len > blen-offset, NULL, 0, 0, "Broken PUBLISH"); + offset += prop_len; + GList *track_properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - track_extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + track_properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -2127,7 +2126,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -2137,12 +2136,12 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish) { moq->conn->socket->callbacks.moq.incoming_publish(moq->conn, - request_id, &tns[0], &tn, track_alias, ¶meters, track_extensions); + request_id, &tns[0], &tn, track_alias, ¶meters, track_properties); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_publish(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); } - g_list_free_full(track_extensions, (GDestroyNotify)imquic_moq_object_extension_free); + g_list_free_full(track_properties, (GDestroyNotify)imquic_moq_property_free); if(error) *error = 0; return offset; @@ -2343,20 +2342,19 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si offset += imquic_moq_parse_request_parameter(moq, &bytes[offset], blen-offset, ¶meters, ¶m, error); IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken SUBSCRIBE_OK"); } - /* v16 added support for Track Extensions */ - size_t ext_offset = 0, ext_len = 0; - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); + size_t prop_offset = 0, prop_len = 0; + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || (prop_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += ext_len; - GList *track_extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + IMQUIC_MOQ_CHECK_ERR(prop_len > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); + offset += prop_len; + GList *track_properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - track_extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + track_properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -2365,16 +2363,16 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.subscribe_accepted) { moq->conn->socket->callbacks.moq.subscribe_accepted(moq->conn, - request_id, track_alias, ¶meters, track_extensions); + request_id, track_alias, ¶meters, track_properties); } - g_list_free_full(track_extensions, (GDestroyNotify)imquic_moq_object_extension_free); + g_list_free_full(track_properties, (GDestroyNotify)imquic_moq_property_free); if(error) *error = 0; return offset; @@ -2821,20 +2819,19 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t offset += imquic_moq_parse_request_parameter(moq, &bytes[offset], blen-offset, ¶meters, ¶m, error); IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken FETCH_OK"); } - /* v16 added support for Track Extensions */ - size_t ext_offset = 0, ext_len = 0; - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || (ext_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); + size_t prop_offset = 0, prop_len = 0; + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || (prop_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(ext_len > blen-offset, NULL, 0, 0, "Broken FETCH_OK"); - offset += ext_len; - GList *track_extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + IMQUIC_MOQ_CHECK_ERR(prop_len > blen-offset, NULL, 0, 0, "Broken FETCH_OK"); + offset += prop_len; + GList *track_properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - track_extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + track_properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -2845,14 +2842,14 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "largest_object_id", json_integer(largest.object)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.fetch_accepted) - moq->conn->socket->callbacks.moq.fetch_accepted(moq->conn, request_id, &largest, ¶meters, track_extensions); - g_list_free_full(track_extensions, (GDestroyNotify)imquic_moq_object_extension_free); + moq->conn->socket->callbacks.moq.fetch_accepted(moq->conn, request_id, &largest, ¶meters, track_properties); + g_list_free_full(track_properties, (GDestroyNotify)imquic_moq_property_free); if(error) *error = 0; return offset; @@ -2924,8 +2921,8 @@ size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, if(bytes == NULL || blen < 5) return 0; /* TODO Check EOG too */ - gboolean has_ext = FALSE, has_oid = TRUE, has_priority = TRUE; - imquic_moq_datagram_message_type_parse(moq->version, dtype, NULL, &has_ext, NULL, &has_oid, &has_priority, NULL); + gboolean has_prop = FALSE, has_oid = TRUE, has_priority = TRUE; + imquic_moq_datagram_message_type_parse(moq->version, dtype, NULL, &has_prop, NULL, &has_oid, &has_priority, NULL); size_t offset = 0; uint8_t length = 0; uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); @@ -2953,23 +2950,23 @@ size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, } IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Publisher Priority: %"SCNu8"\n", imquic_get_connection_name(moq->conn), priority); - size_t ext_offset = 0, ext_len = 0; - if(has_ext) { - /* The object contains extensions */ - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + size_t prop_offset = 0, prop_len = 0; + if(has_prop) { + /* The object contains properties */ + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); - IMQUIC_MOQ_CHECK_ERR(ext_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Extensions length is 0 but type is OBJECT_DATAGRAM"); + IMQUIC_MOQ_CHECK_ERR(prop_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Properties length is 0 but type is OBJECT_DATAGRAM"); offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(length == 0 || ext_len >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); - offset += ext_len; - } - GList *extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + IMQUIC_MOQ_CHECK_ERR(length == 0 || prop_len >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); + offset += prop_len; + } + GList *properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Payload Length: %"SCNu64"\n", imquic_get_connection_name(moq->conn), blen-offset); @@ -2984,7 +2981,7 @@ size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, .priority = priority, .payload = (blen-offset > 0 ? &bytes[offset] : NULL), .payload_len = blen-offset, - .extensions = extensions, + .properties = properties, .delivery = IMQUIC_MOQ_USE_DATAGRAM, .end_of_stream = FALSE /* No stream is involved here */ }; @@ -2995,7 +2992,7 @@ size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, #endif if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_object) moq->conn->socket->callbacks.moq.incoming_object(moq->conn, &object); - g_list_free_full(extensions, (GDestroyNotify)imquic_moq_object_extension_free); + g_list_free_full(properties, (GDestroyNotify)imquic_moq_property_free); if(error) *error = 0; return offset; @@ -3006,8 +3003,8 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 5) return 0; - gboolean has_ext = FALSE, has_oid = TRUE, has_priority = TRUE; - imquic_moq_datagram_message_type_parse(moq->version, dtype, NULL, &has_ext, NULL, &has_oid, &has_priority, NULL); + gboolean has_prop = FALSE, has_oid = TRUE, has_priority = TRUE; + imquic_moq_datagram_message_type_parse(moq->version, dtype, NULL, &has_prop, NULL, &has_oid, &has_priority, NULL); size_t offset = 0; uint8_t length = 0; uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); @@ -3035,23 +3032,23 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t } IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Publisher Priority: %"SCNu8"\n", imquic_get_connection_name(moq->conn), priority); - size_t ext_offset = 0, ext_len = 0; - if(has_ext) { - /* The object contains extensions */ - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + size_t prop_offset = 0, prop_len = 0; + if(has_prop) { + /* The object contains properties */ + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); - IMQUIC_MOQ_CHECK_ERR(ext_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Extensions length is 0 but type is OBJECT_DATAGRAM_STATUS"); + IMQUIC_MOQ_CHECK_ERR(prop_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Properties length is 0 but type is OBJECT_DATAGRAM_STATUS"); offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - IMQUIC_MOQ_CHECK_ERR(length == 0 || ext_len >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); - offset += ext_len; - } - GList *extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + IMQUIC_MOQ_CHECK_ERR(length == 0 || prop_len >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); + offset += prop_len; + } + GList *properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } uint64_t object_status = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); @@ -3070,7 +3067,7 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t .priority = priority, .payload = NULL, .payload_len = 0, - .extensions = extensions, + .properties = properties, .delivery = IMQUIC_MOQ_USE_DATAGRAM, .end_of_stream = FALSE /* No stream is involved here */ }; @@ -3081,7 +3078,7 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t #endif if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_object) moq->conn->socket->callbacks.moq.incoming_object(moq->conn, &object); - g_list_free_full(extensions, (GDestroyNotify)imquic_moq_object_extension_free); + g_list_free_full(properties, (GDestroyNotify)imquic_moq_property_free); if(error) *error = 0; return offset; @@ -3106,11 +3103,11 @@ size_t imquic_moq_parse_subgroup_header(imquic_moq_context *moq, imquic_moq_stre imquic_get_connection_name(moq->conn), group_id); uint64_t subgroup_id = 0; /* Starting from v11, the subgroup ID property is optional */ - gboolean has_subgroup = FALSE, is_sgid0 = FALSE, has_ext = FALSE, is_eog = FALSE, has_priority = FALSE, violation = FALSE; + gboolean has_subgroup = FALSE, is_sgid0 = FALSE, has_prop = FALSE, is_eog = FALSE, has_priority = FALSE, violation = FALSE; imquic_moq_data_message_type_to_subgroup_header(moq->version, dtype, - &has_subgroup, &is_sgid0, &has_ext, &is_eog, &has_priority, &violation); - IMQUIC_LOG(IMQUIC_LOG_HUGE, "[%s][MoQ] SUBGROUP_HEADER type %02x: sg=%d, sgid0=%d, ext=%d, eog=%d, pri=%d, viol=%d\n", - imquic_get_connection_name(moq->conn), dtype, has_subgroup, is_sgid0, has_ext, is_eog, has_priority, violation); + &has_subgroup, &is_sgid0, &has_prop, &is_eog, &has_priority, &violation); + IMQUIC_LOG(IMQUIC_LOG_HUGE, "[%s][MoQ] SUBGROUP_HEADER type %02x: sg=%d, sgid0=%d, prop=%d, eog=%d, pri=%d, viol=%d\n", + imquic_get_connection_name(moq->conn), dtype, has_subgroup, is_sgid0, has_prop, is_eog, has_priority, violation); IMQUIC_MOQ_CHECK_ERR(violation, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid SUBGROUP_HEADER type"); if(has_subgroup) { subgroup_id = imquic_read_varint(&bytes[offset], blen-offset, &length); @@ -3162,23 +3159,23 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; - size_t ext_offset = 0, ext_len = 0; + size_t prop_offset = 0, prop_len = 0; /* TODO We can optimize this by only doing it once, when we parse the header */ /* TODO Check EOG too */ - gboolean has_subgroup = FALSE, is_sgid0 = FALSE, has_ext = FALSE, has_priority = FALSE; - imquic_moq_data_message_type_to_subgroup_header(moq->version, moq_stream->type, &has_subgroup, &is_sgid0, &has_ext, NULL, &has_priority, NULL); - if(has_ext) { - /* The object contains extensions */ - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + gboolean has_subgroup = FALSE, is_sgid0 = FALSE, has_prop = FALSE, has_priority = FALSE; + imquic_moq_data_message_type_to_subgroup_header(moq->version, moq_stream->type, &has_subgroup, &is_sgid0, &has_prop, NULL, &has_priority, NULL); + if(has_prop) { + /* The object contains properties */ + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - if(length == 0 || ext_len >= blen-offset) + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + if(length == 0 || prop_len >= blen-offset) return -1; /* Not enough data, try again later */ - offset += ext_len; + offset += prop_len; } uint64_t p_len = imquic_read_varint(&bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) @@ -3191,7 +3188,7 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ return -1; /* Not enough data, try again later */ /* TODO An invalid object status should be a protocol violation error */ //~ IMQUIC_MOQ_CHECK_ERR(object_status > IMQUIC_MOQ_END_OF_TRACK, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid object status"); - //~ IMQUIC_MOQ_CHECK_ERR(object_status == IMQUIC_MOQ_OBJECT_DOESNT_EXIST && ext_len > 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Extensions received in object with status 'Does Not Exist'"); + //~ IMQUIC_MOQ_CHECK_ERR(object_status == IMQUIC_MOQ_OBJECT_DOESNT_EXIST && prop_len > 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Properties received in object with status 'Does Not Exist'"); offset += length; } if(p_len > blen-offset) @@ -3216,10 +3213,10 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ if(!moq_stream->got_objects) moq_stream->got_objects = TRUE; moq_stream->last_object_id = object_id; - GList *extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + GList *properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } /* Notify the payload at the application layer */ imquic_moq_object object = { @@ -3232,7 +3229,7 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ .priority = moq_stream->priority, .payload = bytes + offset, .payload_len = p_len, - .extensions = extensions, + .properties = properties, .delivery = IMQUIC_MOQ_USE_SUBGROUP, .end_of_stream = complete }; @@ -3242,7 +3239,7 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ #endif if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_object) moq->conn->socket->callbacks.moq.incoming_object(moq->conn, &object); - g_list_free_full(extensions, (GDestroyNotify)imquic_moq_object_extension_free); + g_list_free_full(properties, (GDestroyNotify)imquic_moq_property_free); /* Move on */ offset += p_len; imquic_buffer_shift(moq_stream->buffer, offset); @@ -3298,10 +3295,10 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str if(length >= blen-offset) return -1; /* Not enough data, try again later */ imquic_moq_fetch_subgroup_type subgroup_type = IMQUIC_MOQ_FETCH_SUBGROUP_ID; - gboolean has_oid = FALSE, has_group = FALSE, has_priority = FALSE, has_ext = FALSE, + gboolean has_oid = FALSE, has_group = FALSE, has_priority = FALSE, has_prop = FALSE, is_datagram = FALSE, end_ne_range = FALSE, end_uk_range = FALSE, violation = FALSE; imquic_moq_parse_fetch_serialization_flags(moq->version, flags, - &subgroup_type, &has_oid, &has_group, &has_priority, &has_ext, &is_datagram, &end_ne_range, &end_uk_range, &violation); + &subgroup_type, &has_oid, &has_group, &has_priority, &has_prop, &is_datagram, &end_ne_range, &end_uk_range, &violation); uint64_t group_id = 0; if(has_group) { group_id = imquic_read_varint(&bytes[offset], blen-offset, &length); @@ -3347,18 +3344,18 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str IMQUIC_MOQ_CHECK_ERR(!moq_stream->got_objects, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, -1, "Serialization flag references non-existing previous object"); priority = moq_stream->last_priority; } - size_t ext_offset = 0, ext_len = 0; - if(has_ext) { - ext_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + size_t prop_offset = 0, prop_len = 0; + if(has_prop) { + prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Extensions Length: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), ext_len); - ext_offset = offset; - if(length == 0 || ext_len >= blen-offset) + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Properties Length: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), prop_len); + prop_offset = offset; + if(length == 0 || prop_len >= blen-offset) return -1; /* Not enough data, try again later */ - offset += ext_len; + offset += prop_len; } uint64_t p_len = imquic_read_varint(&bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) @@ -3371,7 +3368,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str return -1; /* Not enough data, try again later */ /* TODO An invalid object status should be a protocol violation error */ //~ IMQUIC_MOQ_CHECK_ERR(object_status > IMQUIC_MOQ_END_OF_TRACK, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid object status"); - //~ IMQUIC_MOQ_CHECK_ERR(object_status == IMQUIC_MOQ_OBJECT_DOESNT_EXIST && ext_len > 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Extensions received in object with status 'Does Not Exist'"); + //~ IMQUIC_MOQ_CHECK_ERR(object_status == IMQUIC_MOQ_OBJECT_DOESNT_EXIST && prop_len > 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Properties received in object with status 'Does Not Exist'"); offset += length; } if(p_len > blen-offset) @@ -3394,10 +3391,10 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str moq_stream->last_subgroup_id = subgroup_id; moq_stream->last_object_id = object_id; moq_stream->last_priority = priority; - GList *extensions = NULL; - if(ext_offset > 0 && ext_len > 0) { + GList *properties = NULL; + if(prop_offset > 0 && prop_len > 0) { /* TODO Check Protocol Violation cases */ - extensions = imquic_moq_parse_object_extensions(moq->version, &bytes[ext_offset], ext_len); + properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } /* Notify the payload at the application layer */ imquic_moq_object object = { @@ -3410,7 +3407,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str .priority = priority, .payload = bytes + offset, .payload_len = p_len, - .extensions = extensions, + .properties = properties, .delivery = IMQUIC_MOQ_USE_FETCH, .end_of_stream = complete }; @@ -3420,7 +3417,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str #endif if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_object) moq->conn->socket->callbacks.moq.incoming_object(moq->conn, &object); - g_list_free_full(extensions, (GDestroyNotify)imquic_moq_object_extension_free); + g_list_free_full(properties, (GDestroyNotify)imquic_moq_property_free); /* Move on */ offset += p_len; imquic_buffer_shift(moq_stream->buffer, offset); @@ -3698,7 +3695,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t } size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { + imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { if(bytes == NULL || blen < 1 || track_namespace == NULL || track_name == NULL || (track_name->buffer == NULL && track_name->length > 0)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", @@ -3713,11 +3710,11 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); - /* Check if there are extensions to encode */ - uint8_t extensions[256]; - size_t extensions_len = 0; - extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); + /* Check if there are properties to encode */ + uint8_t properties[256]; + size_t properties_len = 0; + properties_len = imquic_moq_build_properties(moq->version, track_properties, properties, sizeof(properties)); + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, properties_len); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -3728,7 +3725,7 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -3817,7 +3814,7 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si } size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { if(bytes == NULL || blen < 1) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_OK, moq->version)); @@ -3829,11 +3826,11 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); - /* Check if there are extensions to encode */ - uint8_t extensions[256]; - size_t extensions_len = 0; - extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); + /* Check if there are properties to encode */ + uint8_t properties[256]; + size_t properties_len = 0; + properties_len = imquic_moq_build_properties(moq->version, track_properties, properties, sizeof(properties)); + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, properties_len); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -3842,7 +3839,7 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -4062,7 +4059,7 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size } size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_extensions) { + uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_properties) { if(bytes == NULL || blen < 1) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_FETCH_OK, moq->version)); @@ -4077,11 +4074,11 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b offset += imquic_write_varint(end_location->object, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); - /* Check if there are extensions to encode */ - uint8_t extensions[256]; - size_t extensions_len = 0; - extensions_len = imquic_moq_build_object_extensions(moq->version, track_extensions, extensions, sizeof(extensions)); - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, extensions_len); + /* Check if there are properties to encode */ + uint8_t properties[256]; + size_t properties_len = 0; + properties_len = imquic_moq_build_properties(moq->version, track_properties, properties, sizeof(properties)); + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, properties_len); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4092,7 +4089,7 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b json_object_set_new(message, "largest_object_id", json_integer(end_location->object)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_qlog_moq_message_add_extensions(message, track_extensions, "track_extensions"); + imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -4161,19 +4158,19 @@ size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t ble size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, uint64_t group_id, uint64_t object_id, uint64_t object_status, uint8_t priority, - uint8_t *payload, size_t plen, uint8_t *extensions, size_t elen) { + uint8_t *payload, size_t plen, uint8_t *properties, size_t prlen) { if(bytes == NULL || blen < 1) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_datagram_message_type_str(IMQUIC_MOQ_OBJECT_DATAGRAM, moq->version)); return 0; } /* TODO Involve EOG */ - gboolean has_ext = (extensions != NULL && elen > 0), is_eog = FALSE; + gboolean has_prop = (properties != NULL && prlen > 0), is_eog = FALSE; gboolean has_oid = (object_id != 0); gboolean has_priority = TRUE; /* FIXME */ imquic_moq_datagram_message_type dtype = imquic_moq_datagram_message_type_return(moq->version, TRUE, /* Payload */ - has_ext, /* Extensions */ + has_prop, /* Properties */ is_eog, /* End of Group */ has_oid, /* Object ID */ has_priority); /* Priority */ @@ -4186,8 +4183,8 @@ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, s bytes[offset] = priority; offset++; } - if(has_ext) - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, elen); + if(has_prop) + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); if(payload != NULL && plen > 0) { memcpy(&bytes[offset], payload, plen); offset += plen; @@ -4197,18 +4194,18 @@ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, s size_t imquic_moq_add_object_datagram_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t track_alias, uint64_t group_id, uint64_t object_id, uint8_t priority, - uint64_t object_status, uint8_t *extensions, size_t elen) { + uint64_t object_status, uint8_t *properties, size_t prlen) { if(bytes == NULL || blen < 1) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_datagram_message_type_str(IMQUIC_MOQ_OBJECT_DATAGRAM_STATUS, moq->version)); return 0; } - gboolean has_ext = (extensions != NULL && elen > 0); + gboolean has_prop = (properties != NULL && prlen > 0); gboolean has_oid = (object_id != 0); gboolean has_priority = TRUE; /* FIXME */ imquic_moq_datagram_message_type dtype = imquic_moq_datagram_message_type_return(moq->version, FALSE, /* Status */ - has_ext, /* Extensions */ + has_prop, /* Properties */ FALSE, /* End of Group */ has_oid, /* Object ID */ has_priority); /* Priority */ @@ -4221,8 +4218,8 @@ size_t imquic_moq_add_object_datagram_status(imquic_moq_context *moq, uint8_t *b bytes[offset] = priority; offset++; } - if(has_ext) - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, elen); + if(has_prop) + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); offset += imquic_write_varint(object_status, &bytes[offset], blen-offset); return offset; } @@ -4251,7 +4248,7 @@ size_t imquic_moq_add_subgroup_header(imquic_moq_context *moq, imquic_moq_stream size_t imquic_moq_add_subgroup_header_object(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t object_id, uint64_t object_status, - uint8_t *payload, size_t plen, uint8_t *extensions, size_t elen) { + uint8_t *payload, size_t plen, uint8_t *properties, size_t prlen) { if(bytes == NULL || blen < 1) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s object: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_data_message_type_str(IMQUIC_MOQ_SUBGROUP_HEADER, moq->version)); @@ -4261,10 +4258,10 @@ size_t imquic_moq_add_subgroup_header_object(imquic_moq_context *moq, imquic_moq offset += imquic_write_varint(object_id, &bytes[offset], blen-offset); /* TODO We can optimize this by only doing it once, when we parse the header */ /* TODO Involve EOG too */ - gboolean has_ext = FALSE; - imquic_moq_data_message_type_to_subgroup_header(moq->version, moq_stream->type, NULL, NULL, &has_ext, NULL, NULL, NULL); - if(has_ext) - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, elen); + gboolean has_prop = FALSE; + imquic_moq_data_message_type_to_subgroup_header(moq->version, moq_stream->type, NULL, NULL, &has_prop, NULL, NULL, NULL); + if(has_prop) + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); if(payload == NULL) plen = 0; offset += imquic_write_varint(plen, &bytes[offset], blen-offset); @@ -4290,7 +4287,7 @@ size_t imquic_moq_add_fetch_header(imquic_moq_context *moq, uint8_t *bytes, size size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t flags, uint64_t group_id, uint64_t subgroup_id, uint64_t object_id, uint8_t priority, - uint64_t object_status, uint8_t *payload, size_t plen, uint8_t *extensions, size_t elen) { + uint64_t object_status, uint8_t *payload, size_t plen, uint8_t *properties, size_t prlen) { if(bytes == NULL || blen < 1) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s object: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_data_message_type_str(IMQUIC_MOQ_FETCH_HEADER, moq->version)); @@ -4298,9 +4295,9 @@ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *byte } size_t offset = 0; imquic_moq_fetch_subgroup_type subgroup_type = IMQUIC_MOQ_FETCH_SUBGROUP_ID; - gboolean has_oid = FALSE, has_group = FALSE, has_priority = FALSE, has_ext = FALSE, is_datagram = FALSE; + gboolean has_oid = FALSE, has_group = FALSE, has_priority = FALSE, has_prop = FALSE, is_datagram = FALSE; imquic_moq_parse_fetch_serialization_flags(moq->version, flags, - &subgroup_type, &has_oid, &has_group, &has_priority, &has_ext, &is_datagram, NULL, NULL, NULL); + &subgroup_type, &has_oid, &has_group, &has_priority, &has_prop, &is_datagram, NULL, NULL, NULL); offset += imquic_write_varint(flags, &bytes[offset], blen-offset); if(has_group) offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); @@ -4312,8 +4309,8 @@ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *byte bytes[offset] = priority; offset++; } - if(has_ext) - offset += imquic_moq_add_object_extensions(moq, &bytes[offset], blen-offset, extensions, elen); + if(has_prop) + offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); if(payload == NULL) plen = 0; offset += imquic_write_varint(plen, &bytes[offset], blen-offset); @@ -4326,22 +4323,22 @@ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *byte return offset; } -size_t imquic_moq_add_object_extensions(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint8_t *extensions, size_t elen) { +size_t imquic_moq_add_properties(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint8_t *properties, size_t prlen) { if(bytes == NULL || blen < 1) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't serialize MoQ object extensions: invalid arguments\n", + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Can't serialize MoQ properties: invalid arguments\n", imquic_get_connection_name(moq->conn)); return 0; } - if(extensions == NULL || elen == 0) { - extensions = NULL; - elen = 0; + if(properties == NULL || prlen == 0) { + properties = NULL; + prlen = 0; } size_t offset = 0; - offset += imquic_write_varint(elen, &bytes[offset], blen-offset); - if(extensions != NULL && elen > 0) { - memcpy(&bytes[offset], extensions, elen); - offset += elen; + offset += imquic_write_varint(prlen, &bytes[offset], blen-offset); + if(properties != NULL && prlen > 0) { + memcpy(&bytes[offset], properties, prlen); + offset += prlen; } return offset; } @@ -4423,27 +4420,27 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si IMQUIC_MOQ_CHECK_ERR(len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); } /* Update the parsed parameter */ - if(type == IMQUIC_MOQ_SETUP_PARAM_PATH) { + if(type == IMQUIC_MOQ_SETUP_OPTION_PATH) { params->path_set = TRUE; if(len > 0) g_snprintf(params->path, sizeof(params->path), "%.*s", (int)len, &bytes[offset]); IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- '%s'\n", imquic_get_connection_name(moq->conn), params->path); - } else if(type == IMQUIC_MOQ_SETUP_PARAM_MAX_REQUEST_ID) { + } else if(type == IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID) { params->max_request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); params->max_request_id_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->max_request_id); len = length; - } else if(type == IMQUIC_MOQ_SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE) { + } else if(type == IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE) { params->max_auth_token_cache_size = imquic_read_varint(&bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); params->max_auth_token_cache_size_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->max_request_id); len = length; - } else if(type == IMQUIC_MOQ_SETUP_PARAM_AUTHORIZATION_TOKEN) { + } else if(type == IMQUIC_MOQ_SETUP_OPTION_AUTHORIZATION_TOKEN) { params->auth_token_set = TRUE; size_t auth_len = len; if(auth_len > sizeof(params->auth_token)) { @@ -4456,13 +4453,13 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si char ai_str[513]; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %s\n", imquic_get_connection_name(moq->conn), imquic_hex_str(&bytes[offset], auth_len, ai_str, sizeof(ai_str))); - } else if(type == IMQUIC_MOQ_SETUP_PARAM_AUTHORITY) { + } else if(type == IMQUIC_MOQ_SETUP_OPTION_AUTHORITY) { params->authority_set = TRUE; if(len > 0) g_snprintf(params->authority, sizeof(params->authority), "%.*s", (int)len, &bytes[offset]); IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- '%s'\n", imquic_get_connection_name(moq->conn), params->authority); - } else if(type == IMQUIC_MOQ_SETUP_PARAM_MOQT_IMPLEMENTATION) { + } else if(type == IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION) { params->moqt_implementation_set = TRUE; if(len > 0) g_snprintf(params->moqt_implementation, sizeof(params->moqt_implementation), "%.*s", (int)len, &bytes[offset]); @@ -4701,64 +4698,64 @@ const char *imquic_moq_get_remote_implementation(imquic_connection *conn) { return implementation; } -/* Object extensions management */ -GList *imquic_moq_parse_object_extensions(imquic_moq_version version, uint8_t *extensions, size_t elen) { - if(extensions == NULL || elen == 0) +/* Propertie management */ +GList *imquic_moq_parse_properties(imquic_moq_version version, uint8_t *properties, size_t prlen) { + if(properties == NULL || prlen == 0) return NULL; - GList *exts = NULL; + GList *props = NULL; size_t offset = 0; uint8_t length = 0; uint64_t last_id = 0; - /* Parse extensions */ - while(elen-offset > 0) { - uint64_t ext_type = imquic_read_varint(&extensions[offset], elen-offset, &length); - if(length == 0 || length >= elen-offset) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken object extensions\n"); - g_list_free_full(exts, (GDestroyNotify)imquic_moq_object_extension_free); + /* Parse properties */ + while(prlen-offset > 0) { + uint64_t prop_type = imquic_read_varint(&properties[offset], prlen-offset, &length); + if(length == 0 || length >= prlen-offset) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken properties\n"); + g_list_free_full(props, (GDestroyNotify)imquic_moq_property_free); return 0; } - ext_type += last_id; - last_id = ext_type; + prop_type += last_id; + last_id = prop_type; offset += length; - if(ext_type % 2 == 0) { + if(prop_type % 2 == 0) { /* Even types are followed by a numeric value */ - uint64_t ext_val = imquic_read_varint(&extensions[offset], elen-offset, &length); - if(length == 0 || length > elen-offset) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken object extensions\n"); - g_list_free_full(exts, (GDestroyNotify)imquic_moq_object_extension_free); + uint64_t prop_val = imquic_read_varint(&properties[offset], prlen-offset, &length); + if(length == 0 || length > prlen-offset) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken properties\n"); + g_list_free_full(props, (GDestroyNotify)imquic_moq_property_free); return 0; } offset += length; - imquic_moq_object_extension *extension = g_malloc0(sizeof(imquic_moq_object_extension)); - extension->id = ext_type; - extension->value.number = ext_val; - exts = g_list_prepend(exts, extension); + imquic_moq_property *property = g_malloc0(sizeof(imquic_moq_property)); + property->id = prop_type; + property->value.number = prop_val; + props = g_list_prepend(props, property); } else { /* Odd typed are followed by a length and a value */ - uint64_t ext_len = imquic_read_varint(&extensions[offset], elen-offset, &length); - if(length == 0 || length >= elen-offset || ext_len >= elen-offset) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken object extensions\n"); - g_list_free_full(exts, (GDestroyNotify)imquic_moq_object_extension_free); + uint64_t prop_len = imquic_read_varint(&properties[offset], prlen-offset, &length); + if(length == 0 || length >= prlen-offset || prop_len >= prlen-offset) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken properties\n"); + g_list_free_full(props, (GDestroyNotify)imquic_moq_property_free); return 0; } /* TODO A length larger than UINT16_MAX should be a protocol violation error */ - //~ IMQUIC_MOQ_CHECK_ERR(ext_len > UINT16_MAX, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Key-Value-Pair length"); + //~ IMQUIC_MOQ_CHECK_ERR(prop_len > UINT16_MAX, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid Key-Value-Pair length"); offset += length; - imquic_moq_object_extension *extension = g_malloc0(sizeof(imquic_moq_object_extension)); - extension->id = ext_type; - if(ext_len > 0) { - extension->value.data.length = ext_len; - extension->value.data.buffer = g_malloc(ext_len); - memcpy(extension->value.data.buffer, &extensions[offset], ext_len); + imquic_moq_property *property = g_malloc0(sizeof(imquic_moq_property)); + property->id = prop_type; + if(prop_len > 0) { + property->value.data.length = prop_len; + property->value.data.buffer = g_malloc(prop_len); + memcpy(property->value.data.buffer, &properties[offset], prop_len); } - exts = g_list_prepend(exts, extension); - offset += ext_len; + props = g_list_prepend(props, property); + offset += prop_len; } } - return g_list_reverse(exts); + return g_list_reverse(props); } -static int imquic_moq_extension_type_sort(imquic_moq_object_extension *a, imquic_moq_object_extension *b) { +static int imquic_moq_property_type_sort(imquic_moq_property *a, imquic_moq_property *b) { if(!a && !b) return 0; else if(!b || a->id < b->id) @@ -4768,26 +4765,26 @@ static int imquic_moq_extension_type_sort(imquic_moq_object_extension *a, imquic return 0; } -size_t imquic_moq_build_object_extensions(imquic_moq_version version, GList *extensions, uint8_t *bytes, size_t blen) { - if(extensions == NULL || bytes == NULL || blen == 0) +size_t imquic_moq_build_properties(imquic_moq_version version, GList *properties, uint8_t *bytes, size_t blen) { + if(properties == NULL || bytes == NULL || blen == 0) return 0; size_t offset = 0; - /* Starting from v16, extensions are encoded with the type delta-encoded, + /* Starting from v16, properties are encoded with the type delta-encoded, * which means we need to sort them all in increasing type order */ - GList *ordered = g_list_sort(g_list_copy(extensions), (GCompareFunc)imquic_moq_extension_type_sort); + GList *ordered = g_list_sort(g_list_copy(properties), (GCompareFunc)imquic_moq_property_type_sort); GList *temp = ordered; uint64_t last_id = 0; while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; - offset += imquic_write_varint((ext->id - last_id), &bytes[offset], blen-offset); - last_id = ext->id; - if(ext->id % 2 == 0) { - offset += imquic_write_varint(ext->value.number, &bytes[offset], blen-offset); + imquic_moq_property *prop = (imquic_moq_property *)temp->data; + offset += imquic_write_varint((prop->id - last_id), &bytes[offset], blen-offset); + last_id = prop->id; + if(prop->id % 2 == 0) { + offset += imquic_write_varint(prop->value.number, &bytes[offset], blen-offset); } else { - offset += imquic_write_varint(ext->value.data.length, &bytes[offset], blen-offset); - if(ext->value.data.length > 0) { - memcpy(&bytes[offset], ext->value.data.buffer, ext->value.data.length); - offset += ext->value.data.length; + offset += imquic_write_varint(prop->value.data.length, &bytes[offset], blen-offset); + if(prop->value.data.length > 0) { + memcpy(&bytes[offset], prop->value.data.buffer, prop->value.data.length); + offset += prop->value.data.length; } } temp = temp->next; @@ -4966,7 +4963,7 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, imquic_moq_namesp } int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_extensions) { + uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0 || @@ -5000,7 +4997,7 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_ size_t blen = sizeof(buffer); size_t sb_len = 0; sb_len = imquic_moq_add_publish(moq, buffer, blen, - request_id, tns, tn, track_alias, parameters, track_extensions); + request_id, tns, tn, track_alias, parameters, track_properties); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ @@ -5110,7 +5107,7 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, } int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, - imquic_moq_request_parameters *parameters, GList *track_extensions) { + imquic_moq_request_parameters *parameters, GList *track_properties) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL) { @@ -5133,7 +5130,7 @@ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, ui uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = imquic_moq_add_subscribe_ok(moq, buffer, blen, - request_id, track_alias, parameters, track_extensions); + request_id, track_alias, parameters, track_properties); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ @@ -5631,7 +5628,7 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 } int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, - imquic_moq_request_parameters *parameters, GList *track_extensions) { + imquic_moq_request_parameters *parameters, GList *track_properties) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL || largest == NULL) { @@ -5650,7 +5647,7 @@ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, imquic request_id, 0, /* TODO End of track */ largest, /* Largest location */ - parameters, track_extensions); + parameters, track_properties); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, f_len, FALSE); /* Done */ @@ -5855,13 +5852,13 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { /* Check if we have data to send */ gboolean has_payload = (object->payload_len > 0 && object->payload != NULL); gboolean valid_pkt = has_payload || (object->object_status != IMQUIC_MOQ_NORMAL_OBJECT); - /* Check if there are extensions to encode */ - uint8_t extensions[256]; - size_t extensions_len = 0; - if(object->extensions != NULL) - extensions_len = imquic_moq_build_object_extensions(moq->version, object->extensions, extensions, sizeof(extensions)); + /* Check if there are properties to encode */ + uint8_t properties[256]; + size_t properties_len = 0; + if(object->properties != NULL) + properties_len = imquic_moq_build_properties(moq->version, object->properties, properties, sizeof(properties)); /* Check how we should send this */ - size_t bufsize = extensions_len + object->payload_len + 100; + size_t bufsize = properties_len + object->payload_len + 100; uint8_t *buffer = g_malloc(bufsize); /* FIXME */ if(object->delivery == IMQUIC_MOQ_USE_DATAGRAM) { /* Use a datagram */ @@ -5869,7 +5866,7 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { size_t dg_len = imquic_moq_add_object_datagram(moq, buffer, bufsize, object->request_id, object->track_alias, object->group_id, object->object_id, object->object_status, object->priority, object->payload, object->payload_len, - extensions, extensions_len); + properties, properties_len); #ifdef HAVE_QLOG if(conn->qlog != NULL && conn->qlog->moq) imquic_moq_qlog_object_datagram_created(conn->qlog, object); @@ -5878,7 +5875,7 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { } else { size_t dg_len = imquic_moq_add_object_datagram_status(moq, buffer, bufsize, object->track_alias, object->group_id, object->object_id, object->priority, - object->object_status, extensions, extensions_len); + object->object_status, properties, properties_len); imquic_connection_send_on_datagram(conn, buffer, dg_len); #ifdef HAVE_QLOG if(conn->qlog != NULL && conn->qlog->moq) @@ -5910,14 +5907,14 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { } /* Create a new stream */ moq_stream = g_malloc0(sizeof(imquic_moq_stream)); - /* TODO Change the type depending on whether extensions/subgroup will be set: + /* TODO Change the type depending on whether properties/subgroup will be set: * since we don't have an API for that, for now we always set the type * that will allow us to dynamically use them all. This also means we * currently don't have a way to specify an End-of-Group flag */ moq_stream->type = imquic_moq_data_message_type_from_subgroup_header(moq->version, TRUE, /* We'll explicitly specify the Subgroup ID */ FALSE, /* Whether the default Subgroup ID is 0 (ignored, since we set it) */ - TRUE, /* We'll add the extensions block, whether there are extensions or not */ + TRUE, /* We'll add the properties block, whether there are properties or not */ TRUE, /* End-of-Group is set */ TRUE); /* We'll add the Publisher Priority property */ moq_stream->priority = 128; /* FIXME */ @@ -5960,7 +5957,7 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { moq_stream->last_object_id = object->object_id; shgo_len = imquic_moq_add_subgroup_header_object(moq, moq_stream, buffer, bufsize, object_id, object->object_status, object->payload, object->payload_len, - extensions, extensions_len); + properties, properties_len); #ifdef HAVE_QLOG if(conn->qlog != NULL && conn->qlog->moq) imquic_moq_qlog_subgroup_object_created(conn->qlog, moq_stream->stream_id, object); @@ -6027,13 +6024,13 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { TRUE, /* We write the Object ID */ TRUE, /* We write the Group ID */ TRUE, /* We write the Priority */ - TRUE, /* We add extensions */ + TRUE, /* We add properties */ FALSE, /* We assume Forwarding Preference is not DATAGRAM */ FALSE, FALSE); /* We don't use the "end of range" flags */ shto_len = imquic_moq_add_fetch_header_object(moq, buffer, bufsize, flags, object->group_id, object->subgroup_id, object->object_id, object->priority, object->object_status, object->payload, object->payload_len, - extensions, extensions_len); + properties, properties_len); #ifdef HAVE_QLOG if(conn->qlog != NULL && conn->qlog->moq) imquic_moq_qlog_fetch_object_created(conn->qlog, moq_stream->stream_id, object); @@ -6357,20 +6354,20 @@ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_ json_object_set_new(message, name, params); } -void imquic_qlog_moq_message_add_extensions(json_t *message, GList *extensions, const char *name) { - if(message == NULL || extensions == NULL || name == NULL) +void imquic_qlog_moq_message_add_properties(json_t *message, GList *properties, const char *name) { + if(message == NULL || properties == NULL || name == NULL) return; json_t *headers = json_array(); - GList *temp = extensions; + GList *temp = properties; while(temp) { - imquic_moq_object_extension *ext = (imquic_moq_object_extension *)temp->data; + imquic_moq_property *prop = (imquic_moq_property *)temp->data; json_t *header = json_object(); - json_object_set_new(header, "header_type", json_integer(ext->id)); - if(ext->id % 2 == 0) { - json_object_set_new(header, "header_value", json_integer(ext->value.number)); + json_object_set_new(header, "type", json_integer(prop->id)); + if(prop->id % 2 == 0) { + json_object_set_new(header, "value", json_integer(prop->value.number)); } else { /* FIXME */ - json_object_set_new(header, "header_length", json_integer(ext->value.data.length)); + json_object_set_new(header, "length", json_integer(prop->value.data.length)); } json_array_append_new(headers, header); temp = temp->next; @@ -6432,7 +6429,7 @@ void imquic_moq_qlog_object_datagram_created(imquic_qlog *qlog, imquic_moq_objec json_object_set_new(data, "group_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); json_object_set_new(data, "publisher_priority", json_integer(object->priority)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); if(object->payload_len > 0) { imquic_qlog_event_add_raw(data, "object_payload", (qlog->moq_objects ? object->payload : NULL), object->payload_len); @@ -6449,7 +6446,7 @@ void imquic_moq_qlog_object_datagram_parsed(imquic_qlog *qlog, imquic_moq_object json_object_set_new(data, "group_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); json_object_set_new(data, "publisher_priority", json_integer(object->priority)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); if(object->payload_len > 0) { imquic_qlog_event_add_raw(data, "object_payload", (qlog->moq_objects ? object->payload : NULL), object->payload_len); @@ -6466,7 +6463,7 @@ void imquic_moq_qlog_object_datagram_status_created(imquic_qlog *qlog, imquic_mo json_object_set_new(data, "group_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); json_object_set_new(data, "publisher_priority", json_integer(object->priority)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); json_object_set_new(data, "object_status", json_integer(object->object_status)); if(object->payload_len > 0) { imquic_qlog_event_add_raw(data, "object_payload", @@ -6484,7 +6481,7 @@ void imquic_moq_qlog_object_datagram_status_parsed(imquic_qlog *qlog, imquic_moq json_object_set_new(data, "group_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); json_object_set_new(data, "publisher_priority", json_integer(object->priority)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); json_object_set_new(data, "object_status", json_integer(object->object_status)); if(object->payload_len > 0) { imquic_qlog_event_add_raw(data, "object_payload", @@ -6537,7 +6534,7 @@ void imquic_moq_qlog_subgroup_object_created(imquic_qlog *qlog, uint64_t stream_ json_object_set_new(data, "subgroup_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); json_object_set_new(data, "publisher_priority", json_integer(object->priority)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); json_object_set_new(data, "object_payload_length", json_integer(object->payload_len)); json_object_set_new(data, "object_status", json_integer(object->object_status)); if(object->payload_len > 0) { @@ -6557,7 +6554,7 @@ void imquic_moq_qlog_subgroup_object_parsed(imquic_qlog *qlog, uint64_t stream_i json_object_set_new(data, "subgroup_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); json_object_set_new(data, "publisher_priority", json_integer(object->priority)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); json_object_set_new(data, "object_payload_length", json_integer(object->payload_len)); json_object_set_new(data, "object_status", json_integer(object->object_status)); if(object->payload_len > 0) { @@ -6602,7 +6599,7 @@ void imquic_moq_qlog_fetch_object_created(imquic_qlog *qlog, uint64_t stream_id, json_object_set_new(data, "group_id", json_integer(object->group_id)); json_object_set_new(data, "subgroup_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); json_object_set_new(data, "object_payload_length", json_integer(object->payload_len)); json_object_set_new(data, "object_status", json_integer(object->object_status)); if(object->payload_len > 0) { @@ -6621,7 +6618,7 @@ void imquic_moq_qlog_fetch_object_parsed(imquic_qlog *qlog, uint64_t stream_id, json_object_set_new(data, "group_id", json_integer(object->group_id)); json_object_set_new(data, "subgroup_id", json_integer(object->group_id)); json_object_set_new(data, "object_id", json_integer(object->object_id)); - imquic_qlog_moq_message_add_extensions(data, object->extensions, "extension_headers"); + imquic_qlog_moq_message_add_properties(data, object->properties, "properties"); json_object_set_new(data, "object_payload_length", json_integer(object->payload_len)); json_object_set_new(data, "object_status", json_integer(object->object_status)); if(object->payload_len > 0) { From 72ba0236ffc206c926f8d71cef9eda37e9562248 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 4 Mar 2026 16:54:58 +0100 Subject: [PATCH 07/30] Added timeout to GOAWAY --- examples/moq-pub.c | 5 +++-- examples/moq-sub.c | 5 +++-- src/imquic-moq.c | 2 +- src/imquic/moq.h | 5 +++-- src/internal/moq.h | 5 +++-- src/moq.c | 20 ++++++++++++++++---- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/moq-pub.c b/examples/moq-pub.c index f97951c..266e5c7 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -256,9 +256,10 @@ static void imquic_demo_incoming_unsubscribe(imquic_connection *conn, uint64_t r g_atomic_int_set(&send_objects, 0); } -static void imquic_demo_incoming_go_away(imquic_connection *conn, const char *uri) { +static void imquic_demo_incoming_go_away(imquic_connection *conn, const char *uri, uint64_t timeout) { /* Connection was closed */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got a GOAWAY: %s\n", imquic_get_connection_name(conn), uri); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got a GOAWAY: %s (timeout=%"SCNu64"ms)\n", + imquic_get_connection_name(conn), uri, timeout); /* Stop here */ g_atomic_int_inc(&stop); } diff --git a/examples/moq-sub.c b/examples/moq-sub.c index 2bf2571..12ef15a 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -636,9 +636,10 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje } } -static void imquic_demo_incoming_go_away(imquic_connection *conn, const char *uri) { +static void imquic_demo_incoming_go_away(imquic_connection *conn, const char *uri, uint64_t timeout) { /* Connection was closed */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got a GOAWAY: %s\n", imquic_get_connection_name(conn), uri); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Got a GOAWAY: %s (timeout=%"SCNu64"ms)\n", + imquic_get_connection_name(conn), uri, timeout); /* Stop here */ g_atomic_int_inc(&stop); } diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 39c02ec..32a8283 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -776,7 +776,7 @@ void imquic_set_incoming_object_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_goaway_cb(imquic_endpoint *endpoint, - void (* incoming_goaway)(imquic_connection *conn, const char *uri)) { + void (* incoming_goaway)(imquic_connection *conn, const char *uri, uint64_t timeout)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 9cac788..fdd0994 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -1023,7 +1023,7 @@ void imquic_set_incoming_object_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_goaway Pointer to the function that will handle the incoming \c GOAWAY */ void imquic_set_incoming_goaway_cb(imquic_endpoint *endpoint, - void (* incoming_goaway)(imquic_connection *conn, const char *uri)); + void (* incoming_goaway)(imquic_connection *conn, const char *uri, uint64_t timeout)); /*! \brief Configure the callback function to be notified when an existing * MoQ connection handled by this endpoint has been closed/shut down. * @note This is a good place to release the last reference to the connection @@ -1357,8 +1357,9 @@ int imquic_moq_requests_blocked(imquic_connection *conn); /*! \brief Function to send a \c GOAWAY request * @param conn The imquic_connection to send the request on * @param uri Where the client can connect to continue the session + * @param timeout Timeout in ms to add to the request (added in v17, ignored for older versions) * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_goaway(imquic_connection *conn, const char *uri); +int imquic_moq_goaway(imquic_connection *conn, const char *uri, uint64_t timeout); ///@} #endif diff --git a/src/internal/moq.h b/src/internal/moq.h index 9454abc..cbaede1 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -1043,8 +1043,9 @@ size_t imquic_moq_add_track_status_error(imquic_moq_context *moq, uint8_t *bytes * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param new_session_uri New uri value to put in the message, if any + * @param timeout Timeout to put in the message (added in v17, ignored for older versions) * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t blen, const char *new_session_uri); +size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t blen, const char *new_session_uri, uint64_t timeout); /*! \brief Helper to add an \c OBJECT_DATAGRAM message to a buffer * @note This assumes the connection negotiated \c DATAGRAM support * @param moq The imquic_moq_context generating the message @@ -1302,7 +1303,7 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming MoQ objects */ void (* incoming_object)(imquic_connection *conn, imquic_moq_object *object); /*! \brief Callback function to be notified about incoming \c GOAWAY messages */ - void (* incoming_goaway)(imquic_connection *conn, const char *uri); + void (* incoming_goaway)(imquic_connection *conn, const char *uri, uint64_t timeout); /*! \brief Callback function to be notified about MoQ connections being closed */ void (* connection_gone)(imquic_connection *conn); } imquic_moq_callbacks; diff --git a/src/moq.c b/src/moq.c index d2550a9..f77c827 100644 --- a/src/moq.c +++ b/src/moq.c @@ -3452,10 +3452,18 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b } } offset += uri_len; + uint64_t timeout = 0; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + timeout = imquic_read_varint(&bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken GOAWAY"); + offset += length; + } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("goaway"); imquic_qlog_event_add_raw(message, "new_session_uri", (uint8_t *)uri_str, uri_len); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "timeout", json_integer(timeout)); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); } #endif @@ -3463,7 +3471,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Multiple GOAWAY messages received"); /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_goaway) - moq->conn->socket->callbacks.moq.incoming_goaway(moq->conn, uri_str); + moq->conn->socket->callbacks.moq.incoming_goaway(moq->conn, uri_str, timeout); if(error) *error = 0; return offset; @@ -4126,7 +4134,7 @@ size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size return offset; } -size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t blen, const char *new_session_uri) { +size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t blen, const char *new_session_uri, uint64_t timeout) { if(bytes == NULL || blen < 1 || (new_session_uri && strlen(new_session_uri) > 8192)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_GOAWAY, moq->version)); @@ -4145,11 +4153,15 @@ size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t ble memcpy(&bytes[offset], new_session_uri, uri_len); offset += uri_len; } + if(moq->version >= IMQUIC_MOQ_VERSION_17) + offset += imquic_write_varint(timeout, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("goaway"); imquic_qlog_event_add_raw(message, "new_session_uri", (uint8_t *)new_session_uri, uri_len); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "timeout", json_integer(timeout)); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -5812,7 +5824,7 @@ int imquic_moq_requests_blocked(imquic_connection *conn) { return 0; } -int imquic_moq_goaway(imquic_connection *conn, const char *uri) { +int imquic_moq_goaway(imquic_connection *conn, const char *uri, uint64_t timeout) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL) { @@ -5825,7 +5837,7 @@ int imquic_moq_goaway(imquic_connection *conn, const char *uri) { imquic_mutex_unlock(&moq_mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t g_len = imquic_moq_add_goaway(moq, buffer, blen, uri); + size_t g_len = imquic_moq_add_goaway(moq, buffer, blen, uri, timeout); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, g_len, FALSE); /* Done */ From ed56138e3775cdfdb0d26439b69a50e40a2a0a2b Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 4 Mar 2026 17:10:29 +0100 Subject: [PATCH 08/30] Added new error codes --- src/imquic/moq.h | 8 +++++++- src/moq.c | 42 +++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/imquic/moq.h b/src/imquic/moq.h index fdd0994..f4ea8df 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -671,6 +671,8 @@ typedef enum imquic_moq_request_error_code { IMQUIC_MOQ_REQERR_NOT_SUPPORTED = 0x3, IMQUIC_MOQ_REQERR_MALFORMED_AUTH_TOKEN = 0x4, IMQUIC_MOQ_REQERR_EXPIRED_AUTH_TOKEN = 0x5, + IMQUIC_MOQ_REQERR_GOING_AWAY = 0x6, + IMQUIC_MOQ_REQERR_EXCESSIVE_LOAD = 0x9, /* The following are returned by publishers */ IMQUIC_MOQ_REQERR_DOES_NOT_EXIST = 0x10, IMQUIC_MOQ_REQERR_INVALID_RANGE = 0x11, @@ -680,6 +682,7 @@ typedef enum imquic_moq_request_error_code { IMQUIC_MOQ_REQERR_UNINTERESTED = 0x20, /* Others */ IMQUIC_MOQ_REQERR_PREFIX_OVERLAP = 0x30, + IMQUIC_MOQ_REQERR_NAMESPACE_TOO_LARGE = 0x31, IMQUIC_MOQ_REQERR_INVALID_JOINING_REQUEST_ID = 0x32, } imquic_moq_request_error_code; /*! \brief Helper function to serialize to string the name of a imquic_moq_request_error_code value. @@ -696,8 +699,9 @@ typedef enum imquic_moq_pub_done_code { IMQUIC_MOQ_PUBDONE_GOING_AWAY = 0x4, IMQUIC_MOQ_PUBDONE_EXPIRED = 0x5, IMQUIC_MOQ_PUBDONE_TOO_FAR_BEHIND = 0x6, - IMQUIC_MOQ_PUBDONE_MALFORMED_TRACK = 0x12, IMQUIC_MOQ_PUBDONE_UPDATE_FAILED = 0x8, + IMQUIC_MOQ_PUBDONE_EXCESSIVE_LOAD = 0x9, + IMQUIC_MOQ_PUBDONE_MALFORMED_TRACK = 0x12, } imquic_moq_pub_done_code; /*! \brief Helper function to serialize to string the name of a imquic_moq_pub_done_code value. * @param code The imquic_moq_pub_done_code value @@ -711,6 +715,8 @@ typedef enum imquic_moq_reset_stream_code { IMQUIC_MOQ_RESET_DELIVERY_TIMEOUT = 0x2, IMQUIC_MOQ_RESET_SESSION_CLOSED = 0x3, IMQUIC_MOQ_RESET_UNKNOWN_OBJECT_STATUS = 0x4, + IMQUIC_MOQ_RESET_TOO_FAR_BEHIND = 0x5, + IMQUIC_MOQ_RESET_EXCESSIVE_LOAD = 0x9, IMQUIC_MOQ_RESET_MALFORMED_TRACK = 0x12, } imquic_moq_reset_stream_code; /*! \brief Helper function to serialize to string the name of a imquic_moq_reset_stream_code value. diff --git a/src/moq.c b/src/moq.c index f77c827..d22a60e 100644 --- a/src/moq.c +++ b/src/moq.c @@ -370,31 +370,37 @@ const char *imquic_moq_error_code_str(imquic_moq_error_code code) { const char *imquic_moq_request_error_code_str(imquic_moq_request_error_code code) { switch(code) { case IMQUIC_MOQ_REQERR_INTERNAL_ERROR: - return "INTERNAL_ERROR"; + return "Internal Error"; case IMQUIC_MOQ_REQERR_UNAUTHORIZED: - return "UNAUTHORIZED"; + return "Unauthorized"; case IMQUIC_MOQ_REQERR_TIMEOUT: - return "TIMEOUT"; + return "Timeout"; case IMQUIC_MOQ_REQERR_NOT_SUPPORTED: - return "NOT_SUPPORTED"; + return "Not Suppoered"; case IMQUIC_MOQ_REQERR_MALFORMED_AUTH_TOKEN: - return "MALFORMED_AUTH_TOKEN"; + return "Malformed Auth Token"; case IMQUIC_MOQ_REQERR_EXPIRED_AUTH_TOKEN: - return "EXPIRED_AUTH_TOKEN"; + return "Expired Auth Token"; + case IMQUIC_MOQ_REQERR_GOING_AWAY: + return "Going Away"; + case IMQUIC_MOQ_REQERR_EXCESSIVE_LOAD: + return "Excessive Load"; case IMQUIC_MOQ_REQERR_DOES_NOT_EXIST: - return "DOES_NOT_EXIST"; + return "Does Not Exist"; case IMQUIC_MOQ_REQERR_INVALID_RANGE: - return "INVALID_RANGE"; + return "Invalid Range"; case IMQUIC_MOQ_REQERR_MALFORMED_TRACK: - return "MALFORMED_TRACK"; + return "Malformed Track"; case IMQUIC_MOQ_REQERR_DUPLICATE_SUBSCRIPTION: - return "DUPLICATE_SUBSCRIPTION"; + return "Duplicate Subscription"; case IMQUIC_MOQ_REQERR_UNINTERESTED: - return "UNINTERESTED"; + return "Uninterested"; case IMQUIC_MOQ_REQERR_PREFIX_OVERLAP: - return "PREFIX_OVERLAP"; + return "Prefix Overlap"; + case IMQUIC_MOQ_REQERR_NAMESPACE_TOO_LARGE: + return "Namespace Too Large"; case IMQUIC_MOQ_REQERR_INVALID_JOINING_REQUEST_ID: - return "INVALID_JOINING_REQUEST_ID"; + return "Invalid Joining Request ID"; default: break; } return NULL; @@ -416,10 +422,12 @@ const char *imquic_moq_pub_done_code_str(imquic_moq_pub_done_code code) { return "Expired"; case IMQUIC_MOQ_PUBDONE_TOO_FAR_BEHIND: return "Too Far Behind"; - case IMQUIC_MOQ_PUBDONE_MALFORMED_TRACK: - return "Malformed Track"; case IMQUIC_MOQ_PUBDONE_UPDATE_FAILED: return "Update Failed"; + case IMQUIC_MOQ_PUBDONE_EXCESSIVE_LOAD: + return "Excessive Load"; + case IMQUIC_MOQ_PUBDONE_MALFORMED_TRACK: + return "Malformed Track"; default: break; } return NULL; @@ -437,6 +445,10 @@ const char *imquic_moq_reset_stream_code_str(imquic_moq_reset_stream_code code) return "Session Closed"; case IMQUIC_MOQ_RESET_UNKNOWN_OBJECT_STATUS: return "Unknown Object Status"; + case IMQUIC_MOQ_RESET_TOO_FAR_BEHIND: + return "Too Far Behind"; + case IMQUIC_MOQ_RESET_EXCESSIVE_LOAD: + return "Excessive Load"; case IMQUIC_MOQ_RESET_MALFORMED_TRACK: return "Malformed Track"; default: break; From e5558fe33e9739a47a9a7733484ab365cdc83211 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 4 Mar 2026 17:20:05 +0100 Subject: [PATCH 09/30] Added new error code --- src/imquic/moq.h | 3 ++- src/moq.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/imquic/moq.h b/src/imquic/moq.h index f4ea8df..1e1e60e 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -641,7 +641,8 @@ typedef enum imquic_moq_error_code { IMQUIC_MOQ_INVALID_REQUEST_ID = 0x4, IMQUIC_MOQ_DUPLICATE_TRACK_ALIAS = 0x5, IMQUIC_MOQ_KEYVALUE_FORMATTING_ERROR = 0x6, - IMQUIC_MOQ_TOO_MANY_REQUESTS = 0x7, + IMQUIC_MOQ_INVALID_REQUIRED_REQUEST_ID = 0x7, + IMQUIC_MOQ_TOO_MANY_REQUESTS = 0x7, /* Deprecated in v17 */ IMQUIC_MOQ_INVALID_PATH = 0x8, IMQUIC_MOQ_MALFORMED_PATH = 0x9, IMQUIC_MOQ_GOAWAY_TIMEOUT = 0x10, diff --git a/src/moq.c b/src/moq.c index d22a60e..9556f1a 100644 --- a/src/moq.c +++ b/src/moq.c @@ -332,8 +332,8 @@ const char *imquic_moq_error_code_str(imquic_moq_error_code code) { return "Duplicate Track Alias"; case IMQUIC_MOQ_KEYVALUE_FORMATTING_ERROR: return "Key-Value Formatting Error"; - case IMQUIC_MOQ_TOO_MANY_REQUESTS: - return "Too Many Requests"; + case IMQUIC_MOQ_INVALID_REQUIRED_REQUEST_ID: + return "Invalid Required Request ID"; case IMQUIC_MOQ_INVALID_PATH: return "Invalid Path"; case IMQUIC_MOQ_MALFORMED_PATH: From b509991a076262d209cab633f1fa26765259456f Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 4 Mar 2026 18:16:35 +0100 Subject: [PATCH 10/30] Use the right varint implementation depending on the negotiated version --- examples/moq-utils.c | 4 +- src/imquic/moq.h | 52 +++--- src/internal/moq.h | 2 +- src/moq.c | 414 ++++++++++++++++++++++--------------------- 4 files changed, 239 insertions(+), 233 deletions(-) diff --git a/examples/moq-utils.c b/examples/moq-utils.c index 7874a1c..c015275 100644 --- a/examples/moq-utils.c +++ b/examples/moq-utils.c @@ -98,7 +98,7 @@ int imquic_moq_auth_info_to_bytes(imquic_connection *conn, const char *auth_info token.token_type = 0; /* FIXME */ token.token_value.buffer = (uint8_t *)auth_info; token.token_value.length = strlen(auth_info); - size_t offset = imquic_moq_build_auth_token(&token, auth, *authlen); + size_t offset = imquic_moq_build_auth_token(imquic_moq_get_version(conn), &token, auth, *authlen); if(offset == 0) return -1; *authlen = offset; @@ -125,7 +125,7 @@ gboolean imquic_moq_check_auth_info(imquic_connection *conn, const char *auth_in auth_str[0] = '\0'; /* Unpack the token */ imquic_moq_auth_token token = { 0 }; - if(imquic_moq_parse_auth_token(auth, authlen, &token) < 0) + if(imquic_moq_parse_auth_token(imquic_moq_get_version(conn), auth, authlen, &token) < 0) return FALSE; if(token.alias_type != IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE) { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] This demo currently only supports %s as an auth token alias type, ignoring %s\n", diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 1e1e60e..30072e2 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -300,6 +300,29 @@ /** @name MoQ resources */ ///@{ +/*! \brief Versions that can be negotiated */ +typedef enum imquic_moq_version { + /* Base */ + IMQUIC_MOQ_VERSION_BASE = 0xff000000, + /* Draft version -16 */ + IMQUIC_MOQ_VERSION_MIN = 0xff000010, + IMQUIC_MOQ_VERSION_16 = 0xff000010, + /* Draft version -17 */ + IMQUIC_MOQ_VERSION_17 = 0xff000011, + IMQUIC_MOQ_VERSION_MAX = IMQUIC_MOQ_VERSION_17, + /* Any version starting from v15: for client, it means offer all supported versions; + * for servers, it means accept the first supported offered version */ + IMQUIC_MOQ_VERSION_ANY = 0xff0000ff, +} imquic_moq_version; +/*! \brief Helper function to serialize to string the name of a imquic_moq_version property. + * @param version The imquic_moq_version property + * @returns The version name as a string, if valid, or NULL otherwise */ +const char *imquic_moq_version_str(imquic_moq_version version); +/*! \brief Helper function to get the MoQ version associated with a connection. + * @param conn The imquic_connection to query + * @returns The imquic_moq_version value */ +imquic_moq_version imquic_moq_get_version(imquic_connection *conn); + /*! \brief MoQ Track Namespace */ typedef struct imquic_moq_namespace { /*! \brief Namespace data (typically a non-null terminated string) */ @@ -617,17 +640,19 @@ typedef struct imquic_moq_auth_token { * @note The buffer in the \c value property will point to data in the original \c bytes buffer, * which means that no allocation will be performed by this method. If you need to store the * token value somewhere, it's up to you to copy it before \c bytes is invalidated by the application + * @param[in] version The MoQ version used on the connection * @param[in] bytes The buffer containing the auth token data * @param[in] blen The size of the buffer containing the auth token data data * @param[out] token The imquic_moq_auth_token to put the parsed token info to * @returns 0 in case of success, or a negative integer otherwise */ -int imquic_moq_parse_auth_token(uint8_t *bytes, size_t blen, imquic_moq_auth_token *token); +int imquic_moq_parse_auth_token(imquic_moq_version version, uint8_t *bytes, size_t blen, imquic_moq_auth_token *token); /*! \brief Helper mode to craft an auth token buffer out of a imquic_moq_auth_token instance + * @param[in] version The MoQ version used on the connection * @param[in] token The imquic_moq_auth_token instance to serialize * @param[out] bytes The buffer to write the auth token to * @param[in] blen The size of the buffer to write to * @returns How many bytes were written, if successful */ -size_t imquic_moq_build_auth_token(imquic_moq_auth_token *token, uint8_t *bytes, size_t blen); +size_t imquic_moq_build_auth_token(imquic_moq_version version, imquic_moq_auth_token *token, uint8_t *bytes, size_t blen); /** @name MoQ error and status codes */ @@ -1040,29 +1065,6 @@ void imquic_set_moq_connection_gone_cb(imquic_endpoint *endpoint, void (* moq_connection_gone)(imquic_connection *conn)); ///@} -/*! \brief Versions that can be negotiated */ -typedef enum imquic_moq_version { - /* Base */ - IMQUIC_MOQ_VERSION_BASE = 0xff000000, - /* Draft version -16 */ - IMQUIC_MOQ_VERSION_MIN = 0xff000010, - IMQUIC_MOQ_VERSION_16 = 0xff000010, - /* Draft version -17 */ - IMQUIC_MOQ_VERSION_17 = 0xff000011, - IMQUIC_MOQ_VERSION_MAX = IMQUIC_MOQ_VERSION_17, - /* Any version starting from v15: for client, it means offer all supported versions; - * for servers, it means accept the first supported offered version */ - IMQUIC_MOQ_VERSION_ANY = 0xff0000ff, -} imquic_moq_version; -/*! \brief Helper function to serialize to string the name of a imquic_moq_version property. - * @param version The imquic_moq_version property - * @returns The version name as a string, if valid, or NULL otherwise */ -const char *imquic_moq_version_str(imquic_moq_version version); -/*! \brief Helper function to get the MoQ version associated with a connection. - * @param conn The imquic_connection to query - * @returns The imquic_moq_version value */ -imquic_moq_version imquic_moq_get_version(imquic_connection *conn); - /*! \brief Method to provide credentials, as a client, on a new connection. * If credentials need to provided, this must be done as soon as the * connection is established, and before sending any MoQ message. diff --git a/src/internal/moq.h b/src/internal/moq.h index cbaede1..721d0e8 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -1201,7 +1201,7 @@ size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, si uint64_t param, uint64_t prev, uint8_t *buf, size_t buflen); /*! \brief Helper to serialize a imquic_moq_setup_options set to a buffer * @param[in] moq The imquic_moq_context instance the parameter is for - * @param[in] parameters The imquic_moq_setup_options to serialize + * @param[in] options The imquic_moq_setup_options to serialize * @param[out] bytes The buffer to add paramerers to * @param[in] blen The size of the buffer * @param[out] params_num The number of parameters added to the buffer diff --git a/src/moq.c b/src/moq.c index 9556f1a..1b5f515 100644 --- a/src/moq.c +++ b/src/moq.c @@ -36,8 +36,8 @@ static GHashTable *moq_sessions = NULL; static imquic_mutex moq_mutex = IMQUIC_MUTEX_INITIALIZER; /* MoQ's flavour of varint (introduced in v17) */ -uint64_t imquic_read_moqint(uint8_t *bytes, size_t blen, uint8_t *length); -uint8_t imquic_write_moqint(uint64_t number, uint8_t *bytes, size_t blen); +uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length); +uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen); /* Initialization */ static void imquic_moq_context_destroy(imquic_moq_context *moq); @@ -884,7 +884,7 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, size_t offset = 0; if(options == NULL) { /* No options */ - offset += imquic_write_varint(0, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, 0, &bytes[offset], blen-offset); } else { uint64_t new_id = 0, last_id = 0; GList *list = NULL; @@ -901,7 +901,7 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, if(options->moqt_implementation_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION)); *params_num = g_list_length(list); - offset += imquic_write_varint(*params_num, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, *params_num, &bytes[offset], blen-offset); if(list != NULL) { list = g_list_sort(list, imquic_moq_compare_types); GList *temp = list; @@ -958,7 +958,7 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, size_t offset = 0; if(parameters == NULL) { /* No parameters */ - offset += imquic_write_varint(0, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, 0, &bytes[offset], blen-offset); } else { uint64_t new_id = 0, last_id = 0; GList *list = NULL; @@ -981,7 +981,7 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, if(parameters->new_group_request_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST)); *params_num = g_list_length(list); - offset += imquic_write_varint(*params_num, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, *params_num, &bytes[offset], blen-offset); if(list != NULL) { list = g_list_sort(list, imquic_moq_compare_types); GList *temp = list; @@ -1006,14 +1006,14 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER) { uint8_t temp[40]; size_t tlen = sizeof(temp); - size_t toffset = imquic_write_varint(parameters->subscription_filter.type, temp, tlen); + size_t toffset = imquic_write_moqint(moq->version, parameters->subscription_filter.type, temp, tlen); if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - toffset += imquic_write_varint(parameters->subscription_filter.start_location.group, &temp[toffset], tlen-toffset); - toffset += imquic_write_varint(parameters->subscription_filter.start_location.object, &temp[toffset], tlen-toffset); + toffset += imquic_write_moqint(moq->version, parameters->subscription_filter.start_location.group, &temp[toffset], tlen-toffset); + toffset += imquic_write_moqint(moq->version, parameters->subscription_filter.start_location.object, &temp[toffset], tlen-toffset); } if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - toffset += imquic_write_varint(parameters->subscription_filter.end_group, &temp[toffset], tlen-toffset); + toffset += imquic_write_moqint(moq->version, parameters->subscription_filter.end_group, &temp[toffset], tlen-toffset); offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, temp, toffset); @@ -1024,8 +1024,8 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT) { uint8_t temp[40]; size_t tlen = sizeof(temp); - size_t toffset = imquic_write_varint(parameters->largest_object.group, temp, tlen); - toffset += imquic_write_varint(parameters->largest_object.object, &temp[toffset], tlen-toffset); + size_t toffset = imquic_write_moqint(moq->version, parameters->largest_object.group, temp, tlen); + toffset += imquic_write_moqint(moq->version, parameters->largest_object.object, &temp[toffset], tlen-toffset); offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, temp, toffset); @@ -1085,7 +1085,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { #define IMQUIC_MOQ_PARSE_NAMESPACES(request, tns_num, i, error_message, last) \ do { \ - tns_num = imquic_read_varint(&bytes[offset], blen-offset, &length); \ + tns_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); \ IMQUIC_MOQ_CHECK_ERR(length == 0 || (tns_num > 0 && length >= blen-offset), NULL, 0, 0, error_message); \ IMQUIC_MOQ_CHECK_ERR((tns_num == 0 && request != IMQUIC_MOQ_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE_DONE) || tns_num > 32, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid number of namespaces"); \ offset += length; \ @@ -1093,7 +1093,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { i = 0; \ for(i = 0; i < tns_num; i++) { \ IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, error_message); \ - uint64_t tns_len = imquic_read_varint(&bytes[offset], blen-offset, &length); \ + uint64_t tns_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); \ IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, error_message); \ IMQUIC_MOQ_CHECK_ERR(tns_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid track namespace field length"); \ offset += length; \ @@ -1117,7 +1117,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { #define IMQUIC_MOQ_PARSE_TRACKNAME(error_message, last) \ do { \ - uint64_t tn_len = imquic_read_varint(&bytes[offset], blen-offset, &length); \ + uint64_t tn_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); \ if(last) { \ IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, error_message); \ } else { \ @@ -1153,10 +1153,10 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(request, moq->version)); \ return 0; \ } \ - offset += imquic_write_varint(tns_num, &bytes[offset], blen-offset); \ + offset += imquic_write_moqint(moq->version, tns_num, &bytes[offset], blen-offset); \ temp = track_namespace; \ while(temp) { \ - offset += imquic_write_varint(temp->length, &bytes[offset], blen-offset); \ + offset += imquic_write_moqint(moq->version, temp->length, &bytes[offset], blen-offset); \ if(temp->length > 0) { \ memcpy(&bytes[offset], temp->buffer, temp->length); \ offset += temp->length; \ @@ -1172,7 +1172,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(request, moq->version)); \ return 0; \ } \ - offset += imquic_write_varint(track_name->length, &bytes[offset], blen-offset); \ + offset += imquic_write_moqint(moq->version, track_name->length, &bytes[offset], blen-offset); \ if(track_name->length > 0) { \ memcpy(&bytes[offset], track_name->buffer, track_name->length); \ offset += track_name->length; \ @@ -1181,7 +1181,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { #define IMQUIC_MOQ_ADD_MESSAGE_TYPE(type) \ do { \ - offset = imquic_write_varint(type, bytes, blen); \ + offset = imquic_write_moqint(moq->version, type, bytes, blen); \ len_offset = offset; \ offset += 2; \ } while(0) @@ -1199,7 +1199,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ uint8_t tlen = 0, error = 0; /* If this is a datagram, it can only be OBJECT_DATAGRAM or OBJECT_DATAGRAM_STATUS */ if(datagram) { - imquic_moq_datagram_message_type dtype = imquic_read_varint(&bytes[offset], blen-offset, &tlen); + imquic_moq_datagram_message_type dtype = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &tlen); offset += tlen; gboolean valid = FALSE, payload = FALSE, violation = FALSE; valid = imquic_moq_is_datagram_message_type_valid(moq->version, dtype); @@ -1238,7 +1238,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ /* Iterate on all frames */ while((moq_stream == NULL || moq_stream->subscribe_namespace) && blen-offset > 0) { /* If we're here, we're either on the control stream, or on a media stream waiting to know what it will be like */ - imquic_moq_message_type type = imquic_read_varint(&bytes[offset], blen-offset, &tlen); + imquic_moq_message_type type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &tlen); IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ][%zu] >> %s (%02x, %u)\n", imquic_get_connection_name(moq->conn), offset, imquic_moq_message_type_str(type, moq->version), type, tlen); if(stream_id != moq->control_stream_id && moq_stream == NULL) { @@ -1575,7 +1575,7 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si } size_t offset = 0; uint8_t length = 0; - uint64_t opts_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t opts_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(opts_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); IMQUIC_MOQ_CHECK_ERR(opts_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken CLIENT_SETUP"); offset += length; @@ -1668,7 +1668,7 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - uint64_t opts_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t opts_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(opts_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); IMQUIC_MOQ_CHECK_ERR(opts_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SERVER_SETUP"); offset += length; @@ -1733,7 +1733,7 @@ size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, return 0; size_t offset = 0; uint8_t length = 0; - uint64_t max = imquic_read_varint(&bytes[offset], blen-offset, &length) + 1; + uint64_t max = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length) + 1; IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken MAX_REQUEST_ID"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Maximum Request ID %"SCNu64":\n", @@ -1760,7 +1760,7 @@ size_t imquic_moq_parse_requests_blocked(imquic_moq_context *moq, uint8_t *bytes return 0; size_t offset = 0; uint8_t length = 0; - uint64_t max = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t max = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUESTS_BLOCKED"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Maximum Request ID %"SCNu64":\n", @@ -1790,12 +1790,12 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK for SUBSCRIBE_NAMESPACE"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken REQUEST_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken REQUEST_OK"); offset += length; @@ -1860,22 +1860,22 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR for SUBSCRIBE_NAMESPACE"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t error_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_error_code_str(error_code), error_code); - uint64_t retry_interval = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t retry_interval = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Retry Interval: %"SCNu64"\n", imquic_get_connection_name(moq->conn), retry_interval); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t rs_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); offset += length; char reason[1024], *reason_str = NULL; @@ -1954,7 +1954,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *byte return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -1963,7 +1963,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *byte memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE, tns_num, i, "Broken PUBLISH_NAMESPACE", FALSE); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); offset += length; @@ -2040,12 +2040,12 @@ size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_ char reason[1024], *reason_str = NULL; uint64_t tns_num = 0, i = 0; IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE, tns_num, i, "Broken PUBLISH_NAMESPACE_CANCEL", FALSE); - error_code = imquic_read_varint(&bytes[offset], blen-offset, &length); + error_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_CANCEL"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_error_code_str(error_code), error_code); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t rs_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_CANCEL"); offset += length; if(rs_len > 0) { @@ -2085,7 +2085,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2096,14 +2096,14 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_PUBLISH, tns_num, i, "Broken PUBLISH", FALSE); imquic_moq_name tn = { 0 }; IMQUIC_MOQ_PARSE_TRACKNAME("Broken PUBLISH", FALSE); - uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t track_alias = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", imquic_get_connection_name(moq->conn), track_alias); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken PUBLISH"); offset += length; @@ -2116,7 +2116,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken PUBLISH"); } size_t prop_offset = 0, prop_len = 0; - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || (prop_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken PUBLISH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Properties Length: %"SCNu64"\n", @@ -2166,14 +2166,14 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken PUBLISH_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken PUBLISH_OK"); offset += length; @@ -2209,7 +2209,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2223,7 +2223,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ IMQUIC_MOQ_PARSE_TRACKNAME("Broken SUBSCRIBE", FALSE); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SUBSCRIBE"); offset += length; @@ -2274,19 +2274,19 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t sub_request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t sub_request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Subscription Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), sub_request_id); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken REQUEST_UPDATE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken REQUEST_UPDATE"); offset += length; @@ -2330,19 +2330,19 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t track_alias = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", imquic_get_connection_name(moq->conn), track_alias); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); offset += length; @@ -2355,7 +2355,7 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken SUBSCRIBE_OK"); } size_t prop_offset = 0, prop_len = 0; - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || (prop_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Properties Length: %"SCNu64"\n", @@ -2397,7 +2397,7 @@ size_t imquic_moq_parse_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, siz return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken UNSUBSCRIBE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2432,22 +2432,22 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_DONE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t status_code = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t status_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_DONE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Status Code: %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_pub_done_code_str(status_code), status_code); - uint64_t streams_count = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t streams_count = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_DONE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Streams Count: %"SCNu64"\n", imquic_get_connection_name(moq->conn), streams_count); - uint64_t rs_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t rs_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH_DONE"); offset += length; char reason[1024], *reason_str = NULL; @@ -2494,7 +2494,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_NAMESPACE"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2503,10 +2503,10 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE, tns_num, i, "Broken SUBSCRIBE_NAMESPACE", FALSE); - imquic_moq_subscribe_namespace_options subscribe_options = imquic_read_varint(&bytes[offset], blen-offset, &length); + imquic_moq_subscribe_namespace_options subscribe_options = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset || subscribe_options > IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); offset += length; - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); offset += length; @@ -2631,7 +2631,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2643,38 +2643,38 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl imquic_moq_fetch_type type = IMQUIC_MOQ_FETCH_STANDALONE; imquic_moq_location_range range = { 0 }; uint64_t joining_request_id = 0, joining_start = 0; - type = imquic_read_varint(&bytes[offset], blen-offset, &length); + type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; if(type == IMQUIC_MOQ_FETCH_STANDALONE) { uint64_t tns_num = 0, i = 0; IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_FETCH, tns_num, i, "Broken FETCH", FALSE); IMQUIC_MOQ_PARSE_TRACKNAME("Broken FETCH", FALSE); - range.start.group = imquic_read_varint(&bytes[offset], blen-offset, &length); + range.start.group = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Group: %"SCNu64"\n", imquic_get_connection_name(moq->conn), range.start.group); - range.start.object = imquic_read_varint(&bytes[offset], blen-offset, &length); + range.start.object = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- Start Object: %"SCNu64"\n", imquic_get_connection_name(moq->conn), range.start.object); - range.end.group = imquic_read_varint(&bytes[offset], blen-offset, &length); + range.end.group = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Group: %"SCNu64"\n", imquic_get_connection_name(moq->conn), range.end.group); - range.end.object = imquic_read_varint(&bytes[offset], blen-offset, &length); + range.end.object = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Object: %"SCNu64"\n", imquic_get_connection_name(moq->conn), range.end.object); } else if(type == IMQUIC_MOQ_FETCH_JOINING_RELATIVE || type == IMQUIC_MOQ_FETCH_JOINING_ABSOLUTE) { - joining_request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + joining_request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; - joining_start = imquic_read_varint(&bytes[offset], blen-offset, &length); + joining_start = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); offset += length; } else { @@ -2684,7 +2684,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl } imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken FETCH"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken FETCH"); offset += length; @@ -2757,7 +2757,7 @@ size_t imquic_moq_parse_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken FETCH_CANCEL"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2795,7 +2795,7 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2807,19 +2807,19 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- End Of Track: %"SCNu8")\n", imquic_get_connection_name(moq->conn), end_of_track); imquic_moq_location largest = { 0 }; - largest.group = imquic_read_varint(&bytes[offset], blen-offset, &length); + largest.group = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Group ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), largest.group); - largest.object = imquic_read_varint(&bytes[offset], blen-offset, &length); + largest.object = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Largest Object ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), largest.object); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken FETCH_OK"); offset += length; @@ -2832,7 +2832,7 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken FETCH_OK"); } size_t prop_offset = 0, prop_len = 0; - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || (prop_len > 0 && length >= blen-offset), NULL, 0, 0, "Broken FETCH_OK"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Properties Length: %"SCNu64"\n", @@ -2874,7 +2874,7 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken TRACK_STATUS"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -2888,7 +2888,7 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si IMQUIC_MOQ_PARSE_TRACKNAME("Broken TRACK_STATUS", FALSE); imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); - uint64_t params_num = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken TRACK_STATUS"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken TRACK_STATUS"); offset += length; @@ -2937,19 +2937,19 @@ size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, imquic_moq_datagram_message_type_parse(moq->version, dtype, NULL, &has_prop, NULL, &has_oid, &has_priority, NULL); size_t offset = 0; uint8_t length = 0; - uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t track_alias = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", imquic_get_connection_name(moq->conn), track_alias); - uint64_t group_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t group_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Group ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), group_id); uint64_t object_id = 0; if(has_oid) { - object_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + object_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); offset += length; } @@ -2965,7 +2965,7 @@ size_t imquic_moq_parse_object_datagram(imquic_moq_context *moq, uint8_t *bytes, size_t prop_offset = 0, prop_len = 0; if(has_prop) { /* The object contains properties */ - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM"); IMQUIC_MOQ_CHECK_ERR(prop_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Properties length is 0 but type is OBJECT_DATAGRAM"); offset += length; @@ -3019,19 +3019,19 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t imquic_moq_datagram_message_type_parse(moq->version, dtype, NULL, &has_prop, NULL, &has_oid, &has_priority, NULL); size_t offset = 0; uint8_t length = 0; - uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t track_alias = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track Alias: %"SCNu64"\n", imquic_get_connection_name(moq->conn), track_alias); - uint64_t group_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t group_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Group ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), group_id); - uint64_t object_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t object_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(has_oid) { - object_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + object_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); offset += length; } @@ -3047,7 +3047,7 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t size_t prop_offset = 0, prop_len = 0; if(has_prop) { /* The object contains properties */ - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); IMQUIC_MOQ_CHECK_ERR(prop_len == 0, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Properties length is 0 but type is OBJECT_DATAGRAM_STATUS"); offset += length; @@ -3062,7 +3062,7 @@ size_t imquic_moq_parse_object_datagram_status(imquic_moq_context *moq, uint8_t /* TODO Check Protocol Violation cases */ properties = imquic_moq_parse_properties(moq->version, &bytes[prop_offset], prop_len); } - uint64_t object_status = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t object_status = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken OBJECT_DATAGRAM_STATUS"); IMQUIC_MOQ_CHECK_ERR(object_status > IMQUIC_MOQ_END_OF_TRACK, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid object status"); offset += length; @@ -3103,12 +3103,12 @@ size_t imquic_moq_parse_subgroup_header(imquic_moq_context *moq, imquic_moq_stre return 0; size_t offset = 0; uint8_t length = 0; - uint64_t track_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t track_alias = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBGROUP_HEADER"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Track alias: %"SCNu64"\n", imquic_get_connection_name(moq->conn), track_alias); - uint64_t group_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t group_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBGROUP_HEADER"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Group ID: %"SCNu64"\n", @@ -3122,7 +3122,7 @@ size_t imquic_moq_parse_subgroup_header(imquic_moq_context *moq, imquic_moq_stre imquic_get_connection_name(moq->conn), dtype, has_subgroup, is_sgid0, has_prop, is_eog, has_priority, violation); IMQUIC_MOQ_CHECK_ERR(violation, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid SUBGROUP_HEADER type"); if(has_subgroup) { - subgroup_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + subgroup_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBGROUP_HEADER"); offset += length; } else { @@ -3167,7 +3167,7 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ size_t offset = 0; uint8_t length = 0; /* Note: this will be a delta, on v14 and later */ - uint64_t object_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t object_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3178,7 +3178,7 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ imquic_moq_data_message_type_to_subgroup_header(moq->version, moq_stream->type, &has_subgroup, &is_sgid0, &has_prop, NULL, &has_priority, NULL); if(has_prop) { /* The object contains properties */ - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3189,13 +3189,13 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ return -1; /* Not enough data, try again later */ offset += prop_len; } - uint64_t p_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t p_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; uint64_t object_status = 0; if(p_len == 0) { - object_status = imquic_read_varint(&bytes[offset], blen-offset, &length); + object_status = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length > blen-offset) return -1; /* Not enough data, try again later */ /* TODO An invalid object status should be a protocol violation error */ @@ -3268,7 +3268,7 @@ size_t imquic_moq_parse_fetch_header(imquic_moq_context *moq, imquic_moq_stream return 0; size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken FETCH_HEADER"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", @@ -3300,7 +3300,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str uint8_t length = 0; /* Since v15, FETCH objects are prefixed by serialization flags * that are supposed to optimize what will and will not be there */ - uint64_t flags = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t flags = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3313,7 +3313,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str &subgroup_type, &has_oid, &has_group, &has_priority, &has_prop, &is_datagram, &end_ne_range, &end_uk_range, &violation); uint64_t group_id = 0; if(has_group) { - group_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + group_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3324,7 +3324,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str } uint64_t subgroup_id = 0; if(subgroup_type == IMQUIC_MOQ_FETCH_SUBGROUP_ID) { - subgroup_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + subgroup_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3338,7 +3338,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str } uint64_t object_id = 0; if(has_oid) { - object_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + object_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3358,7 +3358,7 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str } size_t prop_offset = 0, prop_len = 0; if(has_prop) { - prop_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + prop_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; @@ -3369,13 +3369,13 @@ int imquic_moq_parse_fetch_header_object(imquic_moq_context *moq, imquic_moq_str return -1; /* Not enough data, try again later */ offset += prop_len; } - uint64_t p_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t p_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ offset += length; uint64_t object_status = 0; if(p_len == 0) { - object_status = imquic_read_varint(&bytes[offset], blen-offset, &length); + object_status = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length > blen-offset) return -1; /* Not enough data, try again later */ /* TODO An invalid object status should be a protocol violation error */ @@ -3446,7 +3446,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b return 0; size_t offset = 0; uint8_t length = 0; - uint64_t uri_len = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t uri_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken GOAWAY"); offset += length; char uri[8192], *uri_str = NULL; @@ -3466,7 +3466,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b offset += uri_len; uint64_t timeout = 0; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - timeout = imquic_read_varint(&bytes[offset], blen-offset, &length); + timeout = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken GOAWAY"); offset += length; } @@ -3544,7 +3544,7 @@ size_t imquic_moq_add_max_request_id(imquic_moq_context *moq, uint8_t *bytes, si } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_MAX_REQUEST_ID); - offset += imquic_write_varint(max_request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, max_request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -3564,7 +3564,7 @@ size_t imquic_moq_add_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUESTS_BLOCKED); - offset += imquic_write_varint(max_request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, max_request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -3585,7 +3585,7 @@ size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -3611,11 +3611,11 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_ERROR); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); - offset += imquic_write_varint(retry_interval, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, error, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, retry_interval, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, reason_len, &bytes[offset], blen-offset); if(reason_len > 0) { memcpy(&bytes[offset], reason, reason_len); offset += reason_len; @@ -3645,7 +3645,7 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); @@ -3693,9 +3693,9 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL); - offset += imquic_write_varint(error, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, error, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, reason_len, &bytes[offset], blen-offset); if(reason_len > 0) { memcpy(&bytes[offset], reason, reason_len); offset += reason_len; @@ -3724,10 +3724,10 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_PUBLISH); - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are properties to encode */ @@ -3761,7 +3761,7 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -3787,7 +3787,7 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_SUBSCRIBE); uint8_t params_num = 0; @@ -3816,8 +3816,8 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_UPDATE); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(sub_request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, sub_request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -3842,8 +3842,8 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are properties to encode */ @@ -3874,7 +3874,7 @@ size_t imquic_moq_add_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_ } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_UNSUBSCRIBE); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -3895,11 +3895,11 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_DONE); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(status, &bytes[offset], blen-offset); - offset += imquic_write_varint(streams_count, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, status, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, streams_count, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; - offset += imquic_write_varint(reason_len, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, reason_len, &bytes[offset], blen-offset); if(reason_len > 0) { memcpy(&bytes[offset], reason, reason_len); offset += reason_len; @@ -3929,9 +3929,9 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); - offset += imquic_write_varint(subscribe_options, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, subscribe_options, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -4019,18 +4019,18 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(type, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, type, &bytes[offset], blen-offset); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_FETCH); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_FETCH); - offset += imquic_write_varint(range->start.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(range->start.object, &bytes[offset], blen-offset); - offset += imquic_write_varint(range->end.group, &bytes[offset], blen-offset); - offset += imquic_write_varint(range->end.object, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, range->start.group, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, range->start.object, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, range->end.group, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, range->end.object, &bytes[offset], blen-offset); } else { - offset += imquic_write_varint(joining_request_id, &bytes[offset], blen-offset); - offset += imquic_write_varint(preceding_group_offset, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, joining_request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, preceding_group_offset, &bytes[offset], blen-offset); } uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); @@ -4066,7 +4066,7 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH_CANCEL); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4087,11 +4087,11 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH_OK); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); bytes[offset] = end_of_track; offset++; - offset += imquic_write_varint(end_location->group, &bytes[offset], blen-offset); - offset += imquic_write_varint(end_location->object, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, end_location->group, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, end_location->object, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are properties to encode */ @@ -4126,7 +4126,7 @@ size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_TRACK_STATUS); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_TRACK_STATUS); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_TRACK_STATUS); uint8_t params_num = 0; @@ -4160,13 +4160,13 @@ size_t imquic_moq_add_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t ble size_t uri_len = new_session_uri ? strlen(new_session_uri) : 0; size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_GOAWAY); - offset += imquic_write_varint(uri_len, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, uri_len, &bytes[offset], blen-offset); if(uri_len > 0) { memcpy(&bytes[offset], new_session_uri, uri_len); offset += uri_len; } if(moq->version >= IMQUIC_MOQ_VERSION_17) - offset += imquic_write_varint(timeout, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, timeout, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4198,11 +4198,11 @@ size_t imquic_moq_add_object_datagram(imquic_moq_context *moq, uint8_t *bytes, s is_eog, /* End of Group */ has_oid, /* Object ID */ has_priority); /* Priority */ - size_t offset = imquic_write_varint(dtype, bytes, blen); - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); + size_t offset = imquic_write_moqint(moq->version, dtype, bytes, blen); + offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, group_id, &bytes[offset], blen-offset); if(has_oid) - offset += imquic_write_varint(object_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_id, &bytes[offset], blen-offset); if(has_priority) { bytes[offset] = priority; offset++; @@ -4233,18 +4233,18 @@ size_t imquic_moq_add_object_datagram_status(imquic_moq_context *moq, uint8_t *b FALSE, /* End of Group */ has_oid, /* Object ID */ has_priority); /* Priority */ - size_t offset = imquic_write_varint(dtype, bytes, blen); - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); + size_t offset = imquic_write_moqint(moq->version, dtype, bytes, blen); + offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, group_id, &bytes[offset], blen-offset); if(has_oid) - offset += imquic_write_varint(object_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_id, &bytes[offset], blen-offset); if(has_priority) { bytes[offset] = priority; offset++; } if(has_prop) offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); - offset += imquic_write_varint(object_status, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_status, &bytes[offset], blen-offset); return offset; } @@ -4258,11 +4258,11 @@ size_t imquic_moq_add_subgroup_header(imquic_moq_context *moq, imquic_moq_stream imquic_moq_data_message_type dtype = moq_stream->type; gboolean has_sg = FALSE, has_priority = FALSE; imquic_moq_data_message_type_to_subgroup_header(moq->version, moq_stream->type, &has_sg, NULL, NULL, NULL, &has_priority, NULL); - size_t offset = imquic_write_varint(dtype, bytes, blen); - offset += imquic_write_varint(track_alias, &bytes[offset], blen-offset); - offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); + size_t offset = imquic_write_moqint(moq->version, dtype, bytes, blen); + offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, group_id, &bytes[offset], blen-offset); if(has_sg) - offset += imquic_write_varint(subgroup_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, subgroup_id, &bytes[offset], blen-offset); if(has_sg) { bytes[offset] = priority; offset++; @@ -4279,7 +4279,7 @@ size_t imquic_moq_add_subgroup_header_object(imquic_moq_context *moq, imquic_moq return 0; } size_t offset = 0; - offset += imquic_write_varint(object_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_id, &bytes[offset], blen-offset); /* TODO We can optimize this by only doing it once, when we parse the header */ /* TODO Involve EOG too */ gboolean has_prop = FALSE; @@ -4288,9 +4288,9 @@ size_t imquic_moq_add_subgroup_header_object(imquic_moq_context *moq, imquic_moq offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); if(payload == NULL) plen = 0; - offset += imquic_write_varint(plen, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, plen, &bytes[offset], blen-offset); if(plen == 0) - offset += imquic_write_varint(object_status, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_status, &bytes[offset], blen-offset); if(plen > 0) { memcpy(&bytes[offset], payload, plen); offset += plen; @@ -4304,8 +4304,8 @@ size_t imquic_moq_add_fetch_header(imquic_moq_context *moq, uint8_t *bytes, size imquic_get_connection_name(moq->conn), imquic_moq_data_message_type_str(IMQUIC_MOQ_FETCH_HEADER, moq->version)); return 0; } - size_t offset = imquic_write_varint(IMQUIC_MOQ_FETCH_HEADER, bytes, blen); - offset += imquic_write_varint(request_id, &bytes[offset], blen-offset); + size_t offset = imquic_write_moqint(moq->version, IMQUIC_MOQ_FETCH_HEADER, bytes, blen); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); return offset; } @@ -4322,13 +4322,13 @@ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *byte gboolean has_oid = FALSE, has_group = FALSE, has_priority = FALSE, has_prop = FALSE, is_datagram = FALSE; imquic_moq_parse_fetch_serialization_flags(moq->version, flags, &subgroup_type, &has_oid, &has_group, &has_priority, &has_prop, &is_datagram, NULL, NULL, NULL); - offset += imquic_write_varint(flags, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, flags, &bytes[offset], blen-offset); if(has_group) - offset += imquic_write_varint(group_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, group_id, &bytes[offset], blen-offset); if(subgroup_type == IMQUIC_MOQ_FETCH_SUBGROUP_ID && !is_datagram) - offset += imquic_write_varint(subgroup_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, subgroup_id, &bytes[offset], blen-offset); if(has_oid) - offset += imquic_write_varint(object_id, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_id, &bytes[offset], blen-offset); if(has_priority) { bytes[offset] = priority; offset++; @@ -4337,9 +4337,9 @@ size_t imquic_moq_add_fetch_header_object(imquic_moq_context *moq, uint8_t *byte offset += imquic_moq_add_properties(moq, &bytes[offset], blen-offset, properties, prlen); if(payload == NULL) plen = 0; - offset += imquic_write_varint(plen, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, plen, &bytes[offset], blen-offset); if(plen == 0) - offset += imquic_write_varint(object_status, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, object_status, &bytes[offset], blen-offset); if(plen > 0) { memcpy(&bytes[offset], payload, plen); offset += plen; @@ -4359,7 +4359,7 @@ size_t imquic_moq_add_properties(imquic_moq_context *moq, uint8_t *bytes, size_t prlen = 0; } size_t offset = 0; - offset += imquic_write_varint(prlen, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, prlen, &bytes[offset], blen-offset); if(properties != NULL && prlen > 0) { memcpy(&bytes[offset], properties, prlen); offset += prlen; @@ -4386,8 +4386,8 @@ size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, siz return 0; } param -= prev; - size_t offset = imquic_write_varint(param, &bytes[0], blen); - offset += imquic_write_varint(number, &bytes[offset], blen-offset); + size_t offset = imquic_write_moqint(moq->version, param, &bytes[0], blen); + offset += imquic_write_moqint(moq->version, number, &bytes[offset], blen-offset); return offset; } @@ -4409,8 +4409,8 @@ size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, si return 0; } param -= prev; - size_t offset = imquic_write_varint(param, &bytes[0], blen); - offset += imquic_write_varint(buflen, &bytes[offset], blen); + size_t offset = imquic_write_moqint(moq->version, param, &bytes[0], blen); + offset += imquic_write_moqint(moq->version, buflen, &bytes[offset], blen); if(buflen > 0) { memcpy(&bytes[offset], buf, buflen); offset += buflen; @@ -4429,7 +4429,7 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si } size_t offset = 0; uint8_t length = 0; - uint64_t type = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); offset += length; type += *param_type; @@ -4438,7 +4438,7 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si imquic_get_connection_name(moq->conn), imquic_moq_setup_option_type_str(type), type); uint64_t len = 0; if(type % 2 == 1) { - len = imquic_read_varint(&bytes[offset], blen-offset, &length); + len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ setup parameter"); offset += length; IMQUIC_MOQ_CHECK_ERR(len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); @@ -4451,14 +4451,14 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- '%s'\n", imquic_get_connection_name(moq->conn), params->path); } else if(type == IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID) { - params->max_request_id = imquic_read_varint(&bytes[offset], blen-offset, &length); + params->max_request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); params->max_request_id_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->max_request_id); len = length; } else if(type == IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE) { - params->max_auth_token_cache_size = imquic_read_varint(&bytes[offset], blen-offset, &length); + params->max_auth_token_cache_size = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); params->max_auth_token_cache_size_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", @@ -4513,7 +4513,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte } size_t offset = 0; uint8_t length = 0; - uint64_t type = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken MoQ request parameter"); offset += length; type += *param_type; @@ -4522,7 +4522,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte imquic_get_connection_name(moq->conn), imquic_moq_request_parameter_type_str(type, moq->version), type); uint64_t len = 0; if(type % 2 == 1) { - len = imquic_read_varint(&bytes[offset], blen-offset, &length); + len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken MoQ request parameter"); offset += length; IMQUIC_MOQ_CHECK_ERR(len > blen-offset, NULL, 0, 0, "Broken MoQ request parameter"); @@ -4542,14 +4542,14 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %s\n", imquic_get_connection_name(moq->conn), imquic_hex_str(&bytes[offset], auth_len, ai_str, sizeof(ai_str))); } else if(type == IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT) { - params->delivery_timeout = imquic_read_varint(&bytes[offset], blen-offset, &length); + params->delivery_timeout = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || params->delivery_timeout == 0, NULL, 0, 0, "Broken MoQ request parameter"); params->delivery_timeout_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->delivery_timeout); len = length; } else if(type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY) { - uint64_t subscriber_priority = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t subscriber_priority = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || subscriber_priority > 255, NULL, 0, 0, "Broken MoQ request parameter"); params->subscriber_priority = subscriber_priority; params->subscriber_priority_set = TRUE; @@ -4557,7 +4557,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte imquic_get_connection_name(moq->conn), params->subscriber_priority); len = length; } else if(type == IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER) { - uint64_t group_order = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t group_order = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || group_order > IMQUIC_MOQ_ORDERING_DESCENDING, NULL, 0, 0, "Broken MoQ request parameter"); params->group_order = group_order; params->group_order_set = TRUE; @@ -4567,27 +4567,27 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte } else if(type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER) { uint8_t *tmp = &bytes[offset]; size_t toffset = 0, tlen = len; - params->subscription_filter.type = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); + params->subscription_filter.type = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); toffset += length; if(params->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_START || params->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - params->subscription_filter.start_location.group = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); + params->subscription_filter.start_location.group = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); toffset += length; - params->subscription_filter.start_location.object = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); + params->subscription_filter.start_location.object = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); toffset += length; } if(params->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { - params->subscription_filter.end_group = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); + params->subscription_filter.end_group = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); } params->subscription_filter_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %d\n", imquic_get_connection_name(moq->conn), params->subscription_filter.type); } else if(type == IMQUIC_MOQ_REQUEST_PARAM_EXPIRES) { - params->expires = imquic_read_varint(&bytes[offset], blen-offset, &length); + params->expires = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); params->expires_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", @@ -4596,16 +4596,16 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte } else if(type == IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT) { uint8_t *tmp = &bytes[offset]; size_t toffset = 0, tlen = len; - params->largest_object.group = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); + params->largest_object.group = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); toffset += length; - params->largest_object.object = imquic_read_varint(&tmp[toffset], tlen-toffset, &length); + params->largest_object.object = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); params->largest_object_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64" / %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->largest_object.group, params->largest_object.object); } else if(type == IMQUIC_MOQ_REQUEST_PARAM_FORWARD) { - uint64_t forward = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t forward = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || forward > 1, NULL, 0, 0, "Broken MoQ request parameter"); params->forward = (forward > 0); params->forward_set = TRUE; @@ -4613,7 +4613,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte imquic_get_connection_name(moq->conn), params->forward); len = length; } else if(type == IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST) { - params->new_group_request = imquic_read_varint(&bytes[offset], blen-offset, &length); + params->new_group_request = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); params->new_group_request_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", @@ -4732,7 +4732,7 @@ GList *imquic_moq_parse_properties(imquic_moq_version version, uint8_t *properti uint64_t last_id = 0; /* Parse properties */ while(prlen-offset > 0) { - uint64_t prop_type = imquic_read_varint(&properties[offset], prlen-offset, &length); + uint64_t prop_type = imquic_read_moqint(version, &properties[offset], prlen-offset, &length); if(length == 0 || length >= prlen-offset) { IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken properties\n"); g_list_free_full(props, (GDestroyNotify)imquic_moq_property_free); @@ -4743,7 +4743,7 @@ GList *imquic_moq_parse_properties(imquic_moq_version version, uint8_t *properti offset += length; if(prop_type % 2 == 0) { /* Even types are followed by a numeric value */ - uint64_t prop_val = imquic_read_varint(&properties[offset], prlen-offset, &length); + uint64_t prop_val = imquic_read_moqint(version, &properties[offset], prlen-offset, &length); if(length == 0 || length > prlen-offset) { IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken properties\n"); g_list_free_full(props, (GDestroyNotify)imquic_moq_property_free); @@ -4756,7 +4756,7 @@ GList *imquic_moq_parse_properties(imquic_moq_version version, uint8_t *properti props = g_list_prepend(props, property); } else { /* Odd typed are followed by a length and a value */ - uint64_t prop_len = imquic_read_varint(&properties[offset], prlen-offset, &length); + uint64_t prop_len = imquic_read_moqint(version, &properties[offset], prlen-offset, &length); if(length == 0 || length >= prlen-offset || prop_len >= prlen-offset) { IMQUIC_LOG(IMQUIC_LOG_ERR, "Broken properties\n"); g_list_free_full(props, (GDestroyNotify)imquic_moq_property_free); @@ -4800,12 +4800,12 @@ size_t imquic_moq_build_properties(imquic_moq_version version, GList *properties uint64_t last_id = 0; while(temp) { imquic_moq_property *prop = (imquic_moq_property *)temp->data; - offset += imquic_write_varint((prop->id - last_id), &bytes[offset], blen-offset); + offset += imquic_write_moqint(version, (prop->id - last_id), &bytes[offset], blen-offset); last_id = prop->id; if(prop->id % 2 == 0) { - offset += imquic_write_varint(prop->value.number, &bytes[offset], blen-offset); + offset += imquic_write_moqint(version, prop->value.number, &bytes[offset], blen-offset); } else { - offset += imquic_write_varint(prop->value.data.length, &bytes[offset], blen-offset); + offset += imquic_write_moqint(version, prop->value.data.length, &bytes[offset], blen-offset); if(prop->value.data.length > 0) { memcpy(&bytes[offset], prop->value.data.buffer, prop->value.data.length); offset += prop->value.data.length; @@ -4818,13 +4818,13 @@ size_t imquic_moq_build_properties(imquic_moq_version version, GList *properties } /* Auth token management */ -int imquic_moq_parse_auth_token(uint8_t *bytes, size_t blen, imquic_moq_auth_token *token) { +int imquic_moq_parse_auth_token(imquic_moq_version version, uint8_t *bytes, size_t blen, imquic_moq_auth_token *token) { if(bytes == NULL || blen == 0 || token == NULL) return -1; memset(token, 0, sizeof(*token)); size_t offset = 0; uint8_t length = 0; - uint64_t alias_type = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t alias_type = imquic_read_moqint(version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, -1, "Broken auth token"); offset += length; if(alias_type != IMQUIC_MOQ_AUTH_TOKEN_DELETE && alias_type != IMQUIC_MOQ_AUTH_TOKEN_REGISTER && @@ -4834,14 +4834,14 @@ int imquic_moq_parse_auth_token(uint8_t *bytes, size_t blen, imquic_moq_auth_tok } token->alias_type = alias_type; if(alias_type != IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE) { - uint64_t token_alias = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t token_alias = imquic_read_moqint(version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, -1, "Broken auth token"); offset += length; token->token_alias_set = TRUE; token->token_alias = token_alias; } if(alias_type == IMQUIC_MOQ_AUTH_TOKEN_REGISTER || alias_type == IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE) { - uint64_t token_type = imquic_read_varint(&bytes[offset], blen-offset, &length); + uint64_t token_type = imquic_read_moqint(version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, -1, "Broken auth token"); offset += length; token->token_type_set = TRUE; @@ -4852,7 +4852,7 @@ int imquic_moq_parse_auth_token(uint8_t *bytes, size_t blen, imquic_moq_auth_tok return 0; } -size_t imquic_moq_build_auth_token(imquic_moq_auth_token *token, uint8_t *bytes, size_t blen) { +size_t imquic_moq_build_auth_token(imquic_moq_version version, imquic_moq_auth_token *token, uint8_t *bytes, size_t blen) { if(token == NULL || bytes == NULL || blen == 0) return 0; if(token->alias_type != IMQUIC_MOQ_AUTH_TOKEN_DELETE && token->alias_type != IMQUIC_MOQ_AUTH_TOKEN_REGISTER && @@ -4860,20 +4860,20 @@ size_t imquic_moq_build_auth_token(imquic_moq_auth_token *token, uint8_t *bytes, IMQUIC_LOG(IMQUIC_LOG_ERR, "Invalid alias type %d\n", token->alias_type); return 0; } - size_t offset = imquic_write_varint(token->alias_type, bytes, blen); + size_t offset = imquic_write_moqint(version, token->alias_type, bytes, blen); if(token->alias_type != IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE) { if(!token->token_alias_set) { IMQUIC_LOG(IMQUIC_LOG_ERR, "Token alias is required when using %s\n", imquic_moq_auth_token_alias_type_str(token->alias_type)); return 0; } - offset += imquic_write_varint(token->token_alias, &bytes[offset], blen-offset); + offset += imquic_write_moqint(version, token->token_alias, &bytes[offset], blen-offset); } if(token->alias_type == IMQUIC_MOQ_AUTH_TOKEN_REGISTER || token->alias_type == IMQUIC_MOQ_AUTH_TOKEN_USE_VALUE) { if(!token->token_type_set) { IMQUIC_LOG(IMQUIC_LOG_ERR, "Token type is required when using %s\n", imquic_moq_auth_token_alias_type_str(token->alias_type)); return 0; } - offset += imquic_write_varint(token->token_type, &bytes[offset], blen-offset); + offset += imquic_write_moqint(version, token->token_type, &bytes[offset], blen-offset); if(token->token_value.buffer && token->token_value.length > 0) { memcpy(&bytes[offset], token->token_value.buffer, token->token_value.length); offset += token->token_value.length; @@ -6076,7 +6076,9 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { } /* Reading and writing MoQ's flavour of variable size integers */ -uint64_t imquic_read_moqint(uint8_t *bytes, size_t blen, uint8_t *length) { +uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length) { + if(version <= IMQUIC_MOQ_VERSION_16) + return imquic_read_varint(bytes, blen, length); if(length) *length = 0; if(bytes == NULL || blen == 0) @@ -6124,7 +6126,9 @@ uint64_t imquic_read_moqint(uint8_t *bytes, size_t blen, uint8_t *length) { return res; } -uint8_t imquic_write_moqint(uint64_t number, uint8_t *bytes, size_t blen) { +uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen) { + if(version <= IMQUIC_MOQ_VERSION_16) + return imquic_write_varint(number, bytes, blen); if(blen < 1) return 0; if(number <= 127) { From 39600d339e89f3a8818dc8af761e0a97848a3e75 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 5 Mar 2026 12:10:43 +0100 Subject: [PATCH 11/30] Added hooks to RESET_STREAM and STOP_SENDING (WIP) --- src/connection.c | 38 ++++++++++++++++++++++++++++++-- src/imquic-moq.c | 2 ++ src/imquic.c | 11 ++++++++++ src/imquic/imquic.h | 6 +++++ src/internal/connection.h | 6 +++++ src/internal/moq.h | 5 +++++ src/internal/network.h | 2 ++ src/moq.c | 21 ++++++++++++++++++ src/quic.c | 46 ++++++++++++++++++++++++++++++++++++++- 9 files changed, 134 insertions(+), 3 deletions(-) diff --git a/src/connection.c b/src/connection.c index ee6a552..3ab9a58 100644 --- a/src/connection.c +++ b/src/connection.c @@ -241,7 +241,7 @@ void imquic_connection_reset_stream(imquic_connection *conn, uint64_t stream_id, imquic_stream *stream = g_hash_table_lookup(conn->streams, &stream_id); if(stream == NULL || !stream->can_send) { imquic_mutex_unlock(&conn->mutex); - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Couldn't close stream, no such stream %"SCNu64"\n", + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Couldn't reset stream, no such stream %"SCNu64"\n", imquic_get_connection_name(conn), stream_id); return; } @@ -256,7 +256,7 @@ void imquic_connection_reset_stream(imquic_connection *conn, uint64_t stream_id, imquic_stream_mark_complete(stream, FALSE); stream->out_state = IMQUIC_STREAM_RESET; imquic_mutex_unlock(&stream->mutex); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Closing stream %"SCNu64" (RESET_STREAM)\n", + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Resetting stream %"SCNu64" (RESET_STREAM)\n", imquic_get_connection_name(conn), stream_id); imquic_connection_event *event = imquic_connection_event_create(IMQUIC_CONNECTION_EVENT_RESET_STREAM); event->stream_id = stream_id; @@ -267,6 +267,40 @@ void imquic_connection_reset_stream(imquic_connection *conn, uint64_t stream_id, imquic_refcount_decrease(&stream->ref); } +/* Helper to stop a STREAM */ +void imquic_connection_stop_sending_stream(imquic_connection *conn, uint64_t stream_id, uint64_t error_code) { + if(conn == NULL) + return; + imquic_mutex_lock(&conn->mutex); + imquic_stream *stream = g_hash_table_lookup(conn->streams, &stream_id); + if(stream == NULL || !stream->can_send) { + imquic_mutex_unlock(&conn->mutex); + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Couldn't stop stream, no such stream %"SCNu64"\n", + imquic_get_connection_name(conn), stream_id); + return; + } + imquic_refcount_increase(&stream->ref); + imquic_mutex_unlock(&conn->mutex); + imquic_mutex_lock(&stream->mutex); + if(stream->in_state >= IMQUIC_STREAM_RESET) { + imquic_mutex_unlock(&stream->mutex); + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Couldn't prepare STOP_SENDING for %"SCNu64" (alreayd sent?)\n", + imquic_get_connection_name(conn), stream_id); + } else { + imquic_stream_mark_complete(stream, FALSE); + stream->in_state = IMQUIC_STREAM_RESET; + imquic_mutex_unlock(&stream->mutex); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Stopping stream %"SCNu64" (RESET_STREAM)\n", + imquic_get_connection_name(conn), stream_id); + imquic_connection_event *event = imquic_connection_event_create(IMQUIC_CONNECTION_EVENT_STOP_SENDING); + event->stream_id = stream_id; + event->error_code = error_code; + g_async_queue_push(conn->queued_events, event); + imquic_loop_wakeup(); + } + imquic_refcount_decrease(&stream->ref); +} + /* Helpers to close connections */ void imquic_connection_close(imquic_connection *conn, uint64_t error_code, const char *reason) { /* Send a CONNECTION CLOSE */ diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 32a8283..1a4cb5a 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -117,6 +117,7 @@ imquic_server *imquic_create_moq_server(const char *name, ...) { server->stream_incoming = imquic_moq_stream_incoming; server->datagram_incoming = imquic_moq_datagram_incoming; server->reset_stream_incoming = imquic_moq_reset_stream_incoming; + server->stop_sending_incoming = imquic_moq_stop_sending_incoming; server->connection_gone = imquic_moq_connection_gone; return server; } @@ -219,6 +220,7 @@ imquic_client *imquic_create_moq_client(const char *name, ...) { client->stream_incoming = imquic_moq_stream_incoming; client->datagram_incoming = imquic_moq_datagram_incoming; client->reset_stream_incoming = imquic_moq_reset_stream_incoming; + client->stop_sending_incoming = imquic_moq_stop_sending_incoming; client->connection_gone = imquic_moq_connection_gone; return client; } diff --git a/src/imquic.c b/src/imquic.c index ff30918..d0cf86b 100644 --- a/src/imquic.c +++ b/src/imquic.c @@ -469,6 +469,17 @@ void imquic_set_reset_stream_cb(imquic_endpoint *endpoint, } } +void imquic_set_stop_sending_cb(imquic_endpoint *endpoint, + void (* stop_sending_incoming)(imquic_connection *conn, uint64_t stream_id, uint64_t error_code)) { + if(endpoint != NULL) { + if(endpoint->internal_callbacks) { + IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't seq QUIC callback when using specific protocol handler\n"); + } else { + endpoint->stop_sending_incoming = stop_sending_incoming; + } + } +} + void imquic_set_connection_failed_cb(imquic_endpoint *endpoint, void (* connection_failed)(void *user_data)) { if(endpoint != NULL && !endpoint->is_server) diff --git a/src/imquic/imquic.h b/src/imquic/imquic.h index 30f5098..f42eb7d 100644 --- a/src/imquic/imquic.h +++ b/src/imquic/imquic.h @@ -463,6 +463,12 @@ void imquic_set_datagram_incoming_cb(imquic_endpoint *endpoint, * @param reset_stream_incoming Pointer to the function that will be invoked on the new RESET_STREAM */ void imquic_set_reset_stream_cb(imquic_endpoint *endpoint, void (* reset_stream_incoming)(imquic_connection *conn, uint64_t stream_id, uint64_t error_code)); +/*! \brief Configure the callback function to be notified about incoming + * STOP_SENDING messages on an existing connection handled by this endpoint. + * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure + * @param reset_stop_sending Pointer to the function that will be invoked on the new RESET_STREAM */ +void imquic_set_stop_sending_cb(imquic_endpoint *endpoint, + void (* reset_stop_sending)(imquic_connection *conn, uint64_t stream_id, uint64_t error_code)); /*! \brief Configure the callback function to be notified when an attemp * to establish a connection failed, e.g., because the server is unreachable. * @note Considering the application never received a connection instance diff --git a/src/internal/connection.h b/src/internal/connection.h index 039fa17..27b8332 100644 --- a/src/internal/connection.h +++ b/src/internal/connection.h @@ -146,6 +146,11 @@ void imquic_connection_notify_gone(imquic_connection *conn); * @param stream_id ID of the stream to reset * @param error_code The error code to add to the frame */ void imquic_connection_reset_stream(imquic_connection *conn, uint64_t stream_id, uint64_t error_code); +/*! \brief Helper to ask the peer to stop sending on a stream, sending a \c STOP_SENDING + * @param conn The imquic_connection instance that owns the stream to stop + * @param stream_id ID of the stream to stop + * @param error_code The error code to add to the frame */ +void imquic_connection_stop_sending_stream(imquic_connection *conn, uint64_t stream_id, uint64_t error_code); /*! \brief Helpers to close connections * @param conn The imquic_connection instance to close * @param error_code The error code to send back in the \c CONNECTION_CLOSE frame @@ -162,6 +167,7 @@ typedef enum imquic_connection_event_type { IMQUIC_CONNECTION_EVENT_STREAM, IMQUIC_CONNECTION_EVENT_DATAGRAM, IMQUIC_CONNECTION_EVENT_RESET_STREAM, + IMQUIC_CONNECTION_EVENT_STOP_SENDING, IMQUIC_CONNECTION_EVENT_CLOSE_CONN, } imquic_connection_event_type; diff --git a/src/internal/moq.h b/src/internal/moq.h index 721d0e8..a53afac 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -1334,6 +1334,11 @@ void imquic_moq_datagram_incoming(imquic_connection *conn, uint8_t *bytes, uint6 * @param stream_id The ID of the stream that was reset * @param error_code The error code that was received */ void imquic_moq_reset_stream_incoming(imquic_connection *conn, uint64_t stream_id, uint64_t error_code); +/*! \brief Callback the core invokes when there's an incoming \c STOP_SENDING + * @param conn The imquic_connection instance for which new \c STOP_SENDING is available + * @param stream_id The ID of the stream to stop sending data on + * @param error_code The error code that was received */ +void imquic_moq_stop_sending_incoming(imquic_connection *conn, uint64_t stream_id, uint64_t error_code); /*! \brief Callback the core invokes when an existing MoQ connection is not available anymore * @param conn The imquic_connection instance that is now gone */ void imquic_moq_connection_gone(imquic_connection *conn); diff --git a/src/internal/network.h b/src/internal/network.h index 82812aa..fab2b81 100644 --- a/src/internal/network.h +++ b/src/internal/network.h @@ -97,6 +97,8 @@ typedef struct imquic_network_endpoint { void (* datagram_incoming)(imquic_connection *conn, uint8_t *bytes, uint64_t length); /*! \brief Callback to invoke when a \c RESET_STREAM arrives on one of the connections handled by this endpoint */ void (* reset_stream_incoming)(imquic_connection *conn, uint64_t stream_id, uint64_t error_code); + /*! \brief Callback to invoke when a \c STOP_SENDING arrives on one of the connections handled by this endpoint */ + void (* stop_sending_incoming)(imquic_connection *conn, uint64_t stream_id, uint64_t error_code); /*! \brief Callback to invoke when new one of the connections handled by this endpoint is closed */ void (* connection_gone)(imquic_connection *conn); /*! \brief Callback to invoke when a client connection attempt fails */ diff --git a/src/moq.c b/src/moq.c index 1b5f515..507115f 100644 --- a/src/moq.c +++ b/src/moq.c @@ -269,6 +269,27 @@ void imquic_moq_reset_stream_incoming(imquic_connection *conn, uint64_t stream_i moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace(moq->conn, request_id, NULL); } +void imquic_moq_stop_sending_incoming(imquic_connection *conn, uint64_t stream_id, uint64_t error_code) { + /* We got a STOP_SENDING */ + imquic_mutex_lock(&moq_mutex); + imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); + imquic_mutex_unlock(&moq_mutex); + if(moq == NULL) + return; + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams, &stream_id); + if(moq_stream == NULL) { + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Got STOP_SENDING for unknown STREAM %"SCNu64": %"SCNu64" (%s)\n", + imquic_get_connection_name(conn), stream_id, error_code, imquic_moq_reset_stream_code_str(error_code)); + imquic_mutex_unlock(&moq->mutex); + return; + } + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Got STOP_SENDING for STREAM %"SCNu64": %"SCNu64" (%s)\n", + imquic_get_connection_name(conn), stream_id, error_code, imquic_moq_reset_stream_code_str(error_code)); + imquic_mutex_unlock(&moq->mutex); + /* TODO */ +} + void imquic_moq_connection_gone(imquic_connection *conn) { /* Connection was closed */ imquic_mutex_lock(&moq_mutex); diff --git a/src/quic.c b/src/quic.c index 0ad88e0..868f312 100644 --- a/src/quic.c +++ b/src/quic.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "internal/quic.h" @@ -206,6 +207,13 @@ gboolean imquic_quic_queued_event(imquic_connection *conn, imquic_connection_eve IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Error resetting STREAM %"SCNu64": %d\n", conn->name, event->stream_id, ret); } + } else if(event->type == IMQUIC_CONNECTION_EVENT_STOP_SENDING) { + /* Send a STOP_SENDING */ + int ret = picoquic_stop_sending(conn->piconn, event->stream_id, event->error_code); + if(ret != 0) { + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Error stopping STREAM %"SCNu64": %d\n", + conn->name, event->stream_id, ret); + } } else if(event->type == IMQUIC_CONNECTION_EVENT_CLOSE_CONN) { /* Send a CONNECTION_CLOSE */ int ret = picoquic_close(conn->piconn, event->error_code); @@ -231,7 +239,7 @@ void imquic_quic_next_step(imquic_network_endpoint *endpoint) { static int imquic_quic_stream_callback(picoquic_cnx_t *pconn, uint64_t stream_id, uint8_t *bytes, size_t blen, picoquic_call_back_event_t fin_or_event, void *callback_ctx, void *v_stream_ctx) { - /* TODO */ + /* Check what the callback is about */ imquic_network_endpoint *endpoint = (imquic_network_endpoint *)callback_ctx; imquic_connection *conn = pconn ? g_hash_table_lookup(endpoint->connections_by_cnx, pconn) : NULL; char *name = conn ? conn->name : endpoint->name; @@ -319,6 +327,42 @@ static int imquic_quic_stream_callback(picoquic_cnx_t *pconn, /* Pass the data to the application callback */ imquic_connection_notify_stream_incoming(conn, stream, bytes, blen); } + } else if(fin_or_event == picoquic_callback_stream_reset) { + /* Use the picoquic internal API to obtain the error_code */ + uint64_t error_code = 0; + picoquic_stream_head_t *ps = picoquic_find_stream(pconn, stream_id); + if(ps != NULL) + error_code = ps->remote_error; + /* Update the local state of the stream */ + imquic_mutex_lock(&conn->mutex); + imquic_stream *stream = g_hash_table_lookup(conn->streams, &stream_id); + if(stream != NULL) { + IMQUIC_LOG(IMQUIC_LOG_INFO, "Stream %"SCNu64" has been reset by the peer\n", stream_id); + if(stream->in_state != IMQUIC_STREAM_COMPLETE) + stream->in_state = IMQUIC_STREAM_RESET; + } + imquic_mutex_unlock(&conn->mutex); + /* Pass the data to the application callback */ + if(endpoint->reset_stream_incoming) + endpoint->reset_stream_incoming(conn, stream_id, error_code); + } else if(fin_or_event == picoquic_callback_stop_sending) { + /* Use the picoquic internal API to obtain the error_code */ + uint64_t error_code = 0; + picoquic_stream_head_t *ps = picoquic_find_stream(pconn, stream_id); + if(ps != NULL) + error_code = ps->remote_stop_error; + /* Update the local state of the stream */ + imquic_mutex_lock(&conn->mutex); + imquic_stream *stream = g_hash_table_lookup(conn->streams, &stream_id); + if(stream != NULL) { + IMQUIC_LOG(IMQUIC_LOG_INFO, "We've been asked to stop sending on stream %"SCNu64"\n", stream_id); + if(stream->out_state != IMQUIC_STREAM_COMPLETE) + stream->out_state = IMQUIC_STREAM_RESET; + } + imquic_mutex_unlock(&conn->mutex); + /* Pass the data to the application callback */ + if(endpoint->stop_sending_incoming) + endpoint->stop_sending_incoming(conn, stream_id, error_code); } else if(fin_or_event == picoquic_callback_application_close) { /* TODO Should we handle this somehow? */ } else if(fin_or_event == picoquic_callback_close) { From c7bbb62bf873ba2d6bc61b9c9ac784969ef15576 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 5 Mar 2026 17:59:01 +0100 Subject: [PATCH 12/30] Split bidirectional control stream in unidirectional control streams --- src/imquic/moq.h | 13 ++- src/internal/moq.h | 48 ++++++--- src/moq.c | 261 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 248 insertions(+), 74 deletions(-) diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 30072e2..c972fc1 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -858,7 +858,8 @@ void imquic_set_moq_ready_cb(imquic_endpoint *endpoint, void imquic_set_incoming_publish_namespace_cb(imquic_endpoint *endpoint, void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's - * an incoming \c PUBLISH_NAMESPACE_CANCEL request. + * an incoming \c PUBLISH_NAMESPACE_CANCEL request (legacy), or when + * the associated stream is closed (new draft versions) * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_publish_namespace_cancel Pointer to the function that will handle the incoming \c PUBLISH_NAMESPACE_CANCEL */ void imquic_set_incoming_publish_namespace_cancel_cb(imquic_endpoint *endpoint, @@ -951,6 +952,7 @@ void imquic_set_incoming_unsubscribe_cb(imquic_endpoint *endpoint, void (* incoming_unsubscribe)(imquic_connection *conn, uint64_t request_id)); /*! \brief Configure the callback function to be notified when there's * an incoming \c REQUESTS_BLOCKED request. + * \note Deprecated in v17 * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param requests_blocked Pointer to the function that will handle the incoming \c REQUESTS_BLOCKED */ void imquic_set_requests_blocked_cb(imquic_endpoint *endpoint, @@ -1007,7 +1009,8 @@ void imquic_set_incoming_joining_fetch_cb(imquic_endpoint *endpoint, void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's - * an incoming \c FETCH_CANCEL request. + * an incoming \c FETCH_CANCEL request (legacy), or when + * the associated stream is closed (new draft versions) * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_fetch_cancel Pointer to the function that will handle the incoming \c FETCH_CANCEL */ void imquic_set_incoming_fetch_cancel_cb(imquic_endpoint *endpoint, @@ -1079,7 +1082,8 @@ void imquic_set_moq_connection_gone_cb(imquic_endpoint *endpoint, int imquic_moq_set_connection_auth(imquic_connection *conn, uint8_t *auth, size_t authlen); /*! \brief Helper function to set the Maximum Request ID a subscriber can send - * \note If invoked before the MoQ connection setup, it will be put in the + * \note Deprecated in v17, and so not needed anymore. For older versions, + * if invoked before the MoQ connection setup, it will be put in the * setup parameter, otherwise it's sent in a \c MAX_REQUEST_ID request. * Notice that whatever is passed to the request will be decremented by * 1, as per the specification, meaning you cannot pass \c 0 as a value here @@ -1318,7 +1322,8 @@ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); -/*! \brief Function to send a \c FETCH_CANCEL request +/*! \brief Function to send a \c FETCH_CANCEL request (legacy) or close + * the stream associated with the \c FETCH subscription (new draft versions) * @param conn The imquic_connection to send the request on * @param request_id The unique \c request_id value associated to the subscription to cancel_fetch from * @returns 0 in case of success, a negative integer otherwise */ diff --git a/src/internal/moq.h b/src/internal/moq.h index a53afac..3828a75 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -45,22 +45,23 @@ typedef enum imquic_moq_message_type { IMQUIC_MOQ_SUBSCRIBE = 0x3, IMQUIC_MOQ_SUBSCRIBE_OK = 0x4, IMQUIC_MOQ_PUBLISH_NAMESPACE = 0x6, - IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE = 0x9, - IMQUIC_MOQ_UNSUBSCRIBE = 0xa, + IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE = 0x9, /* Deprecated in v17 */ + IMQUIC_MOQ_UNSUBSCRIBE = 0xa, /* Deprecated in v17 */ IMQUIC_MOQ_PUBLISH_DONE = 0xb, - IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL = 0xc, + IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL = 0xc, /* Deprecated in v17 */ IMQUIC_MOQ_TRACK_STATUS = 0xd, IMQUIC_MOQ_GOAWAY = 0x10, IMQUIC_MOQ_SUBSCRIBE_NAMESPACE = 0x11, IMQUIC_MOQ_NAMESPACE = 0x8, IMQUIC_MOQ_NAMESPACE_DONE = 0xe, - IMQUIC_MOQ_MAX_REQUEST_ID = 0x15, - IMQUIC_MOQ_REQUESTS_BLOCKED = 0x1A, + IMQUIC_MOQ_MAX_REQUEST_ID = 0x15, /* Deprecated in v17 */ + IMQUIC_MOQ_REQUESTS_BLOCKED = 0x1A, /* Deprecated in v17 */ IMQUIC_MOQ_FETCH = 0x16, - IMQUIC_MOQ_FETCH_CANCEL = 0x17, + IMQUIC_MOQ_FETCH_CANCEL = 0x17, /* Deprecated in v17 */ IMQUIC_MOQ_FETCH_OK = 0x18, - IMQUIC_MOQ_CLIENT_SETUP = 0x20, - IMQUIC_MOQ_SERVER_SETUP = 0x21, + IMQUIC_MOQ_SETUP = 0x2F00, + IMQUIC_MOQ_CLIENT_SETUP = 0x20, /* Deprecated in v17 */ + IMQUIC_MOQ_SERVER_SETUP = 0x21, /* Deprecated in v17 */ IMQUIC_MOQ_PUBLISH = 0x1D, IMQUIC_MOQ_PUBLISH_OK = 0x1E, } imquic_moq_message_type; @@ -240,9 +241,11 @@ typedef struct imquic_moq_setup_options { gboolean path_set; /*! \brief Value of the PATH parameter */ char path[256]; - /*! \brief Whether the MAX_REQUEST_ID parameter is set */ + /*! \brief Whether the MAX_REQUEST_ID parameter is set + * \note Deprecated in v17 */ gboolean max_request_id_set; - /*! \brief Value of the MAX_REQUEST_ID parameter */ + /*! \brief Value of the MAX_REQUEST_ID parameter + * \note Deprecated in v17 */ uint64_t max_request_id; /*! \brief Whether the MAX_AUTH_TOKEN_CACHE_SIZE parameter is set */ gboolean max_auth_token_cache_size_set; @@ -312,8 +315,10 @@ typedef struct imquic_moq_context { gboolean is_server; /*! \brief Whether a MoQ control stream has been established */ gboolean has_control_stream; - /*! \brief ID of the control stream */ - uint64_t control_stream_id; + /*! \brief ID(s) of the control stream (legacy bidirectional, or new unidirectional) */ + uint64_t control_stream_id, remote_control_stream_id; + /*! \brief Whether we sent and received a SETUP */ + gboolean sent_setup, recvd_setup; /*! \brief QUIC streams handled by the stack */ GHashTable *streams; /*! \brief Subscriptions this connection will send objects to, indexed by track_alias */ @@ -434,6 +439,7 @@ void imquic_moq_subscription_destroy(imquic_moq_subscription *moq_sub); * @returns 0 in case of success, or a negative integer otherwise */ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_t *bytes, size_t blen, gboolean complete, gboolean datagram); /*! \brief Helper to parse a \c CLIENT_SETUP message + * \note This message was deprecated in v17: now both client and server use \c SETUP * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -441,12 +447,20 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c SERVER_SETUP message + * \note This message was deprecated in v17: now both client and server use \c SETUP * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +/*! \brief Helper to parse a \c SETUP message + * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] bytes The buffer containing the message to parse + * @param[in] blen Size of the buffer to parse + * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors + * @returns The size of the parsed message, if successful, or 0 otherwise */ +size_t imquic_moq_parse_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c MAX_REQUEST_ID message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse @@ -719,6 +733,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b */ ///@{ /*! \brief Helper method to add a \c CLIENT_SETUP message to a buffer + * \note This message was deprecated in v17: now both client and server use \c SETUP * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -727,6 +742,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_setup_options *options); /*! \brief Helper method to add a \c SERVER_SETUP message to a buffer + * \note This message was deprecated in v17: now both client and server use \c SETUP * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -734,6 +750,14 @@ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_setup_options *options); +/*! \brief Helper method to add a \c SETUP message to a buffer + * @param moq The imquic_moq_context generating the message + * @param bytes The buffer to add the message to + * @param blen The size of the buffer + * @param options The setup options to send + * @returns The size of the generated message, if successful, or 0 otherwise */ +size_t imquic_moq_add_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + imquic_moq_setup_options *options); /*! \brief Helper method to add a \c MAX_REQUEST_ID message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to diff --git a/src/moq.c b/src/moq.c index 507115f..19d412f 100644 --- a/src/moq.c +++ b/src/moq.c @@ -76,6 +76,9 @@ static gboolean moq_is_request_id_valid(imquic_moq_context *moq, uint64_t reques moq->is_server ? "odd" : "even", moq->is_server ? "server" : "client"); return FALSE; } + /* We only need stricter checks on older versions */ + if(moq->version >= IMQUIC_MOQ_VERSION_17) + return TRUE; if(request_id < moq->next_request_id) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Request ID lower than the next we expected (%"SCNu64" < %"SCNu64")\n", imquic_get_connection_name(moq->conn), request_id, moq->next_request_id); @@ -94,6 +97,9 @@ static gboolean moq_is_request_id_valid(imquic_moq_context *moq, uint64_t reques !moq->is_server ? "odd" : "even", !moq->is_server ? "server" : "client"); return FALSE; } + /* We only need stricter checks on older versions */ + if(moq->version >= IMQUIC_MOQ_VERSION_17) + return TRUE; if(request_id != moq->expected_request_id) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Request ID not the one next we expected (%"SCNu64" != %"SCNu64")\n", imquic_get_connection_name(moq->conn), request_id, moq->expected_request_id); @@ -140,23 +146,38 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { imquic_mutex_lock(&moq_mutex); g_hash_table_insert(moq_sessions, conn, moq); imquic_mutex_unlock(&moq_mutex); - /* If we're a client, let's create a control stream */ - if(!moq->is_server) { + /* Let's check if we need to create a control stream */ + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + /* For older versions, we only open a bidirectional STREAM ourselves + * if we're a client, as we'll need to send a CLIENT_SETUP */ + if(!moq->is_server) { + uint64_t stream_id = 0; + imquic_connection_new_stream_id(conn, TRUE, &stream_id); + moq->control_stream_id = stream_id; + moq->has_control_stream = TRUE; +#ifdef HAVE_QLOG + if(conn->qlog != NULL && conn->qlog->moq) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq->control_stream_id, "control"); +#endif + } + } else { + /* For newer versions, the role doesn't matter, as we always create + * a unidirectional STREAM to send a SETUP message right away */ uint64_t stream_id = 0; - imquic_connection_new_stream_id(conn, TRUE, &stream_id); + imquic_connection_new_stream_id(conn, FALSE, &stream_id); moq->control_stream_id = stream_id; - moq->has_control_stream = TRUE; + moq->sent_setup = TRUE; #ifdef HAVE_QLOG if(conn->qlog != NULL && conn->qlog->moq) imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq->control_stream_id, "control"); #endif } - /* Notify the application: for clients, we'll need it to set role and version */ + /* Notify the application: we may get some info back to use next */ if(conn->socket && conn->socket->callbacks.moq.new_connection) conn->socket->callbacks.moq.new_connection(conn, user_data); /* After the function returns, check if we can do something */ - if(!moq->is_server) { - /* Generate a CLIENT_SETUP */ + if(moq->version <= IMQUIC_MOQ_VERSION_16 && !moq->is_server) { + /* Legacy version, generate a CLIENT_SETUP */ imquic_moq_setup_options parameters = { 0 }; if(moq->local_max_request_id > 0) { parameters.max_request_id_set = TRUE; @@ -186,6 +207,33 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { size_t cs_len = imquic_moq_add_client_setup(moq, buffer, blen, ¶meters); imquic_connection_send_on_stream(moq->conn, moq->control_stream_id, buffer, cs_len, FALSE); + } else if(moq->version >= IMQUIC_MOQ_VERSION_17) { + /* New version, generate a SETUP no matter the role */ + imquic_moq_setup_options parameters = { 0 }; + if(moq->local_max_auth_token_cache_size > 0) { + parameters.max_auth_token_cache_size_set = TRUE; + parameters.max_auth_token_cache_size = moq->local_max_auth_token_cache_size; + } + if(moq->auth != NULL && moq->authlen > 0) { + parameters.auth_token_set = TRUE; + if(moq->authlen > sizeof(parameters.auth_token)) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] Auth token too large (%zu > %zu), it will be truncated\n", + imquic_get_connection_name(moq->conn), moq->authlen, sizeof(parameters.auth_token)); + moq->authlen = sizeof(parameters.auth_token); + } + memcpy(parameters.auth_token, moq->auth, moq->authlen); + parameters.auth_token_len = moq->authlen; + } + /* Add the implementation */ + parameters.moqt_implementation_set = TRUE; + g_snprintf(parameters.moqt_implementation, sizeof(parameters.moqt_implementation), "imquic %s", imquic_version_string_full); + /* TODO For raw quic connections, we should expose ways to + * fill in and use the PATH and ATTRIBUTE parameters as well */ + uint8_t buffer[200]; + size_t blen = sizeof(buffer); + size_t cs_len = imquic_moq_add_setup(moq, buffer, blen, ¶meters); + imquic_connection_send_on_stream(moq->conn, moq->control_stream_id, + buffer, cs_len, FALSE); } } @@ -207,17 +255,23 @@ void imquic_moq_stream_incoming(imquic_connection *conn, uint64_t stream_id, uint64_t actual_id = 0; gboolean client_initiated = FALSE, bidirectional = FALSE; imquic_parse_stream_id(stream_id, &actual_id, &client_initiated, &bidirectional); - if(!bidirectional) { - /* First stream we get is not a bidirectional control stream */ - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Not a bidirectional MoQ control stream\n", - imquic_get_connection_name(conn)); + if((moq->version <= IMQUIC_MOQ_VERSION_16 && !bidirectional) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && bidirectional)) { + /* FIXME Depending on the version, we'll be waiting for the remote + * control stream on either a bidirectional or unidirectional stream */ + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Not a %s MoQ control stream\n", + imquic_get_connection_name(conn), + (moq->version <= IMQUIC_MOQ_VERSION_16 ? "bidirectional" : "unidirectional")); return; } moq->has_control_stream = TRUE; - moq->control_stream_id = stream_id; + if(moq->version <= IMQUIC_MOQ_VERSION_16) + moq->control_stream_id = stream_id; + else + moq->remote_control_stream_id = stream_id; #ifdef HAVE_QLOG if(conn->qlog != NULL && conn->qlog->moq) - imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq->control_stream_id, "control"); + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, stream_id, "control"); #endif } imquic_moq_parse_message(moq, stream_id, bytes, length, complete, FALSE); @@ -520,6 +574,8 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "FETCH_CANCEL"; case IMQUIC_MOQ_FETCH_OK: return "FETCH_OK"; + case IMQUIC_MOQ_SETUP: + return "SETUP"; case IMQUIC_MOQ_CLIENT_SETUP: return "CLIENT_SETUP"; case IMQUIC_MOQ_SERVER_SETUP: @@ -905,7 +961,8 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, size_t offset = 0; if(options == NULL) { /* No options */ - offset += imquic_write_moqint(moq->version, 0, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, 0, &bytes[offset], blen-offset); } else { uint64_t new_id = 0, last_id = 0; GList *list = NULL; @@ -922,7 +979,8 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, if(options->moqt_implementation_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION)); *params_num = g_list_length(list); - offset += imquic_write_moqint(moq->version, *params_num, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, *params_num, &bytes[offset], blen-offset); if(list != NULL) { list = g_list_sort(list, imquic_moq_compare_types); GList *temp = list; @@ -1215,6 +1273,15 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { } while(0) /* Parse MoQ messages */ +static uint64_t imquic_moq_get_control_stream(imquic_moq_context *moq) { + return (moq->version <= IMQUIC_MOQ_VERSION_16) ? moq->control_stream_id : moq->remote_control_stream_id; +} +static gboolean imquic_moq_is_control_stream(imquic_moq_context *moq, uint64_t stream_id) { + if((moq->version <= IMQUIC_MOQ_VERSION_16 && stream_id == moq->control_stream_id) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && stream_id == moq->remote_control_stream_id)) + return TRUE; + return FALSE; +} int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_t *bytes, size_t blen, gboolean complete, gboolean datagram) { size_t offset = 0, parsed = 0, parsed_prev = 0; uint8_t tlen = 0, error = 0; @@ -1245,7 +1312,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } /* Check if this is a media stream */ imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams, &stream_id); - if(stream_id == moq->control_stream_id) { + if(imquic_moq_is_control_stream(moq, stream_id)) { imquic_buffer_append(moq->buffer, bytes, blen); bytes = moq->buffer->bytes; blen = moq->buffer->length; @@ -1262,7 +1329,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_moq_message_type type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &tlen); IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ][%zu] >> %s (%02x, %u)\n", imquic_get_connection_name(moq->conn), offset, imquic_moq_message_type_str(type, moq->version), type, tlen); - if(stream_id != moq->control_stream_id && moq_stream == NULL) { + if(!imquic_moq_is_control_stream(moq, stream_id) && moq_stream == NULL) { /* Not the control stream, check what it's for (namespaces * or objects) and then make sure it's a supported message */ gboolean bidirectional = FALSE; @@ -1298,7 +1365,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } parsed_prev = parsed; offset += tlen; - if(stream_id == moq->control_stream_id) { + if(imquic_moq_is_control_stream(moq, stream_id)) { /* Control message */ size_t plen = blen-offset; tlen = 2; @@ -1318,7 +1385,10 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_get_connection_name(moq->conn), plen, blen-offset); goto done; } - if(type == IMQUIC_MOQ_CLIENT_SETUP) { + if(type == IMQUIC_MOQ_SETUP) { + /* Parse this SETUP message */ + parsed = imquic_moq_parse_setup(moq, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_CLIENT_SETUP) { /* Parse this CLIENT_SETUP message */ parsed = imquic_moq_parse_client_setup(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_SERVER_SETUP) { @@ -1387,7 +1457,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("unknown"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, &bytes[offset], plen, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, stream_id, &bytes[offset], plen, message); } #endif imquic_buffer_shift(moq->buffer, plen); @@ -1584,16 +1654,10 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 5) - return 0; - if(!moq->is_server) { - /* Got a CLIENT_SETUP but we're a client */ - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Received a CLIENT_SETUP, but we're a client\n", - imquic_get_connection_name(moq->conn)); - if(error) - *error = IMQUIC_MOQ_PROTOCOL_VIOLATION; + if(bytes == NULL || blen < 1) return 0; - } + IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "CLIENT_SETUP was deprecated"); + IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Received a CLIENT_SETUP, but we're a client"); size_t offset = 0; uint8_t length = 0; uint64_t opts_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -1643,7 +1707,7 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si json_t *message = imquic_qlog_moq_message_prepare("client_setup"); json_object_set_new(message, "number_of_options", json_integer(opts_num)); imquic_qlog_moq_message_add_setup_options(message, &options, "setup_options"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application, if we have a callback */ @@ -1685,7 +1749,9 @@ size_t imquic_moq_parse_client_setup(imquic_moq_context *moq, uint8_t *bytes, si size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; - if(bytes == NULL || blen < 5) + IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "SERVER_SETUP was deprecated"); + IMQUIC_MOQ_CHECK_ERR(moq->is_server, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Received a SERVER_SETUP, but we're a server"); + if(bytes == NULL || blen < 1) return 0; size_t offset = 0; uint8_t length = 0; @@ -1735,7 +1801,7 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si json_t *message = imquic_qlog_moq_message_prepare("server_setup"); json_object_set_new(message, "number_of_options", json_integer(opts_num)); imquic_qlog_moq_message_add_setup_options(message, &options, "setup_options"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application the session is ready */ @@ -1747,9 +1813,66 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si return offset; } +size_t imquic_moq_parse_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { + if(error) + *error = IMQUIC_MOQ_UNKNOWN_ERROR; + IMQUIC_MOQ_CHECK_ERR(moq->version <= IMQUIC_MOQ_VERSION_16, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "SETUP unsupported on older versions"); + /* Parse the SETUP options */ + size_t offset = 0; + imquic_moq_setup_options options = { 0 }; + uint64_t opt = 0; + while(bytes != NULL && offset < blen) { + offset += imquic_moq_parse_setup_option(moq, &bytes[offset], blen-offset, &options, &opt, error); + IMQUIC_MOQ_CHECK_ERR(error && *error, NULL, 0, 0, "Broken SETUP"); + } + if(options.max_auth_token_cache_size_set) { + /* Update the value we have */ + moq->max_auth_token_cache_size = options.max_auth_token_cache_size; + } + if(options.moqt_implementation_set) { + /* Take note of the implemntation */ + g_free(moq->peer_implementation); + moq->peer_implementation = NULL; + if(strlen(options.moqt_implementation) > 0) + moq->peer_implementation = g_strdup(options.moqt_implementation); + } + if(options.path_set) { + /* Servers can't use PATH */ + IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_INVALID_PATH, 0, "PATH received from a server"); + } + if(options.authority_set) { + /* Servers can't use AUTHORITY */ + IMQUIC_MOQ_CHECK_ERR(!moq->is_server, error, IMQUIC_MOQ_INVALID_PATH, 0, "AUTHORITY received from a server"); + } + if(moq->max_request_id == 0) { + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] No Max Request ID option received, setting it to 1\n", + imquic_get_connection_name(moq->conn)); + moq->max_request_id = 1; + } +#ifdef HAVE_QLOG + if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + json_t *message = imquic_qlog_moq_message_prepare("setup"); + imquic_qlog_moq_message_add_setup_options(message, &options, "setup_options"); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + } +#endif + /* Notify the application the session is ready, if we're done */ + moq->recvd_setup = TRUE; + /* FIXME */ + if(moq->recvd_setup && moq->sent_setup) { + g_atomic_int_set(&moq->connected, 1); + if(moq->conn->socket && moq->conn->socket->callbacks.moq.moq_ready) + moq->conn->socket->callbacks.moq.moq_ready(moq->conn); + } + if(error) + *error = 0; + return offset; +} + size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; + IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "SERVER_SETUP was deprecated"); if(bytes == NULL || blen < 1) return 0; size_t offset = 0; @@ -1766,7 +1889,7 @@ size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("max_request_id"); json_object_set_new(message, "request_id", json_integer(max)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif if(error) @@ -1790,7 +1913,7 @@ size_t imquic_moq_parse_requests_blocked(imquic_moq_context *moq, uint8_t *bytes if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("requests_blocked"); json_object_set_new(message, "maximum_request_id", json_integer(max)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -1836,7 +1959,7 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, - (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes-3, offset+3, message); + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Notify the application, but we'll need to check which callback to trigger */ @@ -1921,7 +2044,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream if(reason_str != NULL) json_object_set_new(message, "reason", json_string(reason_str)); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, - (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes-3, offset+3, message); + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Notify the application, but we'll need to check which callback to trigger */ @@ -2004,7 +2127,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *byte imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2037,7 +2160,7 @@ size_t imquic_moq_parse_publish_namespace_done(imquic_moq_context *moq, uint8_t if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_namespace_done"); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2088,7 +2211,7 @@ size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_ json_object_set_new(message, "error_code", json_integer(error_code)); if(reason_str != NULL) json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2160,7 +2283,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2212,7 +2335,7 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2264,7 +2387,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2325,7 +2448,7 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2397,7 +2520,7 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2435,7 +2558,7 @@ size_t imquic_moq_parse_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, siz if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("unsubscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2492,7 +2615,7 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "streams_count", json_integer(streams_count)); if(reason_str != NULL) json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2551,7 +2674,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, - (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes-3, offset+3, message); + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2735,7 +2858,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2798,7 +2921,7 @@ size_t imquic_moq_parse_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, si if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch_cancel"); json_object_set_new(message, "request_id", json_integer(request_id)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2876,7 +2999,7 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2929,7 +3052,7 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -3497,7 +3620,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b imquic_qlog_event_add_raw(message, "new_session_uri", (uint8_t *)uri_str, uri_len); if(moq->version >= IMQUIC_MOQ_VERSION_17) json_object_set_new(message, "timeout", json_integer(timeout)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq->control_stream_id, bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif IMQUIC_MOQ_CHECK_ERR(!g_atomic_int_compare_and_exchange(&moq->got_goaway, 0, 1), @@ -3513,7 +3636,7 @@ size_t imquic_moq_parse_goaway(imquic_moq_context *moq, uint8_t *bytes, size_t b /* Message building */ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_setup_options *options) { - if(bytes == NULL || blen < 2) { + if(bytes == NULL || blen < 2 || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_CLIENT_SETUP, moq->version)); return 0; @@ -3536,7 +3659,7 @@ size_t imquic_moq_add_client_setup(imquic_moq_context *moq, uint8_t *bytes, size size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_setup_options *options) { - if(bytes == NULL || blen < 2) { + if(bytes == NULL || blen < 2 || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SERVER_SETUP, moq->version)); return 0; @@ -3546,6 +3669,28 @@ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size uint8_t opts_num = 0; offset += imquic_moq_setup_options_serialize(moq, options, &bytes[offset], blen-offset, &opts_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); +#ifdef HAVE_QLOG + if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + json_t *message = imquic_qlog_moq_message_prepare("setup"); + imquic_qlog_moq_message_add_setup_options(message, options, "setup_options"); + imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + } +#endif + return offset; +} + +size_t imquic_moq_add_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + imquic_moq_setup_options *options) { + if(bytes == NULL || blen < 2 || moq->version <= IMQUIC_MOQ_VERSION_16) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", + imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SETUP, moq->version)); + return 0; + } + size_t offset = 0, len_offset = 0; + IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SETUP); + uint8_t opts_num = 0; + offset += imquic_moq_setup_options_serialize(moq, options, &bytes[offset], blen-offset, &opts_num); + IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("server_setup"); @@ -3558,7 +3703,7 @@ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size } size_t imquic_moq_add_max_request_id(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t max_request_id) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_MAX_REQUEST_ID, moq->version)); return 0; @@ -3578,7 +3723,7 @@ size_t imquic_moq_add_max_request_id(imquic_moq_context *moq, uint8_t *bytes, si } size_t imquic_moq_add_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t max_request_id) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUESTS_BLOCKED, moq->version)); return 0; @@ -3706,7 +3851,7 @@ size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *b size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace, imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || track_namespace == NULL || (reason && strlen(reason) > 1024)) { + if(bytes == NULL || blen < 1 || track_namespace == NULL || (reason && strlen(reason) > 1024) || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL, moq->version)); return 0; @@ -4080,7 +4225,7 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen } size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_FETCH_CANCEL, moq->version)); return 0; From 78b70be128934fcc6871fef12f47d756fe647d99 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 6 Mar 2026 11:48:27 +0100 Subject: [PATCH 13/30] Buffer STREAM data if MoQ connection hasnt been SETUP yet --- examples/moq-pub.c | 2 +- src/imquic/moq.h | 24 +++++-- src/internal/moq.h | 171 ++++++++------------------------------------- src/moq.c | 131 ++++++++++++++++++++++++++++------ 4 files changed, 158 insertions(+), 170 deletions(-) diff --git a/examples/moq-pub.c b/examples/moq-pub.c index 266e5c7..530627e 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -459,7 +459,7 @@ int main(int argc, char *argv[]) { if(options.publish) { IMQUIC_LOG(IMQUIC_LOG_INFO, "Will use PUBLISH instead of PUBLISH_NAMESPACE + SUBSCRIBE\n"); } - IMQUIC_LOG(IMQUIC_LOG_INFO, "Will use track_alias=%"SCNu64", if a version higher or equal than 12 is negotiated\n", + IMQUIC_LOG(IMQUIC_LOG_INFO, "Will use track_alias=%"SCNu64"\n", options.track_alias); moq_track_alias = options.track_alias; diff --git a/src/imquic/moq.h b/src/imquic/moq.h index c972fc1..d8aede4 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -858,8 +858,11 @@ void imquic_set_moq_ready_cb(imquic_endpoint *endpoint, void imquic_set_incoming_publish_namespace_cb(imquic_endpoint *endpoint, void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's - * an incoming \c PUBLISH_NAMESPACE_CANCEL request (legacy), or when - * the associated stream is closed (new draft versions) + * an incoming \c PUBLISH_NAMESPACE_CANCEL request. + * \note Starting in v17, \c PUBLISH_NAMESPACE_CANCEL doesn't exist anymore, + * so this callback is only fired if the endpoint that sent the + * \c PUBLISH_NAMESPACE closed the associated bidirectiomal stream before + * getting a \c REQUEST_OK or \c REQUEST_ERROR back. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_publish_namespace_cancel Pointer to the function that will handle the incoming \c PUBLISH_NAMESPACE_CANCEL */ void imquic_set_incoming_publish_namespace_cancel_cb(imquic_endpoint *endpoint, @@ -878,6 +881,10 @@ void imquic_set_publish_namespace_error_cb(imquic_endpoint *endpoint, void (* publish_namespace_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval)); /*! \brief Configure the callback function to be notified when there's * an incoming \c PUBLISH_NAMESPACE_DONE request. + * \note Starting in v17, \c PUBLISH_NAMESPACE_DONE doesn't exist anymore, + * so this callback is only fired if the endpoint that sent the + * \c PUBLISH_NAMESPACE closed the associated bidirectiomal stream after + * getting a \c REQUEST_OK or \c REQUEST_ERROR back. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param publish_namespace_done Pointer to the function that will handle the incoming \c PUBLISH_NAMESPACE_DONE */ void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, @@ -946,6 +953,9 @@ void imquic_set_publish_done_cb(imquic_endpoint *endpoint, void (* publish_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_pub_done_code status_code, uint64_t streams_count, const char *reason)); /*! \brief Configure the callback function to be notified when there's * an incoming \c UNSUBSCRIBE request. + * \note Starting in v17, \c UNSUBSCRIBE doesn't exist anymore, + * so this callback is only fired if the endpoint that sent the + * \c SUBSCRIBE closed the associated bidirectiomal stream. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_unsubscribe Pointer to the function that will handle the incoming \c UNSUBSCRIBE */ void imquic_set_incoming_unsubscribe_cb(imquic_endpoint *endpoint, @@ -978,6 +988,9 @@ void imquic_set_subscribe_namespace_error_cb(imquic_endpoint *endpoint, void (* subscribe_namespace_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval)); /*! \brief Configure the callback function to be notified when there's * an incoming \c UNSUBSCRIBE_NAMESPACE request. + * \note On newer versions, \c UNSUBSCRIBE_NAMESPACE doesn't exist anymore, + * so this callback is only fired if the endpoint that sent the + * \c SUBSCRIBE_NAMESPACE closed the associated bidirectiomal stream. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_unsubscribe_namespace Pointer to the function that will handle the incoming \c UNSUBSCRIBE_NAMESPACE */ void imquic_set_incoming_unsubscribe_namespace_cb(imquic_endpoint *endpoint, @@ -1009,8 +1022,11 @@ void imquic_set_incoming_joining_fetch_cb(imquic_endpoint *endpoint, void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's - * an incoming \c FETCH_CANCEL request (legacy), or when - * the associated stream is closed (new draft versions) + * an incoming \c FETCH_CANCEL request. + * \note Starting in v17, \c FETCH_CANCEL doesn't exist anymore, + * so this callback is only fired if the endpoint that sent the + * \c FETCH closed the associated bidirectiomal stream before + * getting a \c FETCH_OK or \c REQUEST_ERROR back. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_fetch_cancel Pointer to the function that will handle the incoming \c FETCH_CANCEL */ void imquic_set_incoming_fetch_cancel_cb(imquic_endpoint *endpoint, diff --git a/src/internal/moq.h b/src/internal/moq.h index 3828a75..e62e643 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -341,6 +341,8 @@ typedef struct imquic_moq_context { imquic_mutex mutex; /*! \brief Whether we have established a connection */ volatile gint connected; + /*! \brief Check if it's time to handle pending streams */ + volatile gint check_pending; /*! \brief Whether we have received a GOAWAY */ volatile gint got_goaway; /*! \brief Whether this instance has been destroyed (reference counting) */ @@ -351,13 +353,15 @@ typedef struct imquic_moq_context { /*! \brief MoQ stream * \note This is usually used for objects (e.g., via SUBGROUP_HEADER or - * FETCH), but starting in v16, namespace advertising uses streams too */ + * FETCH), but starting in v16, requests can use streams too */ typedef struct imquic_moq_stream { /*! \brief QUIC stream ID */ uint64_t stream_id; - /* Whether this STREAM is used for objects, or namespaces */ - gboolean subscribe_namespace, namespace_publisher; - /* State of SUBSCRIBE_NAMESPACE */ + /*! In case this is a bidirectional STREAM for a request, the associated request type */ + imquic_moq_message_type request_type; + /* In case this is for SUBSCRIBE_NAMESPACE, whether this is a publisher or subscriber side */ + gboolean namespace_publisher; + /* In case this is for SUBSCRIBE_NAMESPACE, the state of SUBSCRIBE_NAMESPACE */ volatile gint subscribe_namespace_state; /*! \brief In case this is for SUBSCRIBE_NAMESPACE, the namespace prefix */ imquic_moq_namespace *namespace_prefix, *last_tuple; @@ -462,6 +466,7 @@ size_t imquic_moq_parse_server_setup(imquic_moq_context *moq, uint8_t *bytes, si * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c MAX_REQUEST_ID message + * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -469,6 +474,7 @@ size_t imquic_moq_parse_setup(imquic_moq_context *moq, uint8_t *bytes, size_t bl * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c REQUESTS_BLOCKED message + * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -499,6 +505,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_NAMESPACE_DONE message + * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -506,6 +513,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *byte * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_NAMESPACE_CANCEL message + * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -526,13 +534,6 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c PUBLISH_ERROR message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c SUBSCRIBE message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse @@ -554,14 +555,8 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c SUBSCRIBE_ERROR message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_subscribe_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse an \c UNSUBSCRIBE message + * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -590,20 +585,6 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_subscribe_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c SUBSCRIBE_NAMESPACE_ERROR message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_subscribe_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse an \c UNSUBSCRIBE_NAMESPACE message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c NAMESPACE message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] moq_stream The imquic_moq_stream instance the message came from @@ -628,6 +609,7 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c FETCH_CANCEL message + * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse @@ -641,13 +623,6 @@ size_t imquic_moq_parse_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, si * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c FETCH_ERROR message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_fetch_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c TRACK_STATUS message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse @@ -655,20 +630,6 @@ size_t imquic_moq_parse_fetch_error(imquic_moq_context *moq, uint8_t *bytes, siz * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c TRACK_STATUS_OK message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_track_status_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c TRACK_STATUS_ERROR message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_track_status_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse an \c OBJECT_DATAGRAM message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse @@ -759,6 +720,7 @@ size_t imquic_moq_add_server_setup(imquic_moq_context *moq, uint8_t *bytes, size size_t imquic_moq_add_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_setup_options *options); /*! \brief Helper method to add a \c MAX_REQUEST_ID message to a buffer + * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -766,6 +728,7 @@ size_t imquic_moq_add_setup(imquic_moq_context *moq, uint8_t *bytes, size_t blen * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_max_request_id(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t max_request_id); /*! \brief Helper method to add a \c REQUESTS_BLOCKED message to a buffer + * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -811,24 +774,16 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, * @param request_id The request ID to put in the message * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); -/*! \brief Helper method to add a \c PUBLISH_NAMESPACE_ERROR message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param error Error code associated to the message - * @param reason Verbose description of the error, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason); /*! \brief Helper method to add a \c PUBLISH_NAMESPACE_DONE message to a buffer + * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param track_namespace Namespace to publish_namespace_done * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace); -/*! \brief Helper method to add aN \c PUBLISH_NAMESPACE_CANCEL message to a buffer +/*! \brief Helper method to add a \c PUBLISH_NAMESPACE_CANCEL message to a buffer + * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -861,16 +816,6 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_request_parameters *parameters); -/*! \brief Helper method to add a \c PUBLISH_ERRROR message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param error Error code associated to the message - * @param reason Verbose description of the error, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_error_code error, const char *reason); /*! \brief Helper to add a \c SUBSCRIBE message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -903,17 +848,8 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); -/*! \brief Helper method to add a \c SUBSCRIBE_ERRROR message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param error Error code associated to the message - * @param reason Verbose description of the error, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_error_code error, const char *reason); /*! \brief Helper method to add an \c UNSUBSCRIBE message to a buffer + * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -943,30 +879,6 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters); -/*! \brief Helper method to add a \c SUBSCRIBE_NAMESPACE_OK message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); -/*! \brief Helper method to add a \c SUBSCRIBE_NAMESPACE_ERRROR message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param error Error code associated to the message - * @param reason Verbose description of the error, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe_namespace_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_request_error_code error, const char *reason); -/*! \brief Helper method to add an \c UNSUBSCRIBE_NAMESPACE message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_unsubscribe_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); /*! \brief Helper method to add a \c NAMESPACE_DONE message to a buffer * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for @@ -1003,6 +915,7 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add an \c FETCH_CANCEL message to a buffer + * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer @@ -1021,16 +934,6 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_properties); -/*! \brief Helper method to add a \c FETCH_ERRROR message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param error Error code associated to the message - * @param reason Verbose description of the error, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_fetch_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_error_code error, const char *reason); /*! \brief Helper to add a \c TRACK_STATUS message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -1042,26 +945,6 @@ size_t imquic_moq_add_fetch_error(imquic_moq_context *moq, uint8_t *bytes, size_ * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters); -/*! \brief Helper method to add a \c TRACK_STATUS_OK message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param track_alias The track alias to put in the message - * @param parameters The parameters to add, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_track_status_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - uint64_t track_alias, imquic_moq_request_parameters *parameters); -/*! \brief Helper method to add a \c TRACK_STATUS_ERRROR message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @param error Error code associated to the message - * @param reason Verbose description of the error, if any - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_track_status_error(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_error_code error, const char *reason); /*! \brief Helper method to add a \c GOAWAY message to a buffer * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to @@ -1259,13 +1142,14 @@ typedef struct imquic_moq_callbacks { void (* moq_ready)(imquic_connection *conn); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE messages */ void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters); - /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_CANCEL messages */ + /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_CANCEL messages, or when the bidirectional stream is closed */ void (* incoming_publish_namespace_cancel)(imquic_connection *conn, imquic_moq_namespace *tns, imquic_moq_request_error_code error_code, const char *reason); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_ACCEPTED messages */ void (* publish_namespace_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_ERROR messages */ void (* publish_namespace_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); - /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_DONE messages */ + /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_DONE messages + * \note This message was deprecated in v17 */ void (* publish_namespace_done)(imquic_connection *conn, imquic_moq_namespace *tns); /*! \brief Callback function to be notified about incoming \c PUBLISH messages */ void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, @@ -1289,9 +1173,10 @@ typedef struct imquic_moq_callbacks { void (* request_update_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c PUBLISH_DONE messages */ void (* publish_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_pub_done_code status_code, uint64_t streams_count, const char *reason); - /*! \brief Callback function to be notified about incoming \c UNBSUBSCRIBE messages */ + /*! \brief Callback function to be notified about incoming \c UNBSUBSCRIBE messages, or when the bidirectional stream is closed */ void (* incoming_unsubscribe)(imquic_connection *conn, uint64_t request_id); - /*! \brief Callback function to be notified about incoming \c REQUESTS_BLOCKED messages */ + /*! \brief Callback function to be notified about incoming \c REQUESTS_BLOCKED messages + * \note This message was deprecated in v17 */ void (* requests_blocked)(imquic_connection *conn, uint64_t max_request_id); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_NAMESPACE messages */ void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, @@ -1311,7 +1196,7 @@ typedef struct imquic_moq_callbacks { imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters); - /*! \brief Callback function to be notified about incoming \c FETCH_CANCEL messages */ + /*! \brief Callback function to be notified about incoming \c FETCH_CANCEL messages, or when the bidirectional stream is closed */ void (* incoming_fetch_cancel)(imquic_connection *conn, uint64_t request_id); /*! \brief Callback function to be notified about incoming \c FETCH_ACCEPTED messages */ void (* fetch_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_location *largest, imquic_moq_request_parameters *parameters, GList *track_properties); diff --git a/src/moq.c b/src/moq.c index 19d412f..2c61832 100644 --- a/src/moq.c +++ b/src/moq.c @@ -35,6 +35,20 @@ static GHashTable *moq_sessions = NULL; static imquic_mutex moq_mutex = IMQUIC_MUTEX_INITIALIZER; +/* Buffering of streams/requests, where needed */ +typedef struct imquic_moq_pending_stream { + uint64_t stream_id; + imquic_buffer *buffer; + gboolean complete; +} imquic_moq_pending_stream; +static void imquic_moq_pending_stream_destroy(imquic_moq_pending_stream *stream) { + if(stream != NULL) { + imquic_buffer_destroy(stream->buffer); + g_free(stream); + } +} +static GHashTable *moq_pending_streams = NULL; + /* MoQ's flavour of varint (introduced in v17) */ uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length); uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen); @@ -44,6 +58,7 @@ static void imquic_moq_context_destroy(imquic_moq_context *moq); static void imquic_moq_context_free(const imquic_refcount *moq_ref); void imquic_moq_init(void) { moq_sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)imquic_moq_context_destroy); + moq_pending_streams = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_hash_table_unref); } void imquic_moq_deinit(void) { @@ -51,6 +66,9 @@ void imquic_moq_deinit(void) { if(moq_sessions != NULL) g_hash_table_unref(moq_sessions); moq_sessions = NULL; + if(moq_pending_streams != NULL) + g_hash_table_unref(moq_pending_streams); + moq_pending_streams = NULL; imquic_mutex_unlock(&moq_mutex); } @@ -115,6 +133,49 @@ static gboolean moq_is_request_id_valid(imquic_moq_context *moq, uint64_t reques return TRUE; } +/* Helpers to manage pending streams */ +static void imquic_moq_track_pending_stream(imquic_connection *conn, uint64_t stream_id, uint8_t *bytes, size_t length, gboolean complete) { + imquic_mutex_lock(&moq_mutex); + GHashTable *streams = g_hash_table_lookup(moq_pending_streams, conn); + if(streams == NULL) { + /* No map for this connection yet, create it now */ + streams = g_hash_table_new_full(g_int64_hash, g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)imquic_moq_pending_stream_destroy); + g_hash_table_insert(moq_pending_streams, conn, streams); + } + /* Keep track of the stream data */ + imquic_moq_pending_stream *stream = g_hash_table_lookup(streams, &stream_id); + if(stream == NULL) { + stream = g_malloc0(sizeof(imquic_moq_pending_stream)); + stream->stream_id = stream_id; + stream->buffer = imquic_buffer_create(NULL, 0); + g_hash_table_insert(streams, imquic_uint64_dup(stream_id), stream); + } + imquic_buffer_append(stream->buffer, bytes, length); + stream->complete = complete; + imquic_mutex_unlock(&moq_mutex); +} + +static void imquic_moq_handle_pending_streams(imquic_connection *conn) { + GHashTable *streams = NULL; + imquic_mutex_lock(&moq_mutex); + g_hash_table_steal_extended(moq_pending_streams, conn, + NULL, (gpointer *)&streams); + imquic_mutex_unlock(&moq_mutex); + /* Iterate on the streams list and cleanup */ + if(streams != NULL) { + GHashTableIter iter; + gpointer value; + g_hash_table_iter_init(&iter, streams); + while(g_hash_table_iter_next(&iter, NULL, &value)) { + imquic_moq_pending_stream *stream = value; + imquic_moq_stream_incoming(conn, stream->stream_id, + stream->buffer->bytes, stream->buffer->length, stream->complete); + } + g_hash_table_unref(streams); + } +} + /* Callbacks */ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { /* Got new connection */ @@ -145,6 +206,8 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { imquic_refcount_init(&moq->ref, imquic_moq_context_free); imquic_mutex_lock(&moq_mutex); g_hash_table_insert(moq_sessions, conn, moq); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + g_hash_table_remove(moq_pending_streams, conn); imquic_mutex_unlock(&moq_mutex); /* Let's check if we need to create a control stream */ if(moq->version <= IMQUIC_MOQ_VERSION_16) { @@ -235,6 +298,8 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { imquic_connection_send_on_stream(moq->conn, moq->control_stream_id, buffer, cs_len, FALSE); } + /* Check if there are streams we kept on hold because we didn't have a context */ + imquic_moq_handle_pending_streams(conn); } void imquic_moq_stream_incoming(imquic_connection *conn, uint64_t stream_id, @@ -247,21 +312,33 @@ void imquic_moq_stream_incoming(imquic_connection *conn, uint64_t stream_id, imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); imquic_mutex_unlock(&moq_mutex); if(moq == NULL) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Ignoring incoming STREAM data on unknown context\n", + /* FIXME For newer versions, we may get bidirectional stream data + * from requests before we get the SETUP on the unidirectional + * control stream, which means we need to buffer data for later */ + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Buffering incoming STREAM data on unknown context\n", imquic_get_connection_name(conn)); + imquic_moq_track_pending_stream(conn, stream_id, bytes, length, complete); return; } if(!moq->has_control_stream) { uint64_t actual_id = 0; gboolean client_initiated = FALSE, bidirectional = FALSE; imquic_parse_stream_id(stream_id, &actual_id, &client_initiated, &bidirectional); - if((moq->version <= IMQUIC_MOQ_VERSION_16 && !bidirectional) || - (moq->version >= IMQUIC_MOQ_VERSION_17 && bidirectional)) { - /* FIXME Depending on the version, we'll be waiting for the remote - * control stream on either a bidirectional or unidirectional stream */ - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Not a %s MoQ control stream\n", - imquic_get_connection_name(conn), - (moq->version <= IMQUIC_MOQ_VERSION_16 ? "bidirectional" : "unidirectional")); + /* FIXME Depending on the version, we'll be waiting for the remote + * control stream on either a bidirectional or unidirectional stream */ + if(moq->version <= IMQUIC_MOQ_VERSION_16 && !bidirectional) { + /* Legacy version, we need a bidirectional control stream as a first thing */ + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Not a bidirectional MoQ control stream\n", + imquic_get_connection_name(conn)); + return; + } else if(moq->version >= IMQUIC_MOQ_VERSION_17 && bidirectional) { + /* New version, the remote control stream will be unidirectional, + * but we may get some bidirectional streams for requests too + * in the meanwhile: if that happens, queue that data, and we + * will handle it later, once the control stream has been setup */ + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Not a unidirectional MoQ control stream, buffering stream %"SCNu64" data\n", + imquic_get_connection_name(conn), stream_id); + imquic_moq_track_pending_stream(conn, stream_id, bytes, length, complete); return; } moq->has_control_stream = TRUE; @@ -275,6 +352,14 @@ void imquic_moq_stream_incoming(imquic_connection *conn, uint64_t stream_id, #endif } imquic_moq_parse_message(moq, stream_id, bytes, length, complete, FALSE); + /* After we've handled this stream, check if there is pending stream + * data we should process now: this can happen in newer MoQ versions + * if we received data from a bidirectional stream (e.g., a request) + * before we received the SETUP on the unidirectional control stream */ + if(g_atomic_int_compare_and_exchange(&moq->check_pending, 1, 0)) { + /* We do, check if there are streams to process */ + imquic_moq_handle_pending_streams(conn); + } } void imquic_moq_datagram_incoming(imquic_connection *conn, uint8_t *bytes, uint64_t length) { @@ -306,7 +391,7 @@ void imquic_moq_reset_stream_incoming(imquic_connection *conn, uint64_t stream_i } IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Got RESET_STREAM for STREAM %"SCNu64": %"SCNu64" (%s)\n", imquic_get_connection_name(conn), stream_id, error_code, imquic_moq_reset_stream_code_str(error_code)); - if(!moq_stream->subscribe_namespace) { + if(moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { /* FIXME Not the SUBSCRIBE_NAMESPACE stream, we ignore it for now */ imquic_mutex_unlock(&moq->mutex); return; @@ -348,6 +433,7 @@ void imquic_moq_connection_gone(imquic_connection *conn) { /* Connection was closed */ imquic_mutex_lock(&moq_mutex); gboolean removed = g_hash_table_remove(moq_sessions, conn); + g_hash_table_remove(moq_pending_streams, conn); imquic_mutex_unlock(&moq_mutex); if(conn->socket && conn->socket->callbacks.moq.connection_gone) conn->socket->callbacks.moq.connection_gone(conn); @@ -1316,7 +1402,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_buffer_append(moq->buffer, bytes, blen); bytes = moq->buffer->bytes; blen = moq->buffer->length; - } else if(moq_stream != NULL && moq_stream->subscribe_namespace) { + } else if(moq_stream != NULL && moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { if(moq_stream->buffer == NULL) moq_stream->buffer = imquic_buffer_create(NULL, 0); imquic_buffer_append(moq_stream->buffer, bytes, blen); @@ -1324,7 +1410,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ blen = moq_stream->buffer->length; } /* Iterate on all frames */ - while((moq_stream == NULL || moq_stream->subscribe_namespace) && blen-offset > 0) { + while((moq_stream == NULL || moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) && blen-offset > 0) { /* If we're here, we're either on the control stream, or on a media stream waiting to know what it will be like */ imquic_moq_message_type type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &tlen); IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ][%zu] >> %s (%02x, %u)\n", @@ -1341,7 +1427,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_get_connection_name(moq->conn), stream_id); moq_stream = g_malloc0(sizeof(imquic_moq_stream)); moq_stream->stream_id = stream_id; - moq_stream->subscribe_namespace = TRUE; + moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE_NAMESPACE; moq_stream->namespace_publisher = TRUE; g_hash_table_insert(moq->streams, imquic_dup_uint64(stream_id), moq_stream); moq_stream->buffer = imquic_buffer_create(bytes, blen); @@ -1483,7 +1569,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ bytes = moq->buffer->bytes; blen = moq->buffer->length; offset = 0; - } else if(moq_stream->subscribe_namespace) { + } else if(moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { /* Control message for namespaces advertisement */ size_t plen = blen-offset; tlen = 2; @@ -1573,7 +1659,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } } /* Check if we have a media stream to process */ - if(moq_stream != NULL && !moq_stream->subscribe_namespace && blen > offset) { + if(moq_stream != NULL && moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && blen > offset) { IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] MoQ media stream %"SCNu64" (%zu bytes)\n", imquic_get_connection_name(moq->conn), stream_id, blen - offset); /* Copy the incoming data to the buffer, as we'll use that for parsing */ @@ -1611,7 +1697,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ done: if(moq_stream != NULL && complete) { - if(moq_stream->subscribe_namespace) { + if(moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { /* The SUBSCRIBE_NAMESPACE dedicated bidirectional STREAM has been closed */ gboolean notify = moq_stream->namespace_publisher; uint64_t request_id = moq_stream->request_id; @@ -1861,6 +1947,7 @@ size_t imquic_moq_parse_setup(imquic_moq_context *moq, uint8_t *bytes, size_t bl /* FIXME */ if(moq->recvd_setup && moq->sent_setup) { g_atomic_int_set(&moq->connected, 1); + g_atomic_int_set(&moq->check_pending, 1); if(moq->conn->socket && moq->conn->socket->callbacks.moq.moq_ready) moq->conn->socket->callbacks.moq.moq_ready(moq->conn); } @@ -1929,7 +2016,7 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && + IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && (moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2))), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK for SUBSCRIBE_NAMESPACE"); size_t offset = 0; @@ -1999,7 +2086,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && + IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && (moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2))), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR for SUBSCRIBE_NAMESPACE"); size_t offset = 0; @@ -5529,7 +5616,7 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = g_malloc0(sizeof(imquic_moq_stream)); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); - moq_stream->subscribe_namespace = TRUE; + moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE_NAMESPACE; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -5570,7 +5657,7 @@ int imquic_moq_accept_subscribe_namespace(imquic_connection *conn, uint64_t requ * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { imquic_mutex_unlock(&moq->mutex); IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", @@ -5606,7 +5693,7 @@ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t requ * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { imquic_mutex_unlock(&moq->mutex); IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", @@ -5672,7 +5759,7 @@ int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, im /* Check if the request ID exists */ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || g_atomic_int_get(&moq_stream->subscribe_namespace_state) < 2 || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { imquic_mutex_unlock(&moq->mutex); @@ -5711,7 +5798,7 @@ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_i /* Check if the request ID exists */ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || !moq_stream->subscribe_namespace || !moq_stream->namespace_publisher || + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || g_atomic_int_get(&moq_stream->subscribe_namespace_state) < 2 || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { imquic_mutex_unlock(&moq->mutex); From dc0865cba7c5abc798b2d90bbbabd5e065ba10ee Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 6 Mar 2026 18:09:02 +0100 Subject: [PATCH 14/30] Moved requests to bidirectional streams (WIP) --- examples/moq-interop-test.c | 19 +- examples/moq-pub.c | 19 +- examples/moq-relay.c | 52 +- examples/moq-sub.c | 12 +- src/imquic-moq.c | 6 +- src/imquic/moq.h | 13 +- src/internal/moq.h | 113 ++-- src/moq.c | 1189 +++++++++++++++++++++++++---------- 8 files changed, 970 insertions(+), 453 deletions(-) diff --git a/examples/moq-interop-test.c b/examples/moq-interop-test.c index 0ff7fd3..ff6a219 100644 --- a/examples/moq-interop-test.c +++ b/examples/moq-interop-test.c @@ -84,6 +84,7 @@ typedef struct imquic_moq_interop_client { imquic_client *client; imquic_connection *conn; gboolean publisher; + uint64_t request_id; } imquic_moq_interop_client; static void imquic_moq_interop_client_destroy(imquic_moq_interop_client *mc) { if(mc != NULL) { @@ -525,7 +526,8 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { tns[1].buffer = (uint8_t *)"interop"; tns[1].length = strlen("interop"); tns[1].next = NULL; - imquic_moq_publish_namespace(conn, imquic_moq_get_next_request_id(conn), &tns[0], NULL); + client->request_id = imquic_moq_get_next_request_id(conn); + imquic_moq_publish_namespace(conn, client->request_id, &tns[0], NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("publisher announced namespace")); } else if(test->name == IMQUIC_INTEROP_SUBSCRIBE_ERROR) { @@ -541,7 +543,8 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { .buffer = (uint8_t *)"test-track", .length = strlen("test-track") }; - imquic_moq_subscribe(conn, imquic_moq_get_next_request_id(conn), &tns[0], &tn, NULL); + client->request_id = imquic_moq_get_next_request_id(conn); + imquic_moq_subscribe(conn, client->request_id, &tns[0], &tn, NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("subscriber subscribed to non-existing track")); } else if((test->name == IMQUIC_INTEROP_ANNOUNCE_SUBSCRIBE || @@ -558,7 +561,8 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { .buffer = (uint8_t *)"test-track", .length = strlen("test-track") }; - imquic_moq_subscribe(conn, imquic_moq_get_next_request_id(conn), &tns[0], &tn, NULL); + client->request_id = imquic_moq_get_next_request_id(conn); + imquic_moq_subscribe(conn, client->request_id, &tns[0], &tn, NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("subscriber subscribed to track")); if(test->name == IMQUIC_INTEROP_SUBSCRIBE_BEFORE_ANNOUNCE) { @@ -584,14 +588,7 @@ static void imquic_moq_interop_publish_namespace_accepted(imquic_connection *con g_atomic_int_set(&test->done, 1); } else if(test->name == IMQUIC_INTEROP_PUBLISH_NAMESPACE_DONE) { /* Send a PUBLISH_NAMESPACE_DONE */ - imquic_moq_namespace tns[2]; - tns[0].buffer = (uint8_t *)"moq-test"; - tns[0].length = strlen("moq-test"); - tns[0].next = &tns[1]; - tns[1].buffer = (uint8_t *)"interop"; - tns[1].length = strlen("interop"); - tns[1].next = NULL; - int ret = imquic_moq_publish_namespace_done(conn, &tns[0]); + int ret = imquic_moq_publish_namespace_done(conn, client->request_id); if(ret == 0) { g_atomic_int_set(&test->success, 1); if(verbose) diff --git a/examples/moq-pub.c b/examples/moq-pub.c index 530627e..4885830 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -41,7 +41,7 @@ static void imquic_demo_handle_signal(int signum) { /* Publisher state */ static imquic_connection *moq_conn = NULL; static imquic_moq_version moq_version = IMQUIC_MOQ_VERSION_ANY; -static uint64_t moq_request_id = 0, moq_track_alias = 0; +static uint64_t moq_tns_request_id = 0, moq_request_id = 0, moq_track_alias = 0; static imquic_moq_delivery delivery = IMQUIC_MOQ_USE_SUBGROUP; static char pub_tns_buffer[256], pub_tn_buffer[256]; static const char *pub_tns = NULL, *pub_tn = NULL; @@ -119,7 +119,8 @@ static void imquic_demo_ready(imquic_connection *conn) { imquic_get_connection_name(conn)); } } - imquic_moq_publish_namespace(conn, imquic_moq_get_next_request_id(conn), &tns[0], ¶ms); + moq_tns_request_id = imquic_moq_get_next_request_id(conn); + imquic_moq_publish_namespace(conn, moq_tns_request_id, &tns[0], ¶ms); } else { /* We use PUBLISH */ IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publishing namespace/track '%s--%s'\n", imquic_get_connection_name(conn), pub_tns, pub_tn); @@ -610,18 +611,8 @@ int main(int argc, char *argv[]) { /* We're done, check if we need to send a PUBLISH_DONE and/or an PUBLISH_NAMESPACE_DONE */ if(g_atomic_int_get(&started) && !g_atomic_int_get(&done_sent)) imquic_moq_publish_done(moq_conn, moq_request_id, IMQUIC_MOQ_PUBDONE_SUBSCRIPTION_ENDED, "Publisher left"); - if(!options.publish) { - imquic_moq_namespace tns[32]; /* FIXME */ - int i = 0; - while(options.track_namespace[i] != NULL) { - const char *track_namespace = options.track_namespace[i]; - tns[i].buffer = (uint8_t *)track_namespace; - tns[i].length = strlen(track_namespace); - tns[i].next = (options.track_namespace[i+1] != NULL) ? &tns[i+1] : NULL; - i++; - } - imquic_moq_publish_namespace_done(moq_conn, &tns[0]); - } + if(!options.publish) + imquic_moq_publish_namespace_done(moq_conn, moq_tns_request_id); /* Shutdown the client */ imquic_shutdown_endpoint(client); diff --git a/examples/moq-relay.c b/examples/moq-relay.c index 519fc74..b0a23ed 100644 --- a/examples/moq-relay.c +++ b/examples/moq-relay.c @@ -49,6 +49,7 @@ static GList *fetches = NULL; typedef struct imquic_demo_moq_publisher { imquic_connection *conn; GHashTable *namespaces; + GHashTable *namespaces_by_id; GHashTable *subscriptions; GHashTable *subscriptions_by_id; uint64_t relay_track_alias; @@ -59,6 +60,7 @@ static void imquic_demo_moq_publisher_destroy(imquic_demo_moq_publisher *pub); typedef struct imquic_demo_moq_published_namespace { imquic_demo_moq_publisher *pub; + uint64_t request_id; char *track_namespace; imquic_moq_namespace *tns; gboolean announced; @@ -66,7 +68,7 @@ typedef struct imquic_demo_moq_published_namespace { imquic_mutex mutex; } imquic_demo_moq_published_namespace; static imquic_demo_moq_published_namespace *imquic_demo_moq_published_namespace_create(imquic_demo_moq_publisher *pub, - const char *track_namespace, imquic_moq_namespace *tns, gboolean announced); + uint64_t request_id, const char *track_namespace, imquic_moq_namespace *tns, gboolean announced); static void imquic_demo_moq_published_namespace_destroy(imquic_demo_moq_published_namespace *annc); typedef struct imquic_demo_moq_track { @@ -135,6 +137,7 @@ static imquic_demo_moq_publisher *imquic_demo_moq_publisher_create(imquic_connec pub->conn = conn; pub->namespaces = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)imquic_demo_moq_published_namespace_destroy); + pub->namespaces_by_id = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL); pub->subscriptions = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL); pub->subscriptions_by_id = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL); @@ -155,6 +158,8 @@ static void imquic_demo_moq_publisher_destroy(imquic_demo_moq_publisher *pub) { } g_hash_table_unref(pub->namespaces); } + if(pub->namespaces_by_id) + g_hash_table_unref(pub->namespaces_by_id); if(pub->subscriptions != NULL) g_hash_table_unref(pub->subscriptions); if(pub->subscriptions_by_id != NULL) @@ -164,9 +169,10 @@ static void imquic_demo_moq_publisher_destroy(imquic_demo_moq_publisher *pub) { } } static imquic_demo_moq_published_namespace *imquic_demo_moq_published_namespace_create(imquic_demo_moq_publisher *pub, - const char *track_namespace, imquic_moq_namespace *tns, gboolean announced) { + uint64_t request_id, const char *track_namespace, imquic_moq_namespace *tns, gboolean announced) { imquic_demo_moq_published_namespace *annc = g_malloc0(sizeof(imquic_demo_moq_published_namespace)); annc->pub = pub; + annc->request_id = request_id; annc->track_namespace = g_strdup(track_namespace); annc->tns = imquic_moq_namespace_duplicate(tns); annc->announced = announced; @@ -492,8 +498,9 @@ static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint g_hash_table_insert(publishers, conn, pub); } /* Let's keep track of it */ - imquic_demo_moq_published_namespace *annc = imquic_demo_moq_published_namespace_create(pub, ns, tns, TRUE); + imquic_demo_moq_published_namespace *annc = imquic_demo_moq_published_namespace_create(pub, request_id, ns, tns, TRUE); g_hash_table_insert(pub->namespaces, g_strdup(ns), annc); + g_hash_table_insert(pub->namespaces_by_id, imquic_uint64_dup(request_id), annc); g_hash_table_insert(namespaces, g_strdup(ns), annc); /* Check if there's monitors interested in this */ imquic_demo_alert_monitors(annc, NULL, FALSE); @@ -502,15 +509,16 @@ static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint imquic_moq_accept_publish_namespace(conn, request_id, NULL); } -static void imquic_demo_incoming_publish_namespace_cancel(imquic_connection *conn, imquic_moq_namespace *tns, imquic_moq_request_error_code error_code, const char *reason) { +static void imquic_demo_incoming_publish_namespace_cancel(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason) { /* We received an publish_namespace cancel */ - char buffer[256]; - const char *ns = imquic_moq_namespace_str(tns, buffer, sizeof(buffer), TRUE); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Cancelled publishing of namespace: '%s' (%d, %s)\n", - imquic_get_connection_name(conn), ns, error_code, reason); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Cancelled publishing of namespace: %"SCNu64" (%d, %s)\n", + imquic_get_connection_name(conn), request_id, error_code, reason); /* Find the namespace */ imquic_mutex_lock(&mutex); - imquic_demo_moq_published_namespace *annc = g_hash_table_lookup(namespaces, ns); + imquic_demo_moq_published_namespace *annc = NULL; + imquic_demo_moq_publisher *pub = g_hash_table_lookup(publishers, conn); + if(pub != NULL) + annc = g_hash_table_lookup(pub->namespaces_by_id, &request_id); if(annc == NULL || !annc->announced) { imquic_mutex_unlock(&mutex); IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Namespace not found\n", @@ -524,21 +532,22 @@ static void imquic_demo_incoming_publish_namespace_cancel(imquic_connection *con return; } /* Get rid of it */ - g_hash_table_remove(namespaces, ns); + g_hash_table_remove(namespaces, annc->track_namespace); if(annc->pub->namespaces) g_hash_table_remove(annc->pub->namespaces, annc->track_namespace); imquic_mutex_unlock(&mutex); } -static void imquic_demo_publish_namespace_done(imquic_connection *conn, imquic_moq_namespace *tns) { +static void imquic_demo_publish_namespace_done(imquic_connection *conn, uint64_t request_id) { /* We received an publish_namespace_done */ - char buffer[256]; - const char *ns = imquic_moq_namespace_str(tns, buffer, sizeof(buffer), TRUE); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publish Namespace done: '%s'\n", - imquic_get_connection_name(conn), ns); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publish Namespace done: %"SCNu64"\n", + imquic_get_connection_name(conn), request_id); /* Find the namespace */ imquic_mutex_lock(&mutex); - imquic_demo_moq_published_namespace *annc = g_hash_table_lookup(namespaces, ns); + imquic_demo_moq_published_namespace *annc = NULL; + imquic_demo_moq_publisher *pub = g_hash_table_lookup(publishers, conn); + if(pub != NULL) + annc = g_hash_table_lookup(pub->namespaces_by_id, &request_id); if(annc == NULL || !annc->announced) { imquic_mutex_unlock(&mutex); IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s] Namespace not found\n", @@ -554,7 +563,7 @@ static void imquic_demo_publish_namespace_done(imquic_connection *conn, imquic_m /* Check if there's monitors interested in this */ imquic_demo_alert_monitors(annc, NULL, TRUE); /* Get rid of it */ - g_hash_table_remove(namespaces, ns); + g_hash_table_remove(namespaces, annc->track_namespace); if(annc->pub->namespaces) g_hash_table_remove(annc->pub->namespaces, annc->track_namespace); imquic_mutex_unlock(&mutex); @@ -586,7 +595,7 @@ static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t reque g_hash_table_insert(publishers, conn, pub); } /* Let's keep track of it */ - annc = imquic_demo_moq_published_namespace_create(pub, ns, tns, FALSE); + annc = imquic_demo_moq_published_namespace_create(pub, 0, ns, tns, FALSE); g_hash_table_insert(pub->namespaces, g_strdup(ns), annc); g_hash_table_insert(namespaces, g_strdup(ns), annc); } @@ -902,7 +911,10 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req params.forward = TRUE; params.subscription_filter_set = TRUE; params.subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - imquic_moq_subscribe(annc->pub->conn, track->request_id, tns, tn, ¶ms); + if(imquic_moq_subscribe(annc->pub->conn, track->request_id, tns, tn, ¶ms) < 0) { + g_hash_table_remove(annc->pub->subscriptions_by_id, &track->request_id); + imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_INTERNAL_ERROR, "Error creating upstream subscription", 0); + } } imquic_mutex_unlock(&mutex); } @@ -1121,7 +1133,7 @@ static void imquic_demo_incoming_subscribe_namespace(imquic_connection *conn, ui imquic_mutex_unlock(&mutex); } -static void imquic_demo_incoming_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns) { +static void imquic_demo_incoming_unsubscribe_namespace(imquic_connection *conn, uint64_t request_id) { /* We received an unsubscribe */ IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming unsubscribe for namespace via ID %"SCNu64"\n", imquic_get_connection_name(conn), request_id); diff --git a/examples/moq-sub.c b/examples/moq-sub.c index 12ef15a..5f6a212 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -273,18 +273,16 @@ static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint /* We received an PUBLISH_NAMESPACE (older MoQ version) */ char buffer[256]; const char *ns = imquic_moq_namespace_str(tns, buffer, sizeof(buffer), TRUE); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] New published namespace: '%s'\n", - imquic_get_connection_name(conn), ns); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] New published namespace via ID %"SCNu64": '%s'\n", + imquic_get_connection_name(conn), request_id, ns); /* Accept the request */ imquic_moq_accept_publish_namespace(conn, request_id, NULL); } -static void imquic_demo_publish_namespace_done(imquic_connection *conn, imquic_moq_namespace *tns) { +static void imquic_demo_publish_namespace_done(imquic_connection *conn, uint64_t request_id) { /* We received an PUBLISH_NAMESPACE_DONE (older MoQ version) */ - char buffer[256]; - const char *ns = imquic_moq_namespace_str(tns, buffer, sizeof(buffer), TRUE); - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publish Namespace done: '%s'\n", - imquic_get_connection_name(conn), ns); + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publish Namespace done: %"SCNu64"\n", + imquic_get_connection_name(conn), request_id); } static void imquic_demo_incoming_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns_suffix) { diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 1a4cb5a..1a5993b 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -431,7 +431,7 @@ void imquic_set_incoming_publish_namespace_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_publish_namespace_cancel_cb(imquic_endpoint *endpoint, - void (* incoming_publish_namespace_cancel)(imquic_connection *conn, imquic_moq_namespace *tns, imquic_moq_request_error_code error_code, const char *reason)) { + void (* incoming_publish_namespace_cancel)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -464,7 +464,7 @@ void imquic_set_publish_namespace_error_cb(imquic_endpoint *endpoint, } void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, - void (* publish_namespace_done)(imquic_connection *conn, imquic_moq_namespace *tns)) { + void (* publish_namespace_done)(imquic_connection *conn, uint64_t request_id)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -643,7 +643,7 @@ void imquic_set_subscribe_namespace_error_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_unsubscribe_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_unsubscribe_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns)) { + void (* incoming_unsubscribe_namespace)(imquic_connection *conn, uint64_t request_id)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); diff --git a/src/imquic/moq.h b/src/imquic/moq.h index d8aede4..5ec9ff6 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -866,7 +866,7 @@ void imquic_set_incoming_publish_namespace_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_publish_namespace_cancel Pointer to the function that will handle the incoming \c PUBLISH_NAMESPACE_CANCEL */ void imquic_set_incoming_publish_namespace_cancel_cb(imquic_endpoint *endpoint, - void (* incoming_publish_namespace_cancel)(imquic_connection *conn, imquic_moq_namespace *tns, imquic_moq_request_error_code error_code, const char *reason)); + void (* incoming_publish_namespace_cancel)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason)); /*! \brief Configure the callback function to be notified when an * \c PUBLISH_NAMESPACE we previously sent was accepted * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -888,7 +888,7 @@ void imquic_set_publish_namespace_error_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param publish_namespace_done Pointer to the function that will handle the incoming \c PUBLISH_NAMESPACE_DONE */ void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, - void (* publish_namespace_done)(imquic_connection *conn, imquic_moq_namespace *tns)); + void (* publish_namespace_done)(imquic_connection *conn, uint64_t request_id)); /*! \brief Configure the callback function to be notified when there's * an incoming \c PUBLISH request. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -994,7 +994,7 @@ void imquic_set_subscribe_namespace_error_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_unsubscribe_namespace Pointer to the function that will handle the incoming \c UNSUBSCRIBE_NAMESPACE */ void imquic_set_incoming_unsubscribe_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_unsubscribe_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns)); + void (* incoming_unsubscribe_namespace)(imquic_connection *conn, uint64_t request_id)); /*! \brief Configure the callback function to be notified when there's * an incoming \c NAMESPACE request. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -1025,8 +1025,7 @@ void imquic_set_incoming_joining_fetch_cb(imquic_endpoint *endpoint, * an incoming \c FETCH_CANCEL request. * \note Starting in v17, \c FETCH_CANCEL doesn't exist anymore, * so this callback is only fired if the endpoint that sent the - * \c FETCH closed the associated bidirectiomal stream before - * getting a \c FETCH_OK or \c REQUEST_ERROR back. + * \c FETCH closed the associated bidirectiomal stream. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_fetch_cancel Pointer to the function that will handle the incoming \c FETCH_CANCEL */ void imquic_set_incoming_fetch_cancel_cb(imquic_endpoint *endpoint, @@ -1151,9 +1150,9 @@ int imquic_moq_reject_publish_namespace(imquic_connection *conn, uint64_t reques imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Function to send a \c PUBLISH_NAMESPACE_DONE request * @param conn The imquic_connection to send the request on - * @param tns The imquic_moq_namespace namespace to publish_namespace_done + * @param request_id The unique \c request_id value associated to the original \c PUBLISH_NAMESPACE * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_publish_namespace_done(imquic_connection *conn, imquic_moq_namespace *tns); +int imquic_moq_publish_namespace_done(imquic_connection *conn, uint64_t request_id); /*! \brief Function to send a \c PUBLISH request * @param conn The imquic_connection to send the request on * @param request_id A unique request ID to associate to this subscription diff --git a/src/internal/moq.h b/src/internal/moq.h index e62e643..ef95841 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -321,12 +321,12 @@ typedef struct imquic_moq_context { gboolean sent_setup, recvd_setup; /*! \brief QUIC streams handled by the stack */ GHashTable *streams; + /*! \brief Map of request streams, indexed by Request ID */ + GHashTable *streams_by_reqid; /*! \brief Subscriptions this connection will send objects to, indexed by track_alias */ GHashTable *subscriptions; /*! \brief Subscriptions this connection will send objects to, indexed by request_id */ GHashTable *subscriptions_by_id; - /*! \brief Track namespace subscriptions (served or asked), indexed by request_id */ - GHashTable *tns_subscriptions_by_id; /*! \brief Map of Request IDs and what they were for */ GHashTable *requests; /*! \brief Current Request IDs we expect and we can send */ @@ -359,10 +359,10 @@ typedef struct imquic_moq_stream { uint64_t stream_id; /*! In case this is a bidirectional STREAM for a request, the associated request type */ imquic_moq_message_type request_type; - /* In case this is for SUBSCRIBE_NAMESPACE, whether this is a publisher or subscriber side */ - gboolean namespace_publisher; - /* In case this is for SUBSCRIBE_NAMESPACE, the state of SUBSCRIBE_NAMESPACE */ - volatile gint subscribe_namespace_state; + /*! In case this is a bidirectional STREAM for a request, if this endpoint originated it */ + gboolean request_sender; + /*! In case this is a bidirectional STREAM for a request, its current state */ + volatile gint request_state; /*! \brief In case this is for SUBSCRIBE_NAMESPACE, the namespace prefix */ imquic_moq_namespace *namespace_prefix, *last_tuple; /*! \brief In case this is for SUBSCRIBE_NAMESPACE, how many tuples are in the namespace prefix */ @@ -499,11 +499,12 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_NAMESPACE message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_NAMESPACE_DONE message * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for @@ -522,39 +523,44 @@ size_t imquic_moq_parse_publish_namespace_done(imquic_moq_context *moq, uint8_t size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_OK message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c SUBSCRIBE message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c REQUEST_UPDATE message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c SUBSCRIBE_OK message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse an \c UNSUBSCRIBE message * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for @@ -565,11 +571,12 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si size_t imquic_moq_parse_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c PUBLISH_DONE message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c SUBSCRIBE_NAMESPACE message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] moq_stream The imquic_moq_stream instance the message came from @@ -578,13 +585,6 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, si * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); -/*! \brief Helper to parse a \c SUBSCRIBE_NAMESPACE_OK message - * @param[in] moq The imquic_moq_context instance the message is for - * @param[in] bytes The buffer containing the message to parse - * @param[in] blen Size of the buffer to parse - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_subscribe_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c NAMESPACE message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] moq_stream The imquic_moq_stream instance the message came from @@ -603,11 +603,12 @@ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *mo size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c FETCH message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c FETCH_CANCEL message * \note This message was deprecated in v17 * @param[in] moq The imquic_moq_context instance the message is for @@ -618,18 +619,20 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl size_t imquic_moq_parse_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c FETCH_OK message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c TRACK_STATUS message * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from * @param[in] bytes The buffer containing the message to parse * @param[in] blen Size of the buffer to parse * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ -size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error); +size_t imquic_moq_parse_track_status(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse an \c OBJECT_DATAGRAM message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] bytes The buffer containing the message to parse @@ -759,42 +762,37 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t error, const char *reason, uint64_t retry_interval); /*! \brief Helper method to add a \c PUBLISH_NAMESPACE message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message * @param track_namespace Namespace to publish_namespace * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters); -/*! \brief Helper method to add a \c PUBLISH_NAMESPACE_OK message to a buffer - * @param moq The imquic_moq_context generating the message - * @param bytes The buffer to add the message to - * @param blen The size of the buffer - * @param request_id The request ID to put in the message - * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_namespace_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); +size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c PUBLISH_NAMESPACE_DONE message to a buffer * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param track_namespace Namespace to publish_namespace_done + * @param request_id The request ID to put in the message * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace); +size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); /*! \brief Helper method to add a \c PUBLISH_NAMESPACE_CANCEL message to a buffer * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message * @param bytes The buffer to add the message to * @param blen The size of the buffer - * @param track_namespace Namespace for which to cancel the publish_namespacement + * @param request_id The request ID to put in the message * @param error Error code associated to the message * @param reason Verbose description of the error, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace, +size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_request_error_code error, const char *reason); /*! \brief Helper to add a \c PUBLISH message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message @@ -804,20 +802,23 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t * @param parameters The parameters to add, if any * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper method to add a \c PUBLISH_OK message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, - imquic_moq_request_parameters *parameters); +size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Helper to add a \c SUBSCRIBE message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message @@ -825,20 +826,23 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t * @param track_name The track name to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c REQUEST_UPDATE message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message * @param sub_request_id The subscription request ID to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters); +size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c SUBSCRIBE_OK message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message @@ -846,7 +850,8 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si * @param parameters The parameters to add, if any * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper method to add an \c UNSUBSCRIBE message to a buffer * \note This message was deprecated in v17 @@ -858,6 +863,7 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size size_t imquic_moq_add_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); /*! \brief Helper method to add a \c PUBLISH_DONE message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message @@ -865,7 +871,8 @@ size_t imquic_moq_add_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_ * @param streams_count The streams count * @param reason Verbose description of the status * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_pub_done_code status, uint64_t streams_count, const char *reason); /*! \brief Helper to add a \c SUBSCRIBE_NAMESPACE message to a buffer * @param moq The imquic_moq_context generating the message @@ -899,6 +906,7 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace_suffix); /*! \brief Helper to add a \c FETCH message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param type The FETCH type @@ -910,7 +918,8 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream * @param range The Start/End Locations to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, +size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, uint64_t request_id, uint64_t joining_request_id, uint64_t preceding_group_offset, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); @@ -924,6 +933,7 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id); /*! \brief Helper method to add a \c FETCH_OK message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message @@ -932,10 +942,12 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size * @param parameters The parameters to add, if any * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper to add a \c TRACK_STATUS message to a buffer * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message @@ -943,7 +955,8 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b * @param track_name The track name to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_track_status(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c GOAWAY message to a buffer * @param moq The imquic_moq_context generating the message @@ -1143,14 +1156,14 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE messages */ void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_CANCEL messages, or when the bidirectional stream is closed */ - void (* incoming_publish_namespace_cancel)(imquic_connection *conn, imquic_moq_namespace *tns, imquic_moq_request_error_code error_code, const char *reason); + void (* incoming_publish_namespace_cancel)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_ACCEPTED messages */ void (* publish_namespace_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_ERROR messages */ void (* publish_namespace_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_DONE messages * \note This message was deprecated in v17 */ - void (* publish_namespace_done)(imquic_connection *conn, imquic_moq_namespace *tns); + void (* publish_namespace_done)(imquic_connection *conn, uint64_t request_id); /*! \brief Callback function to be notified about incoming \c PUBLISH messages */ void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); @@ -1186,7 +1199,7 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_NAMESPACE_ERROR messages */ void (* subscribe_namespace_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c UNSUBSCRIBE_NAMESPACE messages, or when the bidirectional stream is closed */ - void (* incoming_unsubscribe_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); + void (* incoming_unsubscribe_namespace)(imquic_connection *conn, uint64_t request_id); /*! \brief Callback function to be notified about incoming \c NAMESPACE messages */ void (* incoming_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); /*! \brief Callback function to be notified about incoming \c NAMESPACE_DONE messages */ diff --git a/src/moq.c b/src/moq.c index 2c61832..c9055e1 100644 --- a/src/moq.c +++ b/src/moq.c @@ -193,12 +193,12 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { imquic_moq_version_str(moq->version), alpn); moq->streams = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)imquic_moq_stream_destroy); + moq->streams_by_reqid = g_hash_table_new_full(g_int64_hash, g_int64_equal, + (GDestroyNotify)g_free, NULL); moq->subscriptions = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL); moq->subscriptions_by_id = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)imquic_moq_subscription_destroy); - moq->tns_subscriptions_by_id = g_hash_table_new_full(g_int64_hash, g_int64_equal, - (GDestroyNotify)g_free, NULL); moq->requests = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL); moq->buffer = imquic_buffer_create(NULL, 0); @@ -374,6 +374,40 @@ void imquic_moq_datagram_incoming(imquic_connection *conn, uint8_t *bytes, uint6 imquic_moq_parse_message(moq, 0, bytes, length, FALSE, TRUE); } +static void imquic_moq_request_stream_closed(imquic_moq_context *moq, imquic_moq_stream *moq_stream) { + if(moq == NULL || moq_stream == NULL || moq_stream->request_type == 0) + return; + imquic_moq_message_type request_type = moq_stream->request_type; + IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] -- Getting rid of %s '%"SCNu64"'\n", + imquic_get_connection_name(moq->conn), + imquic_moq_message_type_str(request_type, IMQUIC_MOQ_VERSION_17), + moq_stream->request_id); + gboolean request_sender = moq_stream->request_sender; + uint64_t request_id = moq_stream->request_id; + gboolean notify = !request_sender; + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); /* */ + imquic_mutex_unlock(&moq->mutex); + /* FIXME Trigger the application callbacks, if needed */ + if(request_type == IMQUIC_MOQ_PUBLISH_NAMESPACE) { + if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.publish_namespace_done) + moq->conn->socket->callbacks.moq.publish_namespace_done(moq->conn, request_id); + } else if(request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { + if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace) + moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace(moq->conn, request_id); + } else if(request_type == IMQUIC_MOQ_PUBLISH) { + /* FIXME */ + if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.publish_done) + moq->conn->socket->callbacks.moq.publish_done(moq->conn, request_id, IMQUIC_MOQ_PUBDONE_SUBSCRIPTION_ENDED, 0, "Stream closed"); + } else if(request_type == IMQUIC_MOQ_SUBSCRIBE) { + if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_unsubscribe) + moq->conn->socket->callbacks.moq.incoming_unsubscribe(moq->conn, request_id); + } else if(request_type == IMQUIC_MOQ_FETCH) { + if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_fetch_cancel) + moq->conn->socket->callbacks.moq.incoming_fetch_cancel(moq->conn, request_id); + } +} + void imquic_moq_reset_stream_incoming(imquic_connection *conn, uint64_t stream_id, uint64_t error_code) { /* We got a RESET_STREAM */ imquic_mutex_lock(&moq_mutex); @@ -391,21 +425,13 @@ void imquic_moq_reset_stream_incoming(imquic_connection *conn, uint64_t stream_i } IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Got RESET_STREAM for STREAM %"SCNu64": %"SCNu64" (%s)\n", imquic_get_connection_name(conn), stream_id, error_code, imquic_moq_reset_stream_code_str(error_code)); - if(moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { - /* FIXME Not the SUBSCRIBE_NAMESPACE stream, we ignore it for now */ + if(moq_stream->request_type == 0) { + /* FIXME Not a request stream, we ignore it for now */ imquic_mutex_unlock(&moq->mutex); return; } - /* If we got here, a SUBSCRIBE_NAMESPACE bidirectional STREAM was closed */ - IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] -- Getting rid of SUBSCRBE_NAMESPACE '%"SCNu64"'\n", - imquic_get_connection_name(conn), moq_stream->request_id); - gboolean notify = moq_stream->namespace_publisher; - uint64_t request_id = moq_stream->request_id; - g_hash_table_remove(moq->tns_subscriptions_by_id, &moq_stream->request_id); - g_hash_table_remove(moq->streams, &moq_stream->stream_id); /* */ - imquic_mutex_unlock(&moq->mutex); - if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace) - moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace(moq->conn, request_id, NULL); + /* If we got here, a request bidirectional STREAM was closed */ + imquic_moq_request_stream_closed(moq, moq_stream); } void imquic_moq_stop_sending_incoming(imquic_connection *conn, uint64_t stream_id, uint64_t error_code) { @@ -426,7 +452,13 @@ void imquic_moq_stop_sending_incoming(imquic_connection *conn, uint64_t stream_i IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s][MoQ] Got STOP_SENDING for STREAM %"SCNu64": %"SCNu64" (%s)\n", imquic_get_connection_name(conn), stream_id, error_code, imquic_moq_reset_stream_code_str(error_code)); imquic_mutex_unlock(&moq->mutex); - /* TODO */ + if(moq_stream->request_type == 0) { + /* FIXME Not a request stream, we ignore it for now */ + imquic_mutex_unlock(&moq->mutex); + return; + } + /* If we got here, a request bidirectional STREAM was closed */ + imquic_moq_request_stream_closed(moq, moq_stream); } void imquic_moq_connection_gone(imquic_connection *conn) { @@ -460,8 +492,8 @@ static void imquic_moq_context_free(const imquic_refcount *moq_ref) { g_hash_table_unref(moq->subscriptions); if(moq->subscriptions_by_id) g_hash_table_unref(moq->subscriptions_by_id); - if(moq->tns_subscriptions_by_id) - g_hash_table_unref(moq->tns_subscriptions_by_id); + if(moq->streams_by_reqid) + g_hash_table_unref(moq->streams_by_reqid); if(moq->requests) g_hash_table_unref(moq->requests); imquic_buffer_destroy(moq->buffer); @@ -618,113 +650,56 @@ const char *imquic_moq_reset_stream_code_str(imquic_moq_reset_stream_code code) } const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq_version version) { - if(version <= IMQUIC_MOQ_VERSION_16) { - switch(type) { - case IMQUIC_MOQ_REQUEST_OK: - return "REQUEST_OK"; - case IMQUIC_MOQ_REQUEST_ERROR: - return "REQUEST_ERROR"; - case IMQUIC_MOQ_SUBSCRIBE: - return "SUBSCRIBE"; - case IMQUIC_MOQ_SUBSCRIBE_OK: - return "SUBSCRIBE_OK"; - case IMQUIC_MOQ_REQUEST_UPDATE: - return "REQUEST_UPDATE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE: - return "PUBLISH_NAMESPACE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE: - return "PUBLISH_NAMESPACE_DONE"; - case IMQUIC_MOQ_UNSUBSCRIBE: - return "UNSUBSCRIBE"; - case IMQUIC_MOQ_PUBLISH_DONE: - return "PUBLISH_DONE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL: - return "PUBLISH_NAMESPACE_CANCEL"; - case IMQUIC_MOQ_TRACK_STATUS: - return "TRACK_STATUS"; - case IMQUIC_MOQ_GOAWAY: - return "GOAWAY"; - case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE: - return "SUBSCRIBE_NAMESPACE"; - case IMQUIC_MOQ_NAMESPACE: - return "NAMESPACE"; - case IMQUIC_MOQ_NAMESPACE_DONE: - return "NAMESPACE_DONE"; - case IMQUIC_MOQ_MAX_REQUEST_ID: - return "MAX_REQUEST_ID"; - case IMQUIC_MOQ_REQUESTS_BLOCKED: - return "REQUESTS_BLOCKED"; - case IMQUIC_MOQ_FETCH: - return "FETCH"; - case IMQUIC_MOQ_FETCH_CANCEL: - return "FETCH_CANCEL"; - case IMQUIC_MOQ_FETCH_OK: - return "FETCH_OK"; - case IMQUIC_MOQ_SETUP: - return "SETUP"; - case IMQUIC_MOQ_CLIENT_SETUP: - return "CLIENT_SETUP"; - case IMQUIC_MOQ_SERVER_SETUP: - return "SERVER_SETUP"; - case IMQUIC_MOQ_PUBLISH: - return "PUBLISH"; - case IMQUIC_MOQ_PUBLISH_OK: - return "PUBLISH_OK"; - default: break; - } - } else { - /* TODO New messages in v17 */ - switch(type) { - case IMQUIC_MOQ_REQUEST_OK: - return "REQUEST_OK"; - case IMQUIC_MOQ_REQUEST_ERROR: - return "REQUEST_ERROR"; - case IMQUIC_MOQ_SUBSCRIBE: - return "SUBSCRIBE"; - case IMQUIC_MOQ_SUBSCRIBE_OK: - return "SUBSCRIBE_OK"; - case IMQUIC_MOQ_REQUEST_UPDATE: - return "REQUEST_UPDATE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE: - return "PUBLISH_NAMESPACE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE: - return "PUBLISH_NAMESPACE_DONE"; - case IMQUIC_MOQ_UNSUBSCRIBE: - return "UNSUBSCRIBE"; - case IMQUIC_MOQ_PUBLISH_DONE: - return "PUBLISH_DONE"; - case IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL: - return "PUBLISH_NAMESPACE_CANCEL"; - case IMQUIC_MOQ_TRACK_STATUS: - return "TRACK_STATUS"; - case IMQUIC_MOQ_GOAWAY: - return "GOAWAY"; - case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE: - return "SUBSCRIBE_NAMESPACE"; - case IMQUIC_MOQ_NAMESPACE: - return "NAMESPACE"; - case IMQUIC_MOQ_NAMESPACE_DONE: - return "NAMESPACE_DONE"; - case IMQUIC_MOQ_MAX_REQUEST_ID: - return "MAX_REQUEST_ID"; - case IMQUIC_MOQ_REQUESTS_BLOCKED: - return "REQUESTS_BLOCKED"; - case IMQUIC_MOQ_FETCH: - return "FETCH"; - case IMQUIC_MOQ_FETCH_CANCEL: - return "FETCH_CANCEL"; - case IMQUIC_MOQ_FETCH_OK: - return "FETCH_OK"; - case IMQUIC_MOQ_CLIENT_SETUP: - return "CLIENT_SETUP"; - case IMQUIC_MOQ_SERVER_SETUP: - return "SERVER_SETUP"; - case IMQUIC_MOQ_PUBLISH: - return "PUBLISH"; - case IMQUIC_MOQ_PUBLISH_OK: - return "PUBLISH_OK"; - default: break; - } + switch(type) { + case IMQUIC_MOQ_REQUEST_OK: + return "REQUEST_OK"; + case IMQUIC_MOQ_REQUEST_ERROR: + return "REQUEST_ERROR"; + case IMQUIC_MOQ_SUBSCRIBE: + return "SUBSCRIBE"; + case IMQUIC_MOQ_SUBSCRIBE_OK: + return "SUBSCRIBE_OK"; + case IMQUIC_MOQ_REQUEST_UPDATE: + return "REQUEST_UPDATE"; + case IMQUIC_MOQ_PUBLISH_NAMESPACE: + return "PUBLISH_NAMESPACE"; + case IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE: + return "PUBLISH_NAMESPACE_DONE"; + case IMQUIC_MOQ_UNSUBSCRIBE: + return "UNSUBSCRIBE"; + case IMQUIC_MOQ_PUBLISH_DONE: + return "PUBLISH_DONE"; + case IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL: + return "PUBLISH_NAMESPACE_CANCEL"; + case IMQUIC_MOQ_TRACK_STATUS: + return "TRACK_STATUS"; + case IMQUIC_MOQ_GOAWAY: + return "GOAWAY"; + case IMQUIC_MOQ_SUBSCRIBE_NAMESPACE: + return "SUBSCRIBE_NAMESPACE"; + case IMQUIC_MOQ_NAMESPACE: + return "NAMESPACE"; + case IMQUIC_MOQ_NAMESPACE_DONE: + return "NAMESPACE_DONE"; + case IMQUIC_MOQ_MAX_REQUEST_ID: + return "MAX_REQUEST_ID"; + case IMQUIC_MOQ_REQUESTS_BLOCKED: + return "REQUESTS_BLOCKED"; + case IMQUIC_MOQ_FETCH: + return "FETCH"; + case IMQUIC_MOQ_FETCH_CANCEL: + return "FETCH_CANCEL"; + case IMQUIC_MOQ_FETCH_OK: + return "FETCH_OK"; + case IMQUIC_MOQ_CLIENT_SETUP: + return "CLIENT_SETUP"; + case IMQUIC_MOQ_SERVER_SETUP: + return "SERVER_SETUP"; + case IMQUIC_MOQ_PUBLISH: + return "PUBLISH"; + case IMQUIC_MOQ_PUBLISH_OK: + return "PUBLISH_OK"; + default: break; } return NULL; } @@ -1402,7 +1377,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_buffer_append(moq->buffer, bytes, blen); bytes = moq->buffer->bytes; blen = moq->buffer->length; - } else if(moq_stream != NULL && moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { + } else if(moq_stream != NULL && moq_stream->request_type > 0) { if(moq_stream->buffer == NULL) moq_stream->buffer = imquic_buffer_create(NULL, 0); imquic_buffer_append(moq_stream->buffer, bytes, blen); @@ -1410,25 +1385,27 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ blen = moq_stream->buffer->length; } /* Iterate on all frames */ - while((moq_stream == NULL || moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) && blen-offset > 0) { - /* If we're here, we're either on the control stream, or on a media stream waiting to know what it will be like */ + while((moq_stream == NULL || moq_stream->request_type != 0) && blen-offset > 0) { + /* If we're here, we're either on the control stream, on a request + * stream, or on a media stream waiting to know what it will be like */ imquic_moq_message_type type = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &tlen); IMQUIC_LOG(IMQUIC_MOQ_LOG_VERB, "[%s][MoQ][%zu] >> %s (%02x, %u)\n", imquic_get_connection_name(moq->conn), offset, imquic_moq_message_type_str(type, moq->version), type, tlen); if(!imquic_moq_is_control_stream(moq, stream_id) && moq_stream == NULL) { - /* Not the control stream, check what it's for (namespaces + /* Not the control stream, check what it's for (request * or objects) and then make sure it's a supported message */ gboolean bidirectional = FALSE; imquic_parse_stream_id(stream_id, NULL, NULL, &bidirectional); imquic_moq_data_message_type dtype = (imquic_moq_data_message_type)type; - if(bidirectional && type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { - /* Create a new MoQ stream for namespaces and track it */ - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Stream %"SCNu64" will be used for namespaces\n", - imquic_get_connection_name(moq->conn), stream_id); + if(bidirectional && (type == IMQUIC_MOQ_PUBLISH_NAMESPACE || type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || + type == IMQUIC_MOQ_PUBLISH || type == IMQUIC_MOQ_SUBSCRIBE || + type == IMQUIC_MOQ_FETCH || type == IMQUIC_MOQ_TRACK_STATUS)) { + /* Create a new MoQ stream for the request and track it */ + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Stream %"SCNu64" will be used for %s\n", + imquic_get_connection_name(moq->conn), stream_id, imquic_moq_message_type_str(type, moq->version)); moq_stream = g_malloc0(sizeof(imquic_moq_stream)); moq_stream->stream_id = stream_id; - moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE_NAMESPACE; - moq_stream->namespace_publisher = TRUE; + moq_stream->request_type = type; g_hash_table_insert(moq->streams, imquic_dup_uint64(stream_id), moq_stream); moq_stream->buffer = imquic_buffer_create(bytes, blen); bytes = moq_stream->buffer->bytes; @@ -1471,10 +1448,31 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_get_connection_name(moq->conn), plen, blen-offset); goto done; } - if(type == IMQUIC_MOQ_SETUP) { - /* Parse this SETUP message */ - parsed = imquic_moq_parse_setup(moq, &bytes[offset], plen, &error); - } else if(type == IMQUIC_MOQ_CLIENT_SETUP) { + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + /* On newer versions of the protocol, the unidirectional + * control streams can only carry a limited set of messages */ + if(type == IMQUIC_MOQ_SETUP) { + /* Parse this SETUP message */ + parsed = imquic_moq_parse_setup(moq, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_GOAWAY) { + /* Parse this GOAWAY message */ + parsed = imquic_moq_parse_goaway(moq, &bytes[offset], plen, &error); + } else { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Unsupported message '%02x' (%s)\n", + imquic_get_connection_name(moq->conn), type, + imquic_moq_message_type_str(type, moq->version)); + error = IMQUIC_MOQ_PROTOCOL_VIOLATION; +#ifdef HAVE_QLOG + if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + json_t *message = imquic_qlog_moq_message_prepare("unknown"); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, stream_id, &bytes[offset], plen, message); + } +#endif + } + goto next; + } + /* If we're here, we're on the legacy version of the protocol */ + if(type == IMQUIC_MOQ_CLIENT_SETUP) { /* Parse this CLIENT_SETUP message */ parsed = imquic_moq_parse_client_setup(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_SERVER_SETUP) { @@ -1494,7 +1492,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ parsed = imquic_moq_parse_request_error(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE) { /* Parse this PUBLISH_NAMESPACE message */ - parsed = imquic_moq_parse_publish_namespace(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_publish_namespace(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE) { /* Parse this PUBLISH_NAMESPACE_DONE message */ parsed = imquic_moq_parse_publish_namespace_done(moq, &bytes[offset], plen, &error); @@ -1503,52 +1501,53 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ parsed = imquic_moq_parse_publish_namespace_cancel(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH) { /* Parse this PUBLISH message */ - parsed = imquic_moq_parse_publish(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_publish(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_OK) { /* Parse this PUBLISH_OK message */ - parsed = imquic_moq_parse_publish_ok(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_publish_ok(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_SUBSCRIBE) { /* Parse this SUBSCRIBE message */ - parsed = imquic_moq_parse_subscribe(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_subscribe(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_REQUEST_UPDATE) { /* Parse this REQUEST_UPDATE message */ - parsed = imquic_moq_parse_request_update(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_request_update(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_SUBSCRIBE_OK) { /* Parse this SUBSCRIBE_OK message */ - parsed = imquic_moq_parse_subscribe_ok(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_subscribe_ok(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_UNSUBSCRIBE) { /* Parse this UNSUBSCRIBE message */ parsed = imquic_moq_parse_unsubscribe(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_PUBLISH_DONE) { /* Parse this PUBLISH_DONE message */ - parsed = imquic_moq_parse_publish_done(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_publish_done(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_FETCH) { /* Parse this FETCH message */ - parsed = imquic_moq_parse_fetch(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_fetch(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_FETCH_CANCEL) { /* Parse this FETCH_CANCEL message */ parsed = imquic_moq_parse_fetch_cancel(moq, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_FETCH_OK) { /* Parse this FETCH_OK message */ - parsed = imquic_moq_parse_fetch_ok(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_fetch_ok(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_TRACK_STATUS) { /* Parse this TRACK_STATUS message */ - parsed = imquic_moq_parse_track_status(moq, &bytes[offset], plen, &error); + parsed = imquic_moq_parse_track_status(moq, NULL, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_GOAWAY) { /* Parse this GOAWAY message */ parsed = imquic_moq_parse_goaway(moq, &bytes[offset], plen, &error); } else { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported message '%02x'\n", - imquic_get_connection_name(moq->conn), type); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Unsupported message '%02x' (%s)\n", + imquic_get_connection_name(moq->conn), type, + imquic_moq_message_type_str(type, moq->version)); + error = IMQUIC_MOQ_PROTOCOL_VIOLATION; #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("unknown"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, stream_id, &bytes[offset], plen, message); } #endif - imquic_buffer_shift(moq->buffer, plen); - return -1; } +next: if(error) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Error parsing MoQ message %s: %s\n", imquic_get_connection_name(moq->conn), @@ -1569,8 +1568,8 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ bytes = moq->buffer->bytes; blen = moq->buffer->length; offset = 0; - } else if(moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { - /* Control message for namespaces advertisement */ + } else if(moq_stream->request_type > 0) { + /* Control message for requests */ size_t plen = blen-offset; tlen = 2; if(blen - offset < tlen) { @@ -1589,9 +1588,39 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_get_connection_name(moq->conn), plen, blen-offset); goto done; } - if(type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { + if(type == IMQUIC_MOQ_PUBLISH_NAMESPACE) { + /* Parse this SPUBLISH_NAMESPACE message */ + parsed = imquic_moq_parse_publish_namespace(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { /* Parse this SUBSCRIBE_NAMESPACE message */ parsed = imquic_moq_parse_subscribe_namespace(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_PUBLISH) { + /* Parse this PUBLISH message */ + parsed = imquic_moq_parse_publish(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_PUBLISH_OK) { + /* Parse this PUBLISH_OK message */ + parsed = imquic_moq_parse_publish_ok(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_PUBLISH_DONE) { + /* Parse this PUBLISH_DONE message */ + parsed = imquic_moq_parse_publish_done(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_SUBSCRIBE) { + /* Parse this SUBSCRIBE message */ + parsed = imquic_moq_parse_subscribe(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_SUBSCRIBE_OK) { + /* Parse this SUBSCRIBE_OK message */ + parsed = imquic_moq_parse_subscribe_ok(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_FETCH) { + /* Parse this FETCH message */ + parsed = imquic_moq_parse_fetch(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_FETCH_OK) { + /* Parse this FETCH_OK message */ + parsed = imquic_moq_parse_fetch_ok(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_TRACK_STATUS) { + /* Parse this TRACK_STATUS message */ + parsed = imquic_moq_parse_track_status(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_REQUEST_UPDATE) { + /* Parse this REQUEST_UPDATE message */ + parsed = imquic_moq_parse_request_update(moq, moq_stream, &bytes[offset], plen, &error); } else if(type == IMQUIC_MOQ_REQUEST_OK) { /* Parse this REQUEST_OK message */ parsed = imquic_moq_parse_request_ok(moq, moq_stream, &bytes[offset], plen, &error); @@ -1605,8 +1634,11 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ /* Parse this NAMESPACE_DONE message */ parsed = imquic_moq_parse_namespace_done(moq, moq_stream, &bytes[offset], plen, &error); } else { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported message '%02x'\n", - imquic_get_connection_name(moq->conn), type); + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported message '%02x' (%s) on a %s request stream\n", + imquic_get_connection_name(moq->conn), type, + imquic_moq_message_type_str(type, moq->version), + imquic_moq_message_type_str(moq_stream->request_type, moq->version)); + error = IMQUIC_MOQ_PROTOCOL_VIOLATION; #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("unknown"); @@ -1697,16 +1729,9 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ done: if(moq_stream != NULL && complete) { - if(moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE) { - /* The SUBSCRIBE_NAMESPACE dedicated bidirectional STREAM has been closed */ - gboolean notify = moq_stream->namespace_publisher; - uint64_t request_id = moq_stream->request_id; - imquic_mutex_lock(&moq->mutex); - g_hash_table_remove(moq->tns_subscriptions_by_id, &moq_stream->request_id); - g_hash_table_remove(moq->streams, &moq_stream->stream_id); /* */ - imquic_mutex_unlock(&moq->mutex); - if(notify && moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace) - moq->conn->socket->callbacks.moq.incoming_unsubscribe_namespace(moq->conn, request_id, NULL); + if(moq_stream->request_type > 0) { + /* The request dedicated bidirectional STREAM has been closed */ + imquic_moq_request_stream_closed(moq, moq_stream); return 0; } IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] Media stream %"SCNu64" is complete\n", @@ -1959,7 +1984,7 @@ size_t imquic_moq_parse_setup(imquic_moq_context *moq, uint8_t *bytes, size_t bl size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; - IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "SERVER_SETUP was deprecated"); + IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "MAX_REQUEST_ID was deprecated"); if(bytes == NULL || blen < 1) return 0; size_t offset = 0; @@ -1987,6 +2012,7 @@ size_t imquic_moq_parse_max_request_id(imquic_moq_context *moq, uint8_t *bytes, size_t imquic_moq_parse_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; + IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "REQUESTS_BLOCKED was deprecated"); if(bytes == NULL || blen < 1) return 0; size_t offset = 0; @@ -2016,9 +2042,10 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && - (moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2))), - error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK for SUBSCRIBE_NAMESPACE"); + /* FIXME State management needs to be fixed, because an update will trigger OK/ERROR too */ + IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || + !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2086,9 +2113,10 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; - IMQUIC_MOQ_CHECK_ERR((moq_stream != NULL && moq_stream->request_type == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && - (moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2))), - error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR for SUBSCRIBE_NAMESPACE"); + /* FIXME State management needs to be fixed, because an update will trigger OK/ERROR too */ + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || + !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2178,11 +2206,14 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream return offset; } -size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2209,17 +2240,27 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, uint8_t *byte } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "publish_namespace"); json_t *message = imquic_qlog_moq_message_prepare("publish_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; + /* If we're on a recent version of MoQ, track this request via its ID */ + if(moq_stream != NULL) { + moq_stream->request_id = request_id; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish_namespace) { moq->conn->socket->callbacks.moq.incoming_publish_namespace(moq->conn, request_id, &tns[0], ¶meters); @@ -2239,20 +2280,19 @@ size_t imquic_moq_parse_publish_namespace_done(imquic_moq_context *moq, uint8_t return 0; size_t offset = 0; uint8_t length = 0; - imquic_moq_namespace tns[32]; - memset(&tns, 0, sizeof(tns)); - uint64_t tns_num = 0, i = 0; - IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE, tns_num, i, "Broken PUBLISH_NAMESPACE_DONE", TRUE); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); + offset += length; #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_namespace_done"); - imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); + json_object_set_new(message, "request_id", json_integer(request_id)); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); } #endif /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.publish_namespace_done) - moq->conn->socket->callbacks.moq.publish_namespace_done(moq->conn, &tns[0]); + moq->conn->socket->callbacks.moq.publish_namespace_done(moq->conn, request_id); if(error) *error = 0; return offset; @@ -2265,13 +2305,10 @@ size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_ return 0; size_t offset = 0; uint8_t length = 0; - imquic_moq_namespace tns[32]; - memset(&tns, 0, sizeof(tns)); - uint64_t error_code = 0; - char reason[1024], *reason_str = NULL; - uint64_t tns_num = 0, i = 0; - IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE, tns_num, i, "Broken PUBLISH_NAMESPACE_CANCEL", FALSE); - error_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); + offset += length; + uint64_t error_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_CANCEL"); offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Error Code: %s (%"SCNu64")\n", @@ -2279,6 +2316,7 @@ size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_ uint64_t rs_len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_CANCEL"); offset += length; + char reason[1024], *reason_str = NULL; if(rs_len > 0) { IMQUIC_MOQ_CHECK_ERR(rs_len > blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_CANCEL"); IMQUIC_MOQ_CHECK_ERR(rs_len > sizeof(reason), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid reason length"); @@ -2294,7 +2332,7 @@ size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_ #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_namespace_cancel"); - imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "error_code", json_integer(error_code)); if(reason_str != NULL) json_object_set_new(message, "reason", json_string(reason_str)); @@ -2303,17 +2341,20 @@ size_t imquic_moq_parse_publish_namespace_cancel(imquic_moq_context *moq, uint8_ #endif /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish_namespace_cancel) - moq->conn->socket->callbacks.moq.incoming_publish_namespace_cancel(moq->conn, &tns[0], error_code, reason); + moq->conn->socket->callbacks.moq.incoming_publish_namespace_cancel(moq->conn, request_id, error_code, reason); if(error) *error = 0; return offset; } -size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2362,6 +2403,8 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "publish"); json_t *message = imquic_qlog_moq_message_prepare("publish"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); @@ -2370,12 +2413,20 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; + /* If we're on a recent version of MoQ, track this request via its ID */ + if(moq_stream != NULL) { + moq_stream->request_id = request_id; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish) { moq->conn->socket->callbacks.moq.incoming_publish(moq->conn, @@ -2390,11 +2441,14 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, uint8_t *bytes, size_t return offset; } -size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || + !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2422,7 +2476,8 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2433,11 +2488,14 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size return offset; } -size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2468,18 +2526,28 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe"); json_t *message = imquic_qlog_moq_message_prepare("subscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; + /* If we're on a recent version of MoQ, track this request via its ID */ + if(moq_stream != NULL) { + moq_stream->request_id = request_id; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } /* Track this subscription */ imquic_moq_subscription *moq_sub = imquic_moq_subscription_create(request_id, 0); imquic_mutex_lock(&moq->mutex); @@ -2498,11 +2566,15 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_ return offset; } -size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + /* FIXME State management needs to be fixed, because an update will trigger OK/ERROR too */ + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || + moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2)), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_UPDATE on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2535,7 +2607,8 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ @@ -2554,11 +2627,14 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, uint8_t *bytes, return offset; } -size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || + !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2607,7 +2683,8 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2656,11 +2733,14 @@ size_t imquic_moq_parse_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, siz return offset; } -size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || + moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2)), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2702,7 +2782,8 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "streams_count", json_integer(streams_count)); if(reason_str != NULL) json_object_set_new(message, "reason", json_string(reason_str)); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -2721,8 +2802,8 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || - !moq_stream->namespace_publisher || !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 0, 1)), - error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_NAMESPACE"); + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1)), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2767,7 +2848,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; - /* If we're on a recent version of MoQ, track this subscription via its request ID */ + /* If we're on a recent version of MoQ, track this request via its request ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); @@ -2775,7 +2856,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ moq_stream->last_tuple = moq_stream->last_tuple->next; moq_stream->namespace_prefix_size = tns_num; imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->tns_subscriptions_by_id, imquic_dup_uint64(request_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); } /* Notify the application */ @@ -2796,6 +2877,9 @@ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *mo *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1)), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; imquic_moq_namespace tns[32]; @@ -2828,6 +2912,9 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1)), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; imquic_moq_namespace tns[32]; @@ -2855,11 +2942,14 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea return offset; } -size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of FETCH on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2929,6 +3019,8 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "fetch"); json_t *message = imquic_qlog_moq_message_prepare("fetch"); json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "fetch_type", json_integer(type)); @@ -2945,12 +3037,20 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t bl } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; + /* If we're on a recent version of MoQ, track this request via its request ID */ + if(moq_stream != NULL) { + moq_stream->request_id = request_id; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } /* Track this fetch subscription */ imquic_moq_subscription *moq_sub = imquic_moq_subscription_create(request_id, 0); moq_sub->fetch = TRUE; @@ -3019,11 +3119,14 @@ size_t imquic_moq_parse_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, si return offset; } -size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_FETCH || + !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of FETCH_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -3086,7 +3189,8 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Notify the application */ @@ -3098,11 +3202,14 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t return offset; } -size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint8_t *error) { +size_t imquic_moq_parse_track_status(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; if(bytes == NULL || blen < 1) return 0; + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || + moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of TRACK_STATUS on bidirectional request"); size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -3133,18 +3240,28 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, uint8_t *bytes, si } #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "track_status"); json_t *message = imquic_qlog_moq_message_prepare("track_status"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); - imquic_moq_qlog_control_message_parsed(moq->conn->qlog, imquic_moq_get_control_stream(moq), bytes-3, offset+3, message); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; + /* If we're on a recent version of MoQ, track this request via its ID */ + if(moq_stream != NULL) { + moq_stream->request_id = request_id; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_track_status) { moq->conn->socket->callbacks.moq.incoming_track_status(moq->conn, @@ -3370,7 +3487,7 @@ size_t imquic_moq_parse_subgroup_header(imquic_moq_context *moq, imquic_moq_stre imquic_get_connection_name(moq->conn), priority); /* Track these properties */ if(moq_stream != NULL) { - moq_stream->request_id = 0; /* TODO remove? */ + moq_stream->request_id = 0; moq_stream->track_alias = track_alias; moq_stream->group_id = group_id; moq_stream->subgroup_id = subgroup_id; @@ -3831,7 +3948,7 @@ size_t imquic_moq_add_requests_blocked(imquic_moq_context *moq, uint8_t *bytes, size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUEST_OK, moq->version)); return 0; @@ -3857,7 +3974,8 @@ size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t error, const char *reason, uint64_t retry_interval) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { + if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUEST_ERROR, moq->version)); return 0; @@ -3889,9 +4007,10 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * return offset; } -size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, size_t blen, +size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1 || track_namespace == NULL) { + if(bytes == NULL || blen < 1 || track_namespace == NULL || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE, moq->version)); return 0; @@ -3905,31 +4024,34 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, uint8_t *bytes, IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "publish_namespace"); json_t *message = imquic_qlog_moq_message_prepare("publish_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace) { - if(bytes == NULL || blen < 1 || track_namespace == NULL) { +size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id) { + if(bytes == NULL || blen < 1 || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE, moq->version)); return 0; } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE); - IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_DONE); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_namespace_done"); - imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); + json_object_set_new(message, "request_id", json_integer(request_id)); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); } #endif @@ -3937,15 +4059,15 @@ size_t imquic_moq_add_publish_namespace_done(imquic_moq_context *moq, uint8_t *b } size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_namespace *track_namespace, imquic_moq_request_error_code error, const char *reason) { - if(bytes == NULL || blen < 1 || track_namespace == NULL || (reason && strlen(reason) > 1024) || moq->version >= IMQUIC_MOQ_VERSION_17) { + uint64_t request_id, imquic_moq_request_error_code error, const char *reason) { + if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024) || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL, moq->version)); return 0; } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL); - IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE_CANCEL); + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, error, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; offset += imquic_write_moqint(moq->version, reason_len, &bytes[offset], blen-offset); @@ -3957,7 +4079,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_namespace_cancel"); - imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "error_code", json_integer(error)); if(reason != NULL) json_object_set_new(message, "reason", json_string(reason)); @@ -3967,10 +4089,11 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t return offset; } -size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { if(bytes == NULL || blen < 1 || track_namespace == NULL || - track_name == NULL || (track_name->buffer == NULL && track_name->length > 0)) { + track_name == NULL || (track_name->buffer == NULL && track_name->length > 0) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH, moq->version)); return 0; @@ -3991,6 +4114,8 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "publish"); json_t *message = imquic_qlog_moq_message_prepare("publish"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); @@ -3999,15 +4124,17 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, uint8_t *bytes, size_t bl json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 2) { + if(bytes == NULL || blen < 2 || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH, moq->version)); return 0; @@ -4024,16 +4151,18 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, uint8_t *bytes, size_t json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || track_namespace == NULL || - track_name == NULL || (track_name->buffer == NULL && track_name->length > 0)) { + track_name == NULL || (track_name->buffer == NULL && track_name->length > 0) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE, moq->version)); return 0; @@ -4048,21 +4177,24 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, uint8_t *bytes, size_t IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "subscribe"); json_t *message = imquic_qlog_moq_message_prepare("subscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, size_t blen, +size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUEST_UPDATE, moq->version)); return 0; @@ -4080,15 +4212,17 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, uint8_t *bytes, si json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 3 || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_OK, moq->version)); return 0; @@ -4113,14 +4247,15 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, uint8_t *bytes, size json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } size_t imquic_moq_add_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 2) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_UNSUBSCRIBE, moq->version)); return 0; @@ -4139,9 +4274,11 @@ size_t imquic_moq_add_unsubscribe(imquic_moq_context *moq, uint8_t *bytes, size_ return offset; } -size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_pub_done_code status, uint64_t streams_count, const char *reason) { - if(bytes == NULL || blen < 1 || (reason && strlen(reason) > 1024)) { + if(bytes == NULL || blen < 5 || (reason && strlen(reason) > 1024) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_PUBLISH_DONE, moq->version)); return 0; @@ -4166,7 +4303,8 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, uint8_t *bytes, size json_object_set_new(message, "streams_count", json_integer(streams_count)); if(reason != NULL) json_object_set_new(message, "reason", json_string(reason)); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; @@ -4190,15 +4328,14 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe_namespace"); + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "subscribe_namespace"); json_t *message = imquic_qlog_moq_message_prepare("subscribe_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace_prefix"); json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, - (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, moq_stream->stream_id, bytes, offset, message); } #endif return offset; @@ -4206,7 +4343,7 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st size_t imquic_moq_add_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || moq_stream == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_NAMESPACE, moq->version)); return 0; @@ -4229,7 +4366,7 @@ size_t imquic_moq_add_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || moq_stream == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_NAMESPACE_DONE, moq->version)); return 0; @@ -4250,11 +4387,13 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream return offset; } -size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, +size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, uint64_t request_id, uint64_t joining_request_id, uint64_t preceding_group_offset, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1 || (range == NULL && type == IMQUIC_MOQ_FETCH_STANDALONE)) { + if(bytes == NULL || blen < 1 || (range == NULL && type == IMQUIC_MOQ_FETCH_STANDALONE) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_FETCH, moq->version)); return 0; @@ -4290,6 +4429,8 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "fetch"); json_t *message = imquic_qlog_moq_message_prepare("fetch"); json_object_set_new(message, "request_id", json_integer(request_id)); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { @@ -4305,7 +4446,8 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, uint8_t *bytes, size_t blen } json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; @@ -4331,9 +4473,10 @@ size_t imquic_moq_add_fetch_cancel(imquic_moq_context *moq, uint8_t *bytes, size return offset; } -size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint8_t end_of_track, imquic_moq_location *end_location, imquic_moq_request_parameters *parameters, GList *track_properties) { - if(bytes == NULL || blen < 1) { + if(bytes == NULL || blen < 1 || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_FETCH_OK, moq->version)); return 0; @@ -4363,16 +4506,18 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, uint8_t *bytes, size_t b json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_qlog_moq_message_add_properties(message, track_properties, "track_properties"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; } -size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_track_status(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || track_namespace == NULL || - track_name == NULL || (track_name->buffer == NULL && track_name->length > 0)) { + track_name == NULL || (track_name->buffer == NULL && track_name->length > 0) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_TRACK_STATUS, moq->version)); return 0; @@ -4387,13 +4532,16 @@ size_t imquic_moq_add_track_status(imquic_moq_context *moq, uint8_t *bytes, size IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + if(moq_stream != NULL) + imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "track_status"); json_t *message = imquic_qlog_moq_message_prepare("track_status"); json_object_set_new(message, "request_id", json_integer(request_id)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); - imquic_moq_qlog_control_message_created(moq->conn->qlog, moq->control_stream_id, bytes, offset, message); + imquic_moq_qlog_control_message_created(moq->conn->qlog, + (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); } #endif return offset; @@ -4929,7 +5077,8 @@ int imquic_moq_set_connection_auth(imquic_connection *conn, uint8_t *auth, size_ int imquic_moq_set_max_request_id(imquic_connection *conn, uint64_t max_request_id) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL || max_request_id == 0 || moq->local_max_request_id >= max_request_id) { + if(moq == NULL || moq->version >= IMQUIC_MOQ_VERSION_17 || + max_request_id == 0 || moq->local_max_request_id >= max_request_id) { imquic_mutex_unlock(&moq_mutex); return -1; } @@ -5160,10 +5309,25 @@ int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, i imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_PUBLISH_NAMESPACE)); imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->request_type = IMQUIC_MOQ_PUBLISH_NAMESPACE; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; + g_atomic_int_set(&moq_stream->request_state, 1); + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t ann_len = imquic_moq_add_publish_namespace(moq, buffer, blen, request_id, tns, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t ann_len = imquic_moq_add_publish_namespace(moq, moq_stream, buffer, blen, request_id, tns, parameters); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, ann_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5181,12 +5345,27 @@ int imquic_moq_accept_publish_namespace(imquic_connection *conn, uint64_t reques } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if the request ID exists */ - /* TODO Check if this namespace exists and was publish_namespaced here */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_OK/ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t ann_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t ann_len = imquic_moq_add_request_ok(moq, moq_stream, buffer, blen, request_id, parameters); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, ann_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5205,22 +5384,37 @@ int imquic_moq_reject_publish_namespace(imquic_connection *conn, uint64_t reques } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if the request ID exists */ - /* TODO Check if this namespace exists and was publish_namespaced here */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_OK/ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t ann_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t ann_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, ann_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); return 0; } -int imquic_moq_publish_namespace_done(imquic_connection *conn, imquic_moq_namespace *tns) { +int imquic_moq_publish_namespace_done(imquic_connection *conn, uint64_t request_id) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0) { + if(moq == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq_mutex); @@ -5228,10 +5422,31 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, imquic_moq_namesp } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if this namespace exists and was publish_namespaced here */ + /* Check if we have a STREAM to close */ + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + /* On newer versions of MoQ, requests uses a dedicated + * bidirectional STREAM, so we simply close the STREAM */ + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || !moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + /* Reset the STREAM */ + imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + return 0; + } + /* If we're here,we're sending the legacy PUBLISH_NAMESPACE_DONE */ uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t ann_len = imquic_moq_add_publish_namespace_done(moq, buffer, blen, tns); + size_t ann_len = imquic_moq_add_publish_namespace_done(moq, buffer, blen, request_id); imquic_connection_send_on_stream(conn, moq->control_stream_id, buffer, ann_len, FALSE); /* Done */ @@ -5270,12 +5485,27 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_ imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_PUBLISH)); imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->request_type = IMQUIC_MOQ_PUBLISH; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; + g_atomic_int_set(&moq_stream->request_state, 1); + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; - sb_len = imquic_moq_add_publish(moq, buffer, blen, + sb_len = imquic_moq_add_publish(moq, moq_stream, buffer, blen, request_id, tns, tn, track_alias, parameters, track_properties); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5302,12 +5532,28 @@ int imquic_moq_accept_publish(imquic_connection *conn, uint64_t request_id, imqu imquic_refcount_decrease(&moq->ref); return -1; } - /* TODO Check if we were subscribed */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the PUBLISH_OK responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; - sb_len = imquic_moq_add_publish_ok(moq, buffer, blen, request_id, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + sb_len = imquic_moq_add_publish_ok(moq, moq_stream, buffer, blen, request_id, parameters); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5326,11 +5572,27 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were subscribed */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5371,12 +5633,27 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_SUBSCRIBE)); imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; + g_atomic_int_set(&moq_stream->request_state, 1); + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; - sb_len = imquic_moq_add_subscribe(moq, buffer, blen, + sb_len = imquic_moq_add_subscribe(moq, moq_stream, buffer, blen, request_id, tns, tn, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5395,20 +5672,36 @@ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, ui } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were subscribed */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the SUBSCRIBE_OK responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } imquic_mutex_lock(&moq->mutex); imquic_moq_subscription *moq_sub = g_hash_table_lookup(moq->subscriptions_by_id, &request_id); if(moq_sub != NULL) { - /* Track this subscription */ + /* Track this subscription */ moq_sub->track_alias = track_alias; g_hash_table_insert(moq->subscriptions, imquic_dup_uint64(track_alias), moq_sub); } imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = imquic_moq_add_subscribe_ok(moq, buffer, blen, + size_t sb_len = imquic_moq_add_subscribe_ok(moq, moq_stream, buffer, blen, request_id, track_alias, parameters, track_properties); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5427,11 +5720,27 @@ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were subscribed */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5463,11 +5772,28 @@ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_UPDATE)); imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_UPDATE responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type == 0 || !moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t su_len = imquic_moq_add_request_update(moq, buffer, blen, + size_t su_len = imquic_moq_add_request_update(moq, moq_stream, buffer, blen, request_id, sub_request_id, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, su_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5485,12 +5811,27 @@ int imquic_moq_accept_request_update(imquic_connection *conn, uint64_t request_i } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if the request ID exists */ - /* TODO Check if we were subscribed */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_OK responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type == 0 || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t sb_len = imquic_moq_add_request_ok(moq, moq_stream, buffer, blen, request_id, parameters); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5509,11 +5850,27 @@ int imquic_moq_reject_request_update(imquic_connection *conn, uint64_t request_i } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were subscribed */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type == 0 || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t sb_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5531,7 +5888,28 @@ int imquic_moq_unsubscribe(imquic_connection *conn, uint64_t request_id) { } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were subscribed */ + /* Check if we have a STREAM to close */ + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + /* On newer versions of MoQ, requests uses a dedicated + * bidirectional STREAM, so we simply close the STREAM */ + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || !moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + /* Reset the STREAM */ + imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + return 0; + } + /* If we're here,we're sending the legacy UNSUBSCRIBE */ uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = imquic_moq_add_unsubscribe(moq, buffer, blen, request_id); @@ -5565,12 +5943,28 @@ int imquic_moq_publish_done(imquic_connection *conn, uint64_t request_id, imquic } uint64_t streams_count = moq_sub->streams_count; imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the PUBLISH_DONE responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || !moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - /* TODO Compute streams count */ - size_t sd_len = imquic_moq_add_publish_done(moq, buffer, blen, + size_t sd_len = imquic_moq_add_publish_done(moq, moq_stream, buffer, blen, request_id, status_code, streams_count, reason); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sd_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5617,6 +6011,8 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_stream *moq_stream = g_malloc0(sizeof(imquic_moq_stream)); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE_NAMESPACE; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -5625,14 +6021,14 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, size_t sb_len = 0; sb_len = imquic_moq_add_subscribe_namespace(moq, moq_stream, buffer, blen, request_id, tns, subscribe_options, parameters); /* Track the request, and map it to the dedicated bidirectional STREAM */ - g_atomic_int_set(&moq_stream->subscribe_namespace_state, 1); + g_atomic_int_set(&moq_stream->request_state, 1); moq_stream->request_id = request_id; moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); while(moq_stream->last_tuple->next != NULL) moq_stream->last_tuple = moq_stream->last_tuple->next; moq_stream->namespace_prefix_size = tns_num; imquic_mutex_lock(&moq->mutex); - g_hash_table_insert(moq->tns_subscriptions_by_id, imquic_dup_uint64(request_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); /* Send on the dedicated bidirectional STREAM */ imquic_connection_send_on_stream(conn, moq_stream->stream_id, @@ -5656,13 +6052,13 @@ int imquic_moq_accept_subscribe_namespace(imquic_connection *conn, uint64_t requ /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ imquic_mutex_lock(&moq->mutex); - imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || - !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -5692,13 +6088,13 @@ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t requ /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated * bidirectional STREAM, and the same applies to REQUEST_OK/ERROR */ imquic_mutex_lock(&moq->mutex); - imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || - !g_atomic_int_compare_and_exchange(&moq_stream->subscribe_namespace_state, 1, 2)) { + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -5728,8 +6124,9 @@ int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_i * bidirectional STREAM, so unsubscribing is done without sending * any actual message: we simply close the STREAM */ imquic_mutex_lock(&moq->mutex); - imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL) { + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || + !moq_stream->request_sender) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments: no such subscription\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq->mutex); @@ -5738,7 +6135,7 @@ int imquic_moq_unsubscribe_namespace(imquic_connection *conn, uint64_t request_i } /* Reset the STREAM */ imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); - g_hash_table_remove(moq->tns_subscriptions_by_id, &request_id); + g_hash_table_remove(moq->streams_by_reqid, &request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); @@ -5758,11 +6155,12 @@ int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, im imquic_mutex_unlock(&moq_mutex); /* Check if the request ID exists */ imquic_mutex_lock(&moq->mutex); - imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || - g_atomic_int_get(&moq_stream->subscribe_namespace_state) < 2 || + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2 || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", imquic_get_connection_name(conn)); return -1; @@ -5797,14 +6195,14 @@ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_i imquic_mutex_unlock(&moq_mutex); /* Check if the request ID exists */ imquic_mutex_lock(&moq->mutex); - imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->tns_subscriptions_by_id, &request_id); - if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || !moq_stream->namespace_publisher || - g_atomic_int_get(&moq_stream->subscribe_namespace_state) < 2 || + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2 || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", imquic_get_connection_name(conn)); - imquic_mutex_unlock(&moq_mutex); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -5848,16 +6246,31 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_FETCH)); imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->request_type = IMQUIC_MOQ_FETCH; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; + g_atomic_int_set(&moq_stream->request_state, 1); + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t f_len = 0; - f_len = imquic_moq_add_fetch(moq, buffer, blen, + f_len = imquic_moq_add_fetch(moq, moq_stream, buffer, blen, IMQUIC_MOQ_FETCH_STANDALONE, request_id, 0, 0, /* Ignored, as they're only used for Joining Fetch */ tns, tn, range, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, f_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5888,16 +6301,31 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_FETCH)); imquic_mutex_unlock(&moq->mutex); + /* Starting from v17, requests on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->request_type = IMQUIC_MOQ_FETCH; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; + g_atomic_int_set(&moq_stream->request_state, 1); + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t f_len = 0; - f_len = imquic_moq_add_fetch(moq, buffer, blen, + f_len = imquic_moq_add_fetch(moq, moq_stream, buffer, blen, (absolute ? IMQUIC_MOQ_FETCH_JOINING_ABSOLUTE : IMQUIC_MOQ_FETCH_JOINING_RELATIVE), request_id, joining_request_id, joining_start, NULL, NULL, /* Ignored, as namespaces/track are only used for Standalone Fetch */ NULL, /* Ignored, as the fetch range is only used for Standalone Fetch */ parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, f_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5916,16 +6344,32 @@ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, imquic } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were fetched */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the FETCH_OK responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_FETCH || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); /* TODO Make other properties configurable */ - size_t f_len = imquic_moq_add_fetch_ok(moq, buffer, blen, + size_t f_len = imquic_moq_add_fetch_ok(moq, moq_stream, buffer, blen, request_id, 0, /* TODO End of track */ largest, /* Largest location */ parameters, track_properties); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, f_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -5944,11 +6388,27 @@ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); - /* TODO Check if we were fetched */ + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type == 0 || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t f_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t f_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, f_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -6011,13 +6471,27 @@ int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_TRACK_STATUS)); imquic_mutex_unlock(&moq->mutex); - /* Send the request */ + /* Starting from v17, requests on a dedicated bidirectional STREAM */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); + moq_stream->request_type = IMQUIC_MOQ_TRACK_STATUS; + moq_stream->request_id = request_id; + moq_stream->request_sender = TRUE; + g_atomic_int_set(&moq_stream->request_state, 1); + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); + g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; - sb_len = imquic_moq_add_track_status(moq, buffer, blen, + sb_len = imquic_moq_add_track_status(moq, moq_stream, buffer, blen, request_id, tns, tn, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -6036,10 +6510,27 @@ int imquic_moq_accept_track_status(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_OK responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_TRACK_STATUS || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t tso_len = imquic_moq_add_request_ok(moq, NULL, buffer, blen, request_id, parameters); - imquic_connection_send_on_stream(conn, moq->control_stream_id, + size_t tso_len = imquic_moq_add_request_ok(moq, moq_stream, buffer, blen, request_id, parameters); + imquic_connection_send_on_stream(conn, + moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, tso_len, FALSE); /* Done */ imquic_refcount_decrease(&moq->ref); @@ -6058,6 +6549,22 @@ int imquic_moq_reject_track_status(imquic_connection *conn, uint64_t request_id, } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); + /* Starting from v17, requests go on a dedicated bidirectional + * STREAM, and the same applies to the REQUEST_ERROR responses */ + imquic_moq_stream *moq_stream = NULL; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + imquic_mutex_lock(&moq->mutex); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_TRACK_STATUS || moq_stream->request_sender || + !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t tsr_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); @@ -6071,7 +6578,7 @@ int imquic_moq_reject_track_status(imquic_connection *conn, uint64_t request_id, int imquic_moq_requests_blocked(imquic_connection *conn) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL) { + if(moq == NULL || moq->version >= IMQUIC_MOQ_VERSION_17) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq_mutex); From 38db87a4cbaabe0f4dfdfb1564d1c2fed1f7bdd1 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 6 Mar 2026 18:55:02 +0100 Subject: [PATCH 15/30] Added Required Request ID Delta to API --- examples/moq-interop-test.c | 10 +- examples/moq-pub.c | 6 +- examples/moq-relay.c | 16 +-- examples/moq-sub.c | 19 +-- examples/moq-test.c | 8 +- src/imquic-moq.c | 12 +- src/imquic/moq.h | 35 +++-- src/internal/moq.h | 31 ++-- src/moq.c | 275 ++++++++++++++++++++++++++---------- 9 files changed, 277 insertions(+), 135 deletions(-) diff --git a/examples/moq-interop-test.c b/examples/moq-interop-test.c index ff6a219..7f1359f 100644 --- a/examples/moq-interop-test.c +++ b/examples/moq-interop-test.c @@ -143,7 +143,7 @@ static void imquic_moq_interop_publish_namespace_accepted(imquic_connection *con imquic_moq_request_parameters *parameters); static void imquic_moq_interop_publish_namespace_error(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); -static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, +static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); static void imquic_moq_interop_subscribe_accepted(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); @@ -527,7 +527,7 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { tns[1].length = strlen("interop"); tns[1].next = NULL; client->request_id = imquic_moq_get_next_request_id(conn); - imquic_moq_publish_namespace(conn, client->request_id, &tns[0], NULL); + imquic_moq_publish_namespace(conn, client->request_id, 0, &tns[0], NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("publisher announced namespace")); } else if(test->name == IMQUIC_INTEROP_SUBSCRIBE_ERROR) { @@ -544,7 +544,7 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { .length = strlen("test-track") }; client->request_id = imquic_moq_get_next_request_id(conn); - imquic_moq_subscribe(conn, client->request_id, &tns[0], &tn, NULL); + imquic_moq_subscribe(conn, client->request_id, 0, &tns[0], &tn, NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("subscriber subscribed to non-existing track")); } else if((test->name == IMQUIC_INTEROP_ANNOUNCE_SUBSCRIBE || @@ -562,7 +562,7 @@ static void imquic_moq_interop_ready(imquic_connection *conn) { .length = strlen("test-track") }; client->request_id = imquic_moq_get_next_request_id(conn); - imquic_moq_subscribe(conn, client->request_id, &tns[0], &tn, NULL); + imquic_moq_subscribe(conn, client->request_id, 0, &tns[0], &tn, NULL); if(verbose) test->subtests = g_list_append(test->subtests, g_strdup("subscriber subscribed to track")); if(test->name == IMQUIC_INTEROP_SUBSCRIBE_BEFORE_ANNOUNCE) { @@ -626,7 +626,7 @@ static void imquic_moq_interop_publish_namespace_error(imquic_connection *conn, /* TODO Other tests */ } -static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, +static void imquic_moq_interop_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { /* Depending on the test, we may or may not be done */ imquic_mutex_lock(&mutex); diff --git a/examples/moq-pub.c b/examples/moq-pub.c index 4885830..e95f6df 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -120,7 +120,7 @@ static void imquic_demo_ready(imquic_connection *conn) { } } moq_tns_request_id = imquic_moq_get_next_request_id(conn); - imquic_moq_publish_namespace(conn, moq_tns_request_id, &tns[0], ¶ms); + imquic_moq_publish_namespace(conn, moq_tns_request_id, 0, &tns[0], ¶ms); } else { /* We use PUBLISH */ IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Publishing namespace/track '%s--%s'\n", imquic_get_connection_name(conn), pub_tns, pub_tn); @@ -142,7 +142,7 @@ static void imquic_demo_ready(imquic_connection *conn) { imquic_get_connection_name(conn)); } } - imquic_moq_publish(conn, moq_request_id, &tns[0], &tn, moq_track_alias, ¶ms, NULL); + imquic_moq_publish(conn, moq_request_id, 0, &tns[0], &tn, moq_track_alias, ¶ms, NULL); } } @@ -176,7 +176,7 @@ static void imquic_demo_publish_error(imquic_connection *conn, uint64_t request_ g_atomic_int_inc(&stop); } -static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, +static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); diff --git a/examples/moq-relay.c b/examples/moq-relay.c index b0a23ed..bb10bbd 100644 --- a/examples/moq-relay.c +++ b/examples/moq-relay.c @@ -412,7 +412,7 @@ static void imquic_demo_alert_monitors(imquic_demo_moq_published_namespace *annc }; imquic_moq_request_parameters params; imquic_moq_request_parameters_init_defaults(¶ms); - imquic_moq_publish(mon->conn, relay_request_id, tns, &tn, relay_track_alias, ¶ms, track->properties); + imquic_moq_publish(mon->conn, relay_request_id, 0, tns, &tn, relay_track_alias, ¶ms, track->properties); } temp = temp->next; } @@ -475,7 +475,7 @@ static void imquic_demo_ready(imquic_connection *conn) { peer ? peer : "unknown implementation"); } -static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters) { +static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters) { /* We received an publish_namespace */ char buffer[256]; const char *ns = imquic_moq_namespace_str(tns, buffer, sizeof(buffer), TRUE); @@ -569,7 +569,7 @@ static void imquic_demo_publish_namespace_done(imquic_connection *conn, uint64_t imquic_mutex_unlock(&mutex); } -static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, +static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { /* We received a publish */ char tns_buffer[256], tn_buffer[256]; @@ -785,7 +785,7 @@ static void imquic_demo_incoming_track_status(imquic_connection *conn, uint64_t imquic_moq_accept_track_status(conn, request_id, &rparams); } -static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, +static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { /* We received a subscribe */ char tns_buffer[256], tn_buffer[256]; @@ -911,7 +911,7 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req params.forward = TRUE; params.subscription_filter_set = TRUE; params.subscription_filter.type = IMQUIC_MOQ_FILTER_LARGEST_OBJECT; - if(imquic_moq_subscribe(annc->pub->conn, track->request_id, tns, tn, ¶ms) < 0) { + if(imquic_moq_subscribe(annc->pub->conn, track->request_id, 0, tns, tn, ¶ms) < 0) { g_hash_table_remove(annc->pub->subscriptions_by_id, &track->request_id); imquic_moq_reject_subscribe(conn, request_id, IMQUIC_MOQ_REQERR_INTERNAL_ERROR, "Error creating upstream subscription", 0); } @@ -1098,7 +1098,7 @@ static void imquic_demo_incoming_unsubscribe(imquic_connection *conn, uint64_t r imquic_mutex_unlock(&mutex); } -static void imquic_demo_incoming_subscribe_namespace(imquic_connection *conn, uint64_t request_id, +static void imquic_demo_incoming_subscribe_namespace(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters) { /* We received a subscribe for a namespace tuple */ char tns_buffer[256]; @@ -1153,7 +1153,7 @@ static void imquic_demo_incoming_unsubscribe_namespace(imquic_connection *conn, imquic_mutex_unlock(&mutex); } -static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint64_t request_id, +static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { //~ gboolean descending, imquic_moq_location_range *range, uint8_t *auth, size_t authlen) { /* We received a standalone fetch */ @@ -1242,7 +1242,7 @@ static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint6 imquic_mutex_unlock(&mutex); } -static void imquic_demo_incoming_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id , +static void imquic_demo_incoming_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters) { /* We received a joining fetch */ IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming %s joining fetch for subscription %"SCNu64" (ID %"SCNu64"; start=%"SCNu64"; %s order)\n", diff --git a/examples/moq-sub.c b/examples/moq-sub.c index 5f6a212..e4fc52f 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -196,7 +196,7 @@ static void imquic_demo_ready(imquic_connection *conn) { params.forward = TRUE; if(options.update_subscribe > 0 && (options.fetch == NULL || options.join_offset >= 0)) params.forward = FALSE; - imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), tns, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); + imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), 0, tns, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); return; } /* Parameters in case we need to FETCH */ @@ -237,7 +237,7 @@ static void imquic_demo_ready(imquic_connection *conn) { if(options.fetch == NULL) { if(!options.track_status) { /* Send a SUBSCRIBE */ - imquic_moq_subscribe(conn, request_id, &tns[0], &tn, ¶ms); + imquic_moq_subscribe(conn, request_id, 0, &tns[0], &tn, ¶ms); if(!params.forward) request_ids = g_list_append(request_ids, imquic_uint64_dup(request_id)); } else { @@ -252,10 +252,10 @@ static void imquic_demo_ready(imquic_connection *conn) { .start = start_location, .end = end_location }; - imquic_moq_standalone_fetch(conn, request_id, &tns[0], &tn, &range, &fparams); + imquic_moq_standalone_fetch(conn, request_id, 0, &tns[0], &tn, &range, &fparams); } else { /* Send a SUBSCRIBE first, we'll send the joining FETCH when the subscription is accepted */ - imquic_moq_subscribe(conn, request_id, &tns[0], &tn, ¶ms); + imquic_moq_subscribe(conn, request_id, 0, &tns[0], &tn, ¶ms); if(!params.forward) request_ids = g_list_append(request_ids, imquic_uint64_dup(request_id)); } @@ -269,7 +269,8 @@ static void imquic_demo_ready(imquic_connection *conn) { } } -static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters) { +static void imquic_demo_incoming_publish_namespace(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, + imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters) { /* We received an PUBLISH_NAMESPACE (older MoQ version) */ char buffer[256]; const char *ns = imquic_moq_namespace_str(tns, buffer, sizeof(buffer), TRUE); @@ -357,7 +358,7 @@ static void imquic_demo_subscribe_accepted(imquic_connection *conn, uint64_t req uint64_t fetch_request_id = imquic_moq_get_next_request_id(conn); IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Sending Joining Fetch for subscription %"SCNu64", using ID %"SCNu64" (offset=%d)\n", imquic_get_connection_name(conn), request_id, fetch_request_id, options.join_offset); - imquic_moq_joining_fetch(conn, fetch_request_id, request_id, + imquic_moq_joining_fetch(conn, fetch_request_id, 0, request_id, FALSE, options.join_offset, &fparams); } } @@ -379,8 +380,8 @@ static void imquic_demo_request_update_error(imquic_connection *conn, uint64_t r imquic_get_connection_name(conn), request_id, error_code, reason); } -static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { +static void imquic_demo_incoming_publish(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, + imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { /* We received a publish */ char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); @@ -622,7 +623,7 @@ static void imquic_demo_incoming_object(imquic_connection *conn, imquic_moq_obje params.subscription_filter.type = filter_type; params.subscription_filter.start_location = start_location; params.subscription_filter.end_group = end_location_sub.group; - imquic_moq_subscribe(conn, request_id, &tns[0], &tn, ¶ms); + imquic_moq_subscribe(conn, request_id, 0, &tns[0], &tn, ¶ms); } if(object->end_of_stream) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Stream closed (status '%s' and eos=%d)\n", diff --git a/examples/moq-test.c b/examples/moq-test.c index 31a615a..bcbe930 100644 --- a/examples/moq-test.c +++ b/examples/moq-test.c @@ -307,7 +307,7 @@ static void imquic_demo_ready(imquic_connection *conn) { peer ? peer : "unknown implementation"); } -static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, +static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { /* We received a subscribe */ char tns_buffer[256], tn_buffer[256]; @@ -437,8 +437,8 @@ static void imquic_demo_incoming_unsubscribe(imquic_connection *conn, uint64_t r g_mutex_unlock(&mutex); } -static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, - imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { +static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, + imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { /* We received a standalone fetch */ char tns_buffer[256], tn_buffer[256]; const char *ns = imquic_moq_namespace_str(tns, tns_buffer, sizeof(tns_buffer), TRUE); @@ -523,7 +523,7 @@ static void imquic_demo_incoming_standalone_fetch(imquic_connection *conn, uint6 } } -static void imquic_demo_incoming_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id , +static void imquic_demo_incoming_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id , gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters) { /* We received a joining fetch */ IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming %s joining fetch for subscription %"SCNu64" (ID %"SCNu64"; start=%"SCNu64"; %s order)\n", diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 1a5993b..c78d372 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -420,7 +420,7 @@ void imquic_set_moq_ready_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_publish_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters)) { + void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -475,7 +475,7 @@ void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_publish_cb(imquic_endpoint *endpoint, - void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, + void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { @@ -509,7 +509,7 @@ void imquic_set_publish_error_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_subscribe_cb(imquic_endpoint *endpoint, - void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, + void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { @@ -609,7 +609,7 @@ void imquic_set_requests_blocked_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_subscribe_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, + void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { @@ -676,7 +676,7 @@ void imquic_set_incoming_namespace_done_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_standalone_fetch_cb(imquic_endpoint *endpoint, - void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, + void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { @@ -688,7 +688,7 @@ void imquic_set_incoming_standalone_fetch_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_joining_fetch_cb(imquic_endpoint *endpoint, - void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, + void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 5ec9ff6..b663d5a 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -856,7 +856,7 @@ void imquic_set_moq_ready_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_publish_namespace Pointer to the function that will handle the incoming \c PUBLISH_NAMESPACE */ void imquic_set_incoming_publish_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters)); + void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's * an incoming \c PUBLISH_NAMESPACE_CANCEL request. * \note Starting in v17, \c PUBLISH_NAMESPACE_CANCEL doesn't exist anymore, @@ -894,7 +894,7 @@ void imquic_set_publish_namespace_done_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_publish Pointer to the function that will handle the incoming \c PUBLISH */ void imquic_set_incoming_publish_cb(imquic_endpoint *endpoint, - void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, + void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties)); /*! \brief Configure the callback function to be notified when a * \c PUBLISH we previously sent was accepted @@ -913,7 +913,7 @@ void imquic_set_publish_error_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_subscribe Pointer to the function that will handle the incoming \c SUBSCRIBE */ void imquic_set_incoming_subscribe_cb(imquic_endpoint *endpoint, - void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, + void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when a * \c SUBSCRIBE we previously sent was accepted @@ -972,7 +972,7 @@ void imquic_set_requests_blocked_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_subscribe_namespace Pointer to the function that will handle the incoming \c SUBSCRIBE_NAMESPACE */ void imquic_set_incoming_subscribe_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, + void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when an * \c SUBSCRIBE_NAMESPACE we previously sent was accepted @@ -1012,14 +1012,14 @@ void imquic_set_incoming_namespace_done_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_standalone_fetch Pointer to the function that will handle the incoming \c FETCH */ void imquic_set_incoming_standalone_fetch_cb(imquic_endpoint *endpoint, - void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, + void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's * an incoming joining \c FETCH request. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param incoming_joining_fetch Pointer to the function that will handle the incoming \c FETCH */ void imquic_set_incoming_joining_fetch_cb(imquic_endpoint *endpoint, - void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, + void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when there's * an incoming \c FETCH_CANCEL request. @@ -1127,11 +1127,12 @@ const char *imquic_moq_get_remote_implementation(imquic_connection *conn); /*! \brief Function to send a \c PUBLISH_NAMESPACE request * @param conn The imquic_connection to send the request on * @param request_id A unique request ID + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param tns The imquic_moq_namespace namespace to publish_namespace * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, - imquic_moq_request_parameters *parameters); +int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, + uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c PUBLISH_NAMESPACE request * @param conn The imquic_connection to send the request on * @param request_id The request ID of the original \c PUBLISH_NAMESPACE request @@ -1156,13 +1157,15 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, uint64_t request_ /*! \brief Function to send a \c PUBLISH request * @param conn The imquic_connection to send the request on * @param request_id A unique request ID to associate to this subscription + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param tns The imquic_moq_namespace namespace the track to publish to belongs to * @param tn The imquic_moq_name track name to publish to * @param track_alias A unique numeric identifier to associate to the track in this subscription * @param parameters The parameters to add to the request * @param track_properties List of track properties to add, if any * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, +int imquic_moq_publish(imquic_connection *conn, + uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Function to accept an incoming \c PUBLISH request @@ -1183,11 +1186,12 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, /*! \brief Function to send a \c SUBSCRIBE request * @param conn The imquic_connection to send the request on * @param request_id A unique request ID to associate to this subscription + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param tns The imquic_moq_namespace namespace the track to subscribe to belongs to * @param tn The imquic_moq_name track name to subscribe to * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, +int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c SUBSCRIBE request * @param conn The imquic_connection to send the request on @@ -1248,11 +1252,12 @@ int imquic_moq_unsubscribe(imquic_connection *conn, uint64_t request_id); /*! \brief Function to send a \c SUBSCRIBE_NAMESPACE request * @param conn The imquic_connection to send the request on * @param request_id A unique request ID + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param tns The imquic_moq_namespace namespace the track to subscribe to belongs to * @param subscribe_options The subscribe options to add to the request * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, +int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c SUBSCRIBE_NAMESPACE request * @param conn The imquic_connection to send the request on @@ -1300,24 +1305,28 @@ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_i /*! \brief Function to send a standalone \c FETCH request * @param conn The imquic_connection to send the request on * @param request_id A unique numeric identifier to associate to this subscription + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param tns The imquic_moq_namespace namespace the track to fetch to belongs to * @param tn The imquic_moq_name track name to fetch to * @param range The range of groups/objects to fetch * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, +int imquic_moq_standalone_fetch(imquic_connection *conn, + uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); /*! \brief Function to send a joining \c FETCH request * @param conn The imquic_connection to send the request on * @param request_id A unique numeric identifier to associate to this subscription + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param joining_request_id Existing subscription to join * @param absolute Whether this is an absolute or relative joining \c FETCH * @param joining_start How many groups to retrieve before the current one, * for relative joins, or starting group ID for absolute joins * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ -int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, +int imquic_moq_joining_fetch(imquic_connection *conn, + uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c FETCH request * @param conn The imquic_connection to send the request on diff --git a/src/internal/moq.h b/src/internal/moq.h index ef95841..5f3665a 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -766,11 +766,13 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message + * @param required_id_delta The required request ID delta to put in the message (ignored before v17) * @param track_namespace Namespace to publish_namespace * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, - uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters); + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, + imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c PUBLISH_NAMESPACE_DONE message to a buffer * \note This message was deprecated in v17 * @param moq The imquic_moq_context generating the message @@ -796,6 +798,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message + * @param required_id_delta The required request ID delta to put in the message (ignored before v17) * @param track_namespace The namespace to put in the message * @param track_name The track name to put in the message * @param track_alias The track alias to put in the message @@ -803,7 +806,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t * @param track_properties List of track properties to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, - uint8_t *bytes, size_t blen, uint64_t request_id, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Helper method to add a \c PUBLISH_OK message to a buffer @@ -822,12 +825,13 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message + * @param required_id_delta The required request ID delta to put in the message (ignored before v17) * @param track_namespace The namespace to put in the message * @param track_name The track name to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, - uint8_t *bytes, size_t blen, uint64_t request_id, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c REQUEST_UPDATE message to a buffer * @param moq The imquic_moq_context generating the message @@ -880,12 +884,14 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *m * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message + * @param required_id_delta The required request ID delta to put in the message (ignored before v17) * @param track_namespace The namespace to put in the message * @param subscribe_options The subscribe options to put in the message * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ -size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters); +size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, + imquic_moq_namespace *track_namespace, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c NAMESPACE_DONE message to a buffer * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for @@ -911,6 +917,7 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream * @param blen The size of the buffer * @param type The FETCH type * @param request_id The request ID to put in the message + * @param required_id_delta The required request ID delta to put in the message (ignored before v17) * @param joining_request_id The joining request ID to put in the message, if any * @param preceding_group_offset The preceding group offset for joining fetches, if any * @param track_namespace The namespace to put in the message @@ -920,7 +927,7 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, - uint64_t request_id, uint64_t joining_request_id, uint64_t preceding_group_offset, + uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, uint64_t preceding_group_offset, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add an \c FETCH_CANCEL message to a buffer @@ -1154,7 +1161,7 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified when a MoQ connection is ready (setup performed on both ends) */ void (* moq_ready)(imquic_connection *conn); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE messages */ - void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters); + void (* incoming_publish_namespace)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_CANCEL messages, or when the bidirectional stream is closed */ void (* incoming_publish_namespace_cancel)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason); /*! \brief Callback function to be notified about incoming \c PUBLISH_NAMESPACE_ACCEPTED messages */ @@ -1165,14 +1172,14 @@ typedef struct imquic_moq_callbacks { * \note This message was deprecated in v17 */ void (* publish_namespace_done)(imquic_connection *conn, uint64_t request_id); /*! \brief Callback function to be notified about incoming \c PUBLISH messages */ - void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, + void (* incoming_publish)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); /*! \brief Callback function to be notified about incoming \c PUBLISH_ACCEPTED messages */ void (* publish_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c PUBLISH_ERROR messages */ void (* publish_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE messages */ - void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, + void (* incoming_subscribe)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_ACCEPTED messages */ void (* subscribe_accepted)(imquic_connection *conn, uint64_t request_id, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties); @@ -1192,7 +1199,7 @@ typedef struct imquic_moq_callbacks { * \note This message was deprecated in v17 */ void (* requests_blocked)(imquic_connection *conn, uint64_t max_request_id); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_NAMESPACE messages */ - void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, + void (* incoming_subscribe_namespace)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_NAMESPACE_ACCEPTED messages */ void (* subscribe_namespace_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); @@ -1205,9 +1212,9 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming \c NAMESPACE_DONE messages */ void (* incoming_namespace_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); /*! \brief Callback function to be notified about incoming \c FETCH messages */ - void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, + void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); - void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, + void (* incoming_joining_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming \c FETCH_CANCEL messages, or when the bidirectional stream is closed */ void (* incoming_fetch_cancel)(imquic_connection *conn, uint64_t request_id); diff --git a/src/moq.c b/src/moq.c index c9055e1..53997e8 100644 --- a/src/moq.c +++ b/src/moq.c @@ -2048,11 +2048,16 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); + uint64_t request_id = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), request_id); + } else { + request_id = moq_stream->request_id; + } uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken REQUEST_OK"); IMQUIC_MOQ_CHECK_ERR(params_num == 0 && (length == 0 || length > blen-offset), NULL, 0, 0, "Broken REQUEST_OK"); @@ -2069,7 +2074,8 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, @@ -2119,11 +2125,16 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR on bidirectional request"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); + uint64_t request_id = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), request_id); + } else { + request_id = moq_stream->request_id; + } uint64_t error_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); offset += length; @@ -2153,7 +2164,8 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "error_code", json_integer(error_code)); json_object_set_new(message, "retry_interval", json_integer(retry_interval)); if(reason_str != NULL) @@ -2221,6 +2233,14 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_st offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); + uint64_t required_id_delta = 0; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + required_id_delta = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Required Request ID Delta: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), required_id_delta); + } imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; @@ -2244,6 +2264,8 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_st imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "publish_namespace"); json_t *message = imquic_qlog_moq_message_prepare("publish_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); @@ -2263,7 +2285,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_st } /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish_namespace) { - moq->conn->socket->callbacks.moq.incoming_publish_namespace(moq->conn, request_id, &tns[0], ¶meters); + moq->conn->socket->callbacks.moq.incoming_publish_namespace(moq->conn, request_id, required_id_delta, &tns[0], ¶meters); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_publish_namespace(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); @@ -2281,7 +2303,7 @@ size_t imquic_moq_parse_publish_namespace_done(imquic_moq_context *moq, uint8_t size_t offset = 0; uint8_t length = 0; uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE"); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_NAMESPACE_DONE"); offset += length; #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -2362,6 +2384,14 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_ offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); + uint64_t required_id_delta = 0; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + required_id_delta = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Required Request ID Delta: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), required_id_delta); + } imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; @@ -2407,6 +2437,8 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_ imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "publish"); json_t *message = imquic_qlog_moq_message_prepare("publish"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "track_alias", json_integer(track_alias)); @@ -2430,7 +2462,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_ /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish) { moq->conn->socket->callbacks.moq.incoming_publish(moq->conn, - request_id, &tns[0], &tn, track_alias, ¶meters, track_properties); + request_id, required_id_delta, &tns[0], &tn, track_alias, ¶meters, track_properties); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_publish(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); @@ -2451,11 +2483,16 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *m error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); + uint64_t request_id = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), request_id); + } else { + request_id = moq_stream->request_id; + } imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2473,7 +2510,8 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *m #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, @@ -2503,6 +2541,14 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *mo offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); + uint64_t required_id_delta = 0; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + required_id_delta = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Required Request ID Delta: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), required_id_delta); + } /* Move on */ imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); @@ -2530,6 +2576,8 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *mo imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe"); json_t *message = imquic_qlog_moq_message_prepare("subscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); imquic_qlog_moq_message_add_track(message, &tn); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); @@ -2556,7 +2604,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *mo /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_subscribe) { moq->conn->socket->callbacks.moq.incoming_subscribe(moq->conn, - request_id, &tns[0], &tn, ¶meters); + request_id, required_id_delta, &tns[0], &tn, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_subscribe(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); @@ -2605,7 +2653,10 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_strea if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_update"); json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); + else + json_object_set_new(message, "required_request_id_delta", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); @@ -2637,11 +2688,16 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); + uint64_t request_id = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), request_id); + } else { + request_id = moq_stream->request_id; + } uint64_t track_alias = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_OK"); offset += length; @@ -2678,7 +2734,8 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("subscribe_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); @@ -2743,11 +2800,16 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, imquic_moq_stream error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_DONE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); + uint64_t request_id = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), request_id); + } else { + request_id = moq_stream->request_id; + } uint64_t status_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH_DONE"); offset += length; @@ -2777,7 +2839,8 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, imquic_moq_stream #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_done"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "status_code", json_integer(status_code)); json_object_set_new(message, "streams_count", json_integer(streams_count)); if(reason_str != NULL) @@ -2811,6 +2874,14 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); + uint64_t required_id_delta = 0; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + required_id_delta = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken SUBSCRIBE_NAMESPACE"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Required Request ID Delta: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), required_id_delta); + } imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); uint64_t tns_num = 0, i = 0; @@ -2837,6 +2908,8 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "subscribe_namespace"); json_t *message = imquic_qlog_moq_message_prepare("subscribe_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace_prefix"); json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); @@ -2862,7 +2935,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_subscribe_namespace) { moq->conn->socket->callbacks.moq.incoming_subscribe_namespace(moq->conn, - request_id, &tns[0], subscribe_options, ¶meters); + request_id, required_id_delta, &tns[0], subscribe_options, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_subscribe_namespace(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); @@ -2957,6 +3030,14 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); + uint64_t required_id_delta = 0; + if(moq->version >= IMQUIC_MOQ_VERSION_17) { + required_id_delta = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Required Request ID Delta: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), required_id_delta); + } /* Move on */ imquic_moq_namespace tns[32]; memset(&tns, 0, sizeof(tns)); @@ -3023,6 +3104,8 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st imquic_moq_qlog_stream_type_set(moq->conn->qlog, FALSE, moq_stream->stream_id, "fetch"); json_t *message = imquic_qlog_moq_message_prepare("fetch"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); json_object_set_new(message, "fetch_type", json_integer(type)); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { imquic_qlog_moq_message_add_namespace(message, &tns[0], "track_namespace"); @@ -3061,7 +3144,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st if(type == IMQUIC_MOQ_FETCH_STANDALONE) { if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_standalone_fetch) { moq->conn->socket->callbacks.moq.incoming_standalone_fetch(moq->conn, - request_id, &tns[0], &tn, &range, ¶meters); + request_id, required_id_delta, &tns[0], &tn, &range, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_fetch(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); @@ -3069,7 +3152,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st } else { if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_joining_fetch) { moq->conn->socket->callbacks.moq.incoming_joining_fetch(moq->conn, - request_id, joining_request_id, + request_id, required_id_delta, joining_request_id, (type == IMQUIC_MOQ_FETCH_JOINING_ABSOLUTE), joining_start, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ @@ -3129,11 +3212,16 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of FETCH_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; - uint64_t request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken FETCH_OK"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), request_id); + uint64_t request_id = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length > blen-offset, NULL, 0, 0, "Broken REQUEST_OK"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), request_id); + } else { + request_id = moq_stream->request_id; + } IMQUIC_MOQ_CHECK_ERR(blen-offset == 0, NULL, 0, 0, "Broken FETCH_OK"); uint8_t end_of_track = bytes[offset]; offset++; @@ -3182,7 +3270,8 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "end_of_track", json_integer(end_of_track)); json_object_set_new(message, "largest_group_id", json_integer(largest.group)); json_object_set_new(message, "largest_object_id", json_integer(largest.object)); @@ -3955,14 +4044,16 @@ size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_OK); - offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, @@ -3982,7 +4073,8 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_ERROR); - offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, error, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, retry_interval, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; @@ -3995,7 +4087,8 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_error"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "error_code", json_integer(error)); json_object_set_new(message, "retry_interval", json_integer(retry_interval)); if(reason != NULL) @@ -4008,7 +4101,7 @@ size_t imquic_moq_add_request_error(imquic_moq_context *moq, imquic_moq_stream * } size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, - uint64_t request_id, imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters) { + uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || track_namespace == NULL || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", @@ -4018,6 +4111,8 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stre size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_NAMESPACE); offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); @@ -4028,6 +4123,8 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stre imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "publish_namespace"); json_t *message = imquic_qlog_moq_message_prepare("publish_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); @@ -4089,7 +4186,7 @@ size_t imquic_moq_add_publish_namespace_cancel(imquic_moq_context *moq, uint8_t return offset; } -size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { if(bytes == NULL || blen < 1 || track_namespace == NULL || track_name == NULL || (track_name->buffer == NULL && track_name->length > 0) || @@ -4101,6 +4198,8 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_st size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH); offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_PUBLISH); offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); @@ -4118,6 +4217,8 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_st imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "publish"); json_t *message = imquic_qlog_moq_message_prepare("publish"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); json_object_set_new(message, "track_alias", json_integer(track_alias)); @@ -4141,14 +4242,16 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_OK); - offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, @@ -4158,7 +4261,8 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq return offset; } -size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, +size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || track_namespace == NULL || track_name == NULL || (track_name->buffer == NULL && track_name->length > 0) || @@ -4170,6 +4274,8 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_ size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE); offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_SUBSCRIBE); uint8_t params_num = 0; @@ -4181,6 +4287,8 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_ imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "subscribe"); json_t *message = imquic_qlog_moq_message_prepare("subscribe"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); @@ -4210,7 +4318,10 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_update"); json_object_set_new(message, "request_id", json_integer(request_id)); - json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); + else + json_object_set_new(message, "required_request_id_delta", json_integer(sub_request_id)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); @@ -4229,7 +4340,8 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *m } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_OK); - offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); @@ -4242,7 +4354,8 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *m #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("subscribe_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "track_alias", json_integer(track_alias)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); @@ -4285,7 +4398,8 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *m } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_DONE); - offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, status, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, streams_count, &bytes[offset], blen-offset); size_t reason_len = reason ? strlen(reason) : 0; @@ -4298,7 +4412,8 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *m #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("publish_done"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "status_code", json_integer(status)); json_object_set_new(message, "streams_count", json_integer(streams_count)); if(reason != NULL) @@ -4311,7 +4426,7 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *m } size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, - uint8_t *bytes, size_t blen, uint64_t request_id, imquic_moq_namespace *track_namespace, + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || track_namespace == NULL || moq_stream == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", @@ -4321,6 +4436,8 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); offset += imquic_write_moqint(moq->version, subscribe_options, &bytes[offset], blen-offset); uint8_t params_num = 0; @@ -4331,6 +4448,8 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "subscribe_namespace"); json_t *message = imquic_qlog_moq_message_prepare("subscribe_namespace"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace_prefix"); json_object_set_new(message, "subscribe_options", json_integer(subscribe_options)); json_object_set_new(message, "number_of_parameters", json_integer(params_num)); @@ -4389,7 +4508,7 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, - uint64_t request_id, uint64_t joining_request_id, uint64_t preceding_group_offset, + uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, uint64_t preceding_group_offset, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || (range == NULL && type == IMQUIC_MOQ_FETCH_STANDALONE) || @@ -4412,6 +4531,8 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stre size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH); offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, type, &bytes[offset], blen-offset); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_FETCH); @@ -4433,6 +4554,8 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stre imquic_moq_qlog_stream_type_set(moq->conn->qlog, TRUE, moq_stream->stream_id, "fetch"); json_t *message = imquic_qlog_moq_message_prepare("fetch"); json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version >= IMQUIC_MOQ_VERSION_17) + json_object_set_new(message, "required_request_id_delta", json_integer(required_id_delta)); if(type == IMQUIC_MOQ_FETCH_STANDALONE) { imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace"); imquic_qlog_moq_message_add_track(message, track_name); @@ -4483,7 +4606,8 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_s } size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_FETCH_OK); - offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); bytes[offset] = end_of_track; offset++; offset += imquic_write_moqint(moq->version, end_location->group, &bytes[offset], blen-offset); @@ -4499,7 +4623,8 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_s #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("fetch_ok"); - json_object_set_new(message, "request_id", json_integer(request_id)); + if(moq->version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(message, "request_id", json_integer(request_id)); json_object_set_new(message, "end_of_track", json_integer(end_of_track)); json_object_set_new(message, "largest_group_id", json_integer(end_location->group)); json_object_set_new(message, "largest_object_id", json_integer(end_location->object)); @@ -5285,8 +5410,8 @@ size_t imquic_moq_build_auth_token(imquic_moq_version version, imquic_moq_auth_t } /* Namespaces and subscriptions */ -int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, - imquic_moq_request_parameters *parameters) { +int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, + imquic_moq_namespace *tns, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0) { @@ -5325,7 +5450,7 @@ int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, i } uint8_t buffer[200]; size_t blen = sizeof(buffer); - size_t ann_len = imquic_moq_add_publish_namespace(moq, moq_stream, buffer, blen, request_id, tns, parameters); + size_t ann_len = imquic_moq_add_publish_namespace(moq, moq_stream, buffer, blen, request_id, required_id_delta, tns, parameters); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, ann_len, FALSE); @@ -5454,7 +5579,7 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, uint64_t request_ return 0; } -int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn, +int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, uint64_t track_alias, imquic_moq_request_parameters *parameters, GList *track_properties) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); @@ -5503,7 +5628,7 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, imquic_moq_ size_t blen = sizeof(buffer); size_t sb_len = 0; sb_len = imquic_moq_add_publish(moq, moq_stream, buffer, blen, - request_id, tns, tn, track_alias, parameters, track_properties); + request_id, required_id_delta, tns, tn, track_alias, parameters, track_properties); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); @@ -5599,7 +5724,7 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, return 0; } -int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, +int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); @@ -5651,7 +5776,7 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, size_t blen = sizeof(buffer); size_t sb_len = 0; sb_len = imquic_moq_add_subscribe(moq, moq_stream, buffer, blen, - request_id, tns, tn, parameters); + request_id, required_id_delta, tns, tn, parameters); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, sb_len, FALSE); @@ -5971,7 +6096,7 @@ int imquic_moq_publish_done(imquic_connection *conn, uint64_t request_id, imquic return 0; } -int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, +int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); @@ -6019,7 +6144,7 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = 0; - sb_len = imquic_moq_add_subscribe_namespace(moq, moq_stream, buffer, blen, request_id, tns, subscribe_options, parameters); + sb_len = imquic_moq_add_subscribe_namespace(moq, moq_stream, buffer, blen, request_id, required_id_delta, tns, subscribe_options, parameters); /* Track the request, and map it to the dedicated bidirectional STREAM */ g_atomic_int_set(&moq_stream->request_state, 1); moq_stream->request_id = request_id; @@ -6222,7 +6347,7 @@ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_i return 0; } -int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, +int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); @@ -6265,7 +6390,7 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, size_t f_len = 0; f_len = imquic_moq_add_fetch(moq, moq_stream, buffer, blen, IMQUIC_MOQ_FETCH_STANDALONE, - request_id, + request_id, required_id_delta, 0, 0, /* Ignored, as they're only used for Joining Fetch */ tns, tn, range, parameters); @@ -6277,7 +6402,7 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, return 0; } -int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t joining_request_id, +int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, gboolean absolute, uint64_t joining_start, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); @@ -6320,7 +6445,7 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 size_t f_len = 0; f_len = imquic_moq_add_fetch(moq, moq_stream, buffer, blen, (absolute ? IMQUIC_MOQ_FETCH_JOINING_ABSOLUTE : IMQUIC_MOQ_FETCH_JOINING_RELATIVE), - request_id, joining_request_id, joining_start, + request_id, required_id_delta, joining_request_id, joining_start, NULL, NULL, /* Ignored, as namespaces/track are only used for Standalone Fetch */ NULL, /* Ignored, as the fetch range is only used for Standalone Fetch */ parameters); From 5f43dd98a676cff3a24a7c8d60eb558b9b64566b Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 6 Mar 2026 19:14:13 +0100 Subject: [PATCH 16/30] Added new message PUBLISH_BLOCKED --- src/imquic-moq.c | 15 +++++- src/imquic/moq.h | 17 +++++++ src/internal/moq.h | 21 +++++++++ src/moq.c | 115 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 163 insertions(+), 5 deletions(-) diff --git a/src/imquic-moq.c b/src/imquic-moq.c index c78d372..d666409 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -654,7 +654,7 @@ void imquic_set_incoming_unsubscribe_namespace_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_namespace_cb(imquic_endpoint *endpoint, - void (* incoming_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns_suffix)) { + void (* incoming_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -665,7 +665,7 @@ void imquic_set_incoming_namespace_cb(imquic_endpoint *endpoint, } void imquic_set_incoming_namespace_done_cb(imquic_endpoint *endpoint, - void (* incoming_namespace_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns_suffix)) { + void (* incoming_namespace_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); @@ -675,6 +675,17 @@ void imquic_set_incoming_namespace_done_cb(imquic_endpoint *endpoint, } } +void imquic_set_incoming_publish_blocked_cb(imquic_endpoint *endpoint, + void (* incoming_publish_blocked)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn)) { + if(endpoint != NULL) { + if(endpoint->protocol != IMQUIC_MOQ) { + IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); + return; + } + endpoint->callbacks.moq.incoming_publish_blocked = incoming_publish_blocked; + } +} + void imquic_set_incoming_standalone_fetch_cb(imquic_endpoint *endpoint, void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters)) { diff --git a/src/imquic/moq.h b/src/imquic/moq.h index b663d5a..4907bef 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -1007,6 +1007,12 @@ void imquic_set_incoming_namespace_cb(imquic_endpoint *endpoint, * @param incoming_namespace_done Pointer to the function that will handle the incoming \c NAMESPACE_DONE */ void imquic_set_incoming_namespace_done_cb(imquic_endpoint *endpoint, void (* incoming_namespace_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns)); +/*! \brief Configure the callback function to be notified when there's + * an incoming \c PUBLISH_BLOCKED request. + * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure + * @param incoming_publish_blocked Pointer to the function that will handle the incoming \c PUBLISH_BLOCKED */ +void imquic_set_incoming_publish_blocked_cb(imquic_endpoint *endpoint, + void (* incoming_publish_blocked)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn)); /*! \brief Configure the callback function to be notified when there's * an incoming standalone \c FETCH request. * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -1302,6 +1308,17 @@ int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, im * @param tns The imquic_moq_namespace namespace this request refers to * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); +/*! \brief Function to send a \c PUBLISH_BLOCKED request + * \note While the request itself doesn't contain the request ID, we use + * it to find the subscription and use the right STREAM. + * Notice the method expects the full track namespace: the stack will strip + * the prefix itself, before sending the actual message. + * @param conn The imquic_connection to send the request on + * @param request_id The request ID of the original \c SUBSCRIBE_NAMESPACE request + * @param tns The imquic_moq_namespace namespace this request refers to + * @param tn The imquic_moq_name track this request refers to + * @returns 0 in case of success, a negative integer otherwise */ +int imquic_moq_notify_publish_blocked(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn); /*! \brief Function to send a standalone \c FETCH request * @param conn The imquic_connection to send the request on * @param request_id A unique numeric identifier to associate to this subscription diff --git a/src/internal/moq.h b/src/internal/moq.h index 5f3665a..9d8be70 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -54,6 +54,7 @@ typedef enum imquic_moq_message_type { IMQUIC_MOQ_SUBSCRIBE_NAMESPACE = 0x11, IMQUIC_MOQ_NAMESPACE = 0x8, IMQUIC_MOQ_NAMESPACE_DONE = 0xe, + IMQUIC_MOQ_PUBLISH_BLOCKED = 0xf, IMQUIC_MOQ_MAX_REQUEST_ID = 0x15, /* Deprecated in v17 */ IMQUIC_MOQ_REQUESTS_BLOCKED = 0x1A, /* Deprecated in v17 */ IMQUIC_MOQ_FETCH = 0x16, @@ -601,6 +602,14 @@ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *mo * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors * @returns The size of the parsed message, if successful, or 0 otherwise */ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); +/*! \brief Helper to parse a \c PUBLISH_BLOCKED message + * @param[in] moq The imquic_moq_context instance the message is for + * @param[in] moq_stream The imquic_moq_stream instance the message came from + * @param[in] bytes The buffer containing the message to parse + * @param[in] blen Size of the buffer to parse + * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors + * @returns The size of the parsed message, if successful, or 0 otherwise */ +size_t imquic_moq_parse_publish_blocked(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error); /*! \brief Helper to parse a \c FETCH message * @param[in] moq The imquic_moq_context instance the message is for * @param[in] moq_stream The imquic_moq_stream instance the message came from @@ -910,6 +919,16 @@ size_t imquic_moq_add_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_ * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace_suffix); +/*! \brief Helper method to add a \c PUBLISH_BLOCKED message to a buffer + * @param moq The imquic_moq_context generating the message + * @param moq_stream The imquic_moq_stream instance the message is for + * @param bytes The buffer to add the message to + * @param blen The size of the buffer + * @param track_namespace_suffix Namespace suffix that is impacted + * @param track Track that is blocked + * @returns The size of the generated message, if successful, or 0 otherwise */ +size_t imquic_moq_add_publish_blocked(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace_suffix, imquic_moq_name *track); /*! \brief Helper to add a \c FETCH message to a buffer * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for @@ -1211,6 +1230,8 @@ typedef struct imquic_moq_callbacks { void (* incoming_namespace)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); /*! \brief Callback function to be notified about incoming \c NAMESPACE_DONE messages */ void (* incoming_namespace_done)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns); + /*! \brief Callback function to be notified about incoming \c PUBLISH_BLOCKED messages */ + void (* incoming_publish_blocked)(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn); /*! \brief Callback function to be notified about incoming \c FETCH messages */ void (* incoming_standalone_fetch)(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters); diff --git a/src/moq.c b/src/moq.c index 53997e8..a6ff76e 100644 --- a/src/moq.c +++ b/src/moq.c @@ -681,6 +681,8 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "NAMESPACE"; case IMQUIC_MOQ_NAMESPACE_DONE: return "NAMESPACE_DONE"; + case IMQUIC_MOQ_PUBLISH_BLOCKED: + return "PUBLISH_BLOCKED"; case IMQUIC_MOQ_MAX_REQUEST_ID: return "MAX_REQUEST_ID"; case IMQUIC_MOQ_REQUESTS_BLOCKED: @@ -1633,6 +1635,9 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } else if(type == IMQUIC_MOQ_NAMESPACE_DONE) { /* Parse this NAMESPACE_DONE message */ parsed = imquic_moq_parse_namespace_done(moq, moq_stream, &bytes[offset], plen, &error); + } else if(type == IMQUIC_MOQ_PUBLISH_BLOCKED) { + /* Parse this PUBLISH_BLOCKED message */ + parsed = imquic_moq_parse_publish_blocked(moq, moq_stream, &bytes[offset], plen, &error); } else { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported message '%02x' (%s) on a %s request stream\n", imquic_get_connection_name(moq->conn), type, @@ -2951,7 +2956,7 @@ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *mo if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1)), + moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2986,7 +2991,7 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1)), + moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3015,6 +3020,44 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea return offset; } +size_t imquic_moq_parse_publish_blocked(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { + if(error) + *error = IMQUIC_MOQ_UNKNOWN_ERROR; + if(bytes == NULL || blen < 1) + return 0; + IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || + moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2), + error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_BLOCKED on bidirectional request"); + size_t offset = 0; + uint8_t length = 0; + imquic_moq_namespace tns[32]; + memset(&tns, 0, sizeof(tns)); + uint64_t tns_num = 0, i = 0; + IMQUIC_MOQ_PARSE_NAMESPACES(IMQUIC_MOQ_NAMESPACE_DONE, tns_num, i, "Broken PUBLISH_BLOCKED", TRUE); + IMQUIC_MOQ_CHECK_ERR((tns_num + moq_stream->namespace_prefix_size) > 32, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid number of namespaces"); + imquic_moq_name tn = { 0 }; + IMQUIC_MOQ_PARSE_TRACKNAME("Broken PUBLISH_BLOCKED", FALSE); +#ifdef HAVE_QLOG + if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + json_t *message = imquic_qlog_moq_message_prepare("publish_blocked"); + imquic_qlog_moq_message_add_namespace(message, (tns_num > 0 ? &tns[0] : NULL), "track_namespace_suffix"); + imquic_qlog_moq_message_add_track(message, &tn); + imquic_moq_qlog_control_message_parsed(moq->conn->qlog, moq_stream->stream_id, bytes-3, offset+3, message); + } +#endif + /* Notify the application */ + if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_publish_blocked) { + /* Prepare the full track namespace */ + if(tns_num > 0) + moq_stream->last_tuple->next = &tns[0]; + moq->conn->socket->callbacks.moq.incoming_publish_blocked(moq->conn, moq_stream->request_id, moq_stream->namespace_prefix, &tn); + moq_stream->last_tuple->next = NULL; + } + if(error) + *error = 0; + return offset; +} + size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint8_t *error) { if(error) *error = IMQUIC_MOQ_UNKNOWN_ERROR; @@ -4498,7 +4541,7 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { - json_t *message = imquic_qlog_moq_message_prepare("namespace"); + json_t *message = imquic_qlog_moq_message_prepare("namespace_done"); imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace_suffix"); imquic_moq_qlog_control_message_created(moq->conn->qlog, moq_stream->stream_id, bytes, offset, message); } @@ -4506,6 +4549,31 @@ size_t imquic_moq_add_namespace_done(imquic_moq_context *moq, imquic_moq_stream return offset; } +size_t imquic_moq_add_publish_blocked(imquic_moq_context *moq, imquic_moq_stream *moq_stream, + uint8_t *bytes, size_t blen, imquic_moq_namespace *track_namespace, imquic_moq_name *track_name) { + if(bytes == NULL || blen < 1 || moq_stream == NULL) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", + imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_NAMESPACE_DONE, moq->version)); + return 0; + } + size_t offset = 0, len_offset = 0; + /* FIXME A tuple of size 0 is allowed here, this macro needs fixing */ + IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_PUBLISH_BLOCKED); + /* FIXME A tuple of size 0 is allowed here, this macro needs fixing */ + IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_BLOCKED); + IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_PUBLISH_BLOCKED); + IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); +#ifdef HAVE_QLOG + if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { + json_t *message = imquic_qlog_moq_message_prepare("publish_blocked"); + imquic_qlog_moq_message_add_namespace(message, track_namespace, "track_namespace_suffix"); + imquic_qlog_moq_message_add_track(message, track_name); + imquic_moq_qlog_control_message_created(moq->conn->qlog, moq_stream->stream_id, bytes, offset, message); + } +#endif + return offset; +} + size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, imquic_moq_fetch_type type, uint64_t request_id, uint64_t required_id_delta, uint64_t joining_request_id, uint64_t preceding_group_offset, @@ -6347,6 +6415,47 @@ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_i return 0; } +int imquic_moq_notify_publish_blocked(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_name *tn) { + imquic_mutex_lock(&moq_mutex); + imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); + if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0 || + tn == NULL || tn->buffer == 0 || tn->length == 0) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", + imquic_get_connection_name(conn)); + imquic_mutex_unlock(&moq_mutex); + return -1; + } + imquic_refcount_increase(&moq->ref); + imquic_mutex_unlock(&moq_mutex); + /* Check if the request ID exists */ + imquic_mutex_lock(&moq->mutex); + imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || + g_atomic_int_get(&moq_stream->request_state) < 2 || + !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { + imquic_mutex_unlock(&moq->mutex); + imquic_refcount_decrease(&moq->ref); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", + imquic_get_connection_name(conn)); + return -1; + } + imquic_mutex_unlock(&moq->mutex); + /* We need the track namespace suffix */ + imquic_moq_namespace *tns_suffix = tns; + for(uint8_t i=0; inamespace_prefix_size; i++) + tns_suffix = tns_suffix->next; + /* Prepare the message */ + uint8_t buffer[200]; + size_t blen = sizeof(buffer); + size_t nn_len = imquic_moq_add_publish_blocked(moq, moq_stream, buffer, blen, tns_suffix, tn); + /* Send on the dedicated bidirectional STREAM */ + imquic_connection_send_on_stream(conn, moq_stream->stream_id, + buffer, nn_len, FALSE); + /* Done */ + imquic_refcount_decrease(&moq->ref); + return 0; +} + int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *tns, imquic_moq_name *tn, imquic_moq_location_range *range, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); From b460c2ee62670e31b17d6e1c8d1b761397cd56ee Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 6 Mar 2026 20:14:48 +0100 Subject: [PATCH 17/30] Implemented new format of Message Parameters, and added RENDEZVOUS_TIMEOUT --- src/imquic/moq.h | 4 + src/internal/moq.h | 98 +++++++++++++++------ src/moq.c | 215 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 248 insertions(+), 69 deletions(-) diff --git a/src/imquic/moq.h b/src/imquic/moq.h index 4907bef..de1a216 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -459,6 +459,10 @@ typedef struct imquic_moq_request_parameters { gboolean delivery_timeout_set; /*! \brief Value of the DELIVERY_TIMEOUT parameter */ uint64_t delivery_timeout; + /*! \brief Whether the RENDEZVOUS_TIMEOUT parameter is set */ + gboolean rendezvous_timeout_set; + /*! \brief Value of the RENDEZVOUS_TIMEOUT parameter */ + uint64_t rendezvous_timeout; /*! \brief Whether the SUBSCRIBER_PRIORITY parameter is set */ gboolean subscriber_priority_set; /*! \brief Value of the SUBSCRIBER_PRIORITY parameter */ diff --git a/src/internal/moq.h b/src/internal/moq.h index 9d8be70..344c7e5 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -222,6 +222,7 @@ const char *imquic_moq_setup_option_type_str(imquic_moq_setup_option_type type); typedef enum imquic_moq_request_parameter_type { IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN = 0x03, IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT = 0x02, + IMQUIC_MOQ_REQUEST_PARAM_RENDEZVOUS_TIMEOUT = 0x04, IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY = 0x20, IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER = 0x22, IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER = 0x21, @@ -1099,9 +1100,30 @@ size_t imquic_moq_add_properties(imquic_moq_context *moq, uint8_t *bytes, size_t uint8_t *properties, size_t prlen); ///@} -/** @name Parsing and building MoQ parameters +/** @name Parsing and building MoQ setup options (TLV) */ ///@{ +/*! \brief Helper to add a MoQ setup option with a numeric value to a buffer + * @param moq The imquic_moq_context instance the setup option is for + * @param bytes Buffer to add the setup option to + * @param blen Size of the buffer + * @param opt ID of the setup option to add + * @param prev ID of the previously added setup option, if we're delta-encoding + * @param number The numeric value of the setup option to add + * @returns The size of the setup option, if successful, or 0 otherwise */ +size_t imquic_moq_setup_option_add_int(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t opt, uint64_t prev, uint64_t number); +/*! \brief Helper to add a MoQ setup option with generic data to a buffer + * @param moq The imquic_moq_context instance the setup option is for + * @param bytes Buffer to add the setup option to + * @param blen Size of the buffer + * @param opt ID of the setup option to add + * @param prev ID of the previously added setup option, if we're delta-encoding + * @param buf The data acting as a value for the setup option to add + * @param buflen The size of the data value + * @returns The size of the setup option, if successful, or 0 otherwise */ +size_t imquic_moq_setup_option_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t opt, uint64_t prev, uint8_t *buf, size_t buflen); /*! \brief Helper method to parse a MoQ setup parameter * @note This method does nothing at the moment * @param[in] moq The imquic_moq_context instance to update with the new parameter @@ -1113,18 +1135,22 @@ size_t imquic_moq_add_properties(imquic_moq_context *moq, uint8_t *bytes, size_t * @returns The size of the parameter, if successful, or 0 otherwise */ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_setup_options *params, uint64_t *param_type, uint8_t *error); -/*! \brief Helper method to parse a MoQ subscribe parameter - * @note This method does nothing at the moment - * @param[in] moq The imquic_moq_context instance to update with the new parameter - * @param[in] bytes Buffer containing the parameter to parse - * @param[in] blen Size of the buffer to parse - * @param[out] params imquic_moq_request_parameters instance to put the parsed parameter in - * @param[out] param_type Type of the parsed parameter, needed for delta-decoding - * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors - * @returns The size of the parameter, if successful, or 0 otherwise */ -size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *bytes, size_t blen, - imquic_moq_request_parameters *params, uint64_t *param_type, uint8_t *error); -/*! \brief Helper to add a MoQ (setup or subscribe) parameter with a numeric value to a buffer +/*! \brief Helper to serialize a imquic_moq_setup_options set to a buffer + * @param[in] moq The imquic_moq_context instance the parameter is for + * @param[in] options The imquic_moq_setup_options to serialize + * @param[out] bytes The buffer to add paramerers to + * @param[in] blen The size of the buffer + * @param[out] params_num The number of parameters added to the buffer + * @returns The size of the serialized parameters, if successful, or 0 otherwise */ +size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, + imquic_moq_setup_options *options, + uint8_t *bytes, size_t blen, uint8_t *params_num); +///@} + +/** @name Parsing and building MoQ parameters (TLV or not, depending on version) + */ +///@{ +/*! \brief Helper to add a MoQ parameter with a numeric value to a buffer as a varint * @param moq The imquic_moq_context instance the parameter is for * @param bytes Buffer to add the parameter to * @param blen Size of the buffer @@ -1132,9 +1158,29 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte * @param prev ID of the previously added parameter, if we're delta-encoding * @param number The numeric value of the parameter to add * @returns The size of the parameter, if successful, or 0 otherwise */ -size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, size_t blen, +size_t imquic_moq_parameter_add_varint(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t param, uint64_t prev, uint64_t number); -/*! \brief Helper to add a MoQ (setup or subscribe) parameter with generic data to a buffer +/*! \brief Helper to add a MoQ parameter with a numeric value to a buffer as a byte + * @param moq The imquic_moq_context instance the parameter is for + * @param bytes Buffer to add the parameter to + * @param blen Size of the buffer + * @param param ID of the parameter to add + * @param prev ID of the previously added parameter, if we're delta-encoding + * @param number The numeric value of the parameter to add + * @returns The size of the parameter, if successful, or 0 otherwise */ +size_t imquic_moq_parameter_add_uint8(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t param, uint64_t prev, uint8_t number); +/*! \brief Helper to add a MoQ parameter with a location to a buffer + * @param moq The imquic_moq_context instance the parameter is for + * @param bytes Buffer to add the parameter to + * @param blen Size of the buffer + * @param param ID of the parameter to add + * @param prev ID of the previously added parameter, if we're delta-encoding + * @param location The location parameter to add + * @returns The size of the parameter, if successful, or 0 otherwise */ +size_t imquic_moq_parameter_add_location(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t param, uint64_t prev, imquic_moq_location *location); +/*! \brief Helper to add a MoQ parameter with generic data to a buffer * @param moq The imquic_moq_context instance the parameter is for * @param bytes Buffer to add the parameter to * @param blen Size of the buffer @@ -1145,17 +1191,17 @@ size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, siz * @returns The size of the parameter, if successful, or 0 otherwise */ size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t param, uint64_t prev, uint8_t *buf, size_t buflen); -/*! \brief Helper to serialize a imquic_moq_setup_options set to a buffer - * @param[in] moq The imquic_moq_context instance the parameter is for - * @param[in] options The imquic_moq_setup_options to serialize - * @param[out] bytes The buffer to add paramerers to - * @param[in] blen The size of the buffer - * @param[out] params_num The number of parameters added to the buffer - * @returns The size of the serialized parameters, if successful, or 0 otherwise */ -size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, - imquic_moq_setup_options *options, - uint8_t *bytes, size_t blen, uint8_t *params_num); - +/*! \brief Helper method to parse a MoQ subscribe parameter + * @note This method does nothing at the moment + * @param[in] moq The imquic_moq_context instance to update with the new parameter + * @param[in] bytes Buffer containing the parameter to parse + * @param[in] blen Size of the buffer to parse + * @param[out] params imquic_moq_request_parameters instance to put the parsed parameter in + * @param[out] param_type Type of the parsed parameter, needed for delta-decoding + * @param[out] error In/out property, initialized to 0 and set to something else in case of parsing errors + * @returns The size of the parameter, if successful, or 0 otherwise */ +size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + imquic_moq_request_parameters *params, uint64_t *param_type, uint8_t *error); /*! \brief Helper to serialize a imquic_moq_request_parameters set to a buffer * @param[in] moq The imquic_moq_context instance the parameter is for * @param[in] parameters The imquic_moq_request_parameters to serialize diff --git a/src/moq.c b/src/moq.c index a6ff76e..797e856 100644 --- a/src/moq.c +++ b/src/moq.c @@ -921,6 +921,8 @@ const char *imquic_moq_request_parameter_type_str(imquic_moq_request_parameter_t switch(type) { case IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT: return "DELIVERY_TIMEOUT"; + case IMQUIC_MOQ_REQUEST_PARAM_RENDEZVOUS_TIMEOUT: + return "RENDEZVOUS_TIMEOUT"; case IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN: return "AUTHORIZATION_TOKEN"; case IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY: @@ -1050,27 +1052,27 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, while(temp) { new_id = GPOINTER_TO_UINT(temp->data); if(new_id == IMQUIC_MOQ_SETUP_OPTION_PATH) { - offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, + offset += imquic_moq_setup_option_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->path, strlen(options->path)); } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_setup_option_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, options->max_request_id); } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_MAX_AUTH_TOKEN_CACHE_SIZE) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_setup_option_add_int(moq, &bytes[offset], blen-offset, new_id, last_id, options->max_auth_token_cache_size); } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_AUTHORIZATION_TOKEN) { - offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, + offset += imquic_moq_setup_option_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, options->auth_token, options->auth_token_len); } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_AUTHORITY) { - offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, + offset += imquic_moq_setup_option_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->authority, strlen(options->authority)); } else if(new_id == IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION) { - offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, + offset += imquic_moq_setup_option_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->moqt_implementation, strlen(options->moqt_implementation)); } @@ -1108,6 +1110,8 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN)); if(parameters->delivery_timeout_set && parameters->delivery_timeout > 0) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT)); + if(parameters->rendezvous_timeout_set && parameters->rendezvous_timeout > 0 && moq->version >= IMQUIC_MOQ_VERSION_17) + list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_RENDEZVOUS_TIMEOUT)); if(parameters->subscriber_priority_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY)); if(parameters->group_order_set) @@ -1134,15 +1138,19 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, new_id, last_id, parameters->auth_token, parameters->auth_token_len); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_varint(moq, &bytes[offset], blen-offset, new_id, last_id, parameters->delivery_timeout); + } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_RENDEZVOUS_TIMEOUT) { + offset += imquic_moq_parameter_add_varint(moq, &bytes[offset], blen-offset, + new_id, last_id, + parameters->rendezvous_timeout); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_uint8(moq, &bytes[offset], blen-offset, new_id, last_id, (uint64_t)parameters->subscriber_priority); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_uint8(moq, &bytes[offset], blen-offset, new_id, last_id, parameters->group_order); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER) { @@ -1160,23 +1168,19 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, new_id, last_id, temp, toffset); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_EXPIRES) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_varint(moq, &bytes[offset], blen-offset, new_id, last_id, parameters->expires); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT) { - uint8_t temp[40]; - size_t tlen = sizeof(temp); - size_t toffset = imquic_write_moqint(moq->version, parameters->largest_object.group, temp, tlen); - toffset += imquic_write_moqint(moq->version, parameters->largest_object.object, &temp[toffset], tlen-toffset); - offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_location(moq, &bytes[offset], blen-offset, new_id, last_id, - temp, toffset); + ¶meters->largest_object); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_FORWARD) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_uint8(moq, &bytes[offset], blen-offset, new_id, last_id, (uint64_t)parameters->forward); } else if(new_id == IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST) { - offset += imquic_moq_parameter_add_int(moq, &bytes[offset], blen-offset, + offset += imquic_moq_parameter_add_varint(moq, &bytes[offset], blen-offset, new_id, last_id, (uint64_t)parameters->new_group_request); } @@ -4961,21 +4965,21 @@ size_t imquic_moq_add_properties(imquic_moq_context *moq, uint8_t *bytes, size_t return offset; } -/* Adding parameters to a buffer */ -size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, size_t blen, +/* Adding and parsing setup options and parameters to a buffer */ +size_t imquic_moq_setup_option_add_int(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t param, uint64_t prev, uint64_t number) { if(bytes == NULL || blen == 0) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric parameter %"SCNu64": invalid arguments\n", + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric setup option %"SCNu64": invalid arguments\n", imquic_get_connection_name(moq->conn), param); return 0; } if(param % 2 != 0) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric parameter %"SCNu64": type is odd\n", + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric setup option %"SCNu64": type is odd\n", imquic_get_connection_name(moq->conn), param); return 0; } if(prev > param) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ numeric setup option %"SCNu64": previous setup option %"SCNu64" for delta-encoding is larger\n", imquic_get_connection_name(moq->conn), param, prev); return 0; } @@ -4985,20 +4989,20 @@ size_t imquic_moq_parameter_add_int(imquic_moq_context *moq, uint8_t *bytes, siz return offset; } -size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, +size_t imquic_moq_setup_option_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, uint64_t param, uint64_t prev, uint8_t *buf, size_t buflen) { if(bytes == NULL || blen == 0 || (buflen > 0 && buf == 0) || buflen > UINT16_MAX) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": invalid arguments\n", + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data setup option %"SCNu64": invalid arguments\n", imquic_get_connection_name(moq->conn), param); return 0; } if(param % 2 != 1) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": type is even\n", + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data setup option %"SCNu64": type is even\n", imquic_get_connection_name(moq->conn), param); return 0; } if(prev > param) { - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data setup option %"SCNu64": previous setup option %"SCNu64" for delta-encoding is larger\n", imquic_get_connection_name(moq->conn), param, prev); return 0; } @@ -5096,6 +5100,92 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si return offset; } +size_t imquic_moq_parameter_add_varint(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t param, uint64_t prev, uint64_t number) { + if(bytes == NULL || blen == 0) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ varint parameter %"SCNu64": invalid arguments\n", + imquic_get_connection_name(moq->conn), param); + return 0; + } + if(moq->version <= IMQUIC_MOQ_VERSION_16 && param % 2 != 0) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ varint parameter %"SCNu64": type is odd\n", + imquic_get_connection_name(moq->conn), param); + return 0; + } + if(prev > param) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ varint parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + imquic_get_connection_name(moq->conn), param, prev); + return 0; + } + param -= prev; + size_t offset = 0; + offset += imquic_write_moqint(moq->version, param, &bytes[0], blen-offset); + offset += imquic_write_moqint(moq->version, number, &bytes[offset], blen-offset); + return offset; +} + +size_t imquic_moq_parameter_add_uint8(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t param, uint64_t prev, uint8_t number) { + if(moq->version <= IMQUIC_MOQ_VERSION_16) + return imquic_moq_parameter_add_varint(moq, bytes, blen, param, prev, number); + if(bytes == NULL || blen == 0) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ byte parameter %"SCNu64": invalid arguments\n", + imquic_get_connection_name(moq->conn), param); + return 0; + } + if(prev > param) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ byte parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + imquic_get_connection_name(moq->conn), param, prev); + return 0; + } + param -= prev; + size_t offset = 0; + offset += imquic_write_moqint(moq->version, param, &bytes[0], blen-offset); + bytes[offset] = number; + return offset+1; +} + +size_t imquic_moq_parameter_add_location(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t param, uint64_t prev, imquic_moq_location *location) { + if(bytes == NULL || blen == 0 || location == NULL) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ location parameter %"SCNu64": invalid arguments\n", + imquic_get_connection_name(moq->conn), param); + return 0; + } + uint8_t temp[40]; + size_t tlen = sizeof(temp); + size_t toffset = imquic_write_moqint(moq->version, location->group, temp, tlen); + toffset += imquic_write_moqint(moq->version, location->object, &temp[toffset], tlen-toffset); + return imquic_moq_parameter_add_data(moq, bytes, blen, param, prev, temp, toffset); +} + +size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, + uint64_t param, uint64_t prev, uint8_t *buf, size_t buflen) { + if(bytes == NULL || blen == 0 || (buflen > 0 && buf == 0) || buflen > UINT16_MAX) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": invalid arguments\n", + imquic_get_connection_name(moq->conn), param); + return 0; + } + if(moq->version <= IMQUIC_MOQ_VERSION_16 && param % 2 != 1) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": type is even\n", + imquic_get_connection_name(moq->conn), param); + return 0; + } + if(prev > param) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ data parameter %"SCNu64": previous parameter %"SCNu64" for delta-encoding is larger\n", + imquic_get_connection_name(moq->conn), param, prev); + return 0; + } + param -= prev; + size_t offset = imquic_write_moqint(moq->version, param, &bytes[0], blen); + offset += imquic_write_moqint(moq->version, buflen, &bytes[offset], blen); + if(buflen > 0) { + memcpy(&bytes[offset], buf, buflen); + offset += buflen; + } + return offset; +} + size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *bytes, size_t blen, imquic_moq_request_parameters *params, uint64_t *param_type, uint8_t *error) { if(error) @@ -5115,7 +5205,14 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- %s (%"SCNu64")\n", imquic_get_connection_name(moq->conn), imquic_moq_request_parameter_type_str(type, moq->version), type); uint64_t len = 0; - if(type % 2 == 1) { + /* Parameters are formatted differently, depending on the version: + * older versions used TLV, while newer versions have hardcoded + * mappings between known parameters and the types to parse them as. + * As such, we only read the length if it's an older version and + * TLS tells us so, or for newer versions for params that need it */ + if((moq->version <= IMQUIC_MOQ_VERSION_16 && type % 2 == 1) || + (moq->version >= IMQUIC_MOQ_VERSION_17 && (type == IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN || + type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER))) { len = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken MoQ request parameter"); offset += length; @@ -5142,17 +5239,36 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->delivery_timeout); len = length; + } else if(type == IMQUIC_MOQ_REQUEST_PARAM_RENDEZVOUS_TIMEOUT) { + params->rendezvous_timeout = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || params->rendezvous_timeout == 0, NULL, 0, 0, "Broken MoQ request parameter"); + params->rendezvous_timeout_set = TRUE; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", + imquic_get_connection_name(moq->conn), params->rendezvous_timeout); + len = length; } else if(type == IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY) { - uint64_t subscriber_priority = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || subscriber_priority > 255, NULL, 0, 0, "Broken MoQ request parameter"); + uint64_t subscriber_priority = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + subscriber_priority = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || subscriber_priority > 255, NULL, 0, 0, "Broken MoQ request parameter"); + } else { + subscriber_priority = bytes[offset]; + length = 1; + } params->subscriber_priority = subscriber_priority; params->subscriber_priority_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu8"\n", imquic_get_connection_name(moq->conn), params->subscriber_priority); len = length; } else if(type == IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER) { - uint64_t group_order = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || group_order > IMQUIC_MOQ_ORDERING_DESCENDING, NULL, 0, 0, "Broken MoQ request parameter"); + uint64_t group_order = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + group_order = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || group_order > 255, NULL, 0, 0, "Broken MoQ request parameter"); + } else { + group_order = bytes[offset]; + length = 1; + } params->group_order = group_order; params->group_order_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64" (%s)\n", @@ -5188,19 +5304,32 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte imquic_get_connection_name(moq->conn), params->expires); len = length; } else if(type == IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT) { - uint8_t *tmp = &bytes[offset]; - size_t toffset = 0, tlen = len; - params->largest_object.group = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); - toffset += length; - params->largest_object.object = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + uint8_t *tmp = &bytes[offset]; + size_t toffset = 0, tlen = len; + params->largest_object.group = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + toffset += length; + params->largest_object.object = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + } else { + params->largest_object.group = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + params->largest_object.object = imquic_read_moqint(moq->version, &bytes[offset+length], blen-offset-length, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + } params->largest_object_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64" / %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->largest_object.group, params->largest_object.object); } else if(type == IMQUIC_MOQ_REQUEST_PARAM_FORWARD) { - uint64_t forward = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || forward > 1, NULL, 0, 0, "Broken MoQ request parameter"); + uint64_t forward = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + forward = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || forward > 255, NULL, 0, 0, "Broken MoQ request parameter"); + } else { + forward = bytes[offset]; + length = 1; + } params->forward = (forward > 0); params->forward_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu8"\n", @@ -5213,7 +5342,7 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->new_group_request); len = length; - } else { + } else if(moq->version <= IMQUIC_MOQ_VERSION_16) { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported parameter %"SCNu64"\n", imquic_get_connection_name(moq->conn), type); if(type % 2 == 0) @@ -5317,7 +5446,7 @@ const char *imquic_moq_get_remote_implementation(imquic_connection *conn) { return implementation; } -/* Propertie management */ +/* Properties management */ GList *imquic_moq_parse_properties(imquic_moq_version version, uint8_t *properties, size_t prlen) { if(properties == NULL || prlen == 0) return NULL; From 4f7e5d9af5903fe41644daed1b82a21329212f14 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 16:16:22 +0100 Subject: [PATCH 18/30] Fixed broken REQUEST_UPDATE --- examples/moq-relay.c | 2 +- examples/moq-sub.c | 6 +- examples/moq-test.c | 3 +- src/imquic-moq.c | 2 +- src/imquic/moq.h | 7 +- src/internal/moq.h | 30 +++- src/moq.c | 373 +++++++++++++++++++++++++++++-------------- 7 files changed, 289 insertions(+), 134 deletions(-) diff --git a/examples/moq-relay.c b/examples/moq-relay.c index bb10bbd..82a1c10 100644 --- a/examples/moq-relay.c +++ b/examples/moq-relay.c @@ -1004,7 +1004,7 @@ static void imquic_demo_subscribe_error(imquic_connection *conn, uint64_t reques } static void imquic_demo_request_updated(imquic_connection *conn, uint64_t request_id, - uint64_t sub_request_id, imquic_moq_request_parameters *parameters) { + uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming update for request %"SCNu64"\n", imquic_get_connection_name(conn), request_id); /* Find the subscriber */ diff --git a/examples/moq-sub.c b/examples/moq-sub.c index e4fc52f..0cdcf7f 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -933,7 +933,6 @@ int main(int argc, char *argv[]) { if(update_time > 0 && g_get_monotonic_time() >= update_time) { /* Send a REQUEST_UPDATE with forward=true */ update_time = 0; - /* TODO This should be done for all subscriptions */ GList *temp = request_ids; while(temp) { uint64_t *rid = (uint64_t *)temp->data; @@ -949,11 +948,10 @@ int main(int argc, char *argv[]) { params.subscription_filter.type = filter_type; params.subscription_filter.start_location = start_location; params.subscription_filter.end_group = end_location_sub.group; - uint64_t request_id = imquic_moq_get_next_request_id(moq_conn), - sub_request_id = request_id; + uint64_t request_id = imquic_moq_get_next_request_id(moq_conn); IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Sending a REQUEST_UPDATE for ID %"SCNu64" (ID %"SCNu64")\n", imquic_get_connection_name(moq_conn), *rid, request_id); - imquic_moq_update_request(moq_conn, request_id, sub_request_id, ¶ms); + imquic_moq_update_request(moq_conn, request_id, *rid, 0, ¶ms); temp = temp->next; } } diff --git a/examples/moq-test.c b/examples/moq-test.c index bcbe930..4096e63 100644 --- a/examples/moq-test.c +++ b/examples/moq-test.c @@ -395,7 +395,8 @@ static void imquic_demo_incoming_subscribe(imquic_connection *conn, uint64_t req } } -static void imquic_demo_request_updated(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters) { +static void imquic_demo_request_updated(imquic_connection *conn, uint64_t request_id, + uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters) { IMQUIC_LOG(IMQUIC_LOG_INFO, "[%s] Incoming update for subscription%"SCNu64"\n", imquic_get_connection_name(conn), request_id); /* Find the subscriber */ diff --git a/src/imquic-moq.c b/src/imquic-moq.c index d666409..3b6efdc 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -543,7 +543,7 @@ void imquic_set_subscribe_error_cb(imquic_endpoint *endpoint, } void imquic_set_request_updated_cb(imquic_endpoint *endpoint, - void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters)) { + void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters)) { if(endpoint != NULL) { if(endpoint->protocol != IMQUIC_MOQ) { IMQUIC_LOG(IMQUIC_LOG_WARN, "Can't set MoQ callback on non-MoQ endpoint\n"); diff --git a/src/imquic/moq.h b/src/imquic/moq.h index de1a216..4ca6e5f 100644 --- a/src/imquic/moq.h +++ b/src/imquic/moq.h @@ -936,7 +936,7 @@ void imquic_set_subscribe_error_cb(imquic_endpoint *endpoint, * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure * @param request_updated Pointer to the function that will fire when a \c SUBSCRIBE is done */ void imquic_set_request_updated_cb(imquic_endpoint *endpoint, - void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters)); + void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters)); /*! \brief Configure the callback function to be notified when an OK * is received for a \c REQUEST_UPDATE we previously sent * @param endpoint The imquic_endpoint (imquic_server or imquic_client) to configure @@ -1223,12 +1223,13 @@ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Function to send a \c REQUEST_UPDATE request * @param conn The imquic_connection to send the request on - * @param request_id Unique \c request_id value (before v14, this is associated to the subscription to update) + * @param request_id Unique \c request_id value * @param sub_request_id Unique \c request_id value associated to the subscription to update + * @param required_id_delta Required Request ID Delta, if needed (ignored before v17) * @param parameters The parameters to add to the request * @returns 0 in case of success, a negative integer otherwise */ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, - uint64_t sub_request_id, imquic_moq_request_parameters *parameters); + uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters); /*! \brief Function to accept an incoming \c REQUEST_UPDATE request * @param conn The imquic_connection to send the request on * @param request_id The request ID of the original \c REQUEST_UPDATE request diff --git a/src/internal/moq.h b/src/internal/moq.h index 344c7e5..30434db 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -331,6 +331,8 @@ typedef struct imquic_moq_context { GHashTable *subscriptions_by_id; /*! \brief Map of Request IDs and what they were for */ GHashTable *requests; + /*! \brief Map of Request IDs to Existing Request IDs, for updates */ + GHashTable *update_requests; /*! \brief Current Request IDs we expect and we can send */ uint64_t expected_request_id, next_request_id; /*! \brief Maximum Request IDs we can send and the one we accept */ @@ -353,6 +355,21 @@ typedef struct imquic_moq_context { imquic_refcount ref; } imquic_moq_context; +/*! \brief MoQ stream request state + * \note Only needed for tracking the state of bidirectional requests, not media */ +typedef enum imquic_media_stream_request_state { + IMQUIC_MOQ_REQUEST_STATE_NEW = 0, + IMQUIC_MOQ_REQUEST_STATE_SENT, + IMQUIC_MOQ_REQUEST_STATE_OK, + IMQUIC_MOQ_REQUEST_STATE_ERROR, + IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT, + IMQUIC_MOQ_REQUEST_STATE_DONE, +} imquic_media_stream_request_state; +/*! \brief Helper function to serialize to string the name of a imquic_media_stream_request_state value. + * @param state The imquic_media_stream_request_state value + * @returns The state name as a string, if valid, or NULL otherwise */ +const char *imquic_media_stream_request_state_str(imquic_media_stream_request_state state); + /*! \brief MoQ stream * \note This is usually used for objects (e.g., via SUBGROUP_HEADER or * FETCH), but starting in v16, requests can use streams too */ @@ -364,15 +381,15 @@ typedef struct imquic_moq_stream { /*! In case this is a bidirectional STREAM for a request, if this endpoint originated it */ gboolean request_sender; /*! In case this is a bidirectional STREAM for a request, its current state */ - volatile gint request_state; + imquic_media_stream_request_state request_state; /*! \brief In case this is for SUBSCRIBE_NAMESPACE, the namespace prefix */ imquic_moq_namespace *namespace_prefix, *last_tuple; /*! \brief In case this is for SUBSCRIBE_NAMESPACE, how many tuples are in the namespace prefix */ uint8_t namespace_prefix_size; /*! \brief Delivery mode for this stream, in case it's used for objects */ imquic_moq_data_message_type type; - /*! \brief ID of the subscription */ - uint64_t request_id; + /*! \brief ID of the request/subscription, and of the update if one was involved */ + uint64_t request_id, update_request_id; /*! \brief Track alias */ uint64_t track_alias; /*! \brief Group ID */ @@ -849,11 +866,12 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_ * @param bytes The buffer to add the message to * @param blen The size of the buffer * @param request_id The request ID to put in the message - * @param sub_request_id The subscription request ID to put in the message + * @param sub_request_id The subscription request ID to put in the message (not added to message starting in v17) + * @param required_id_delta The required request ID delta to put in the message (ignored before v17) * @param parameters The parameters to add, if any * @returns The size of the generated message, if successful, or 0 otherwise */ size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream *moq_stream, - uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters); + uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters); /*! \brief Helper method to add a \c SUBSCRIBE_OK message to a buffer * @param moq The imquic_moq_context generating the message * @param moq_stream The imquic_moq_stream instance the message is for @@ -1251,7 +1269,7 @@ typedef struct imquic_moq_callbacks { /*! \brief Callback function to be notified about incoming \c SUBSCRIBE_ERROR messages */ void (* subscribe_error)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_error_code error_code, const char *reason, uint64_t retry_interval); /*! \brief Callback function to be notified about incoming \c REQUEST_UPDATE messages */ - void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters); + void (* request_updated)(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about an ACK to a previously sent \c REQUEST_UPDATE message */ void (* request_update_accepted)(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); /*! \brief Callback function to be notified about incoming errors to a previously \c REQUEST_UPDATE message */ diff --git a/src/moq.c b/src/moq.c index 797e856..c803122 100644 --- a/src/moq.c +++ b/src/moq.c @@ -201,6 +201,8 @@ void imquic_moq_new_connection(imquic_connection *conn, void *user_data) { (GDestroyNotify)g_free, (GDestroyNotify)imquic_moq_subscription_destroy); moq->requests = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL); + moq->update_requests = g_hash_table_new_full(g_int64_hash, g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)g_free); moq->buffer = imquic_buffer_create(NULL, 0); imquic_mutex_init(&moq->mutex); imquic_refcount_init(&moq->ref, imquic_moq_context_free); @@ -496,6 +498,8 @@ static void imquic_moq_context_free(const imquic_refcount *moq_ref) { g_hash_table_unref(moq->streams_by_reqid); if(moq->requests) g_hash_table_unref(moq->requests); + if(moq->update_requests) + g_hash_table_unref(moq->update_requests); imquic_buffer_destroy(moq->buffer); g_free(moq); } @@ -706,6 +710,25 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return NULL; } +const char *imquic_media_stream_request_state_str(imquic_media_stream_request_state state) { + switch(state) { + case IMQUIC_MOQ_REQUEST_STATE_NEW: + return "New"; + case IMQUIC_MOQ_REQUEST_STATE_SENT: + return "Sent"; + case IMQUIC_MOQ_REQUEST_STATE_OK: + return "OK"; + case IMQUIC_MOQ_REQUEST_STATE_ERROR: + return "Error"; + case IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT: + return "Update Sent"; + case IMQUIC_MOQ_REQUEST_STATE_DONE: + return "Done"; + default: break; + } + return NULL; +} + gboolean imquic_moq_is_datagram_message_type_valid(imquic_moq_version version, uint8_t type) { return (type <= 0x0F || (type >= 0x20 && type <= 0x2D)); } @@ -2052,8 +2075,8 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m if(bytes == NULL || blen < 1) return 0; /* FIXME State management needs to be fixed, because an update will trigger OK/ERROR too */ - IMQUIC_MOQ_CHECK_ERR(moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || - !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)), + IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || + !moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT))), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2065,7 +2088,8 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); } else { - request_id = moq_stream->request_id; + request_id = moq_stream->update_request_id; + moq_stream->update_request_id = 0; } uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(params_num > 0 && (length == 0 || length >= blen-offset), NULL, 0, 0, "Broken REQUEST_OK"); @@ -2093,6 +2117,8 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m #endif /* Notify the application, but we'll need to check which callback to trigger */ imquic_mutex_lock(&moq->mutex); + if(moq_stream != NULL) + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_moq_message_type type = GPOINTER_TO_UINT(g_hash_table_lookup(moq->requests, &request_id)); g_hash_table_remove(moq->requests, &request_id); imquic_mutex_unlock(&moq->mutex); @@ -2114,8 +2140,8 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m moq->conn->socket->callbacks.moq.track_status_accepted(moq->conn, request_id, ¶meters); break; default: - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Couldn't find a request associated to ID %"SCNu64" (type %d), can't notify success\n", - imquic_get_connection_name(moq->conn), request_id, type); + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Couldn't find a request associated to ID %"SCNu64" (%s), can't notify success\n", + imquic_get_connection_name(moq->conn), request_id, imquic_moq_message_type_str(type, moq->version)); break; } if(error) @@ -2130,7 +2156,7 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream return 0; /* FIXME State management needs to be fixed, because an update will trigger OK/ERROR too */ IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || - !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + !moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT))), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_ERROR on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2142,7 +2168,8 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); } else { - request_id = moq_stream->request_id; + request_id = moq_stream->update_request_id; + moq_stream->update_request_id = 0; } uint64_t error_code = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_ERROR"); @@ -2185,6 +2212,10 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream #endif /* Notify the application, but we'll need to check which callback to trigger */ imquic_mutex_lock(&moq->mutex); + if(moq_stream != NULL) { + moq_stream->request_state = (moq_stream->request_state == IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT) ? + IMQUIC_MOQ_REQUEST_STATE_OK : IMQUIC_MOQ_REQUEST_STATE_ERROR; + } imquic_moq_message_type type = GPOINTER_TO_UINT(g_hash_table_lookup(moq->requests, &request_id)); g_hash_table_remove(moq->requests, &request_id); imquic_mutex_unlock(&moq->mutex); @@ -2218,8 +2249,8 @@ size_t imquic_moq_parse_request_error(imquic_moq_context *moq, imquic_moq_stream moq->conn->socket->callbacks.moq.track_status_error(moq->conn, request_id, error_code, reason_str, retry_interval); break; default: - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Couldn't find a request associated to ID %"SCNu64" (type %d), can't notify error\n", - imquic_get_connection_name(moq->conn), request_id, type); + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Couldn't find a request associated to ID %"SCNu64" (%s), can't notify error\n", + imquic_get_connection_name(moq->conn), request_id, imquic_moq_message_type_str(type, moq->version)); break; } if(error) @@ -2233,7 +2264,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_st if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_NEW)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2288,6 +2319,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_st /* If we're on a recent version of MoQ, track this request via its ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -2384,7 +2416,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_ if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_NEW)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2464,6 +2496,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_ /* If we're on a recent version of MoQ, track this request via its ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -2488,7 +2521,7 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *m if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || - !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + !moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2527,6 +2560,8 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *m (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif + if(moq_stream != NULL) + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.publish_accepted) moq->conn->socket->callbacks.moq.publish_accepted(moq->conn, request_id, ¶meters); @@ -2541,7 +2576,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *mo if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_NEW)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2601,6 +2636,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *mo /* If we're on a recent version of MoQ, track this request via its ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -2630,7 +2666,7 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_strea return 0; /* FIXME State management needs to be fixed, because an update will trigger OK/ERROR too */ IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type == 0 || - moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2)), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of REQUEST_UPDATE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2639,11 +2675,20 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_strea offset += length; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Request ID: %"SCNu64"\n", imquic_get_connection_name(moq->conn), request_id); - uint64_t sub_request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); - IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); - offset += length; - IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Subscription Request ID: %"SCNu64"\n", - imquic_get_connection_name(moq->conn), sub_request_id); + uint64_t sub_request_id = 0, required_id_delta = 0; + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + sub_request_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken REQUEST_UPDATE"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Subscription Request ID: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), sub_request_id); + } else { + required_id_delta = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || length >= blen-offset, NULL, 0, 0, "Broken PUBLISH"); + offset += length; + IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Required Request ID Delta: %"SCNu64"\n", + imquic_get_connection_name(moq->conn), required_id_delta); + } imquic_moq_request_parameters parameters; imquic_moq_request_parameters_init_defaults(¶meters); uint64_t params_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); @@ -2662,22 +2707,30 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_strea if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_update"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_16) + if(moq->version <= IMQUIC_MOQ_VERSION_16) { json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); - else + } else { json_object_set_new(message, "required_request_id_delta", json_integer(sub_request_id)); + } imquic_qlog_moq_message_add_request_parameters(message, moq->version, ¶meters, "parameters"); imquic_moq_qlog_control_message_parsed(moq->conn->qlog, (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif + if(moq_stream != NULL) { + sub_request_id = moq_stream->request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT; + } /* Make sure this is in line with the expected request ID */ IMQUIC_MOQ_CHECK_ERR(!moq_is_request_id_valid(moq, request_id, FALSE), error, IMQUIC_MOQ_INVALID_REQUEST_ID, 0, "Invalid Request ID"); moq->expected_request_id = request_id + IMQUIC_MOQ_REQUEST_ID_INCREMENT; /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.request_updated) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->update_requests, imquic_dup_uint64(request_id), imquic_dup_uint64(sub_request_id)); + imquic_mutex_unlock(&moq->mutex); moq->conn->socket->callbacks.moq.request_updated(moq->conn, - request_id, sub_request_id, ¶meters); + request_id, sub_request_id, required_id_delta, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_request_update(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); @@ -2693,7 +2746,7 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || - !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + !moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2753,6 +2806,8 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif + if(moq_stream != NULL) + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.subscribe_accepted) { moq->conn->socket->callbacks.moq.subscribe_accepted(moq->conn, @@ -2805,7 +2860,8 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, imquic_moq_stream if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || - moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2)), + moq_stream->request_sender || moq_stream->request_state == IMQUIC_MOQ_REQUEST_STATE_NEW || + moq_stream->request_state == IMQUIC_MOQ_REQUEST_STATE_ERROR || moq_stream->request_state == IMQUIC_MOQ_REQUEST_STATE_DONE)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2858,6 +2914,8 @@ size_t imquic_moq_parse_publish_done(imquic_moq_context *moq, imquic_moq_stream (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif + if(moq_stream != NULL) + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_DONE; /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.publish_done) { moq->conn->socket->callbacks.moq.publish_done(moq->conn, @@ -2874,7 +2932,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1)), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_NEW), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of SUBSCRIBE_NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2933,6 +2991,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ /* If we're on a recent version of MoQ, track this request via its request ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); while(moq_stream->last_tuple->next != NULL) moq_stream->last_tuple = moq_stream->last_tuple->next; @@ -2960,7 +3019,7 @@ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *mo if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2), + moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -2995,7 +3054,7 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2), + moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3030,7 +3089,7 @@ size_t imquic_moq_parse_publish_blocked(imquic_moq_context *moq, imquic_moq_stre if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || g_atomic_int_get(&moq_stream->request_state) < 2), + moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_BLOCKED on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3068,7 +3127,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_NEW)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of FETCH on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3177,6 +3236,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st /* If we're on a recent version of MoQ, track this request via its request ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -3255,7 +3315,7 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_FETCH || - !moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2))), + !moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of FETCH_OK on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3329,6 +3389,8 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq (moq_stream ? moq_stream->stream_id : imquic_moq_get_control_stream(moq)), bytes-3, offset+3, message); } #endif + if(moq_stream != NULL) + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.fetch_accepted) moq->conn->socket->callbacks.moq.fetch_accepted(moq->conn, request_id, &largest, ¶meters, track_properties); @@ -3344,7 +3406,7 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, imquic_moq_stream if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq->version >= IMQUIC_MOQ_VERSION_17 && (moq_stream == NULL || - moq_stream->request_sender || !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 0, 1))), + moq_stream->request_sender || moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_NEW)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of TRACK_STATUS on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3394,6 +3456,7 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, imquic_moq_stream /* If we're on a recent version of MoQ, track this request via its ID */ if(moq_stream != NULL) { moq_stream->request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); imquic_mutex_unlock(&moq->mutex); @@ -3650,7 +3713,6 @@ int imquic_moq_parse_subgroup_header_object(imquic_moq_context *moq, imquic_moq_ size_t blen = moq_stream->buffer->length; size_t offset = 0; uint8_t length = 0; - /* Note: this will be a delta, on v14 and later */ uint64_t object_id = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); if(length == 0 || length >= blen-offset) return -1; /* Not enough data, try again later */ @@ -4348,7 +4410,7 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_ } size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, - uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters) { + uint64_t request_id, uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters) { if(bytes == NULL || blen < 1 || (moq->version >= IMQUIC_MOQ_VERSION_17 && moq_stream == NULL)) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_REQUEST_UPDATE, moq->version)); @@ -4357,7 +4419,11 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream size_t offset = 0, len_offset = 0; IMQUIC_MOQ_ADD_MESSAGE_TYPE(IMQUIC_MOQ_REQUEST_UPDATE); offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); - offset += imquic_write_moqint(moq->version, sub_request_id, &bytes[offset], blen-offset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + offset += imquic_write_moqint(moq->version, sub_request_id, &bytes[offset], blen-offset); + } else { + offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); + } uint8_t params_num = 0; offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); @@ -4365,10 +4431,11 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { json_t *message = imquic_qlog_moq_message_prepare("request_update"); json_object_set_new(message, "request_id", json_integer(request_id)); - if(moq->version <= IMQUIC_MOQ_VERSION_16) + if(moq->version <= IMQUIC_MOQ_VERSION_16) { json_object_set_new(message, "subscription_request_id", json_integer(sub_request_id)); - else + } else { json_object_set_new(message, "required_request_id_delta", json_integer(sub_request_id)); + } imquic_qlog_moq_message_add_request_parameters(message, moq->version, parameters, "parameters"); imquic_moq_qlog_control_message_created(moq->conn->qlog, (moq_stream ? moq_stream->stream_id : moq->control_stream_id), bytes, offset, message); @@ -5639,7 +5706,7 @@ int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, u moq_stream->request_type = IMQUIC_MOQ_PUBLISH_NAMESPACE; moq_stream->request_id = request_id; moq_stream->request_sender = TRUE; - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); @@ -5674,13 +5741,14 @@ int imquic_moq_accept_publish_namespace(imquic_connection *conn, uint64_t reques imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -5713,13 +5781,14 @@ int imquic_moq_reject_publish_namespace(imquic_connection *conn, uint64_t reques imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_ERROR; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -5727,7 +5796,12 @@ int imquic_moq_reject_publish_namespace(imquic_connection *conn, uint64_t reques size_t ann_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, - buffer, ann_len, FALSE); + buffer, ann_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; @@ -5751,11 +5825,11 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, uint64_t request_ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || !moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2) { + (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } /* Reset the STREAM */ @@ -5815,7 +5889,7 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, uint64_t re moq_stream->request_type = IMQUIC_MOQ_PUBLISH; moq_stream->request_id = request_id; moq_stream->request_sender = TRUE; - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); @@ -5861,13 +5935,14 @@ int imquic_moq_accept_publish(imquic_connection *conn, uint64_t request_id, imqu imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -5901,13 +5976,14 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH_NAMESPACE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_ERROR; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -5915,7 +5991,12 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, - buffer, sb_len, FALSE); + buffer, sb_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; @@ -5963,7 +6044,7 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE; moq_stream->request_id = request_id; moq_stream->request_sender = TRUE; - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); @@ -6001,13 +6082,14 @@ int imquic_moq_accept_subscribe(imquic_connection *conn, uint64_t request_id, ui imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } imquic_mutex_lock(&moq->mutex); @@ -6049,13 +6131,14 @@ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_ERROR; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -6063,13 +6146,18 @@ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, - buffer, sb_len, FALSE); + buffer, sb_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; } -int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, imquic_moq_request_parameters *parameters) { +int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint64_t sub_request_id, uint64_t required_id_delta, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); if(moq == NULL) { @@ -6099,21 +6187,23 @@ int imquic_moq_update_request(imquic_connection *conn, uint64_t request_id, uint imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { imquic_mutex_lock(&moq->mutex); - moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &sub_request_id); if(moq_stream == NULL || moq_stream->request_type == 0 || !moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->update_request_id = request_id; + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t su_len = imquic_moq_add_request_update(moq, moq_stream, buffer, blen, - request_id, sub_request_id, parameters); + request_id, sub_request_id, required_id_delta, parameters); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, buffer, su_len, FALSE); @@ -6133,20 +6223,33 @@ int imquic_moq_accept_request_update(imquic_connection *conn, uint64_t request_i } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); + /* Check which request this update refers to */ + imquic_mutex_lock(&moq->mutex); + uint64_t *rid = g_hash_table_lookup(moq->update_requests, &request_id); + if(rid == NULL) { + imquic_mutex_unlock(&moq->mutex); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", + imquic_get_connection_name(conn)); + return -1; + } + uint64_t sub_request_id = *rid; + g_hash_table_remove(moq->update_requests, &request_id); + imquic_mutex_unlock(&moq->mutex); /* Starting from v17, requests go on a dedicated bidirectional * STREAM, and the same applies to the REQUEST_OK responses */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { imquic_mutex_lock(&moq->mutex); - moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &sub_request_id); if(moq_stream == NULL || moq_stream->request_type == 0 || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -6172,20 +6275,34 @@ int imquic_moq_reject_request_update(imquic_connection *conn, uint64_t request_i } imquic_refcount_increase(&moq->ref); imquic_mutex_unlock(&moq_mutex); + /* Check which request this update refers to */ + imquic_mutex_lock(&moq->mutex); + uint64_t *rid = g_hash_table_lookup(moq->update_requests, &request_id); + if(rid == NULL) { + imquic_mutex_unlock(&moq->mutex); + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", + imquic_get_connection_name(conn)); + return -1; + } + uint64_t sub_request_id = *rid; + g_hash_table_remove(moq->update_requests, &request_id); + imquic_mutex_unlock(&moq->mutex); /* Starting from v17, requests go on a dedicated bidirectional * STREAM, and the same applies to the REQUEST_ERROR responses */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { imquic_mutex_lock(&moq->mutex); - moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); + moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &sub_request_id); if(moq_stream == NULL || moq_stream->request_type == 0 || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + /* FIXME We mark the state as OK, as this is an update */ + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -6216,12 +6333,11 @@ int imquic_moq_unsubscribe(imquic_connection *conn, uint64_t request_id) { * bidirectional STREAM, so we simply close the STREAM */ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); - if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || !moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2) { + if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE || !moq_stream->request_sender) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } /* Reset the STREAM */ @@ -6272,11 +6388,11 @@ int imquic_moq_publish_done(imquic_connection *conn, uint64_t request_id, imquic imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_PUBLISH || !moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2) { + (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -6343,7 +6459,7 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, size_t sb_len = 0; sb_len = imquic_moq_add_subscribe_namespace(moq, moq_stream, buffer, blen, request_id, required_id_delta, tns, subscribe_options, parameters); /* Track the request, and map it to the dedicated bidirectional STREAM */ - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; moq_stream->request_id = request_id; moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); while(moq_stream->last_tuple->next != NULL) @@ -6376,13 +6492,14 @@ int imquic_moq_accept_subscribe_namespace(imquic_connection *conn, uint64_t requ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); @@ -6412,20 +6529,26 @@ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t requ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_ERROR; imquic_mutex_unlock(&moq->mutex); uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t sb_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); /* Send on the dedicated bidirectional STREAM */ imquic_connection_send_on_stream(conn, moq_stream->stream_id, - buffer, sb_len, FALSE); + buffer, sb_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; @@ -6479,12 +6602,12 @@ int imquic_moq_notify_namespace(imquic_connection *conn, uint64_t request_id, im imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2 || + (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT) || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -6519,12 +6642,12 @@ int imquic_moq_notify_namespace_done(imquic_connection *conn, uint64_t request_i imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2 || + (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT) || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -6560,12 +6683,12 @@ int imquic_moq_notify_publish_blocked(imquic_connection *conn, uint64_t request_ imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || moq_stream->request_sender || - g_atomic_int_get(&moq_stream->request_state) < 2 || + (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT) || !imquic_moq_namespace_contains(moq_stream->namespace_prefix, tns)) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } imquic_mutex_unlock(&moq->mutex); @@ -6617,7 +6740,7 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, ui moq_stream->request_type = IMQUIC_MOQ_FETCH; moq_stream->request_id = request_id; moq_stream->request_sender = TRUE; - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); @@ -6672,7 +6795,7 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 moq_stream->request_type = IMQUIC_MOQ_FETCH; moq_stream->request_id = request_id; moq_stream->request_sender = TRUE; - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); @@ -6714,13 +6837,14 @@ int imquic_moq_accept_fetch(imquic_connection *conn, uint64_t request_id, imquic imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_FETCH || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -6758,13 +6882,14 @@ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type == 0 || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_ERROR; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -6772,7 +6897,12 @@ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, size_t f_len = imquic_moq_add_request_error(moq, moq_stream, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, - buffer, f_len, FALSE); + buffer, f_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; @@ -6842,7 +6972,7 @@ int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, moq_stream->request_type = IMQUIC_MOQ_TRACK_STATUS; moq_stream->request_id = request_id; moq_stream->request_sender = TRUE; - g_atomic_int_set(&moq_stream->request_state, 1); + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(moq_stream->stream_id), moq_stream); g_hash_table_insert(moq->streams_by_reqid, imquic_dup_uint64(request_id), moq_stream); @@ -6880,13 +7010,14 @@ int imquic_moq_accept_track_status(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_TRACK_STATUS || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_OK; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; @@ -6919,20 +7050,26 @@ int imquic_moq_reject_track_status(imquic_connection *conn, uint64_t request_id, imquic_mutex_lock(&moq->mutex); moq_stream = g_hash_table_lookup(moq->streams_by_reqid, &request_id); if(moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_TRACK_STATUS || moq_stream->request_sender || - !g_atomic_int_compare_and_exchange(&moq_stream->request_state, 1, 2)) { + moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_SENT) { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state (%s)\n", + imquic_get_connection_name(conn), moq_stream ? imquic_media_stream_request_state_str(moq_stream->request_state) : "No stream"); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); - IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid request/state\n", - imquic_get_connection_name(conn)); return -1; } + moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_ERROR; imquic_mutex_unlock(&moq->mutex); } uint8_t buffer[200]; size_t blen = sizeof(buffer); size_t tsr_len = imquic_moq_add_request_error(moq, NULL, buffer, blen, request_id, error_code, reason, retry_interval); imquic_connection_send_on_stream(conn, moq->control_stream_id, - buffer, tsr_len, FALSE); + buffer, tsr_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; From 0dd7e82bc0f5239d1da0fd15721c94a582686b5a Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 17:32:12 +0100 Subject: [PATCH 19/30] Use ID from the reserved space, for test properties in moq-pub --- examples/moq-pub.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/moq-pub.c b/examples/moq-pub.c index e95f6df..65706b2 100644 --- a/examples/moq-pub.c +++ b/examples/moq-pub.c @@ -306,11 +306,12 @@ static void imquic_demo_send_data(char *text, gboolean first, gboolean last) { } if(options.properties) { /* Just for fun, we add a couple of fake properties to the object: a numeric - * property set to the length of the text, and a data property with a fixed string */ - numprop.id = 0x6; /* FIXME */ + * property set to the length of the text, and a data property with a fixed string. + * We use the reserved space mentioned in the draft, for their IDs */ + numprop.id = 0x38; numprop.value.number = strlen(text); props = g_list_append(props, &numprop); - dataprop.id = 0x7; /* FIXME */ + dataprop.id = 0x39; dataprop.value.data.buffer = (uint8_t *)"lminiero"; dataprop.value.data.length = strlen("lminiero"); props = g_list_append(props, &dataprop); From 6d391a45708266eb2a7b195e5d06954875426d95 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 17:32:37 +0100 Subject: [PATCH 20/30] Added support for GREASE, and used in for SETUP options --- src/moq.c | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/moq.c b/src/moq.c index c803122..a86207d 100644 --- a/src/moq.c +++ b/src/moq.c @@ -50,8 +50,14 @@ static void imquic_moq_pending_stream_destroy(imquic_moq_pending_stream *stream) static GHashTable *moq_pending_streams = NULL; /* MoQ's flavour of varint (introduced in v17) */ -uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length); -uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen); +static uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length); +static uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen); + +/* Helpers to check and generate GREASE values */ +#define IMQUIC_MOQ_GREASE_BASE 0x7f +#define IMQUIC_MOQ_GREASE_SUM 0x9D +static gboolean imquic_moq_is_grease(uint64_t value); +static uint64_t imquic_moq_random_grease(void); /* Initialization */ static void imquic_moq_context_destroy(imquic_moq_context *moq); @@ -1066,6 +1072,9 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_AUTHORITY)); if(options->moqt_implementation_set) list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_SETUP_OPTION_MOQT_IMPLEMENTATION)); + /* For newer versions, we always add a GREASE option */ + if(moq->version >= IMQUIC_MOQ_VERSION_17) + list = g_list_append(list, GUINT_TO_POINTER(imquic_moq_random_grease())); *params_num = g_list_length(list); if(moq->version <= IMQUIC_MOQ_VERSION_16) offset += imquic_write_moqint(moq->version, *params_num, &bytes[offset], blen-offset); @@ -1098,6 +1107,17 @@ size_t imquic_moq_setup_options_serialize(imquic_moq_context *moq, offset += imquic_moq_setup_option_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, (uint8_t *)options->moqt_implementation, strlen(options->moqt_implementation)); + } else if(moq->version >= IMQUIC_MOQ_VERSION_17 && imquic_moq_is_grease(new_id)) { + /* Add a GREASE setup option */ + if(new_id % 2 == 0) { + uint64_t value = g_random_int_range(1, 1000); + offset += imquic_moq_setup_option_add_int(moq, &bytes[offset], blen-offset, + new_id, last_id, value); + } else { + uint8_t data[] = { 0x01, 0x02, 0x03, 0x04 }; + offset += imquic_moq_setup_option_add_data(moq, &bytes[offset], blen-offset, + new_id, last_id, data, sizeof(data)); + } } last_id = new_id; temp = temp->next; @@ -5154,6 +5174,13 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si g_snprintf(params->moqt_implementation, sizeof(params->moqt_implementation), "%.*s", (int)len, &bytes[offset]); IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- '%s'\n", imquic_get_connection_name(moq->conn), params->moqt_implementation); + } else if(moq->version >= IMQUIC_MOQ_VERSION_17 && imquic_moq_is_grease(type)) { + /* This is a GREASE setup option, just skip it */ + if(type % 2 == 0) { + uint64_t grease = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + IMQUIC_MOQ_CHECK_ERR(length == 0 || len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); + len = length; + } } else { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported parameter '%"SCNu64"'\n", imquic_get_connection_name(moq->conn), type); @@ -7336,7 +7363,7 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { } /* Reading and writing MoQ's flavour of variable size integers */ -uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length) { +static uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t blen, uint8_t *length) { if(version <= IMQUIC_MOQ_VERSION_16) return imquic_read_varint(bytes, blen, length); if(length) @@ -7386,7 +7413,7 @@ uint64_t imquic_read_moqint(imquic_moq_version version, uint8_t *bytes, size_t b return res; } -uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen) { +static uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t *bytes, size_t blen) { if(version <= IMQUIC_MOQ_VERSION_16) return imquic_write_varint(number, bytes, blen); if(blen < 1) @@ -7473,6 +7500,20 @@ uint8_t imquic_write_moqint(imquic_moq_version version, uint64_t number, uint8_t return 0; } +/* Helpers to check and generate GREASE values */ +static gboolean imquic_moq_is_grease(uint64_t value) { + if(value < IMQUIC_MOQ_GREASE_SUM) + return FALSE; + uint64_t n = (value - IMQUIC_MOQ_GREASE_SUM) / IMQUIC_MOQ_GREASE_BASE; + return (((n * IMQUIC_MOQ_GREASE_BASE) + IMQUIC_MOQ_GREASE_SUM) == value); +} + +static uint64_t imquic_moq_random_grease(void) { + /* FIXME */ + uint64_t n = g_random_int_range(0, 1000); + return (n * IMQUIC_MOQ_GREASE_BASE) + IMQUIC_MOQ_GREASE_SUM; +} + #ifdef HAVE_QLOG /* QLOG support */ json_t *imquic_qlog_moq_message_prepare(const char *type) { From 52cfbc8e735a9090398266d11aa144553d0f0ae6 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 17:44:04 +0100 Subject: [PATCH 21/30] Close with a PROTOCOL_VIOLATION if parsing parameters fails --- src/internal/moq.h | 2 +- src/moq.c | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/internal/moq.h b/src/internal/moq.h index 30434db..e5a2bf2 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -204,7 +204,7 @@ void imquic_moq_parse_fetch_serialization_flags(imquic_moq_version version, uint imquic_moq_fetch_subgroup_type *subgroup, gboolean *oid, gboolean *group, gboolean *priority, gboolean *prop, gboolean *datagram, gboolean *end_ne_range, gboolean *end_uk_range, gboolean *violation); -/*! \brief MoQ setup parameter types */ +/*! \brief MoQ setup option type */ typedef enum imquic_moq_setup_option_type { IMQUIC_MOQ_SETUP_OPTION_PATH = 0x01, IMQUIC_MOQ_SETUP_OPTION_MAX_REQUEST_ID = 0x02, diff --git a/src/moq.c b/src/moq.c index a86207d..aba2054 100644 --- a/src/moq.c +++ b/src/moq.c @@ -2122,7 +2122,7 @@ size_t imquic_moq_parse_request_ok(imquic_moq_context *moq, imquic_moq_stream *m for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -2316,7 +2316,7 @@ size_t imquic_moq_parse_publish_namespace(imquic_moq_context *moq, imquic_moq_st for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -2476,7 +2476,7 @@ size_t imquic_moq_parse_publish(imquic_moq_context *moq, imquic_moq_stream *moq_ for(i = 0; iversion, &bytes[offset], blen-offset, &length); @@ -2567,7 +2567,7 @@ size_t imquic_moq_parse_publish_ok(imquic_moq_context *moq, imquic_moq_stream *m for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -2632,7 +2632,7 @@ size_t imquic_moq_parse_subscribe(imquic_moq_context *moq, imquic_moq_stream *mo for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -2721,7 +2721,7 @@ size_t imquic_moq_parse_request_update(imquic_moq_context *moq, imquic_moq_strea for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -2797,7 +2797,7 @@ size_t imquic_moq_parse_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream for(i = 0; iversion, &bytes[offset], blen-offset, &length); @@ -2987,7 +2987,7 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -3222,7 +3222,7 @@ size_t imquic_moq_parse_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_st for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { @@ -3378,7 +3378,7 @@ size_t imquic_moq_parse_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq for(i = 0; iversion, &bytes[offset], blen-offset, &length); @@ -3454,7 +3454,7 @@ size_t imquic_moq_parse_track_status(imquic_moq_context *moq, imquic_moq_stream for(i = 0; iconn->qlog != NULL && moq->conn->qlog->moq) { From 4e40278b05f5c513465c693eb9bdb86663dbb6d1 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 18:36:53 +0100 Subject: [PATCH 22/30] Fixed parsing of request parameters --- src/moq.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/moq.c b/src/moq.c index aba2054..bdda296 100644 --- a/src/moq.c +++ b/src/moq.c @@ -707,6 +707,8 @@ const char *imquic_moq_message_type_str(imquic_moq_message_type type, imquic_moq return "CLIENT_SETUP"; case IMQUIC_MOQ_SERVER_SETUP: return "SERVER_SETUP"; + case IMQUIC_MOQ_SETUP: + return "SETUP"; case IMQUIC_MOQ_PUBLISH: return "PUBLISH"; case IMQUIC_MOQ_PUBLISH_OK: @@ -5177,7 +5179,7 @@ size_t imquic_moq_parse_setup_option(imquic_moq_context *moq, uint8_t *bytes, si } else if(moq->version >= IMQUIC_MOQ_VERSION_17 && imquic_moq_is_grease(type)) { /* This is a GREASE setup option, just skip it */ if(type % 2 == 0) { - uint64_t grease = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); + (void)imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0 || len > blen-offset, NULL, 0, 0, "Broken MoQ setup parameter"); len = length; } @@ -5213,7 +5215,7 @@ size_t imquic_moq_parameter_add_varint(imquic_moq_context *moq, uint8_t *bytes, } param -= prev; size_t offset = 0; - offset += imquic_write_moqint(moq->version, param, &bytes[0], blen-offset); + offset += imquic_write_moqint(moq->version, param, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, number, &bytes[offset], blen-offset); return offset; } @@ -5233,8 +5235,7 @@ size_t imquic_moq_parameter_add_uint8(imquic_moq_context *moq, uint8_t *bytes, s return 0; } param -= prev; - size_t offset = 0; - offset += imquic_write_moqint(moq->version, param, &bytes[0], blen-offset); + size_t offset = imquic_write_moqint(moq->version, param, bytes, blen); bytes[offset] = number; return offset+1; } @@ -5246,11 +5247,19 @@ size_t imquic_moq_parameter_add_location(imquic_moq_context *moq, uint8_t *bytes imquic_get_connection_name(moq->conn), param); return 0; } - uint8_t temp[40]; - size_t tlen = sizeof(temp); - size_t toffset = imquic_write_moqint(moq->version, location->group, temp, tlen); - toffset += imquic_write_moqint(moq->version, location->object, &temp[toffset], tlen-toffset); - return imquic_moq_parameter_add_data(moq, bytes, blen, param, prev, temp, toffset); + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + uint8_t temp[40]; + size_t tlen = sizeof(temp); + size_t toffset = imquic_write_moqint(moq->version, location->group, temp, tlen); + toffset += imquic_write_moqint(moq->version, location->object, &temp[toffset], tlen-toffset); + return imquic_moq_parameter_add_data(moq, bytes, blen, param, prev, temp, toffset); + } + param -= prev; + size_t offset = 0; + offset += imquic_write_moqint(moq->version, param, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, location->group, &bytes[offset], blen-offset); + offset += imquic_write_moqint(moq->version, location->object, &bytes[offset], blen-offset); + return offset; } size_t imquic_moq_parameter_add_data(imquic_moq_context *moq, uint8_t *bytes, size_t blen, @@ -5409,8 +5418,10 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte } else { params->largest_object.group = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + len = length; params->largest_object.object = imquic_read_moqint(moq->version, &bytes[offset+length], blen-offset-length, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + len += length; } params->largest_object_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64" / %"SCNu64"\n", @@ -5436,11 +5447,19 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %"SCNu64"\n", imquic_get_connection_name(moq->conn), params->new_group_request); len = length; - } else if(moq->version <= IMQUIC_MOQ_VERSION_16) { - IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported parameter %"SCNu64"\n", - imquic_get_connection_name(moq->conn), type); - if(type % 2 == 0) - len = length; + } else { + if(moq->version <= IMQUIC_MOQ_VERSION_16) { + IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported parameter %"SCNu64"\n", + imquic_get_connection_name(moq->conn), type); + if(type % 2 == 0) + len = length; + } else { + IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Unsupported parameter %"SCNu64"\n", + imquic_get_connection_name(moq->conn), type); + if(error) + *error = IMQUIC_MOQ_PROTOCOL_VIOLATION; + return 0; + } } offset += len; if(error) From e9d530c331cf3da9d5ed8f015a7b315cc4729a51 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 19:33:32 +0100 Subject: [PATCH 23/30] Updated SUBSCRIPTION_FILTER to use deltas for end group --- src/internal/moq.h | 3 +- src/moq.c | 91 +++++++++++++++++++++++++++++++++------------- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/src/internal/moq.h b/src/internal/moq.h index e5a2bf2..b845206 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -1222,13 +1222,14 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte imquic_moq_request_parameters *params, uint64_t *param_type, uint8_t *error); /*! \brief Helper to serialize a imquic_moq_request_parameters set to a buffer * @param[in] moq The imquic_moq_context instance the parameter is for + * @param[in] request The imquic_moq_message_type request originating the parameters to serialize * @param[in] parameters The imquic_moq_request_parameters to serialize * @param[out] bytes The buffer to add paramerers to * @param[in] blen The size of the buffer * @param[out] params_num The number of parameters added to the buffer * @returns The size of the serialized parameters, if successful, or 0 otherwise */ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, - imquic_moq_request_parameters *parameters, + imquic_moq_message_type request, imquic_moq_request_parameters *parameters, uint8_t *bytes, size_t blen, uint8_t *params_num); ///@} diff --git a/src/moq.c b/src/moq.c index bdda296..a9f092c 100644 --- a/src/moq.c +++ b/src/moq.c @@ -1140,7 +1140,7 @@ void imquic_moq_request_parameters_init_defaults(imquic_moq_request_parameters * } size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, - imquic_moq_request_parameters *parameters, + imquic_moq_message_type request, imquic_moq_request_parameters *parameters, uint8_t *bytes, size_t blen, uint8_t *params_num) { if(bytes == NULL || blen == 0) return 0; @@ -1151,26 +1151,46 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, } else { uint64_t new_id = 0, last_id = 0; GList *list = NULL; - if(parameters->auth_token_set) + if(parameters->auth_token_set && request != IMQUIC_MOQ_REQUEST_OK && request != IMQUIC_MOQ_REQUEST_ERROR) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_AUTHORIZATION_TOKEN)); - if(parameters->delivery_timeout_set && parameters->delivery_timeout > 0) + } + if(parameters->delivery_timeout_set && parameters->delivery_timeout > 0 && + (request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_SUBSCRIBE || request == IMQUIC_MOQ_REQUEST_UPDATE)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_DELIVERY_TIMEOUT)); - if(parameters->rendezvous_timeout_set && parameters->rendezvous_timeout > 0 && moq->version >= IMQUIC_MOQ_VERSION_17) + } + if(parameters->rendezvous_timeout_set && parameters->rendezvous_timeout > 0 && + moq->version >= IMQUIC_MOQ_VERSION_17 && request == IMQUIC_MOQ_SUBSCRIBE) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_RENDEZVOUS_TIMEOUT)); - if(parameters->subscriber_priority_set) + } + if(parameters->subscriber_priority_set && + (request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_SUBSCRIBE || request == IMQUIC_MOQ_FETCH || request == IMQUIC_MOQ_REQUEST_UPDATE)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIBER_PRIORITY)); - if(parameters->group_order_set) + } + if(parameters->group_order_set && + (request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_SUBSCRIBE || request == IMQUIC_MOQ_FETCH)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_GROUP_ORDER)); - if(parameters->subscription_filter_set) + } + if(parameters->subscription_filter_set && + (request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_SUBSCRIBE || request == IMQUIC_MOQ_REQUEST_UPDATE)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_SUBSCRIPTION_FILTER)); - if(parameters->expires_set) + } + if(parameters->expires_set && + (request == IMQUIC_MOQ_PUBLISH || request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_REQUEST_OK)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_EXPIRES)); - if(parameters->largest_object_set) + } + if(parameters->largest_object_set && + (request == IMQUIC_MOQ_PUBLISH || request == IMQUIC_MOQ_SUBSCRIBE_OK || request == IMQUIC_MOQ_REQUEST_OK)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_LARGEST_OBJECT)); - if(parameters->forward_set) + } + if(parameters->forward_set && + (request == IMQUIC_MOQ_PUBLISH || request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_SUBSCRIBE || + request == IMQUIC_MOQ_REQUEST_UPDATE || request == IMQUIC_MOQ_SUBSCRIBE_NAMESPACE)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_FORWARD)); - if(parameters->new_group_request_set) + } + if(parameters->new_group_request_set && + (request == IMQUIC_MOQ_PUBLISH_OK || request == IMQUIC_MOQ_SUBSCRIBE || request == IMQUIC_MOQ_REQUEST_UPDATE)) { list = g_list_append(list, GUINT_TO_POINTER(IMQUIC_MOQ_REQUEST_PARAM_NEW_GROUP_REQUEST)); + } *params_num = g_list_length(list); offset += imquic_write_moqint(moq->version, *params_num, &bytes[offset], blen-offset); if(list != NULL) { @@ -1207,8 +1227,13 @@ size_t imquic_moq_request_parameters_serialize(imquic_moq_context *moq, toffset += imquic_write_moqint(moq->version, parameters->subscription_filter.start_location.group, &temp[toffset], tlen-toffset); toffset += imquic_write_moqint(moq->version, parameters->subscription_filter.start_location.object, &temp[toffset], tlen-toffset); } - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - toffset += imquic_write_moqint(moq->version, parameters->subscription_filter.end_group, &temp[toffset], tlen-toffset); + if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { + /* End group is a delta, starting from v17 */ + uint64_t end_group = parameters->subscription_filter.end_group; + if(moq->version >= IMQUIC_MOQ_VERSION_16) + end_group -= parameters->subscription_filter.start_location.group; + toffset += imquic_write_moqint(moq->version, end_group, &temp[toffset], tlen-toffset); + } offset += imquic_moq_parameter_add_data(moq, &bytes[offset], blen-offset, new_id, last_id, temp, toffset); @@ -4178,7 +4203,7 @@ size_t imquic_moq_add_request_ok(imquic_moq_context *moq, imquic_moq_stream *moq if(moq->version <= IMQUIC_MOQ_VERSION_16) offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_REQUEST_OK, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4246,7 +4271,7 @@ size_t imquic_moq_add_publish_namespace(imquic_moq_context *moq, imquic_moq_stre offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_PUBLISH_NAMESPACE); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_PUBLISH_NAMESPACE, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4335,7 +4360,7 @@ size_t imquic_moq_add_publish(imquic_moq_context *moq, imquic_moq_stream *moq_st IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_PUBLISH); offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_PUBLISH, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are properties to encode */ uint8_t properties[256]; size_t properties_len = 0; @@ -4376,7 +4401,7 @@ size_t imquic_moq_add_publish_ok(imquic_moq_context *moq, imquic_moq_stream *moq if(moq->version <= IMQUIC_MOQ_VERSION_16) offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_PUBLISH_OK, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn != NULL && moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4410,7 +4435,7 @@ size_t imquic_moq_add_subscribe(imquic_moq_context *moq, imquic_moq_stream *moq_ IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_SUBSCRIBE); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_SUBSCRIBE, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4447,7 +4472,7 @@ size_t imquic_moq_add_request_update(imquic_moq_context *moq, imquic_moq_stream offset += imquic_write_moqint(moq->version, required_id_delta, &bytes[offset], blen-offset); } uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_REQUEST_UPDATE, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4480,7 +4505,7 @@ size_t imquic_moq_add_subscribe_ok(imquic_moq_context *moq, imquic_moq_stream *m offset += imquic_write_moqint(moq->version, request_id, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, track_alias, &bytes[offset], blen-offset); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_SUBSCRIBE_OK, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are properties to encode */ uint8_t properties[256]; size_t properties_len = 0; @@ -4577,7 +4602,7 @@ size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_st IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE); offset += imquic_write_moqint(moq->version, subscribe_options, &bytes[offset], blen-offset); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_SUBSCRIBE_NAMESPACE, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4707,7 +4732,7 @@ size_t imquic_moq_add_fetch(imquic_moq_context *moq, imquic_moq_stream *moq_stre offset += imquic_write_moqint(moq->version, preceding_group_offset, &bytes[offset], blen-offset); } uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_FETCH, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -4774,7 +4799,7 @@ size_t imquic_moq_add_fetch_ok(imquic_moq_context *moq, imquic_moq_stream *moq_s offset += imquic_write_moqint(moq->version, end_location->group, &bytes[offset], blen-offset); offset += imquic_write_moqint(moq->version, end_location->object, &bytes[offset], blen-offset); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_FETCH_OK, parameters, &bytes[offset], blen-offset, ¶ms_num); /* Check if there are properties to encode */ uint8_t properties[256]; size_t properties_len = 0; @@ -4814,7 +4839,7 @@ size_t imquic_moq_add_track_status(imquic_moq_context *moq, imquic_moq_stream *m IMQUIC_MOQ_ADD_NAMESPACES(IMQUIC_MOQ_TRACK_STATUS); IMQUIC_MOQ_ADD_TRACKNAME(IMQUIC_MOQ_TRACK_STATUS); uint8_t params_num = 0; - offset += imquic_moq_request_parameters_serialize(moq, parameters, &bytes[offset], blen-offset, ¶ms_num); + offset += imquic_moq_request_parameters_serialize(moq, IMQUIC_MOQ_TRACK_STATUS, parameters, &bytes[offset], blen-offset, ¶ms_num); IMQUIC_MOQ_ADD_MESSAGE_LENGTH(); #ifdef HAVE_QLOG if(moq->conn->qlog != NULL && moq->conn->qlog->moq) { @@ -5395,6 +5420,10 @@ size_t imquic_moq_parse_request_parameter(imquic_moq_context *moq, uint8_t *byte if(params->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { params->subscription_filter.end_group = imquic_read_moqint(moq->version, &tmp[toffset], tlen-toffset, &length); IMQUIC_MOQ_CHECK_ERR(length == 0, NULL, 0, 0, "Broken MoQ request parameter"); + /* The End group property is a delta, starting from v17, but + * we expose the full actual value to the application */ + if(moq->version >= IMQUIC_MOQ_VERSION_17) + params->subscription_filter.end_group += params->subscription_filter.start_location.group; } params->subscription_filter_set = TRUE; IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- -- -- %d\n", @@ -7636,6 +7665,12 @@ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_ json_object_set_new(delivery_timeout, "value", json_integer(parameters->delivery_timeout)); json_array_append_new(params, delivery_timeout); } + if(parameters->rendezvous_timeout_set) { + json_t *rendezvous_timeout = json_object(); + json_object_set_new(rendezvous_timeout, "name", json_string("rendezvous_timeout")); + json_object_set_new(rendezvous_timeout, "value", json_integer(parameters->rendezvous_timeout)); + json_array_append_new(params, rendezvous_timeout); + } if(parameters->subscriber_priority_set) { json_t *subscriber_priority = json_object(); json_object_set_new(subscriber_priority, "name", json_string("subscriber_priority")); @@ -7661,8 +7696,12 @@ void imquic_qlog_moq_message_add_request_parameters(json_t *message, imquic_moq_ json_object_set_new(lo, "object", json_integer(parameters->subscription_filter.start_location.object)); json_object_set_new(sf, "start_location", lo); } - if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) - json_object_set_new(sf, "end_group", json_integer(parameters->subscription_filter.end_group)); + if(parameters->subscription_filter.type == IMQUIC_MOQ_FILTER_ABSOLUTE_RANGE) { + if(version <= IMQUIC_MOQ_VERSION_16) + json_object_set_new(sf, "end_group", json_integer(parameters->subscription_filter.end_group)); + else + json_object_set_new(sf, "end_group_delta", json_integer(parameters->subscription_filter.end_group - parameters->subscription_filter.start_location.group)); + } json_object_set_new(subscription_filter, "value", sf); json_array_append_new(params, subscription_filter); } From b926e9304c64c24535ffb23ef65fd304d8978089 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 9 Mar 2026 19:41:59 +0100 Subject: [PATCH 24/30] Some more actions on streams when interacting with the API --- src/moq.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/moq.c b/src/moq.c index a9f092c..b7374d2 100644 --- a/src/moq.c +++ b/src/moq.c @@ -6415,8 +6415,8 @@ int imquic_moq_unsubscribe(imquic_connection *conn, uint64_t request_id) { imquic_refcount_decrease(&moq->ref); return -1; } - /* Reset the STREAM */ - imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); + /* Send a STOP_SENDING */ + imquic_connection_stop_sending_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); @@ -6478,7 +6478,12 @@ int imquic_moq_publish_done(imquic_connection *conn, uint64_t request_id, imquic request_id, status_code, streams_count, reason); imquic_connection_send_on_stream(conn, moq_stream ? moq_stream->stream_id : moq->control_stream_id, - buffer, sd_len, FALSE); + buffer, sd_len, moq_stream ? TRUE : FALSE); + if(moq_stream != NULL) { + imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams, &moq_stream->stream_id); + imquic_mutex_unlock(&moq->mutex); + } /* Done */ imquic_refcount_decrease(&moq->ref); return 0; From 7410ef3c8644a645809ec11c3fbfea00781a999f Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 10 Mar 2026 14:31:59 +0100 Subject: [PATCH 25/30] Allow SUBSCRIBE_NAMESPACE to have an empty namespace tuple --- examples/moq-sub.c | 2 +- src/moq.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/moq-sub.c b/examples/moq-sub.c index 0cdcf7f..6c8e0b9 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -196,7 +196,7 @@ static void imquic_demo_ready(imquic_connection *conn) { params.forward = TRUE; if(options.update_subscribe > 0 && (options.fetch == NULL || options.join_offset >= 0)) params.forward = FALSE; - imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), 0, tns, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); + imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), 0, NULL, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); return; } /* Parameters in case we need to FETCH */ diff --git a/src/moq.c b/src/moq.c index b7374d2..bf93873 100644 --- a/src/moq.c +++ b/src/moq.c @@ -1303,7 +1303,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { do { \ tns_num = imquic_read_moqint(moq->version, &bytes[offset], blen-offset, &length); \ IMQUIC_MOQ_CHECK_ERR(length == 0 || (tns_num > 0 && length >= blen-offset), NULL, 0, 0, error_message); \ - IMQUIC_MOQ_CHECK_ERR((tns_num == 0 && request != IMQUIC_MOQ_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE_DONE) || tns_num > 32, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid number of namespaces"); \ + IMQUIC_MOQ_CHECK_ERR((tns_num == 0 && request != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE_DONE) || tns_num > 32, error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid number of namespaces"); \ offset += length; \ uint64_t total_len = 0; \ i = 0; \ @@ -1364,7 +1364,7 @@ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { tns_num++; \ temp = temp->next; \ } \ - if((tns_num == 0 && request != IMQUIC_MOQ_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE_DONE) || tns_num > 32) { \ + if((tns_num == 0 && request != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE && request != IMQUIC_MOQ_NAMESPACE_DONE) || tns_num > 32) { \ IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid number of tuples\n", \ imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(request, moq->version)); \ return 0; \ @@ -4589,7 +4589,7 @@ size_t imquic_moq_add_publish_done(imquic_moq_context *moq, imquic_moq_stream *m size_t imquic_moq_add_subscribe_namespace(imquic_moq_context *moq, imquic_moq_stream *moq_stream, uint8_t *bytes, size_t blen, uint64_t request_id, uint64_t required_id_delta, imquic_moq_namespace *track_namespace, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters) { - if(bytes == NULL || blen < 1 || track_namespace == NULL || moq_stream == NULL) { + if(bytes == NULL || blen < 1 || moq_stream == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Can't add MoQ %s: invalid arguments\n", imquic_get_connection_name(moq->conn), imquic_moq_message_type_str(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE, moq->version)); return 0; @@ -6493,7 +6493,7 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, imquic_moq_namespace *tns, imquic_moq_subscribe_namespace_options subscribe_options, imquic_moq_request_parameters *parameters) { imquic_mutex_lock(&moq_mutex); imquic_moq_context *moq = g_hash_table_lookup(moq_sessions, conn); - if(moq == NULL || tns == NULL || tns->buffer == 0 || tns->length == 0) { + if(moq == NULL) { IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid arguments\n", imquic_get_connection_name(conn)); imquic_mutex_unlock(&moq_mutex); @@ -6541,8 +6541,8 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, /* Track the request, and map it to the dedicated bidirectional STREAM */ moq_stream->request_state = IMQUIC_MOQ_REQUEST_STATE_SENT; moq_stream->request_id = request_id; - moq_stream->namespace_prefix = moq_stream->last_tuple = imquic_moq_namespace_duplicate(tns); - while(moq_stream->last_tuple->next != NULL) + moq_stream->namespace_prefix = moq_stream->last_tuple = tns ? imquic_moq_namespace_duplicate(tns) : g_malloc0(sizeof(imquic_moq_namespace)); + while(moq_stream->last_tuple != NULL && moq_stream->last_tuple->next != NULL) moq_stream->last_tuple = moq_stream->last_tuple->next; moq_stream->namespace_prefix_size = tns_num; imquic_mutex_lock(&moq->mutex); From 5b10431c6d71e5a63ed5db72fd4d04cb14417cbc Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 10 Mar 2026 14:33:55 +0100 Subject: [PATCH 26/30] Fixed debug line in demo --- examples/moq-sub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/moq-sub.c b/examples/moq-sub.c index 6c8e0b9..0cdcf7f 100644 --- a/examples/moq-sub.c +++ b/examples/moq-sub.c @@ -196,7 +196,7 @@ static void imquic_demo_ready(imquic_connection *conn) { params.forward = TRUE; if(options.update_subscribe > 0 && (options.fetch == NULL || options.join_offset >= 0)) params.forward = FALSE; - imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), 0, NULL, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); + imquic_moq_subscribe_namespace(conn, imquic_moq_get_next_request_id(conn), 0, tns, IMQUIC_MOQ_WANT_PUBLISH_AND_NAMESPACE, ¶ms); return; } /* Parameters in case we need to FETCH */ From 3e5b0a0ab008c368a630a04b1ffc674d8b56998e Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 10 Mar 2026 14:36:20 +0100 Subject: [PATCH 27/30] Fixed state management for NAMESPACE events --- src/moq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/moq.c b/src/moq.c index bf93873..edef0fb 100644 --- a/src/moq.c +++ b/src/moq.c @@ -3066,7 +3066,7 @@ size_t imquic_moq_parse_namespace(imquic_moq_context *moq, imquic_moq_stream *mo if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), + !moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3101,7 +3101,7 @@ size_t imquic_moq_parse_namespace_done(imquic_moq_context *moq, imquic_moq_strea if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), + !moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of NAMESPACE_DONE on bidirectional request"); size_t offset = 0; uint8_t length = 0; @@ -3136,7 +3136,7 @@ size_t imquic_moq_parse_publish_blocked(imquic_moq_context *moq, imquic_moq_stre if(bytes == NULL || blen < 1) return 0; IMQUIC_MOQ_CHECK_ERR((moq_stream == NULL || moq_stream->request_type != IMQUIC_MOQ_SUBSCRIBE_NAMESPACE || - moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), + !moq_stream->request_sender || (moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_OK && moq_stream->request_state != IMQUIC_MOQ_REQUEST_STATE_UPDATE_SENT)), error, IMQUIC_MOQ_PROTOCOL_VIOLATION, 0, "Invalid use of PUBLISH_BLOCKED on bidirectional request"); size_t offset = 0; uint8_t length = 0; From 6c94bf1679a7e3e105ae8a6ffc28bbeb0ee60627 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 10 Mar 2026 14:54:31 +0100 Subject: [PATCH 28/30] Relay demo now honors SUBSCRIBE_NAMESPACE with zero namespace fields --- examples/moq-relay.c | 2 +- src/imquic-moq.c | 8 ++++++-- src/moq.c | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/moq-relay.c b/examples/moq-relay.c index 82a1c10..09d9fc0 100644 --- a/examples/moq-relay.c +++ b/examples/moq-relay.c @@ -330,7 +330,7 @@ static void imquic_demo_moq_monitor_destroy(imquic_demo_moq_monitor *mon) { /* Helper functions to return monitors that match a namespace */ static GList *imquic_demo_match_monitors(imquic_connection *conn, imquic_moq_namespace *tns) { - if(monitors == NULL || tns == NULL) + if(monitors == NULL) return NULL; imquic_demo_moq_monitor *mon = NULL; GList *list = NULL, *temp = monitors; diff --git a/src/imquic-moq.c b/src/imquic-moq.c index 3b6efdc..ca77508 100644 --- a/src/imquic-moq.c +++ b/src/imquic-moq.c @@ -253,9 +253,11 @@ static size_t imquic_moq_name_render(uint8_t *data, size_t dlen, char *buffer, s } const char *imquic_moq_namespace_str(imquic_moq_namespace *tns, char *buffer, size_t blen, gboolean tuple) { - if(tns == NULL) + if(buffer == NULL) return NULL; *buffer = '\0'; + if(tns == NULL) + return buffer; size_t offset = 0; while(tns != NULL) { if(blen - offset == 0) @@ -299,7 +301,9 @@ gboolean imquic_moq_namespace_equals(imquic_moq_namespace *first, imquic_moq_nam } gboolean imquic_moq_namespace_contains(imquic_moq_namespace *parent, imquic_moq_namespace *child) { - if(parent == NULL || child == NULL) + if(parent == NULL) + return TRUE; + if(child == NULL) return FALSE; size_t i = 0; while(parent) { diff --git a/src/moq.c b/src/moq.c index edef0fb..a7352ac 100644 --- a/src/moq.c +++ b/src/moq.c @@ -3050,7 +3050,9 @@ size_t imquic_moq_parse_subscribe_namespace(imquic_moq_context *moq, imquic_moq_ /* Notify the application */ if(moq->conn->socket && moq->conn->socket->callbacks.moq.incoming_subscribe_namespace) { moq->conn->socket->callbacks.moq.incoming_subscribe_namespace(moq->conn, - request_id, required_id_delta, &tns[0], subscribe_options, ¶meters); + request_id, required_id_delta, + (tns_num > 0 ? &tns[0] : NULL), + subscribe_options, ¶meters); } else { /* No handler for this request, let's reject it ourselves */ imquic_moq_reject_subscribe_namespace(moq->conn, request_id, IMQUIC_MOQ_REQERR_NOT_SUPPORTED, "Not handled", 0); From b6b37543d0695c172b68329f1c4758144a19671f Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 10 Mar 2026 15:02:07 +0100 Subject: [PATCH 29/30] Fixed missing lock --- src/moq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/moq.c b/src/moq.c index a7352ac..054e1bb 100644 --- a/src/moq.c +++ b/src/moq.c @@ -393,6 +393,7 @@ static void imquic_moq_request_stream_closed(imquic_moq_context *moq, imquic_moq gboolean request_sender = moq_stream->request_sender; uint64_t request_id = moq_stream->request_id; gboolean notify = !request_sender; + imquic_mutex_lock(&moq->mutex); g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); /* */ imquic_mutex_unlock(&moq->mutex); From 3a15fd1db3184b32b6e36340fa72b5d417b3ce63 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 10 Mar 2026 16:41:25 +0100 Subject: [PATCH 30/30] Use reference counters for MoQ streams --- examples/moq-interop-test.c | 10 ----- src/internal/moq.h | 7 ++++ src/moq.c | 82 +++++++++++++++++++++++++++++-------- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/examples/moq-interop-test.c b/examples/moq-interop-test.c index 7f1359f..b820c57 100644 --- a/examples/moq-interop-test.c +++ b/examples/moq-interop-test.c @@ -137,7 +137,6 @@ static imquic_moq_interop_client *imquic_moq_interop_client_create(imquic_moq_in /* Callbacks */ static void imquic_moq_interop_new_connection(imquic_connection *conn, void *user_data); -static void imquic_moq_interop_connection_failed(void *user_data); static void imquic_moq_interop_ready(imquic_connection *conn); static void imquic_moq_interop_publish_namespace_accepted(imquic_connection *conn, uint64_t request_id, imquic_moq_request_parameters *parameters); @@ -455,7 +454,6 @@ static imquic_moq_interop_client *imquic_moq_interop_client_create(imquic_moq_in return NULL; } imquic_set_new_moq_connection_cb(mc->client, imquic_moq_interop_new_connection); - imquic_set_connection_failed_cb(mc->client, imquic_moq_interop_connection_failed); imquic_set_moq_ready_cb(mc->client, imquic_moq_interop_ready); imquic_set_moq_connection_gone_cb(mc->client, imquic_moq_interop_connection_gone); if(publisher) { @@ -482,14 +480,6 @@ static void imquic_moq_interop_new_connection(imquic_connection *conn, void *use imquic_moq_set_max_request_id(conn, max_request_id); } -static void imquic_moq_interop_connection_failed(void *user_data) { - imquic_moq_interop_client *client = (imquic_moq_interop_client *)user_data; - if(client != NULL) { - imquic_moq_interop_test_context *test = (imquic_moq_interop_test_context *)client->test; - g_atomic_int_set(&test->done, 1); - } -} - static void imquic_moq_interop_ready(imquic_connection *conn) { /* Depending on the test, we may or may not be done */ imquic_mutex_lock(&mutex); diff --git a/src/internal/moq.h b/src/internal/moq.h index b845206..563111c 100644 --- a/src/internal/moq.h +++ b/src/internal/moq.h @@ -416,7 +416,14 @@ typedef struct imquic_moq_stream { uint8_t last_priority; /*! \brief Whether we closed this stream */ gboolean closed; + /*! \brief Whether this instance has been destroyed (reference counting) */ + volatile gint destroyed; + /*! \brief Reference counter */ + imquic_refcount ref; } imquic_moq_stream; +/*! \brief Create a new MoQ stream + * @returns A pointer to a new moq_stream instance, if successful, or NULL otherwise */ +imquic_moq_stream *imquic_moq_stream_create(void); /*! \brief Destroy an existing MoQ stream * @param moq_stream MoQ stream to destroy */ void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream); diff --git a/src/moq.c b/src/moq.c index 054e1bb..f816000 100644 --- a/src/moq.c +++ b/src/moq.c @@ -1283,12 +1283,22 @@ void imquic_moq_subscription_destroy(imquic_moq_subscription *moq_sub) { } } +static void imquic_moq_stream_free(const imquic_refcount *ms_ref) { + imquic_moq_stream *moq_stream = imquic_refcount_containerof(ms_ref, imquic_moq_stream, ref); + imquic_moq_namespace_free(moq_stream->namespace_prefix); + imquic_buffer_destroy(moq_stream->buffer); + g_free(moq_stream); +} + +imquic_moq_stream *imquic_moq_stream_create(void) { + imquic_moq_stream *moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_refcount_init(&moq_stream->ref, imquic_moq_stream_free); + return moq_stream; +} + void imquic_moq_stream_destroy(imquic_moq_stream *moq_stream) { - if(moq_stream != NULL) { - imquic_moq_namespace_free(moq_stream->namespace_prefix); - imquic_buffer_destroy(moq_stream->buffer); - g_free(moq_stream); - } + if(moq_stream && g_atomic_int_compare_and_exchange(&moq_stream->destroyed, 0, 1)) + imquic_refcount_decrease(&moq_stream->ref); } /* Parsing and building macros */ @@ -1449,6 +1459,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ return 0; } /* Check if this is a media stream */ + imquic_mutex_lock(&moq->mutex); imquic_moq_stream *moq_stream = g_hash_table_lookup(moq->streams, &stream_id); if(imquic_moq_is_control_stream(moq, stream_id)) { imquic_buffer_append(moq->buffer, bytes, blen); @@ -1461,6 +1472,9 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ bytes = moq_stream->buffer->bytes; blen = moq_stream->buffer->length; } + if(moq_stream != NULL) + imquic_refcount_increase(&moq_stream->ref); + imquic_mutex_unlock(&moq->mutex); /* Iterate on all frames */ while((moq_stream == NULL || moq_stream->request_type != 0) && blen-offset > 0) { /* If we're here, we're either on the control stream, on a request @@ -1480,22 +1494,30 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ /* Create a new MoQ stream for the request and track it */ IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Stream %"SCNu64" will be used for %s\n", imquic_get_connection_name(moq->conn), stream_id, imquic_moq_message_type_str(type, moq->version)); - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); moq_stream->stream_id = stream_id; moq_stream->request_type = type; - g_hash_table_insert(moq->streams, imquic_dup_uint64(stream_id), moq_stream); moq_stream->buffer = imquic_buffer_create(bytes, blen); bytes = moq_stream->buffer->bytes; blen = moq_stream->buffer->length; + imquic_mutex_lock(&moq->mutex); + g_hash_table_insert(moq->streams, imquic_dup_uint64(stream_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + /* This reference is for managing the message */ + imquic_refcount_increase(&moq_stream->ref); } else if(!bidirectional && imquic_moq_is_data_message_type_valid(moq->version, dtype)) { /* Create a new MoQ stream for data and track it */ IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] -- Stream %"SCNu64" will be used for %s\n", imquic_get_connection_name(moq->conn), stream_id, imquic_moq_data_message_type_str(dtype, moq->version)); - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); moq_stream->stream_id = stream_id; moq_stream->type = dtype; moq_stream->priority = 128; /* FIXME */ + imquic_mutex_lock(&moq->mutex); g_hash_table_insert(moq->streams, imquic_dup_uint64(stream_id), moq_stream); + imquic_mutex_unlock(&moq->mutex); + /* This reference is for managing the message */ + imquic_refcount_increase(&moq_stream->ref); } else { /* TODO Handle failure */ IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] MoQ message '%s' (%02x) is not allowed on media streams\n", @@ -1633,6 +1655,8 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_buffer_shift(moq->buffer, plen); if(error != IMQUIC_MOQ_UNKNOWN_ERROR) imquic_connection_close(moq->conn, error, imquic_moq_error_code_str(error)); + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); return -1; } /* Move to the next message */ @@ -1734,6 +1758,8 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ imquic_buffer_shift(moq_stream->buffer, plen); if(error != IMQUIC_MOQ_UNKNOWN_ERROR) imquic_connection_close(moq->conn, error, imquic_moq_error_code_str(error)); + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); return -1; } /* Move to the next message */ @@ -1761,12 +1787,16 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ } else { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Unsupported data message '%02x'\n", imquic_get_connection_name(moq->conn), type); + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); return -1; } } if(parsed == parsed_prev) { IMQUIC_LOG(IMQUIC_LOG_WARN, "[%s][MoQ] Broken MoQ message (didn't advance from offset %zu/%zu)\n", imquic_get_connection_name(moq->conn), parsed, blen); + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); return -1; } } @@ -1798,11 +1828,15 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ /* FIXME Shouldn't happen */ IMQUIC_LOG(IMQUIC_LOG_ERR, "[%s][MoQ] Invalid MoQ stream type '%s' (%02x)\n", imquic_get_connection_name(moq->conn), imquic_moq_data_message_type_str(moq_stream->type, moq->version), moq_stream->type); + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); return -1; } } if(error && error != IMQUIC_MOQ_UNKNOWN_ERROR) { imquic_connection_close(moq->conn, error, imquic_moq_error_code_str(error)); + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); return -1; } } @@ -1812,6 +1846,7 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ if(moq_stream->request_type > 0) { /* The request dedicated bidirectional STREAM has been closed */ imquic_moq_request_stream_closed(moq, moq_stream); + imquic_refcount_decrease(&moq_stream->ref); return 0; } IMQUIC_LOG(IMQUIC_MOQ_LOG_HUGE, "[%s][MoQ] Media stream %"SCNu64" is complete\n", @@ -1838,6 +1873,8 @@ int imquic_moq_parse_message(imquic_moq_context *moq, uint64_t stream_id, uint8_ g_hash_table_remove(moq->streams, &stream_id); imquic_mutex_unlock(&moq->mutex); } + if(moq_stream != NULL) + imquic_refcount_decrease(&moq_stream->ref); /* Done */ return 0; } @@ -5779,7 +5816,7 @@ int imquic_moq_publish_namespace(imquic_connection *conn, uint64_t request_id, u /* Starting from v17, requests on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_PUBLISH_NAMESPACE; moq_stream->request_id = request_id; @@ -5912,6 +5949,7 @@ int imquic_moq_publish_namespace_done(imquic_connection *conn, uint64_t request_ } /* Reset the STREAM */ imquic_connection_reset_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); imquic_refcount_decrease(&moq->ref); @@ -5962,7 +6000,7 @@ int imquic_moq_publish(imquic_connection *conn, uint64_t request_id, uint64_t re /* Starting from v17, requests on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_PUBLISH; moq_stream->request_id = request_id; @@ -6072,6 +6110,7 @@ int imquic_moq_reject_publish(imquic_connection *conn, uint64_t request_id, buffer, sb_len, moq_stream ? TRUE : FALSE); if(moq_stream != NULL) { imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); } @@ -6117,7 +6156,7 @@ int imquic_moq_subscribe(imquic_connection *conn, uint64_t request_id, uint64_t /* Starting from v17, requests on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE; moq_stream->request_id = request_id; @@ -6227,6 +6266,7 @@ int imquic_moq_reject_subscribe(imquic_connection *conn, uint64_t request_id, buffer, sb_len, moq_stream ? TRUE : FALSE); if(moq_stream != NULL) { imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); } @@ -6419,9 +6459,11 @@ int imquic_moq_unsubscribe(imquic_connection *conn, uint64_t request_id) { return -1; } /* Send a STOP_SENDING */ - imquic_connection_stop_sending_stream(moq->conn, moq_stream->stream_id, IMQUIC_MOQ_RESET_CANCELLED); + uint64_t stream_id = moq_stream->stream_id; + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); + imquic_connection_stop_sending_stream(moq->conn, stream_id, IMQUIC_MOQ_RESET_CANCELLED); imquic_refcount_decrease(&moq->ref); return 0; } @@ -6484,6 +6526,7 @@ int imquic_moq_publish_done(imquic_connection *conn, uint64_t request_id, imquic buffer, sd_len, moq_stream ? TRUE : FALSE); if(moq_stream != NULL) { imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); } @@ -6529,7 +6572,7 @@ int imquic_moq_subscribe_namespace(imquic_connection *conn, uint64_t request_id, g_hash_table_insert(moq->requests, imquic_dup_uint64(request_id), GUINT_TO_POINTER(IMQUIC_MOQ_SUBSCRIBE_NAMESPACE)); imquic_mutex_unlock(&moq->mutex); /* Starting from v16, SUBSCRIBE_NAMESPACE goes on a dedicated bidirectional STREAM */ - imquic_moq_stream *moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + imquic_moq_stream *moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_SUBSCRIBE_NAMESPACE; moq_stream->request_id = request_id; @@ -6629,6 +6672,7 @@ int imquic_moq_reject_subscribe_namespace(imquic_connection *conn, uint64_t requ buffer, sb_len, moq_stream ? TRUE : FALSE); if(moq_stream != NULL) { imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); } @@ -6818,7 +6862,7 @@ int imquic_moq_standalone_fetch(imquic_connection *conn, uint64_t request_id, ui /* Starting from v17, requests on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_FETCH; moq_stream->request_id = request_id; @@ -6873,7 +6917,7 @@ int imquic_moq_joining_fetch(imquic_connection *conn, uint64_t request_id, uint6 /* Starting from v17, requests on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_FETCH; moq_stream->request_id = request_id; @@ -6983,6 +7027,7 @@ int imquic_moq_reject_fetch(imquic_connection *conn, uint64_t request_id, buffer, f_len, moq_stream ? TRUE : FALSE); if(moq_stream != NULL) { imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); } @@ -7050,7 +7095,7 @@ int imquic_moq_track_status(imquic_connection *conn, uint64_t request_id, /* Starting from v17, requests on a dedicated bidirectional STREAM */ imquic_moq_stream *moq_stream = NULL; if(moq->version >= IMQUIC_MOQ_VERSION_17) { - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); imquic_connection_new_stream_id(moq->conn, TRUE, &moq_stream->stream_id); moq_stream->request_type = IMQUIC_MOQ_TRACK_STATUS; moq_stream->request_id = request_id; @@ -7150,6 +7195,7 @@ int imquic_moq_reject_track_status(imquic_connection *conn, uint64_t request_id, buffer, tsr_len, moq_stream ? TRUE : FALSE); if(moq_stream != NULL) { imquic_mutex_lock(&moq->mutex); + g_hash_table_remove(moq->streams_by_reqid, &moq_stream->request_id); g_hash_table_remove(moq->streams, &moq_stream->stream_id); imquic_mutex_unlock(&moq->mutex); } @@ -7273,7 +7319,7 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { return -1; } /* Create a new stream */ - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); /* TODO Change the type depending on whether properties/subgroup will be set: * since we don't have an API for that, for now we always set the type * that will allow us to dynamically use them all. This also means we @@ -7360,7 +7406,7 @@ int imquic_moq_send_object(imquic_connection *conn, imquic_moq_object *object) { return -1; } /* Create a new stream */ - moq_stream = g_malloc0(sizeof(imquic_moq_stream)); + moq_stream = imquic_moq_stream_create(); moq_stream->type = IMQUIC_MOQ_FETCH_HEADER; moq_stream->priority = 128; /* FIXME */ imquic_connection_new_stream_id(conn, FALSE, &moq_stream->stream_id);