Commit 94c22bfce0 for bind
commit 94c22bfce04302b3c6f43798a00c0bc4e0fdd179
Author: Aydın Mercan <aydin@isc.org>
Date: Thu Aug 27 12:02:05 2026 +0300
Initial definition of QUIC connection state machine
Add a minimal definition of the `isc_quic_conn_t` state machine for
usage in other places (e.g. the QUIC router) before having the required
functionality.
diff --git a/lib/isc/include/isc/quic.h b/lib/isc/include/isc/quic.h
index a0af5b8000..7c45baecdc 100644
--- a/lib/isc/include/isc/quic.h
+++ b/lib/isc/include/isc/quic.h
@@ -17,6 +17,8 @@
#include <isc/region.h>
#include <isc/result.h>
#include <isc/tid.h>
+#include <isc/time.h>
+#include <isc/tls.h>
#include <isc/types.h>
/*! \file isc/quic.h */
@@ -52,23 +54,6 @@
*/
typedef struct isc_quic_router isc_quic_router_t;
-/**
- * \brief
- * Callbacks the router uses to keep a connection alive while it is reachable
- * through the router or has been handed out by a lookup.
- *
- * `conn_ref` must acquire a reference on `conn`; `conn_unref` must release one.
- * They allow the router to hand out a retained connection pointer without
- * racing a concurrent teardown.
- *
- * \warning
- * `conn_unref` may be invoked from an RCU worker thread, because the router
- * releases its own reference from a deferred-reclamation (call_rcu) callback.
- * It must therefore be safe to call from any thread.
- */
-typedef void (*isc_quic_conn_ref_t)(void *conn);
-typedef void (*isc_quic_conn_unref_t)(void *conn);
-
typedef enum isc_quic_version {
/** Invalid QUIC version */
ISC_QUIC_VERSION_INVALID = 0,
@@ -85,11 +70,56 @@ typedef enum isc_quic_version {
ISC_QUIC_VERSION__MAX = 4,
} isc_quic_version_t;
+/**
+ * \brief
+ * User-specified callbacks
+ *
+ * All callbacks are optional.
+ */
+struct isc_quic_conn_callbacks {};
+
+/**
+ * \brief
+ * Connection independent QUIC connection options of an endpoint.
+ */
+struct isc_quic_conn_options {
+ /**
+ * \brief
+ * TLS context used by the QUIC connection.
+ */
+ isc_tlsctx_t *tlsctx;
+
+ /**
+ * \brief
+ * ALPN value of the TLS handshake.
+ *
+ * \warning
+ * Must be less than 7-bytes, might be increased in the future.
+ */
+ isc_constregion_t alpn;
+
+ /**
+ * \brief
+ * Handshake timeout of the state machine
+ *
+ * Must not be `isc_quic_timestamp_invalid`. Zero value disables
+ * timeout.
+ */
+ isc_nanosecs_t handshake_timeout;
+
+ /**
+ * \brief
+ * Idle timeout of the state machine
+ *
+ * Must not be `isc_quic_timestamp_invalid`. Zero value disables
+ * timeout.
+ */
+ isc_nanosecs_t idle_timeout;
+};
+
void
isc_quic_router_create(isc_mem_t *mctx, size_t cidlen,
- isc_quic_conn_ref_t conn_ref,
- isc_quic_conn_unref_t conn_unref,
- isc_quic_router_t **routerp);
+ isc_quic_router_t **routerp);
/**<
* \brief
* Create a new QUIC CID router.
@@ -137,7 +167,7 @@ isc_quic_router_add_cid(isc_quic_router_t *router, isc_constregion_t cid,
isc_result_t
isc_quic_router_get_cid(isc_quic_router_t *router, isc_constregion_t cid,
- isc_tid_t *tidp, void **connp);
+ isc_tid_t *tidp, isc_quic_conn_t **connp);
/**<
* \brief
* Get the connection associated with a given CID and its thread if `tidp` is
@@ -202,7 +232,7 @@ isc_result_t
isc_quic_router_get_stateless_reset(
isc_quic_router_t *router,
const uint8_t token[const restrict ISC_QUIC_STATELESS_TOKEN_LENGTH],
- isc_tid_t *tidp, void **connp);
+ isc_tid_t *tidp, isc_quic_conn_t **connp);
/**<
* \brief
* Get the connection associated with the given stateless reset token and its
@@ -243,7 +273,7 @@ isc_quic_router_handle_packet(isc_quic_router_t *router,
isc_quic_version_t *versionp,
isc_constregion_t *dcidp,
isc_constregion_t *scidp, isc_tid_t *tidp,
- void **connp);
+ isc_quic_conn_t **connp);
/**<
* \brief
* Extracts the associated value and relevant information of a given QUIC
@@ -294,3 +324,64 @@ isc_quic_router_handle_packet(isc_quic_router_t *router,
* Unlike ISC_R_UNEXPECTED, the caller MUST NOT send a stateless reset in
* response (RFC9000, Section 10.3).
*/
+
+isc_result_t
+isc_quic_conn_client_create(isc_mem_t *mctx, isc_quic_router_t *router,
+ const isc_quic_conn_callbacks_t *callbacks,
+ void *callback_arg,
+ const isc_quic_conn_options_t *options,
+ const char *sni, const isc_sockaddr_t *local,
+ const isc_sockaddr_t *peer,
+ isc_quic_conn_t **connp);
+
+/**<
+ * \brief
+ * Create a new client state machine.
+ *
+ * \par Requires
+ * \li `mctx` is a valid memory context
+ * \li `router` is a valid QUIC router
+ * \li `options != NULL` and is valid
+ * \li `version` is a valid and defined QUIC version
+ * \li `sni` points to a valid SNI string
+ * \li `local != NULL`
+ * \li `peer != NULL`
+ * \li `connp != NULL` and `*connp == NULL`
+ *
+ * \retval ISC_R_SUCCESS on success
+ * \retval ISC_R_NOTIMPLEMENTED if the given QUIC version is not supported
+ * \retval ISC_R_TLSERROR on internal TLS failure
+ * \retval ISC_R_NOMEMORY on allocation failure
+ * \retval ISC_R_FAILURE on unknown failure
+ */
+
+isc_result_t
+isc_quic_conn_server_create(
+ isc_mem_t *mctx, isc_quic_router_t *router,
+ const isc_quic_conn_callbacks_t *callbacks, void *callback_arg,
+ const isc_quic_conn_options_t *options, isc_constregion_t initial_dcid,
+ isc_constregion_t initial_scid, const isc_sockaddr_t *local,
+ const isc_sockaddr_t *peer, isc_quic_conn_t **connp);
+/**<
+ * \brief
+ * Create a new server state machine
+ *
+ * \par Requires
+ * \li `mctx` is a valid memory context
+ * \li `router` is a valid QUIC router
+ * \li `options != NULL` and is valid
+ * \li `initial_version` is a valid and defined QUIC version
+ * \li `initial_dcid.base != NULL` and `initial_dcid.length` ∈ [1, 20]
+ * \li `initial_scid.base != NULL` and `initial_scid.length` ∈ [1, 20]
+ * \li `local != NULL`
+ * \li `peer != NULL`
+ * \li `connp != NULL` and `*connp == NULL`
+ *
+ * \retval ISC_R_SUCCESS on success
+ * \retval ISC_R_NOTIMPLEMENTED if the given QUIC version is not supported
+ * \retval ISC_R_TLSERROR on internal TLS failure
+ * \retval ISC_R_NOMEMORY on allocation failure
+ * \retval ISC_R_FAILURE on unknown failure
+ */
+
+ISC_REFCOUNT_DECL(isc_quic_conn);
diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h
index 9bcd44f8dd..fcbe1e4092 100644
--- a/lib/isc/include/isc/types.h
+++ b/lib/isc/include/isc/types.h
@@ -79,6 +79,12 @@ typedef struct isc_timer isc_timer_t; /*%< Timer */
typedef struct isc_work isc_work_t; /*%< Work offloaded to an
* external thread */
+#ifdef HAVE_LIBNGTCP2
+typedef struct isc_quic_conn isc_quic_conn_t;
+typedef struct isc_quic_conn_callbacks isc_quic_conn_callbacks_t;
+typedef struct isc_quic_conn_options isc_quic_conn_options_t;
+#endif /* HAVE_LIBNGTCP2 */
+
#if HAVE_LIBNGHTTP2
typedef struct isc_nm_http_endpoints isc_nm_http_endpoints_t;
/*%< HTTP endpoints set */
diff --git a/lib/isc/quic/connection.c b/lib/isc/quic/connection.c
new file mode 100644
index 0000000000..8dd4e9de95
--- /dev/null
+++ b/lib/isc/quic/connection.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdint.h>
+
+#include <ngtcp2/ngtcp2.h>
+
+#include <isc/attributes.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#include "quic_p.h" /* IWYU pragma: keep */
+
+#define VALID_CONNECTION(c) ISC_MAGIC_VALID(c, conn_magic)
+
+constexpr uint32_t conn_magic = ISC_MAGIC('Q', 'U', 'I', 'c');
+
+static void
+destroy(isc_quic_conn_t *conn) {
+ isc_mem_t *mctx = conn->mem.user_data;
+
+ isc_quic_router_unref(conn->router);
+
+ isc_mem_put(mctx, conn, sizeof(*conn));
+ isc_mem_unref(mctx);
+}
+
+ISC_REFCOUNT_IMPL(isc_quic_conn, destroy);
+
+isc_result_t
+isc_quic_conn_client_create(
+ isc_mem_t *mctx, isc_quic_router_t *router,
+ const isc_quic_conn_callbacks_t *callbacks, void *callback_arg,
+ const isc_quic_conn_options_t *options ISC_ATTR_UNUSED,
+ const char *sni ISC_ATTR_UNUSED,
+ const isc_sockaddr_t *local ISC_ATTR_UNUSED,
+ const isc_sockaddr_t *peer ISC_ATTR_UNUSED, isc_quic_conn_t **connp) {
+ isc_quic_conn_t *conn;
+
+ REQUIRE(connp != NULL && *connp == NULL);
+
+ conn = isc_mem_get(mctx, sizeof(*conn));
+ *conn = (isc_quic_conn_t){
+ .magic = conn_magic,
+ .references = ISC_REFCOUNT_INITIALIZER(1),
+ .router = isc_quic_router_ref(router),
+ .cb = callbacks,
+ .cbarg = callback_arg,
+ .mem = { .user_data = isc_mem_ref(mctx) },
+ };
+
+ *connp = conn;
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t
+isc_quic_conn_server_create(
+ isc_mem_t *mctx, isc_quic_router_t *router,
+ const isc_quic_conn_callbacks_t *callbacks, void *callback_arg,
+ const isc_quic_conn_options_t *options ISC_ATTR_UNUSED,
+ isc_constregion_t initial_dcid ISC_ATTR_UNUSED,
+ isc_constregion_t initial_scid ISC_ATTR_UNUSED,
+ const isc_sockaddr_t *local ISC_ATTR_UNUSED,
+ const isc_sockaddr_t *peer ISC_ATTR_UNUSED, isc_quic_conn_t **connp) {
+ isc_quic_conn_t *conn;
+
+ REQUIRE(connp != NULL && *connp == NULL);
+
+ conn = isc_mem_get(mctx, sizeof(*conn));
+ *conn = (isc_quic_conn_t){
+ .magic = conn_magic,
+ .references = ISC_REFCOUNT_INITIALIZER(1),
+ .router = isc_quic_router_ref(router),
+ .cb = callbacks,
+ .cbarg = callback_arg,
+ .mem = { .user_data = isc_mem_ref(mctx) },
+ };
+
+ *connp = conn;
+
+ return ISC_R_SUCCESS;
+}
diff --git a/lib/isc/quic/meson.build b/lib/isc/quic/meson.build
index 18a216ae73..2223bd501f 100644
--- a/lib/isc/quic/meson.build
+++ b/lib/isc/quic/meson.build
@@ -12,6 +12,7 @@
isc_srcset.add(
ngtcp2_dep,
files(
+ 'connection.c',
'router.c',
),
)
diff --git a/lib/isc/quic/quic_p.h b/lib/isc/quic/quic_p.h
new file mode 100644
index 0000000000..4f16c5480a
--- /dev/null
+++ b/lib/isc/quic/quic_p.h
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <ngtcp2/ngtcp2.h>
+
+#include <isc/quic.h>
+#include <isc/types.h>
+
+struct isc_quic_conn {
+ uint32_t magic;
+ isc_refcount_t references;
+ isc_quic_router_t *router;
+
+ const isc_quic_conn_callbacks_t *cb;
+ void *cbarg;
+
+ /* isc_mem_t resides inside `mem.user_data` */
+ ngtcp2_mem mem;
+};
diff --git a/lib/isc/quic/router.c b/lib/isc/quic/router.c
index 4858d6570c..e694a91a9b 100644
--- a/lib/isc/quic/router.c
+++ b/lib/isc/quic/router.c
@@ -31,8 +31,7 @@ struct cid_entry {
struct cds_lfht_node node;
struct rcu_head rcu_head;
isc_mem_t *mctx;
- isc_quic_conn_unref_t unref;
- void *value;
+ isc_quic_conn_t *value;
isc_tid_t tid;
size_t length;
uint8_t data[] ISC_ATTR_COUNTED_BY(length);
@@ -42,9 +41,8 @@ struct reset_entry_t {
struct cds_lfht_node node;
struct rcu_head rcu_head;
isc_mem_t *mctx;
- isc_quic_conn_unref_t unref;
isc_tid_t tid;
- void *value;
+ isc_quic_conn_t *value;
uint8_t token[ISC_QUIC_STATELESS_TOKEN_LENGTH];
};
@@ -53,8 +51,6 @@ struct isc_quic_router {
isc_refcount_t references;
isc_mem_t *mctx;
size_t cidlen;
- isc_quic_conn_ref_t conn_ref;
- isc_quic_conn_unref_t conn_unref;
struct cds_lfht *cid_ht;
struct cds_lfht *reset_ht;
};
@@ -94,7 +90,7 @@ cid_match(struct cds_lfht_node *node, const void *key) {
static void
cid_free(struct rcu_head *rcu_head) {
cid_entry_t *entry = caa_container_of(rcu_head, cid_entry_t, rcu_head);
- entry->unref(entry->value);
+ isc_quic_conn_unref(entry->value);
isc_mem_putanddetach(&entry->mctx, entry,
STRUCT_FLEX_SIZE(entry, data, entry->length));
}
@@ -110,7 +106,7 @@ static void
reset_free(struct rcu_head *rcu_head) {
reset_entry_t *entry = caa_container_of(rcu_head, reset_entry_t,
rcu_head);
- entry->unref(entry->value);
+ isc_quic_conn_unref(entry->value);
isc_mem_putanddetach(&entry->mctx, entry, sizeof(*entry));
}
@@ -141,15 +137,12 @@ ISC_REFCOUNT_IMPL(isc_quic_router, destroy);
void
isc_quic_router_create(isc_mem_t *mctx, size_t cidlen,
- isc_quic_conn_ref_t conn_ref,
- isc_quic_conn_unref_t conn_unref,
isc_quic_router_t **routerp) {
isc_quic_router_t *router;
REQUIRE(routerp != NULL && *routerp == NULL);
REQUIRE(cidlen >= ISC_QUIC_CID_MIN_LENGTH &&
cidlen <= ISC_QUIC_CID_MAX_LENGTH);
- REQUIRE(conn_ref != NULL && conn_unref != NULL);
router = isc_mem_get(mctx, sizeof(*router));
*router = (isc_quic_router_t){
@@ -157,8 +150,6 @@ isc_quic_router_create(isc_mem_t *mctx, size_t cidlen,
.references = ISC_REFCOUNT_INITIALIZER(1),
.mctx = isc_mem_ref(mctx),
.cidlen = cidlen,
- .conn_ref = conn_ref,
- .conn_unref = conn_unref,
.cid_ht = cds_lfht_new(
ht_init_size, ht_min_size, 0,
CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL),
@@ -191,14 +182,13 @@ isc_quic_router_add_cid(isc_quic_router_t *router, isc_constregion_t cid,
*entry = (cid_entry_t){
.value = conn,
.mctx = isc_mem_ref(router->mctx),
- .unref = router->conn_unref,
.tid = tid,
.length = cid.length,
};
memmove(entry->data, cid.base, cid.length);
/* The routing table holds a reference for as long as it stores conn. */
- router->conn_ref(conn);
+ isc_quic_conn_ref(conn);
rcu_read_lock();
node = cds_lfht_add_unique(router->cid_ht, hash, cid_match, &cid,
@@ -206,7 +196,7 @@ isc_quic_router_add_cid(isc_quic_router_t *router, isc_constregion_t cid,
rcu_read_unlock();
if (node != &entry->node) {
- router->conn_unref(conn);
+ isc_quic_conn_unref(conn);
isc_mem_putanddetach(&entry->mctx, entry,
STRUCT_FLEX_SIZE(entry, data, cid.length));
return ISC_R_EXISTS;
@@ -217,7 +207,7 @@ isc_quic_router_add_cid(isc_quic_router_t *router, isc_constregion_t cid,
isc_result_t
isc_quic_router_get_cid(isc_quic_router_t *router, isc_constregion_t cid,
- isc_tid_t *tidp, void **connp) {
+ isc_tid_t *tidp, isc_quic_conn_t **connp) {
struct cds_lfht_node *node;
struct cds_lfht_iter iter;
isc_result_t result;
@@ -239,7 +229,7 @@ isc_quic_router_get_cid(isc_quic_router_t *router, isc_constregion_t cid,
} else {
result = ISC_R_SUCCESS;
if (connp != NULL) {
- router->conn_ref(entry->value);
+ isc_quic_conn_ref(entry->value);
*connp = entry->value;
}
SET_IF_NOT_NULL(tidp, entry->tid);
@@ -300,13 +290,12 @@ isc_quic_router_add_stateless_reset(
*entry = (reset_entry_t){
.value = conn,
.mctx = isc_mem_ref(router->mctx),
- .unref = router->conn_unref,
.tid = tid,
};
memmove(entry->token, token, ISC_QUIC_STATELESS_TOKEN_LENGTH);
/* The routing table holds a reference for as long as it stores conn. */
- router->conn_ref(conn);
+ isc_quic_conn_ref(conn);
rcu_read_lock();
node = cds_lfht_add_unique(router->reset_ht, hash, reset_match, token,
@@ -314,7 +303,7 @@ isc_quic_router_add_stateless_reset(
rcu_read_unlock();
if (node != &entry->node) {
- router->conn_unref(conn);
+ isc_quic_conn_unref(conn);
isc_mem_putanddetach(&entry->mctx, entry, sizeof(*entry));
return ISC_R_EXISTS;
}
@@ -326,7 +315,7 @@ isc_result_t
isc_quic_router_get_stateless_reset(
isc_quic_router_t *router,
const uint8_t token[const restrict ISC_QUIC_STATELESS_TOKEN_LENGTH],
- isc_tid_t *tidp, void **connp) {
+ isc_tid_t *tidp, isc_quic_conn_t **connp) {
struct cds_lfht_node *node;
struct cds_lfht_iter iter;
reset_entry_t *entry;
@@ -348,7 +337,7 @@ isc_quic_router_get_stateless_reset(
result = ISC_R_SUCCESS;
SET_IF_NOT_NULL(tidp, entry->tid);
if (connp != NULL) {
- router->conn_ref(entry->value);
+ isc_quic_conn_ref(entry->value);
*connp = entry->value;
}
}
@@ -396,7 +385,7 @@ isc_quic_router_handle_packet(isc_quic_router_t *router,
isc_quic_version_t *versionp,
isc_constregion_t *dcidp,
isc_constregion_t *scidp, isc_tid_t *tidp,
- void **connp) {
+ isc_quic_conn_t **connp) {
isc_constregion_t dcid, scid;
ngtcp2_version_cid version;
const uint8_t *token;
diff --git a/tests/isc/quic_test.c b/tests/isc/quic_test.c
index c6791eff88..79304231f6 100644
--- a/tests/isc/quic_test.c
+++ b/tests/isc/quic_test.c
@@ -32,25 +32,6 @@
constexpr isc_tid_t connection_tid = 3;
-/*
- * The tests use a sentinel pointer as the "connection"; these callbacks let
- * them assert that the router balances every reference it takes and hands out.
- */
-static atomic_int conn_refs = 0;
-
-static void
-test_conn_ref(void *conn) {
- (void)conn;
- (void)atomic_fetch_add(&conn_refs, 1);
-}
-
-static void
-test_conn_unref(void *conn) {
- /* May run on an RCU worker thread, hence the atomic counter. */
- (void)conn;
- (void)atomic_fetch_sub(&conn_refs, 1);
-}
-
constexpr uint8_t client_dcid[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
};
@@ -160,204 +141,233 @@ constexpr uint8_t short_header_packet[] = {
ISC_RUN_TEST_IMPL(isc_quic_router_cid) {
isc_quic_router_t *router = NULL;
+ isc_quic_conn_t *conn, *found;
isc_constregion_t cid;
isc_result_t result;
isc_tid_t tid = ISC_TID_UNKNOWN;
- void *value = NULL;
- isc_quic_router_create(isc_g_mctx, sizeof(client_dcid), test_conn_ref,
- test_conn_unref, &router);
+ isc_quic_conn_options_t opts = {};
+
+ isc_quic_router_create(isc_g_mctx, sizeof(client_dcid), &router);
+
+ conn = NULL;
+ result = isc_quic_conn_client_create(isc_g_mctx, router, NULL, NULL,
+ &opts, NULL, NULL, NULL, &conn);
+ assert_int_equal(result, ISC_R_SUCCESS);
cid = (isc_constregion_t){ sizeof(client_dcid), client_dcid };
- result = isc_quic_router_add_cid(router, cid, connection_tid, router);
+ result = isc_quic_router_add_cid(router, cid, connection_tid, conn);
assert_int_equal(result, ISC_R_SUCCESS);
cid = (isc_constregion_t){ sizeof(client_dcid), client_dcid };
- result = isc_quic_router_add_cid(router, cid, connection_tid, router);
+ result = isc_quic_router_add_cid(router, cid, connection_tid, conn);
assert_int_equal(result, ISC_R_EXISTS);
+ found = NULL;
cid = (isc_constregion_t){ sizeof(client_dcid), client_dcid };
- result = isc_quic_router_get_cid(router, cid, &tid, &value);
+ result = isc_quic_router_get_cid(router, cid, &tid, &found);
assert_int_equal(result, ISC_R_SUCCESS);
- assert_ptr_equal(value, router);
+ assert_ptr_equal(found, conn);
assert_int_equal(tid, connection_tid);
- test_conn_unref(value);
+ isc_quic_conn_unref(found);
- value = NULL;
+ found = NULL;
cid = (isc_constregion_t){ sizeof(unknown_cid), unknown_cid };
- result = isc_quic_router_get_cid(router, cid, NULL, &value);
+ result = isc_quic_router_get_cid(router, cid, NULL, &found);
assert_int_equal(result, ISC_R_NOTFOUND);
cid = (isc_constregion_t){ sizeof(unknown_cid), unknown_cid };
- result = isc_quic_router_add_cid(router, cid, connection_tid, router);
+ result = isc_quic_router_add_cid(router, cid, connection_tid, conn);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_quic_router_del_cid(router, cid);
assert_int_equal(result, ISC_R_SUCCESS);
- isc_quic_router_detach(&router);
+ cid = (isc_constregion_t){ sizeof(client_dcid), client_dcid };
+ result = isc_quic_router_del_cid(router, cid);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_quic_router_del_cid(router, cid);
+ assert_int_equal(result, ISC_R_NOTFOUND);
- /* Flush deferred frees, then check the router balanced every ref. */
- rcu_barrier();
- assert_int_equal(atomic_load(&conn_refs), 0);
+ isc_quic_router_detach(&router);
+ isc_quic_conn_detach(&conn);
}
ISC_RUN_TEST_IMPL(isc_quic_router_stateless_reset) {
uint8_t token[ISC_QUIC_STATELESS_TOKEN_LENGTH];
isc_quic_router_t *router = NULL;
+ isc_quic_conn_t *conn, *found;
isc_result_t result;
isc_tid_t tid = ISC_TID_UNKNOWN;
- void *value = NULL;
- isc_quic_router_create(isc_g_mctx, sizeof(client_dcid), test_conn_ref,
- test_conn_unref, &router);
+ isc_quic_conn_options_t opts = {};
+
+ isc_quic_router_create(isc_g_mctx, sizeof(client_dcid), &router);
+
+ conn = NULL;
+ result = isc_quic_conn_client_create(isc_g_mctx, router, NULL, NULL,
+ &opts, NULL, NULL, NULL, &conn);
+ assert_int_equal(result, ISC_R_SUCCESS);
isc_random_buf(token, sizeof(token));
+ found = NULL;
result = isc_quic_router_get_stateless_reset(router, token, NULL,
- &value);
+ &found);
assert_int_equal(result, ISC_R_NOTFOUND);
result = isc_quic_router_add_stateless_reset(router, token,
- connection_tid, router);
+ connection_tid, conn);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_quic_router_add_stateless_reset(router, token,
- connection_tid, router);
+ connection_tid, conn);
assert_int_equal(result, ISC_R_EXISTS);
+ found = NULL;
result = isc_quic_router_get_stateless_reset(router, token, &tid,
- &value);
+ &found);
assert_int_equal(result, ISC_R_SUCCESS);
- assert_ptr_equal(value, router);
+ assert_ptr_equal(found, conn);
assert_int_equal(tid, connection_tid);
- test_conn_unref(value);
+ isc_quic_conn_unref(found);
result = isc_quic_router_del_stateless_reset(router, token);
assert_int_equal(result, ISC_R_SUCCESS);
+ found = NULL;
result = isc_quic_router_get_stateless_reset(router, token, NULL,
- &value);
+ &found);
assert_int_equal(result, ISC_R_NOTFOUND);
result = isc_quic_router_del_stateless_reset(router, token);
assert_int_equal(result, ISC_R_NOTFOUND);
isc_quic_router_detach(&router);
-
- /* Flush deferred frees, then check the router balanced every ref. */
- rcu_barrier();
- assert_int_equal(atomic_load(&conn_refs), 0);
+ isc_quic_conn_detach(&conn);
}
ISC_RUN_TEST_IMPL(isc_quic_router_packet) {
isc_quic_router_t *router = NULL;
+ isc_quic_conn_t *conn, *found;
isc_quic_version_t version;
isc_constregion_t dcid, scid;
isc_result_t result;
isc_tid_t tid = ISC_TID_UNKNOWN;
- void *value = NULL;
- isc_quic_router_create(isc_g_mctx, sizeof(client_dcid), test_conn_ref,
- test_conn_unref, &router);
+ isc_quic_conn_options_t opts = {};
+
+ isc_quic_router_create(isc_g_mctx, sizeof(client_dcid), &router);
+
+ conn = NULL;
+ result = isc_quic_conn_client_create(isc_g_mctx, router, NULL, NULL,
+ &opts, NULL, NULL, NULL, &conn);
+ assert_int_equal(result, ISC_R_SUCCESS);
/* Initial CRYPTO frames MUST be 1200 bytes */
+ found = NULL;
result = isc_quic_router_handle_packet(
router, (isc_constregion_t){ 1199, initial_frame_v1 }, &version,
- &dcid, &scid, NULL, &value);
+ &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_IGNORE);
assert_int_equal(version, ISC_QUIC_VERSION_V1);
+ assert_ptr_equal(found, NULL);
/* Use reserved version 0x0A0A0A0A */
result = isc_quic_router_handle_packet(
router,
(isc_constregion_t){ 1200, initial_frame_reserved_version },
- &version, &dcid, &scid, NULL, &value);
+ &version, &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_NOTIMPLEMENTED);
assert_int_equal(version, ISC_QUIC_VERSION_UNKNOWN);
+ assert_ptr_equal(found, NULL);
result = isc_quic_router_handle_packet(
router, (isc_constregion_t){ 1200, initial_frame_v1 }, &version,
- &dcid, &scid, NULL, &value);
+ &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_NOTFOUND);
assert_int_equal(version, ISC_QUIC_VERSION_V1);
assert_int_equal(dcid.length, sizeof(client_dcid));
assert_memory_equal(dcid.base, client_dcid, dcid.length);
+ assert_ptr_equal(found, NULL);
/* A 1-RTT packet for an unknown connection: caller MAY send a reset */
result = isc_quic_router_handle_packet(
router,
(isc_constregion_t){ sizeof(short_header_packet),
short_header_packet },
- NULL, &dcid, &scid, NULL, &value);
+ NULL, &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_UNEXPECTED);
- assert_null(value);
+ assert_null(found);
assert_int_equal(dcid.length, sizeof(client_dcid));
assert_memory_equal(dcid.base, client_dcid, dcid.length);
- result = isc_quic_router_add_cid(router, dcid, connection_tid, router);
+ result = isc_quic_router_add_cid(router, dcid, connection_tid, conn);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_quic_router_handle_packet(
router, (isc_constregion_t){ 1200, initial_frame_v1 }, &version,
- &dcid, &scid, NULL, &value);
+ &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(version, ISC_QUIC_VERSION_V1);
- assert_ptr_equal(value, router);
- test_conn_unref(value);
+ assert_ptr_equal(found, conn);
+ isc_quic_conn_unref(found);
- value = NULL;
+ found = NULL;
result = isc_quic_router_handle_packet(
- router, (isc_constregion_t){ 1200, initial_frame_v1 }, &version,
- &dcid, &scid, NULL, &value);
+ router, (isc_constregion_t){ 500, initial_frame_v1 }, &version,
+ &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_SUCCESS);
- assert_ptr_equal(value, router);
- test_conn_unref(value);
+ assert_ptr_equal(found, conn);
+ isc_quic_conn_unref(found);
- value = NULL;
+ found = NULL;
result = isc_quic_router_handle_packet(
router,
(isc_constregion_t){ sizeof(short_header_packet),
short_header_packet },
- NULL, &dcid, &scid, &tid, &value);
+ NULL, &dcid, &scid, &tid, &found);
assert_int_equal(result, ISC_R_SUCCESS);
- assert_ptr_equal(value, router);
+ assert_ptr_equal(found, conn);
assert_int_equal(tid, connection_tid);
assert_int_equal(dcid.length, sizeof(client_dcid));
assert_memory_equal(dcid.base, client_dcid, dcid.length);
- test_conn_unref(value);
+ isc_quic_conn_unref(found);
result = isc_quic_router_del_cid(router, dcid);
assert_int_equal(result, ISC_R_SUCCESS);
- value = NULL;
+ found = NULL;
result = isc_quic_router_handle_packet(
router, (isc_constregion_t){ 1200, initial_frame_v1 }, &version,
- &dcid, &scid, NULL, &value);
+ &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_NOTFOUND);
result = isc_quic_router_handle_packet(
router,
(isc_constregion_t){ sizeof(short_header_packet),
short_header_packet },
- NULL, &dcid, &scid, NULL, &value);
+ NULL, &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_UNEXPECTED);
- assert_null(value);
+ assert_null(found);
result = isc_quic_router_add_stateless_reset(
- router, stateless_reset_token, connection_tid, router);
+ router, stateless_reset_token, connection_tid, conn);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_quic_router_handle_packet(
router,
(isc_constregion_t){ sizeof(stateless_reset_packet),
stateless_reset_packet },
- NULL, &dcid, &scid, NULL, &value);
+ NULL, &dcid, &scid, NULL, &found);
assert_int_equal(result, ISC_R_CONNECTIONRESET);
- test_conn_unref(value);
+ isc_quic_conn_unref(found);
- isc_quic_router_detach(&router);
+ result = isc_quic_router_del_stateless_reset(router,
+ stateless_reset_token);
+ assert_int_equal(result, ISC_R_SUCCESS);
- /* Flush deferred frees, then check the router balanced every ref. */
- rcu_barrier();
- assert_int_equal(atomic_load(&conn_refs), 0);
+ isc_quic_conn_detach(&conn);
+ isc_quic_router_detach(&router);
}
ISC_TEST_LIST_START