24228 lines
834 KiB
Diff
24228 lines
834 KiB
Diff
From e8384b6daea3b8091ad1bcfce84efc9e2c6a746d Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Thu, 22 Jan 2026 14:27:09 +0100
|
|
Subject: [PATCH 01/66] s3:libads: Allocate cli_credentials on a stackframe
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This fixes:
|
|
ERROR: talloc_free with references at ../../source3/libads/ldap_utils.c:158
|
|
|
|
What happens:
|
|
|
|
* `struct cli_credentials *creds` is allocated on `ads` talloc context
|
|
* gensec_set_credentials() creates a talloc_reference to `creds`
|
|
* TALLOC_FREE(creds) sees two parents and complains
|
|
|
|
All other code is using temporary talloc_stackframe() for `creds`.
|
|
Do it here as well.
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Stefan Metzmacher <metze@samba.org>
|
|
|
|
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
|
|
Autobuild-Date(master): Fri Jan 23 11:20:28 UTC 2026 on atb-devel-224
|
|
---
|
|
source3/libads/ldap_utils.c | 9 ++++++---
|
|
1 file changed, 6 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c
|
|
index 9d6d962a2bc..d01afa69697 100644
|
|
--- a/source3/libads/ldap_utils.c
|
|
+++ b/source3/libads/ldap_utils.c
|
|
@@ -99,6 +99,7 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind
|
|
struct cli_credentials *creds = NULL;
|
|
char *cred_name = NULL;
|
|
NTSTATUS ntstatus;
|
|
+ TALLOC_CTX *frame = talloc_stackframe();
|
|
|
|
if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) &&
|
|
ads->config.ldap_page_size >= (lp_ldap_page_size() / 4) &&
|
|
@@ -119,18 +120,20 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind
|
|
DBG_NOTICE("Search for %s in <%s> failed: %s\n",
|
|
expr, bp, ads_errstr(status));
|
|
SAFE_FREE(bp);
|
|
+ TALLOC_FREE(frame);
|
|
return status;
|
|
}
|
|
|
|
ntstatus = ads->auth.reconnect_state->fn(ads,
|
|
ads->auth.reconnect_state->private_data,
|
|
- ads, &creds);
|
|
+ frame, &creds);
|
|
if (!NT_STATUS_IS_OK(ntstatus)) {
|
|
DBG_WARNING("Failed to get creds for realm(%s): %s\n",
|
|
ads->server.realm, nt_errstr(ntstatus));
|
|
DBG_WARNING("Search for %s in <%s> failed: %s\n",
|
|
expr, bp, ads_errstr(status));
|
|
SAFE_FREE(bp);
|
|
+ TALLOC_FREE(frame);
|
|
return status;
|
|
}
|
|
|
|
@@ -151,11 +154,11 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind
|
|
* callers depend on it being around.
|
|
*/
|
|
ads_disconnect(ads);
|
|
- TALLOC_FREE(creds);
|
|
+ TALLOC_FREE(frame);
|
|
SAFE_FREE(bp);
|
|
return status;
|
|
}
|
|
- TALLOC_FREE(creds);
|
|
+ TALLOC_FREE(frame);
|
|
|
|
*res = NULL;
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 7af95c7cb142aeb5f422a69d3b7a0ea3c0d2c2c2 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Mon, 26 Jan 2026 13:36:02 +0100
|
|
Subject: [PATCH 02/66] s3:rpc_client: Fix memory leak opening local named pipe
|
|
|
|
If no local server name was passed to rpc_pipe_open_local_np() then
|
|
get_myname() was called with NULL talloc context instead of the
|
|
current stackframe.
|
|
|
|
This was causing an increase of memory usage on busy servers with long-living
|
|
rpcd_* workers.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15979
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Noel Power <noel.power@suse.com>
|
|
Reviewed-by: Volker Lendecke <vl@samba.org>
|
|
|
|
Autobuild-User(master): Volker Lendecke <vl@samba.org>
|
|
Autobuild-Date(master): Tue Jan 27 10:13:40 UTC 2026 on atb-devel-224
|
|
|
|
(cherry picked from commit 24dc455362fb49ef81c99d95880e106a234ce29a)
|
|
---
|
|
source3/rpc_client/cli_pipe.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
|
|
index e3f48526492..c61b8eb16cf 100644
|
|
--- a/source3/rpc_client/cli_pipe.c
|
|
+++ b/source3/rpc_client/cli_pipe.c
|
|
@@ -3625,7 +3625,7 @@ NTSTATUS rpc_pipe_open_local_np(
|
|
}
|
|
|
|
if (local_server_name == NULL) {
|
|
- local_server_name = get_myname(result);
|
|
+ local_server_name = get_myname(frame);
|
|
}
|
|
|
|
if (local_server_addr != NULL) {
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From ab1287f78bd9d2397c8eb26fbedafa028e2aaa16 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
|
Date: Tue, 2 Dec 2025 17:17:33 +0100
|
|
Subject: [PATCH 03/66] s3-selftest: mention in-memory ccache usage when
|
|
nothing is provided
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15840
|
|
|
|
Guenther
|
|
|
|
Signed-off-by: Guenther Deschner <gd@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
---
|
|
source3/script/tests/test_net_ads_kerberos.sh | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/source3/script/tests/test_net_ads_kerberos.sh b/source3/script/tests/test_net_ads_kerberos.sh
|
|
index 8a3c9ef2bc7..92d3996d078 100755
|
|
--- a/source3/script/tests/test_net_ads_kerberos.sh
|
|
+++ b/source3/script/tests/test_net_ads_kerberos.sh
|
|
@@ -30,6 +30,7 @@ KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
|
|
## Test "net ads kerberos kinit" variants
|
|
#################################################
|
|
|
|
+#simply uses in memory ccache
|
|
testit "net_ads_kerberos_kinit" \
|
|
"$VALGRIND" "$BINDIR"/net ads kerberos kinit \
|
|
-U"$USERNAME"%"$PASSWORD" "$ADDARGS" \
|
|
@@ -50,6 +51,7 @@ rm -f "$KRB5CCNAME_PATH"
|
|
# --use-krb5-ccache=${KRB5CCNAME} \
|
|
# || failed=$((failed + 1))
|
|
|
|
+#simply uses in memory ccache
|
|
testit "net_ads_kerberos_kinit (-P)" \
|
|
"$VALGRIND" "$BINDIR"/net ads kerberos kinit \
|
|
-P "$ADDARGS" \
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 0aa0d39e9a5deb77114f40930b599f11fd7cf3b6 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
|
Date: Tue, 2 Dec 2025 17:18:41 +0100
|
|
Subject: [PATCH 04/66] s3-selftest: verify KRB5CCNAME presence after kinit
|
|
using klist
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15840
|
|
|
|
Guenther
|
|
|
|
Signed-off-by: Guenther Deschner <gd@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
---
|
|
source3/script/tests/test_net_ads_kerberos.sh | 12 ++++++++++++
|
|
1 file changed, 12 insertions(+)
|
|
|
|
diff --git a/source3/script/tests/test_net_ads_kerberos.sh b/source3/script/tests/test_net_ads_kerberos.sh
|
|
index 92d3996d078..c53520cf733 100755
|
|
--- a/source3/script/tests/test_net_ads_kerberos.sh
|
|
+++ b/source3/script/tests/test_net_ads_kerberos.sh
|
|
@@ -14,6 +14,12 @@ PREFIX="$4"
|
|
shift 4
|
|
ADDARGS="$*"
|
|
|
|
+if [ -x $(which klist) ]; then
|
|
+ KLIST=$(which klist);
|
|
+else
|
|
+ KLIST="test -e";
|
|
+fi
|
|
+
|
|
incdir=$(dirname "$0")/../../../testprogs/blackbox
|
|
. "$incdir"/subunit.sh
|
|
|
|
@@ -41,6 +47,9 @@ testit "net_ads_kerberos_kinit (KRB5CCNAME env set)" \
|
|
"$VALGRIND" "$BINDIR"/net ads kerberos kinit \
|
|
-U"$USERNAME"%"$PASSWORD" "$ADDARGS" \
|
|
|| failed=$((failed + 1))
|
|
+testit "klist env $KRB5CCNAME" \
|
|
+ "$KLIST" "$KRB5CCNAME" \
|
|
+ || failed=$((failed +1))
|
|
unset KRB5CCNAME
|
|
rm -f "$KRB5CCNAME_PATH"
|
|
|
|
@@ -62,6 +71,9 @@ testit "net_ads_kerberos_kinit (-P and KRB5CCNAME env set)" \
|
|
"$VALGRIND" "$BINDIR"/net ads kerberos kinit \
|
|
-P "$ADDARGS" \
|
|
|| failed=$((failed + 1))
|
|
+testit "klist env $KRB5CCNAME" \
|
|
+ "$KLIST" "$KRB5CCNAME" \
|
|
+ || failed=$((failed +1))
|
|
unset KRB5CCNAME
|
|
rm -f "$KRB5CCNAME_PATH"
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From b9c07d59c6a20931b80fa104629477ab8f78b4ad Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
|
Date: Tue, 2 Dec 2025 17:01:31 +0100
|
|
Subject: [PATCH 05/66] s3-selftest: Activate "net ads kerberos kinit" tests
|
|
with --use-krb5-ccache
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15840
|
|
|
|
Guenther
|
|
|
|
Signed-off-by: Guenther Deschner <gd@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
---
|
|
selftest/knownfail | 2 ++
|
|
source3/script/tests/test_net_ads_kerberos.sh | 30 +++++++++++--------
|
|
2 files changed, 20 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/selftest/knownfail b/selftest/knownfail
|
|
index ab2d79d7114..76f1dae605d 100644
|
|
--- a/selftest/knownfail
|
|
+++ b/selftest/knownfail
|
|
@@ -338,3 +338,5 @@
|
|
|
|
# We currently don't send referrals for LDAP modify of non-replicated attrs
|
|
^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.*
|
|
+
|
|
+^samba3.blackbox.net_ads_kerberos.*.klist.*--use-krb5-ccache.*
|
|
diff --git a/source3/script/tests/test_net_ads_kerberos.sh b/source3/script/tests/test_net_ads_kerberos.sh
|
|
index c53520cf733..b7933bab6a6 100755
|
|
--- a/source3/script/tests/test_net_ads_kerberos.sh
|
|
+++ b/source3/script/tests/test_net_ads_kerberos.sh
|
|
@@ -53,12 +53,15 @@ testit "klist env $KRB5CCNAME" \
|
|
unset KRB5CCNAME
|
|
rm -f "$KRB5CCNAME_PATH"
|
|
|
|
-# --use-krb5-ccache is not working
|
|
-#testit "net_ads_kerberos_kinit (with --use-krb5-ccache)" \
|
|
-# $VALGRIND $BINDIR/net ads kerberos kinit \
|
|
-# -U$USERNAME%$PASSWORD $ADDARGS \
|
|
-# --use-krb5-ccache=${KRB5CCNAME} \
|
|
-# || failed=$((failed + 1))
|
|
+testit "net_ads_kerberos_kinit (with --use-krb5-ccache)" \
|
|
+ "$VALGRIND" "$BINDIR"/net ads kerberos kinit \
|
|
+ -U"$USERNAME"%"$PASSWORD" "$ADDARGS" \
|
|
+ --use-krb5-ccache="${KRB5CCNAME_PATH}" \
|
|
+ || failed=$((failed + 1))
|
|
+testit "klist --use-krb5-ccache $KRB5CCNAME_PATH" \
|
|
+ "$KLIST" "$KRB5CCNAME_PATH" \
|
|
+ || failed=$((failed +1))
|
|
+rm -f "$KRB5CCNAME_PATH"
|
|
|
|
#simply uses in memory ccache
|
|
testit "net_ads_kerberos_kinit (-P)" \
|
|
@@ -77,12 +80,15 @@ testit "klist env $KRB5CCNAME" \
|
|
unset KRB5CCNAME
|
|
rm -f "$KRB5CCNAME_PATH"
|
|
|
|
-# --use-krb5-ccache is not working
|
|
-#testit "net_ads_kerberos_kinit (-P with --use-krb5-ccache)" \
|
|
-# $VALGRIND $BINDIR/net ads kerberos kinit \
|
|
-# -P $ADDARGS \
|
|
-# --use-krb5-ccache=${KRB5CCNAME} \
|
|
-# || failed=$((failed + 1))
|
|
+testit "net_ads_kerberos_kinit (-P with --use-krb5-ccache)" \
|
|
+ "$VALGRIND" "$BINDIR"/net ads kerberos kinit \
|
|
+ -P "$ADDARGS" \
|
|
+ --use-krb5-ccache="${KRB5CCNAME_PATH}" \
|
|
+ || failed=$((failed + 1))
|
|
+testit "klist --use-krb5-ccache $KRB5CCNAME_PATH" \
|
|
+ "$KLIST" "$KRB5CCNAME_PATH" \
|
|
+ || failed=$((failed +1))
|
|
+rm -f "$KRB5CCNAME_PATH"
|
|
|
|
|
|
#################################################
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From c82b7636b633575621e8e5964a93332956c238ff Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
|
Date: Tue, 2 Dec 2025 16:56:44 +0100
|
|
Subject: [PATCH 06/66] s3-net: properly setup krb5 ccache name via
|
|
--use-krb5-ccache
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15840
|
|
|
|
Guenther
|
|
|
|
Signed-off-by: Guenther Deschner <gd@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
---
|
|
selftest/knownfail | 2 --
|
|
source3/utils/net.c | 19 ++++++++++++-------
|
|
source3/utils/net_ads.c | 4 ++++
|
|
3 files changed, 16 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/selftest/knownfail b/selftest/knownfail
|
|
index 76f1dae605d..ab2d79d7114 100644
|
|
--- a/selftest/knownfail
|
|
+++ b/selftest/knownfail
|
|
@@ -338,5 +338,3 @@
|
|
|
|
# We currently don't send referrals for LDAP modify of non-replicated attrs
|
|
^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.*
|
|
-
|
|
-^samba3.blackbox.net_ads_kerberos.*.klist.*--use-krb5-ccache.*
|
|
diff --git a/source3/utils/net.c b/source3/utils/net.c
|
|
index ecabd980d0c..271c96cf804 100644
|
|
--- a/source3/utils/net.c
|
|
+++ b/source3/utils/net.c
|
|
@@ -1396,7 +1396,7 @@ static struct functable net_func[] = {
|
|
cli_credentials_get_principal_obtained(c->creds);
|
|
enum credentials_obtained password_obtained =
|
|
cli_credentials_get_password_obtained(c->creds);
|
|
- char *krb5ccname = NULL;
|
|
+ const char *krb5ccname = NULL;
|
|
|
|
if (principal_obtained == CRED_SPECIFIED) {
|
|
c->explicit_credentials = true;
|
|
@@ -1415,15 +1415,20 @@ static struct functable net_func[] = {
|
|
}
|
|
|
|
/* cli_credentials_get_ccache_name_obtained() would not work
|
|
- * here, we also cannot get the content of --use-krb5-ccache= so
|
|
- * for now at least honour the KRB5CCNAME environment variable
|
|
- * to get 'net ads kerberos' functions to work at all - gd */
|
|
-
|
|
- krb5ccname = getenv("KRB5CCNAME");
|
|
- if (krb5ccname == NULL) {
|
|
+ * here but we can now access the content of the
|
|
+ * --use-krb5-ccache option via cli credentials. Fallback to
|
|
+ * KRB5CCNAME environment variable to get 'net ads kerberos'
|
|
+ * functions to work at all - gd */
|
|
+
|
|
+ krb5ccname = cli_credentials_get_out_ccache_name(c->creds);
|
|
+ if (krb5ccname == NULL || krb5ccname[0] == '\0') {
|
|
+ krb5ccname = getenv("KRB5CCNAME");
|
|
+ }
|
|
+ if (krb5ccname == NULL || krb5ccname[0] == '\0') {
|
|
krb5ccname = talloc_strdup(c, "MEMORY:net");
|
|
}
|
|
if (krb5ccname == NULL) {
|
|
+ DBG_ERR("Not able to setup krb5 ccache");
|
|
exit(1);
|
|
}
|
|
c->opt_krb5_ccache = krb5ccname;
|
|
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
|
|
index d49b7537e71..5c57a0b290e 100644
|
|
--- a/source3/utils/net_ads.c
|
|
+++ b/source3/utils/net_ads.c
|
|
@@ -3245,7 +3245,11 @@ static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **
|
|
if (ret) {
|
|
d_printf(_("failed to kinit password: %s\n"),
|
|
nt_errstr(status));
|
|
+ return ret;
|
|
}
|
|
+
|
|
+ d_printf("Stored Kerberos TGT in: %s\n", c->opt_krb5_ccache);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 4f5ffea631d805564f7e92cc5f0f2f7ad55ba493 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
|
Date: Sat, 13 Dec 2025 13:49:37 +0100
|
|
Subject: [PATCH 07/66] doc-xml: Document "net ads kerberos" commands
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15840
|
|
|
|
Guenther
|
|
|
|
Signed-off-by: Guenther Deschner <gd@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
|
|
Autobuild-User(master): Günther Deschner <gd@samba.org>
|
|
Autobuild-Date(master): Mon Jan 5 15:49:04 UTC 2026 on atb-devel-224
|
|
---
|
|
docs-xml/manpages/net.8.xml | 139 ++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 139 insertions(+)
|
|
|
|
diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml
|
|
index d9293d0bb34..737415b3722 100644
|
|
--- a/docs-xml/manpages/net.8.xml
|
|
+++ b/docs-xml/manpages/net.8.xml
|
|
@@ -1810,7 +1810,146 @@ the following entry types;
|
|
|
|
</refsect2>
|
|
|
|
+<refsect2>
|
|
+ <title>ADS KERBEROS</title>
|
|
+
|
|
+<para>
|
|
+ Issue Kerberos operations against an Active Directory KDC.
|
|
+</para>
|
|
+
|
|
+</refsect2>
|
|
+
|
|
+<refsect2>
|
|
+ <title>ADS KERBEROS KINIT</title>
|
|
+
|
|
+<para>
|
|
+ Issue a kinit request for a given user. When no other options are
|
|
+ defined the ticket granting ticket (TGT) will be stored in a memory cache.
|
|
+</para>
|
|
+
|
|
+<para>
|
|
+ To store the TGT in a different location either use the
|
|
+ <option>--krb5-ccache</option> option or set the
|
|
+ <replaceable>KRB5CCNAME</replaceable> environment variable.
|
|
+</para>
|
|
+
|
|
+<para>Example: <userinput>net ads kerberos kinit -P --krb5-ccache=/tmp/krb5cache</userinput></para>
|
|
+
|
|
+</refsect2>
|
|
+
|
|
+<refsect2>
|
|
+ <title>ADS KERBEROS RENEW</title>
|
|
+
|
|
+<para>
|
|
+ Renew an already acquired ticket granting ticket (TGT).
|
|
+</para>
|
|
+
|
|
+<para>Example: <userinput>net ads kerberos renew</userinput></para>
|
|
+
|
|
+</refsect2>
|
|
+
|
|
+<refsect2>
|
|
+ <title>ADS KERBEROS PAC</title>
|
|
+
|
|
+<para>
|
|
+ Request a Kerberos PAC while authenticating to an Active Directory KDC.
|
|
+</para>
|
|
+
|
|
+<para>
|
|
+ The following commands are provided:
|
|
+</para>
|
|
+
|
|
+<simplelist>
|
|
+<member>net ads kerberos pac dump - Dump a PAC to stdout.</member>
|
|
+<member>net ads kerneros pac save - Save a PAC to a file.</member>
|
|
+</simplelist>
|
|
+
|
|
+<para>
|
|
+ All commands allow to define an impersonation principal to do a Kerberos
|
|
+ Service for User (S4U2SELF) operation via
|
|
+ the <replaceable>impersonate=STRING</replaceable> option.
|
|
+ The impersonation principal can have multiple different formats:
|
|
+</para>
|
|
+
|
|
+<itemizedlist>
|
|
+ <listitem>
|
|
+ <para><replaceable>user@MY.REALM</replaceable></para>
|
|
+ <para>This is the default format.</para>
|
|
+ </listitem>
|
|
+ <listitem>
|
|
+ <para><replaceable>user@MY.REALM@MY.REALM</replaceable></para>
|
|
+ <para>The Kerberos Service for User (S4U2SELF) also supports
|
|
+ Enterprise Principals.</para>
|
|
+ </listitem>
|
|
+ <listitem>
|
|
+ <para><replaceable>user@UPN.SUFFIX@MY.REALM</replaceable></para>
|
|
+ <para>Enterprise Principal using a defined upn suffix.</para>
|
|
+ </listitem>
|
|
+ <listitem>
|
|
+ <para><replaceable>user@WORKGROUP@MY.REALM</replaceable></para>
|
|
+ <para>Enterprise Principal with netbios domain name.
|
|
+ This format is currently not supported by Samba AD.</para>
|
|
+ </listitem>
|
|
+</itemizedlist>
|
|
|
|
+<para>
|
|
+ By default net will request a service ticket for the local service
|
|
+ of the joined machine. A different service can be defined via
|
|
+ <replaceable>local_service=STRING</replaceable>.
|
|
+</para>
|
|
+
|
|
+</refsect2>
|
|
+<refsect2>
|
|
+ <title>ADS KERBEROS PAC DUMP [impersonate=string] [local_service=string] [pac_buffer_type=int]</title>
|
|
+
|
|
+<para>
|
|
+ Request a Kerberos PAC while authenticating to an Active Directory KDC.
|
|
+ The PAC will be printed on stdout.
|
|
+</para>
|
|
+
|
|
+<para>
|
|
+ When no specific pac_buffer is selected, all buffers will be printed.
|
|
+ It is possible to select a specific one via
|
|
+ <replaceable>pac_buffer_type=INT</replaceable> from this list:
|
|
+</para>
|
|
+
|
|
+<simplelist>
|
|
+<member>1 PAC_TYPE_LOGON_INFO</member>
|
|
+<member>2 PAC_TYPE_CREDENTIAL_INFO</member>
|
|
+<member>6 PAC_TYPE_SRV_CHECKSUM</member>
|
|
+<member>7 PAC_TYPE_KDC_CHECKSUM</member>
|
|
+<member>10 PAC_TYPE_LOGON_NAME</member>
|
|
+<member>11 PAC_TYPE_CONSTRAINED_DELEGATION</member>
|
|
+<member>12 PAC_TYPE_UPN_DNS_INFO</member>
|
|
+<member>13 PAC_TYPE_CLIENT_CLAIMS_INFO</member>
|
|
+<member>14 PAC_TYPE_DEVICE_INFO</member>
|
|
+<member>15 PAC_TYPE_DEVICE_CLAIMS_INFO</member>
|
|
+<member>16 PAC_TYPE_TICKET_CHECKSUM</member>
|
|
+<member>17 PAC_TYPE_ATTRIBUTES_INFO</member>
|
|
+<member>18 PAC_TYPE_REQUESTER_SID</member>
|
|
+<member>19 PAC_TYPE_FULL_CHECKSUM</member>
|
|
+</simplelist>
|
|
+
|
|
+<para>Example: <userinput>net ads kerberos pac dump -P impersonate=anyuser@MY.REALM.COM</userinput></para>
|
|
+
|
|
+</refsect2>
|
|
+
|
|
+<refsect2>
|
|
+ <title>ADS KERBEROS PAC SAVE [impersonate=string] [local_service=string] [filename=string]</title>
|
|
+
|
|
+<para>
|
|
+ Request a Kerberos PAC while authenticating to an Active Directory KDC.
|
|
+ The PAC will be saved in a file.
|
|
+</para>
|
|
+
|
|
+<para>
|
|
+ The filename to store the PAC can be set via the
|
|
+ <replaceable>filename=STRING</replaceable> option.
|
|
+</para>
|
|
+
|
|
+<para>Example: <userinput>net ads kerberos pac save -U user%password filename=/tmp/pacstore</userinput></para>
|
|
+
|
|
+</refsect2>
|
|
<refsect2>
|
|
<title>SAM CREATEBUILTINGROUP <NAME></title>
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From f634526bd95b8396ea7f5f1c8ed059eb01a5286b Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Tue, 3 Feb 2026 12:53:10 +0100
|
|
Subject: [PATCH 08/66] s3:utils: 'net ads kerberos kinit' should use also
|
|
default ccache name from krb5.conf
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This is re-introducing the behavior from samba-4.20 where both these
|
|
commands operated on the same ccache (default_ccache_name in
|
|
[libdefaults] section of krb5.conf)
|
|
|
|
'net ads kerberos kinit -P'
|
|
'klist'
|
|
|
|
With samba-4.21 it no longer works, 'net ads kerberos kinit -P'
|
|
fallbacks to 'MEMORY:net' (which is of a very limited use, ticket
|
|
cannot be used by other process) and klist finds no ticket.
|
|
|
|
The order is changed from:
|
|
|
|
--use-krb5-ccache
|
|
env "KRB5CCNAME"
|
|
"MEMORY:net"
|
|
|
|
to ("MEMORY:net" is removed):
|
|
|
|
--use-krb5-ccache
|
|
env "KRB5CCNAME"
|
|
default_ccache_name
|
|
|
|
'--use-krb5-ccache=MEMORY:net' can be used to validate the credentials.
|
|
|
|
Use smb_force_krb5_cc_default_name() instead of krb5_cc_default_name()
|
|
because of commit:
|
|
1ca6fb5 make sure krb5_cc_default[_name]() is no longer used directly
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15993
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
(cherry picked from commit 4cc6a13590434f6a3aa1add663728188970d727e)
|
|
---
|
|
source3/utils/net.c | 36 ++++++++++++++++++++++++++----------
|
|
1 file changed, 26 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/source3/utils/net.c b/source3/utils/net.c
|
|
index 271c96cf804..0ce03f8213d 100644
|
|
--- a/source3/utils/net.c
|
|
+++ b/source3/utils/net.c
|
|
@@ -54,6 +54,7 @@
|
|
#include "source3/utils/passwd_proto.h"
|
|
#include "auth/gensec/gensec.h"
|
|
#include "lib/param/param.h"
|
|
+#include "lib/krb5_wrap/krb5_samba.h"
|
|
|
|
#ifdef WITH_FAKE_KASERVER
|
|
#include "utils/net_afs.h"
|
|
@@ -1414,18 +1415,33 @@ static struct functable net_func[] = {
|
|
CRED_SPECIFIED);
|
|
}
|
|
|
|
- /* cli_credentials_get_ccache_name_obtained() would not work
|
|
- * here but we can now access the content of the
|
|
- * --use-krb5-ccache option via cli credentials. Fallback to
|
|
- * KRB5CCNAME environment variable to get 'net ads kerberos'
|
|
- * functions to work at all - gd */
|
|
-
|
|
+ /*
|
|
+ * Priority order for krb5 credential cache name
|
|
+ *
|
|
+ * via cli_credentials_get_out_ccache_name() :
|
|
+ *
|
|
+ * 1. '--use-krb5-ccache' option
|
|
+ *
|
|
+ * via krb5_cc_default_name() :
|
|
+ *
|
|
+ * 2. KRB5CCNAME environment variable
|
|
+ * 3. default_ccache_name in [libdefaults] section of krb5.conf
|
|
+ * 4. ...more - krb5_cc_default_name() always returns something
|
|
+ * - see documentation
|
|
+ */
|
|
krb5ccname = cli_credentials_get_out_ccache_name(c->creds);
|
|
if (krb5ccname == NULL || krb5ccname[0] == '\0') {
|
|
- krb5ccname = getenv("KRB5CCNAME");
|
|
- }
|
|
- if (krb5ccname == NULL || krb5ccname[0] == '\0') {
|
|
- krb5ccname = talloc_strdup(c, "MEMORY:net");
|
|
+ krb5_context ct = NULL;
|
|
+ krb5_error_code ret = smb_krb5_init_context_common(&ct);
|
|
+
|
|
+ if (ret == 0) {
|
|
+ krb5ccname = smb_force_krb5_cc_default_name(ct);
|
|
+ if (krb5ccname != NULL) {
|
|
+ krb5ccname = talloc_strdup(c,
|
|
+ krb5ccname);
|
|
+ }
|
|
+ krb5_free_context(ct);
|
|
+ }
|
|
}
|
|
if (krb5ccname == NULL) {
|
|
DBG_ERR("Not able to setup krb5 ccache");
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 0ca830d6ddded29b2b5d1969ebcbc4df1156656e Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Thu, 5 Feb 2026 16:04:25 +0100
|
|
Subject: [PATCH 09/66] manpages: Update NET ADS KERBEROS KINIT manpage
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15993
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
|
|
Autobuild-User(master): Pavel Filipensky <pfilipensky@samba.org>
|
|
Autobuild-Date(master): Thu Feb 5 21:11:13 UTC 2026 on atb-devel-224
|
|
|
|
(cherry picked from commit 9d083a28fe45afd8f82441c6e24255e4c64c113b)
|
|
---
|
|
docs-xml/manpages/net.8.xml | 36 ++++++++++++++++++++++++++++--------
|
|
1 file changed, 28 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml
|
|
index 737415b3722..b793361a27f 100644
|
|
--- a/docs-xml/manpages/net.8.xml
|
|
+++ b/docs-xml/manpages/net.8.xml
|
|
@@ -1823,17 +1823,37 @@ the following entry types;
|
|
<title>ADS KERBEROS KINIT</title>
|
|
|
|
<para>
|
|
- Issue a kinit request for a given user. When no other options are
|
|
- defined the ticket granting ticket (TGT) will be stored in a memory cache.
|
|
+ Issue a kinit request for a given user. The following methods can be used
|
|
+ to specify where to store the ticket granting ticket (TGT) (in order of
|
|
+ precedence):
|
|
</para>
|
|
|
|
-<para>
|
|
- To store the TGT in a different location either use the
|
|
- <option>--krb5-ccache</option> option or set the
|
|
- <replaceable>KRB5CCNAME</replaceable> environment variable.
|
|
-</para>
|
|
+<itemizedlist>
|
|
+ <listitem>
|
|
+ <para>option <option>--use-krb5-ccache</option></para>
|
|
+ </listitem>
|
|
+ <listitem>
|
|
+ <para><replaceable>KRB5CCNAME</replaceable> environment variable</para>
|
|
+ </listitem>
|
|
+ <listitem>
|
|
+ <para><parameter>default_ccache_name</parameter> setting in <filename>krb5.conf</filename></para>
|
|
+ </listitem>
|
|
+</itemizedlist>
|
|
|
|
-<para>Example: <userinput>net ads kerberos kinit -P --krb5-ccache=/tmp/krb5cache</userinput></para>
|
|
+<variablelist><title>Examples:</title>
|
|
+<varlistentry>
|
|
+<term>Use file based cache (FILE:/tmp/krb5cache)</term>
|
|
+<listitem><literallayout>
|
|
+net ads kerberos kinit -P --use-krb5-ccache=/tmp/krb5cache
|
|
+</literallayout></listitem>
|
|
+</varlistentry>
|
|
+<varlistentry>
|
|
+<term>Use memory cache (MEMORY:net) to verify the authentication</term>
|
|
+<listitem><literallayout>
|
|
+net ads kerberos kinit -P --use-krb5-ccache=MEMORY:net
|
|
+</literallayout></listitem>
|
|
+</varlistentry>
|
|
+</variablelist>
|
|
|
|
</refsect2>
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 44b613d80c6a3818cc6ca593d57d51cd1bc00aa5 Mon Sep 17 00:00:00 2001
|
|
From: Noel Power <noel.power@suse.com>
|
|
Date: Fri, 13 Feb 2026 11:54:46 +0000
|
|
Subject: [PATCH 10/66] selftest: Update tests to use
|
|
--use-kereros=desired|required no creds
|
|
|
|
Add tests to call smbclient without passing credentials to
|
|
demonstrate failure with --use-kereros=desired
|
|
|
|
Also add knownfail
|
|
|
|
Signed-off-by: Noel Power <noel.power@suse.com>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
(cherry picked from commit a22af9420965083b99b956477d1833000b7f2414)
|
|
---
|
|
selftest/knownfail | 2 ++
|
|
source3/script/tests/test_smbclient_kerberos.sh | 12 ++++++++++++
|
|
2 files changed, 14 insertions(+)
|
|
|
|
diff --git a/selftest/knownfail b/selftest/knownfail
|
|
index ab2d79d7114..f0a5f7bb935 100644
|
|
--- a/selftest/knownfail
|
|
+++ b/selftest/knownfail
|
|
@@ -315,6 +315,8 @@
|
|
# ad_member don't support ntlmv1 (not even over SMB1)
|
|
^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.member.creds.*as.user.*ad_member
|
|
^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.*mNT1.member.creds.*as.user.*ad_member
|
|
+# regression smbclient using --use-kerberos=desired https://bugzilla.samba.org/show_bug.cgi?id=15789
|
|
+samba3.blackbox.smbclient.kerberos.smbclient.smb3.kerberos.desired \(no user/pass\).*
|
|
#nt-vfs server blocks read with execute access
|
|
^samba4.smb2.read.access
|
|
#ntvfs server blocks copychunk with execute access on read handle
|
|
diff --git a/source3/script/tests/test_smbclient_kerberos.sh b/source3/script/tests/test_smbclient_kerberos.sh
|
|
index 31678d17e28..1139efd70d7 100755
|
|
--- a/source3/script/tests/test_smbclient_kerberos.sh
|
|
+++ b/source3/script/tests/test_smbclient_kerberos.sh
|
|
@@ -73,6 +73,18 @@ test_smbclient "smbclient.smb3.kerberos.desired[//${SERVER}/tmp]" \
|
|
--use-kerberos=desired -U${USERNAME}%${PASSWORD} -mSMB3 ||
|
|
failed=$(expr $failed + 1)
|
|
|
|
+test_smbclient "smbclient.smb3.kerberos.desired (no user/pass) [//${SERVER}/tmp]" \
|
|
+ "ls; quit" //${SERVER}/tmp \
|
|
+ --use-kerberos=desired -mSMB3 ||
|
|
+ failed=$(expr $failed + 1)
|
|
+
|
|
+test_smbclient "smbclient.smb3.kerberos.required (no user/pass) [//${SERVER}/tmp]" \
|
|
+ "ls; quit" //${SERVER}/tmp \
|
|
+ --use-kerberos=required -mSMB3 ||
|
|
+ failed=$(expr $failed + 1)
|
|
+
|
|
+
|
|
+
|
|
$samba_kdestroy
|
|
|
|
rm -rf $KRB5CCNAME_PATH
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 65f70c0505759489a8b219e1297f8cdee2cc260a Mon Sep 17 00:00:00 2001
|
|
From: Noel Power <noel.power@suse.com>
|
|
Date: Mon, 19 Jan 2026 15:46:59 +0000
|
|
Subject: [PATCH 11/66] auth/credentials: Fix regression with
|
|
--use-kerberos=desired for smbclient
|
|
|
|
As part of the gse_krb5 processing the following call chain
|
|
|
|
gensec_gse_client_start()
|
|
---> gensec_kerberos_possible()
|
|
---> cli_credentials_authentication_requested()
|
|
|
|
gensec_kerberos_possible() will always fail when
|
|
cli_credentials_get_kerberos_state() returns CRED_USE_KERBEROS_DESIRED
|
|
|
|
It seems since use kerberos == desired is the default that it isn't
|
|
necessary to see if credentials were modified to indicated authentication
|
|
was requested. gensec_kerberos_possible() should afaics return true
|
|
if kerberos is desired OR required (regardless of whether credentials
|
|
were requested)
|
|
|
|
This commit removes the knownfail associated with this bug.
|
|
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15789
|
|
Signed-off-by: <noel.power@suse.com>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
(cherry picked from commit 88f42eb222f299189d5f5f8204ae353e63a50970)
|
|
---
|
|
auth/gensec/gensec_util.c | 5 -----
|
|
selftest/knownfail | 2 --
|
|
2 files changed, 7 deletions(-)
|
|
|
|
diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c
|
|
index 0c7688d33d2..af6d198d48f 100644
|
|
--- a/auth/gensec/gensec_util.c
|
|
+++ b/auth/gensec/gensec_util.c
|
|
@@ -362,7 +362,6 @@ char *gensec_get_unparsed_target_principal(struct gensec_security *gensec_securi
|
|
NTSTATUS gensec_kerberos_possible(struct gensec_security *gensec_security)
|
|
{
|
|
struct cli_credentials *creds = gensec_get_credentials(gensec_security);
|
|
- bool auth_requested = cli_credentials_authentication_requested(creds);
|
|
enum credentials_use_kerberos krb5_state =
|
|
cli_credentials_get_kerberos_state(creds);
|
|
char *user_principal = NULL;
|
|
@@ -370,10 +369,6 @@ NTSTATUS gensec_kerberos_possible(struct gensec_security *gensec_security)
|
|
const char *target_principal = gensec_get_target_principal(gensec_security);
|
|
const char *hostname = gensec_get_target_hostname(gensec_security);
|
|
|
|
- if (!auth_requested) {
|
|
- return NT_STATUS_INVALID_PARAMETER;
|
|
- }
|
|
-
|
|
if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
|
|
return NT_STATUS_INVALID_PARAMETER;
|
|
}
|
|
diff --git a/selftest/knownfail b/selftest/knownfail
|
|
index f0a5f7bb935..ab2d79d7114 100644
|
|
--- a/selftest/knownfail
|
|
+++ b/selftest/knownfail
|
|
@@ -315,8 +315,6 @@
|
|
# ad_member don't support ntlmv1 (not even over SMB1)
|
|
^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.member.creds.*as.user.*ad_member
|
|
^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.*mNT1.member.creds.*as.user.*ad_member
|
|
-# regression smbclient using --use-kerberos=desired https://bugzilla.samba.org/show_bug.cgi?id=15789
|
|
-samba3.blackbox.smbclient.kerberos.smbclient.smb3.kerberos.desired \(no user/pass\).*
|
|
#nt-vfs server blocks read with execute access
|
|
^samba4.smb2.read.access
|
|
#ntvfs server blocks copychunk with execute access on read handle
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 8c955cad98b197936fceaf98306047e1f929ddfe Mon Sep 17 00:00:00 2001
|
|
From: Noel Power <noel.power@suse.com>
|
|
Date: Mon, 19 Jan 2026 16:10:10 +0000
|
|
Subject: [PATCH 12/66] s3/libsmb: cli_session_creds_init fails when kerberos
|
|
is desired
|
|
|
|
There is a regression with code using cli_session_creds_init when
|
|
cli_credentials_get_kerberos_state() returns CRED_USE_KERBEROS_DESIRED
|
|
|
|
Authentication succeeds when boolean fallback_after_kerberos is false
|
|
and fails when true.
|
|
There doesn't seem to be a good reason why the value of
|
|
fallback_after_kerberos should initialise the krb5 ccache or not.
|
|
It would seems that krb5 cache should be setup for creds
|
|
for *any* kerberos auth (whether fallback is enabled or not)
|
|
|
|
Partial patch from <will69@gmx.de> (see bug referenced below)
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15789
|
|
Signed-off-by: Noel Power <noel.power@suse.com>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
(cherry picked from commit 1c48599105736499d18aa1f647bce9e1f8dbdcca)
|
|
---
|
|
source3/libsmb/cliconnect.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
|
|
index 116f746d37e..3fd423d8e5f 100644
|
|
--- a/source3/libsmb/cliconnect.c
|
|
+++ b/source3/libsmb/cliconnect.c
|
|
@@ -218,7 +218,7 @@ struct cli_credentials *cli_session_creds_init(TALLOC_CTX *mem_ctx,
|
|
goto fail;
|
|
}
|
|
}
|
|
- } else if (use_kerberos && !fallback_after_kerberos) {
|
|
+ } else if (use_kerberos) {
|
|
const char *error_string = NULL;
|
|
int rc;
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 015167aea7ece2bb683f86aa4b8c688d7a83267d Mon Sep 17 00:00:00 2001
|
|
From: Noel Power <noel.power@suse.com>
|
|
Date: Mon, 19 Jan 2026 16:18:02 +0000
|
|
Subject: [PATCH 13/66] s3/libsmb: block anon authentication fallback is
|
|
use-kerberos = desired
|
|
|
|
When cli_credentials_get_kerberos_state returns CRED_USE_KERBEROS_REQUIRED
|
|
libsmbclient method SMBC_server_internal will still try to fallback to
|
|
anon NTLM. This patch prevents that.
|
|
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15789
|
|
Signed-off-by: Noel Power <noel.power@suse.com>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
|
|
Autobuild-User(master): Noel Power <npower@samba.org>
|
|
Autobuild-Date(master): Tue Feb 17 16:06:18 UTC 2026 on atb-devel-224
|
|
|
|
(cherry picked from commit bc868800276fe09cbcb206ebe4cb4da32af7599f)
|
|
---
|
|
source3/libsmb/libsmb_server.c | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c
|
|
index f9b52e1f05a..8c7208aaee0 100644
|
|
--- a/source3/libsmb/libsmb_server.c
|
|
+++ b/source3/libsmb/libsmb_server.c
|
|
@@ -632,6 +632,8 @@ SMBC_server_internal(TALLOC_CTX *ctx,
|
|
password_used = "";
|
|
|
|
if (smbc_getOptionNoAutoAnonymousLogin(context) ||
|
|
+ cli_credentials_get_kerberos_state(creds) ==
|
|
+ CRED_USE_KERBEROS_REQUIRED ||
|
|
!NT_STATUS_IS_OK(cli_session_setup_anon(c))) {
|
|
|
|
cli_shutdown(c);
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 3f66a4fbb46f614bf81533677944b1093439aaf8 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Wed, 18 Mar 2026 20:24:37 +0100
|
|
Subject: [PATCH 14/66] s3:libnet: Fix DC numeric ip handling
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This is fixing regression introduced via 82f53c8
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15999
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
---
|
|
source3/libnet/libnet_join.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
|
|
index 609b2b96222..66d682a5b95 100644
|
|
--- a/source3/libnet/libnet_join.c
|
|
+++ b/source3/libnet/libnet_join.c
|
|
@@ -2643,7 +2643,7 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
|
|
struct sockaddr_storage ss = {0};
|
|
const char *numeric_dcip = info->dc_address + 2;
|
|
|
|
- if (numeric_dcip[0] == '\0') {
|
|
+ if (numeric_dcip[0] != '\0') {
|
|
if (!interpret_string_addr(&ss, numeric_dcip,
|
|
AI_NUMERICHOST)) {
|
|
DBG_ERR(
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 4725da7df3028d37d8bf34b3671c553b7337703b Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Mon, 23 Mar 2026 19:03:34 +0100
|
|
Subject: [PATCH 15/66] s3:libads: Allow to specify 'dns_lookup_kdc' in
|
|
krb5.conf
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15999
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
---
|
|
source3/libads/kerberos.c | 23 ++++++++++++++++-------
|
|
source3/libads/kerberos_proto.h | 33 +++++++++++++++++++++++++++++----
|
|
2 files changed, 45 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
|
|
index 5593364c397..865c32d73ca 100644
|
|
--- a/source3/libads/kerberos.c
|
|
+++ b/source3/libads/kerberos.c
|
|
@@ -1362,10 +1362,12 @@ static char *get_enctypes(TALLOC_CTX *mem_ctx)
|
|
}
|
|
#endif
|
|
|
|
-bool create_local_private_krb5_conf_for_domain(const char *realm,
|
|
- const char *domain,
|
|
- const char *sitename,
|
|
- const struct sockaddr_storage *pss)
|
|
+bool create_local_private_krb5_conf_for_domain_internal(
|
|
+ const char *realm,
|
|
+ const char *domain,
|
|
+ const char *sitename,
|
|
+ const struct sockaddr_storage *pss,
|
|
+ bool dns_lookup_kdc)
|
|
{
|
|
char *dname;
|
|
char *tmpname = NULL;
|
|
@@ -1450,10 +1452,16 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
|
|
#endif
|
|
|
|
/*
|
|
- * We are setting 'dns_lookup_kdc' to true, because we want to lookup
|
|
- * KDCs which are not configured via DNS SRV records, eg. if we do:
|
|
+ * Normally 'dns_lookup_kdc' should be set to true, because we want to
|
|
+ * also lookup KDCs via DNS SRV records, e.g. cross domain scenario:
|
|
*
|
|
* net ads join -Uadmin@otherdomain
|
|
+ *
|
|
+ * However, during domain join we need to set it to false when we
|
|
+ * reconnect using the freshly created machine account credentials.
|
|
+ * With dns_lookup_kdc = true, Kerberos may pick a different DC
|
|
+ * for the TCP retry (after UDP response is too large), and that DC
|
|
+ * might not have replicated the new machine account yet.
|
|
*/
|
|
file_contents =
|
|
talloc_asprintf(fname,
|
|
@@ -1467,7 +1475,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
|
|
"\tdefault_realm = %s\n"
|
|
"%s"
|
|
"\tdns_lookup_realm = false\n"
|
|
- "\tdns_lookup_kdc = true\n\n"
|
|
+ "\tdns_lookup_kdc = %s\n\n"
|
|
"[realms]\n\t%s = {\n"
|
|
"%s\t}\n"
|
|
"\t%s = {\n"
|
|
@@ -1476,6 +1484,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
|
|
timeout_sec,
|
|
realm_upper,
|
|
enctypes,
|
|
+ dns_lookup_kdc ? "true" : "false",
|
|
realm_upper,
|
|
kdc_ip_string,
|
|
domain,
|
|
diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h
|
|
index a96211c7289..fbeaeff92a9 100644
|
|
--- a/source3/libads/kerberos_proto.h
|
|
+++ b/source3/libads/kerberos_proto.h
|
|
@@ -70,10 +70,35 @@ int ads_kdestroy(const char *cc_name);
|
|
int kerberos_kinit_password(const char *principal,
|
|
const char *password,
|
|
const char *cache_name);
|
|
-bool create_local_private_krb5_conf_for_domain(const char *realm,
|
|
- const char *domain,
|
|
- const char *sitename,
|
|
- const struct sockaddr_storage *pss);
|
|
+
|
|
+bool create_local_private_krb5_conf_for_domain_internal(
|
|
+ const char *realm,
|
|
+ const char *domain,
|
|
+ const char *sitename,
|
|
+ const struct sockaddr_storage *pss,
|
|
+ bool dns_lookup_kdc);
|
|
+
|
|
+/* Create krb5.conf that allows DC lookup using DNS. */
|
|
+static inline bool create_local_private_krb5_conf_for_domain(
|
|
+ const char *realm,
|
|
+ const char *domain,
|
|
+ const char *sitename,
|
|
+ const struct sockaddr_storage *pss)
|
|
+{
|
|
+ return create_local_private_krb5_conf_for_domain_internal(
|
|
+ realm, domain, sitename, pss, true);
|
|
+}
|
|
+
|
|
+/* Create krb5.conf that disables DC lookup using DNS - needed during join. */
|
|
+static inline bool create_local_private_krb5_conf_for_domain_join(
|
|
+ const char *realm,
|
|
+ const char *domain,
|
|
+ const char *sitename,
|
|
+ const struct sockaddr_storage *pss)
|
|
+{
|
|
+ return create_local_private_krb5_conf_for_domain_internal(
|
|
+ realm, domain, sitename, pss, false);
|
|
+}
|
|
|
|
/* The following definitions come from libads/authdata.c */
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 5e1fde5e03c3899b329bd38c36033c385f6fb5f0 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Mon, 23 Mar 2026 19:05:31 +0100
|
|
Subject: [PATCH 16/66] s3:libads: Set dns_lookup_kdc=false during net ads join
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15999
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
|
|
Autobuild-User(master): Pavel Filipensky <pfilipensky@samba.org>
|
|
Autobuild-Date(master): Tue Apr 7 14:09:40 UTC 2026 on atb-devel-224
|
|
---
|
|
source3/libnet/libnet_join.c | 60 +++++++++++++++++++++++++++++++++++-
|
|
1 file changed, 59 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
|
|
index 66d682a5b95..81bcb9793a6 100644
|
|
--- a/source3/libnet/libnet_join.c
|
|
+++ b/source3/libnet/libnet_join.c
|
|
@@ -2881,6 +2881,10 @@ WERROR libnet_Join(TALLOC_CTX *mem_ctx,
|
|
struct libnet_JoinCtx *r)
|
|
{
|
|
WERROR werr;
|
|
+#ifdef HAVE_ADS
|
|
+ struct sockaddr_storage dc_ss = {0};
|
|
+ bool dns_lookup_kdc_disabled = false;
|
|
+#endif /* HAVE_ADS */
|
|
|
|
if (r->in.debug) {
|
|
LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
|
|
@@ -2904,6 +2908,49 @@ WERROR libnet_Join(TALLOC_CTX *mem_ctx,
|
|
}
|
|
}
|
|
|
|
+#ifdef HAVE_ADS
|
|
+ /*
|
|
+ * The machine account was just created on r->in.dc_name,
|
|
+ * but might not have replicated to other DCs yet.
|
|
+ * Regenerate the krb5.conf with dns_lookup_kdc = false
|
|
+ * so that the Kerberos library only talks to the DC
|
|
+ * where the account was created. This covers all
|
|
+ * subsequent machine-credential operations:
|
|
+ * - libnet_join_post_processing_ads_modify() (etype update)
|
|
+ * - libnet_join_post_verify() (domain membership verification)
|
|
+ */
|
|
+ if (r->out.domain_is_ad &&
|
|
+ !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
|
|
+ !r->in.request_offline_join)
|
|
+ {
|
|
+ bool ok;
|
|
+ const char *ip = NULL;
|
|
+
|
|
+ /* dcinfo might not be set for offline joins, however this
|
|
+ * check is redundant since we have a guard:
|
|
+ * !r->in.request_offline_join
|
|
+ */
|
|
+ if (r->out.dcinfo) {
|
|
+ ip = r->out.dcinfo->dc_address + 2; /* Strip "\\" */
|
|
+ }
|
|
+
|
|
+ if (ip && ip[0] != '\0') {
|
|
+ ok = interpret_string_addr(&dc_ss, ip, AI_NUMERICHOST);
|
|
+ } else {
|
|
+ ok = interpret_string_addr(&dc_ss, r->in.dc_name, 0);
|
|
+ }
|
|
+
|
|
+ if (ok) {
|
|
+ create_local_private_krb5_conf_for_domain_join(
|
|
+ r->out.dns_domain_name,
|
|
+ r->out.netbios_domain_name,
|
|
+ NULL, /* sitename */
|
|
+ &dc_ss);
|
|
+ dns_lookup_kdc_disabled = true;
|
|
+ }
|
|
+ }
|
|
+#endif /* HAVE_ADS */
|
|
+
|
|
werr = libnet_join_post_processing(mem_ctx, r);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
@@ -2931,7 +2978,18 @@ WERROR libnet_Join(TALLOC_CTX *mem_ctx,
|
|
}
|
|
}
|
|
|
|
- done:
|
|
+done:
|
|
+#ifdef HAVE_ADS
|
|
+ if (dns_lookup_kdc_disabled) {
|
|
+ /* Restore dns_lookup_kdc = true for subsequent operations */
|
|
+ create_local_private_krb5_conf_for_domain(
|
|
+ r->out.dns_domain_name,
|
|
+ r->out.netbios_domain_name,
|
|
+ NULL, /* sitename */
|
|
+ &dc_ss);
|
|
+ }
|
|
+#endif /* HAVE_ADS */
|
|
+
|
|
r->out.result = werr;
|
|
|
|
if (r->in.debug) {
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 42e48d3dd29027573f6e1c04f78f8d9cb91eb4ab Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Fri, 14 Feb 2025 17:07:14 +0100
|
|
Subject: [PATCH 17/66] vfs: Add VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
|
|
|
|
It disallows traversal of mount points during path resolution, including bind
|
|
mounts.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/include/vfs.h | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
|
|
index e87a0d923e5..15e2186eab7 100644
|
|
--- a/source3/include/vfs.h
|
|
+++ b/source3/include/vfs.h
|
|
@@ -926,6 +926,7 @@ struct vfs_aio_state {
|
|
|
|
#define VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS 1
|
|
#define VFS_OPEN_HOW_WITH_BACKUP_INTENT 2
|
|
+#define VFS_OPEN_HOW_RESOLVE_NO_XDEV 4
|
|
|
|
struct vfs_open_how {
|
|
int flags;
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 5656562fd43507501aea62b7a43b1d3d5431b313 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Fri, 14 Feb 2025 17:13:39 +0100
|
|
Subject: [PATCH 18/66] vfs: Use RESOLVE_NO_XDEV by default on all shares
|
|
|
|
Enable the flag by default on all shares, it will be automatically
|
|
disabled if the system does not support openat2().
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
script/autobuild.py | 2 +-
|
|
source3/modules/vfs_default.c | 11 +++++++++++
|
|
2 files changed, 12 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/script/autobuild.py b/script/autobuild.py
|
|
index 8acf6cdc854..97d44a07ee4 100755
|
|
--- a/script/autobuild.py
|
|
+++ b/script/autobuild.py
|
|
@@ -338,7 +338,7 @@ tasks = {
|
|
"samba-no-opath-build": {
|
|
"git-clone-required": True,
|
|
"sequence": [
|
|
- ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1 -DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS=1 -DDISABLE_PROC_FDS=1' ./configure.developer --without-ad-dc " + samba_configure_params),
|
|
+ ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1 -DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS=1 -DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_XDEV=1 -DDISABLE_PROC_FDS=1' ./configure.developer --without-ad-dc " + samba_configure_params),
|
|
("make", "make -j"),
|
|
("check-clean-tree", CLEAN_SOURCE_TREE_CMD),
|
|
("chmod-R-a-w", "chmod -R a-w ."),
|
|
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
|
|
index 83c9cc06de8..d531f277199 100644
|
|
--- a/source3/modules/vfs_default.c
|
|
+++ b/source3/modules/vfs_default.c
|
|
@@ -76,6 +76,17 @@ static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const
|
|
#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
|
|
handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
|
|
#endif
|
|
+ bval = lp_parm_bool(SNUM(handle->conn),
|
|
+ "vfs_default",
|
|
+ "VFS_OPEN_HOW_RESOLVE_NO_XDEV",
|
|
+ true);
|
|
+ if (bval) {
|
|
+ handle->conn->open_how_resolve |=
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
+ }
|
|
+#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_XDEV
|
|
+ handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
+#endif
|
|
|
|
return 0; /* Return >= 0 for success */
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 21ce7f160fb6f2bec613be36f2120002205bf84e Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Wed, 8 Oct 2025 10:54:55 +0200
|
|
Subject: [PATCH 19/66] selftest/Samba3: nt4_dc* use
|
|
vfs_default:VFS_OPEN_HOW_RESOLVE_NO_XDEV=no
|
|
|
|
From 076c22fbd7ecbf22dbfeb1711609f07fd42f88b0, we should always test the
|
|
code path without openat2 being available, even if the kernel supports it.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
selftest/target/Samba3.pm | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
|
|
index 6f17d659d96..3b990bcb349 100755
|
|
--- a/selftest/target/Samba3.pm
|
|
+++ b/selftest/target/Samba3.pm
|
|
@@ -304,6 +304,7 @@ sub setup_nt4_dc
|
|
server schannel require seal:torturetest\$ = no
|
|
|
|
vfs_default:VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS = no
|
|
+ vfs_default:VFS_OPEN_HOW_RESOLVE_NO_XDEV = no
|
|
|
|
fss: sequence timeout = 1
|
|
check parent directory delete on close = yes
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 0f873b9e694c2db4c54bb480183583d04dde3bdd Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Fri, 14 Feb 2025 17:14:59 +0100
|
|
Subject: [PATCH 20/66] vfs: Pass the RESOLVE_NO_XDEV from upper layers to
|
|
openat2() syscall
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_default.c | 19 ++++++++++++++++---
|
|
1 file changed, 16 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
|
|
index d531f277199..f0270e96002 100644
|
|
--- a/source3/modules/vfs_default.c
|
|
+++ b/source3/modules/vfs_default.c
|
|
@@ -630,7 +630,9 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
|
SMB_ASSERT((dirfd != -1) || (smb_fname->base_name[0] == '/'));
|
|
|
|
if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
|
|
- VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
|
|
+ VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV))
|
|
+ {
|
|
errno = ENOSYS;
|
|
result = -1;
|
|
goto out;
|
|
@@ -663,12 +665,20 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
|
}
|
|
#endif
|
|
|
|
- if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
|
|
+ if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS ||
|
|
+ how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
|
|
+ {
|
|
struct open_how linux_how = {
|
|
.flags = flags,
|
|
.mode = mode,
|
|
- .resolve = RESOLVE_NO_SYMLINKS,
|
|
+ .resolve = 0,
|
|
};
|
|
+ if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
|
|
+ linux_how.resolve |= RESOLVE_NO_SYMLINKS;
|
|
+ }
|
|
+ if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
|
|
+ linux_how.resolve |= RESOLVE_NO_XDEV;
|
|
+ }
|
|
|
|
result = openat2(dirfd,
|
|
smb_fname->base_name,
|
|
@@ -681,10 +691,13 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
|
* openat2(), so indicate to
|
|
* the callers that
|
|
* VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
|
|
+ * or VFS_OPEN_HOW_RESOLVE_NO_XDEV
|
|
* would just be a waste of time.
|
|
*/
|
|
fsp->conn->open_how_resolve &=
|
|
~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
|
|
+ fsp->conn->open_how_resolve &=
|
|
+ ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
}
|
|
goto out;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From ff04fbf4e754c6eca9ea87a13d91bb84613ff9f9 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Wed, 8 Oct 2025 13:18:44 +0200
|
|
Subject: [PATCH 21/66] smbd: Refactor reopen_from_fsp(), factor out name based
|
|
reopen
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/smbd/open.c | 55 +++++++++++++++++++++++++++++++--------------
|
|
1 file changed, 38 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
|
|
index f2cbf7d6bf6..8443ddd32d3 100644
|
|
--- a/source3/smbd/open.c
|
|
+++ b/source3/smbd/open.c
|
|
@@ -847,6 +847,33 @@ static NTSTATUS fd_open_atomic(struct files_struct *dirfsp,
|
|
return status;
|
|
}
|
|
|
|
+/*
|
|
+ * Close the existing pathref fd and set the fsp flag
|
|
+ * is_pathref to false so we get a "normal" fd this time.
|
|
+ */
|
|
+static NTSTATUS reopen_from_fsp_namebased(struct files_struct *dirfsp,
|
|
+ struct smb_filename *smb_fname,
|
|
+ struct files_struct *fsp,
|
|
+ const struct vfs_open_how *how,
|
|
+ bool *p_file_created)
|
|
+{
|
|
+ NTSTATUS status;
|
|
+
|
|
+ status = fd_close(fsp);
|
|
+ if (!NT_STATUS_IS_OK(status)) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ fsp->fsp_flags.is_pathref = false;
|
|
+
|
|
+ status = fd_open_atomic(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
+ return status;
|
|
+}
|
|
+
|
|
NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
struct smb_filename *smb_fname,
|
|
struct files_struct *fsp,
|
|
@@ -896,7 +923,12 @@ NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
* point we get ENOENT. We
|
|
* have to retry pathbased.
|
|
*/
|
|
- goto namebased_open;
|
|
+ return reopen_from_fsp_namebased(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
+
|
|
}
|
|
/* restore ENOENT if changed in the meantime */
|
|
errno = ENOENT;
|
|
@@ -916,22 +948,11 @@ NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
-#if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
|
|
-namebased_open:
|
|
-#endif
|
|
- /*
|
|
- * Close the existing pathref fd and set the fsp flag
|
|
- * is_pathref to false so we get a "normal" fd this time.
|
|
- */
|
|
- status = fd_close(fsp);
|
|
- if (!NT_STATUS_IS_OK(status)) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- fsp->fsp_flags.is_pathref = false;
|
|
-
|
|
- status = fd_open_atomic(dirfsp, smb_fname, fsp, how, p_file_created);
|
|
- return status;
|
|
+ return reopen_from_fsp_namebased(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
}
|
|
|
|
/****************************************************************************
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 1f869b2d814930c4c97a9fff461a3ec2327f4503 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Wed, 8 Oct 2025 13:53:14 +0200
|
|
Subject: [PATCH 22/66] smbd: Refactor reopen_from_fsp(), factor out
|
|
automounter mountpoint check
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/smbd/open.c | 66 +++++++++++++++++++++++++++------------------
|
|
1 file changed, 40 insertions(+), 26 deletions(-)
|
|
|
|
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
|
|
index 8443ddd32d3..67bb9774429 100644
|
|
--- a/source3/smbd/open.c
|
|
+++ b/source3/smbd/open.c
|
|
@@ -874,6 +874,30 @@ static NTSTATUS reopen_from_fsp_namebased(struct files_struct *dirfsp,
|
|
return status;
|
|
}
|
|
|
|
+static bool fsp_is_automount_mountpoint(struct files_struct *fsp, int old_fd)
|
|
+{
|
|
+#if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
|
|
+ struct statfs sbuf = {};
|
|
+ int ret;
|
|
+
|
|
+ if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ ret = fstatfs(old_fd, &sbuf);
|
|
+ if (ret == -1) {
|
|
+ DBG_ERR("fstatfs failed: %s\n", strerror(errno));
|
|
+ return false;
|
|
+ }
|
|
+ if (sbuf.f_type == AUTOFS_SUPER_MAGIC) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+#else
|
|
+ return false;
|
|
+#endif
|
|
+}
|
|
+
|
|
NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
struct smb_filename *smb_fname,
|
|
struct files_struct *fsp,
|
|
@@ -908,33 +932,23 @@ NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
fsp,
|
|
how);
|
|
if (new_fd == -1) {
|
|
-#if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
|
|
- if (S_ISDIR(fsp->fsp_name->st.st_ex_mode) &&
|
|
- (errno == ENOENT)) {
|
|
- struct statfs sbuf = {};
|
|
- int ret = fstatfs(old_fd, &sbuf);
|
|
- if (ret == -1) {
|
|
- DBG_ERR("fstatfs failed: %s\n",
|
|
- strerror(errno));
|
|
- } else if (sbuf.f_type == AUTOFS_SUPER_MAGIC) {
|
|
- /*
|
|
- * When reopening an as-yet
|
|
- * unmounted autofs mount
|
|
- * point we get ENOENT. We
|
|
- * have to retry pathbased.
|
|
- */
|
|
- return reopen_from_fsp_namebased(dirfsp,
|
|
- smb_fname,
|
|
- fsp,
|
|
- how,
|
|
- p_file_created);
|
|
-
|
|
- }
|
|
- /* restore ENOENT if changed in the meantime */
|
|
- errno = ENOENT;
|
|
+ int saved_errno = errno;
|
|
+ if (saved_errno == ENOENT &&
|
|
+ fsp_is_automount_mountpoint(fsp, old_fd))
|
|
+ {
|
|
+ /*
|
|
+ * When reopening an as-yet unmounted autofs
|
|
+ * mount point we get ENOENT. We have to retry
|
|
+ * pathbased.
|
|
+ */
|
|
+ return reopen_from_fsp_namebased(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
}
|
|
-#endif
|
|
- status = map_nt_error_from_unix(errno);
|
|
+
|
|
+ status = map_nt_error_from_unix(saved_errno);
|
|
fd_close(fsp);
|
|
return status;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From d1f0323322b0c70998e901ad79aafcce795646a4 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Wed, 8 Oct 2025 14:17:27 +0200
|
|
Subject: [PATCH 23/66] smbd: Refactor reopen_from_fsp(), factor out pathref
|
|
based
|
|
|
|
Best viewed ignoring white space changes
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/smbd/open.c | 117 +++++++++++++++++++++++++-------------------
|
|
1 file changed, 66 insertions(+), 51 deletions(-)
|
|
|
|
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
|
|
index 67bb9774429..69c78ff563c 100644
|
|
--- a/source3/smbd/open.c
|
|
+++ b/source3/smbd/open.c
|
|
@@ -898,68 +898,83 @@ static bool fsp_is_automount_mountpoint(struct files_struct *fsp, int old_fd)
|
|
#endif
|
|
}
|
|
|
|
-NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
- struct smb_filename *smb_fname,
|
|
- struct files_struct *fsp,
|
|
- const struct vfs_open_how *how,
|
|
- bool *p_file_created)
|
|
+static NTSTATUS reopen_from_fsp_pathref_based(
|
|
+ struct files_struct *dirfsp,
|
|
+ struct smb_filename *smb_fname,
|
|
+ struct files_struct *fsp,
|
|
+ const struct vfs_open_how *how,
|
|
+ bool *p_file_created)
|
|
{
|
|
NTSTATUS status;
|
|
- int old_fd;
|
|
+ struct sys_proc_fd_path_buf buf;
|
|
+ int pathref_fd = fsp_get_pathref_fd(fsp);
|
|
+ struct smb_filename proc_fname = {
|
|
+ .base_name = sys_proc_fd_path(pathref_fd, &buf),
|
|
+ };
|
|
+ mode_t mode = fsp->fsp_name->st.st_ex_mode;
|
|
+ int new_fd;
|
|
|
|
- if (fsp->fsp_flags.have_proc_fds &&
|
|
- ((old_fd = fsp_get_pathref_fd(fsp)) != -1)) {
|
|
+ if (S_ISLNK(mode)) {
|
|
+ return NT_STATUS_STOPPED_ON_SYMLINK;
|
|
+ }
|
|
+ if (!(S_ISREG(mode) || S_ISDIR(mode))) {
|
|
+ return NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED;
|
|
+ }
|
|
|
|
- struct sys_proc_fd_path_buf buf;
|
|
- struct smb_filename proc_fname = {
|
|
- .base_name = sys_proc_fd_path(old_fd, &buf),
|
|
- };
|
|
- mode_t mode = fsp->fsp_name->st.st_ex_mode;
|
|
- int new_fd;
|
|
+ fsp->fsp_flags.is_pathref = false;
|
|
|
|
- if (S_ISLNK(mode)) {
|
|
- return NT_STATUS_STOPPED_ON_SYMLINK;
|
|
- }
|
|
- if (!(S_ISREG(mode) || S_ISDIR(mode))) {
|
|
- return NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED;
|
|
+ new_fd = SMB_VFS_OPENAT(fsp->conn,
|
|
+ fsp->conn->cwd_fsp,
|
|
+ &proc_fname,
|
|
+ fsp,
|
|
+ how);
|
|
+ if (new_fd == -1) {
|
|
+ int saved_errno = errno;
|
|
+ if (saved_errno == ENOENT &&
|
|
+ fsp_is_automount_mountpoint(fsp, pathref_fd))
|
|
+ {
|
|
+ /*
|
|
+ * When reopening an as-yet unmounted autofs
|
|
+ * mount point we get ENOENT. We have to retry
|
|
+ * pathbased.
|
|
+ */
|
|
+ return reopen_from_fsp_namebased(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
}
|
|
|
|
- fsp->fsp_flags.is_pathref = false;
|
|
+ status = map_nt_error_from_unix(saved_errno);
|
|
+ fd_close(fsp);
|
|
+ return status;
|
|
+ }
|
|
|
|
- new_fd = SMB_VFS_OPENAT(fsp->conn,
|
|
- fsp->conn->cwd_fsp,
|
|
- &proc_fname,
|
|
- fsp,
|
|
- how);
|
|
- if (new_fd == -1) {
|
|
- int saved_errno = errno;
|
|
- if (saved_errno == ENOENT &&
|
|
- fsp_is_automount_mountpoint(fsp, old_fd))
|
|
- {
|
|
- /*
|
|
- * When reopening an as-yet unmounted autofs
|
|
- * mount point we get ENOENT. We have to retry
|
|
- * pathbased.
|
|
- */
|
|
- return reopen_from_fsp_namebased(dirfsp,
|
|
- smb_fname,
|
|
- fsp,
|
|
- how,
|
|
- p_file_created);
|
|
- }
|
|
+ status = fd_close(fsp);
|
|
+ if (!NT_STATUS_IS_OK(status)) {
|
|
+ return status;
|
|
+ }
|
|
|
|
- status = map_nt_error_from_unix(saved_errno);
|
|
- fd_close(fsp);
|
|
- return status;
|
|
- }
|
|
+ fsp_set_fd(fsp, new_fd);
|
|
+ return NT_STATUS_OK;
|
|
+}
|
|
|
|
- status = fd_close(fsp);
|
|
- if (!NT_STATUS_IS_OK(status)) {
|
|
- return status;
|
|
- }
|
|
+NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
|
+ struct smb_filename *smb_fname,
|
|
+ struct files_struct *fsp,
|
|
+ const struct vfs_open_how *how,
|
|
+ bool *p_file_created)
|
|
+{
|
|
+ int old_fd;
|
|
|
|
- fsp_set_fd(fsp, new_fd);
|
|
- return NT_STATUS_OK;
|
|
+ if (fsp->fsp_flags.have_proc_fds &&
|
|
+ ((old_fd = fsp_get_pathref_fd(fsp)) != -1))
|
|
+ {
|
|
+ return reopen_from_fsp_pathref_based(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
}
|
|
|
|
return reopen_from_fsp_namebased(dirfsp,
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 55bddf76fe649ca7ba30f0645a199255f2698a70 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Wed, 8 Oct 2025 17:09:22 +0200
|
|
Subject: [PATCH 24/66] smbd: Fix crossing direct automounter mount points
|
|
|
|
The workaround implemented in commit ac7a16f9cc4bd97ef546d1b7b02605991000d0f9
|
|
to trigger automounts does not work for direct automounts (either with
|
|
systemd-automount or autofs daemon).
|
|
|
|
In direct automounts the mount point is a real directory instead of a "ghost"
|
|
directory so when turning the O_PATH handle into a real one through
|
|
/proc/self/fd/<fdnum> openat() does not return ENOENT, it returs a fd referring
|
|
to the mount point without triggering the mount.
|
|
|
|
To trigger the mount first we have to know when we are crossing mount points
|
|
by using the RESOLVE_NO_XDEV flag in open_how.resolve, then we can check with
|
|
fstatfs() the .f_type and fallback to a path-based open for automounts or
|
|
retry without RESOLVE_NO_XDEV otherwise.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/smbd/open.c | 71 ++++++++++++++++++++++++++++++++++++++++++---
|
|
1 file changed, 67 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
|
|
index 69c78ff563c..ea400c41aa8 100644
|
|
--- a/source3/smbd/open.c
|
|
+++ b/source3/smbd/open.c
|
|
@@ -913,6 +913,7 @@ static NTSTATUS reopen_from_fsp_pathref_based(
|
|
};
|
|
mode_t mode = fsp->fsp_name->st.st_ex_mode;
|
|
int new_fd;
|
|
+ struct vfs_open_how pathref_how = *how;
|
|
|
|
if (S_ISLNK(mode)) {
|
|
return NT_STATUS_STOPPED_ON_SYMLINK;
|
|
@@ -923,26 +924,88 @@ static NTSTATUS reopen_from_fsp_pathref_based(
|
|
|
|
fsp->fsp_flags.is_pathref = false;
|
|
|
|
+#if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
|
|
+ /*
|
|
+ * There is no point in setting RESOLVE_NO_XDEV if we can't
|
|
+ * check with fstatfs later in fsp_is_automount_mountpoint
|
|
+ */
|
|
+ if (S_ISDIR(fsp->fsp_name->st.st_ex_mode) &&
|
|
+ fsp->conn->open_how_resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
|
|
+ /*
|
|
+ * If the *at cwd_fsp is a pathref (opened with O_PATH)
|
|
+ * and old_fd refers to an automounter mount point not
|
|
+ * yet mounted, we will get a fd referring to the
|
|
+ * mount point without actually triggering the mount
|
|
+ * (man 2 openat). To detect this situation set the
|
|
+ * RESOLVE_NO_XDEV flag so openat2 will return an
|
|
+ * error when crossing mount points. Then check
|
|
+ * with fstatfs if it is an autofs mount point or not,
|
|
+ * falling back to name-based openat or retry without
|
|
+ * RESOLVE_NO_XDEV otherwise (could be a bind mount,
|
|
+ * other type of mount of an automounter mount point
|
|
+ * already mounted).
|
|
+ */
|
|
+ pathref_how.resolve |= VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+retry:
|
|
new_fd = SMB_VFS_OPENAT(fsp->conn,
|
|
fsp->conn->cwd_fsp,
|
|
&proc_fname,
|
|
fsp,
|
|
- how);
|
|
+ &pathref_how);
|
|
if (new_fd == -1) {
|
|
int saved_errno = errno;
|
|
if (saved_errno == ENOENT &&
|
|
fsp_is_automount_mountpoint(fsp, pathref_fd))
|
|
{
|
|
/*
|
|
- * When reopening an as-yet unmounted autofs
|
|
- * mount point we get ENOENT. We have to retry
|
|
- * pathbased.
|
|
+ * This is a not yet triggered indirect automount
|
|
+ * detected by openat(pathref_fd). Retry name-based.
|
|
*/
|
|
return reopen_from_fsp_namebased(dirfsp,
|
|
smb_fname,
|
|
fsp,
|
|
how,
|
|
p_file_created);
|
|
+ } else if (saved_errno == EXDEV &&
|
|
+ pathref_how.resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV &&
|
|
+ fsp_is_automount_mountpoint(fsp, pathref_fd))
|
|
+ {
|
|
+ /*
|
|
+ * This is a not yet triggered direct or indirect
|
|
+ * automount, detected by
|
|
+ * openat2(pathref_fd, .., RESOLVE_NO_XDEV).
|
|
+ * Retry name-based.
|
|
+ */
|
|
+ return reopen_from_fsp_namebased(dirfsp,
|
|
+ smb_fname,
|
|
+ fsp,
|
|
+ how,
|
|
+ p_file_created);
|
|
+ } else if (saved_errno == ENOSYS &&
|
|
+ pathref_how.resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
|
|
+ {
|
|
+ /*
|
|
+ * The kernel doesn't support openat2() yet, or any
|
|
+ * VFS module rejected the flag. Notify to the user
|
|
+ * and retry without RESOLVE_NO_XDEV.
|
|
+ */
|
|
+ DBG_WARNING("Failed to open directory disallowing the "
|
|
+ "traversal of mount points during path "
|
|
+ "resolution. Retrying allowing traversal, "
|
|
+ "but automounts won't be triggered.\n");
|
|
+ pathref_how.resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
+ goto retry;
|
|
+ } else if (saved_errno == EXDEV &&
|
|
+ pathref_how.resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
|
|
+ {
|
|
+ /*
|
|
+ * Just crossing a mount. Retry allowing traversals.
|
|
+ */
|
|
+ pathref_how.resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
+ goto retry;
|
|
}
|
|
|
|
status = map_nt_error_from_unix(saved_errno);
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 4872b32c28d540618462ee186e91716c9ee3807c Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@suse.de>
|
|
Date: Fri, 2 May 2025 11:57:30 +0200
|
|
Subject: [PATCH 25/66] vfs:aio_pthread: Handle VFS_OPEN_HOW_RESOLVE_NO_XDEV
|
|
flag
|
|
|
|
This module uses openat() instead of openat2() so the flag won't be used and
|
|
automounts might not be triggered.
|
|
|
|
Disable flag usage for subsequent opens and return an error to callers to warn
|
|
the user and retry without the flag.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_aio_pthread.c | 14 +++++++++++++-
|
|
1 file changed, 13 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_aio_pthread.c b/source3/modules/vfs_aio_pthread.c
|
|
index bd0c94b8cce..afbaaedf7b5 100644
|
|
--- a/source3/modules/vfs_aio_pthread.c
|
|
+++ b/source3/modules/vfs_aio_pthread.c
|
|
@@ -457,7 +457,9 @@ static int aio_pthread_openat_fn(vfs_handle_struct *handle,
|
|
bool aio_allow_open = lp_parm_bool(
|
|
SNUM(handle->conn), "aio_pthread", "aio open", false);
|
|
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
@@ -498,6 +500,16 @@ static int aio_pthread_openat_fn(vfs_handle_struct *handle,
|
|
aio_allow_open = false;
|
|
}
|
|
|
|
+ if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
|
|
+ /*
|
|
+ * RESOLVE_NO_XDEV needs openat2(). Disallow further usage of
|
|
+ * this flag and return ENOSYS to force a retry.
|
|
+ */
|
|
+ fsp->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
|
|
+ errno = ENOSYS;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
if (!aio_allow_open) {
|
|
/* aio opens turned off. */
|
|
return SMB_VFS_NEXT_OPENAT(handle,
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From e11fa05e10b1a5fadd7c73c87dcb68b048c73878 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@suse.de>
|
|
Date: Fri, 2 May 2025 12:11:01 +0200
|
|
Subject: [PATCH 26/66] vfs:ceph: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
|
|
|
|
Don't return ENOSYS if the flag is set. It will be ignored,
|
|
does not make sense in a ceph virtual filesystem.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_ceph.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
|
|
index 8ea7eb09099..4add6cf993e 100644
|
|
--- a/source3/modules/vfs_ceph.c
|
|
+++ b/source3/modules/vfs_ceph.c
|
|
@@ -472,7 +472,9 @@ static int cephwrap_openat(struct vfs_handle_struct *handle,
|
|
int result = -ENOENT;
|
|
int dirfd = -1;
|
|
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 4cd5f6c4c39ac172e3e3e9e2c11fa9be06f2ed38 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Tue, 30 Sep 2025 10:32:36 +0200
|
|
Subject: [PATCH 27/66] vfs:ceph_new: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
|
|
|
|
Don't return ENOSYS if the flag is set. It will be ignored,
|
|
does not make sense in a ceph filesystem.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_ceph_new.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_ceph_new.c b/source3/modules/vfs_ceph_new.c
|
|
index 6ea8e56c155..37cff6fe051 100644
|
|
--- a/source3/modules/vfs_ceph_new.c
|
|
+++ b/source3/modules/vfs_ceph_new.c
|
|
@@ -2325,7 +2325,9 @@ static int vfs_ceph_openat(struct vfs_handle_struct *handle,
|
|
int result = -ENOENT;
|
|
|
|
START_PROFILE_X(SNUM(handle->conn), syscall_openat);
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
result = -ENOSYS;
|
|
goto err_out;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 8f4ad32afca03b564d00a5a6795d4b4a50ae8c66 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Thu, 9 Oct 2025 12:30:17 +0200
|
|
Subject: [PATCH 28/66] vfs:glusterfs: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
|
|
|
|
Don't return ENOSYS if the flag is set. It will be ignored as does not make
|
|
sense in this module.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_glusterfs.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
|
|
index 63dc7a30b04..4d7d96f2888 100644
|
|
--- a/source3/modules/vfs_glusterfs.c
|
|
+++ b/source3/modules/vfs_glusterfs.c
|
|
@@ -731,7 +731,9 @@ static int vfs_gluster_openat(struct vfs_handle_struct *handle,
|
|
|
|
START_PROFILE(syscall_openat);
|
|
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
END_PROFILE(syscall_openat);
|
|
errno = ENOSYS;
|
|
return -1;
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From b41558ebe158f413d2cfa71478c3eeb5e1a201ec Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@suse.de>
|
|
Date: Fri, 2 May 2025 13:21:52 +0200
|
|
Subject: [PATCH 29/66] vfs:shadow_copy2: Allow RESOLVE_NO_XDEV flag
|
|
|
|
This module updates the path and calls the next VFS module.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_shadow_copy2.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
|
|
index 449d08e8830..465a0f9d28e 100644
|
|
--- a/source3/modules/vfs_shadow_copy2.c
|
|
+++ b/source3/modules/vfs_shadow_copy2.c
|
|
@@ -1563,7 +1563,9 @@ static int shadow_copy2_openat(vfs_handle_struct *handle,
|
|
int ret;
|
|
bool ok;
|
|
|
|
- if ((how.resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how.resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 49ac956d858b455291edd1330a8d428209728ea0 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Thu, 9 Oct 2025 12:52:11 +0200
|
|
Subject: [PATCH 30/66] vfs:streams_depot: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
|
|
flag
|
|
|
|
The flag is passed down the modules stack.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_streams_depot.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c
|
|
index 19b9356fd57..bcf5acf79b4 100644
|
|
--- a/source3/modules/vfs_streams_depot.c
|
|
+++ b/source3/modules/vfs_streams_depot.c
|
|
@@ -729,7 +729,9 @@ static int streams_depot_openat(struct vfs_handle_struct *handle,
|
|
handle, dirfsp, smb_fname, fsp, how);
|
|
}
|
|
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 7b875e245ec205ee083c5c4158933e0e42e8a064 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Thu, 9 Oct 2025 12:59:59 +0200
|
|
Subject: [PATCH 31/66] vfs:fruit: Allow RESOLVE_NO_XDEV flag
|
|
|
|
For stream opens, it returns a fake fd. The streams will be stored by
|
|
vfs_streams_depot or vfs_streams_xattr.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
---
|
|
source3/modules/vfs_fruit.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
|
|
index 4da7c1efa07..812e3a351d2 100644
|
|
--- a/source3/modules/vfs_fruit.c
|
|
+++ b/source3/modules/vfs_fruit.c
|
|
@@ -1787,7 +1787,9 @@ static int fruit_openat(vfs_handle_struct *handle,
|
|
return fd;
|
|
}
|
|
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 97fb984b6c5c5fe1c562cd23980ea8e110438577 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Cabrero <scabrero@samba.org>
|
|
Date: Thu, 9 Oct 2025 13:05:16 +0200
|
|
Subject: [PATCH 32/66] vfs:streams_xattr: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
|
|
|
|
The open function returns a fake fd. Extended attributes will be stored by
|
|
vfs_xattr_tdb or vfs_default.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
|
|
|
|
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
|
|
|
Autobuild-User(master): Samuel Cabrero <scabrero@samba.org>
|
|
Autobuild-Date(master): Tue Nov 18 09:08:38 UTC 2025 on atb-devel-224
|
|
---
|
|
source3/modules/vfs_streams_xattr.c | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
|
|
index 58e5b1eb189..410cd793cd9 100644
|
|
--- a/source3/modules/vfs_streams_xattr.c
|
|
+++ b/source3/modules/vfs_streams_xattr.c
|
|
@@ -416,7 +416,9 @@ static int streams_xattr_openat(struct vfs_handle_struct *handle,
|
|
how);
|
|
}
|
|
|
|
- if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
|
|
+ if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
|
|
+ VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
|
|
+ {
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 23aa86c38e049eb0f75bdd21d18c670abf2c6134 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20Filipensk=C3=BD?= <pfilipensky@samba.org>
|
|
Date: Tue, 7 Apr 2026 16:28:05 +0200
|
|
Subject: [PATCH 33/66] smbdotconf: Add "automount fs types" to smb.conf
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This adds a new global parameter "automount fs types" that allows
|
|
administrators to configure additional filesystem types that should
|
|
trigger automounting, beyond the always-supported autofs filesystem.
|
|
|
|
To enable 'samba unaware FS' automounting, add:
|
|
|
|
automount fs types = 0x12345678
|
|
|
|
This allows e.g. ZFS snapshots in <dataset root>/.zfs/snapshot to be
|
|
mounted. To find out the magic number that is not listed
|
|
in /usr/include/linux/magic.h, run:
|
|
|
|
stat -f -c '0x%t' /path/to/mountpoint
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15991
|
|
|
|
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
|
|
Reviewed-by: Samuel Cabrero <scabrero@samba.org>
|
|
|
|
Autobuild-User(master): Pavel Filipensky <pfilipensky@samba.org>
|
|
Autobuild-Date(master): Mon Apr 20 19:57:42 UTC 2026 on atb-devel-224
|
|
---
|
|
docs-xml/smbdotconf/misc/automountfstypes.xml | 24 ++++++++++++++
|
|
source3/smbd/open.c | 31 +++++++++++++++++++
|
|
2 files changed, 55 insertions(+)
|
|
create mode 100644 docs-xml/smbdotconf/misc/automountfstypes.xml
|
|
|
|
diff --git a/docs-xml/smbdotconf/misc/automountfstypes.xml b/docs-xml/smbdotconf/misc/automountfstypes.xml
|
|
new file mode 100644
|
|
index 00000000000..4c5bc510520
|
|
--- /dev/null
|
|
+++ b/docs-xml/smbdotconf/misc/automountfstypes.xml
|
|
@@ -0,0 +1,24 @@
|
|
+<samba:parameter name="automount fs types"
|
|
+ context="G"
|
|
+ type="cmdlist"
|
|
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
|
|
+<description>
|
|
+ <para>This parameter specifies a list of additional filesystem magic numbers
|
|
+ that should trigger automounting when accessed.</para>
|
|
+
|
|
+ <para>The values should be specified as hexadecimal numbers (with or without
|
|
+ 0x prefix), separated by spaces or commas.</para>
|
|
+
|
|
+ <para>Note: This parameter is only available on Linux systems.</para>
|
|
+
|
|
+ <para>To find the filesystem magic number for a mounted filesystem,
|
|
+ consult /usr/include/linux/magic.h or call:
|
|
+ <command>stat -f -c '0x%t' /path/to/mountpoint</command></para>
|
|
+
|
|
+ <para>Note: autofs (0x187) is always checked and does not need to be included
|
|
+ in this list.</para>
|
|
+</description>
|
|
+
|
|
+<value type="default"></value>
|
|
+<value type="example">0xA0B0C0D0 0x12345678</value>
|
|
+</samba:parameter>
|
|
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
|
|
index ea400c41aa8..ae1ce208cba 100644
|
|
--- a/source3/smbd/open.c
|
|
+++ b/source3/smbd/open.c
|
|
@@ -42,6 +42,7 @@
|
|
#include "locking/leases_db.h"
|
|
#include "librpc/gen_ndr/ndr_leases_db.h"
|
|
#include "lib/util/time_basic.h"
|
|
+#include "lib/util/smb_strtox.h"
|
|
#include "source3/smbd/dir.h"
|
|
|
|
#if defined(HAVE_LINUX_MAGIC_H)
|
|
@@ -879,6 +880,8 @@ static bool fsp_is_automount_mountpoint(struct files_struct *fsp, int old_fd)
|
|
#if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
|
|
struct statfs sbuf = {};
|
|
int ret;
|
|
+ const char **fs_types_list = NULL;
|
|
+ int i;
|
|
|
|
if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
|
|
return false;
|
|
@@ -892,6 +895,34 @@ static bool fsp_is_automount_mountpoint(struct files_struct *fsp, int old_fd)
|
|
if (sbuf.f_type == AUTOFS_SUPER_MAGIC) {
|
|
return true;
|
|
}
|
|
+
|
|
+ /* Check for additional filesystem types from configuration */
|
|
+ fs_types_list = lp_automount_fs_types();
|
|
+ if (fs_types_list == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ for (i = 0; fs_types_list[i] != NULL; i++) {
|
|
+ unsigned long long fs_type_val;
|
|
+ int error = 0;
|
|
+
|
|
+ fs_type_val = smb_strtoull(fs_types_list[i],
|
|
+ NULL,
|
|
+ 0,
|
|
+ &error,
|
|
+ SMB_STR_FULL_STR_CONV);
|
|
+ if (error != 0) {
|
|
+ DBG_WARNING(
|
|
+ "Invalid value in 'automount fs types': %s\n",
|
|
+ fs_types_list[i]);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (sbuf.f_type == fs_type_val) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
return false;
|
|
#else
|
|
return false;
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 1405b4a8f4772d603083535d6db153c9189ae18c Mon Sep 17 00:00:00 2001
|
|
From: Volker Lendecke <vl@samba.org>
|
|
Date: Thu, 5 Feb 2026 20:24:12 +0100
|
|
Subject: [PATCH 34/66] CVE-2026-1933 tests: Fix permissions used for creating
|
|
reparse points
|
|
|
|
SEC_STD_ALL does not lead to fsp->access_mask to include the required
|
|
bits.
|
|
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15992
|
|
Signed-off-by: Volker Lendecke <vl@samba.org>
|
|
Reviewed-by: Stefan Metzmacher <metze@samba.org>
|
|
---
|
|
python/samba/tests/smb3unix.py | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/python/samba/tests/smb3unix.py b/python/samba/tests/smb3unix.py
|
|
index 075b2a07b17..3039a68a1cd 100644
|
|
--- a/python/samba/tests/smb3unix.py
|
|
+++ b/python/samba/tests/smb3unix.py
|
|
@@ -446,7 +446,7 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
|
|
|
|
wire_mode = libsmb.unix_mode_to_wire(0o600)
|
|
f,_,cc_out = c.create_ex('\\reparse',
|
|
- DesiredAccess=security.SEC_STD_ALL,
|
|
+ DesiredAccess=security.SEC_FILE_WRITE_ATTRIBUTE,
|
|
CreateDisposition=libsmb.FILE_CREATE,
|
|
CreateContexts=[posix_context(wire_mode)])
|
|
|
|
@@ -460,7 +460,7 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
|
|
|
|
wire_mode = libsmb.unix_mode_to_wire(0o600)
|
|
f,_,cc_out = c.create_ex('\\reparse',
|
|
- DesiredAccess=security.SEC_STD_ALL,
|
|
+ DesiredAccess=security.SEC_FILE_WRITE_ATTRIBUTE,
|
|
CreateDisposition=libsmb.FILE_OPEN,
|
|
CreateContexts=[posix_context(wire_mode)])
|
|
c.close(f)
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 6af47933d060e03ab1cceff2652658c2dd230872 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Mon, 2 Feb 2026 11:43:37 +0100
|
|
Subject: [PATCH 35/66] CVE-2026-1933 smbd: Add access checks to reparse point
|
|
operations
|
|
|
|
On a share marked "read only = yes" and on file handles opened R/O
|
|
users can set or delete the reparse point xattrs on files that the
|
|
user has write-access in the file system for. Add the required access
|
|
checks.
|
|
|
|
Thanks to Asim Viladi Oglu Manizada for reporting the issue.
|
|
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15992
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Volker Lendecke <vl@samba.org>
|
|
---
|
|
source3/modules/util_reparse.c | 16 ++++++++++++++++
|
|
1 file changed, 16 insertions(+)
|
|
|
|
diff --git a/source3/modules/util_reparse.c b/source3/modules/util_reparse.c
|
|
index 60373d7fd4e..75aa745e070 100644
|
|
--- a/source3/modules/util_reparse.c
|
|
+++ b/source3/modules/util_reparse.c
|
|
@@ -320,6 +320,14 @@ NTSTATUS fsctl_set_reparse_point(struct files_struct *fsp,
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
+ if ((fsp->fsp_name->twrp != 0) ||
|
|
+ ((fsp->access_mask &
|
|
+ (SEC_FILE_WRITE_DATA | SEC_FILE_WRITE_ATTRIBUTE)) == 0))
|
|
+ {
|
|
+ DBG_DEBUG("Access denied on a readonly handle\n");
|
|
+ return NT_STATUS_ACCESS_DENIED;
|
|
+ }
|
|
+
|
|
status = reparse_buffer_check(in_data,
|
|
in_len,
|
|
&reparse_tag,
|
|
@@ -390,6 +398,14 @@ NTSTATUS fsctl_del_reparse_point(struct files_struct *fsp,
|
|
uint32_t dos_mode;
|
|
int ret;
|
|
|
|
+ if ((fsp->fsp_name->twrp != 0) ||
|
|
+ ((fsp->access_mask &
|
|
+ (SEC_FILE_WRITE_DATA | SEC_FILE_WRITE_ATTRIBUTE)) == 0))
|
|
+ {
|
|
+ DBG_DEBUG("Access denied on a readonly handle\n");
|
|
+ return NT_STATUS_ACCESS_DENIED;
|
|
+ }
|
|
+
|
|
status = fsctl_get_reparse_tag(fsp, &existing_tag);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
return status;
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From aed5ff8b967502a40eefe01f85e292c622931551 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Thu, 19 Feb 2026 12:50:38 +1300
|
|
Subject: [PATCH 36/66] CVE-2026-2340: test whether vfs_worm allows overwrite
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15997
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Reviewed-by: Volker Lendecke <vl@samba.org>
|
|
---
|
|
selftest/knownfail.d/vfs-worm | 2 ++
|
|
source3/script/tests/test_worm.sh | 30 ++++++++++++++++++++++++++++++
|
|
2 files changed, 32 insertions(+)
|
|
create mode 100644 selftest/knownfail.d/vfs-worm
|
|
|
|
diff --git a/selftest/knownfail.d/vfs-worm b/selftest/knownfail.d/vfs-worm
|
|
new file mode 100644
|
|
index 00000000000..f4a330c744b
|
|
--- /dev/null
|
|
+++ b/selftest/knownfail.d/vfs-worm
|
|
@@ -0,0 +1,2 @@
|
|
+^samba3.blackbox.worm.SMB3
|
|
+^samba3.blackbox.worm.NT1
|
|
diff --git a/source3/script/tests/test_worm.sh b/source3/script/tests/test_worm.sh
|
|
index f96c8ec7e47..d38488cb790 100755
|
|
--- a/source3/script/tests/test_worm.sh
|
|
+++ b/source3/script/tests/test_worm.sh
|
|
@@ -40,6 +40,7 @@ do_cleanup()
|
|
#subshell.
|
|
cd "$share_test_dir" || return
|
|
rm -f must-be-deleted must-not-be-deleted must-be-deleted-after-ctime-refresh
|
|
+ rm -f must-not-be-overwritten sentinel-value
|
|
)
|
|
rm -f $tmpfile
|
|
}
|
|
@@ -51,6 +52,10 @@ do_cleanup
|
|
|
|
tmpfile=$PREFIX/smbclient_interactive_prompt_commands
|
|
|
|
+tmp_sentinel=$PREFIX/sentinel_value
|
|
+SENTINEL_VALUE='1'
|
|
+echo $SENTINEL_VALUE > $tmp_sentinel
|
|
+
|
|
test_worm()
|
|
{
|
|
# use echo because helo scripts don't support variables
|
|
@@ -58,6 +63,7 @@ test_worm()
|
|
put $tmpfile must-be-deleted
|
|
put $tmpfile must-be-deleted-after-ctime-refresh
|
|
put $tmpfile must-not-be-deleted
|
|
+put $tmpfile must-not-be-overwritten
|
|
del must-be-deleted
|
|
quit" > $tmpfile
|
|
# make sure the directory is not too old for worm:
|
|
@@ -97,6 +103,30 @@ quit" > $tmpfile
|
|
printf "$0: ERROR: must-not-be-deleted WAS deleted\n"
|
|
return 1
|
|
}
|
|
+
|
|
+ # Check we can't change a protected file by renaming over it.
|
|
+ # The source file needs to recently created or access will be
|
|
+ # denied before RENAME_AT is reached, which is the thing we
|
|
+ # want to test.
|
|
+ original_contents=`cat $share_test_dir/must-not-be-overwritten`
|
|
+ echo "
|
|
+put $tmp_sentinel sentinel-value
|
|
+rename sentinel-value must-not-be-overwritten -f
|
|
+quit" > $tmpfile
|
|
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/worm -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
|
|
+ eval echo "$cmd"
|
|
+ out=$(eval "$cmd")
|
|
+ new_contents=`cat $share_test_dir/must-not-be-overwritten`
|
|
+
|
|
+ if [ "$new_contents" = "$SENTINEL_VALUE" ]; then
|
|
+ echo "must-not-be-overwritten was overwritten"
|
|
+ return 1
|
|
+ fi
|
|
+ if [ "$new_contents" != "$original_contents" ]; then
|
|
+ echo "must-not-be-overwritten was changed (but not precisely overwritten)"
|
|
+ return 1
|
|
+ fi
|
|
+
|
|
# if we're not root, return here:
|
|
test "$UID" = "0" || {
|
|
return 0
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From c8e94fe47601143a86d7b9362313e77d4d19fd2d Mon Sep 17 00:00:00 2001
|
|
From: Pavel Kohout <pavel@aisle.com>
|
|
Date: Fri, 13 Feb 2026 15:51:41 +1300
|
|
Subject: [PATCH 37/66] CVE-2026-2340: vfs_worm: Check destination WORM status
|
|
in rename
|
|
|
|
vfs_worm_renameat() only checked if the source file was WORM-protected,
|
|
but not the destination. This allowed overwriting immutable files via
|
|
SMB2 rename with ReplaceIfExists=1, bypassing WORM protection.
|
|
|
|
Add destination check using FSTATAT on the destination dirfsp, as
|
|
suggested by the maintainer.
|
|
|
|
CWE-284 (Improper Access Control)
|
|
|
|
Reported-by: Pavel Kohout, Aisle Research, www.aisle.com
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15997
|
|
|
|
To backport to 4.23 we change the name of dst_dirfsp and src_dirfsp to
|
|
dstfsp and srcfsp, respectively (accounting for
|
|
76796180cf3af3252db2c29d0e95282a498a8527 in 4.24/master).
|
|
|
|
Signed-off-by: Pavel Kohout <pavel.kohout@aisle.com>
|
|
Reviewed-by: Volker Lendecke <vl@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
selftest/knownfail.d/vfs-worm | 2 --
|
|
source3/modules/vfs_worm.c | 26 ++++++++++++++++++++++++--
|
|
2 files changed, 24 insertions(+), 4 deletions(-)
|
|
delete mode 100644 selftest/knownfail.d/vfs-worm
|
|
|
|
diff --git a/selftest/knownfail.d/vfs-worm b/selftest/knownfail.d/vfs-worm
|
|
deleted file mode 100644
|
|
index f4a330c744b..00000000000
|
|
--- a/selftest/knownfail.d/vfs-worm
|
|
+++ /dev/null
|
|
@@ -1,2 +0,0 @@
|
|
-^samba3.blackbox.worm.SMB3
|
|
-^samba3.blackbox.worm.NT1
|
|
diff --git a/source3/modules/vfs_worm.c b/source3/modules/vfs_worm.c
|
|
index 0fcda162cd7..a1dca280279 100644
|
|
--- a/source3/modules/vfs_worm.c
|
|
+++ b/source3/modules/vfs_worm.c
|
|
@@ -218,13 +218,35 @@ static int vfs_worm_renameat(vfs_handle_struct *handle,
|
|
const struct smb_filename *smb_fname_dst,
|
|
const struct vfs_rename_how *how)
|
|
{
|
|
+ struct stat_ex dst_st;
|
|
+ int ret;
|
|
+
|
|
if (is_readonly(handle, smb_fname_src)) {
|
|
errno = EACCES;
|
|
return -1;
|
|
}
|
|
|
|
- return SMB_VFS_NEXT_RENAMEAT(
|
|
- handle, srcfsp, smb_fname_src, dstfsp, smb_fname_dst, how);
|
|
+ /* Check if destination is WORM-protected (fixes CVE-2026-2340) */
|
|
+ ret = SMB_VFS_FSTATAT(handle->conn,
|
|
+ dstfsp,
|
|
+ smb_fname_dst,
|
|
+ &dst_st,
|
|
+ AT_SYMLINK_NOFOLLOW);
|
|
+ if (ret == 0) {
|
|
+ struct smb_filename dst_with_stat = *smb_fname_dst;
|
|
+ dst_with_stat.st = dst_st;
|
|
+ if (is_readonly(handle, &dst_with_stat)) {
|
|
+ errno = EACCES;
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return SMB_VFS_NEXT_RENAMEAT(handle,
|
|
+ srcfsp,
|
|
+ smb_fname_src,
|
|
+ dstfsp,
|
|
+ smb_fname_dst,
|
|
+ how);
|
|
}
|
|
|
|
static int vfs_worm_fsetxattr(struct vfs_handle_struct *handle,
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 1af2b41cd7ae0d1b65f6ba44a29a2500a0177d24 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Fri, 27 Feb 2026 11:30:40 +1300
|
|
Subject: [PATCH 38/66] CVE-2026-3012: gpo tests: fix test cleanup
|
|
|
|
These tests are going to fail soon but as currently written they do
|
|
not clean up after themselves, erroring instead of failing and causing
|
|
cascading errors in subsequent tests. For now we don't care to make
|
|
the other tests less fragile.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16003
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
|
|
---
|
|
python/samba/tests/gpo.py | 42 +++++++++++++++++++++++----------------
|
|
1 file changed, 25 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py
|
|
index 2e4696cd926..0972cd2f63c 100644
|
|
--- a/python/samba/tests/gpo.py
|
|
+++ b/python/samba/tests/gpo.py
|
|
@@ -6951,6 +6951,7 @@ class GPOTests(tests.TestCase):
|
|
confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
|
|
ca_cn = '%s-CA' % hostname.replace('.', '-')
|
|
certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
|
|
+ self.addCleanup(ldb.delete, certa_dn)
|
|
ldb.add({'dn': certa_dn,
|
|
'objectClass': 'certificationAuthority',
|
|
'authorityRevocationList': ['XXX'],
|
|
@@ -6959,6 +6960,7 @@ class GPOTests(tests.TestCase):
|
|
})
|
|
# Write the dummy pKIEnrollmentService
|
|
enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
|
|
+ self.addCleanup(ldb.delete, enroll_dn)
|
|
ldb.add({'dn': enroll_dn,
|
|
'objectClass': 'pKIEnrollmentService',
|
|
'cACertificate': dummy_certificate(),
|
|
@@ -6967,6 +6969,7 @@ class GPOTests(tests.TestCase):
|
|
})
|
|
# Write the dummy pKICertificateTemplate
|
|
template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
|
|
+ self.addCleanup(ldb.delete, template_dn)
|
|
ldb.add({'dn': template_dn,
|
|
'objectClass': 'pKICertificateTemplate',
|
|
})
|
|
@@ -7012,11 +7015,6 @@ class GPOTests(tests.TestCase):
|
|
self.assertNotIn(b'Workstation', out,
|
|
'Workstation certificate not removed')
|
|
|
|
- # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
|
|
- ldb.delete(certa_dn)
|
|
- ldb.delete(enroll_dn)
|
|
- ldb.delete(template_dn)
|
|
-
|
|
# Unstage the Registry.pol file
|
|
unstage_file(reg_pol)
|
|
|
|
@@ -7027,6 +7025,7 @@ class GPOTests(tests.TestCase):
|
|
'MACHINE/REGISTRY.POL')
|
|
cache_dir = self.lp.get('cache directory')
|
|
store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
|
|
+ self.addCleanup(store.log.close)
|
|
|
|
machine_creds = Credentials()
|
|
machine_creds.guess(self.lp)
|
|
@@ -7059,6 +7058,7 @@ class GPOTests(tests.TestCase):
|
|
confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
|
|
ca_cn = '%s-CA' % hostname.replace('.', '-')
|
|
certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
|
|
+ self.addCleanup(ldb.delete, certa_dn)
|
|
ldb.add({'dn': certa_dn,
|
|
'objectClass': 'certificationAuthority',
|
|
'authorityRevocationList': ['XXX'],
|
|
@@ -7067,6 +7067,7 @@ class GPOTests(tests.TestCase):
|
|
})
|
|
# Write the dummy pKIEnrollmentService
|
|
enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
|
|
+ self.addCleanup(ldb.delete, enroll_dn)
|
|
ldb.add({'dn': enroll_dn,
|
|
'objectClass': 'pKIEnrollmentService',
|
|
'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
|
|
@@ -7075,12 +7076,16 @@ class GPOTests(tests.TestCase):
|
|
})
|
|
# Write the dummy pKICertificateTemplate
|
|
template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
|
|
+ self.addCleanup(ldb.delete, template_dn)
|
|
ldb.add({'dn': template_dn,
|
|
'objectClass': 'pKICertificateTemplate',
|
|
})
|
|
|
|
with TemporaryDirectory() as dname:
|
|
- ext.process_group_policy([], gpos, dname, dname)
|
|
+ try:
|
|
+ ext.process_group_policy([], gpos, dname, dname)
|
|
+ except Exception as e:
|
|
+ self.fail(f"process_group_policy() raised {e}")
|
|
ca_crt = os.path.join(dname, '%s.crt' % ca_cn)
|
|
self.assertTrue(os.path.exists(ca_crt),
|
|
'Root CA certificate was not requested')
|
|
@@ -7169,11 +7174,6 @@ class GPOTests(tests.TestCase):
|
|
self.assertNotIn(b'Workstation', out,
|
|
'Workstation certificate not removed')
|
|
|
|
- # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
|
|
- ldb.delete(certa_dn)
|
|
- ldb.delete(enroll_dn)
|
|
- ldb.delete(template_dn)
|
|
-
|
|
# Unstage the Registry.pol file
|
|
unstage_file(reg_pol)
|
|
|
|
@@ -7626,6 +7626,7 @@ class GPOTests(tests.TestCase):
|
|
'MACHINE/REGISTRY.POL')
|
|
cache_dir = self.lp.get('cache directory')
|
|
store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
|
|
+ self.addCleanup(store.log.close)
|
|
|
|
machine_creds = Credentials()
|
|
machine_creds.guess(self.lp)
|
|
@@ -7667,6 +7668,8 @@ class GPOTests(tests.TestCase):
|
|
confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
|
|
ca_cn = '%s-CA' % hostname.replace('.', '-')
|
|
certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
|
|
+ self.addCleanup(ldb.delete, certa_dn)
|
|
+
|
|
ldb.add({'dn': certa_dn,
|
|
'objectClass': 'certificationAuthority',
|
|
'authorityRevocationList': ['XXX'],
|
|
@@ -7675,6 +7678,7 @@ class GPOTests(tests.TestCase):
|
|
})
|
|
# Write the dummy pKIEnrollmentService
|
|
enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
|
|
+ self.addCleanup(ldb.delete, enroll_dn)
|
|
ldb.add({'dn': enroll_dn,
|
|
'objectClass': 'pKIEnrollmentService',
|
|
'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
|
|
@@ -7683,12 +7687,21 @@ class GPOTests(tests.TestCase):
|
|
})
|
|
# Write the dummy pKICertificateTemplate
|
|
template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
|
|
+ try:
|
|
+ ldb.delete(template_dn)
|
|
+ except _ldb.LdbError:
|
|
+ pass
|
|
+
|
|
+ self.addCleanup(ldb.delete, template_dn)
|
|
ldb.add({'dn': template_dn,
|
|
'objectClass': 'pKICertificateTemplate',
|
|
})
|
|
|
|
with TemporaryDirectory() as dname:
|
|
- ext.process_group_policy([], gpos, dname, dname)
|
|
+ try:
|
|
+ ext.process_group_policy([], gpos, dname, dname)
|
|
+ except Exception as e:
|
|
+ self.fail(f"process_group_policy() raised {e}")
|
|
ca_list = [ca_cn, 'example0-com-CA', 'example1-com-CA',
|
|
'example2-com-CA']
|
|
for ca in ca_list:
|
|
@@ -7751,11 +7764,6 @@ class GPOTests(tests.TestCase):
|
|
self.assertNotIn(b'Workstation', out,
|
|
'Workstation certificate not removed')
|
|
|
|
- # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
|
|
- ldb.delete(certa_dn)
|
|
- ldb.delete(enroll_dn)
|
|
- ldb.delete(template_dn)
|
|
-
|
|
# Unstage the Registry.pol file
|
|
unstage_file(reg_pol)
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From eb449819e1acaa88249f398e15a19ede9adf49b9 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Mon, 23 Feb 2026 11:01:57 +1300
|
|
Subject: [PATCH 39/66] CVE-2026-3012: do not fetch certificate over http
|
|
|
|
In the case where a certificate was found via HTTP, it was trusted
|
|
without verification and put in the global CA store.
|
|
|
|
There is no means to check the certificate other than by comparing it
|
|
to certificates we may have gathered via LDAP, but in that case there
|
|
is no advantage over just using the LDAP-derived certificates.
|
|
|
|
Using the LDAP certificates was already the fallback case if HTTP
|
|
failed, so we just make it the default.
|
|
|
|
The HTTP fetch depends on the NDES service, which is a variant of
|
|
Simple Certificate Enrolment Protocol (SCEP, RFC8894), but in fact
|
|
Samba implements none of that protocol other than the HTTP fetch. SCEP
|
|
is for clients that are not true domain members. Domain members can
|
|
access to certificates over LDAP. This patch is not reducing SCEP
|
|
client support because Samba never had it.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16003
|
|
|
|
Reported-by: Arad Inbar, DREAM Security Research Team
|
|
Reported-by: Nir Somech, DREAM Security Research Team
|
|
Reported-by: Ben Grinberg, DREAM Security Research Team
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
|
|
---
|
|
python/samba/gp/gp_cert_auto_enroll_ext.py | 54 ++++------------------
|
|
selftest/knownfail.d/gpo-auto-enrol | 2 +
|
|
2 files changed, 11 insertions(+), 45 deletions(-)
|
|
create mode 100644 selftest/knownfail.d/gpo-auto-enrol
|
|
|
|
diff --git a/python/samba/gp/gp_cert_auto_enroll_ext.py b/python/samba/gp/gp_cert_auto_enroll_ext.py
|
|
index 877659b043e..815436e11e9 100644
|
|
--- a/python/samba/gp/gp_cert_auto_enroll_ext.py
|
|
+++ b/python/samba/gp/gp_cert_auto_enroll_ext.py
|
|
@@ -16,7 +16,6 @@
|
|
|
|
import os
|
|
import operator
|
|
-import requests
|
|
from samba.gp.gpclass import gp_pol_ext, gp_applier, GPOSTATE
|
|
from samba import Ldb
|
|
from samba.dcerpc import misc
|
|
@@ -195,58 +194,24 @@ def get_supported_templates(server):
|
|
return out.strip().split()
|
|
|
|
|
|
-def getca(ca, url, trust_dir):
|
|
- """Fetch Certificate Chain from the CA."""
|
|
+def getca(ca, trust_dir):
|
|
+ """Fetch a certificate from LDAP."""
|
|
root_cert = os.path.join(trust_dir, '%s.crt' % ca['name'])
|
|
root_certs = []
|
|
-
|
|
- try:
|
|
- r = requests.get(url=url, params={'operation': 'GetCACert',
|
|
- 'message': 'CAIdentifier'})
|
|
- except requests.exceptions.ConnectionError:
|
|
- log.warn('Could not connect to Network Device Enrollment Service.')
|
|
- r = None
|
|
- if r is None or r.content == b'' or r.headers['Content-Type'] == 'text/html':
|
|
- log.warn('Unable to fetch root certificates (requires NDES).')
|
|
- if 'cACertificate' in ca:
|
|
- log.warn('Installing the server certificate only.')
|
|
- der_certificate = base64.b64decode(ca['cACertificate'])
|
|
- try:
|
|
- cert = load_der_x509_certificate(der_certificate)
|
|
- except TypeError:
|
|
- cert = load_der_x509_certificate(der_certificate,
|
|
- default_backend())
|
|
- cert_data = cert.public_bytes(Encoding.PEM)
|
|
- with open(root_cert, 'wb') as w:
|
|
- w.write(cert_data)
|
|
- root_certs.append(root_cert)
|
|
- return root_certs
|
|
-
|
|
- if r.headers['Content-Type'] == 'application/x-x509-ca-cert':
|
|
- # Older versions of load_der_x509_certificate require a backend param
|
|
+ if 'cACertificate' in ca:
|
|
+ log.warn('Installing the server certificate only.')
|
|
+ der_certificate = base64.b64decode(ca['cACertificate'])
|
|
try:
|
|
- cert = load_der_x509_certificate(r.content)
|
|
+ cert = load_der_x509_certificate(der_certificate)
|
|
except TypeError:
|
|
- cert = load_der_x509_certificate(r.content, default_backend())
|
|
+ cert = load_der_x509_certificate(der_certificate,
|
|
+ default_backend())
|
|
cert_data = cert.public_bytes(Encoding.PEM)
|
|
with open(root_cert, 'wb') as w:
|
|
w.write(cert_data)
|
|
root_certs.append(root_cert)
|
|
- elif r.headers['Content-Type'] == 'application/x-x509-ca-ra-cert':
|
|
- certs = load_der_pkcs7_certificates(r.content)
|
|
- for i in range(0, len(certs)):
|
|
- cert = certs[i].public_bytes(Encoding.PEM)
|
|
- filename, extension = root_cert.rsplit('.', 1)
|
|
- dest = '%s.%d.%s' % (filename, i, extension)
|
|
- with open(dest, 'wb') as w:
|
|
- w.write(cert)
|
|
- root_certs.append(dest)
|
|
- else:
|
|
- log.warn('getca: Wrong (or missing) MIME content type')
|
|
-
|
|
return root_certs
|
|
|
|
-
|
|
def find_global_trust_dir():
|
|
"""Return the global trust dir using known paths from various Linux distros."""
|
|
for trust_dir in global_trust_dirs:
|
|
@@ -266,11 +231,10 @@ def changed(new_data, old_data):
|
|
def cert_enroll(ca, ldb, trust_dir, private_dir, auth='Kerberos'):
|
|
"""Install the root certificate chain."""
|
|
data = dict({'files': [], 'templates': []}, **ca)
|
|
- url = 'http://%s/CertSrv/mscep/mscep.dll/pkiclient.exe?' % ca['hostname']
|
|
|
|
log.info("Try to get root or server certificates")
|
|
|
|
- root_certs = getca(ca, url, trust_dir)
|
|
+ root_certs = getca(ca, trust_dir)
|
|
data['files'].extend(root_certs)
|
|
global_trust_dir = find_global_trust_dir()
|
|
for src in root_certs:
|
|
diff --git a/selftest/knownfail.d/gpo-auto-enrol b/selftest/knownfail.d/gpo-auto-enrol
|
|
new file mode 100644
|
|
index 00000000000..4bf4b8e3c72
|
|
--- /dev/null
|
|
+++ b/selftest/knownfail.d/gpo-auto-enrol
|
|
@@ -0,0 +1,2 @@
|
|
+^samba\.tests\.gpo\.samba\.tests\.gpo\.GPOTests\.test_advanced_gp_cert_auto_enroll_ext\(ad_dc:local\)
|
|
+^samba\.tests\.gpo\.samba\.tests\.gpo\.GPOTests\.test_gp_cert_auto_enroll_ext\(ad_dc:local\)
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From a8fc1666366716af45336f32af48826cefd5435e Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Thu, 26 Feb 2026 14:21:01 +1300
|
|
Subject: [PATCH 40/66] CVE-2026-3012: gp_auto_enrol: skip CAs not found in
|
|
LDAP
|
|
|
|
If a certificate is mentioned in a GPO but is not present as a
|
|
cACertificate attribute on a pKIEnrollmentService object, we have no way
|
|
of obtaining it, so we might as well forget it.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16003
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
|
|
---
|
|
python/samba/gp/gp_cert_auto_enroll_ext.py | 10 ++++++++++
|
|
1 file changed, 10 insertions(+)
|
|
|
|
diff --git a/python/samba/gp/gp_cert_auto_enroll_ext.py b/python/samba/gp/gp_cert_auto_enroll_ext.py
|
|
index 815436e11e9..de8b310afd9 100644
|
|
--- a/python/samba/gp/gp_cert_auto_enroll_ext.py
|
|
+++ b/python/samba/gp/gp_cert_auto_enroll_ext.py
|
|
@@ -452,11 +452,21 @@ class gp_cert_auto_enroll_ext(gp_pol_ext, gp_applier):
|
|
# This is a basic configuration.
|
|
cas = fetch_certification_authorities(ldb)
|
|
for _ca in cas:
|
|
+ if 'cACertificate' not in _ca:
|
|
+ log.warning(f"ignoring CA '{_ca['name']}' with no "
|
|
+ "cACertificate in LDAP.")
|
|
+ continue
|
|
+
|
|
self.apply(guid, _ca, cert_enroll, _ca, ldb, trust_dir,
|
|
private_dir)
|
|
ca_names.append(_ca['name'])
|
|
# If EndPoint.URI starts with "HTTPS//":
|
|
elif ca['URL'].lower().startswith('https://'):
|
|
+ if 'cACertificate' not in ca:
|
|
+ log.warning(f"ignoring CA '{ca['name']}' "
|
|
+ f"({ca['URL']}) with no "
|
|
+ "cACertificate in LDAP.")
|
|
+ continue
|
|
self.apply(guid, ca, cert_enroll, ca, ldb, trust_dir,
|
|
private_dir, auth=ca['auth'])
|
|
ca_names.append(ca['name'])
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From cd0a831279bbe890b64898f5a1892bf8c73cfca7 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Fri, 27 Feb 2026 14:46:04 +1300
|
|
Subject: [PATCH 41/66] CVE-2026-3012: gpo tests should use real certificates
|
|
|
|
Or at least, more real than a short arbitrary byte string, so that
|
|
the certificates can be parsed.
|
|
|
|
This shows that certificate enrolment works via LDAP in the situations
|
|
where we would have fetched them via HTTP.
|
|
|
|
This does not fix the advanced_gp_cert_auto_enroll_ext test which
|
|
wants to install certificates it has no access too. This will not be
|
|
fixed in the security release.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16003
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
|
|
---
|
|
python/samba/tests/gpo.py | 8 ++++----
|
|
selftest/knownfail.d/gpo-auto-enrol | 1 -
|
|
2 files changed, 4 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py
|
|
index 0972cd2f63c..5bdee29b50a 100644
|
|
--- a/python/samba/tests/gpo.py
|
|
+++ b/python/samba/tests/gpo.py
|
|
@@ -7062,7 +7062,7 @@ class GPOTests(tests.TestCase):
|
|
ldb.add({'dn': certa_dn,
|
|
'objectClass': 'certificationAuthority',
|
|
'authorityRevocationList': ['XXX'],
|
|
- 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
|
|
+ 'cACertificate': dummy_certificate(),
|
|
'certificateRevocationList': ['XXX'],
|
|
})
|
|
# Write the dummy pKIEnrollmentService
|
|
@@ -7070,7 +7070,7 @@ class GPOTests(tests.TestCase):
|
|
self.addCleanup(ldb.delete, enroll_dn)
|
|
ldb.add({'dn': enroll_dn,
|
|
'objectClass': 'pKIEnrollmentService',
|
|
- 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
|
|
+ 'cACertificate': dummy_certificate(),
|
|
'certificateTemplates': ['Machine'],
|
|
'dNSHostName': hostname,
|
|
})
|
|
@@ -7673,7 +7673,7 @@ class GPOTests(tests.TestCase):
|
|
ldb.add({'dn': certa_dn,
|
|
'objectClass': 'certificationAuthority',
|
|
'authorityRevocationList': ['XXX'],
|
|
- 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
|
|
+ 'cACertificate': dummy_certificate(),
|
|
'certificateRevocationList': ['XXX'],
|
|
})
|
|
# Write the dummy pKIEnrollmentService
|
|
@@ -7681,7 +7681,7 @@ class GPOTests(tests.TestCase):
|
|
self.addCleanup(ldb.delete, enroll_dn)
|
|
ldb.add({'dn': enroll_dn,
|
|
'objectClass': 'pKIEnrollmentService',
|
|
- 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
|
|
+ 'cACertificate': dummy_certificate(),
|
|
'certificateTemplates': ['Machine'],
|
|
'dNSHostName': hostname,
|
|
})
|
|
diff --git a/selftest/knownfail.d/gpo-auto-enrol b/selftest/knownfail.d/gpo-auto-enrol
|
|
index 4bf4b8e3c72..4b787a5ac86 100644
|
|
--- a/selftest/knownfail.d/gpo-auto-enrol
|
|
+++ b/selftest/knownfail.d/gpo-auto-enrol
|
|
@@ -1,2 +1 @@
|
|
^samba\.tests\.gpo\.samba\.tests\.gpo\.GPOTests\.test_advanced_gp_cert_auto_enroll_ext\(ad_dc:local\)
|
|
-^samba\.tests\.gpo\.samba\.tests\.gpo\.GPOTests\.test_gp_cert_auto_enroll_ext\(ad_dc:local\)
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 39970373fe70615e28b0fe6e56169b0e3674b95a Mon Sep 17 00:00:00 2001
|
|
From: Volker Lendecke <vl@samba.org>
|
|
Date: Tue, 24 Feb 2026 16:11:15 +0100
|
|
Subject: [PATCH 42/66] CVE-2026-3238 winsserver4: Dissolve direct variable
|
|
initialization
|
|
|
|
Checks are required before the packet is dereferenced
|
|
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=16012
|
|
Signed-off-by: Volker Lendecke <vl@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source4/nbt_server/wins/winsserver.c | 27 +++++++++++++++++++++------
|
|
1 file changed, 21 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
|
|
index 6679961dc03..1b7fe5641a6 100644
|
|
--- a/source4/nbt_server/wins/winsserver.c
|
|
+++ b/source4/nbt_server/wins/winsserver.c
|
|
@@ -460,16 +460,27 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
|
|
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
|
|
struct nbtd_interface);
|
|
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
|
- struct nbt_name *name = &packet->questions[0].name;
|
|
+ struct nbt_name *name = NULL;
|
|
struct winsdb_record *rec;
|
|
uint8_t rcode = NBT_RCODE_OK;
|
|
- uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
|
|
- const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
|
|
+ struct nbt_res_rec *additional = NULL;
|
|
+ uint16_t nb_flags;
|
|
+ const char *address = NULL;
|
|
+ struct nbt_rdata_address *addresses = NULL;
|
|
bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
|
|
- enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
|
|
+ enum wrepl_name_type new_type;
|
|
struct winsdb_addr *winsdb_addr = NULL;
|
|
bool duplicate_packet;
|
|
|
|
+ name = &packet->questions[0].name;
|
|
+ additional = packet->additional;
|
|
+
|
|
+ addresses = additional[0].rdata.netbios.addresses;
|
|
+
|
|
+ nb_flags = addresses[0].nb_flags;
|
|
+ address = addresses[0].ipaddr;
|
|
+ new_type = wrepl_type(nb_flags, name, mhomed);
|
|
+
|
|
/*
|
|
* as a special case, the local master browser name is always accepted
|
|
* for registration, but never stored, but w2k3 stores it if it's registered
|
|
@@ -729,13 +740,15 @@ static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
|
|
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
|
|
struct nbtd_interface);
|
|
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
|
- struct nbt_name *name = &packet->questions[0].name;
|
|
+ struct nbt_name *name = NULL;
|
|
struct winsdb_record *rec;
|
|
struct winsdb_record *rec_1b = NULL;
|
|
const char **addresses;
|
|
const char **addresses_1b = NULL;
|
|
uint16_t nb_flags = 0;
|
|
|
|
+ name = &packet->questions[0].name;
|
|
+
|
|
if (name->type == NBT_NAME_MASTER) {
|
|
goto notfound;
|
|
}
|
|
@@ -871,11 +884,13 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
|
|
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
|
|
struct nbtd_interface);
|
|
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
|
- struct nbt_name *name = &packet->questions[0].name;
|
|
+ struct nbt_name *name = NULL;
|
|
struct winsdb_record *rec;
|
|
uint32_t modify_flags = 0;
|
|
uint8_t ret;
|
|
|
|
+ name = &packet->questions[0].name;
|
|
+
|
|
if (name->type == NBT_NAME_MASTER) {
|
|
goto done;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From a9c5255d1e46738e8148152721aa49add737e64b Mon Sep 17 00:00:00 2001
|
|
From: Volker Lendecke <vl@samba.org>
|
|
Date: Tue, 24 Feb 2026 16:30:46 +0100
|
|
Subject: [PATCH 43/66] CVE-2026-3238 winsserver4: Validate incoming packets
|
|
|
|
Avoid NULL pointer dereferences, leading to a crash in the nbt process
|
|
serving wins.
|
|
|
|
Thanks to Arad Inbar, Erez Cohen, Nir Somech and Ben Grinberg from
|
|
DREAM Security Research Team for pointing out this crash bug out to
|
|
the Samba team.
|
|
|
|
Bug: https://bugzilla.samba.org/show_bug.cgi?id=16012
|
|
Signed-off-by: Volker Lendecke <vl@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source4/nbt_server/wins/winsserver.c | 11 +++++++++++
|
|
1 file changed, 11 insertions(+)
|
|
|
|
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
|
|
index 1b7fe5641a6..c637657f07c 100644
|
|
--- a/source4/nbt_server/wins/winsserver.c
|
|
+++ b/source4/nbt_server/wins/winsserver.c
|
|
@@ -472,9 +472,16 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
|
|
struct winsdb_addr *winsdb_addr = NULL;
|
|
bool duplicate_packet;
|
|
|
|
+ NBTD_ASSERT_PACKET(packet, src, packet->qdcount > 0);
|
|
+ NBTD_ASSERT_PACKET(packet, src, packet->arcount > 0);
|
|
+
|
|
name = &packet->questions[0].name;
|
|
additional = packet->additional;
|
|
|
|
+ NBTD_ASSERT_PACKET(packet,
|
|
+ src,
|
|
+ additional[0].rdata.netbios.length > 0);
|
|
+
|
|
addresses = additional[0].rdata.netbios.addresses;
|
|
|
|
nb_flags = addresses[0].nb_flags;
|
|
@@ -747,6 +754,8 @@ static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
|
|
const char **addresses_1b = NULL;
|
|
uint16_t nb_flags = 0;
|
|
|
|
+ NBTD_ASSERT_PACKET(packet, src, packet->qdcount > 0);
|
|
+
|
|
name = &packet->questions[0].name;
|
|
|
|
if (name->type == NBT_NAME_MASTER) {
|
|
@@ -889,6 +898,8 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
|
|
uint32_t modify_flags = 0;
|
|
uint8_t ret;
|
|
|
|
+ NBTD_ASSERT_PACKET(packet, src, packet->qdcount > 0);
|
|
+
|
|
name = &packet->questions[0].name;
|
|
|
|
if (name->type == NBT_NAME_MASTER) {
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From ae5323f5bacb2d461a663cc34ba33c9c0fa05f8e Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 18:20:15 +0200
|
|
Subject: [PATCH 44/66] CVE-2026-4480/CVE-2026-4408: lib/util: inline
|
|
string_sub2() into string_sub() the only caller
|
|
|
|
This will simplify further changes.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.c | 20 ++------------------
|
|
1 file changed, 2 insertions(+), 18 deletions(-)
|
|
|
|
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
|
|
index b7b5588da86..26362ca77b2 100644
|
|
--- a/lib/util/substitute.c
|
|
+++ b/lib/util/substitute.c
|
|
@@ -47,10 +47,9 @@
|
|
use of len==0 which was for no length checks to be done.
|
|
**/
|
|
|
|
-static void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
|
|
- bool remove_unsafe_characters, bool replace_once,
|
|
- bool allow_trailing_dollar)
|
|
+void string_sub(char *s, const char *pattern, const char *insert, size_t len)
|
|
{
|
|
+ bool remove_unsafe_characters = true;
|
|
char *p;
|
|
size_t ls, lp, li, i;
|
|
|
|
@@ -79,13 +78,6 @@ static void string_sub2(char *s,const char *pattern, const char *insert, size_t
|
|
for (i=0;i<li;i++) {
|
|
switch (insert[i]) {
|
|
case '$':
|
|
- /* allow a trailing $
|
|
- * (as in machine accounts) */
|
|
- if (allow_trailing_dollar && (i == li - 1 )) {
|
|
- p[i] = insert[i];
|
|
- break;
|
|
- }
|
|
- FALL_THROUGH;
|
|
case '`':
|
|
case '"':
|
|
case '\'':
|
|
@@ -107,17 +99,9 @@ static void string_sub2(char *s,const char *pattern, const char *insert, size_t
|
|
}
|
|
s = p + li;
|
|
ls = ls + li - lp;
|
|
-
|
|
- if (replace_once)
|
|
- break;
|
|
}
|
|
}
|
|
|
|
-void string_sub(char *s,const char *pattern, const char *insert, size_t len)
|
|
-{
|
|
- string_sub2( s, pattern, insert, len, true, false, false );
|
|
-}
|
|
-
|
|
/**
|
|
Similar to string_sub() but allows for any character to be substituted.
|
|
Use with caution!
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From cc8fb24520b1c11e5b43714333d642fdb02449cb Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 18:20:15 +0200
|
|
Subject: [PATCH 45/66] CVE-2026-4480/CVE-2026-4408: lib/util: remove unused
|
|
talloc_strdup(insert) from talloc_string_sub2()
|
|
|
|
The insert string is not modified, so we do not need to copy it.
|
|
|
|
This will simplify further changes.
|
|
|
|
Review with: git show --patience
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.c | 57 +++++++++++++++++++------------------------
|
|
1 file changed, 25 insertions(+), 32 deletions(-)
|
|
|
|
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
|
|
index 26362ca77b2..4a0c58ab3a7 100644
|
|
--- a/lib/util/substitute.c
|
|
+++ b/lib/util/substitute.c
|
|
@@ -157,7 +157,7 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
bool replace_once,
|
|
bool allow_trailing_dollar)
|
|
{
|
|
- char *p, *in;
|
|
+ char *p;
|
|
char *s;
|
|
char *string;
|
|
ssize_t ls,lp,li,ld, i;
|
|
@@ -175,22 +175,32 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
|
|
s = string;
|
|
|
|
- in = talloc_strdup(mem_ctx, insert);
|
|
- if (!in) {
|
|
- DEBUG(0, ("talloc_string_sub2: ENOMEM\n"));
|
|
- talloc_free(string);
|
|
- return NULL;
|
|
- }
|
|
ls = (ssize_t)strlen(s);
|
|
lp = (ssize_t)strlen(pattern);
|
|
li = (ssize_t)strlen(insert);
|
|
ld = li - lp;
|
|
|
|
- for (i=0;i<li;i++) {
|
|
- switch (in[i]) {
|
|
+ while ((p = strstr_m(s,pattern))) {
|
|
+ if (ld > 0) {
|
|
+ int offset = PTR_DIFF(s,string);
|
|
+ string = (char *)talloc_realloc_size(mem_ctx, string,
|
|
+ ls + ld + 1);
|
|
+ if (!string) {
|
|
+ DEBUG(0, ("talloc_string_sub: out of "
|
|
+ "memory!\n"));
|
|
+ return NULL;
|
|
+ }
|
|
+ p = string + offset + (p - s);
|
|
+ }
|
|
+ if (li != lp) {
|
|
+ memmove(p+li,p+lp,strlen(p+lp)+1);
|
|
+ }
|
|
+ for (i=0; i<li; i++) {
|
|
+ switch (insert[i]) {
|
|
case '$':
|
|
- /* allow a trailing $
|
|
- * (as in machine accounts) */
|
|
+ /*
|
|
+ * allow a trailing $ (as in machine accounts)
|
|
+ */
|
|
if (allow_trailing_dollar && (i == li - 1 )) {
|
|
break;
|
|
}
|
|
@@ -204,34 +214,18 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
case '\r':
|
|
case '\n':
|
|
if (remove_unsafe_characters) {
|
|
- in[i] = '_';
|
|
- break;
|
|
+ p[i] = '_';
|
|
+ continue;
|
|
}
|
|
|
|
FALL_THROUGH;
|
|
default:
|
|
/* ok */
|
|
break;
|
|
- }
|
|
- }
|
|
-
|
|
- while ((p = strstr_m(s,pattern))) {
|
|
- if (ld > 0) {
|
|
- int offset = PTR_DIFF(s,string);
|
|
- string = (char *)talloc_realloc_size(mem_ctx, string,
|
|
- ls + ld + 1);
|
|
- if (!string) {
|
|
- DEBUG(0, ("talloc_string_sub: out of "
|
|
- "memory!\n"));
|
|
- TALLOC_FREE(in);
|
|
- return NULL;
|
|
}
|
|
- p = string + offset + (p - s);
|
|
- }
|
|
- if (li != lp) {
|
|
- memmove(p+li,p+lp,strlen(p+lp)+1);
|
|
+
|
|
+ p[i] = insert[i];
|
|
}
|
|
- memcpy(p, in, li);
|
|
s = p + li;
|
|
ls += ld;
|
|
|
|
@@ -239,7 +233,6 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
break;
|
|
}
|
|
}
|
|
- TALLOC_FREE(in);
|
|
return string;
|
|
}
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 1a672e8ba0300ab2067e50fd7bb53a7e3fa7a194 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 18:20:15 +0200
|
|
Subject: [PATCH 46/66] CVE-2026-4480/CVE-2026-4408: lib/util: factor out a
|
|
mask_unsafe_character() helper function
|
|
|
|
This moves the logic into a single place and
|
|
makes if more flexible to be used with more
|
|
values than STRING_SUB_UNSAFE_CHARACTERS.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.c | 109 +++++++++++++++++++++---------------------
|
|
lib/util/substitute.h | 6 ++-
|
|
2 files changed, 60 insertions(+), 55 deletions(-)
|
|
|
|
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
|
|
index 4a0c58ab3a7..b9fe32e993e 100644
|
|
--- a/lib/util/substitute.c
|
|
+++ b/lib/util/substitute.c
|
|
@@ -35,6 +35,33 @@
|
|
* @brief Substitute utilities.
|
|
**/
|
|
|
|
+static inline
|
|
+char mask_unsafe_character(char in,
|
|
+ bool is_last,
|
|
+ bool allow_trailing_dollar,
|
|
+ const char *unsafe_characters,
|
|
+ char safe_out)
|
|
+{
|
|
+ const char *unsafe = NULL;
|
|
+
|
|
+ if (unsafe_characters == NULL) {
|
|
+ return in;
|
|
+ }
|
|
+
|
|
+ /* allow a trailing $ (as in machine accounts) */
|
|
+ if (allow_trailing_dollar && is_last && in == '$') {
|
|
+ return in;
|
|
+ }
|
|
+
|
|
+ unsafe = strchr(unsafe_characters, in);
|
|
+ if (unsafe != NULL) {
|
|
+ return safe_out;
|
|
+ }
|
|
+
|
|
+ /* ok */
|
|
+ return in;
|
|
+}
|
|
+
|
|
/**
|
|
Substitute a string for a pattern in another string. Make sure there is
|
|
enough room!
|
|
@@ -42,14 +69,16 @@
|
|
This routine looks for pattern in s and replaces it with
|
|
insert. It may do multiple replacements or just one.
|
|
|
|
- Any of " ; ' $ or ` in the insert string are replaced with _
|
|
+ Any of STRING_SUB_UNSAFE_CHARACTERS in the insert string are replaced with _
|
|
+
|
|
if len==0 then the string cannot be extended. This is different from the old
|
|
use of len==0 which was for no length checks to be done.
|
|
**/
|
|
|
|
void string_sub(char *s, const char *pattern, const char *insert, size_t len)
|
|
{
|
|
- bool remove_unsafe_characters = true;
|
|
+ const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
+ char safe_character = '_';
|
|
char *p;
|
|
size_t ls, lp, li, i;
|
|
|
|
@@ -76,26 +105,18 @@ void string_sub(char *s, const char *pattern, const char *insert, size_t len)
|
|
memmove(p+li,p+lp,strlen(p+lp)+1);
|
|
}
|
|
for (i=0;i<li;i++) {
|
|
- switch (insert[i]) {
|
|
- case '$':
|
|
- case '`':
|
|
- case '"':
|
|
- case '\'':
|
|
- case ';':
|
|
- case '%':
|
|
- case '\r':
|
|
- case '\n':
|
|
- if ( remove_unsafe_characters ) {
|
|
- p[i] = '_';
|
|
- /* yes this break should be here
|
|
- * since we want to fall throw if
|
|
- * not replacing unsafe chars */
|
|
- break;
|
|
- }
|
|
- FALL_THROUGH;
|
|
- default:
|
|
- p[i] = insert[i];
|
|
- }
|
|
+ /*
|
|
+ * Without allow_trailing_dollar we don't
|
|
+ * need to calculate is_last...
|
|
+ */
|
|
+ const bool is_last = false;
|
|
+ const bool allow_trailing_dollar = false;
|
|
+
|
|
+ p[i] = mask_unsafe_character(insert[i],
|
|
+ is_last,
|
|
+ allow_trailing_dollar,
|
|
+ unsafe_characters,
|
|
+ safe_character);
|
|
}
|
|
s = p + li;
|
|
ls = ls + li - lp;
|
|
@@ -157,9 +178,11 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
bool replace_once,
|
|
bool allow_trailing_dollar)
|
|
{
|
|
- char *p;
|
|
- char *s;
|
|
- char *string;
|
|
+ const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
+ const char safe_character = '_';
|
|
+ char *p = NULL,
|
|
+ char *s = NULL;
|
|
+ char *string = NULL;
|
|
ssize_t ls,lp,li,ld, i;
|
|
|
|
if (!insert || !pattern || !*pattern || !src) {
|
|
@@ -195,36 +218,14 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
if (li != lp) {
|
|
memmove(p+li,p+lp,strlen(p+lp)+1);
|
|
}
|
|
- for (i=0; i<li; i++) {
|
|
- switch (insert[i]) {
|
|
- case '$':
|
|
- /*
|
|
- * allow a trailing $ (as in machine accounts)
|
|
- */
|
|
- if (allow_trailing_dollar && (i == li - 1 )) {
|
|
- break;
|
|
- }
|
|
-
|
|
- FALL_THROUGH;
|
|
- case '`':
|
|
- case '"':
|
|
- case '\'':
|
|
- case ';':
|
|
- case '%':
|
|
- case '\r':
|
|
- case '\n':
|
|
- if (remove_unsafe_characters) {
|
|
- p[i] = '_';
|
|
- continue;
|
|
- }
|
|
-
|
|
- FALL_THROUGH;
|
|
- default:
|
|
- /* ok */
|
|
- break;
|
|
- }
|
|
+ for (i=0; i < li; i++) {
|
|
+ bool is_last = (i == li - 1);
|
|
|
|
- p[i] = insert[i];
|
|
+ p[i] = mask_unsafe_character(insert[i],
|
|
+ is_last,
|
|
+ allow_trailing_dollar,
|
|
+ unsafe_characters,
|
|
+ safe_character);
|
|
}
|
|
s = p + li;
|
|
ls += ld;
|
|
diff --git a/lib/util/substitute.h b/lib/util/substitute.h
|
|
index 3134cfcdea5..e1a82859dac 100644
|
|
--- a/lib/util/substitute.h
|
|
+++ b/lib/util/substitute.h
|
|
@@ -26,6 +26,8 @@
|
|
|
|
#include <talloc.h>
|
|
|
|
+#define STRING_SUB_UNSAFE_CHARACTERS "$`\"';%\r\n"
|
|
+
|
|
/**
|
|
Substitute a string for a pattern in another string. Make sure there is
|
|
enough room!
|
|
@@ -33,7 +35,9 @@
|
|
This routine looks for pattern in s and replaces it with
|
|
insert. It may do multiple replacements.
|
|
|
|
- Any of " ; ' $ or ` in the insert string are replaced with _
|
|
+ Any of STRING_SUB_UNSAFE_CHARACTERS (see above) in the
|
|
+ insert string are replaced with _
|
|
+
|
|
if len==0 then the string cannot be extended. This is different from the old
|
|
use of len==0 which was for no length checks to be done.
|
|
**/
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From f311078eae4731ca2af8a14c1d4091e7263ca507 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 30 Apr 2026 14:48:26 +0200
|
|
Subject: [PATCH 47/66] CVE-2026-4480/CVE-2026-4408: lib/util: split out
|
|
realloc_string_sub_raw()
|
|
|
|
This will allow realloc_string_sub2() to use it in order
|
|
to have the logic in one place only.
|
|
|
|
And it will also allow adjacted callers to be
|
|
more flexible.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.c | 85 ++++++++++++++++++++++++++++++-------------
|
|
lib/util/substitute.h | 18 +++++++++
|
|
2 files changed, 78 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
|
|
index b9fe32e993e..465aea86605 100644
|
|
--- a/lib/util/substitute.c
|
|
+++ b/lib/util/substitute.c
|
|
@@ -171,32 +171,24 @@ _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, siz
|
|
* talloc version of string_sub2.
|
|
*/
|
|
|
|
-char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
- const char *pattern,
|
|
- const char *insert,
|
|
- bool remove_unsafe_characters,
|
|
- bool replace_once,
|
|
- bool allow_trailing_dollar)
|
|
+bool realloc_string_sub_raw(char **_string,
|
|
+ const char *pattern,
|
|
+ const char *insert,
|
|
+ bool replace_once,
|
|
+ bool allow_trailing_dollar,
|
|
+ const char *unsafe_characters,
|
|
+ char safe_character)
|
|
{
|
|
- const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
- const char safe_character = '_';
|
|
- char *p = NULL,
|
|
+ char *p = NULL;
|
|
char *s = NULL;
|
|
char *string = NULL;
|
|
ssize_t ls,lp,li,ld, i;
|
|
|
|
- if (!insert || !pattern || !*pattern || !src) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- string = talloc_strdup(mem_ctx, src);
|
|
- if (string == NULL) {
|
|
- DEBUG(0, ("talloc_string_sub2: "
|
|
- "talloc_strdup failed\n"));
|
|
- return NULL;
|
|
+ if (!insert || !pattern || !*pattern || !_string|| !*_string) {
|
|
+ return false;
|
|
}
|
|
|
|
- s = string;
|
|
+ s = string = *_string;
|
|
|
|
ls = (ssize_t)strlen(s);
|
|
lp = (ssize_t)strlen(pattern);
|
|
@@ -205,14 +197,13 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
|
|
while ((p = strstr_m(s,pattern))) {
|
|
if (ld > 0) {
|
|
- int offset = PTR_DIFF(s,string);
|
|
- string = (char *)talloc_realloc_size(mem_ctx, string,
|
|
- ls + ld + 1);
|
|
+ ptrdiff_t offset = PTR_DIFF(s,string);
|
|
+ string = talloc_realloc(NULL, string, char, ls + ld + 1);
|
|
if (!string) {
|
|
- DEBUG(0, ("talloc_string_sub: out of "
|
|
- "memory!\n"));
|
|
- return NULL;
|
|
+ DBG_ERR("out of memory(realloc)!\n");
|
|
+ return false;
|
|
}
|
|
+ *_string = string;
|
|
p = string + offset + (p - s);
|
|
}
|
|
if (li != lp) {
|
|
@@ -234,6 +225,50 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
break;
|
|
}
|
|
}
|
|
+ return true;
|
|
+}
|
|
+
|
|
+char *talloc_string_sub2(TALLOC_CTX *mem_ctx,
|
|
+ const char *src,
|
|
+ const char *pattern,
|
|
+ const char *insert,
|
|
+ bool remove_unsafe_characters,
|
|
+ bool replace_once,
|
|
+ bool allow_trailing_dollar)
|
|
+{
|
|
+ const char *unsafe_characters = NULL;
|
|
+ char safe_character = '\0';
|
|
+ char *string = NULL;
|
|
+ bool ok;
|
|
+
|
|
+ if (!insert || !pattern || !*pattern || !src) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (remove_unsafe_characters) {
|
|
+ unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
+ safe_character = '_';
|
|
+ }
|
|
+
|
|
+ string = talloc_strdup(mem_ctx, src);
|
|
+ if (string == NULL) {
|
|
+ DBG_ERR("out of memory, talloc_strdup(src)!\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ ok = realloc_string_sub_raw(&string,
|
|
+ pattern,
|
|
+ insert,
|
|
+ replace_once,
|
|
+ allow_trailing_dollar,
|
|
+ unsafe_characters,
|
|
+ safe_character);
|
|
+ if (!ok) {
|
|
+ TALLOC_FREE(string);
|
|
+ DBG_ERR("out of memory, realloc_string_sub_raw()!\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
return string;
|
|
}
|
|
|
|
diff --git a/lib/util/substitute.h b/lib/util/substitute.h
|
|
index e1a82859dac..041a649fd18 100644
|
|
--- a/lib/util/substitute.h
|
|
+++ b/lib/util/substitute.h
|
|
@@ -51,6 +51,24 @@ void string_sub(char *s,const char *pattern, const char *insert, size_t len);
|
|
**/
|
|
void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
|
|
|
|
+/*
|
|
+ * If unsafe_characters is NULL all characters are allowed,
|
|
+ * if unsafe_characters is not NULL all characters caught
|
|
+ * by iscntrl() are also replaced by safe_character.
|
|
+ *
|
|
+ * *_string might be reallocated!
|
|
+ *
|
|
+ * On error *_string may still be reallocated and
|
|
+ * may contain partial replacements.
|
|
+ */
|
|
+bool realloc_string_sub_raw(char **_string,
|
|
+ const char *pattern,
|
|
+ const char *insert,
|
|
+ bool replace_once,
|
|
+ bool allow_trailing_dollar,
|
|
+ const char *unsafe_characters,
|
|
+ char safe_character);
|
|
+
|
|
char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
|
|
const char *pattern,
|
|
const char *insert,
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 3d28a71755b69b6e0afe5f5d9bbc9aff620b0f4f Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Wed, 6 May 2026 17:23:39 +0200
|
|
Subject: [PATCH 48/66] CVE-2026-4480/CVE-2026-4408: s3:lib: fix potential
|
|
memory leak in talloc_sub_basic()
|
|
|
|
This makes the code easier to understand...
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/lib/substitute.c | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/source3/lib/substitute.c b/source3/lib/substitute.c
|
|
index 40eb15aee04..5121fcaac1c 100644
|
|
--- a/source3/lib/substitute.c
|
|
+++ b/source3/lib/substitute.c
|
|
@@ -317,6 +317,7 @@ char *talloc_sub_basic(TALLOC_CTX *mem_ctx,
|
|
}
|
|
|
|
tmp_ctx = talloc_stackframe();
|
|
+ a_string = talloc_steal(tmp_ctx, a_string);
|
|
|
|
for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
|
|
|
|
@@ -478,6 +479,7 @@ error:
|
|
TALLOC_FREE(a_string);
|
|
|
|
done:
|
|
+ a_string = talloc_steal(mem_ctx, a_string);
|
|
TALLOC_FREE(tmp_ctx);
|
|
return a_string;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From c73fc960e67474ded96fdeebf3e2779e2b28799b Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 21:11:27 +0200
|
|
Subject: [PATCH 49/66] CVE-2026-4480/CVE-2026-4408: s3:lib: let
|
|
realloc_string_sub2() use realloc_string_sub_raw()
|
|
|
|
We don't need this logic more than once!
|
|
|
|
But we leave the strange calling convention of
|
|
realloc_string_sub2(), where the caller it
|
|
not allowed to use the passed pointer when
|
|
NULL is returned...
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/lib/substitute_generic.c | 81 ++++++++++----------------------
|
|
1 file changed, 24 insertions(+), 57 deletions(-)
|
|
|
|
diff --git a/source3/lib/substitute_generic.c b/source3/lib/substitute_generic.c
|
|
index 26c5ee761f8..e0639f04eb8 100644
|
|
--- a/source3/lib/substitute_generic.c
|
|
+++ b/source3/lib/substitute_generic.c
|
|
@@ -37,71 +37,38 @@ char *realloc_string_sub2(char *string,
|
|
bool remove_unsafe_characters,
|
|
bool allow_trailing_dollar)
|
|
{
|
|
- char *p, *in;
|
|
- char *s;
|
|
- ssize_t ls,lp,li,ld, i;
|
|
+ const char *unsafe_characters = NULL;
|
|
+ char safe_character = '\0';
|
|
+ bool ok;
|
|
|
|
if (!insert || !pattern || !*pattern || !string || !*string)
|
|
return NULL;
|
|
|
|
- s = string;
|
|
+ if (remove_unsafe_characters) {
|
|
+ unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
+ safe_character = '_';
|
|
+ }
|
|
|
|
- in = talloc_strdup(talloc_tos(), insert);
|
|
- if (!in) {
|
|
- DEBUG(0, ("realloc_string_sub: out of memory!\n"));
|
|
+ ok = realloc_string_sub_raw(&string,
|
|
+ pattern,
|
|
+ insert,
|
|
+ false, /* replace_once */
|
|
+ allow_trailing_dollar,
|
|
+ unsafe_characters,
|
|
+ safe_character);
|
|
+ if (!ok) {
|
|
+ DBG_ERR("out of memory, realloc_string_sub_raw()!\n");
|
|
+ /*
|
|
+ * The calling convention of realloc_string_sub2()
|
|
+ * is very strange regarding stale string pointers.
|
|
+ *
|
|
+ * It is assumed the given string was allocated
|
|
+ * on talloc_tos(), so we just don't touch
|
|
+ * it at all here...
|
|
+ */
|
|
return NULL;
|
|
}
|
|
- ls = (ssize_t)strlen(s);
|
|
- lp = (ssize_t)strlen(pattern);
|
|
- li = (ssize_t)strlen(insert);
|
|
- ld = li - lp;
|
|
- for (i=0;i<li;i++) {
|
|
- switch (in[i]) {
|
|
- case '$':
|
|
- /* allow a trailing $
|
|
- * (as in machine accounts) */
|
|
- if (allow_trailing_dollar && (i == li - 1 )) {
|
|
- break;
|
|
- }
|
|
- FALL_THROUGH;
|
|
- case '`':
|
|
- case '"':
|
|
- case '\'':
|
|
- case ';':
|
|
- case '%':
|
|
- case '\r':
|
|
- case '\n':
|
|
- if ( remove_unsafe_characters ) {
|
|
- in[i] = '_';
|
|
- break;
|
|
- }
|
|
- FALL_THROUGH;
|
|
- default:
|
|
- /* ok */
|
|
- break;
|
|
- }
|
|
- }
|
|
|
|
- while ((p = strstr_m(s,pattern))) {
|
|
- if (ld > 0) {
|
|
- int offset = PTR_DIFF(s,string);
|
|
- string = talloc_realloc(NULL, string, char, ls + ld + 1);
|
|
- if (!string) {
|
|
- DEBUG(0, ("realloc_string_sub: "
|
|
- "out of memory!\n"));
|
|
- talloc_free(in);
|
|
- return NULL;
|
|
- }
|
|
- p = string + offset + (p - s);
|
|
- }
|
|
- if (li != lp) {
|
|
- memmove(p+li,p+lp,strlen(p+lp)+1);
|
|
- }
|
|
- memcpy(p, in, li);
|
|
- s = p + li;
|
|
- ls += ld;
|
|
- }
|
|
- talloc_free(in);
|
|
return string;
|
|
}
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From fc4aa4b816bfe1c3c128acf2cbfac652899d4cb6 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 18:21:08 +0200
|
|
Subject: [PATCH 50/66] CVE-2026-4480/CVE-2026-4408: lib/util: let
|
|
mask_unsafe_character() check all control characters
|
|
|
|
There's no reason to mask only \r and \n.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.c | 8 +++++++-
|
|
lib/util/substitute.h | 6 +++---
|
|
2 files changed, 10 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
|
|
index 465aea86605..30989927da7 100644
|
|
--- a/lib/util/substitute.c
|
|
+++ b/lib/util/substitute.c
|
|
@@ -22,6 +22,7 @@
|
|
*/
|
|
|
|
#include "replace.h"
|
|
+#include "system/locale.h"
|
|
#include "debug.h"
|
|
#ifndef SAMBA_UTIL_CORE_ONLY
|
|
#include "charset/charset.h"
|
|
@@ -53,6 +54,10 @@ char mask_unsafe_character(char in,
|
|
return in;
|
|
}
|
|
|
|
+ if (iscntrl(in)) {
|
|
+ return safe_out;
|
|
+ }
|
|
+
|
|
unsafe = strchr(unsafe_characters, in);
|
|
if (unsafe != NULL) {
|
|
return safe_out;
|
|
@@ -69,7 +74,8 @@ char mask_unsafe_character(char in,
|
|
This routine looks for pattern in s and replaces it with
|
|
insert. It may do multiple replacements or just one.
|
|
|
|
- Any of STRING_SUB_UNSAFE_CHARACTERS in the insert string are replaced with _
|
|
+ Any of STRING_SUB_UNSAFE_CHARACTERS and any character
|
|
+ caught by calling iscntrl() in the insert string are replaced with _
|
|
|
|
if len==0 then the string cannot be extended. This is different from the old
|
|
use of len==0 which was for no length checks to be done.
|
|
diff --git a/lib/util/substitute.h b/lib/util/substitute.h
|
|
index 041a649fd18..b183d864671 100644
|
|
--- a/lib/util/substitute.h
|
|
+++ b/lib/util/substitute.h
|
|
@@ -26,7 +26,7 @@
|
|
|
|
#include <talloc.h>
|
|
|
|
-#define STRING_SUB_UNSAFE_CHARACTERS "$`\"';%\r\n"
|
|
+#define STRING_SUB_UNSAFE_CHARACTERS "$`\"';%"
|
|
|
|
/**
|
|
Substitute a string for a pattern in another string. Make sure there is
|
|
@@ -35,8 +35,8 @@
|
|
This routine looks for pattern in s and replaces it with
|
|
insert. It may do multiple replacements.
|
|
|
|
- Any of STRING_SUB_UNSAFE_CHARACTERS (see above) in the
|
|
- insert string are replaced with _
|
|
+ Any of STRING_SUB_UNSAFE_CHARACTERS (see above) and any character
|
|
+ caught by calling iscntrl() in the insert string are replaced with _
|
|
|
|
if len==0 then the string cannot be extended. This is different from the old
|
|
use of len==0 which was for no length checks to be done.
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From fbe0cdf05b0f8f23a39766158cea9c9886000c67 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 18:21:08 +0200
|
|
Subject: [PATCH 51/66] CVE-2026-4480/CVE-2026-4408: lib/util: add more unsafe
|
|
characters to STRING_SUB_UNSAFE_CHARACTERS
|
|
|
|
|&<> are unsafe characters for shell processing.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.h | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/lib/util/substitute.h b/lib/util/substitute.h
|
|
index b183d864671..41f56c73ba2 100644
|
|
--- a/lib/util/substitute.h
|
|
+++ b/lib/util/substitute.h
|
|
@@ -26,7 +26,7 @@
|
|
|
|
#include <talloc.h>
|
|
|
|
-#define STRING_SUB_UNSAFE_CHARACTERS "$`\"';%"
|
|
+#define STRING_SUB_UNSAFE_CHARACTERS "$`\"';%|&<>"
|
|
|
|
/**
|
|
Substitute a string for a pattern in another string. Make sure there is
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 37158038bc10998a59ff7c2b699c35e0dfecc83d Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Fri, 8 May 2026 22:33:32 +0200
|
|
Subject: [PATCH 52/66] CVE-2026-4480/CVE-2026-4408: lib/util: let log_escape()
|
|
make use of iscntrl()
|
|
|
|
using iscntrl() also handles 0x7F (DEL).
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/util_str_escape.c | 5 +++--
|
|
1 file changed, 3 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/lib/util/util_str_escape.c b/lib/util/util_str_escape.c
|
|
index 8f1f34912ee..c6d7a0c9e77 100644
|
|
--- a/lib/util/util_str_escape.c
|
|
+++ b/lib/util/util_str_escape.c
|
|
@@ -18,6 +18,7 @@
|
|
*/
|
|
|
|
#include "replace.h"
|
|
+#include "system/locale.h"
|
|
#include "lib/util/debug.h"
|
|
#include "lib/util/util_str_escape.h"
|
|
|
|
@@ -28,7 +29,7 @@
|
|
*/
|
|
static size_t encoded_length(unsigned char c)
|
|
{
|
|
- if (c != '\\' && c > 0x1F) {
|
|
+ if (c != '\\' && !iscntrl(c)) {
|
|
return 1;
|
|
} else {
|
|
switch (c) {
|
|
@@ -79,7 +80,7 @@ char *log_escape(TALLOC_CTX *frame, const char *in)
|
|
c = in;
|
|
e = encoded;
|
|
while (*c) {
|
|
- if (*c != '\\' && (unsigned char)(*c) > 0x1F) {
|
|
+ if (*c != '\\' && !iscntrl((unsigned char)(*c))) {
|
|
*e++ = *c++;
|
|
} else {
|
|
switch (*c) {
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From e0f1a55382891d113a43184a692f58a7c9832efe Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 7 May 2026 18:10:50 +0200
|
|
Subject: [PATCH 53/66] CVE-2026-4480/CVE-2026-4408: lib/util: add
|
|
talloc_string_sub_{mixed_quoting,unsafe}() helpers
|
|
|
|
This is the basic helper function for the security problems.
|
|
|
|
talloc_string_sub_mixed_quoting() checks for strange quoting
|
|
in smb.conf options.
|
|
|
|
And talloc_string_sub_unsafe() tries to autodetect how the unsafe
|
|
(client controlled value) and masked and single quote it,
|
|
as a fallback for strange quoting a fixed fallback string
|
|
is used and the caller should warn the admin and give
|
|
hints how to fix the configuration.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Pair-Programmed-With: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/substitute.c | 260 ++++++++++++++++++++++++++++++++++++++++++
|
|
lib/util/substitute.h | 17 +++
|
|
2 files changed, 277 insertions(+)
|
|
|
|
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
|
|
index 30989927da7..406d8424be1 100644
|
|
--- a/lib/util/substitute.c
|
|
+++ b/lib/util/substitute.c
|
|
@@ -25,6 +25,8 @@
|
|
#include "system/locale.h"
|
|
#include "debug.h"
|
|
#ifndef SAMBA_UTIL_CORE_ONLY
|
|
+#include "lib/util/fault.h"
|
|
+#include "lib/util/talloc_stack.h"
|
|
#include "charset/charset.h"
|
|
#else
|
|
#include "charset_compat.h"
|
|
@@ -297,3 +299,261 @@ char *talloc_all_string_sub(TALLOC_CTX *ctx,
|
|
return talloc_string_sub2(ctx, src, pattern, insert,
|
|
false, false, false);
|
|
}
|
|
+
|
|
+#ifndef SAMBA_UTIL_CORE_ONLY
|
|
+
|
|
+bool talloc_string_sub_mixed_quoting(const char *full_cmd, char variable_char)
|
|
+{
|
|
+ /*
|
|
+ * Try to make sure talloc_string_sub_unsafe()
|
|
+ * won't return NULL, instead talloc_stackframe_pool()
|
|
+ * would panic
|
|
+ */
|
|
+ size_t cmd_len = full_cmd != NULL ? strlen(full_cmd) : 0;
|
|
+ size_t pool_size = 512 + cmd_len;
|
|
+ TALLOC_CTX *frame = talloc_stackframe_pool(pool_size);
|
|
+ char *cmd = NULL;
|
|
+ bool modified = false;
|
|
+ bool masked = false;
|
|
+ bool mixed_fallback = false;
|
|
+
|
|
+ cmd = talloc_string_sub_unsafe(frame,
|
|
+ full_cmd,
|
|
+ variable_char,
|
|
+ "U", /* unsafe_value */
|
|
+ "'\"%", /* unsafe_characters */
|
|
+ '_', /* safe_character */
|
|
+ "F", /* fallback_value */
|
|
+ &modified,
|
|
+ &masked,
|
|
+ &mixed_fallback);
|
|
+ if (cmd == NULL) {
|
|
+ mixed_fallback = false;
|
|
+ }
|
|
+ TALLOC_FREE(frame);
|
|
+ return mixed_fallback;
|
|
+}
|
|
+
|
|
+char *talloc_string_sub_unsafe(TALLOC_CTX *mem_ctx,
|
|
+ const char *orig_cmd,
|
|
+ char variable_char,
|
|
+ const char *unsafe_value,
|
|
+ const char *unsafe_characters,
|
|
+ char safe_character,
|
|
+ const char *fallback_value,
|
|
+ bool *_modified,
|
|
+ bool *_masked,
|
|
+ bool *_mixed_fallback)
|
|
+{
|
|
+ TALLOC_CTX *frame = talloc_stackframe();
|
|
+ const char variable[3] =
|
|
+ { '%', variable_char, '\0' };
|
|
+ const char variable_s_quoted[5] =
|
|
+ { '\'', '%', variable_char, '\'', '\0' };
|
|
+ const char variable_d_quoted[5] =
|
|
+ { '"', '%', variable_char, '"', '\0' };
|
|
+ char *cmd = NULL;
|
|
+ char *masked_value = NULL;
|
|
+ char *quoted_value = NULL;
|
|
+ bool has_s_quotes;
|
|
+ bool has_d_quotes;
|
|
+ bool has_variable;
|
|
+ bool has_variable_s_quoted;
|
|
+ bool has_variable_d_quoted;
|
|
+ bool modified = false;
|
|
+ bool masked = false;
|
|
+ bool mixed_fallback = false;
|
|
+ bool ok;
|
|
+
|
|
+ /*
|
|
+ * The unsafe_characters argument should contain
|
|
+ * single and double quotes.
|
|
+ * Otherwise We can't safely handle this.
|
|
+ */
|
|
+ SMB_ASSERT(unsafe_characters != NULL);
|
|
+ SMB_ASSERT(strchr(unsafe_characters, '\'') != NULL);
|
|
+ SMB_ASSERT(strchr(unsafe_characters, '"') != NULL);
|
|
+ SMB_ASSERT(strchr(unsafe_characters, '%') != NULL);
|
|
+
|
|
+ cmd = talloc_strdup(mem_ctx, orig_cmd);
|
|
+ if (cmd == NULL) {
|
|
+ TALLOC_FREE(frame);
|
|
+ return NULL;
|
|
+ }
|
|
+ cmd = talloc_steal(frame, cmd);
|
|
+
|
|
+ has_variable = strstr(orig_cmd, variable) != NULL;
|
|
+ if (!has_variable) {
|
|
+ /*
|
|
+ * Nothing to do...
|
|
+ */
|
|
+ goto done;
|
|
+ }
|
|
+ modified = true;
|
|
+
|
|
+ /*
|
|
+ * Replace all unsafe characters as well as control
|
|
+ * characters.
|
|
+ *
|
|
+ * Note that we start with masked_value = "%u"
|
|
+ * and then replace "%u" with unsafe_value,
|
|
+ * as a result we have a masked version of
|
|
+ * unsafe_value.
|
|
+ *
|
|
+ * And don't allow option injected like
|
|
+ *
|
|
+ * '-h value'
|
|
+ * '--help value'
|
|
+ *
|
|
+ */
|
|
+ masked_value = talloc_strdup(frame, variable);
|
|
+ if (masked_value == NULL) {
|
|
+ goto nomem;
|
|
+ }
|
|
+ ok = realloc_string_sub_raw(&masked_value,
|
|
+ variable,
|
|
+ unsafe_value,
|
|
+ false, /* replace_once */
|
|
+ false, /* allow_trailing_dollar */
|
|
+ unsafe_characters,
|
|
+ safe_character);
|
|
+ if (!ok) {
|
|
+ goto nomem;
|
|
+ }
|
|
+ if (masked_value[0] == '-') {
|
|
+ masked_value[0] = safe_character;
|
|
+ }
|
|
+ masked = strcmp(masked_value, unsafe_value) != 0;
|
|
+
|
|
+retry:
|
|
+
|
|
+ has_s_quotes = strchr(cmd, '\'') != NULL;
|
|
+ has_d_quotes = strchr(cmd, '"') != NULL;
|
|
+ has_variable = strstr(cmd, variable) != NULL;
|
|
+ has_variable_s_quoted = strstr(cmd, variable_s_quoted) != NULL;
|
|
+ has_variable_d_quoted = strstr(cmd, variable_d_quoted) != NULL;
|
|
+
|
|
+ if (has_variable_s_quoted) {
|
|
+ /*
|
|
+ * In smb.conf we have something like
|
|
+ *
|
|
+ * some script = /usr/bin/script '%u'
|
|
+ *
|
|
+ * It is safe to replace '%u' (or '%J' etc, depending
|
|
+ * on variable_char) with '<masked_value>' if
|
|
+ * masked_value does not contain single quotes. We
|
|
+ * have checked that.
|
|
+ */
|
|
+
|
|
+ if (quoted_value == NULL) {
|
|
+ quoted_value = talloc_asprintf(frame, "'%s'",
|
|
+ masked_value);
|
|
+ if (quoted_value == NULL) {
|
|
+ goto nomem;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ok = realloc_string_sub_raw(&cmd,
|
|
+ variable_s_quoted,
|
|
+ quoted_value,
|
|
+ false, /* replace_once */
|
|
+ false, /* allow_trailing_dollar */
|
|
+ NULL, /* unsafe_characters */
|
|
+ '\0'); /* safe_character */
|
|
+ if (!ok) {
|
|
+ goto nomem;
|
|
+ }
|
|
+
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
+ if (has_variable_d_quoted && !has_s_quotes) {
|
|
+ /*
|
|
+ * replace the "%u"
|
|
+ *
|
|
+ * some script = /usr/bin/script "%u"
|
|
+ *
|
|
+ * with '%u' and try the '%u' -> 'variable' substitution
|
|
+ * again.
|
|
+ */
|
|
+
|
|
+ ok = realloc_string_sub_raw(&cmd,
|
|
+ variable_d_quoted,
|
|
+ variable_s_quoted,
|
|
+ false, /* replace_once */
|
|
+ false, /* allow_trailing_dollar */
|
|
+ NULL, /* unsafe_characters */
|
|
+ '\0'); /* safe_character */
|
|
+ if (!ok) {
|
|
+ goto nomem;
|
|
+ }
|
|
+
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
+ if (has_variable && !has_s_quotes && !has_d_quotes) {
|
|
+ /*
|
|
+ * In this case:
|
|
+ *
|
|
+ * some script = /usr/bin/script %u
|
|
+ *
|
|
+ * we can safely substitute %u -> '%u' and try the
|
|
+ * single quote test again.
|
|
+ */
|
|
+
|
|
+ ok = realloc_string_sub_raw(&cmd,
|
|
+ variable,
|
|
+ variable_s_quoted,
|
|
+ false, /* replace_once */
|
|
+ false, /* allow_trailing_dollar */
|
|
+ NULL, /* unsafe_characters */
|
|
+ '\0'); /* safe_character */
|
|
+ if (!ok) {
|
|
+ goto nomem;
|
|
+ }
|
|
+
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
+ if (has_variable) {
|
|
+ /*
|
|
+ * There are single or double quotes, but not tightly
|
|
+ * bound around a %u.
|
|
+ *
|
|
+ * Or there's a mix of single and double quotes.
|
|
+ *
|
|
+ * We just use a generic fallback value.
|
|
+ * and let the caller warn about this
|
|
+ * and give the admin a hind to fix the smb.conf
|
|
+ * option.
|
|
+ */
|
|
+ mixed_fallback = true;
|
|
+
|
|
+ ok = realloc_string_sub_raw(&cmd,
|
|
+ variable,
|
|
+ fallback_value,
|
|
+ false, /* replace_once */
|
|
+ false, /* allow_trailing_dollar */
|
|
+ NULL, /* unsafe_characters */
|
|
+ '\0'); /* safe_character */
|
|
+ if (!ok) {
|
|
+ goto nomem;
|
|
+ }
|
|
+ }
|
|
+
|
|
+done:
|
|
+ *_modified = modified;
|
|
+ *_masked = masked;
|
|
+ *_mixed_fallback = mixed_fallback;
|
|
+ cmd = talloc_steal(mem_ctx, cmd);
|
|
+ TALLOC_FREE(frame);
|
|
+ return cmd;
|
|
+
|
|
+nomem:
|
|
+ *_modified = false;
|
|
+ *_masked = false;
|
|
+ *_mixed_fallback = false;
|
|
+ TALLOC_FREE(frame);
|
|
+ return NULL;
|
|
+}
|
|
+#endif /* ! SAMBA_UTIL_CORE_ONLY */
|
|
diff --git a/lib/util/substitute.h b/lib/util/substitute.h
|
|
index 41f56c73ba2..b8205055da1 100644
|
|
--- a/lib/util/substitute.h
|
|
+++ b/lib/util/substitute.h
|
|
@@ -83,4 +83,21 @@ char *talloc_all_string_sub(TALLOC_CTX *ctx,
|
|
const char *src,
|
|
const char *pattern,
|
|
const char *insert);
|
|
+
|
|
+#ifndef SAMBA_UTIL_CORE_ONLY
|
|
+bool talloc_string_sub_mixed_quoting(const char *full_cmd, char variable_char);
|
|
+
|
|
+char *talloc_string_sub_unsafe(TALLOC_CTX *mem_ctx,
|
|
+ const char *orig_cmd,
|
|
+ char variable_char,
|
|
+ const char *unsafe_value,
|
|
+ const char *unsafe_characters,
|
|
+ char safe_character,
|
|
+ const char *fallback_value,
|
|
+ bool *_modified,
|
|
+ bool *_masked,
|
|
+ bool *_mixed_fallback);
|
|
+
|
|
+#endif /* ! SAMBA_UTIL_CORE_ONLY */
|
|
+
|
|
#endif /* _SAMBA_SUBSTITUTE_H_ */
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From b0425235ed880fb510aba1fe0fc07ee5d7304337 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Sat, 9 May 2026 22:02:47 +1200
|
|
Subject: [PATCH 54/66] CVE-2026-4480/CVE-2026-4408: lib/util: add
|
|
test_string_sub unittests
|
|
|
|
This demonstrates the logic of talloc_string_sub_{mixed_quoting,unsafe}()
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
---
|
|
lib/util/tests/test_string_sub.c | 1044 ++++++++++++++++++++++++++++++
|
|
lib/util/wscript_build | 6 +
|
|
selftest/tests.py | 2 +
|
|
3 files changed, 1052 insertions(+)
|
|
create mode 100644 lib/util/tests/test_string_sub.c
|
|
|
|
diff --git a/lib/util/tests/test_string_sub.c b/lib/util/tests/test_string_sub.c
|
|
new file mode 100644
|
|
index 00000000000..da97c1c936c
|
|
--- /dev/null
|
|
+++ b/lib/util/tests/test_string_sub.c
|
|
@@ -0,0 +1,1044 @@
|
|
+
|
|
+#include <stdarg.h>
|
|
+#include <stddef.h>
|
|
+#include <stdint.h>
|
|
+#include <setjmp.h>
|
|
+#include <sys/stat.h>
|
|
+#include "replace.h"
|
|
+#include <cmocka.h>
|
|
+#include "talloc.h"
|
|
+
|
|
+#include "../substitute.h"
|
|
+
|
|
+/* set _DEBUG_VERBOSE to print more. */
|
|
+#define _DEBUG_VERBOSE
|
|
+
|
|
+#ifdef _DEBUG_VERBOSE
|
|
+#define debug_message(...) print_message(__VA_ARGS__)
|
|
+#else
|
|
+#define debug_message(...) /* debug_message */
|
|
+#endif
|
|
+
|
|
+
|
|
+static int setup_talloc_context(void **state)
|
|
+{
|
|
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
+ *state = mem_ctx;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int teardown_talloc_context(void **state)
|
|
+{
|
|
+ TALLOC_CTX *mem_ctx = *state;
|
|
+ TALLOC_FREE(mem_ctx);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct cmd_expansion {
|
|
+ const char *lp_cmd;
|
|
+ const char *username;
|
|
+ const char *result_cmd;
|
|
+ bool modified;
|
|
+ bool masked;
|
|
+ bool mixed_fallback;
|
|
+};
|
|
+
|
|
+static void _test_talloc_string_sub_unsafe(void **state,
|
|
+ struct cmd_expansion expansions[],
|
|
+ size_t n_expansions,
|
|
+ const char *unsafe_characters)
|
|
+{
|
|
+ TALLOC_CTX *mem_ctx = *state;
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; i < n_expansions; i++) {
|
|
+ struct cmd_expansion t = expansions[i];
|
|
+ char *result_cmd = NULL;
|
|
+ bool masked;
|
|
+ bool mixed_fallback;
|
|
+ bool modified;
|
|
+ bool flags_correct;
|
|
+ bool mixed;
|
|
+ int cmp;
|
|
+
|
|
+ mixed = talloc_string_sub_mixed_quoting(t.lp_cmd, 'u');
|
|
+
|
|
+ result_cmd = talloc_string_sub_unsafe(mem_ctx,
|
|
+ t.lp_cmd,
|
|
+ 'u',
|
|
+ t.username,
|
|
+ unsafe_characters,
|
|
+ '_',
|
|
+ "FallbackUsername",
|
|
+ &modified,
|
|
+ &masked,
|
|
+ &mixed_fallback);
|
|
+ assert_ptr_not_equal(result_cmd, NULL);
|
|
+ assert_ptr_not_equal(t.result_cmd, NULL);
|
|
+
|
|
+ cmp = strcmp(t.result_cmd, result_cmd);
|
|
+ flags_correct = (modified == t.modified &&
|
|
+ masked == t.masked &&
|
|
+ mixed_fallback == t.mixed_fallback);
|
|
+
|
|
+ if (cmp == 0) {
|
|
+ debug_message("[%zu] «%s» «%s» -> «%s»; AS EXPECTED\n",
|
|
+ i, t.lp_cmd,
|
|
+ t.username,
|
|
+ result_cmd);
|
|
+ } else {
|
|
+ debug_message("[%zu] «%s» «%s»; "
|
|
+ "expected [%zu] «%s» got [%zu] «%s»\033[1;31m BAD! \033[0m\n",
|
|
+ i, t.lp_cmd,
|
|
+ t.username,
|
|
+ strlen(t.result_cmd), t.result_cmd,
|
|
+ strlen(result_cmd), result_cmd);
|
|
+ }
|
|
+ assert_int_equal(cmp, 0);
|
|
+ if (!flags_correct) {
|
|
+ debug_message("[%zu] ", i);
|
|
+#define _FLAG(x) debug_message((t. x == x) ? "%s: %s √; ": \
|
|
+ "%s \033[1;31m expected %s \033[0m; ", \
|
|
+ #x, t.x ? "true": "false");
|
|
+ _FLAG(modified);
|
|
+ _FLAG(masked);
|
|
+ _FLAG(mixed_fallback);
|
|
+ debug_message("\n");
|
|
+ }
|
|
+ assert_int_equal(flags_correct, true);
|
|
+ if (mixed_fallback != mixed) {
|
|
+ debug_message("[%zu] %s mixed \033[1;31m expected %s \033[0m; ",
|
|
+ i, t.lp_cmd,
|
|
+ mixed_fallback ? "true": "false");
|
|
+ }
|
|
+ assert_int_equal(mixed_fallback, mixed);
|
|
+#undef _FLAG
|
|
+ }
|
|
+ debug_message("ALL correct\n");
|
|
+}
|
|
+
|
|
+static void test_talloc_string_sub_unsafe(void **state)
|
|
+{
|
|
+ const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
+
|
|
+ static struct cmd_expansion expansions[] = {
|
|
+ {
|
|
+ "/bin/echo \"bob'",
|
|
+ "bob",
|
|
+ "/bin/echo \"bob'",
|
|
+ false,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob'",
|
|
+ "/bin/echo 'bob_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob'''",
|
|
+ "/bin/echo 'bob___'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob\'",
|
|
+ "/bin/echo 'bob_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u",
|
|
+ "bob bob bob",
|
|
+ "/bin/echo 'FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ " ",
|
|
+ "/bin/echo ' '",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo \"--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob !0",
|
|
+ "/bin/echo \"--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "!0",
|
|
+ "/bin/echo '!0'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob \\",
|
|
+ "/bin/echo \"--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "bob >> x",
|
|
+ "/bin/echo --uu='bob __ x'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '--uu=%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo '--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "bob",
|
|
+ "/bin/echo --uu='bob'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "bob",
|
|
+ "/bin/echo --uu'=FallbackUsername'",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu'=FallbackUsername'",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "u%u%u%u%u",
|
|
+ "/bin/echo --uu='u_u_u_u_u'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "$(ls)",
|
|
+ "/bin/echo --uu='_(ls)'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu='_ls_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='1' %u",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu='1' FallbackUsername",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu=\"'%u'\"",
|
|
+ "bob",
|
|
+ "/bin/echo --uu=\"'bob'\"",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u' --yy='%u' '%u' %u",
|
|
+ "bob",
|
|
+ "/bin/echo --uu='bob' --yy='bob' 'bob' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu=%u%u%u'' %user 50%u",
|
|
+ "bob",
|
|
+ "/bin/echo --uu=FallbackUsernameFallbackUsernameFallbackUsername'' FallbackUsernameser 50FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "!!",
|
|
+ "/bin/echo '!!'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ ">xxx",
|
|
+ "/bin/echo '_xxx'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "3",
|
|
+ "/bin/echo '3'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "3$",
|
|
+ "/bin/echo '3_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "comp$",
|
|
+ "/bin/echo 'comp_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "3$3",
|
|
+ "/bin/echo '3_3'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "q $3",
|
|
+ "/bin/echo 'q _3'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u",
|
|
+ "q $3",
|
|
+ "/bin/echo 'FallbackUsername",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s '%u' %u",
|
|
+ "āāā",
|
|
+ "/bin/echo -s 'āāā' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s '%u' %u",
|
|
+ "-āāā",
|
|
+ "/bin/echo -s '_āāā' FallbackUsername",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s %u",
|
|
+ "āāā",
|
|
+ "/bin/echo -s 'āāā'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s %u",
|
|
+ "a -a",
|
|
+ "/bin/echo -s 'a -a'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s=%u %u",
|
|
+ "ā -a",
|
|
+ "/bin/echo -s='ā -a' 'ā -a'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s=\"%u %u\"",
|
|
+ "ā -a",
|
|
+ "/bin/echo -s=\"FallbackUsername FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -m='fridge' %u",
|
|
+ "ā -ß",
|
|
+ "/bin/echo -m='fridge' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -m='fridge' %u",
|
|
+ "-ā -a",
|
|
+ "/bin/echo -m='fridge' FallbackUsername",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "-n",
|
|
+ "/bin/echo '_n'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "o'clock",
|
|
+ "/bin/echo 'o_clock'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"bob'",
|
|
+ "bob",
|
|
+ "/bin/echo \"bob'",
|
|
+ false,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ "%u",
|
|
+ "/bin/echo '_u'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"$(ls)\"",
|
|
+ "%u",
|
|
+ "/bin/echo \"$(ls)\"",
|
|
+ false,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "\\",
|
|
+ "/bin/echo '\\'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "\\",
|
|
+ "/bin/echo '\\'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ "\\",
|
|
+ "/bin/echo '\\'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\" %u",
|
|
+ "\\",
|
|
+ "/bin/echo '\\' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u' \"%u\" %u",
|
|
+ "\\",
|
|
+ "/bin/echo '\\' \"FallbackUsername\" FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u' \"%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob' \"FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ };
|
|
+
|
|
+ _test_talloc_string_sub_unsafe(state,
|
|
+ expansions,
|
|
+ ARRAY_SIZE(expansions),
|
|
+ unsafe_characters);
|
|
+}
|
|
+
|
|
+static void test_talloc_string_sub_unsafe_minimal_unsafe_chars(void **state)
|
|
+{
|
|
+ const char *unsafe_characters = "\"'%";
|
|
+
|
|
+ static struct cmd_expansion expansions[] = {
|
|
+ {
|
|
+ "/bin/echo \"bob'",
|
|
+ "bob",
|
|
+ "/bin/echo \"bob'",
|
|
+ false,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob'",
|
|
+ "/bin/echo 'bob_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob'''",
|
|
+ "/bin/echo 'bob___'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob\'",
|
|
+ "/bin/echo 'bob_'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u",
|
|
+ "bob bob bob",
|
|
+ "/bin/echo 'FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ " ",
|
|
+ "/bin/echo ' '",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo \"--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob !0",
|
|
+ "/bin/echo \"--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "!0",
|
|
+ "/bin/echo '!0'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob \\",
|
|
+ "/bin/echo \"--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "bob >> x",
|
|
+ "/bin/echo --uu='bob >> x'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '--uu=%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo '--uu=FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "bob",
|
|
+ "/bin/echo --uu='bob'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "bob",
|
|
+ "/bin/echo --uu'=FallbackUsername'",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu'=FallbackUsername'",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "u%u%u%u%u",
|
|
+ "/bin/echo --uu='u_u_u_u_u'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "$(ls)",
|
|
+ "/bin/echo --uu='$(ls)'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu='`ls`'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='1' %u",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu='1' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu=\"'%u'\"",
|
|
+ "bob",
|
|
+ "/bin/echo --uu=\"'bob'\"",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u' --yy='%u' '%u' %u",
|
|
+ "bob",
|
|
+ "/bin/echo --uu='bob' --yy='bob' 'bob' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu=%u%u%u'' %user 50%u",
|
|
+ "bob",
|
|
+ "/bin/echo --uu=FallbackUsernameFallbackUsernameFallbackUsername'' FallbackUsernameser 50FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "!!",
|
|
+ "/bin/echo '!!'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ ">xxx",
|
|
+ "/bin/echo '>xxx'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "3",
|
|
+ "/bin/echo '3'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "3$",
|
|
+ "/bin/echo '3$'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "comp$",
|
|
+ "/bin/echo 'comp$'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "3$3",
|
|
+ "/bin/echo '3$3'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "q $3",
|
|
+ "/bin/echo 'q $3'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u",
|
|
+ "q $3",
|
|
+ "/bin/echo 'FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s '%u' %u",
|
|
+ "āāā",
|
|
+ "/bin/echo -s 'āāā' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s '%u' %u",
|
|
+ "-āāā",
|
|
+ "/bin/echo -s '_āāā' FallbackUsername",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s %u",
|
|
+ "āāā",
|
|
+ "/bin/echo -s 'āāā'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s %u",
|
|
+ "a -a",
|
|
+ "/bin/echo -s 'a -a'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s=%u %u",
|
|
+ "ā -a",
|
|
+ "/bin/echo -s='ā -a' 'ā -a'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s=\"%u %u\"",
|
|
+ "ā -a",
|
|
+ "/bin/echo -s=\"FallbackUsername FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -m='fridge' %u",
|
|
+ "ā -ß",
|
|
+ "/bin/echo -m='fridge' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -m='fridge' %u",
|
|
+ "-ā -a",
|
|
+ "/bin/echo -m='fridge' FallbackUsername",
|
|
+ true,
|
|
+ true,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "-n",
|
|
+ "/bin/echo '_n'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "o'clock",
|
|
+ "/bin/echo 'o_clock'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"bob'",
|
|
+ "bob",
|
|
+ "/bin/echo \"bob'",
|
|
+ false,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ "%u",
|
|
+ "/bin/echo '_u'",
|
|
+ true,
|
|
+ true,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"$(ls)\"",
|
|
+ "%u",
|
|
+ "/bin/echo \"$(ls)\"",
|
|
+ false,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "\\",
|
|
+ "/bin/echo '\\'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "\\",
|
|
+ "/bin/echo '\\'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ "\\",
|
|
+ "/bin/echo '\\'",
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\" %u",
|
|
+ "\\",
|
|
+ "/bin/echo '\\' FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u' \"%u\" %u",
|
|
+ "\\",
|
|
+ "/bin/echo '\\' \"FallbackUsername\" FallbackUsername",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u' \"%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob' \"FallbackUsername\"",
|
|
+ true,
|
|
+ false,
|
|
+ true,
|
|
+ },
|
|
+ };
|
|
+
|
|
+ _test_talloc_string_sub_unsafe(state,
|
|
+ expansions,
|
|
+ ARRAY_SIZE(expansions),
|
|
+ unsafe_characters);
|
|
+}
|
|
+
|
|
+static void test_talloc_string_sub_unsafe_all_mixes(void **state)
|
|
+{
|
|
+ const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; i < 32; i++) {
|
|
+ char in[100] = { 0, };
|
|
+ char out[100] = { 0, };
|
|
+ struct cmd_expansion expansions[] = {
|
|
+ {
|
|
+ in,
|
|
+ "bob",
|
|
+ out,
|
|
+ true,
|
|
+ false,
|
|
+ false,
|
|
+ },
|
|
+ };
|
|
+ bool vsq = i & 1;
|
|
+ bool vdq = i & 2;
|
|
+ bool v = i & 4;
|
|
+ bool sq = i & 8;
|
|
+ bool dq = i & 16;
|
|
+ char *inp = in;
|
|
+ char *outp = out;
|
|
+ if (vsq) {
|
|
+ inp = stpcpy(inp, "'%u' ");
|
|
+ outp = stpcpy(outp, "'bob' ");
|
|
+ debug_message("vsq ");
|
|
+ }
|
|
+ if (vdq) {
|
|
+ inp = stpcpy(inp, "\"%u\" ");
|
|
+ outp = stpcpy(outp, (vsq || sq) ? "\"FallbackUsername\" " : "'bob' ");
|
|
+ debug_message("vdq ");
|
|
+ if (vsq || sq) {
|
|
+ expansions[0].mixed_fallback = true;
|
|
+ }
|
|
+ }
|
|
+ if (v) {
|
|
+ inp = stpcpy(inp, "%u ");
|
|
+ outp = stpcpy(outp, (vsq || vdq || sq || dq) ? "FallbackUsername " : "'bob' ");
|
|
+ debug_message("v ");
|
|
+ if (vsq || vdq || sq || dq) {
|
|
+ expansions[0].mixed_fallback = true;
|
|
+ }
|
|
+ }
|
|
+ if (sq) {
|
|
+ inp = stpcpy(inp, "' ");
|
|
+ outp = stpcpy(outp, "' ");
|
|
+ debug_message("sq ");
|
|
+ }
|
|
+ if (dq) {
|
|
+ inp = stpcpy(inp, "\" ");
|
|
+ outp = stpcpy(outp, "\" ");
|
|
+ debug_message("dq ");
|
|
+ }
|
|
+ debug_message("(i: %zu)\n", i);
|
|
+ *inp = '\0';
|
|
+ *outp = '\0';
|
|
+ expansions[0].modified = strcmp(in, out) != 0;
|
|
+
|
|
+ _test_talloc_string_sub_unsafe(state,
|
|
+ expansions,
|
|
+ ARRAY_SIZE(expansions),
|
|
+ unsafe_characters);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+int main(void)
|
|
+{
|
|
+ const struct CMUnitTest tests[] = {
|
|
+ cmocka_unit_test(test_talloc_string_sub_unsafe),
|
|
+ cmocka_unit_test(test_talloc_string_sub_unsafe_minimal_unsafe_chars),
|
|
+ cmocka_unit_test(test_talloc_string_sub_unsafe_all_mixes),
|
|
+ };
|
|
+ if (!isatty(1)) {
|
|
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
|
|
+ }
|
|
+ return cmocka_run_group_tests(tests,
|
|
+ setup_talloc_context,
|
|
+ teardown_talloc_context);
|
|
+}
|
|
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
|
|
index 9dff0e8925d..c9c04f1aaed 100644
|
|
--- a/lib/util/wscript_build
|
|
+++ b/lib/util/wscript_build
|
|
@@ -420,3 +420,9 @@ else:
|
|
deps='cmocka replace talloc stable_sort',
|
|
local_include=False,
|
|
for_selftest=True)
|
|
+
|
|
+ bld.SAMBA3_BINARY('test_string_sub',
|
|
+ source='tests/test_string_sub.c',
|
|
+ deps='''cmocka replace talloc samba-util
|
|
+ ''',
|
|
+ for_selftest=True)
|
|
diff --git a/selftest/tests.py b/selftest/tests.py
|
|
index 104fa65f672..c92676f66eb 100644
|
|
--- a/selftest/tests.py
|
|
+++ b/selftest/tests.py
|
|
@@ -569,6 +569,8 @@ plantestsuite("samba.unittests.sys_rw", "none",
|
|
[os.path.join(bindir(), "default/lib/util/test_sys_rw")])
|
|
plantestsuite("samba.unittests.stable_sort", "none",
|
|
[os.path.join(bindir(), "default/lib/util/test_stable_sort")])
|
|
+plantestsuite("samba.unittests.test_string_sub", "none",
|
|
+ [os.path.join(bindir(), "test_string_sub")])
|
|
plantestsuite("samba.unittests.ntlm_check", "none",
|
|
[os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")])
|
|
plantestsuite("samba.unittests.gnutls", "none",
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 8ee5805b49b6f5f413e627c8b19d10559bbb2aa2 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Sun, 15 Mar 2026 19:15:14 +0100
|
|
Subject: [PATCH 55/66] CVE-2026-4480: s3:printing: mask and/or single quote
|
|
jobname passed as %J to "print command"
|
|
|
|
Fix an unauthenticated remote code execution vulnerability with
|
|
printing set to anything *but* cups and iprint, for example "lprng",
|
|
so that "print command" is executed upon job submission. If the
|
|
client-controlled job name is handed to the "print command" via %J,
|
|
rpcd_spoolssd passes this to the shell without escaping critical
|
|
characters.
|
|
|
|
Using single quotes (directly) around %J, '%J' would avoid the
|
|
problem, we now try to autodetect if we can use '%J' implicitly
|
|
or we fallback to a fixed "__CVE-2026-4480_FallbackJobname__"
|
|
string instead of the client provided jobname.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/printing/print_generic.c | 107 +++++++++++++++++++++++++++----
|
|
1 file changed, 94 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/source3/printing/print_generic.c b/source3/printing/print_generic.c
|
|
index 7c7a14de045..2f642af3f4b 100644
|
|
--- a/source3/printing/print_generic.c
|
|
+++ b/source3/printing/print_generic.c
|
|
@@ -19,6 +19,7 @@
|
|
|
|
#include "includes.h"
|
|
#include "lib/util/util_file.h"
|
|
+#include "lib/util/util_str_escape.h"
|
|
#include "printing.h"
|
|
#include "smbd/proto.h"
|
|
#include "source3/lib/substitute.h"
|
|
@@ -207,6 +208,52 @@ static int generic_queue_get(const char *printer_name,
|
|
return qcount;
|
|
}
|
|
|
|
+static const char *replace_print_cmd_J(TALLOC_CTX *mem_ctx,
|
|
+ const char *orig_cmd,
|
|
+ const char *unsafe_jobname,
|
|
+ const char *fallback_jobname)
|
|
+{
|
|
+ char *cmd = NULL;
|
|
+ bool modified = false;
|
|
+ bool masked = false;
|
|
+ bool mixed_fallback = false;
|
|
+
|
|
+ /*
|
|
+ * This replaces unsafe characters with '_'.
|
|
+ * We also mask forward and backslash here.
|
|
+ *
|
|
+ * Then it replaces %J with an single quoted
|
|
+ * version of the masked jobname or it falls
|
|
+ * back to fallback_jobname is the print command
|
|
+ * uses strange mixed quoting.
|
|
+ */
|
|
+
|
|
+#define JOBNAME_UNSAFE_CHARACTERS \
|
|
+ STRING_SUB_UNSAFE_CHARACTERS "/\\"
|
|
+
|
|
+ cmd = talloc_string_sub_unsafe(mem_ctx,
|
|
+ orig_cmd,
|
|
+ 'J',
|
|
+ unsafe_jobname,
|
|
+ JOBNAME_UNSAFE_CHARACTERS,
|
|
+ '_',
|
|
+ fallback_jobname,
|
|
+ &modified,
|
|
+ &masked,
|
|
+ &mixed_fallback);
|
|
+ if (cmd == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * The caller already checked talloc_string_sub_mixed_quoting()
|
|
+ * and warned the admin, so we don't check mixed_fallback
|
|
+ * here
|
|
+ */
|
|
+
|
|
+ return cmd;
|
|
+}
|
|
+
|
|
/****************************************************************************
|
|
Submit a file for printing - called from print_job_end()
|
|
****************************************************************************/
|
|
@@ -222,11 +269,12 @@ static int generic_job_submit(int snum, struct printjob *pjob,
|
|
char *print_directory = NULL;
|
|
char *wd = NULL;
|
|
char *p = NULL;
|
|
- char *jobname = NULL;
|
|
+ const char *print_cmd = NULL;
|
|
TALLOC_CTX *ctx = talloc_tos();
|
|
fstring job_page_count, job_size;
|
|
print_queue_struct *q = NULL;
|
|
print_status_struct status;
|
|
+ const char *jobname = "No Document Name";
|
|
|
|
/* we print from the directory path to give the best chance of
|
|
parsing the lpq output */
|
|
@@ -255,24 +303,48 @@ static int generic_job_submit(int snum, struct printjob *pjob,
|
|
return -1;
|
|
}
|
|
|
|
- jobname = talloc_strdup(ctx, pjob->jobname);
|
|
- if (!jobname) {
|
|
- ret = -1;
|
|
- goto out;
|
|
+ if (pjob->jobname[0] != '\0') {
|
|
+ jobname = pjob->jobname;
|
|
}
|
|
- jobname = talloc_string_sub(ctx, jobname, "'", "_");
|
|
- if (!jobname) {
|
|
- ret = -1;
|
|
- goto out;
|
|
+
|
|
+ print_cmd = lp_print_command(snum);
|
|
+ if (print_cmd != NULL) {
|
|
+ const char *invalid_jobname = "__CVE-2026-4480_FallbackJobname__";
|
|
+
|
|
+ if (talloc_string_sub_mixed_quoting(print_cmd, 'J')) {
|
|
+ /*
|
|
+ * The admin used a strange mixture of
|
|
+ * single and double quotes, fallback
|
|
+ * to InvalidDocumentName and warn about
|
|
+ * it, so that the admin can adjust to
|
|
+ * the use single quotes directly around %J,
|
|
+ * e.g. '%J'.
|
|
+ */
|
|
+ jobname = invalid_jobname;
|
|
+ D_WARNING("CVE-2026-4480: printer %s "
|
|
+ "strange quoting in 'print command', "
|
|
+ "falling back to jobname=%s, "
|
|
+ "use testparm to fix the configuration\n",
|
|
+ lp_printername(talloc_tos(), lp_sub, snum),
|
|
+ invalid_jobname);
|
|
+ }
|
|
+
|
|
+ print_cmd = replace_print_cmd_J(ctx,
|
|
+ print_cmd,
|
|
+ jobname,
|
|
+ invalid_jobname);
|
|
+ if (!print_cmd) {
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
fstr_sprintf(job_page_count, "%d", pjob->page_count);
|
|
fstr_sprintf(job_size, "%zu", pjob->size);
|
|
|
|
/* send it to the system spooler */
|
|
ret = print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
|
|
- lp_print_command(snum), NULL,
|
|
+ print_cmd, NULL,
|
|
"%s", p,
|
|
- "%J", jobname,
|
|
"%f", p,
|
|
"%z", job_size,
|
|
"%c", job_page_count,
|
|
@@ -293,17 +365,26 @@ static int generic_job_submit(int snum, struct printjob *pjob,
|
|
int i;
|
|
for (i = 0; i < ret; i++) {
|
|
if (strcmp(q[i].fs_file, p) == 0) {
|
|
+ char *le_jobname =
|
|
+ log_escape(talloc_tos(), jobname);
|
|
+
|
|
pjob->sysjob = q[i].sysjob;
|
|
DEBUG(5, ("new job %u (%s) matches sysjob %d\n",
|
|
- pjob->jobid, jobname, pjob->sysjob));
|
|
+ pjob->jobid, le_jobname, pjob->sysjob));
|
|
+
|
|
+ TALLOC_FREE(le_jobname);
|
|
break;
|
|
}
|
|
}
|
|
ret = 0;
|
|
}
|
|
if (pjob->sysjob == -1) {
|
|
+ char *le_jobname = log_escape(talloc_tos(), jobname);
|
|
+
|
|
DEBUG(2, ("failed to get sysjob for job %u (%s), tracking as "
|
|
- "Unix job\n", pjob->jobid, jobname));
|
|
+ "Unix job\n", pjob->jobid, le_jobname));
|
|
+
|
|
+ TALLOC_FREE(le_jobname);
|
|
}
|
|
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 27a1372c85d05f02fd1e7f975798314b95ee75d3 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Fri, 8 May 2026 23:27:35 +0200
|
|
Subject: [PATCH 56/66] CVE-2026-4480: s3:testparm: warn about 'print command'
|
|
%J usage
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/utils/testparm.c | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c
|
|
index 306924ac7c8..c758313d466 100644
|
|
--- a/source3/utils/testparm.c
|
|
+++ b/source3/utils/testparm.c
|
|
@@ -928,6 +928,14 @@ static void do_per_share_checks(int s)
|
|
"parameter is ignored when using CUPS libraries.\n\n",
|
|
lp_servicename(talloc_tos(), lp_sub, s));
|
|
}
|
|
+ if (talloc_string_sub_mixed_quoting(lp_print_command(s), 'J')) {
|
|
+ fprintf(stderr,
|
|
+ "WARNING: Service %s defines a 'print command' "
|
|
+ "with mixed quoting and %%J.\n"
|
|
+ "CVE-2026-4480 changed the way %%J substitution works.\n"
|
|
+ "You should use single quotes (directly) around '%%J'.\n\n",
|
|
+ lp_servicename(talloc_tos(), lp_sub, s));
|
|
+ }
|
|
|
|
vfs_objects = lp_vfs_objects(s);
|
|
if (vfs_objects && str_list_check(vfs_objects, "fruit")) {
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 498d3a2eba50e0d4eff50c99cd54a8a9af4e7639 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Mon, 11 May 2026 14:11:34 +0200
|
|
Subject: [PATCH 57/66] CVE-2026-4480: docs-xml/smbdotconf: clarify '%J' in
|
|
'print command'
|
|
|
|
Admins should use '%J'.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16033
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
docs-xml/smbdotconf/printing/printcommand.xml | 7 +++++--
|
|
1 file changed, 5 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/docs-xml/smbdotconf/printing/printcommand.xml b/docs-xml/smbdotconf/printing/printcommand.xml
|
|
index c84e45f404d..d708287932a 100644
|
|
--- a/docs-xml/smbdotconf/printing/printcommand.xml
|
|
+++ b/docs-xml/smbdotconf/printing/printcommand.xml
|
|
@@ -21,8 +21,11 @@
|
|
<para>%p - the appropriate printer
|
|
name</para>
|
|
|
|
- <para>%J - the job
|
|
- name as transmitted by the client.</para>
|
|
+ <para>%J - the job name as transmitted by the client,
|
|
+ but with dangerous characters being replaced by _.
|
|
+ You should use single quotes (directly) around %J, e.g. '%J',
|
|
+ see CVE-2026-4480 for more details.
|
|
+ </para>
|
|
|
|
<para>%c - The number of printed pages
|
|
of the spooled job (if known).</para>
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 47e15af9f5d77208473b29bac5422665b79191f8 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Thu, 23 Apr 2026 18:56:21 +0200
|
|
Subject: [PATCH 58/66] CVE-2026-4408: lib/util: introduce
|
|
strstr_for_invalid_account_characters()
|
|
|
|
This splits out the logic from samaccountname_bad_chars_check()
|
|
in source4/dsdb/samdb/ldb_modules/samldb.c, this will be used
|
|
in other places soon.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
lib/util/samba_util.h | 9 +++++++++
|
|
lib/util/util_str.c | 38 ++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 47 insertions(+)
|
|
|
|
diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h
|
|
index 03dee5c6137..ea741b51c58 100644
|
|
--- a/lib/util/samba_util.h
|
|
+++ b/lib/util/samba_util.h
|
|
@@ -303,6 +303,15 @@ _PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean);
|
|
*/
|
|
_PUBLIC_ bool conv_str_bool(const char * str, bool * val);
|
|
|
|
+/**
|
|
+ * Returns a pointer to the first invalid character in name.
|
|
+ *
|
|
+ * Passing a NULL pointer as name is not allowed!
|
|
+ *
|
|
+ * This returns NULL for a valid account name.
|
|
+ **/
|
|
+_PUBLIC_ const char *strstr_for_invalid_account_characters(const char *name);
|
|
+
|
|
/**
|
|
* Convert a size specification like 16K into an integral number of bytes.
|
|
**/
|
|
diff --git a/lib/util/util_str.c b/lib/util/util_str.c
|
|
index 19acff4a983..c5987461fe6 100644
|
|
--- a/lib/util/util_str.c
|
|
+++ b/lib/util/util_str.c
|
|
@@ -267,3 +267,41 @@ _PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean)
|
|
}
|
|
return false;
|
|
}
|
|
+
|
|
+_PUBLIC_ const char *strstr_for_invalid_account_characters(const char *name)
|
|
+{
|
|
+ /*
|
|
+ * Return a pointer to the first invalid character in the
|
|
+ * sAMAccountName, or NULL if the whole name is valid.
|
|
+ *
|
|
+ * The rules here are based on
|
|
+ *
|
|
+ * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx
|
|
+ */
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; name[i] != '\0'; i++) {
|
|
+ uint8_t c = name[i];
|
|
+ const char *p = NULL;
|
|
+
|
|
+ if (iscntrl(c)) {
|
|
+ return &name[i];
|
|
+ }
|
|
+
|
|
+ p = strchr("\"[]:;|=+*?<>/\\,", c);
|
|
+ if (p != NULL) {
|
|
+ return &name[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (i == 0) {
|
|
+ return &name[i];
|
|
+ }
|
|
+
|
|
+ if (name[i - 1] == '.') {
|
|
+ i -= 1;
|
|
+ return &name[i];
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From cd1dc2df42eda36bf66e8d7d6f69e365e5d7d8a3 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Mon, 11 May 2026 20:21:36 +0200
|
|
Subject: [PATCH 59/66] CVE-2026-4408: s3:samr-server: only allow
|
|
_samr_ValidatePassword as DC
|
|
|
|
This is only supported with 'rpc start on demand helpers = no',
|
|
as it needs ncacn_ip_tcp, but we better also restrict it to DCs.
|
|
|
|
Maybe only FreeIPA needs it as NT4 didn't support ncacn_ip_tcp.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/rpc_server/samr/srv_samr_nt.c | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c
|
|
index e0d0875bd5d..3937dbe3f32 100644
|
|
--- a/source3/rpc_server/samr/srv_samr_nt.c
|
|
+++ b/source3/rpc_server/samr/srv_samr_nt.c
|
|
@@ -7500,6 +7500,14 @@ NTSTATUS _samr_ValidatePassword(struct pipes_struct *p,
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
+ if (lp_server_role() <= ROLE_DOMAIN_MEMBER) {
|
|
+ /*
|
|
+ * We only want this on DCs
|
|
+ */
|
|
+ p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
|
|
+ return NT_STATUS_ACCESS_DENIED;
|
|
+ }
|
|
+
|
|
if (r->in.level < 1 || r->in.level > 3) {
|
|
return NT_STATUS_INVALID_INFO_CLASS;
|
|
}
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 77c8330fb3b01c3d23f9aac611397334ef6f0007 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Wed, 18 Mar 2026 12:24:47 +0100
|
|
Subject: [PATCH 60/66] CVE-2026-4408: s3:samr-server: deny, mask and/or single
|
|
quote username to 'check password script'
|
|
|
|
We pass this on to the check password script, prevent remote command
|
|
execution.
|
|
|
|
We now try to autodetect if we could implicitly use '%u' for the
|
|
replacement and fallback to a fixed fallback username.
|
|
|
|
Admins should make use of SAMBA_CPS_ACCOUNT_NAME
|
|
instead of passing '%u' to 'check password script'
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Pair-Programmed-With: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/rpc_server/samr/srv_samr_chgpasswd.c | 110 +++++++++++++++++--
|
|
1 file changed, 101 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c
|
|
index 6c0c0da0cfc..9afb8799aea 100644
|
|
--- a/source3/rpc_server/samr/srv_samr_chgpasswd.c
|
|
+++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c
|
|
@@ -54,6 +54,7 @@
|
|
#include "passdb.h"
|
|
#include "auth.h"
|
|
#include "lib/util/sys_rw.h"
|
|
+#include "lib/util/util_str_escape.h"
|
|
#include "librpc/rpc/dcerpc_samr.h"
|
|
|
|
#include "lib/crypto/gnutls_helpers.h"
|
|
@@ -1008,27 +1009,118 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext)
|
|
/***********************************************************
|
|
************************************************************/
|
|
|
|
+static NTSTATUS check_password_complexity_internal(TALLOC_CTX *tosctx,
|
|
+ const char *orig_cmd,
|
|
+ const char *username,
|
|
+ char **cmd_out)
|
|
+{
|
|
+ const char *fallback_username = "__CVE-2026-4408_FallbackUsername__";
|
|
+ const char *inv = NULL;
|
|
+ char *cmd = NULL;
|
|
+ bool modified = false;
|
|
+ bool masked = false;
|
|
+ bool mixed_fallback = false;
|
|
+
|
|
+ *cmd_out = NULL;
|
|
+
|
|
+ if (username == NULL) {
|
|
+ return NT_STATUS_INVALID_USER_PRINCIPAL_NAME;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * This catches invalid characters in account names
|
|
+ * which might be problematic passing to a shell script.
|
|
+ */
|
|
+ inv = strstr_for_invalid_account_characters(username);
|
|
+ if (inv != NULL) {
|
|
+ char *le_username = log_escape(tosctx, username);
|
|
+
|
|
+ DBG_WARNING("username '%s' has invalid or dangerous characters\n",
|
|
+ le_username);
|
|
+
|
|
+ TALLOC_FREE(le_username);
|
|
+
|
|
+ return NT_STATUS_INVALID_USER_PRINCIPAL_NAME;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * This masks the remaining unsafe characters which
|
|
+ * are not already caught by strstr_for_invalid_account_characters()
|
|
+ * with '_'.
|
|
+ *
|
|
+ * Then it replaces %u with an single quoted
|
|
+ * and/or shell escaped version of the masked username.
|
|
+ */
|
|
+ cmd = talloc_string_sub_unsafe(tosctx,
|
|
+ orig_cmd,
|
|
+ 'u',
|
|
+ username,
|
|
+ STRING_SUB_UNSAFE_CHARACTERS,
|
|
+ '_',
|
|
+ fallback_username,
|
|
+ &modified,
|
|
+ &masked,
|
|
+ &mixed_fallback);
|
|
+ if (cmd == NULL) {
|
|
+ return NT_STATUS_NO_MEMORY;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Now warn about unexpected values
|
|
+ */
|
|
+
|
|
+ if (mixed_fallback) {
|
|
+ D_WARNING("CVE-2026-4408: "
|
|
+ "strange quoting in 'check password script', "
|
|
+ "falling back to replace %%u with %s, "
|
|
+ "use testparm to fix the configuration\n",
|
|
+ fallback_username);
|
|
+ D_WARNING("CVE-2026-4408: "
|
|
+ "You should use '%%u', or SAMBA_CPS_ACCOUNT_NAME "
|
|
+ "inside of 'check password script'.\n");
|
|
+ } else if (masked) {
|
|
+ char *le_username = log_escape(tosctx, username);
|
|
+
|
|
+ D_WARNING("CVE-2026-4408: "
|
|
+ "replaced %%u with masked value instead of: %s\n",
|
|
+ le_username);
|
|
+ D_WARNING("CVE-2026-4408: "
|
|
+ "You should use SAMBA_CPS_ACCOUNT_NAME inside "
|
|
+ "'check password script' instead of %%u.\n");
|
|
+
|
|
+ TALLOC_FREE(le_username);
|
|
+ }
|
|
+
|
|
+ *cmd_out = cmd;
|
|
+ return NT_STATUS_OK;
|
|
+}
|
|
+
|
|
+
|
|
NTSTATUS check_password_complexity(const char *username,
|
|
const char *fullname,
|
|
const char *password,
|
|
enum samPwdChangeReason *samr_reject_reason)
|
|
{
|
|
+ int check_ret;
|
|
+ NTSTATUS status;
|
|
TALLOC_CTX *tosctx = talloc_tos();
|
|
const struct loadparm_substitution *lp_sub =
|
|
loadparm_s3_global_substitution();
|
|
- int check_ret;
|
|
- char *cmd;
|
|
+ const char *orig_cmd = NULL;
|
|
+ char *cmd = NULL;
|
|
|
|
- /* Use external script to check password complexity */
|
|
- if ((lp_check_password_script(tosctx, lp_sub) == NULL)
|
|
- || (*(lp_check_password_script(tosctx, lp_sub)) == '\0')){
|
|
+ orig_cmd = lp_check_password_script(tosctx, lp_sub);
|
|
+ if (orig_cmd == NULL || orig_cmd[0] == '\0') {
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
- cmd = talloc_string_sub(tosctx, lp_check_password_script(tosctx, lp_sub), "%u",
|
|
- username);
|
|
- if (!cmd) {
|
|
- return NT_STATUS_PASSWORD_RESTRICTION;
|
|
+ /* note we don't use 'fullname' or 'password' here */
|
|
+ status = check_password_complexity_internal(tosctx,
|
|
+ orig_cmd,
|
|
+ username,
|
|
+ &cmd);
|
|
+ if (!NT_STATUS_IS_OK(status)) {
|
|
+ return status;
|
|
}
|
|
|
|
check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", username, 1);
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 5f898b13ad4361966c8d92a40f50b1a3c6a093ba Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Sat, 2 May 2026 22:12:38 +1200
|
|
Subject: [PATCH 61/66] CVE-2026-4408: s3:samr-server: make
|
|
check_password_complexity_internal() non-static, for easier testing
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/rpc_server/samr/srv_samr_chgpasswd.c | 8 ++++----
|
|
source3/rpc_server/samr/srv_samr_util.h | 5 +++++
|
|
2 files changed, 9 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c
|
|
index 9afb8799aea..3f48da47a5b 100644
|
|
--- a/source3/rpc_server/samr/srv_samr_chgpasswd.c
|
|
+++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c
|
|
@@ -1009,10 +1009,10 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext)
|
|
/***********************************************************
|
|
************************************************************/
|
|
|
|
-static NTSTATUS check_password_complexity_internal(TALLOC_CTX *tosctx,
|
|
- const char *orig_cmd,
|
|
- const char *username,
|
|
- char **cmd_out)
|
|
+NTSTATUS check_password_complexity_internal(TALLOC_CTX *tosctx,
|
|
+ const char *orig_cmd,
|
|
+ const char *username,
|
|
+ char **cmd_out)
|
|
{
|
|
const char *fallback_username = "__CVE-2026-4408_FallbackUsername__";
|
|
const char *inv = NULL;
|
|
diff --git a/source3/rpc_server/samr/srv_samr_util.h b/source3/rpc_server/samr/srv_samr_util.h
|
|
index 5e839ac77c0..a3a22012858 100644
|
|
--- a/source3/rpc_server/samr/srv_samr_util.h
|
|
+++ b/source3/rpc_server/samr/srv_samr_util.h
|
|
@@ -79,6 +79,11 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
|
|
uchar password_encrypted_with_nt_hash[516],
|
|
const uchar old_nt_hash_encrypted[16],
|
|
enum samPwdChangeReason *reject_reason);
|
|
+
|
|
+NTSTATUS check_password_complexity_internal(TALLOC_CTX *mem_ctx,
|
|
+ const char *_orig_cmd,
|
|
+ const char *username,
|
|
+ char **cmd_out);
|
|
NTSTATUS check_password_complexity(const char *username,
|
|
const char *fullname,
|
|
const char *password,
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 1054c2ffdc707cee9778dbc0ff4083ae60d9b359 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Date: Sat, 2 May 2026 22:14:43 +1200
|
|
Subject: [PATCH 62/66] CVE-2026-4408: s3:torture: tests for password
|
|
complexity scripts
|
|
|
|
This tries to demonstrate the new logic for %u in
|
|
'check password script'.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
|
|
|
|
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
---
|
|
selftest/tests.py | 2 +
|
|
source3/torture/test_rpc_samr.c | 358 ++++++++++++++++++++++++++++++++
|
|
source3/torture/wscript_build | 6 +
|
|
3 files changed, 366 insertions(+)
|
|
create mode 100644 source3/torture/test_rpc_samr.c
|
|
|
|
diff --git a/selftest/tests.py b/selftest/tests.py
|
|
index c92676f66eb..84a4baa6e19 100644
|
|
--- a/selftest/tests.py
|
|
+++ b/selftest/tests.py
|
|
@@ -585,6 +585,8 @@ plantestsuite("samba.unittests.test_oLschema2ldif", "none",
|
|
[os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")])
|
|
plantestsuite("samba.unittests.auth.sam", "none",
|
|
[os.path.join(bindir(), "test_auth_sam")])
|
|
+plantestsuite("samba.unittests.test_rpc_samr", "none",
|
|
+ [os.path.join(bindir(), "test_rpc_samr")])
|
|
if have_heimdal_support and not using_system_gssapi:
|
|
plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none",
|
|
[valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))])
|
|
diff --git a/source3/torture/test_rpc_samr.c b/source3/torture/test_rpc_samr.c
|
|
new file mode 100644
|
|
index 00000000000..8d4f3985246
|
|
--- /dev/null
|
|
+++ b/source3/torture/test_rpc_samr.c
|
|
@@ -0,0 +1,358 @@
|
|
+
|
|
+#include <stdarg.h>
|
|
+#include <stddef.h>
|
|
+#include <stdint.h>
|
|
+#include <setjmp.h>
|
|
+#include <sys/stat.h>
|
|
+#include <cmocka.h>
|
|
+#include "includes.h"
|
|
+#include "talloc.h"
|
|
+#include "libcli/util/ntstatus.h"
|
|
+#include "../librpc/gen_ndr/samr.h"
|
|
+#include "rpc_server/samr/srv_samr_util.h"
|
|
+
|
|
+/* set SAMR_DEBUG_VERBOSE to true to print more. */
|
|
+#define SAMR_DEBUG_VERBOSE true
|
|
+
|
|
+#if SAMR_DEBUG_VERBOSE
|
|
+#define debug_message(...) print_message(__VA_ARGS__)
|
|
+#else
|
|
+#define debug_message(...) /* debug_message */
|
|
+#endif
|
|
+
|
|
+static int setup_talloc_context(void **state)
|
|
+{
|
|
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
+ *state = mem_ctx;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int teardown_talloc_context(void **state)
|
|
+{
|
|
+ TALLOC_CTX *mem_ctx = *state;
|
|
+ TALLOC_FREE(mem_ctx);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct cmd_expansion {
|
|
+ const char *lp_cmd;
|
|
+ const char *username;
|
|
+ const char *result_cmd;
|
|
+ NTSTATUS result_code;
|
|
+};
|
|
+
|
|
+static struct cmd_expansion expansions[] = {
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob",
|
|
+ "/bin/echo 'bob'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob'",
|
|
+ "/bin/echo 'bob_'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob\'",
|
|
+ "/bin/echo 'bob_'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob'''",
|
|
+ "/bin/echo 'bob___'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob*",
|
|
+ NULL,
|
|
+ NT_STATUS_INVALID_USER_PRINCIPAL_NAME
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "bob\"",
|
|
+ NULL,
|
|
+ NT_STATUS_INVALID_USER_PRINCIPAL_NAME
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u",
|
|
+ "bob bob bob",
|
|
+ "/bin/echo '__CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"%u\"",
|
|
+ " ",
|
|
+ "/bin/echo ' '",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo \"--uu=__CVE-2026-4408_FallbackUsername__\"",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob !0",
|
|
+ "/bin/echo \"--uu=__CVE-2026-4408_FallbackUsername__\"",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "!0",
|
|
+ "/bin/echo '!0'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo \"--uu=%u\"",
|
|
+ "bob \\",
|
|
+ NULL,
|
|
+ NT_STATUS_INVALID_USER_PRINCIPAL_NAME
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "bob >> x",
|
|
+ NULL,
|
|
+ NT_STATUS_INVALID_USER_PRINCIPAL_NAME
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '--uu=%u\"",
|
|
+ "bob",
|
|
+ "/bin/echo '--uu=__CVE-2026-4408_FallbackUsername__\"",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "bob",
|
|
+ "/bin/echo --uu='bob'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "bob",
|
|
+ "/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "`ls`",
|
|
+ "/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu'=%u'",
|
|
+ "$(ls)",
|
|
+ "/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u'",
|
|
+ "$(ls)",
|
|
+ "/bin/echo --uu='_(ls)'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu=\"'%u'\"",
|
|
+ "bob",
|
|
+ "/bin/echo --uu=\"'bob'\"",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu='%u' --yy='%u' '%u' %u",
|
|
+ "bob",
|
|
+ "/bin/echo --uu='bob' --yy='bob' 'bob' __CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo --uu=%u%u'' %user 50%u",
|
|
+ "bob",
|
|
+ "/bin/echo --uu=__CVE-2026-4408_FallbackUsername____CVE-2026-4408_FallbackUsername__'' __CVE-2026-4408_FallbackUsername__ser 50__CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "!!",
|
|
+ "/bin/echo '!!'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ ">xxx",
|
|
+ NULL,
|
|
+ NT_STATUS_INVALID_USER_PRINCIPAL_NAME
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "\\",
|
|
+ NULL,
|
|
+ NT_STATUS_INVALID_USER_PRINCIPAL_NAME
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "3",
|
|
+ "/bin/echo '3'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "3$",
|
|
+ "/bin/echo '3_'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "comp$",
|
|
+ "/bin/echo 'comp_'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "3$3",
|
|
+ "/bin/echo '3_3'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo '%u'",
|
|
+ "q $3",
|
|
+ "/bin/echo 'q _3'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s '%u' %u",
|
|
+ "āāā",
|
|
+ "/bin/echo -s 'āāā' __CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s '%u' %u",
|
|
+ "-āāā",
|
|
+ "/bin/echo -s '_āāā' __CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s %u",
|
|
+ "āāā",
|
|
+ "/bin/echo -s 'āāā'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s %u",
|
|
+ "a -a",
|
|
+ "/bin/echo -s 'a -a'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s=%u %u",
|
|
+ "ā -a",
|
|
+ "/bin/echo -s='ā -a' 'ā -a'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -s=\"%u %u\"",
|
|
+ "ā -a",
|
|
+ "/bin/echo -s=\"__CVE-2026-4408_FallbackUsername__ __CVE-2026-4408_FallbackUsername__\"",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -m='fridge' %u",
|
|
+ "ā -x -ß",
|
|
+ "/bin/echo -m='fridge' __CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo -m='fridge' %u",
|
|
+ "-ā -a",
|
|
+ "/bin/echo -m='fridge' __CVE-2026-4408_FallbackUsername__",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "-n",
|
|
+ "/bin/echo '_n'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+ {
|
|
+ "/bin/echo %u",
|
|
+ "o'clock",
|
|
+ "/bin/echo 'o_clock'",
|
|
+ NT_STATUS_OK
|
|
+ },
|
|
+};
|
|
+
|
|
+static void test_expansions(void **state)
|
|
+{
|
|
+ TALLOC_CTX *mem_ctx = *state;
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(expansions); i++) {
|
|
+ struct cmd_expansion t = expansions[i];
|
|
+ char *result_cmd = NULL;
|
|
+ NTSTATUS status;
|
|
+
|
|
+ status = check_password_complexity_internal(mem_ctx,
|
|
+ t.lp_cmd,
|
|
+ t.username,
|
|
+ &result_cmd);
|
|
+ if (NT_STATUS_IS_OK(t.result_code) && NT_STATUS_IS_OK(status)) {
|
|
+ int cmp;
|
|
+
|
|
+ cmp = strcmp(t.result_cmd, result_cmd);
|
|
+ if (cmp == 0) {
|
|
+ debug_message("[%zu] «%s» «%s» -> «%s», nstatus %s; AS EXPECTED\n",
|
|
+ i, t.lp_cmd,
|
|
+ t.username,
|
|
+ result_cmd,
|
|
+ nt_errstr(status));
|
|
+ } else {
|
|
+ debug_message("[%zu] «%s» «%s», nstatus %s; "
|
|
+ "expected «%s» got «%s»\033[1;31m BAD! \033[0m\n",
|
|
+ i, t.lp_cmd,
|
|
+ t.username,
|
|
+ nt_errstr(status),
|
|
+ t.result_cmd,
|
|
+ result_cmd);
|
|
+ }
|
|
+ assert_int_equal(cmp, 0);
|
|
+ } else if (NT_STATUS_EQUAL(status, t.result_code)) {
|
|
+ debug_message("[%zu] «%s» «%s», nstatus %s FAILED AS EXPECTED\n",
|
|
+ i, t.lp_cmd,
|
|
+ t.username,
|
|
+ nt_errstr(status));
|
|
+ } else {
|
|
+ debug_message("[%zu] «%s» «%s» -> «%s», nstatus %s; "
|
|
+ "EXPECTED result «%s» ntstatus %s; \033[1;31m BAD! \033[0m\n",
|
|
+ i, t.lp_cmd,
|
|
+ t.username,
|
|
+ result_cmd,
|
|
+ nt_errstr(status),
|
|
+ t.result_cmd,
|
|
+ nt_errstr(t.result_code));
|
|
+ assert_int_equal(true, false);
|
|
+ }
|
|
+ }
|
|
+ debug_message("ALL correct\n");
|
|
+}
|
|
+
|
|
+int main(void)
|
|
+{
|
|
+ const struct CMUnitTest tests[] = {
|
|
+ cmocka_unit_test(test_expansions),
|
|
+ };
|
|
+ if (!isatty(1)) {
|
|
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
|
|
+ }
|
|
+ return cmocka_run_group_tests(tests,
|
|
+ setup_talloc_context,
|
|
+ teardown_talloc_context);
|
|
+}
|
|
diff --git a/source3/torture/wscript_build b/source3/torture/wscript_build
|
|
index 1d2520099e3..d04008b3df1 100644
|
|
--- a/source3/torture/wscript_build
|
|
+++ b/source3/torture/wscript_build
|
|
@@ -133,3 +133,9 @@ bld.SAMBA3_BINARY('vfstest',
|
|
SMBREADLINE
|
|
''',
|
|
for_selftest=True)
|
|
+
|
|
+bld.SAMBA3_BINARY('test_rpc_samr',
|
|
+ source='test_rpc_samr.c',
|
|
+ deps='''RPC_SERVICE cmocka
|
|
+ ''',
|
|
+ for_selftest=True)
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From cd0f499a2478ce5676aa1aefe378d50f11026517 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Fri, 8 May 2026 23:27:35 +0200
|
|
Subject: [PATCH 63/66] CVE-2026-4408: s3:testparm: warn about 'check password
|
|
script' %u usage
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source3/utils/testparm.c | 12 ++++++++++++
|
|
1 file changed, 12 insertions(+)
|
|
|
|
diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c
|
|
index c758313d466..49dc39b2cab 100644
|
|
--- a/source3/utils/testparm.c
|
|
+++ b/source3/utils/testparm.c
|
|
@@ -359,6 +359,7 @@ static int do_global_checks(void)
|
|
const char **lp_ptr = NULL;
|
|
const struct loadparm_substitution *lp_sub =
|
|
loadparm_s3_global_substitution();
|
|
+ const char *check_pw_script = NULL;
|
|
int ival;
|
|
|
|
fprintf(stderr, "\n");
|
|
@@ -831,6 +832,17 @@ static int do_global_checks(void)
|
|
#endif
|
|
}
|
|
|
|
+ check_pw_script = lp_check_password_script(talloc_tos(), lp_sub);
|
|
+ if (talloc_string_sub_mixed_quoting(check_pw_script, 'u')) {
|
|
+ fprintf(stderr,
|
|
+ "WARNING: You are using 'check password script' "
|
|
+ "with mixed quoting and %%u.\n"
|
|
+ "CVE-2026-4408 changed the way %%u substitution works. \n"
|
|
+ "You should use the SAMBA_CPS_ACCOUNT_NAME "
|
|
+ "environment variable exported to the script, or\n"
|
|
+ "at least use single quotes (directly) around '%%u'.\n\n");
|
|
+ }
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From 7c6d55ab1924e93a7c67ab563a7162260cf394eb Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Mon, 11 May 2026 13:52:52 +0200
|
|
Subject: [PATCH 64/66] CVE-2026-4408: docs-xml/smbdotconf: clarify '%u' in
|
|
'check password script'
|
|
|
|
Admins should use SAMBA_CPS_ACCOUNT_NAME.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
docs-xml/smbdotconf/security/checkpasswordscript.xml | 10 ++++++++--
|
|
1 file changed, 8 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/docs-xml/smbdotconf/security/checkpasswordscript.xml b/docs-xml/smbdotconf/security/checkpasswordscript.xml
|
|
index 18aa2c6d290..dd162d89f08 100644
|
|
--- a/docs-xml/smbdotconf/security/checkpasswordscript.xml
|
|
+++ b/docs-xml/smbdotconf/security/checkpasswordscript.xml
|
|
@@ -20,8 +20,8 @@
|
|
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
- SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user,
|
|
- the is the same as the %u substitutions in the none AD DC case.
|
|
+ SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user.
|
|
+ It is the same as the '%u' substitutions in the non AD DC case.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
@@ -33,6 +33,12 @@
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
|
|
+ <para>Even on a non AD DC SAMBA_CPS_ACCOUNT_NAME is the preferred way to access the
|
|
+ account name, as it contains the raw value provided by the client. If that's not
|
|
+ possible you should use single quotes (directly) around %u, e.g. /path/to/somescript '%u',
|
|
+ see CVE-2026-4408 for more details.
|
|
+ </para>
|
|
+
|
|
<para>Note: In the example directory is a sample program called <command moreinfo="none">crackcheck</command>
|
|
that uses cracklib to check the password quality.</para>
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From fbf23d3f6e19dea6331c446e80cebf3018c7e332 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Metzmacher <metze@samba.org>
|
|
Date: Fri, 17 Apr 2026 10:45:58 +0200
|
|
Subject: [PATCH 65/66] third_party/ngtcp2: import v1.22.1 for CVE-2026-40170
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
For CVE-2026-40170 see:
|
|
https://github.com/ngtcp2/ngtcp2/security/advisories/GHSA-f523-465f-8c8f
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16059
|
|
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
|
Reviewed-by: Andreas Schneider <asn@samba.org>
|
|
(cherry picked from commit 706dc118b3bdbe03ada53939c1634ab13c91455a)
|
|
|
|
Autobuild-User(v4-23-test): Björn Jacke <bjacke@samba.org>
|
|
Autobuild-Date(v4-23-test): Mon Apr 27 12:59:57 UTC 2026 on atb-devel-224
|
|
---
|
|
third_party/ngtcp2/crypto/CMakeLists.txt | 6 +
|
|
third_party/ngtcp2/crypto/Makefile.am | 4 +
|
|
.../ngtcp2/crypto/boringssl/boringssl.c | 31 +-
|
|
.../libngtcp2_crypto_boringssl.pc.in | 1 +
|
|
third_party/ngtcp2/crypto/gnutls/gnutls.c | 117 +-
|
|
.../gnutls/libngtcp2_crypto_gnutls.pc.in | 1 +
|
|
.../ngtcp2/crypto/includes/CMakeLists.txt | 2 +-
|
|
.../ngtcp2/crypto/includes/Makefile.am | 4 +
|
|
.../crypto/includes/ngtcp2/ngtcp2_crypto.h | 122 +-
|
|
third_party/ngtcp2/crypto/ossl/CMakeLists.txt | 18 +-
|
|
.../crypto/ossl/libngtcp2_crypto_ossl.pc.in | 1 +
|
|
third_party/ngtcp2/crypto/ossl/ossl.c | 162 +-
|
|
.../picotls/libngtcp2_crypto_picotls.pc.in | 1 +
|
|
third_party/ngtcp2/crypto/picotls/picotls.c | 39 +-
|
|
third_party/ngtcp2/crypto/quictls/.gitignore | 1 +
|
|
.../ngtcp2/crypto/quictls/CMakeLists.txt | 32 +-
|
|
third_party/ngtcp2/crypto/quictls/Makefile.am | 16 +-
|
|
.../quictls/libngtcp2_crypto_libressl.pc.in | 34 +
|
|
.../quictls/libngtcp2_crypto_quictls.pc.in | 1 +
|
|
third_party/ngtcp2/crypto/quictls/quictls.c | 80 +-
|
|
third_party/ngtcp2/crypto/shared.c | 259 ++-
|
|
third_party/ngtcp2/crypto/shared.h | 20 -
|
|
.../wolfssl/libngtcp2_crypto_wolfssl.pc.in | 1 +
|
|
third_party/ngtcp2/crypto/wolfssl/wolfssl.c | 64 +-
|
|
third_party/ngtcp2/lib/CMakeLists.txt | 21 +-
|
|
third_party/ngtcp2/lib/Makefile.am | 10 +-
|
|
third_party/ngtcp2/lib/config.cmake.in | 3 +
|
|
.../ngtcp2/lib/includes/ngtcp2/ngtcp2.h | 748 ++++++-
|
|
third_party/ngtcp2/lib/ngtcp2_acktr.c | 36 +-
|
|
third_party/ngtcp2/lib/ngtcp2_acktr.h | 28 +-
|
|
third_party/ngtcp2/lib/ngtcp2_addr.c | 19 +-
|
|
third_party/ngtcp2/lib/ngtcp2_addr.h | 8 +-
|
|
third_party/ngtcp2/lib/ngtcp2_balloc.c | 14 +-
|
|
third_party/ngtcp2/lib/ngtcp2_bbr.c | 474 +++--
|
|
third_party/ngtcp2/lib/ngtcp2_bbr.h | 26 +-
|
|
third_party/ngtcp2/lib/ngtcp2_buf.c | 14 +-
|
|
third_party/ngtcp2/lib/ngtcp2_buf.h | 11 +-
|
|
third_party/ngtcp2/lib/ngtcp2_callbacks.c | 75 +
|
|
third_party/ngtcp2/lib/ngtcp2_callbacks.h | 73 +
|
|
third_party/ngtcp2/lib/ngtcp2_cc.c | 283 ++-
|
|
third_party/ngtcp2/lib/ngtcp2_cc.h | 78 +-
|
|
third_party/ngtcp2/lib/ngtcp2_cid.c | 41 +-
|
|
third_party/ngtcp2/lib/ngtcp2_cid.h | 34 +-
|
|
third_party/ngtcp2/lib/ngtcp2_conn.c | 1875 ++++++++++++-----
|
|
third_party/ngtcp2/lib/ngtcp2_conn.h | 126 +-
|
|
third_party/ngtcp2/lib/ngtcp2_conn_info.c | 50 +
|
|
third_party/ngtcp2/lib/ngtcp2_conn_info.h | 45 +
|
|
third_party/ngtcp2/lib/ngtcp2_conn_stat.h | 39 +
|
|
third_party/ngtcp2/lib/ngtcp2_conv.c | 34 +-
|
|
third_party/ngtcp2/lib/ngtcp2_crypto.c | 24 +-
|
|
third_party/ngtcp2/lib/ngtcp2_crypto.h | 4 +-
|
|
third_party/ngtcp2/lib/ngtcp2_dcidtr.c | 17 +-
|
|
third_party/ngtcp2/lib/ngtcp2_dcidtr.h | 15 +-
|
|
third_party/ngtcp2/lib/ngtcp2_frame_chain.c | 73 +-
|
|
third_party/ngtcp2/lib/ngtcp2_frame_chain.h | 68 +-
|
|
third_party/ngtcp2/lib/ngtcp2_gaptr.c | 20 +-
|
|
third_party/ngtcp2/lib/ngtcp2_ksl.c | 361 ++--
|
|
third_party/ngtcp2/lib/ngtcp2_ksl.h | 117 +-
|
|
third_party/ngtcp2/lib/ngtcp2_log.c | 604 +++---
|
|
third_party/ngtcp2/lib/ngtcp2_log.h | 69 +-
|
|
third_party/ngtcp2/lib/ngtcp2_macro.h | 7 +
|
|
third_party/ngtcp2/lib/ngtcp2_map.c | 271 ++-
|
|
third_party/ngtcp2/lib/ngtcp2_map.h | 16 +-
|
|
third_party/ngtcp2/lib/ngtcp2_net.h | 8 +-
|
|
third_party/ngtcp2/lib/ngtcp2_objalloc.h | 4 +-
|
|
third_party/ngtcp2/lib/ngtcp2_path.c | 6 -
|
|
third_party/ngtcp2/lib/ngtcp2_path.h | 8 -
|
|
third_party/ngtcp2/lib/ngtcp2_pcg.c | 88 +
|
|
third_party/ngtcp2/lib/ngtcp2_pcg.h | 54 +
|
|
third_party/ngtcp2/lib/ngtcp2_pkt.c | 398 +++-
|
|
third_party/ngtcp2/lib/ngtcp2_pkt.h | 181 +-
|
|
third_party/ngtcp2/lib/ngtcp2_ppe.c | 4 +-
|
|
third_party/ngtcp2/lib/ngtcp2_pv.c | 19 +-
|
|
third_party/ngtcp2/lib/ngtcp2_pv.h | 24 +-
|
|
third_party/ngtcp2/lib/ngtcp2_qlog.c | 185 +-
|
|
third_party/ngtcp2/lib/ngtcp2_qlog.h | 2 +-
|
|
third_party/ngtcp2/lib/ngtcp2_range.c | 22 +-
|
|
third_party/ngtcp2/lib/ngtcp2_ratelim.c | 84 +
|
|
third_party/ngtcp2/lib/ngtcp2_ratelim.h | 59 +
|
|
third_party/ngtcp2/lib/ngtcp2_ringbuf.c | 14 +-
|
|
third_party/ngtcp2/lib/ngtcp2_ringbuf.h | 4 +-
|
|
third_party/ngtcp2/lib/ngtcp2_rob.c | 50 +-
|
|
third_party/ngtcp2/lib/ngtcp2_rob.h | 8 +-
|
|
third_party/ngtcp2/lib/ngtcp2_rst.c | 48 +-
|
|
third_party/ngtcp2/lib/ngtcp2_rst.h | 7 +-
|
|
third_party/ngtcp2/lib/ngtcp2_rtb.c | 210 +-
|
|
third_party/ngtcp2/lib/ngtcp2_rtb.h | 22 +-
|
|
third_party/ngtcp2/lib/ngtcp2_settings.c | 7 +
|
|
third_party/ngtcp2/lib/ngtcp2_settings.h | 7 +
|
|
third_party/ngtcp2/lib/ngtcp2_str.c | 187 +-
|
|
third_party/ngtcp2/lib/ngtcp2_str.h | 35 +-
|
|
third_party/ngtcp2/lib/ngtcp2_strm.c | 210 +-
|
|
third_party/ngtcp2/lib/ngtcp2_strm.h | 40 +-
|
|
.../ngtcp2/lib/ngtcp2_transport_params.c | 21 +-
|
|
.../ngtcp2/lib/ngtcp2_transport_params.h | 14 +-
|
|
third_party/ngtcp2/lib/ngtcp2_vec.c | 39 +-
|
|
third_party/ngtcp2/lib/ngtcp2_vec.h | 31 +-
|
|
third_party/ngtcp2/lib/ngtcp2_window_filter.c | 2 +-
|
|
third_party/ngtcp2/wscript | 4 +
|
|
99 files changed, 5992 insertions(+), 2962 deletions(-)
|
|
create mode 100644 third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_callbacks.c
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_callbacks.h
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_conn_info.c
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_conn_info.h
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_pcg.c
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_pcg.h
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_ratelim.c
|
|
create mode 100644 third_party/ngtcp2/lib/ngtcp2_ratelim.h
|
|
|
|
diff --git a/third_party/ngtcp2/crypto/CMakeLists.txt b/third_party/ngtcp2/crypto/CMakeLists.txt
|
|
index c947837b31e..5e428fa812e 100644
|
|
--- a/third_party/ngtcp2/crypto/CMakeLists.txt
|
|
+++ b/third_party/ngtcp2/crypto/CMakeLists.txt
|
|
@@ -31,6 +31,12 @@ elseif(ENABLE_OPENSSL)
|
|
message(WARNING "libngtcp2_crypto_quictls library is disabled due to lack of good quictls")
|
|
endif()
|
|
|
|
+if(HAVE_LIBRESSL)
|
|
+ add_subdirectory(quictls)
|
|
+elseif(ENABLE_OPENSSL)
|
|
+ message(WARNING "libngtcp2_crypto_libressl library is disabled due to lack of good LibreSSL")
|
|
+endif()
|
|
+
|
|
if(HAVE_GNUTLS)
|
|
add_subdirectory(gnutls)
|
|
elseif(ENABLE_GNUTLS)
|
|
diff --git a/third_party/ngtcp2/crypto/Makefile.am b/third_party/ngtcp2/crypto/Makefile.am
|
|
index 8d2f7600f17..27224b9dcc1 100644
|
|
--- a/third_party/ngtcp2/crypto/Makefile.am
|
|
+++ b/third_party/ngtcp2/crypto/Makefile.am
|
|
@@ -30,6 +30,10 @@ if HAVE_QUICTLS
|
|
SUBDIRS += quictls
|
|
endif
|
|
|
|
+if HAVE_LIBRESSL
|
|
+SUBDIRS += quictls
|
|
+endif
|
|
+
|
|
if HAVE_GNUTLS
|
|
SUBDIRS += gnutls
|
|
endif
|
|
diff --git a/third_party/ngtcp2/crypto/boringssl/boringssl.c b/third_party/ngtcp2/crypto/boringssl/boringssl.c
|
|
index 283063f738e..e43faa76850 100644
|
|
--- a/third_party/ngtcp2/crypto/boringssl/boringssl.c
|
|
+++ b/third_party/ngtcp2/crypto/boringssl/boringssl.c
|
|
@@ -39,6 +39,7 @@
|
|
#include <openssl/chacha.h>
|
|
#include <openssl/rand.h>
|
|
|
|
+#include "ngtcp2_macro.h"
|
|
#include "shared.h"
|
|
|
|
typedef enum ngtcp2_crypto_boringssl_cipher_type {
|
|
@@ -401,7 +402,7 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
|
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
|
const uint8_t *sample) {
|
|
- static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
|
+ static const uint8_t PLAINTEXT[16] = {0};
|
|
ngtcp2_crypto_boringssl_cipher_ctx *ctx = hp_ctx->native_handle;
|
|
uint32_t counter;
|
|
|
|
@@ -419,7 +420,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
#else /* !defined(WORDS_BIGENDIAN) */
|
|
memcpy(&counter, sample, sizeof(counter));
|
|
#endif /* !defined(WORDS_BIGENDIAN) */
|
|
- CRYPTO_chacha_20(dest, PLAINTEXT, sizeof(PLAINTEXT) - 1, ctx->key,
|
|
+ CRYPTO_chacha_20(dest, PLAINTEXT, sizeof(PLAINTEXT), ctx->key,
|
|
sample + sizeof(counter), counter);
|
|
return 0;
|
|
default:
|
|
@@ -435,7 +436,8 @@ int ngtcp2_crypto_read_write_crypto_data(
|
|
int rv;
|
|
int err;
|
|
|
|
- if (SSL_provide_quic_data(
|
|
+ if (datalen &&
|
|
+ SSL_provide_quic_data(
|
|
ssl,
|
|
ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level(encryption_level),
|
|
data, datalen) != 1) {
|
|
@@ -464,6 +466,16 @@ int ngtcp2_crypto_read_write_crypto_data(
|
|
}
|
|
|
|
goto retry;
|
|
+ case SSL_ERROR_WANT_X509_LOOKUP:
|
|
+ case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
|
|
+ case SSL_ERROR_WANT_CERTIFICATE_VERIFY:
|
|
+ /* It might be better to return this error, but ngtcp2 does
|
|
+ not need to know whether handshake has been interrupted or
|
|
+ not. We expect that necessary plumbing should be done by
|
|
+ application when handshake is interrupted (e.g., via
|
|
+ SSL_PRIVATE_KEY_METHOD). If it does not work, we will
|
|
+ reconsider this. */
|
|
+ return 0;
|
|
default:
|
|
return -1;
|
|
}
|
|
@@ -567,6 +579,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data) {
|
|
+ (void)conn;
|
|
+ (void)user_data;
|
|
+
|
|
+ if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
|
|
+ return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
if (RAND_bytes(data, datalen) != 1) {
|
|
return -1;
|
|
diff --git a/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in b/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in
|
|
index 737970a8c6a..cf6ebbca5c2 100644
|
|
--- a/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in
|
|
+++ b/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in
|
|
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
|
|
Version: @VERSION@
|
|
Libs: -L${libdir} -lngtcp2_crypto_boringssl
|
|
Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2
|
|
diff --git a/third_party/ngtcp2/crypto/gnutls/gnutls.c b/third_party/ngtcp2/crypto/gnutls/gnutls.c
|
|
index 4e6990f87ef..cf7e6ca8934 100644
|
|
--- a/third_party/ngtcp2/crypto/gnutls/gnutls.c
|
|
+++ b/third_party/ngtcp2/crypto/gnutls/gnutls.c
|
|
@@ -35,6 +35,7 @@
|
|
#include <gnutls/crypto.h>
|
|
#include <string.h>
|
|
|
|
+#include "ngtcp2_macro.h"
|
|
#include "shared.h"
|
|
|
|
ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead) {
|
|
@@ -219,14 +220,15 @@ int ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
|
gnutls_cipher_algorithm_t cipher =
|
|
(gnutls_cipher_algorithm_t)(intptr_t)aead->native_handle;
|
|
gnutls_aead_cipher_hd_t hd;
|
|
- gnutls_datum_t _key;
|
|
|
|
(void)noncelen;
|
|
|
|
- _key.data = (void *)key;
|
|
- _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead);
|
|
-
|
|
- if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0) {
|
|
+ if (gnutls_aead_cipher_init(
|
|
+ &hd, cipher,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)key,
|
|
+ .size = (unsigned int)ngtcp2_crypto_aead_keylen(aead),
|
|
+ }) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -241,14 +243,15 @@ int ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
|
gnutls_cipher_algorithm_t cipher =
|
|
(gnutls_cipher_algorithm_t)(intptr_t)aead->native_handle;
|
|
gnutls_aead_cipher_hd_t hd;
|
|
- gnutls_datum_t _key;
|
|
|
|
(void)noncelen;
|
|
|
|
- _key.data = (void *)key;
|
|
- _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead);
|
|
-
|
|
- if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0) {
|
|
+ if (gnutls_aead_cipher_init(
|
|
+ &hd, cipher,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)key,
|
|
+ .size = (unsigned int)ngtcp2_crypto_aead_keylen(aead),
|
|
+ }) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -266,15 +269,17 @@ void ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx) {
|
|
int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
|
|
const ngtcp2_crypto_cipher *cipher,
|
|
const uint8_t *key) {
|
|
- gnutls_cipher_algorithm_t _cipher =
|
|
+ gnutls_cipher_algorithm_t cph =
|
|
(gnutls_cipher_algorithm_t)(intptr_t)cipher->native_handle;
|
|
gnutls_cipher_hd_t hd;
|
|
- gnutls_datum_t _key;
|
|
|
|
- _key.data = (void *)key;
|
|
- _key.size = (unsigned int)gnutls_cipher_get_key_size(_cipher);
|
|
-
|
|
- if (gnutls_cipher_init(&hd, _cipher, &_key, NULL) != 0) {
|
|
+ if (gnutls_cipher_init(
|
|
+ &hd, cph,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)key,
|
|
+ .size = (unsigned int)gnutls_cipher_get_key_size(cph),
|
|
+ },
|
|
+ NULL) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -294,10 +299,17 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
|
|
const uint8_t *salt, size_t saltlen) {
|
|
gnutls_mac_algorithm_t prf =
|
|
(gnutls_mac_algorithm_t)(intptr_t)md->native_handle;
|
|
- gnutls_datum_t _secret = {(void *)secret, (unsigned int)secretlen};
|
|
- gnutls_datum_t _salt = {(void *)salt, (unsigned int)saltlen};
|
|
|
|
- if (gnutls_hkdf_extract(prf, &_secret, &_salt, dest) != 0) {
|
|
+ if (gnutls_hkdf_extract(prf,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)secret,
|
|
+ .size = (unsigned int)secretlen,
|
|
+ },
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)salt,
|
|
+ .size = (unsigned int)saltlen,
|
|
+ },
|
|
+ dest) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -310,10 +322,17 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
|
|
size_t infolen) {
|
|
gnutls_mac_algorithm_t prf =
|
|
(gnutls_mac_algorithm_t)(intptr_t)md->native_handle;
|
|
- gnutls_datum_t _secret = {(void *)secret, (unsigned int)secretlen};
|
|
- gnutls_datum_t _info = {(void *)info, (unsigned int)infolen};
|
|
|
|
- if (gnutls_hkdf_expand(prf, &_secret, &_info, dest, destlen) != 0) {
|
|
+ if (gnutls_hkdf_expand(prf,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)secret,
|
|
+ .size = (unsigned int)secretlen,
|
|
+ },
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)info,
|
|
+ .size = (unsigned int)infolen,
|
|
+ },
|
|
+ dest, destlen) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -328,18 +347,32 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen,
|
|
(gnutls_mac_algorithm_t)(intptr_t)md->native_handle;
|
|
size_t keylen = ngtcp2_crypto_md_hashlen(md);
|
|
uint8_t key[64];
|
|
- gnutls_datum_t _secret = {(void *)secret, (unsigned int)secretlen};
|
|
- gnutls_datum_t _key = {(void *)key, (unsigned int)keylen};
|
|
- gnutls_datum_t _salt = {(void *)salt, (unsigned int)saltlen};
|
|
- gnutls_datum_t _info = {(void *)info, (unsigned int)infolen};
|
|
|
|
assert(keylen <= sizeof(key));
|
|
|
|
- if (gnutls_hkdf_extract(prf, &_secret, &_salt, key) != 0) {
|
|
+ if (gnutls_hkdf_extract(prf,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)secret,
|
|
+ .size = (unsigned int)secretlen,
|
|
+ },
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)salt,
|
|
+ .size = (unsigned int)saltlen,
|
|
+ },
|
|
+ key) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
- if (gnutls_hkdf_expand(prf, &_key, &_info, dest, destlen) != 0) {
|
|
+ if (gnutls_hkdf_expand(prf,
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)key,
|
|
+ .size = (unsigned int)keylen,
|
|
+ },
|
|
+ &(gnutls_datum_t){
|
|
+ .data = (uint8_t *)info,
|
|
+ .size = (unsigned int)infolen,
|
|
+ },
|
|
+ dest, destlen) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -402,13 +435,11 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
switch (cipher) {
|
|
case GNUTLS_CIPHER_AES_128_CBC:
|
|
case GNUTLS_CIPHER_AES_256_CBC: {
|
|
- uint8_t iv[16];
|
|
- uint8_t buf[16];
|
|
-
|
|
/* Emulate one block AES-ECB by invalidating the effect of IV */
|
|
- memset(iv, 0, sizeof(iv));
|
|
+ static const uint8_t iv[16] = {0};
|
|
+ uint8_t buf[16];
|
|
|
|
- gnutls_cipher_set_iv(hd, iv, sizeof(iv));
|
|
+ gnutls_cipher_set_iv(hd, (uint8_t *)iv, sizeof(iv));
|
|
|
|
if (gnutls_cipher_encrypt2(hd, sample, 16, buf, sizeof(buf)) != 0) {
|
|
return -1;
|
|
@@ -418,14 +449,14 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
} break;
|
|
|
|
case GNUTLS_CIPHER_CHACHA20_32: {
|
|
- static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
|
+ static const uint8_t PLAINTEXT[16] = {0};
|
|
uint8_t buf[5 + 16];
|
|
size_t buflen = sizeof(buf);
|
|
|
|
gnutls_cipher_set_iv(hd, (void *)sample, 16);
|
|
|
|
- if (gnutls_cipher_encrypt2(hd, PLAINTEXT, sizeof(PLAINTEXT) - 1, buf,
|
|
- buflen) != 0) {
|
|
+ if (gnutls_cipher_encrypt2(hd, PLAINTEXT, sizeof(PLAINTEXT), buf, buflen) !=
|
|
+ 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -542,6 +573,20 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data) {
|
|
+ (void)conn;
|
|
+ (void)user_data;
|
|
+
|
|
+ if (gnutls_rnd(GNUTLS_RND_RANDOM, data->data,
|
|
+ NGTCP2_PATH_CHALLENGE_DATALEN) != 0) {
|
|
+ return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
if (gnutls_rnd(GNUTLS_RND_RANDOM, data, datalen) != 0) {
|
|
return -1;
|
|
diff --git a/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in b/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in
|
|
index 890e89d45f8..3be801a7e85 100644
|
|
--- a/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in
|
|
+++ b/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in
|
|
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
|
|
Version: @VERSION@
|
|
Libs: -L${libdir} -lngtcp2_crypto_gnutls
|
|
Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2, gnutls
|
|
diff --git a/third_party/ngtcp2/crypto/includes/CMakeLists.txt b/third_party/ngtcp2/crypto/includes/CMakeLists.txt
|
|
index 8415158c7e4..888c4991bee 100644
|
|
--- a/third_party/ngtcp2/crypto/includes/CMakeLists.txt
|
|
+++ b/third_party/ngtcp2/crypto/includes/CMakeLists.txt
|
|
@@ -25,7 +25,7 @@ install(FILES
|
|
ngtcp2/ngtcp2_crypto.h
|
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ngtcp2")
|
|
|
|
-if(HAVE_QUICTLS)
|
|
+if(HAVE_QUICTLS OR HAVE_LIBRESSL)
|
|
install(FILES
|
|
ngtcp2/ngtcp2_crypto_quictls.h
|
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ngtcp2")
|
|
diff --git a/third_party/ngtcp2/crypto/includes/Makefile.am b/third_party/ngtcp2/crypto/includes/Makefile.am
|
|
index 4aebf426a3a..63b22af85a9 100644
|
|
--- a/third_party/ngtcp2/crypto/includes/Makefile.am
|
|
+++ b/third_party/ngtcp2/crypto/includes/Makefile.am
|
|
@@ -28,6 +28,10 @@ if HAVE_QUICTLS
|
|
nobase_include_HEADERS += ngtcp2/ngtcp2_crypto_quictls.h
|
|
endif
|
|
|
|
+if HAVE_LIBRESSL
|
|
+nobase_include_HEADERS += ngtcp2/ngtcp2_crypto_quictls.h
|
|
+endif
|
|
+
|
|
if HAVE_GNUTLS
|
|
nobase_include_HEADERS += ngtcp2/ngtcp2_crypto_gnutls.h
|
|
endif
|
|
diff --git a/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
|
|
index 003ec6b4c3f..28eeeb5ead8 100644
|
|
--- a/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
|
|
+++ b/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
|
|
@@ -524,11 +524,14 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn,
|
|
* completes. It is allowed to call this function with |datalen| ==
|
|
* 0. In this case, no additional read operation is done.
|
|
*
|
|
+ * This function is implemented per TLS backend. See
|
|
+ * :ref:`tls-integration` for more details.
|
|
+ *
|
|
* This function returns 0 if it succeeds, or a negative error code.
|
|
* The generic error code is -1 if a specific error code is not
|
|
* suitable. The error codes less than -10000 are specific to
|
|
- * underlying TLS implementation. For quictls, the error codes are
|
|
- * defined in *ngtcp2_crypto_quictls.h*.
|
|
+ * underlying TLS implementation. Refer to the implementation
|
|
+ * specific header files for error codes.
|
|
*/
|
|
NGTCP2_EXTERN int
|
|
ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn,
|
|
@@ -542,11 +545,22 @@ ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn,
|
|
* `ngtcp2_crypto_read_write_crypto_data`. It can be directly passed
|
|
* to :member:`ngtcp2_callbacks.recv_crypto_data` field.
|
|
*
|
|
+ * For quictls and OpenSSL, the following error codes are treated as
|
|
+ * success:
|
|
+ *
|
|
+ * - -10001 (e.g., :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP`)
|
|
+ * - -10002 (e.g., :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB`)
|
|
+ *
|
|
+ * To continue the interrupted handshake, call
|
|
+ * `ngtcp2_conn_continue_handshake`.
|
|
+ *
|
|
+ * See :ref:`tls-integration` for more details.
|
|
+ *
|
|
* If this function is used, the TLS implementation specific error
|
|
* codes described in `ngtcp2_crypto_read_write_crypto_data` are
|
|
- * treated as if it returns -1. Do not use this function if an
|
|
- * application wishes to use the TLS implementation specific error
|
|
- * codes.
|
|
+ * treated as if it returns -1 except for those that are listed above.
|
|
+ * Do not use this function if an application wishes to use the TLS
|
|
+ * implementation specific error codes.
|
|
*/
|
|
NGTCP2_EXTERN int ngtcp2_crypto_recv_crypto_data_cb(
|
|
ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, uint64_t offset,
|
|
@@ -583,7 +597,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
|
|
* :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY` is the magic byte for
|
|
* Retry token generated by `ngtcp2_crypto_generate_retry_token`.
|
|
*/
|
|
-#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xb6
|
|
+#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xB6
|
|
|
|
/**
|
|
* @macro
|
|
@@ -591,7 +605,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
|
|
* :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2` is the magic byte for
|
|
* Retry token generated by `ngtcp2_crypto_generate_retry_token2`.
|
|
*/
|
|
-#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 0xb7
|
|
+#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 0xB7
|
|
|
|
/**
|
|
* @macro
|
|
@@ -627,7 +641,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
|
|
* @macro
|
|
*
|
|
* :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` is the maximum length
|
|
- * of a token generated by `ngtcp2_crypto_generate_regular_token`.
|
|
+ * of a token generated by `ngtcp2_crypto_generate_regular_token`.
|
|
+ * `ngtcp2_crypto_generate_regular_token2` generates a token of length
|
|
+ * at most :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` bytes + the
|
|
+ * length of the provided opaque data.
|
|
*/
|
|
#define NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN \
|
|
(/* magic = */ 1 + sizeof(ngtcp2_tstamp) + /* aead tag = */ 16 + \
|
|
@@ -787,6 +804,77 @@ NGTCP2_EXTERN int ngtcp2_crypto_verify_regular_token(
|
|
size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
|
ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
|
|
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_crypto_generate_regular_token2` generates a token in the
|
|
+ * buffer pointed by |token| that is sent with NEW_TOKEN frame. The
|
|
+ * buffer pointed by |token| must have at least
|
|
+ * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` + |datalen| bytes long.
|
|
+ * The successfully generated token starts with
|
|
+ * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR`. |secret| of length
|
|
+ * |secretlen| is a keying material to generate keys to encrypt the
|
|
+ * token. |remote_addr| of length |remote_addrlen| is an address of
|
|
+ * client. |ts| is the timestamp when the token is generated. |data|
|
|
+ * of length |datalen| is an opaque data embedded in the token.
|
|
+ * |datalen| must be less than or equal to 256.
|
|
+ *
|
|
+ * Calling this function with |datalen| = 0 is equivalent to calling
|
|
+ * `ngtcp2_crypto_generate_regular_token`.
|
|
+ *
|
|
+ * To get the opaque data after successful verification, use
|
|
+ * `ngtcp2_crypto_verify_regular_token2`.
|
|
+ * `ngtcp2_crypto_verify_regular_token` can verify the token with
|
|
+ * |datalen| > 0, but it discards the opaque data.
|
|
+ *
|
|
+ * This function returns the length of generated token if it succeeds,
|
|
+ * or -1.
|
|
+ */
|
|
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
|
|
+ uint8_t *token, const uint8_t *secret, size_t secretlen,
|
|
+ const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
|
+ const void *data, size_t datalen, ngtcp2_tstamp ts);
|
|
+
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_crypto_verify_regular_token2` verifies a regular token
|
|
+ * stored in the buffer pointed by |token| of length |tokenlen|.
|
|
+ * |secret| of length |secretlen| is a keying material to generate
|
|
+ * keys to decrypt the token. |remote_addr| of length
|
|
+ * |remote_addrlen| is an address of client. |timeout| is the period
|
|
+ * during which the token is valid. |ts| is the current timestamp.
|
|
+ * |data| is the pointer to the buffer of length at least
|
|
+ * |max_datalen| bytes. If the token is verified successfully, the
|
|
+ * opaque data embedded in the token is copied to the buffer pointed
|
|
+ * by |data|.
|
|
+ *
|
|
+ * If |tokenlen| is less than
|
|
+ * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN`, this function returns
|
|
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`.
|
|
+ *
|
|
+ * If the length of opaque data is larger than |max_datalen|, the
|
|
+ * verification still succeeds, but nothing is written to the buffer
|
|
+ * pointed by |data|, and this function returns 0. In other words,
|
|
+ * the opaque data is discarded.
|
|
+ *
|
|
+ * This function returns the number of the opaque data written to the
|
|
+ * buffer pointed by |data| if it succeeds, or one of the following
|
|
+ * negative error codes:
|
|
+ *
|
|
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`
|
|
+ * A token is badly formatted; or verifying the integrity
|
|
+ * protection failed.
|
|
+ * :macro:`NGTCP2_CRYPTO_ERR_VERIFY_TOKEN`
|
|
+ * A token validity has expired.
|
|
+ * :macro:`NGTCP2_CRYPTO_ERR_INTERNAL`
|
|
+ * Internal error occurred.
|
|
+ */
|
|
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
|
|
+ void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
|
|
+ const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
|
+ ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
@@ -904,11 +992,29 @@ NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_cipher_ctx_cb(
|
|
*
|
|
* This function can be directly passed to
|
|
* :member:`ngtcp2_callbacks.get_path_challenge_data` field.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use
|
|
+ * `ngtcp2_crypto_get_path_challenge_data2_cb` instead.
|
|
*/
|
|
NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn,
|
|
uint8_t *data,
|
|
void *user_data);
|
|
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_crypto_get_path_challenge_data2_cb` writes unpredictable
|
|
+ * sequence of :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes to |data|
|
|
+ * which is sent with PATH_CHALLENGE frame.
|
|
+ *
|
|
+ * This function can be directly passed to
|
|
+ * :member:`ngtcp2_callbacks.get_path_challenge_data2` field.
|
|
+ *
|
|
+ * This function has been available since v1.22.0.
|
|
+ */
|
|
+NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data2_cb(
|
|
+ ngtcp2_conn *conn, ngtcp2_path_challenge_data *data, void *user_data);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
diff --git a/third_party/ngtcp2/crypto/ossl/CMakeLists.txt b/third_party/ngtcp2/crypto/ossl/CMakeLists.txt
|
|
index da2ef2df763..1a108ada0a4 100644
|
|
--- a/third_party/ngtcp2/crypto/ossl/CMakeLists.txt
|
|
+++ b/third_party/ngtcp2/crypto/ossl/CMakeLists.txt
|
|
@@ -29,14 +29,11 @@ set(ngtcp2_crypto_ossl_SOURCES
|
|
)
|
|
|
|
set(ngtcp2_crypto_ossl_INCLUDE_DIRS
|
|
- "${CMAKE_CURRENT_SOURCE_DIR}/../../lib/includes"
|
|
- "${CMAKE_CURRENT_BINARY_DIR}/../../lib/includes"
|
|
- "${CMAKE_CURRENT_SOURCE_DIR}/../../lib"
|
|
- "${CMAKE_CURRENT_SOURCE_DIR}/../../crypto/includes"
|
|
- "${CMAKE_CURRENT_BINARY_DIR}/../../crypto/includes"
|
|
- "${CMAKE_CURRENT_SOURCE_DIR}/../../crypto"
|
|
- "${CMAKE_CURRENT_BINARY_DIR}/../../crypto"
|
|
- "${OPENSSL_INCLUDE_DIRS}"
|
|
+ "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>"
|
|
+ "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/crypto/includes>"
|
|
+ "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/crypto/includes>"
|
|
+ "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/crypto>"
|
|
+ "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/crypto>"
|
|
)
|
|
|
|
foreach(name libngtcp2_crypto_ossl.pc)
|
|
@@ -55,9 +52,10 @@ if(ENABLE_SHARED_LIB)
|
|
)
|
|
target_include_directories(ngtcp2_crypto_ossl PUBLIC
|
|
${ngtcp2_crypto_ossl_INCLUDE_DIRS})
|
|
- target_link_libraries(ngtcp2_crypto_ossl ngtcp2 ${OPENSSL_LIBRARIES})
|
|
+ target_link_libraries(ngtcp2_crypto_ossl PUBLIC ngtcp2 OpenSSL::SSL)
|
|
|
|
install(TARGETS ngtcp2_crypto_ossl
|
|
+ EXPORT "${PROJECT_NAME}Targets"
|
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
|
@@ -77,8 +75,10 @@ if(ENABLE_STATIC_LIB)
|
|
"-DNGTCP2_STATICLIB")
|
|
target_include_directories(ngtcp2_crypto_ossl_static PUBLIC
|
|
${ngtcp2_crypto_ossl_INCLUDE_DIRS})
|
|
+ target_link_libraries(ngtcp2_crypto_ossl_static PUBLIC ngtcp2_static OpenSSL::SSL)
|
|
|
|
install(TARGETS ngtcp2_crypto_ossl_static
|
|
+ EXPORT "${PROJECT_NAME}Targets"
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
|
endif()
|
|
|
|
diff --git a/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in b/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in
|
|
index 1397b4bfb42..39c254a309b 100644
|
|
--- a/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in
|
|
+++ b/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in
|
|
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
|
|
Version: @VERSION@
|
|
Libs: -L${libdir} -lngtcp2_crypto_ossl
|
|
Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2, openssl
|
|
diff --git a/third_party/ngtcp2/crypto/ossl/ossl.c b/third_party/ngtcp2/crypto/ossl/ossl.c
|
|
index 061d6acd21d..fa393c8ece5 100644
|
|
--- a/third_party/ngtcp2/crypto/ossl/ossl.c
|
|
+++ b/third_party/ngtcp2/crypto/ossl/ossl.c
|
|
@@ -41,70 +41,40 @@
|
|
#include "ngtcp2_macro.h"
|
|
#include "shared.h"
|
|
|
|
-static int crypto_initialized;
|
|
+#if defined(OPENSSL_NO_CHACHA) || defined(OPENSSL_NO_POLY1305)
|
|
+# define NGTCP2_NO_CHACHA_POLY1305
|
|
+#endif /* defined(OPENSSL_NO_CHACHA) || \
|
|
+ defined(OPENSSL_NO_POLY1305) */
|
|
+
|
|
static EVP_CIPHER *crypto_aes_128_gcm;
|
|
static EVP_CIPHER *crypto_aes_256_gcm;
|
|
-static EVP_CIPHER *crypto_chacha20_poly1305;
|
|
static EVP_CIPHER *crypto_aes_128_ccm;
|
|
-static EVP_CIPHER *crypto_aes_128_ctr;
|
|
-static EVP_CIPHER *crypto_aes_256_ctr;
|
|
+static EVP_CIPHER *crypto_aes_128_ecb;
|
|
+static EVP_CIPHER *crypto_aes_256_ecb;
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
+static EVP_CIPHER *crypto_chacha20_poly1305;
|
|
static EVP_CIPHER *crypto_chacha20;
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
static EVP_MD *crypto_sha256;
|
|
static EVP_MD *crypto_sha384;
|
|
static EVP_KDF *crypto_hkdf;
|
|
|
|
int ngtcp2_crypto_ossl_init(void) {
|
|
+ /* We do not care whether the pre-fetch succeeds or not. If it
|
|
+ fails, it returns NULL, which is still the default value, and our
|
|
+ code should still work with it. */
|
|
crypto_aes_128_gcm = EVP_CIPHER_fetch(NULL, "AES-128-GCM", NULL);
|
|
- if (crypto_aes_128_gcm == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
crypto_aes_256_gcm = EVP_CIPHER_fetch(NULL, "AES-256-GCM", NULL);
|
|
- if (crypto_aes_256_gcm == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL);
|
|
- if (crypto_chacha20_poly1305 == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
crypto_aes_128_ccm = EVP_CIPHER_fetch(NULL, "AES-128-CCM", NULL);
|
|
- if (crypto_aes_128_ccm == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL);
|
|
- if (crypto_aes_128_ctr == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL);
|
|
- if (crypto_aes_256_ctr == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
+ crypto_aes_128_ecb = EVP_CIPHER_fetch(NULL, "AES-128-ECB", NULL);
|
|
+ crypto_aes_256_ecb = EVP_CIPHER_fetch(NULL, "AES-256-ECB", NULL);
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
+ crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL);
|
|
crypto_chacha20 = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL);
|
|
- if (crypto_chacha20 == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
crypto_sha256 = EVP_MD_fetch(NULL, "sha256", NULL);
|
|
- if (crypto_sha256 == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
crypto_sha384 = EVP_MD_fetch(NULL, "sha384", NULL);
|
|
- if (crypto_sha384 == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
crypto_hkdf = EVP_KDF_fetch(NULL, "hkdf", NULL);
|
|
- if (crypto_hkdf == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- crypto_initialized = 1;
|
|
|
|
return 0;
|
|
}
|
|
@@ -125,6 +95,7 @@ static const EVP_CIPHER *crypto_aead_aes_256_gcm(void) {
|
|
return EVP_aes_256_gcm();
|
|
}
|
|
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) {
|
|
if (crypto_chacha20_poly1305) {
|
|
return crypto_chacha20_poly1305;
|
|
@@ -132,6 +103,7 @@ static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) {
|
|
|
|
return EVP_chacha20_poly1305();
|
|
}
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
|
|
static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) {
|
|
if (crypto_aes_128_ccm) {
|
|
@@ -141,22 +113,23 @@ static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) {
|
|
return EVP_aes_128_ccm();
|
|
}
|
|
|
|
-static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) {
|
|
- if (crypto_aes_128_ctr) {
|
|
- return crypto_aes_128_ctr;
|
|
+static const EVP_CIPHER *crypto_cipher_aes_128_ecb(void) {
|
|
+ if (crypto_aes_128_ecb) {
|
|
+ return crypto_aes_128_ecb;
|
|
}
|
|
|
|
- return EVP_aes_128_ctr();
|
|
+ return EVP_aes_128_ecb();
|
|
}
|
|
|
|
-static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) {
|
|
- if (crypto_aes_256_ctr) {
|
|
- return crypto_aes_256_ctr;
|
|
+static const EVP_CIPHER *crypto_cipher_aes_256_ecb(void) {
|
|
+ if (crypto_aes_256_ecb) {
|
|
+ return crypto_aes_256_ecb;
|
|
}
|
|
|
|
- return EVP_aes_256_ctr();
|
|
+ return EVP_aes_256_ecb();
|
|
}
|
|
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
static const EVP_CIPHER *crypto_cipher_chacha20(void) {
|
|
if (crypto_chacha20) {
|
|
return crypto_chacha20;
|
|
@@ -164,6 +137,7 @@ static const EVP_CIPHER *crypto_cipher_chacha20(void) {
|
|
|
|
return EVP_chacha20();
|
|
}
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
|
|
static const EVP_MD *crypto_md_sha256(void) {
|
|
if (crypto_sha256) {
|
|
@@ -189,13 +163,21 @@ static EVP_KDF *crypto_kdf_hkdf(void) {
|
|
return EVP_KDF_fetch(NULL, "hkdf", NULL);
|
|
}
|
|
|
|
+static void crypto_kdf_hkdf_free(EVP_KDF *kdf) {
|
|
+ if (kdf && crypto_hkdf != kdf) {
|
|
+ EVP_KDF_free(kdf);
|
|
+ }
|
|
+}
|
|
+
|
|
static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) {
|
|
switch (EVP_CIPHER_nid(aead)) {
|
|
case NID_aes_128_gcm:
|
|
case NID_aes_256_gcm:
|
|
return EVP_GCM_TLS_TAG_LEN;
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case NID_chacha20_poly1305:
|
|
return EVP_CHACHAPOLY_TLS_TAG_LEN;
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
case NID_aes_128_ccm:
|
|
return EVP_CCM_TLS_TAG_LEN;
|
|
default:
|
|
@@ -216,7 +198,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) {
|
|
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
|
|
ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm());
|
|
ctx->md.native_handle = (void *)crypto_md_sha256();
|
|
- ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr();
|
|
+ ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ecb();
|
|
ctx->max_encryption = 0;
|
|
ctx->max_decryption_failure = 0;
|
|
return ctx;
|
|
@@ -239,8 +221,10 @@ static const EVP_CIPHER *crypto_cipher_id_get_aead(uint32_t cipher_id) {
|
|
return crypto_aead_aes_128_gcm();
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
return crypto_aead_aes_256_gcm();
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
return crypto_aead_chacha20_poly1305();
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
return crypto_aead_aes_128_ccm();
|
|
default:
|
|
@@ -253,8 +237,10 @@ static uint64_t crypto_cipher_id_get_aead_max_encryption(uint32_t cipher_id) {
|
|
case TLS1_3_CK_AES_128_GCM_SHA256:
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM;
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305;
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM;
|
|
default:
|
|
@@ -268,8 +254,10 @@ crypto_cipher_id_get_aead_max_decryption_failure(uint32_t cipher_id) {
|
|
case TLS1_3_CK_AES_128_GCM_SHA256:
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM;
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305;
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM;
|
|
default:
|
|
@@ -281,11 +269,13 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) {
|
|
switch (cipher_id) {
|
|
case TLS1_3_CK_AES_128_GCM_SHA256:
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
- return crypto_cipher_aes_128_ctr();
|
|
+ return crypto_cipher_aes_128_ecb();
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
- return crypto_cipher_aes_256_ctr();
|
|
+ return crypto_cipher_aes_256_ecb();
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
return crypto_cipher_chacha20();
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
default:
|
|
return NULL;
|
|
}
|
|
@@ -294,7 +284,9 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) {
|
|
static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) {
|
|
switch (cipher_id) {
|
|
case TLS1_3_CK_AES_128_GCM_SHA256:
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
return crypto_md_sha256();
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
@@ -308,7 +300,9 @@ static int supported_cipher_id(uint32_t cipher_id) {
|
|
switch (cipher_id) {
|
|
case TLS1_3_CK_AES_128_GCM_SHA256:
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
+#ifndef NGTCP2_NO_CHACHA_POLY1305
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
return 1;
|
|
default:
|
|
@@ -697,9 +691,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
|
|
};
|
|
int rv = 0;
|
|
|
|
- if (!crypto_initialized) {
|
|
- EVP_KDF_free(kdf);
|
|
- }
|
|
+ crypto_kdf_hkdf_free(kdf);
|
|
|
|
if (EVP_KDF_derive(kctx, dest, (size_t)EVP_MD_size(prf), params) <= 0) {
|
|
rv = -1;
|
|
@@ -730,9 +722,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
|
|
};
|
|
int rv = 0;
|
|
|
|
- if (!crypto_initialized) {
|
|
- EVP_KDF_free(kdf);
|
|
- }
|
|
+ crypto_kdf_hkdf_free(kdf);
|
|
|
|
if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) {
|
|
rv = -1;
|
|
@@ -763,9 +753,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen,
|
|
};
|
|
int rv = 0;
|
|
|
|
- if (!crypto_initialized) {
|
|
- EVP_KDF_free(kdf);
|
|
- }
|
|
+ crypto_kdf_hkdf_free(kdf);
|
|
|
|
if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) {
|
|
rv = -1;
|
|
@@ -850,16 +838,31 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
|
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
|
const uint8_t *sample) {
|
|
- static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
|
+ static const uint8_t PLAINTEXT[16] = {0};
|
|
EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
|
|
int len;
|
|
|
|
(void)hp;
|
|
|
|
- if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
|
|
- !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) ||
|
|
- !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
|
|
- return -1;
|
|
+ switch (EVP_CIPHER_CTX_nid(actx)) {
|
|
+ case NID_aes_128_ecb:
|
|
+ case NID_aes_256_ecb:
|
|
+ if (!EVP_EncryptUpdate(actx, dest, &len, sample, NGTCP2_HP_SAMPLELEN)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ case NID_chacha20:
|
|
+ if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
|
|
+ !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT)) ||
|
|
+ !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ default:
|
|
+ assert(0);
|
|
+ abort();
|
|
}
|
|
|
|
return 0;
|
|
@@ -994,6 +997,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data) {
|
|
+ (void)conn;
|
|
+ (void)user_data;
|
|
+
|
|
+ if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
|
|
+ return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
if (RAND_bytes(data, (int)datalen) != 1) {
|
|
return -1;
|
|
diff --git a/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in b/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in
|
|
index 1cb24f19388..3cef316f48a 100644
|
|
--- a/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in
|
|
+++ b/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in
|
|
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
|
|
Version: @VERSION@
|
|
Libs: -L${libdir} -lngtcp2_crypto_picotls
|
|
Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2, openssl
|
|
diff --git a/third_party/ngtcp2/crypto/picotls/picotls.c b/third_party/ngtcp2/crypto/picotls/picotls.c
|
|
index 98ebf9e876c..bd29a541277 100644
|
|
--- a/third_party/ngtcp2/crypto/picotls/picotls.c
|
|
+++ b/third_party/ngtcp2/crypto/picotls/picotls.c
|
|
@@ -35,6 +35,7 @@
|
|
#include <picotls.h>
|
|
#include <picotls/openssl.h>
|
|
|
|
+#include "ngtcp2_macro.h"
|
|
#include "shared.h"
|
|
|
|
ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead) {
|
|
@@ -49,7 +50,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) {
|
|
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
|
|
ngtcp2_crypto_aead_init(&ctx->aead, (void *)&ptls_openssl_aes128gcm);
|
|
ctx->md.native_handle = (void *)&ptls_openssl_sha256;
|
|
- ctx->hp.native_handle = (void *)&ptls_openssl_aes128ctr;
|
|
+ ctx->hp.native_handle = (void *)&ptls_openssl_aes128ecb;
|
|
ctx->max_encryption = 0;
|
|
ctx->max_decryption_failure = 0;
|
|
return ctx;
|
|
@@ -103,11 +104,11 @@ crypto_cipher_suite_get_aead_max_decryption_failure(ptls_cipher_suite_t *cs) {
|
|
static const ptls_cipher_algorithm_t *
|
|
crypto_cipher_suite_get_hp(ptls_cipher_suite_t *cs) {
|
|
if (cs->aead == &ptls_openssl_aes128gcm) {
|
|
- return &ptls_openssl_aes128ctr;
|
|
+ return &ptls_openssl_aes128ecb;
|
|
}
|
|
|
|
if (cs->aead == &ptls_openssl_aes256gcm) {
|
|
- return &ptls_openssl_aes256ctr;
|
|
+ return &ptls_openssl_aes256ecb;
|
|
}
|
|
|
|
#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
|
|
@@ -237,6 +238,11 @@ int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
|
|
return -1;
|
|
}
|
|
|
|
+ if (cipher->native_handle == &ptls_openssl_aes128ecb ||
|
|
+ cipher->native_handle == &ptls_openssl_aes256ecb) {
|
|
+ ptls_cipher_init(actx, NULL);
|
|
+ }
|
|
+
|
|
cipher_ctx->native_handle = actx;
|
|
|
|
return 0;
|
|
@@ -351,13 +357,20 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
|
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
|
const uint8_t *sample) {
|
|
+ static const uint8_t PLAINTEXT[16] = {0};
|
|
ptls_cipher_context_t *actx = hp_ctx->native_handle;
|
|
- static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
|
|
|
(void)hp;
|
|
|
|
+ if (hp->native_handle == &ptls_openssl_aes128ecb ||
|
|
+ hp->native_handle == &ptls_openssl_aes256ecb) {
|
|
+ ptls_cipher_encrypt(actx, dest, sample, NGTCP2_HP_SAMPLELEN);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
ptls_cipher_init(actx, sample);
|
|
- ptls_cipher_encrypt(actx, dest, PLAINTEXT, sizeof(PLAINTEXT) - 1);
|
|
+ ptls_cipher_encrypt(actx, dest, PLAINTEXT, sizeof(PLAINTEXT));
|
|
|
|
return 0;
|
|
}
|
|
@@ -376,7 +389,7 @@ int ngtcp2_crypto_read_write_crypto_data(
|
|
|
|
ptls_buffer_init(&sendbuf, (void *)"", 0);
|
|
|
|
- assert(epoch == ptls_get_read_epoch(cptls->ptls));
|
|
+ assert(datalen == 0 || epoch == ptls_get_read_epoch(cptls->ptls));
|
|
|
|
rv = ptls_handle_message(cptls->ptls, &sendbuf, epoch_offsets, epoch, data,
|
|
datalen, &cptls->handshake_properties);
|
|
@@ -492,6 +505,17 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data) {
|
|
+ (void)conn;
|
|
+ (void)user_data;
|
|
+
|
|
+ ptls_openssl_random_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
ptls_openssl_random_bytes(data, datalen);
|
|
|
|
@@ -499,8 +523,7 @@ int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
}
|
|
|
|
void ngtcp2_crypto_picotls_ctx_init(ngtcp2_crypto_picotls_ctx *cptls) {
|
|
- cptls->ptls = NULL;
|
|
- memset(&cptls->handshake_properties, 0, sizeof(cptls->handshake_properties));
|
|
+ *cptls = (ngtcp2_crypto_picotls_ctx){0};
|
|
}
|
|
|
|
static int set_additional_extensions(ptls_handshake_properties_t *hsprops,
|
|
diff --git a/third_party/ngtcp2/crypto/quictls/.gitignore b/third_party/ngtcp2/crypto/quictls/.gitignore
|
|
index 6f4bcf87cbd..e6f94f30474 100644
|
|
--- a/third_party/ngtcp2/crypto/quictls/.gitignore
|
|
+++ b/third_party/ngtcp2/crypto/quictls/.gitignore
|
|
@@ -1 +1,2 @@
|
|
+/libngtcp2_crypto_libressl.pc
|
|
/libngtcp2_crypto_quictls.pc
|
|
diff --git a/third_party/ngtcp2/crypto/quictls/CMakeLists.txt b/third_party/ngtcp2/crypto/quictls/CMakeLists.txt
|
|
index c1296b2cad1..b94e1f0c647 100644
|
|
--- a/third_party/ngtcp2/crypto/quictls/CMakeLists.txt
|
|
+++ b/third_party/ngtcp2/crypto/quictls/CMakeLists.txt
|
|
@@ -39,25 +39,31 @@ set(ngtcp2_crypto_quictls_INCLUDE_DIRS
|
|
"${OPENSSL_INCLUDE_DIRS}"
|
|
)
|
|
|
|
-foreach(name libngtcp2_crypto_quictls.pc)
|
|
+if(HAVE_LIBRESSL)
|
|
+ set(ngtcp2_crypto_lib "ngtcp2_crypto_libressl")
|
|
+else()
|
|
+ set(ngtcp2_crypto_lib "ngtcp2_crypto_quictls")
|
|
+endif()
|
|
+
|
|
+foreach(name lib${ngtcp2_crypto_lib}.pc)
|
|
configure_file("${name}.in" "${name}" @ONLY)
|
|
endforeach()
|
|
|
|
# Public shared library
|
|
if(ENABLE_SHARED_LIB)
|
|
- add_library(ngtcp2_crypto_quictls SHARED ${ngtcp2_crypto_quictls_SOURCES})
|
|
- set_target_properties(ngtcp2_crypto_quictls PROPERTIES
|
|
+ add_library(${ngtcp2_crypto_lib} SHARED ${ngtcp2_crypto_quictls_SOURCES})
|
|
+ set_target_properties(${ngtcp2_crypto_lib} PROPERTIES
|
|
COMPILE_FLAGS "${WARNCFLAGS}"
|
|
VERSION ${CRYPTO_QUICTLS_LT_VERSION}
|
|
SOVERSION ${CRYPTO_QUICTLS_LT_SOVERSION}
|
|
C_VISIBILITY_PRESET hidden
|
|
POSITION_INDEPENDENT_CODE ON
|
|
)
|
|
- target_include_directories(ngtcp2_crypto_quictls PUBLIC
|
|
+ target_include_directories(${ngtcp2_crypto_lib} PUBLIC
|
|
${ngtcp2_crypto_quictls_INCLUDE_DIRS})
|
|
- target_link_libraries(ngtcp2_crypto_quictls ngtcp2 ${OPENSSL_LIBRARIES})
|
|
+ target_link_libraries(${ngtcp2_crypto_lib} ngtcp2 ${OPENSSL_LIBRARIES})
|
|
|
|
- install(TARGETS ngtcp2_crypto_quictls
|
|
+ install(TARGETS ${ngtcp2_crypto_lib}
|
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
|
@@ -65,22 +71,22 @@ endif()
|
|
|
|
if(ENABLE_STATIC_LIB)
|
|
# Public static library
|
|
- add_library(ngtcp2_crypto_quictls_static STATIC ${ngtcp2_crypto_quictls_SOURCES})
|
|
- set_target_properties(ngtcp2_crypto_quictls_static PROPERTIES
|
|
+ add_library(${ngtcp2_crypto_lib}_static STATIC ${ngtcp2_crypto_quictls_SOURCES})
|
|
+ set_target_properties(${ngtcp2_crypto_lib}_static PROPERTIES
|
|
COMPILE_FLAGS "${WARNCFLAGS}"
|
|
VERSION ${CRYPTO_QUICTLS_LT_VERSION}
|
|
SOVERSION ${CRYPTO_QUICTLS_LT_SOVERSION}
|
|
- ARCHIVE_OUTPUT_NAME ngtcp2_crypto_quictls${STATIC_LIB_SUFFIX}
|
|
+ ARCHIVE_OUTPUT_NAME ${ngtcp2_crypto_lib}${STATIC_LIB_SUFFIX}
|
|
C_VISIBILITY_PRESET hidden
|
|
)
|
|
- target_compile_definitions(ngtcp2_crypto_quictls_static PUBLIC
|
|
+ target_compile_definitions(${ngtcp2_crypto_lib}_static PUBLIC
|
|
"-DNGTCP2_STATICLIB")
|
|
- target_include_directories(ngtcp2_crypto_quictls_static PUBLIC
|
|
+ target_include_directories(${ngtcp2_crypto_lib}_static PUBLIC
|
|
${ngtcp2_crypto_quictls_INCLUDE_DIRS})
|
|
|
|
- install(TARGETS ngtcp2_crypto_quictls_static
|
|
+ install(TARGETS ${ngtcp2_crypto_lib}_static
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
|
endif()
|
|
|
|
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libngtcp2_crypto_quictls.pc"
|
|
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/lib${ngtcp2_crypto_lib}.pc"
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
|
diff --git a/third_party/ngtcp2/crypto/quictls/Makefile.am b/third_party/ngtcp2/crypto/quictls/Makefile.am
|
|
index d15dcbb8796..93670f8b828 100644
|
|
--- a/third_party/ngtcp2/crypto/quictls/Makefile.am
|
|
+++ b/third_party/ngtcp2/crypto/quictls/Makefile.am
|
|
@@ -31,9 +31,18 @@ AM_CPPFLAGS = -I$(top_srcdir)/lib/includes -I$(top_builddir)/lib/includes \
|
|
AM_LDFLAGS = ${LIBTOOL_LDFLAGS}
|
|
|
|
pkgconfigdir = $(libdir)/pkgconfig
|
|
-pkgconfig_DATA = libngtcp2_crypto_quictls.pc
|
|
-DISTCLEANFILES = $(pkgconfig_DATA)
|
|
|
|
+if HAVE_LIBRESSL
|
|
+pkgconfig_DATA = libngtcp2_crypto_libressl.pc
|
|
+lib_LTLIBRARIES = libngtcp2_crypto_libressl.la
|
|
+
|
|
+libngtcp2_crypto_libressl_la_SOURCES = quictls.c ../shared.c ../shared.h
|
|
+libngtcp2_crypto_libressl_la_LDFLAGS = -no-undefined \
|
|
+ -version-info $(CRYPTO_LIBRESSL_LT_CURRENT):$(CRYPTO_LIBRESSL_LT_REVISION):$(CRYPTO_LIBRESSL_LT_AGE)
|
|
+libngtcp2_crypto_libressl_la_LIBADD = $(top_builddir)/lib/libngtcp2.la \
|
|
+ @OPENSSL_LIBS@
|
|
+else
|
|
+pkgconfig_DATA = libngtcp2_crypto_quictls.pc
|
|
lib_LTLIBRARIES = libngtcp2_crypto_quictls.la
|
|
|
|
libngtcp2_crypto_quictls_la_SOURCES = quictls.c ../shared.c ../shared.h
|
|
@@ -41,3 +50,6 @@ libngtcp2_crypto_quictls_la_LDFLAGS = -no-undefined \
|
|
-version-info $(CRYPTO_QUICTLS_LT_CURRENT):$(CRYPTO_QUICTLS_LT_REVISION):$(CRYPTO_QUICTLS_LT_AGE)
|
|
libngtcp2_crypto_quictls_la_LIBADD = $(top_builddir)/lib/libngtcp2.la \
|
|
@OPENSSL_LIBS@
|
|
+endif
|
|
+
|
|
+DISTCLEANFILES = $(pkgconfig_DATA)
|
|
diff --git a/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in b/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in
|
|
new file mode 100644
|
|
index 00000000000..903287916ce
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in
|
|
@@ -0,0 +1,34 @@
|
|
+# ngtcp2
|
|
+
|
|
+# Copyright (c) 2019 ngtcp2 contributors
|
|
+
|
|
+# Permission is hereby granted, free of charge, to any person obtaining
|
|
+# a copy of this software and associated documentation files (the
|
|
+# "Software"), to deal in the Software without restriction, including
|
|
+# without limitation the rights to use, copy, modify, merge, publish,
|
|
+# distribute, sublicense, and/or sell copies of the Software, and to
|
|
+# permit persons to whom the Software is furnished to do so, subject to
|
|
+# the following conditions:
|
|
+
|
|
+# The above copyright notice and this permission notice shall be
|
|
+# included in all copies or substantial portions of the Software.
|
|
+
|
|
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+prefix=@prefix@
|
|
+exec_prefix=@exec_prefix@
|
|
+libdir=@libdir@
|
|
+includedir=@includedir@
|
|
+
|
|
+Name: libngtcp2_crypto_libressl
|
|
+Description: ngtcp2 LibreSSL crypto library
|
|
+URL: https://github.com/ngtcp2/ngtcp2
|
|
+Version: @VERSION@
|
|
+Libs: -L${libdir} -lngtcp2_crypto_libressl
|
|
+Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2, openssl
|
|
diff --git a/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in b/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in
|
|
index 991d2a7e79b..6887c1743f2 100644
|
|
--- a/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in
|
|
+++ b/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in
|
|
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
|
|
Version: @VERSION@
|
|
Libs: -L${libdir} -lngtcp2_crypto_quictls
|
|
Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2, openssl
|
|
diff --git a/third_party/ngtcp2/crypto/quictls/quictls.c b/third_party/ngtcp2/crypto/quictls/quictls.c
|
|
index 592e5a86535..1076d97bfc0 100644
|
|
--- a/third_party/ngtcp2/crypto/quictls/quictls.c
|
|
+++ b/third_party/ngtcp2/crypto/quictls/quictls.c
|
|
@@ -40,6 +40,7 @@
|
|
# include <openssl/core_names.h>
|
|
#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
|
|
|
|
+#include "ngtcp2_macro.h"
|
|
#include "shared.h"
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
@@ -48,8 +49,8 @@ static EVP_CIPHER *crypto_aes_128_gcm;
|
|
static EVP_CIPHER *crypto_aes_256_gcm;
|
|
static EVP_CIPHER *crypto_chacha20_poly1305;
|
|
static EVP_CIPHER *crypto_aes_128_ccm;
|
|
-static EVP_CIPHER *crypto_aes_128_ctr;
|
|
-static EVP_CIPHER *crypto_aes_256_ctr;
|
|
+static EVP_CIPHER *crypto_aes_128_ecb;
|
|
+static EVP_CIPHER *crypto_aes_256_ecb;
|
|
static EVP_CIPHER *crypto_chacha20;
|
|
static EVP_MD *crypto_sha256;
|
|
static EVP_MD *crypto_sha384;
|
|
@@ -76,13 +77,13 @@ int ngtcp2_crypto_quictls_init(void) {
|
|
return -1;
|
|
}
|
|
|
|
- crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL);
|
|
- if (crypto_aes_128_ctr == NULL) {
|
|
+ crypto_aes_128_ecb = EVP_CIPHER_fetch(NULL, "AES-128-ECB", NULL);
|
|
+ if (crypto_aes_128_ecb == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
- crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL);
|
|
- if (crypto_aes_256_ctr == NULL) {
|
|
+ crypto_aes_256_ecb = EVP_CIPHER_fetch(NULL, "AES-256-ECB", NULL);
|
|
+ if (crypto_aes_256_ecb == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -143,20 +144,20 @@ static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) {
|
|
return EVP_aes_128_ccm();
|
|
}
|
|
|
|
-static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) {
|
|
- if (crypto_aes_128_ctr) {
|
|
- return crypto_aes_128_ctr;
|
|
+static const EVP_CIPHER *crypto_cipher_aes_128_ecb(void) {
|
|
+ if (crypto_aes_128_ecb) {
|
|
+ return crypto_aes_128_ecb;
|
|
}
|
|
|
|
- return EVP_aes_128_ctr();
|
|
+ return EVP_aes_128_ecb();
|
|
}
|
|
|
|
-static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) {
|
|
- if (crypto_aes_256_ctr) {
|
|
- return crypto_aes_256_ctr;
|
|
+static const EVP_CIPHER *crypto_cipher_aes_256_ecb(void) {
|
|
+ if (crypto_aes_256_ecb) {
|
|
+ return crypto_aes_256_ecb;
|
|
}
|
|
|
|
- return EVP_aes_256_ctr();
|
|
+ return EVP_aes_256_ecb();
|
|
}
|
|
|
|
static const EVP_CIPHER *crypto_cipher_chacha20(void) {
|
|
@@ -195,8 +196,8 @@ static EVP_KDF *crypto_kdf_hkdf(void) {
|
|
# define crypto_aead_aes_256_gcm EVP_aes_256_gcm
|
|
# define crypto_aead_chacha20_poly1305 EVP_chacha20_poly1305
|
|
# define crypto_aead_aes_128_ccm EVP_aes_128_ccm
|
|
-# define crypto_cipher_aes_128_ctr EVP_aes_128_ctr
|
|
-# define crypto_cipher_aes_256_ctr EVP_aes_256_ctr
|
|
+# define crypto_cipher_aes_128_ecb EVP_aes_128_ecb
|
|
+# define crypto_cipher_aes_256_ecb EVP_aes_256_ecb
|
|
# define crypto_cipher_chacha20 EVP_chacha20
|
|
# define crypto_md_sha256 EVP_sha256
|
|
# define crypto_md_sha384 EVP_sha384
|
|
@@ -231,7 +232,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) {
|
|
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
|
|
ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm());
|
|
ctx->md.native_handle = (void *)crypto_md_sha256();
|
|
- ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr();
|
|
+ ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ecb();
|
|
ctx->max_encryption = 0;
|
|
ctx->max_decryption_failure = 0;
|
|
return ctx;
|
|
@@ -296,9 +297,9 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) {
|
|
switch (cipher_id) {
|
|
case TLS1_3_CK_AES_128_GCM_SHA256:
|
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
|
- return crypto_cipher_aes_128_ctr();
|
|
+ return crypto_cipher_aes_128_ecb();
|
|
case TLS1_3_CK_AES_256_GCM_SHA384:
|
|
- return crypto_cipher_aes_256_ctr();
|
|
+ return crypto_cipher_aes_256_ecb();
|
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
|
return crypto_cipher_chacha20();
|
|
default:
|
|
@@ -778,16 +779,31 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
|
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
|
const uint8_t *sample) {
|
|
- static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
|
+ static const uint8_t PLAINTEXT[16] = {0};
|
|
EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
|
|
int len;
|
|
|
|
(void)hp;
|
|
|
|
- if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
|
|
- !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) ||
|
|
- !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
|
|
- return -1;
|
|
+ switch (EVP_CIPHER_CTX_nid(actx)) {
|
|
+ case NID_aes_128_ecb:
|
|
+ case NID_aes_256_ecb:
|
|
+ if (!EVP_EncryptUpdate(actx, dest, &len, sample, NGTCP2_HP_SAMPLELEN)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ case NID_chacha20:
|
|
+ if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
|
|
+ !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT)) ||
|
|
+ !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ default:
|
|
+ assert(0);
|
|
+ abort();
|
|
}
|
|
|
|
return 0;
|
|
@@ -800,7 +816,8 @@ int ngtcp2_crypto_read_write_crypto_data(
|
|
int rv;
|
|
int err;
|
|
|
|
- if (SSL_provide_quic_data(
|
|
+ if (datalen &&
|
|
+ SSL_provide_quic_data(
|
|
ssl,
|
|
ngtcp2_crypto_quictls_from_ngtcp2_encryption_level(encryption_level),
|
|
data, datalen) != 1) {
|
|
@@ -920,6 +937,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data) {
|
|
+ (void)conn;
|
|
+ (void)user_data;
|
|
+
|
|
+ if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
|
|
+ return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
if (RAND_bytes(data, (int)datalen) != 1) {
|
|
return -1;
|
|
diff --git a/third_party/ngtcp2/crypto/shared.c b/third_party/ngtcp2/crypto/shared.c
|
|
index 98cd4de7e80..f1bb9026721 100644
|
|
--- a/third_party/ngtcp2/crypto/shared.c
|
|
+++ b/third_party/ngtcp2/crypto/shared.c
|
|
@@ -37,6 +37,22 @@
|
|
#include "ngtcp2_macro.h"
|
|
#include "ngtcp2_net.h"
|
|
|
|
+/*
|
|
+ * NGTCP2_INITIAL_SALT_V1 is a salt value which is used to derive
|
|
+ * initial secret. It is used for QUIC v1.
|
|
+ */
|
|
+static const uint8_t NGTCP2_INITIAL_SALT_V1[] = {
|
|
+ 0x38, 0x76, 0x2C, 0xF7, 0xF5, 0x59, 0x34, 0xB3, 0x4D, 0x17,
|
|
+ 0x9A, 0xE6, 0xA4, 0xC8, 0x0C, 0xAD, 0xCC, 0xBB, 0x7F, 0x0A};
|
|
+
|
|
+/*
|
|
+ * NGTCP2_INITIAL_SALT_V2 is a salt value which is used to derive
|
|
+ * initial secret. It is used for QUIC v2.
|
|
+ */
|
|
+static const uint8_t NGTCP2_INITIAL_SALT_V2[] = {
|
|
+ 0x0D, 0xED, 0xE3, 0xDE, 0xF7, 0x00, 0xA6, 0xDB, 0x81, 0x93,
|
|
+ 0x81, 0xBE, 0x6E, 0x26, 0x9D, 0xCB, 0xF9, 0xBD, 0x2E, 0xD9};
|
|
+
|
|
ngtcp2_crypto_md *ngtcp2_crypto_md_init(ngtcp2_crypto_md *md,
|
|
void *md_native_handle) {
|
|
md->native_handle = md_native_handle;
|
|
@@ -53,9 +69,9 @@ int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen,
|
|
|
|
*p++ = (uint8_t)(destlen / 256);
|
|
*p++ = (uint8_t)(destlen % 256);
|
|
- *p++ = (uint8_t)(sizeof(LABEL) - 1 + labellen);
|
|
- memcpy(p, LABEL, sizeof(LABEL) - 1);
|
|
- p += sizeof(LABEL) - 1;
|
|
+ *p++ = (uint8_t)(ngtcp2_strlen_lit(LABEL) + labellen);
|
|
+ memcpy(p, LABEL, ngtcp2_strlen_lit(LABEL));
|
|
+ p += ngtcp2_strlen_lit(LABEL);
|
|
memcpy(p, label, labellen);
|
|
p += labellen;
|
|
*p++ = 0;
|
|
@@ -87,12 +103,12 @@ int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret,
|
|
switch (version) {
|
|
case NGTCP2_PROTO_VER_V1:
|
|
default:
|
|
- salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V1;
|
|
- saltlen = sizeof(NGTCP2_INITIAL_SALT_V1) - 1;
|
|
+ salt = NGTCP2_INITIAL_SALT_V1;
|
|
+ saltlen = sizeof(NGTCP2_INITIAL_SALT_V1);
|
|
break;
|
|
case NGTCP2_PROTO_VER_V2:
|
|
- salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2;
|
|
- saltlen = sizeof(NGTCP2_INITIAL_SALT_V2) - 1;
|
|
+ salt = NGTCP2_INITIAL_SALT_V2;
|
|
+ saltlen = sizeof(NGTCP2_INITIAL_SALT_V2);
|
|
break;
|
|
}
|
|
|
|
@@ -111,10 +127,12 @@ int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret,
|
|
|
|
if (ngtcp2_crypto_hkdf_expand_label(
|
|
client_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, &ctx.md, initial_secret,
|
|
- NGTCP2_CRYPTO_INITIAL_SECRETLEN, CLABEL, sizeof(CLABEL) - 1) != 0 ||
|
|
+ NGTCP2_CRYPTO_INITIAL_SECRETLEN, CLABEL,
|
|
+ ngtcp2_strlen_lit(CLABEL)) != 0 ||
|
|
ngtcp2_crypto_hkdf_expand_label(
|
|
server_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, &ctx.md, initial_secret,
|
|
- NGTCP2_CRYPTO_INITIAL_SECRETLEN, SLABEL, sizeof(SLABEL) - 1) != 0) {
|
|
+ NGTCP2_CRYPTO_INITIAL_SECRETLEN, SLABEL,
|
|
+ ngtcp2_strlen_lit(SLABEL)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -148,19 +166,19 @@ int ngtcp2_crypto_derive_packet_protection_key(
|
|
switch (version) {
|
|
case NGTCP2_PROTO_VER_V2:
|
|
key_label = KEY_LABEL_V2;
|
|
- key_labellen = sizeof(KEY_LABEL_V2) - 1;
|
|
+ key_labellen = ngtcp2_strlen_lit(KEY_LABEL_V2);
|
|
iv_label = IV_LABEL_V2;
|
|
- iv_labellen = sizeof(IV_LABEL_V2) - 1;
|
|
+ iv_labellen = ngtcp2_strlen_lit(IV_LABEL_V2);
|
|
hp_key_label = HP_KEY_LABEL_V2;
|
|
- hp_key_labellen = sizeof(HP_KEY_LABEL_V2) - 1;
|
|
+ hp_key_labellen = ngtcp2_strlen_lit(HP_KEY_LABEL_V2);
|
|
break;
|
|
default:
|
|
key_label = KEY_LABEL_V1;
|
|
- key_labellen = sizeof(KEY_LABEL_V1) - 1;
|
|
+ key_labellen = ngtcp2_strlen_lit(KEY_LABEL_V1);
|
|
iv_label = IV_LABEL_V1;
|
|
- iv_labellen = sizeof(IV_LABEL_V1) - 1;
|
|
+ iv_labellen = ngtcp2_strlen_lit(IV_LABEL_V1);
|
|
hp_key_label = HP_KEY_LABEL_V1;
|
|
- hp_key_labellen = sizeof(HP_KEY_LABEL_V1) - 1;
|
|
+ hp_key_labellen = ngtcp2_strlen_lit(HP_KEY_LABEL_V1);
|
|
}
|
|
|
|
if (ngtcp2_crypto_hkdf_expand_label(key, keylen, md, secret, secretlen,
|
|
@@ -194,11 +212,11 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, uint32_t version,
|
|
switch (version) {
|
|
case NGTCP2_PROTO_VER_V2:
|
|
label = LABEL_V2;
|
|
- labellen = sizeof(LABEL_V2) - 1;
|
|
+ labellen = ngtcp2_strlen_lit(LABEL_V2);
|
|
break;
|
|
default:
|
|
label = LABEL;
|
|
- labellen = sizeof(LABEL) - 1;
|
|
+ labellen = ngtcp2_strlen_lit(LABEL);
|
|
}
|
|
|
|
if (ngtcp2_crypto_hkdf_expand_label(dest, secretlen, md, secret, secretlen,
|
|
@@ -461,7 +479,9 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key,
|
|
|
|
if (ngtcp2_conn_is_server(conn) &&
|
|
crypto_set_local_transport_params(conn, tls) != 0) {
|
|
- goto fail;
|
|
+ /* Just return -1 because aead_ctx and hp_ctx are now owned by
|
|
+ conn. */
|
|
+ return -1;
|
|
}
|
|
|
|
break;
|
|
@@ -590,11 +610,11 @@ int ngtcp2_crypto_derive_and_install_initial_key(
|
|
case NGTCP2_PROTO_VER_V1:
|
|
default:
|
|
retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V1;
|
|
- retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
|
|
+ retry_noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
|
|
break;
|
|
case NGTCP2_PROTO_VER_V2:
|
|
retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V2;
|
|
- retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
|
|
+ retry_noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
|
|
break;
|
|
}
|
|
|
|
@@ -843,7 +863,7 @@ int ngtcp2_crypto_generate_stateless_reset_token(uint8_t *token,
|
|
if (ngtcp2_crypto_hkdf(token, NGTCP2_STATELESS_RESET_TOKENLEN,
|
|
ngtcp2_crypto_md_sha256(&md), secret, secretlen,
|
|
cid->data, cid->datalen, info,
|
|
- sizeof(info) - 1) != 0) {
|
|
+ ngtcp2_strlen_lit(info)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -863,8 +883,8 @@ static int crypto_derive_token_key(uint8_t *key, size_t keylen, uint8_t *iv,
|
|
uint8_t *p;
|
|
|
|
assert(ngtcp2_crypto_md_hashlen(md) == sizeof(intsecret));
|
|
- assert(info_prefixlen + sizeof(key_info_suffix) - 1 <= sizeof(info));
|
|
- assert(info_prefixlen + sizeof(iv_info_suffix) - 1 <= sizeof(info));
|
|
+ assert(info_prefixlen + ngtcp2_strlen_lit(key_info_suffix) <= sizeof(info));
|
|
+ assert(info_prefixlen + ngtcp2_strlen_lit(iv_info_suffix) <= sizeof(info));
|
|
|
|
if (ngtcp2_crypto_hkdf_extract(intsecret, md, secret, secretlen, salt,
|
|
saltlen) != 0) {
|
|
@@ -874,8 +894,8 @@ static int crypto_derive_token_key(uint8_t *key, size_t keylen, uint8_t *iv,
|
|
memcpy(info, info_prefix, info_prefixlen);
|
|
p = info + info_prefixlen;
|
|
|
|
- memcpy(p, key_info_suffix, sizeof(key_info_suffix) - 1);
|
|
- p += sizeof(key_info_suffix) - 1;
|
|
+ memcpy(p, key_info_suffix, ngtcp2_strlen_lit(key_info_suffix));
|
|
+ p += ngtcp2_strlen_lit(key_info_suffix);
|
|
|
|
if (ngtcp2_crypto_hkdf_expand(key, keylen, md, intsecret, sizeof(intsecret),
|
|
info, (size_t)(p - info)) != 0) {
|
|
@@ -884,8 +904,8 @@ static int crypto_derive_token_key(uint8_t *key, size_t keylen, uint8_t *iv,
|
|
|
|
p = info + info_prefixlen;
|
|
|
|
- memcpy(p, iv_info_suffix, sizeof(iv_info_suffix) - 1);
|
|
- p += sizeof(iv_info_suffix) - 1;
|
|
+ memcpy(p, iv_info_suffix, ngtcp2_strlen_lit(iv_info_suffix));
|
|
+ p += ngtcp2_strlen_lit(iv_info_suffix);
|
|
|
|
if (ngtcp2_crypto_hkdf_expand(iv, ivlen, md, intsecret, sizeof(intsecret),
|
|
info, (size_t)(p - info)) != 0) {
|
|
@@ -918,8 +938,8 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token(
|
|
uint8_t *token, const uint8_t *secret, size_t secretlen, uint32_t version,
|
|
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
|
const ngtcp2_cid *retry_scid, const ngtcp2_cid *odcid, ngtcp2_tstamp ts) {
|
|
- uint8_t
|
|
- plaintext[/* cid len = */ 1 + NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)];
|
|
+ uint8_t plaintext[/* cid len = */ 1 + NGTCP2_MAX_CIDLEN +
|
|
+ sizeof(ngtcp2_tstamp)] = {0};
|
|
uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
|
|
uint8_t key[16];
|
|
uint8_t iv[12];
|
|
@@ -938,8 +958,6 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token(
|
|
|
|
assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union));
|
|
|
|
- memset(plaintext, 0, sizeof(plaintext));
|
|
-
|
|
*p++ = (uint8_t)odcid->datalen;
|
|
memcpy(p, odcid->data, odcid->datalen);
|
|
p += NGTCP2_MAX_CIDLEN;
|
|
@@ -961,10 +979,10 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token(
|
|
assert(sizeof(key) == keylen);
|
|
assert(sizeof(iv) == ivlen);
|
|
|
|
- if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
|
|
- rand_data, sizeof(rand_data),
|
|
- retry_token_info_prefix,
|
|
- sizeof(retry_token_info_prefix) - 1) != 0) {
|
|
+ if (crypto_derive_token_key(
|
|
+ key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
|
|
+ sizeof(rand_data), retry_token_info_prefix,
|
|
+ ngtcp2_strlen_lit(retry_token_info_prefix)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -1038,10 +1056,10 @@ int ngtcp2_crypto_verify_retry_token(
|
|
assert(sizeof(key) == keylen);
|
|
assert(sizeof(iv) == ivlen);
|
|
|
|
- if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
|
|
- rand_data, NGTCP2_CRYPTO_TOKEN_RAND_DATALEN,
|
|
- retry_token_info_prefix,
|
|
- sizeof(retry_token_info_prefix) - 1) != 0) {
|
|
+ if (crypto_derive_token_key(
|
|
+ key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
|
|
+ NGTCP2_CRYPTO_TOKEN_RAND_DATALEN, retry_token_info_prefix,
|
|
+ ngtcp2_strlen_lit(retry_token_info_prefix)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -1100,7 +1118,7 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token2(
|
|
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
|
const ngtcp2_cid *retry_scid, const ngtcp2_cid *odcid, ngtcp2_tstamp ts) {
|
|
uint8_t plaintext[sizeof(ngtcp2_sockaddr_union) + /* cid len = */ 1 +
|
|
- NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)];
|
|
+ NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)] = {0};
|
|
uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
|
|
uint8_t key[16];
|
|
uint8_t iv[12];
|
|
@@ -1117,8 +1135,6 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token2(
|
|
|
|
assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union));
|
|
|
|
- memset(plaintext, 0, sizeof(plaintext));
|
|
-
|
|
memcpy(p, remote_addr, (size_t)remote_addrlen);
|
|
p += sizeof(ngtcp2_sockaddr_union);
|
|
*p++ = (uint8_t)odcid->datalen;
|
|
@@ -1141,10 +1157,10 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token2(
|
|
assert(sizeof(key) == keylen);
|
|
assert(sizeof(iv) == ivlen);
|
|
|
|
- if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
|
|
- rand_data, sizeof(rand_data),
|
|
- retry_token_info_prefix2,
|
|
- sizeof(retry_token_info_prefix2) - 1) != 0) {
|
|
+ if (crypto_derive_token_key(
|
|
+ key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
|
|
+ sizeof(rand_data), retry_token_info_prefix2,
|
|
+ ngtcp2_strlen_lit(retry_token_info_prefix2)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -1219,10 +1235,10 @@ int ngtcp2_crypto_verify_retry_token2(
|
|
assert(sizeof(key) == keylen);
|
|
assert(sizeof(iv) == ivlen);
|
|
|
|
- if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
|
|
- rand_data, NGTCP2_CRYPTO_TOKEN_RAND_DATALEN,
|
|
- retry_token_info_prefix2,
|
|
- sizeof(retry_token_info_prefix2) - 1) != 0) {
|
|
+ if (crypto_derive_token_key(
|
|
+ key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
|
|
+ NGTCP2_CRYPTO_TOKEN_RAND_DATALEN, retry_token_info_prefix2,
|
|
+ ngtcp2_strlen_lit(retry_token_info_prefix2)) != 0) {
|
|
return NGTCP2_CRYPTO_ERR_INTERNAL;
|
|
}
|
|
|
|
@@ -1305,13 +1321,22 @@ static size_t crypto_generate_regular_token_aad(uint8_t *dest,
|
|
return addrlen;
|
|
}
|
|
|
|
+/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN is the maximum length of
|
|
+ opaque data embedded in a regular token. */
|
|
+#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN 256
|
|
+
|
|
+/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN is the maximum length
|
|
+ of plaintext included in a regular token. */
|
|
+#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN \
|
|
+ (sizeof(ngtcp2_tstamp) + NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN)
|
|
+
|
|
static const uint8_t regular_token_info_prefix[] = "regular_token";
|
|
|
|
-ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
|
+static ngtcp2_ssize crypto_generate_regular_token(
|
|
uint8_t *token, const uint8_t *secret, size_t secretlen,
|
|
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
|
- ngtcp2_tstamp ts) {
|
|
- uint8_t plaintext[sizeof(ngtcp2_tstamp)];
|
|
+ const void *data, size_t datalen, ngtcp2_tstamp ts) {
|
|
+ uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
|
|
uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
|
|
uint8_t key[16];
|
|
uint8_t iv[12];
|
|
@@ -1328,9 +1353,18 @@ ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
|
int rv;
|
|
(void)remote_addrlen;
|
|
|
|
+ if (datalen > NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
memcpy(p, &ts_be, sizeof(ts_be));
|
|
p += sizeof(ts_be);
|
|
|
|
+ if (datalen) {
|
|
+ memcpy(p, data, datalen);
|
|
+ p += datalen;
|
|
+ }
|
|
+
|
|
plaintextlen = (size_t)(p - plaintext);
|
|
|
|
if (ngtcp2_crypto_random(rand_data, sizeof(rand_data)) != 0) {
|
|
@@ -1346,10 +1380,10 @@ ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
|
assert(sizeof(key) == keylen);
|
|
assert(sizeof(iv) == ivlen);
|
|
|
|
- if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
|
|
- rand_data, sizeof(rand_data),
|
|
- regular_token_info_prefix,
|
|
- sizeof(regular_token_info_prefix) - 1) != 0) {
|
|
+ if (crypto_derive_token_key(
|
|
+ key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
|
|
+ sizeof(rand_data), regular_token_info_prefix,
|
|
+ ngtcp2_strlen_lit(regular_token_info_prefix)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
@@ -1378,13 +1412,11 @@ ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
|
return p - token;
|
|
}
|
|
|
|
-int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
|
- const uint8_t *secret, size_t secretlen,
|
|
- const ngtcp2_sockaddr *remote_addr,
|
|
- ngtcp2_socklen remote_addrlen,
|
|
- ngtcp2_duration timeout,
|
|
- ngtcp2_tstamp ts) {
|
|
- uint8_t plaintext[sizeof(ngtcp2_tstamp)];
|
|
+static ngtcp2_ssize crypto_verify_regular_token(
|
|
+ void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
|
|
+ const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
|
+ ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
|
|
+ uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
|
|
uint8_t key[16];
|
|
uint8_t iv[12];
|
|
size_t keylen;
|
|
@@ -1397,13 +1429,14 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
|
const uint8_t *rand_data;
|
|
const uint8_t *ciphertext;
|
|
size_t ciphertextlen;
|
|
+ size_t datalen;
|
|
int rv;
|
|
ngtcp2_tstamp gen_ts;
|
|
(void)remote_addrlen;
|
|
|
|
- if (tokenlen != NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
|
|
+ if (tokenlen < NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
|
|
token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR) {
|
|
- return -1;
|
|
+ return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
|
|
}
|
|
|
|
rand_data = token + tokenlen - NGTCP2_CRYPTO_TOKEN_RAND_DATALEN;
|
|
@@ -1413,23 +1446,27 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
|
ngtcp2_crypto_aead_aes_128_gcm(&aead);
|
|
ngtcp2_crypto_md_sha256(&md);
|
|
|
|
+ if (ciphertextlen > sizeof(plaintext) + aead.max_overhead) {
|
|
+ return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
|
|
+ }
|
|
+
|
|
keylen = ngtcp2_crypto_aead_keylen(&aead);
|
|
ivlen = ngtcp2_crypto_aead_noncelen(&aead);
|
|
|
|
assert(sizeof(key) == keylen);
|
|
assert(sizeof(iv) == ivlen);
|
|
|
|
- if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
|
|
- rand_data, NGTCP2_CRYPTO_TOKEN_RAND_DATALEN,
|
|
- regular_token_info_prefix,
|
|
- sizeof(regular_token_info_prefix) - 1) != 0) {
|
|
- return -1;
|
|
+ if (crypto_derive_token_key(
|
|
+ key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
|
|
+ NGTCP2_CRYPTO_TOKEN_RAND_DATALEN, regular_token_info_prefix,
|
|
+ ngtcp2_strlen_lit(regular_token_info_prefix)) != 0) {
|
|
+ return NGTCP2_CRYPTO_ERR_INTERNAL;
|
|
}
|
|
|
|
aadlen = crypto_generate_regular_token_aad(aad, remote_addr);
|
|
|
|
if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &aead, key, ivlen) != 0) {
|
|
- return -1;
|
|
+ return NGTCP2_CRYPTO_ERR_INTERNAL;
|
|
}
|
|
|
|
rv = ngtcp2_crypto_decrypt(plaintext, &aead, &aead_ctx, ciphertext,
|
|
@@ -1438,19 +1475,74 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
|
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
|
|
|
|
if (rv != 0) {
|
|
- return -1;
|
|
+ return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
|
|
}
|
|
|
|
memcpy(&gen_ts, plaintext, sizeof(gen_ts));
|
|
|
|
gen_ts = ngtcp2_ntohl64(gen_ts);
|
|
if (gen_ts + timeout <= ts) {
|
|
+ return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
|
|
+ }
|
|
+
|
|
+ if (max_datalen == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ datalen = ciphertextlen - aead.max_overhead - sizeof(gen_ts);
|
|
+ if (datalen > max_datalen) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ memcpy(data, plaintext + sizeof(gen_ts), datalen);
|
|
+
|
|
+ return (ngtcp2_ssize)datalen;
|
|
+}
|
|
+
|
|
+ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
|
+ uint8_t *token, const uint8_t *secret, size_t secretlen,
|
|
+ const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
|
+ ngtcp2_tstamp ts) {
|
|
+ return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
|
|
+ remote_addrlen, NULL, 0, ts);
|
|
+}
|
|
+
|
|
+int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
|
+ const uint8_t *secret, size_t secretlen,
|
|
+ const ngtcp2_sockaddr *remote_addr,
|
|
+ ngtcp2_socklen remote_addrlen,
|
|
+ ngtcp2_duration timeout,
|
|
+ ngtcp2_tstamp ts) {
|
|
+ ngtcp2_ssize datalen =
|
|
+ crypto_verify_regular_token(NULL, 0, token, tokenlen, secret, secretlen,
|
|
+ remote_addr, remote_addrlen, timeout, ts);
|
|
+
|
|
+ if (datalen < 0) {
|
|
return -1;
|
|
}
|
|
|
|
+ assert(0 == datalen);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
+ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
|
|
+ uint8_t *token, const uint8_t *secret, size_t secretlen,
|
|
+ const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
|
+ const void *data, size_t datalen, ngtcp2_tstamp ts) {
|
|
+ return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
|
|
+ remote_addrlen, data, datalen, ts);
|
|
+}
|
|
+
|
|
+ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
|
|
+ void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
|
|
+ const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
|
+ ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
|
|
+ return crypto_verify_regular_token(data, max_datalen, token, tokenlen, secret,
|
|
+ secretlen, remote_addr, remote_addrlen,
|
|
+ timeout, ts);
|
|
+}
|
|
+
|
|
ngtcp2_ssize ngtcp2_crypto_write_connection_close(
|
|
uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
|
|
const ngtcp2_cid *scid, uint64_t error_code, const uint8_t *reason,
|
|
@@ -1523,11 +1615,11 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen,
|
|
case NGTCP2_PROTO_VER_V1:
|
|
default:
|
|
key = (const uint8_t *)NGTCP2_RETRY_KEY_V1;
|
|
- noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
|
|
+ noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
|
|
break;
|
|
case NGTCP2_PROTO_VER_V2:
|
|
key = (const uint8_t *)NGTCP2_RETRY_KEY_V2;
|
|
- noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
|
|
+ noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
|
|
break;
|
|
}
|
|
|
|
@@ -1637,8 +1729,21 @@ int ngtcp2_crypto_recv_crypto_data_cb(ngtcp2_conn *conn,
|
|
(void)offset;
|
|
(void)user_data;
|
|
|
|
- if (ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data,
|
|
- datalen) != 0) {
|
|
+ rv =
|
|
+ ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data, datalen);
|
|
+ if (rv != 0) {
|
|
+ switch (rv) {
|
|
+ case /* NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB */ -10001:
|
|
+ case /* NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP */ -10002:
|
|
+ /* These errors are not unrecoverable error, and they just
|
|
+ indicate that handshake has been interrupted. ngtcp2 does
|
|
+ not mind whether handshake is interrupted or not. Just
|
|
+ return 0 in this case. There are OSSL version and they have
|
|
+ the same enum value, therefore we cannot enumerate them
|
|
+ here. */
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
rv = ngtcp2_conn_get_tls_error(conn);
|
|
if (rv) {
|
|
return rv;
|
|
diff --git a/third_party/ngtcp2/crypto/shared.h b/third_party/ngtcp2/crypto/shared.h
|
|
index 34158d3d02d..c517b7f2249 100644
|
|
--- a/third_party/ngtcp2/crypto/shared.h
|
|
+++ b/third_party/ngtcp2/crypto/shared.h
|
|
@@ -31,26 +31,6 @@
|
|
|
|
#include <ngtcp2/ngtcp2_crypto.h>
|
|
|
|
-/**
|
|
- * @macro
|
|
- *
|
|
- * :macro:`NGTCP2_INITIAL_SALT_V1` is a salt value which is used to
|
|
- * derive initial secret. It is used for QUIC v1.
|
|
- */
|
|
-#define NGTCP2_INITIAL_SALT_V1 \
|
|
- "\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb" \
|
|
- "\x7f\x0a"
|
|
-
|
|
-/**
|
|
- * @macro
|
|
- *
|
|
- * :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to
|
|
- * derive initial secret. It is used for QUIC v2.
|
|
- */
|
|
-#define NGTCP2_INITIAL_SALT_V2 \
|
|
- "\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd" \
|
|
- "\x2e\xd9"
|
|
-
|
|
/* Maximum key usage (encryption) limits */
|
|
#define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (1ULL << 23)
|
|
#define NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305 (1ULL << 62)
|
|
diff --git a/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in b/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in
|
|
index 720c7849c0f..e9e670c44f9 100644
|
|
--- a/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in
|
|
+++ b/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in
|
|
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
|
|
Version: @VERSION@
|
|
Libs: -L${libdir} -lngtcp2_crypto_wolfssl
|
|
Cflags: -I${includedir}
|
|
+Requires.private: libngtcp2, wolfssl
|
|
diff --git a/third_party/ngtcp2/crypto/wolfssl/wolfssl.c b/third_party/ngtcp2/crypto/wolfssl/wolfssl.c
|
|
index bc9d9d84a86..fa2b147b6ba 100644
|
|
--- a/third_party/ngtcp2/crypto/wolfssl/wolfssl.c
|
|
+++ b/third_party/ngtcp2/crypto/wolfssl/wolfssl.c
|
|
@@ -34,6 +34,7 @@
|
|
#include <wolfssl/ssl.h>
|
|
#include <wolfssl/quic.h>
|
|
|
|
+#include "ngtcp2_macro.h"
|
|
#include "shared.h"
|
|
|
|
#define PRINTF_DEBUG 0
|
|
@@ -55,7 +56,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) {
|
|
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
|
|
ngtcp2_crypto_aead_init(&ctx->aead, (void *)wolfSSL_EVP_aes_128_gcm());
|
|
ctx->md.native_handle = (void *)wolfSSL_EVP_sha256();
|
|
- ctx->hp.native_handle = (void *)wolfSSL_EVP_aes_128_ctr();
|
|
+ ctx->hp.native_handle = (void *)wolfSSL_EVP_aes_128_ecb();
|
|
ctx->max_encryption = 0;
|
|
ctx->max_decryption_failure = 0;
|
|
return ctx;
|
|
@@ -106,6 +107,21 @@ static int supported_aead(const WOLFSSL_EVP_CIPHER *aead) {
|
|
wolfSSL_quic_aead_is_chacha20(aead) || wolfSSL_quic_aead_is_ccm(aead);
|
|
}
|
|
|
|
+static const WOLFSSL_EVP_CIPHER *
|
|
+crypto_aead_get_hp(const WOLFSSL_EVP_CIPHER *aead) {
|
|
+ switch (wolfSSL_EVP_CIPHER_nid(aead)) {
|
|
+ case NID_aes_128_gcm:
|
|
+ case NID_aes_128_ccm:
|
|
+ return wolfSSL_EVP_aes_128_ecb();
|
|
+ case NID_aes_256_gcm:
|
|
+ return wolfSSL_EVP_aes_256_ecb();
|
|
+ case NID_chacha20_poly1305:
|
|
+ return wolfSSL_EVP_chacha20();
|
|
+ default:
|
|
+ return NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
|
|
void *tls_native_handle) {
|
|
WOLFSSL *ssl = tls_native_handle;
|
|
@@ -121,7 +137,7 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
|
|
|
|
ngtcp2_crypto_aead_init(&ctx->aead, (void *)aead);
|
|
ctx->md.native_handle = (void *)wolfSSL_quic_get_md(ssl);
|
|
- ctx->hp.native_handle = (void *)wolfSSL_quic_get_hp(ssl);
|
|
+ ctx->hp.native_handle = (void *)crypto_aead_get_hp(aead);
|
|
ctx->max_encryption = crypto_aead_get_aead_max_encryption(aead);
|
|
ctx->max_decryption_failure =
|
|
crypto_aead_get_aead_max_decryption_failure(aead);
|
|
@@ -288,20 +304,33 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
|
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
|
const uint8_t *sample) {
|
|
- static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
|
+ static const uint8_t PLAINTEXT[16] = {0};
|
|
WOLFSSL_EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
|
|
int len;
|
|
|
|
(void)hp;
|
|
|
|
- if (wolfSSL_EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) !=
|
|
- WOLFSSL_SUCCESS ||
|
|
- wolfSSL_EVP_CipherUpdate(actx, dest, &len, PLAINTEXT,
|
|
- sizeof(PLAINTEXT) - 1) != WOLFSSL_SUCCESS ||
|
|
- wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len) !=
|
|
- WOLFSSL_SUCCESS) {
|
|
- DEBUG_MSG("WOLFSSL: hp_mask FAILED\n");
|
|
- return -1;
|
|
+ switch (wolfSSL_EVP_CIPHER_CTX_nid(actx)) {
|
|
+ case NID_aes_128_ecb:
|
|
+ case NID_aes_256_ecb:
|
|
+ if (!wolfSSL_EVP_CipherUpdate(actx, dest, &len, sample,
|
|
+ NGTCP2_HP_SAMPLELEN)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ case NID_chacha20:
|
|
+ if (wolfSSL_EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) !=
|
|
+ WOLFSSL_SUCCESS ||
|
|
+ wolfSSL_EVP_CipherUpdate(actx, dest, &len, PLAINTEXT,
|
|
+ sizeof(PLAINTEXT)) != WOLFSSL_SUCCESS ||
|
|
+ wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len) !=
|
|
+ WOLFSSL_SUCCESS) {
|
|
+ DEBUG_MSG("WOLFSSL: hp_mask FAILED\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ break;
|
|
}
|
|
|
|
return 0;
|
|
@@ -442,6 +471,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data) {
|
|
+ (void)conn;
|
|
+ (void)user_data;
|
|
+
|
|
+ DEBUG_MSG("WOLFSSL: get path challenge data\n");
|
|
+ if (wolfSSL_RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
|
|
+ return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
|
|
DEBUG_MSG("WOLFSSL: get random\n");
|
|
if (wolfSSL_RAND_bytes(data, (int)datalen) != 1) {
|
|
diff --git a/third_party/ngtcp2/lib/CMakeLists.txt b/third_party/ngtcp2/lib/CMakeLists.txt
|
|
index dc390e723b5..d16eba05a3e 100644
|
|
--- a/third_party/ngtcp2/lib/CMakeLists.txt
|
|
+++ b/third_party/ngtcp2/lib/CMakeLists.txt
|
|
@@ -67,12 +67,17 @@ set(ngtcp2_SOURCES
|
|
ngtcp2_unreachable.c
|
|
ngtcp2_transport_params.c
|
|
ngtcp2_settings.c
|
|
+ ngtcp2_callbacks.c
|
|
ngtcp2_dcidtr.c
|
|
+ ngtcp2_pcg.c
|
|
+ ngtcp2_ratelim.c
|
|
+ ngtcp2_conn_info.c
|
|
)
|
|
|
|
set(ngtcp2_INCLUDE_DIRS
|
|
- "${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
|
- "${CMAKE_CURRENT_BINARY_DIR}/includes"
|
|
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes>"
|
|
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes>"
|
|
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
|
)
|
|
|
|
set(NGTCP2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
|
@@ -103,11 +108,7 @@ if(ENABLE_SHARED_LIB)
|
|
C_VISIBILITY_PRESET hidden
|
|
POSITION_INDEPENDENT_CODE ON
|
|
)
|
|
- foreach(include_DIR IN LISTS ngtcp2_INCLUDE_DIRS)
|
|
- target_include_directories(ngtcp2 PUBLIC $<BUILD_INTERFACE:${include_DIR}>)
|
|
- endforeach()
|
|
-
|
|
- target_include_directories(ngtcp2 PUBLIC $<INSTALL_INTERFACE:./include>)
|
|
+ target_include_directories(ngtcp2 PUBLIC ${ngtcp2_INCLUDE_DIRS})
|
|
|
|
install(TARGETS ngtcp2
|
|
EXPORT ${NGTCP2_TARGETS_EXPORT_NAME}
|
|
@@ -126,11 +127,7 @@ if(ENABLE_STATIC_LIB)
|
|
C_VISIBILITY_PRESET hidden
|
|
)
|
|
target_compile_definitions(ngtcp2_static PUBLIC "-DNGTCP2_STATICLIB")
|
|
- foreach(include_DIR IN LISTS ngtcp2_INCLUDE_DIRS)
|
|
- target_include_directories(ngtcp2_static PUBLIC $<BUILD_INTERFACE:${include_DIR}>)
|
|
- endforeach()
|
|
-
|
|
- target_include_directories(ngtcp2_static PUBLIC $<INSTALL_INTERFACE:./include>)
|
|
+ target_include_directories(ngtcp2_static PUBLIC ${ngtcp2_INCLUDE_DIRS})
|
|
|
|
install(TARGETS ngtcp2_static
|
|
EXPORT ${NGTCP2_TARGETS_EXPORT_NAME}
|
|
diff --git a/third_party/ngtcp2/lib/Makefile.am b/third_party/ngtcp2/lib/Makefile.am
|
|
index c5231115c3d..8748ca5fb43 100644
|
|
--- a/third_party/ngtcp2/lib/Makefile.am
|
|
+++ b/third_party/ngtcp2/lib/Makefile.am
|
|
@@ -75,7 +75,11 @@ OBJECTS = \
|
|
ngtcp2_unreachable.c \
|
|
ngtcp2_transport_params.c \
|
|
ngtcp2_settings.c \
|
|
- ngtcp2_dcidtr.c
|
|
+ ngtcp2_callbacks.c \
|
|
+ ngtcp2_dcidtr.c \
|
|
+ ngtcp2_pcg.c \
|
|
+ ngtcp2_ratelim.c \
|
|
+ ngtcp2_conn_info.c
|
|
|
|
HFILES = \
|
|
ngtcp2_pkt.h \
|
|
@@ -120,7 +124,11 @@ HFILES = \
|
|
ngtcp2_unreachable.h \
|
|
ngtcp2_transport_params.h \
|
|
ngtcp2_settings.h \
|
|
+ ngtcp2_callbacks.h \
|
|
ngtcp2_dcidtr.h \
|
|
+ ngtcp2_pcg.h \
|
|
+ ngtcp2_ratelim.h \
|
|
+ ngtcp2_conn_info.h \
|
|
ngtcp2_conn_stat.h \
|
|
ngtcp2_pktns_id.h \
|
|
ngtcp2_tstamp.h
|
|
diff --git a/third_party/ngtcp2/lib/config.cmake.in b/third_party/ngtcp2/lib/config.cmake.in
|
|
index 435a4d4a500..fffcd517289 100644
|
|
--- a/third_party/ngtcp2/lib/config.cmake.in
|
|
+++ b/third_party/ngtcp2/lib/config.cmake.in
|
|
@@ -1,3 +1,6 @@
|
|
include(CMakeFindDependencyMacro)
|
|
+if("@HAVE_OSSL@")
|
|
+ find_dependency(OpenSSL)
|
|
+endif()
|
|
|
|
include("${CMAKE_CURRENT_LIST_DIR}/@NGTCP2_TARGETS_EXPORT_NAME@.cmake")
|
|
diff --git a/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
|
|
index d7a27b9213b..c71ff364e30 100644
|
|
--- a/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
|
|
+++ b/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
|
|
@@ -262,7 +262,7 @@ typedef struct ngtcp2_mem {
|
|
*
|
|
* :macro:`NGTCP2_PROTO_VER_V1` is the QUIC version 1.
|
|
*/
|
|
-#define NGTCP2_PROTO_VER_V1 ((uint32_t)0x00000001u)
|
|
+#define NGTCP2_PROTO_VER_V1 ((uint32_t)0x00000001U)
|
|
|
|
/**
|
|
* @macro
|
|
@@ -270,7 +270,7 @@ typedef struct ngtcp2_mem {
|
|
* :macro:`NGTCP2_PROTO_VER_V2` is the QUIC version 2. See
|
|
* :rfc:`9369`.
|
|
*/
|
|
-#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6b3343cfu)
|
|
+#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6B3343CFU)
|
|
|
|
/**
|
|
* @macro
|
|
@@ -294,7 +294,7 @@ typedef struct ngtcp2_mem {
|
|
* :macro:`NGTCP2_RESERVED_VERSION_MASK` is the bit mask of reserved
|
|
* version.
|
|
*/
|
|
-#define NGTCP2_RESERVED_VERSION_MASK 0x0a0a0a0au
|
|
+#define NGTCP2_RESERVED_VERSION_MASK 0x0A0A0A0AU
|
|
|
|
/**
|
|
* @macrosection
|
|
@@ -306,15 +306,29 @@ typedef struct ngtcp2_mem {
|
|
* @macro
|
|
*
|
|
* :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` is the default maximum UDP
|
|
- * datagram payload size that the local endpoint transmits.
|
|
+ * datagram payload size that the local endpoint transmits without
|
|
+ * Path MTU Discovery (PMTUD) or the custom settings (see
|
|
+ * :member:`ngtcp2_settings.max_tx_udp_payload_size` and
|
|
+ * :member:`ngtcp2_settings.no_tx_udp_payload_size_shaping`).
|
|
*/
|
|
#define NGTCP2_MAX_UDP_PAYLOAD_SIZE 1200
|
|
|
|
/**
|
|
* @macro
|
|
*
|
|
- * :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` is the maximum UDP
|
|
+ * :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE` is the maximum UDP datagram
|
|
+ * payload size that this library can output.
|
|
+ */
|
|
+#define NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE 65527
|
|
+
|
|
+/**
|
|
+ * @macro
|
|
+ *
|
|
+ * :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` was the maximum UDP
|
|
* datagram payload size that Path MTU Discovery can discover.
|
|
+ *
|
|
+ * Deprecated since v1.17.0. Path MTU Discovery is not capped to this
|
|
+ * value anymore.
|
|
*/
|
|
#define NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE 1452
|
|
|
|
@@ -363,7 +377,7 @@ typedef struct ngtcp2_mem {
|
|
* integrity tag of Retry packet. It is used for QUIC v1.
|
|
*/
|
|
#define NGTCP2_RETRY_KEY_V1 \
|
|
- "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e"
|
|
+ "\xBE\x0C\x69\x0B\x9F\x66\x57\x5A\x1D\x76\x6B\x54\xE3\x68\xC8\x4E"
|
|
|
|
/**
|
|
* @macro
|
|
@@ -371,7 +385,7 @@ typedef struct ngtcp2_mem {
|
|
* :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating
|
|
* integrity tag of Retry packet. It is used for QUIC v1.
|
|
*/
|
|
-#define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb"
|
|
+#define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xD3\x5D\x63\x2B\xF2\x23\x98\x25\xBB"
|
|
|
|
/**
|
|
* @macro
|
|
@@ -381,7 +395,7 @@ typedef struct ngtcp2_mem {
|
|
* :rfc:`9369`.
|
|
*/
|
|
#define NGTCP2_RETRY_KEY_V2 \
|
|
- "\x8f\xb4\xb0\x1b\x56\xac\x48\xe2\x60\xfb\xcb\xce\xad\x7c\xcc\x92"
|
|
+ "\x8F\xB4\xB0\x1B\x56\xAC\x48\xE2\x60\xFB\xCB\xCE\xAD\x7C\xCC\x92"
|
|
|
|
/**
|
|
* @macro
|
|
@@ -390,7 +404,7 @@ typedef struct ngtcp2_mem {
|
|
* integrity tag of Retry packet. It is used for QUIC v2. See
|
|
* :rfc:`9369`.
|
|
*/
|
|
-#define NGTCP2_RETRY_NONCE_V2 "\xd8\x69\x69\xbc\x2d\x7c\x6d\x99\x90\xef\xb0\x4a"
|
|
+#define NGTCP2_RETRY_NONCE_V2 "\xD8\x69\x69\xBC\x2D\x7C\x6D\x99\x90\xEF\xB0\x4A"
|
|
|
|
/**
|
|
* @macro
|
|
@@ -798,7 +812,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info {
|
|
*
|
|
* :macro:`NGTCP2_PKT_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_PKT_FLAG_NONE 0x00u
|
|
+#define NGTCP2_PKT_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -806,7 +820,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info {
|
|
* :macro:`NGTCP2_PKT_FLAG_LONG_FORM` indicates the Long header packet
|
|
* header.
|
|
*/
|
|
-#define NGTCP2_PKT_FLAG_LONG_FORM 0x01u
|
|
+#define NGTCP2_PKT_FLAG_LONG_FORM 0x01U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -814,14 +828,14 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info {
|
|
* :macro:`NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR` indicates that Fixed Bit
|
|
* (aka QUIC bit) is not set.
|
|
*/
|
|
-#define NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR 0x02u
|
|
+#define NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR 0x02U
|
|
|
|
/**
|
|
* @macro
|
|
*
|
|
* :macro:`NGTCP2_PKT_FLAG_KEY_PHASE` indicates Key Phase bit set.
|
|
*/
|
|
-#define NGTCP2_PKT_FLAG_KEY_PHASE 0x04u
|
|
+#define NGTCP2_PKT_FLAG_KEY_PHASE 0x04U
|
|
|
|
/**
|
|
* @enum
|
|
@@ -873,7 +887,7 @@ typedef enum ngtcp2_pkt_type {
|
|
*
|
|
* :macro:`NGTCP2_NO_ERROR` is QUIC transport error code ``NO_ERROR``.
|
|
*/
|
|
-#define NGTCP2_NO_ERROR 0x0u
|
|
+#define NGTCP2_NO_ERROR 0x0U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -881,7 +895,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_INTERNAL_ERROR` is QUIC transport error code
|
|
* ``INTERNAL_ERROR``.
|
|
*/
|
|
-#define NGTCP2_INTERNAL_ERROR 0x1u
|
|
+#define NGTCP2_INTERNAL_ERROR 0x1U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -889,7 +903,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_CONNECTION_REFUSED` is QUIC transport error code
|
|
* ``CONNECTION_REFUSED``.
|
|
*/
|
|
-#define NGTCP2_CONNECTION_REFUSED 0x2u
|
|
+#define NGTCP2_CONNECTION_REFUSED 0x2U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -897,7 +911,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_FLOW_CONTROL_ERROR` is QUIC transport error code
|
|
* ``FLOW_CONTROL_ERROR``.
|
|
*/
|
|
-#define NGTCP2_FLOW_CONTROL_ERROR 0x3u
|
|
+#define NGTCP2_FLOW_CONTROL_ERROR 0x3U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -905,7 +919,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_STREAM_LIMIT_ERROR` is QUIC transport error code
|
|
* ``STREAM_LIMIT_ERROR``.
|
|
*/
|
|
-#define NGTCP2_STREAM_LIMIT_ERROR 0x4u
|
|
+#define NGTCP2_STREAM_LIMIT_ERROR 0x4U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -913,7 +927,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_STREAM_STATE_ERROR` is QUIC transport error code
|
|
* ``STREAM_STATE_ERROR``.
|
|
*/
|
|
-#define NGTCP2_STREAM_STATE_ERROR 0x5u
|
|
+#define NGTCP2_STREAM_STATE_ERROR 0x5U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -921,7 +935,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_FINAL_SIZE_ERROR` is QUIC transport error code
|
|
* ``FINAL_SIZE_ERROR``.
|
|
*/
|
|
-#define NGTCP2_FINAL_SIZE_ERROR 0x6u
|
|
+#define NGTCP2_FINAL_SIZE_ERROR 0x6U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -929,7 +943,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_FRAME_ENCODING_ERROR` is QUIC transport error code
|
|
* ``FRAME_ENCODING_ERROR``.
|
|
*/
|
|
-#define NGTCP2_FRAME_ENCODING_ERROR 0x7u
|
|
+#define NGTCP2_FRAME_ENCODING_ERROR 0x7U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -937,7 +951,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_TRANSPORT_PARAMETER_ERROR` is QUIC transport error
|
|
* code ``TRANSPORT_PARAMETER_ERROR``.
|
|
*/
|
|
-#define NGTCP2_TRANSPORT_PARAMETER_ERROR 0x8u
|
|
+#define NGTCP2_TRANSPORT_PARAMETER_ERROR 0x8U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -945,7 +959,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_CONNECTION_ID_LIMIT_ERROR` is QUIC transport error
|
|
* code ``CONNECTION_ID_LIMIT_ERROR``.
|
|
*/
|
|
-#define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9u
|
|
+#define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -953,7 +967,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_PROTOCOL_VIOLATION` is QUIC transport error code
|
|
* ``PROTOCOL_VIOLATION``.
|
|
*/
|
|
-#define NGTCP2_PROTOCOL_VIOLATION 0xau
|
|
+#define NGTCP2_PROTOCOL_VIOLATION 0xAU
|
|
|
|
/**
|
|
* @macro
|
|
@@ -961,7 +975,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_INVALID_TOKEN` is QUIC transport error code
|
|
* ``INVALID_TOKEN``.
|
|
*/
|
|
-#define NGTCP2_INVALID_TOKEN 0xbu
|
|
+#define NGTCP2_INVALID_TOKEN 0xBU
|
|
|
|
/**
|
|
* @macro
|
|
@@ -969,7 +983,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_APPLICATION_ERROR` is QUIC transport error code
|
|
* ``APPLICATION_ERROR``.
|
|
*/
|
|
-#define NGTCP2_APPLICATION_ERROR 0xcu
|
|
+#define NGTCP2_APPLICATION_ERROR 0xCU
|
|
|
|
/**
|
|
* @macro
|
|
@@ -977,7 +991,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_CRYPTO_BUFFER_EXCEEDED` is QUIC transport error code
|
|
* ``CRYPTO_BUFFER_EXCEEDED``.
|
|
*/
|
|
-#define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xdu
|
|
+#define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xDU
|
|
|
|
/**
|
|
* @macro
|
|
@@ -985,7 +999,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_KEY_UPDATE_ERROR` is QUIC transport error code
|
|
* ``KEY_UPDATE_ERROR``.
|
|
*/
|
|
-#define NGTCP2_KEY_UPDATE_ERROR 0xeu
|
|
+#define NGTCP2_KEY_UPDATE_ERROR 0xEU
|
|
|
|
/**
|
|
* @macro
|
|
@@ -993,7 +1007,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_AEAD_LIMIT_REACHED` is QUIC transport error code
|
|
* ``AEAD_LIMIT_REACHED``.
|
|
*/
|
|
-#define NGTCP2_AEAD_LIMIT_REACHED 0xfu
|
|
+#define NGTCP2_AEAD_LIMIT_REACHED 0xFU
|
|
|
|
/**
|
|
* @macro
|
|
@@ -1001,7 +1015,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_NO_VIABLE_PATH` is QUIC transport error code
|
|
* ``NO_VIABLE_PATH``.
|
|
*/
|
|
-#define NGTCP2_NO_VIABLE_PATH 0x10u
|
|
+#define NGTCP2_NO_VIABLE_PATH 0x10U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -1009,7 +1023,7 @@ typedef enum ngtcp2_pkt_type {
|
|
* :macro:`NGTCP2_CRYPTO_ERROR` is QUIC transport error code
|
|
* ``CRYPTO_ERROR``.
|
|
*/
|
|
-#define NGTCP2_CRYPTO_ERROR 0x100u
|
|
+#define NGTCP2_CRYPTO_ERROR 0x100U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -1173,6 +1187,9 @@ typedef struct ngtcp2_pkt_hd {
|
|
* @struct
|
|
*
|
|
* :type:`ngtcp2_pkt_stateless_reset` represents Stateless Reset.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :type:`ngtcp2_pkt_stateless_reset2`
|
|
+ * instead.
|
|
*/
|
|
typedef struct ngtcp2_pkt_stateless_reset {
|
|
/**
|
|
@@ -1190,6 +1207,40 @@ typedef struct ngtcp2_pkt_stateless_reset {
|
|
size_t randlen;
|
|
} ngtcp2_pkt_stateless_reset;
|
|
|
|
+/**
|
|
+ * @struct
|
|
+ *
|
|
+ * :type:`ngtcp2_stateless_reset_token` stores stateless reset token.
|
|
+ *
|
|
+ * This struct has been available since v1.22.0.
|
|
+ */
|
|
+typedef struct ngtcp2_stateless_reset_token {
|
|
+ uint8_t data[NGTCP2_STATELESS_RESET_TOKENLEN];
|
|
+} ngtcp2_stateless_reset_token;
|
|
+
|
|
+/**
|
|
+ * @struct
|
|
+ *
|
|
+ * :type:`ngtcp2_pkt_stateless_reset2` represents Stateless Reset.
|
|
+ *
|
|
+ * This struct has been available since v1.22.0.
|
|
+ */
|
|
+typedef struct ngtcp2_pkt_stateless_reset2 {
|
|
+ /**
|
|
+ * :member:`token` contains stateless reset token.
|
|
+ */
|
|
+ ngtcp2_stateless_reset_token token;
|
|
+ /**
|
|
+ * :member:`rand` points a buffer which contains random bytes
|
|
+ * section.
|
|
+ */
|
|
+ const uint8_t *rand;
|
|
+ /**
|
|
+ * :member:`randlen` is the number of random bytes.
|
|
+ */
|
|
+ size_t randlen;
|
|
+} ngtcp2_pkt_stateless_reset2;
|
|
+
|
|
/**
|
|
* @macrosection
|
|
*
|
|
@@ -1236,7 +1287,7 @@ typedef struct ngtcp2_pkt_stateless_reset {
|
|
* :macro:`NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1` is TLS
|
|
* extension type of quic_transport_parameters.
|
|
*/
|
|
-#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39u
|
|
+#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39U
|
|
|
|
#ifdef NGTCP2_USE_GENERIC_SOCKADDR
|
|
# ifndef NGTCP2_AF_INET
|
|
@@ -1267,7 +1318,7 @@ typedef struct ngtcp2_sockaddr_in {
|
|
} ngtcp2_sockaddr_in;
|
|
|
|
typedef struct ngtcp2_in6_addr {
|
|
- uint8_t in6_addr[16];
|
|
+ uint8_t s6_addr[16];
|
|
} ngtcp2_in6_addr;
|
|
|
|
typedef struct ngtcp2_sockaddr_in6 {
|
|
@@ -1561,7 +1612,8 @@ typedef struct ngtcp2_transport_params {
|
|
} ngtcp2_transport_params;
|
|
|
|
#define NGTCP2_CONN_INFO_V1 1
|
|
-#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V1
|
|
+#define NGTCP2_CONN_INFO_V2 2
|
|
+#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V2
|
|
|
|
/**
|
|
* @struct
|
|
@@ -1600,6 +1652,52 @@ typedef struct ngtcp2_conn_info {
|
|
* packets which have not been acknowledged.
|
|
*/
|
|
uint64_t bytes_in_flight;
|
|
+ /* The following fields have been added since NGTCP2_CONN_INFO_V2. */
|
|
+ /**
|
|
+ * :member:`pkt_sent` is the number of QUIC packets sent. This
|
|
+ * field has been available since v1.16.0.
|
|
+ */
|
|
+ uint64_t pkt_sent;
|
|
+ /**
|
|
+ * :member:`bytes_sent` is the number of bytes (the sum of QUIC
|
|
+ * packet length) sent. This field has been available since
|
|
+ * v1.16.0.
|
|
+ */
|
|
+ uint64_t bytes_sent;
|
|
+ /**
|
|
+ * :member:`pkt_recv` is the number of QUIC packets received,
|
|
+ * excluding discarded ones. This field has been available since
|
|
+ * v1.16.0.
|
|
+ */
|
|
+ uint64_t pkt_recv;
|
|
+ /**
|
|
+ * :member:`bytes_recv` is the number of bytes (the sum of QUIC
|
|
+ * packet length) received, excluding discarded ones. This field
|
|
+ * has been available since v1.16.0.
|
|
+ */
|
|
+ uint64_t bytes_recv;
|
|
+ /**
|
|
+ * :member:`pkt_lost` is the number of QUIC packets that are
|
|
+ * considered lost, excluding PMTUD packets. This field has been
|
|
+ * available since v1.16.0.
|
|
+ */
|
|
+ uint64_t pkt_lost;
|
|
+ /**
|
|
+ * :member:`bytes_lost` is the number of bytes (the sum of QUIC
|
|
+ * packet length) lost, excluding PMTUD packets. This field has
|
|
+ * been available since v1.16.0.
|
|
+ */
|
|
+ uint64_t bytes_lost;
|
|
+ /**
|
|
+ * :member:`ping_recv` is the number of PING frames received. This
|
|
+ * field has been available since v1.16.0.
|
|
+ */
|
|
+ uint64_t ping_recv;
|
|
+ /**
|
|
+ * :member:`pkt_discarded` is the number of QUIC packets discarded.
|
|
+ * This field has been available since v1.16.0.
|
|
+ */
|
|
+ uint64_t pkt_discarded;
|
|
} ngtcp2_conn_info;
|
|
|
|
/**
|
|
@@ -1642,14 +1740,14 @@ typedef void (*ngtcp2_printf)(void *user_data, const char *format, ...);
|
|
*
|
|
* :macro:`NGTCP2_QLOG_WRITE_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_QLOG_WRITE_FLAG_NONE 0x00u
|
|
+#define NGTCP2_QLOG_WRITE_FLAG_NONE 0x00U
|
|
/**
|
|
* @macro
|
|
*
|
|
* :macro:`NGTCP2_QLOG_WRITE_FLAG_FIN` indicates that this is the
|
|
* final call to :type:`ngtcp2_qlog_write` in the current connection.
|
|
*/
|
|
-#define NGTCP2_QLOG_WRITE_FLAG_FIN 0x01u
|
|
+#define NGTCP2_QLOG_WRITE_FLAG_FIN 0x01U
|
|
|
|
/**
|
|
* @struct
|
|
@@ -1704,7 +1802,8 @@ typedef enum ngtcp2_token_type {
|
|
|
|
#define NGTCP2_SETTINGS_V1 1
|
|
#define NGTCP2_SETTINGS_V2 2
|
|
-#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V2
|
|
+#define NGTCP2_SETTINGS_V3 3
|
|
+#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V3
|
|
|
|
/**
|
|
* @struct
|
|
@@ -1738,7 +1837,9 @@ typedef struct ngtcp2_settings {
|
|
ngtcp2_printf log_printf;
|
|
/**
|
|
* :member:`max_tx_udp_payload_size` is the maximum size of UDP
|
|
- * datagram payload that the local endpoint transmits.
|
|
+ * datagram payload that the local endpoint transmits. This must be
|
|
+ * larger than or equal to :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE`, and
|
|
+ * less then or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`.
|
|
*/
|
|
size_t max_tx_udp_payload_size;
|
|
/**
|
|
@@ -1802,8 +1903,8 @@ typedef struct ngtcp2_settings {
|
|
uint64_t max_stream_window;
|
|
/**
|
|
* :member:`ack_thresh` is the minimum number of the received ACK
|
|
- * eliciting packets that trigger the immediate acknowledgement from
|
|
- * the local endpoint.
|
|
+ * eliciting packets that triggers the immediate acknowledgement
|
|
+ * from the local endpoint.
|
|
*/
|
|
size_t ack_thresh;
|
|
/**
|
|
@@ -1903,12 +2004,13 @@ typedef struct ngtcp2_settings {
|
|
/**
|
|
* :member:`pmtud_probes` is the array of UDP datagram payload size
|
|
* to probe during Path MTU Discovery. The discovery is done in the
|
|
- * order appeared in this array. The size must be strictly larger
|
|
- * than 1200, otherwise the behavior is undefined. The maximum
|
|
- * value in this array should be set to
|
|
- * :member:`max_tx_udp_payload_size`. If this field is not set, the
|
|
- * predefined PMTUD probes are made. This field has been available
|
|
- * since v1.4.0.
|
|
+ * order appeared in this array. The payload size must be strictly
|
|
+ * larger than :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE`, and less than
|
|
+ * or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`. Otherwise
|
|
+ * the behavior is undefined. The maximum value in this array
|
|
+ * should be set to :member:`max_tx_udp_payload_size`. If this
|
|
+ * field is not set, the predefined PMTUD probes are made. This
|
|
+ * field has been available since v1.4.0.
|
|
*/
|
|
const uint16_t *pmtud_probes;
|
|
/**
|
|
@@ -1917,6 +2019,23 @@ typedef struct ngtcp2_settings {
|
|
* field has been available since v1.4.0.
|
|
*/
|
|
size_t pmtud_probeslen;
|
|
+ /* The following fields have been added since NGTCP2_SETTINGS_V3. */
|
|
+ /**
|
|
+ * :member:`glitch_ratelim_burst` is the maximum number of tokens
|
|
+ * available to "glitch" rate limiter. "glitch" is a suspicious
|
|
+ * activity from a remote endpoint. If detected, certain amount of
|
|
+ * tokens are consumed. If no tokens are available to consume, the
|
|
+ * connection is closed. The rate of token generation is specified
|
|
+ * by :member:`glitch_ratelim_rate`. This field has been available
|
|
+ * since v1.15.0.
|
|
+ */
|
|
+ uint64_t glitch_ratelim_burst;
|
|
+ /**
|
|
+ * :member:`glitch_ratelim_rate` is the number of tokens generated
|
|
+ * per second. See :member:`glitch_ratelim_burst` for "glitch" rate
|
|
+ * limiter. This field has been available since v1.15.0.
|
|
+ */
|
|
+ uint64_t glitch_ratelim_rate;
|
|
} ngtcp2_settings;
|
|
|
|
/**
|
|
@@ -2362,11 +2481,42 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_short(ngtcp2_pkt_hd *dest,
|
|
* :macro:`NGTCP2_ERR_INVALID_ARGUMENT`
|
|
* |randlen| is strictly less than
|
|
* :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use `ngtcp2_pkt_write_stateless_reset2`
|
|
+ * instead.
|
|
*/
|
|
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset(
|
|
uint8_t *dest, size_t destlen, const uint8_t *stateless_reset_token,
|
|
const uint8_t *rand, size_t randlen);
|
|
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_pkt_write_stateless_reset2` writes Stateless Reset packet
|
|
+ * in the buffer pointed by |dest| whose length is |destlen|. |token|
|
|
+ * must store the Stateless Reset Token. |rand| specifies the random
|
|
+ * octets preceding Stateless Reset Token. The length of |rand| is
|
|
+ * specified by |randlen| which must be at least
|
|
+ * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN` bytes long.
|
|
+ *
|
|
+ * If |randlen| is too long to write them all in the buffer, |rand| is
|
|
+ * written to the buffer as much as possible, and is truncated.
|
|
+ *
|
|
+ * This function returns the number of bytes written to the buffer, or
|
|
+ * one of the following negative error codes:
|
|
+ *
|
|
+ * :macro:`NGTCP2_ERR_NOBUF`
|
|
+ * Buffer is too small.
|
|
+ * :macro:`NGTCP2_ERR_INVALID_ARGUMENT`
|
|
+ * |randlen| is strictly less than
|
|
+ * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`.
|
|
+ *
|
|
+ * This function has been available since v1.22.0.
|
|
+ */
|
|
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset2(
|
|
+ uint8_t *dest, size_t destlen, const ngtcp2_stateless_reset_token *token,
|
|
+ const uint8_t *rand, size_t randlen);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
@@ -2662,7 +2812,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
*
|
|
* :macro:`NGTCP2_STREAM_DATA_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_STREAM_DATA_FLAG_NONE 0x00u
|
|
+#define NGTCP2_STREAM_DATA_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -2670,7 +2820,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
* :macro:`NGTCP2_STREAM_DATA_FLAG_FIN` indicates that this chunk of
|
|
* data is final piece of an incoming stream.
|
|
*/
|
|
-#define NGTCP2_STREAM_DATA_FLAG_FIN 0x01u
|
|
+#define NGTCP2_STREAM_DATA_FLAG_FIN 0x01U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -2679,7 +2829,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
* data contains data received in 0-RTT packet, and the handshake has
|
|
* not completed yet, which means that the data might be replayed.
|
|
*/
|
|
-#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02u
|
|
+#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02U
|
|
|
|
/**
|
|
* @functypedef
|
|
@@ -2734,7 +2884,7 @@ typedef int (*ngtcp2_stream_open)(ngtcp2_conn *conn, int64_t stream_id,
|
|
*
|
|
* :macro:`NGTCP2_STREAM_CLOSE_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_STREAM_CLOSE_FLAG_NONE 0x00u
|
|
+#define NGTCP2_STREAM_CLOSE_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -2742,7 +2892,7 @@ typedef int (*ngtcp2_stream_open)(ngtcp2_conn *conn, int64_t stream_id,
|
|
* :macro:`NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET` indicates that
|
|
* app_error_code parameter is set.
|
|
*/
|
|
-#define NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET 0x01u
|
|
+#define NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET 0x01U
|
|
|
|
/**
|
|
* @functypedef
|
|
@@ -2823,6 +2973,9 @@ typedef int (*ngtcp2_acked_stream_data_offset)(
|
|
* The implementation of this callback should return 0 if it succeeds.
|
|
* Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library
|
|
* call return immediately.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :type:`ngtcp2_recv_stateless_reset2`
|
|
+ * instead.
|
|
*/
|
|
typedef int (*ngtcp2_recv_stateless_reset)(ngtcp2_conn *conn,
|
|
const ngtcp2_pkt_stateless_reset *sr,
|
|
@@ -2887,6 +3040,9 @@ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen,
|
|
* The callback function must return 0 if it succeeds. Returning
|
|
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
* immediately.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use
|
|
+ * :type:`ngtcp2_get_new_connection_id2` instead.
|
|
*/
|
|
typedef int (*ngtcp2_get_new_connection_id)(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
|
uint8_t *token, size_t cidlen,
|
|
@@ -2951,7 +3107,7 @@ typedef int (*ngtcp2_update_key)(
|
|
*
|
|
* :macro:`NGTCP2_PATH_VALIDATION_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_PATH_VALIDATION_FLAG_NONE 0x00u
|
|
+#define NGTCP2_PATH_VALIDATION_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -2960,7 +3116,7 @@ typedef int (*ngtcp2_update_key)(
|
|
* validation involving server preferred address. This flag is only
|
|
* set for client.
|
|
*/
|
|
-#define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01u
|
|
+#define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -2969,7 +3125,29 @@ typedef int (*ngtcp2_update_key)(
|
|
* server should send NEW_TOKEN frame for the new remote address.
|
|
* This flag is only set for server.
|
|
*/
|
|
-#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u
|
|
+#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02U
|
|
+
|
|
+/**
|
|
+ * @functypedef
|
|
+ *
|
|
+ * :type:`ngtcp2_begin_path_validation` is a callback function which
|
|
+ * is called when the path validation has started. |flags| is zero or
|
|
+ * more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_*
|
|
+ * <NGTCP2_PATH_VALIDATION_FLAG_NONE>`. |path| is the path that is
|
|
+ * being validated. |fallback_path|, if not NULL, is the path that is
|
|
+ * used when this validation fails.
|
|
+ *
|
|
+ * Currently, the flags may only contain
|
|
+ * :macro:`NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR`.
|
|
+ *
|
|
+ * The callback function must return 0 if it succeeds. Returning
|
|
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
+ * immediately.
|
|
+ */
|
|
+typedef int (*ngtcp2_begin_path_validation)(ngtcp2_conn *conn, uint32_t flags,
|
|
+ const ngtcp2_path *path,
|
|
+ const ngtcp2_path *fallback_path,
|
|
+ void *user_data);
|
|
|
|
/**
|
|
* @functypedef
|
|
@@ -2978,9 +3156,8 @@ typedef int (*ngtcp2_update_key)(
|
|
* an application the outcome of path validation. |flags| is zero or
|
|
* more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_*
|
|
* <NGTCP2_PATH_VALIDATION_FLAG_NONE>`. |path| is the path that was
|
|
- * validated. |old_path| is the path that is previously used before a
|
|
- * local endpoint has migrated to |path| if |old_path| is not NULL.
|
|
- * If |res| is
|
|
+ * validated. |fallback_path|, if not NULL, is the path that is used
|
|
+ * if the path validation failed. If |res| is
|
|
* :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_SUCCESS`,
|
|
* the path validation succeeded. If |res| is
|
|
* :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_FAILURE`,
|
|
@@ -2992,7 +3169,7 @@ typedef int (*ngtcp2_update_key)(
|
|
*/
|
|
typedef int (*ngtcp2_path_validation)(ngtcp2_conn *conn, uint32_t flags,
|
|
const ngtcp2_path *path,
|
|
- const ngtcp2_path *old_path,
|
|
+ const ngtcp2_path *fallback_path,
|
|
ngtcp2_path_validation_result res,
|
|
void *user_data);
|
|
|
|
@@ -3063,6 +3240,9 @@ typedef enum ngtcp2_connection_id_status_type {
|
|
* The callback function must return 0 if it succeeds. Returning
|
|
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
* immediately.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :type:`ngtcp2_connection_id_status2`
|
|
+ * instead.
|
|
*/
|
|
typedef int (*ngtcp2_connection_id_status)(
|
|
ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq,
|
|
@@ -3118,7 +3298,7 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)(
|
|
*
|
|
* :macro:`NGTCP2_DATAGRAM_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_DATAGRAM_FLAG_NONE 0x00u
|
|
+#define NGTCP2_DATAGRAM_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -3127,7 +3307,7 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)(
|
|
* received in 0-RTT packet, and the handshake has not completed yet,
|
|
* which means that the data might be replayed.
|
|
*/
|
|
-#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01u
|
|
+#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01U
|
|
|
|
/**
|
|
* @functypedef
|
|
@@ -3190,6 +3370,9 @@ typedef int (*ngtcp2_lost_datagram)(ngtcp2_conn *conn, uint64_t dgram_id,
|
|
* The callback function must return 0 if it succeeds. Returning
|
|
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
* immediately.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use
|
|
+ * :type:`ngtcp2_get_path_challenge_data2` instead.
|
|
*/
|
|
typedef int (*ngtcp2_get_path_challenge_data)(ngtcp2_conn *conn, uint8_t *data,
|
|
void *user_data);
|
|
@@ -3261,8 +3444,99 @@ typedef int (*ngtcp2_recv_key)(ngtcp2_conn *conn, ngtcp2_encryption_level level,
|
|
typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn,
|
|
void *user_data);
|
|
|
|
+/**
|
|
+ * @functypedef
|
|
+ *
|
|
+ * :type:`ngtcp2_recv_stateless_reset2` is a callback function which
|
|
+ * is called when Stateless Reset packet is received. The stateless
|
|
+ * reset details are given in |sr|.
|
|
+ *
|
|
+ * The implementation of this callback should return 0 if it succeeds.
|
|
+ * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library
|
|
+ * call return immediately.
|
|
+ *
|
|
+ * This type has been available since v1.22.0
|
|
+ */
|
|
+typedef int (*ngtcp2_recv_stateless_reset2)(
|
|
+ ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset2 *sr, void *user_data);
|
|
+
|
|
+/**
|
|
+ * @functypedef
|
|
+ *
|
|
+ * :type:`ngtcp2_get_new_connection_id2` is a callback function to ask
|
|
+ * an application for new connection ID. Application must generate
|
|
+ * new unused connection ID with the exact |cidlen| bytes, and store
|
|
+ * it in |cid|. It also has to generate a stateless reset token, and
|
|
+ * store it in |token|.
|
|
+ *
|
|
+ * The callback function must return 0 if it succeeds. Returning
|
|
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
+ * immediately.
|
|
+ *
|
|
+ * This type has been available since v1.22.0
|
|
+ */
|
|
+typedef int (*ngtcp2_get_new_connection_id2)(
|
|
+ ngtcp2_conn *conn, ngtcp2_cid *cid, ngtcp2_stateless_reset_token *token,
|
|
+ size_t cidlen, void *user_data);
|
|
+
|
|
+/**
|
|
+ * @functypedef
|
|
+ *
|
|
+ * :type:`ngtcp2_connection_id_status2` is a callback function which
|
|
+ * is called when the status of Destination Connection ID changes.
|
|
+ *
|
|
+ * |token| is the associated stateless reset token, and it is ``NULL``
|
|
+ * if no token is present.
|
|
+ *
|
|
+ * |type| is the one of the value defined in
|
|
+ * :type:`ngtcp2_connection_id_status_type`. The new value might be
|
|
+ * added in the future release.
|
|
+ *
|
|
+ * The callback function must return 0 if it succeeds. Returning
|
|
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
+ * immediately.
|
|
+ *
|
|
+ * This type has been available since v1.22.0
|
|
+ */
|
|
+typedef int (*ngtcp2_connection_id_status2)(
|
|
+ ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq,
|
|
+ const ngtcp2_cid *cid, const ngtcp2_stateless_reset_token *token,
|
|
+ void *user_data);
|
|
+
|
|
+/**
|
|
+ * @struct
|
|
+ *
|
|
+ * :type:`ngtcp2_path_challenge_data` stores path challenge data.
|
|
+ *
|
|
+ * This type has been available since v1.22.0.
|
|
+ */
|
|
+typedef struct ngtcp2_path_challenge_data {
|
|
+ uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN];
|
|
+} ngtcp2_path_challenge_data;
|
|
+
|
|
+/**
|
|
+ * @functypedef
|
|
+ *
|
|
+ * :type:`ngtcp2_get_path_challenge_data2` is a callback function to
|
|
+ * ask an application for new data that is sent in PATH_CHALLENGE
|
|
+ * frame. Application must generate new unpredictable, exactly
|
|
+ * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data, and
|
|
+ * store them into |data|.
|
|
+ *
|
|
+ * The callback function must return 0 if it succeeds. Returning
|
|
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
|
|
+ * immediately.
|
|
+ *
|
|
+ * This type has been available since v1.22.0.
|
|
+ */
|
|
+typedef int (*ngtcp2_get_path_challenge_data2)(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data,
|
|
+ void *user_data);
|
|
+
|
|
#define NGTCP2_CALLBACKS_V1 1
|
|
-#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V1
|
|
+#define NGTCP2_CALLBACKS_V2 2
|
|
+#define NGTCP2_CALLBACKS_V3 3
|
|
+#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V3
|
|
|
|
/**
|
|
* @struct
|
|
@@ -3349,6 +3623,11 @@ typedef struct ngtcp2_callbacks {
|
|
* :member:`recv_stateless_reset` is a callback function which is
|
|
* invoked when Stateless Reset packet is received. This callback
|
|
* function is optional.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :member:`recv_stateless_reset2`
|
|
+ * instead. If both :member:`recv_stateless_reset` and
|
|
+ * :member:`recv_stateless_reset2` are set, the latter has the
|
|
+ * precedence.
|
|
*/
|
|
ngtcp2_recv_stateless_reset recv_stateless_reset;
|
|
/**
|
|
@@ -3379,8 +3658,14 @@ typedef struct ngtcp2_callbacks {
|
|
ngtcp2_rand rand;
|
|
/**
|
|
* :member:`get_new_connection_id` is a callback function which is
|
|
- * invoked when the library needs new connection ID. This callback
|
|
- * function must be specified.
|
|
+ * invoked when the library needs new connection ID. Either this
|
|
+ * callback function or :member:`get_new_connection_id2` must be
|
|
+ * specified.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :member:`get_new_connection_id2`
|
|
+ * instead. If both :member:`get_new_connection_id` and
|
|
+ * :member:`get_new_connection_id2` are set, the latter has the
|
|
+ * precedence.
|
|
*/
|
|
ngtcp2_get_new_connection_id get_new_connection_id;
|
|
/**
|
|
@@ -3441,6 +3726,10 @@ typedef struct ngtcp2_callbacks {
|
|
* when the new Destination Connection ID is activated, or the
|
|
* activated Destination Connection ID is now deactivated. This
|
|
* callback function is optional.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :member:`dcid_status2` instead.
|
|
+ * If both :member:`dcid_status` and :member:`dcid_status2` are set,
|
|
+ * the latter has the precedence.
|
|
*/
|
|
ngtcp2_connection_id_status dcid_status;
|
|
/**
|
|
@@ -3491,6 +3780,9 @@ typedef struct ngtcp2_callbacks {
|
|
* :member:`get_path_challenge_data` is a callback function which is
|
|
* invoked when the library needs new data sent along with
|
|
* PATH_CHALLENGE frame. This callback must be specified.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :member:`get_path_challenge_data2`
|
|
+ * instead.
|
|
*/
|
|
ngtcp2_get_path_challenge_data get_path_challenge_data;
|
|
/**
|
|
@@ -3527,6 +3819,42 @@ typedef struct ngtcp2_callbacks {
|
|
* is only used by client.
|
|
*/
|
|
ngtcp2_tls_early_data_rejected tls_early_data_rejected;
|
|
+ /* The following fields have been added since NGTCP2_CALLBACKS_V2. */
|
|
+ /**
|
|
+ * :member:`begin_path_validation` is a callback function which is
|
|
+ * invoked when a path validation has started. This field is
|
|
+ * available since v1.14.0.
|
|
+ */
|
|
+ ngtcp2_begin_path_validation begin_path_validation;
|
|
+ /* The following fields have been added since NGTCP2_CALLBACKS_V3. */
|
|
+ /**
|
|
+ * :member:`recv_stateless_reset2` is a callback function which is
|
|
+ * invoked when Stateless Reset packet is received. This callback
|
|
+ * function is optional. This field is available since v1.22.0.
|
|
+ */
|
|
+ ngtcp2_recv_stateless_reset2 recv_stateless_reset2;
|
|
+ /**
|
|
+ * :member:`get_new_connection_id2` is a callback function which is
|
|
+ * invoked when the library needs new connection ID. This callback
|
|
+ * function must be specified. This field is available since
|
|
+ * v1.22.0.
|
|
+ */
|
|
+ ngtcp2_get_new_connection_id2 get_new_connection_id2;
|
|
+ /**
|
|
+ * :member:`dcid_status2` is a callback function which is invoked
|
|
+ * when the new Destination Connection ID is activated, or the
|
|
+ * activated Destination Connection ID is now deactivated. This
|
|
+ * callback function is optional. This field is available since
|
|
+ * v1.22.0.
|
|
+ */
|
|
+ ngtcp2_connection_id_status2 dcid_status2;
|
|
+ /**
|
|
+ * :member:`get_path_challenge_data2` is a callback function which
|
|
+ * is invoked when the library needs new data sent along with
|
|
+ * PATH_CHALLENGE frame. This callback must be specified. This
|
|
+ * field is available since v1.22.0.
|
|
+ */
|
|
+ ngtcp2_get_path_challenge_data2 get_path_challenge_data2;
|
|
} ngtcp2_callbacks;
|
|
|
|
/**
|
|
@@ -3742,6 +4070,21 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned(
|
|
ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
|
|
ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts);
|
|
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_conn_continue_handshake` resumes handshake interrupted by
|
|
+ * TLS stack routine (e.g., private key operation offloading,
|
|
+ * certificate lookup, etc).
|
|
+ *
|
|
+ * This function returns 0 if it succeeds. In general, this function
|
|
+ * returns the same set of error codes from `ngtcp2_conn_read_pkt`.
|
|
+ *
|
|
+ * This function has been available since v1.22.0.
|
|
+ */
|
|
+NGTCP2_EXTERN int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn,
|
|
+ ngtcp2_tstamp ts);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
@@ -4061,9 +4404,7 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn,
|
|
* `ngtcp2_conn_get_expiry` returns the next expiry time. It returns
|
|
* ``UINT64_MAX`` if there is no next expiry.
|
|
*
|
|
- * Call `ngtcp2_conn_handle_expiry` and then
|
|
- * `ngtcp2_conn_writev_stream` (or `ngtcp2_conn_writev_datagram`) when
|
|
- * the expiry time has passed.
|
|
+ * Call `ngtcp2_conn_handle_expiry` when the expiry time has passed.
|
|
*/
|
|
NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn);
|
|
|
|
@@ -4071,6 +4412,20 @@ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn);
|
|
* @function
|
|
*
|
|
* `ngtcp2_conn_handle_expiry` handles expired timer.
|
|
+ *
|
|
+ * If it returns :macro:`NGTCP2_ERR_IDLE_CLOSE`, it means that an idle
|
|
+ * timer has fired for this particular connection. In this case, drop
|
|
+ * the connection without calling
|
|
+ * `ngtcp2_conn_write_connection_close`. If it returns any of the
|
|
+ * other negative error codes, close the connection by sending the
|
|
+ * terminal packet produced by `ngtcp2_conn_write_connection_close`.
|
|
+ * Otherwise, schedule `ngtcp2_conn_writev_stream` call. An
|
|
+ * application may call any number of additional
|
|
+ * `ngtcp2_conn_read_pkt` and `ngtcp2_conn_handle_expiry` before
|
|
+ * calling `ngtcp2_conn_writev_stream`. After calling
|
|
+ * `ngtcp2_conn_writev_stream`, new expiry is set. The application
|
|
+ * should call `ngtcp2_conn_get_expiry` to get a new deadline and set
|
|
+ * the timer.
|
|
*/
|
|
NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn,
|
|
ngtcp2_tstamp ts);
|
|
@@ -4389,7 +4744,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn,
|
|
*
|
|
* :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_WRITE_STREAM_FLAG_NONE 0x00u
|
|
+#define NGTCP2_WRITE_STREAM_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -4397,7 +4752,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn,
|
|
* :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` indicates that more data may
|
|
* come, and should be coalesced into the same packet if possible.
|
|
*/
|
|
-#define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01u
|
|
+#define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -4405,7 +4760,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn,
|
|
* :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that a passed data
|
|
* is the final part of a stream.
|
|
*/
|
|
-#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u
|
|
+#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -4416,7 +4771,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn,
|
|
* finalizing it. PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE
|
|
* only packets and PMTUD packets are excluded.
|
|
*/
|
|
-#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04u
|
|
+#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04U
|
|
|
|
/**
|
|
* @function
|
|
@@ -4601,7 +4956,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned(
|
|
*
|
|
* :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
-#define NGTCP2_WRITE_DATAGRAM_FLAG_NONE 0x00u
|
|
+#define NGTCP2_WRITE_DATAGRAM_FLAG_NONE 0x00U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -4609,7 +4964,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned(
|
|
* :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_MORE` indicates that more data
|
|
* may come, and should be coalesced into the same packet if possible.
|
|
*/
|
|
-#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u
|
|
+#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01U
|
|
|
|
/**
|
|
* @macro
|
|
@@ -4620,7 +4975,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned(
|
|
* finalizing it. PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE
|
|
* only packets and PMTUD packets are excluded.
|
|
*/
|
|
-#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02u
|
|
+#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02U
|
|
|
|
/**
|
|
* @function
|
|
@@ -4857,6 +5212,8 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest);
|
|
*
|
|
* :type:`ngtcp2_cid_token` is the convenient struct to store
|
|
* Connection ID, its associated path, and stateless reset token.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use :type:`ngtcp2_cid_token2` instead.
|
|
*/
|
|
typedef struct ngtcp2_cid_token {
|
|
/**
|
|
@@ -4896,10 +5253,65 @@ typedef struct ngtcp2_cid_token {
|
|
* sizeof(:type:`ngtcp2_cid_token`) * n bytes available, where n is
|
|
* the return value of `ngtcp2_conn_get_active_dcid` with |dest| ==
|
|
* NULL.
|
|
+ *
|
|
+ * Deprecated since v1.22.0. Use `ngtcp2_conn_get_active_dcid2`
|
|
+ * instead.
|
|
*/
|
|
NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn,
|
|
ngtcp2_cid_token *dest);
|
|
|
|
+/**
|
|
+ * @struct
|
|
+ *
|
|
+ * :type:`ngtcp2_cid_token2` is the convenient struct to store
|
|
+ * Connection ID, its associated path, and stateless reset token.
|
|
+ *
|
|
+ * This type has been available since v1.22.0.
|
|
+ */
|
|
+typedef struct ngtcp2_cid_token2 {
|
|
+ /**
|
|
+ * :member:`seq` is the sequence number of this Connection ID.
|
|
+ */
|
|
+ uint64_t seq;
|
|
+ /**
|
|
+ * :member:`cid` is Connection ID.
|
|
+ */
|
|
+ ngtcp2_cid cid;
|
|
+ /**
|
|
+ * :member:`ps` is the path which this Connection ID is associated
|
|
+ * with.
|
|
+ */
|
|
+ ngtcp2_path_storage ps;
|
|
+ /**
|
|
+ * :member:`token` is the stateless reset token for this Connection
|
|
+ * ID.
|
|
+ */
|
|
+ ngtcp2_stateless_reset_token token;
|
|
+ /**
|
|
+ * :member:`token_present` is nonzero if token contains stateless
|
|
+ * reset token.
|
|
+ */
|
|
+ uint8_t token_present;
|
|
+} ngtcp2_cid_token2;
|
|
+
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_conn_get_active_dcid2` writes the all active Destination
|
|
+ * Connection IDs and their tokens to |dest|. Before handshake
|
|
+ * completes, this function returns 0. If |dest| is NULL, this
|
|
+ * function does not write anything, and returns the number of
|
|
+ * Destination Connection IDs that would otherwise be written to the
|
|
+ * provided buffer. The buffer pointed by |dest| must have
|
|
+ * sizeof(:type:`ngtcp2_cid_token2`) * n bytes available, where n is
|
|
+ * the return value of `ngtcp2_conn_get_active_dcid2` with |dest| ==
|
|
+ * NULL.
|
|
+ *
|
|
+ * This function has been available since v1.22.0.
|
|
+ */
|
|
+NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn,
|
|
+ ngtcp2_cid_token2 *dest);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
@@ -5430,7 +5842,7 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr,
|
|
* @function
|
|
*
|
|
* `ngtcp2_conn_write_connection_close` writes a packet which contains
|
|
- * CONNECTION_CLOSE frame(s) (type 0x1c or 0x1d) in the buffer pointed
|
|
+ * CONNECTION_CLOSE frame(s) (type 0x1C or 0x1D) in the buffer pointed
|
|
* by |dest| whose capacity is |destlen|.
|
|
*
|
|
* For client, |destlen| should be at least
|
|
@@ -5447,16 +5859,18 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr,
|
|
*
|
|
* If :member:`ccerr->type <ngtcp2_ccerr.type>` ==
|
|
* :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, this
|
|
- * function sends CONNECTION_CLOSE (type 0x1c) frame. If
|
|
+ * function sends CONNECTION_CLOSE (type 0x1C) frame. If
|
|
* :member:`ccerr->type <ngtcp2_ccerr.type>` ==
|
|
* :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, it sends
|
|
- * CONNECTION_CLOSE (type 0x1d) frame. Otherwise, it does not produce
|
|
+ * CONNECTION_CLOSE (type 0x1D) frame. Otherwise, it does not produce
|
|
* any data, and returns 0.
|
|
*
|
|
* |destlen| could be shorten by some factors (e.g., server side
|
|
* amplification limit). This function returns
|
|
* :macro:`NGTCP2_ERR_NOBUF` if the resulting buffer is too small even
|
|
- * if the given buffer has enough space.
|
|
+ * if the given buffer has enough space. This can happen if sending a
|
|
+ * packet would exceed a transmission limit (e.g., for amplification
|
|
+ * attack protection).
|
|
*
|
|
* This function must not be called from inside the callback
|
|
* functions.
|
|
@@ -5471,7 +5885,8 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr,
|
|
* :macro:`NGTCP2_ERR_NOMEM`
|
|
* Out of memory
|
|
* :macro:`NGTCP2_ERR_NOBUF`
|
|
- * Buffer is too small
|
|
+ * Buffer is too small or packet would exceed the transmission
|
|
+ * limit (e.g., for amplification attack protection).
|
|
* :macro:`NGTCP2_ERR_INVALID_STATE`
|
|
* The current state does not allow sending CONNECTION_CLOSE
|
|
* frame.
|
|
@@ -5535,6 +5950,26 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn,
|
|
int64_t stream_id,
|
|
void *stream_user_data);
|
|
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_conn_get_stream_user_data` returns stream_user_data
|
|
+ * associated to the stream identified by |stream_id|. If the stream
|
|
+ * is not found, or no stream data is associated to the stream, this
|
|
+ * function returns NULL.
|
|
+ *
|
|
+ * The stream_user_data can be associated to the stream by one of the
|
|
+ * following functions:
|
|
+ *
|
|
+ * - `ngtcp2_conn_open_bidi_stream`
|
|
+ * - `ngtcp2_conn_open_uni_stream`
|
|
+ * - `ngtcp2_conn_set_stream_user_data`
|
|
+ *
|
|
+ * This function has been available since v1.17.0.
|
|
+ */
|
|
+NGTCP2_EXTERN void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn,
|
|
+ int64_t stream_id);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
@@ -5568,6 +6003,119 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn);
|
|
NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn,
|
|
int64_t stream_id);
|
|
|
|
+/**
|
|
+ * @functypedef
|
|
+ *
|
|
+ * :type:`ngtcp2_write_pkt` is a callback function to write a single
|
|
+ * packet in the buffer pointed by |dest| of length |destlen|. The
|
|
+ * implementation should use `ngtcp2_conn_write_pkt`,
|
|
+ * `ngtcp2_conn_writev_stream`, `ngtcp2_conn_writev_datagram`, or
|
|
+ * their variants to write the packet. |path|, |pi|, |dest|,
|
|
+ * |destlen|, and |ts| should be directly passed to those functions.
|
|
+ * If the callback succeeds, it should return the number of bytes
|
|
+ * written to the buffer. In general, this callback function should
|
|
+ * return the value that the above mentioned functions returned except
|
|
+ * for the following error codes:
|
|
+ *
|
|
+ * - :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`
|
|
+ * - :macro:`NGTCP2_ERR_STREAM_SHUT_WR`
|
|
+ * - :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`
|
|
+ *
|
|
+ * Those error codes should be handled by an application. If any
|
|
+ * error occurred outside those functions, return
|
|
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE`. If no packet is produced,
|
|
+ * return 0.
|
|
+ *
|
|
+ * Because GSO requires that the aggregated packets have the same
|
|
+ * length, :macro:`NGTCP2_WRITE_STREAM_FLAG_PADDING` (or
|
|
+ * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` if
|
|
+ * `ngtcp2_conn_writev_datagram` is used) is recommended.
|
|
+ *
|
|
+ * This callback function has been available since v1.15.0.
|
|
+ */
|
|
+typedef ngtcp2_ssize (*ngtcp2_write_pkt)(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
+ ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
+ size_t destlen, ngtcp2_tstamp ts,
|
|
+ void *user_data);
|
|
+
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_conn_write_aggregate_pkt` is a helper function to write
|
|
+ * multiple packets in the provided buffer, which is suitable to be
|
|
+ * sent at once in GSO. This function returns the number of bytes
|
|
+ * written to the buffer pointed by |buf| of length |buflen|.
|
|
+ * |buflen| must be at least
|
|
+ * `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn)
|
|
+ * <ngtcp2_conn_get_path_max_tx_udp_payload_size>` bytes long. It is
|
|
+ * recommended to pass the buffer at least
|
|
+ * `ngtcp2_conn_get_max_tx_udp_payload_size(conn)
|
|
+ * <ngtcp2_conn_get_max_tx_udp_payload_size>` bytes in order to send a
|
|
+ * PMTUD packet. This function only writes multiple packets if the
|
|
+ * first packet is `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn)
|
|
+ * <ngtcp2_conn_get_path_max_tx_udp_payload_size>` bytes long. The
|
|
+ * application can adjust the length of the buffer to limit the number
|
|
+ * of packets to aggregate (or use `ngtcp2_conn_write_aggregate_pkt2`
|
|
+ * to control the number of packets to write directly). If this
|
|
+ * function returns positive integer, all packets share the same
|
|
+ * :type:`ngtcp2_path` and :type:`ngtcp2_pkt_info` values, and they
|
|
+ * are assigned to the objects pointed by |path| and |pi|
|
|
+ * respectively. The length of all packets other than the last packet
|
|
+ * is assigned to |*pgsolen|. The length of last packet is equal to
|
|
+ * or less than |*pgsolen|. |write_pkt| must write a single packet.
|
|
+ * After all packets are written, this function calls
|
|
+ * `ngtcp2_conn_update_pkt_tx_time`.
|
|
+ *
|
|
+ * This function is equivalent to call
|
|
+ * `ngtcp2_conn_write_aggregate_pkt2` with |buflen| = min(|buflen|,
|
|
+ * `ngtcp2_conn_get_send_quantum(conn)
|
|
+ * <ngtcp2_conn_get_send_quantum>`) and |num_pkts| = 0 followed by
|
|
+ * `ngtcp2_conn_update_pkt_tx_time(conn)
|
|
+ * <ngtcp2_conn_update_pkt_tx_time>`.
|
|
+ *
|
|
+ * This function returns the number of bytes written to the buffer, or
|
|
+ * a negative error code returned by |write_pkt|.
|
|
+ *
|
|
+ * This function has been available since v1.15.0.
|
|
+ */
|
|
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned(
|
|
+ ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
|
|
+ ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
|
|
+ ngtcp2_write_pkt write_pkt, ngtcp2_tstamp ts);
|
|
+
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_conn_write_aggregate_pkt2` behaves like
|
|
+ * `ngtcp2_conn_write_aggregate_pkt`, but it accepts |num_pkts| to
|
|
+ * specify the maximum number of packets to write. If |num_pkts| is
|
|
+ * 0, this function writes packets as much as possible. The actual
|
|
+ * number of packets to write is determined by the connection state
|
|
+ * (e.g., the congestion controller, data available to send) and the
|
|
+ * length of packet produced. It also does not clamp |buflen|, and
|
|
+ * does not call `ngtcp2_conn_update_pkt_tx_time`.
|
|
+ *
|
|
+ * This function offers more flexibility and optimization chances to
|
|
+ * an application. It can experiment different GSO buffer size
|
|
+ * strategy and number of GSO writes per event loop.
|
|
+ *
|
|
+ * This function has been available since v1.17.0.
|
|
+ */
|
|
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned(
|
|
+ ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
|
|
+ ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
|
|
+ ngtcp2_write_pkt write_pkt, size_t num_pkts, ngtcp2_tstamp ts);
|
|
+
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_conn_get_timestamp` returns the latest timestamp that is
|
|
+ * known to |conn|.
|
|
+ *
|
|
+ * This function has been available since v1.16.0.
|
|
+ */
|
|
+NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn);
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
@@ -5650,15 +6198,19 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps);
|
|
* values. First this function fills |settings| with 0, and set the
|
|
* default value to the following fields:
|
|
*
|
|
- * * :type:`cc_algo <ngtcp2_settings.cc_algo>` =
|
|
+ * * :member:`cc_algo <ngtcp2_settings.cc_algo>` =
|
|
* :enum:`ngtcp2_cc_algo.NGTCP2_CC_ALGO_CUBIC`
|
|
- * * :type:`initial_rtt <ngtcp2_settings.initial_rtt>` =
|
|
+ * * :member:`initial_rtt <ngtcp2_settings.initial_rtt>` =
|
|
* :macro:`NGTCP2_DEFAULT_INITIAL_RTT`
|
|
- * * :type:`ack_thresh <ngtcp2_settings.ack_thresh>` = 2
|
|
- * * :type:`max_tx_udp_payload_size
|
|
+ * * :member:`ack_thresh <ngtcp2_settings.ack_thresh>` = 2
|
|
+ * * :member:`max_tx_udp_payload_size
|
|
* <ngtcp2_settings.max_tx_udp_payload_size>` = 1452
|
|
- * * :type:`handshake_timeout <ngtcp2_settings.handshake_timeout>` =
|
|
+ * * :member:`handshake_timeout <ngtcp2_settings.handshake_timeout>` =
|
|
* ``UINT64_MAX``
|
|
+ * * :member:`glitch_ratelim_burst
|
|
+ * <ngtcp2_settings.glitch_ratelim_burst>` = 10000
|
|
+ * * :member:`glitch_ratelim_rate
|
|
+ * <ngtcp2_settings.glitch_ratelim_rate>` = 330
|
|
*/
|
|
NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version,
|
|
ngtcp2_settings *settings);
|
|
@@ -5670,15 +6222,15 @@ NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version,
|
|
* default values. First this function fills |params| with 0, and set
|
|
* the default value to the following fields:
|
|
*
|
|
- * * :type:`max_udp_payload_size
|
|
+ * * :member:`max_udp_payload_size
|
|
* <ngtcp2_transport_params.max_udp_payload_size>` =
|
|
* :macro:`NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE`
|
|
- * * :type:`ack_delay_exponent
|
|
+ * * :member:`ack_delay_exponent
|
|
* <ngtcp2_transport_params.ack_delay_exponent>` =
|
|
* :macro:`NGTCP2_DEFAULT_ACK_DELAY_EXPONENT`
|
|
- * * :type:`max_ack_delay <ngtcp2_transport_params.max_ack_delay>` =
|
|
+ * * :member:`max_ack_delay <ngtcp2_transport_params.max_ack_delay>` =
|
|
* :macro:`NGTCP2_DEFAULT_MAX_ACK_DELAY`
|
|
- * * :type:`active_connection_id_limit
|
|
+ * * :member:`active_connection_id_limit
|
|
* <ngtcp2_transport_params.active_connection_id_limit>` =
|
|
* :macro:`NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT`
|
|
*/
|
|
@@ -5950,6 +6502,28 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions,
|
|
#define ngtcp2_conn_get_conn_info(CONN, CINFO) \
|
|
ngtcp2_conn_get_conn_info_versioned((CONN), NGTCP2_CONN_INFO_VERSION, (CINFO))
|
|
|
|
+/*
|
|
+ * `ngtcp2_conn_write_aggregate_pkt` is a wrapper around
|
|
+ * `ngtcp2_conn_write_aggregate_pkt_versioned` to set the correct
|
|
+ * struct version.
|
|
+ */
|
|
+#define ngtcp2_conn_write_aggregate_pkt(CONN, PATH, PI, BUF, BUFLEN, PGSOLEN, \
|
|
+ WRITE_PKT, TS) \
|
|
+ ngtcp2_conn_write_aggregate_pkt_versioned( \
|
|
+ (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (BUF), (BUFLEN), (PGSOLEN), \
|
|
+ (WRITE_PKT), (TS))
|
|
+
|
|
+/*
|
|
+ * `ngtcp2_conn_write_aggregate_pkt2` is a wrapper around
|
|
+ * `ngtcp2_conn_write_aggregate_pkt2_versioned` to set the correct
|
|
+ * struct version.
|
|
+ */
|
|
+#define ngtcp2_conn_write_aggregate_pkt2(CONN, PATH, PI, BUF, BUFLEN, PGSOLEN, \
|
|
+ WRITE_PKT, NUM_PKTS, TS) \
|
|
+ ngtcp2_conn_write_aggregate_pkt2_versioned( \
|
|
+ (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (BUF), (BUFLEN), (PGSOLEN), \
|
|
+ (WRITE_PKT), (NUM_PKTS), (TS))
|
|
+
|
|
/*
|
|
* `ngtcp2_settings_default` is a wrapper around
|
|
* `ngtcp2_settings_default_versioned` to set the correct struct
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_acktr.c b/third_party/ngtcp2/lib/ngtcp2_acktr.c
|
|
index 776dc0c2c3e..4a9ac5cf0aa 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_acktr.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_acktr.c
|
|
@@ -34,9 +34,11 @@ ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent)
|
|
|
|
static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num,
|
|
ngtcp2_tstamp tstamp) {
|
|
- ent->pkt_num = pkt_num;
|
|
- ent->len = 1;
|
|
- ent->tstamp = tstamp;
|
|
+ *ent = (ngtcp2_acktr_entry){
|
|
+ .pkt_num = pkt_num,
|
|
+ .len = 1,
|
|
+ .tstamp = tstamp,
|
|
+ };
|
|
}
|
|
|
|
int ngtcp2_acktr_entry_objalloc_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
|
|
@@ -219,8 +221,10 @@ ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
|
|
int64_t largest_ack) {
|
|
ngtcp2_acktr_ack_entry *ent = ngtcp2_ringbuf_push_front(&acktr->acks.rb);
|
|
|
|
- ent->largest_ack = largest_ack;
|
|
- ent->pkt_num = pkt_num;
|
|
+ *ent = (ngtcp2_acktr_ack_entry){
|
|
+ .largest_ack = largest_ack,
|
|
+ .pkt_num = pkt_num,
|
|
+ };
|
|
|
|
return ent;
|
|
}
|
|
@@ -316,9 +320,9 @@ void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) {
|
|
}
|
|
|
|
void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) {
|
|
- acktr->flags &= (uint16_t) ~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK |
|
|
- NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK |
|
|
- NGTCP2_ACKTR_FLAG_CANCEL_TIMER);
|
|
+ acktr->flags &=
|
|
+ (uint16_t)~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK | NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK |
|
|
+ NGTCP2_ACKTR_FLAG_CANCEL_TIMER);
|
|
acktr->first_unacked_ts = UINT64_MAX;
|
|
acktr->rx_npkt = 0;
|
|
}
|
|
@@ -333,16 +337,14 @@ void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) {
|
|
acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
|
|
}
|
|
|
|
-ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
|
- ngtcp2_frame *fr, uint8_t type,
|
|
- ngtcp2_tstamp ts,
|
|
- ngtcp2_duration ack_delay,
|
|
- uint64_t ack_delay_exponent) {
|
|
+int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack,
|
|
+ uint8_t type, ngtcp2_tstamp ts,
|
|
+ ngtcp2_duration ack_delay,
|
|
+ uint64_t ack_delay_exponent) {
|
|
int64_t last_pkt_num;
|
|
ngtcp2_ack_range *range;
|
|
ngtcp2_ksl_it it;
|
|
ngtcp2_acktr_entry *rpkt;
|
|
- ngtcp2_ack *ack = &fr->ack;
|
|
ngtcp2_tstamp largest_ack_ts;
|
|
size_t num_acks;
|
|
|
|
@@ -351,13 +353,13 @@ ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
|
}
|
|
|
|
if (!ngtcp2_acktr_require_active_ack(acktr, ack_delay, ts)) {
|
|
- return NULL;
|
|
+ return -1;
|
|
}
|
|
|
|
it = ngtcp2_acktr_get(acktr);
|
|
if (ngtcp2_ksl_it_end(&it)) {
|
|
ngtcp2_acktr_commit_ack(acktr);
|
|
- return NULL;
|
|
+ return -1;
|
|
}
|
|
|
|
num_acks = ngtcp2_ksl_len(&acktr->ents);
|
|
@@ -420,7 +422,7 @@ ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
|
last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
|
|
}
|
|
|
|
- return fr;
|
|
+ return 0;
|
|
}
|
|
|
|
void ngtcp2_acktr_increase_ecn_counts(ngtcp2_acktr *acktr,
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_acktr.h b/third_party/ngtcp2/lib/ngtcp2_acktr.h
|
|
index cf75a774db3..026c2cabe87 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_acktr.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_acktr.h
|
|
@@ -97,16 +97,16 @@ typedef struct ngtcp2_acktr_ack_entry {
|
|
} ngtcp2_acktr_ack_entry;
|
|
|
|
/* NGTCP2_ACKTR_FLAG_NONE indicates that no flag set. */
|
|
-#define NGTCP2_ACKTR_FLAG_NONE 0x00u
|
|
+#define NGTCP2_ACKTR_FLAG_NONE 0x00U
|
|
/* NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK indicates that immediate
|
|
acknowledgement is required. */
|
|
-#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01u
|
|
+#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01U
|
|
/* NGTCP2_ACKTR_FLAG_ACTIVE_ACK indicates that there are pending
|
|
protected packet to be acknowledged. */
|
|
-#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02u
|
|
+#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02U
|
|
/* NGTCP2_ACKTR_FLAG_CANCEL_TIMER is set when ACK delay timer is
|
|
expired and canceled. */
|
|
-#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100u
|
|
+#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100U
|
|
|
|
ngtcp2_static_ringbuf_def(acks, 32, sizeof(ngtcp2_acktr_ack_entry))
|
|
|
|
@@ -120,8 +120,6 @@ typedef struct ngtcp2_acktr {
|
|
packet number. */
|
|
ngtcp2_ksl ents;
|
|
ngtcp2_log *log;
|
|
- /* flags is bitwise OR of zero, or more of NGTCP2_ACKTR_FLAG_*. */
|
|
- uint16_t flags;
|
|
/* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added
|
|
first time after the last outgoing ACK frame. */
|
|
ngtcp2_tstamp first_unacked_ts;
|
|
@@ -148,6 +146,9 @@ typedef struct ngtcp2_acktr {
|
|
uint64_t ce;
|
|
} ack;
|
|
} ecn;
|
|
+
|
|
+ /* flags is bitwise OR of zero, or more of NGTCP2_ACKTR_FLAG_*. */
|
|
+ uint16_t flags;
|
|
} ngtcp2_acktr;
|
|
|
|
/*
|
|
@@ -235,19 +236,18 @@ void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr);
|
|
|
|
/*
|
|
* ngtcp2_acktr_create_ack_frame creates ACK frame in the object
|
|
- * pointed by |fr|, and returns |fr| if there are any received packets
|
|
- * to acknowledge. If there are no packets to acknowledge, this
|
|
- * function returns NULL. fr->ack.ranges must be able to contain at
|
|
+ * pointed by |ack|, and returns 0 if it successfully creates ACK
|
|
+ * frame in |ack|. If there are no packets to acknowledge, this
|
|
+ * function returns -1. |ack|->ranges must be able to contain at
|
|
* least NGTCP2_MAX_ACK_RANGES elements.
|
|
*
|
|
* Call ngtcp2_acktr_commit_ack after a created ACK frame is
|
|
* successfully serialized into a packet.
|
|
*/
|
|
-ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
|
- ngtcp2_frame *fr, uint8_t type,
|
|
- ngtcp2_tstamp ts,
|
|
- ngtcp2_duration ack_delay,
|
|
- uint64_t ack_delay_exponent);
|
|
+int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack,
|
|
+ uint8_t type, ngtcp2_tstamp ts,
|
|
+ ngtcp2_duration ack_delay,
|
|
+ uint64_t ack_delay_exponent);
|
|
|
|
/*
|
|
* ngtcp2_acktr_increase_ecn_counts increases ECN counts from |pi|.
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_addr.c b/third_party/ngtcp2/lib/ngtcp2_addr.c
|
|
index 1fb273d494e..58694e3836e 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_addr.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_addr.c
|
|
@@ -31,8 +31,11 @@
|
|
|
|
ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
|
|
ngtcp2_socklen addrlen) {
|
|
- dest->addrlen = addrlen;
|
|
- dest->addr = (ngtcp2_sockaddr *)addr;
|
|
+ *dest = (ngtcp2_addr){
|
|
+ .addr = (ngtcp2_sockaddr *)addr,
|
|
+ .addrlen = addrlen,
|
|
+ };
|
|
+
|
|
return dest;
|
|
}
|
|
|
|
@@ -58,14 +61,12 @@ int ngtcp2_sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) {
|
|
|
|
switch (a->sa_family) {
|
|
case NGTCP2_AF_INET: {
|
|
- const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
|
|
- *bi = (const ngtcp2_sockaddr_in *)(void *)b;
|
|
+ const ngtcp2_sockaddr_in *ai = (void *)a, *bi = (void *)b;
|
|
return ai->sin_port == bi->sin_port &&
|
|
memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr)) == 0;
|
|
}
|
|
case NGTCP2_AF_INET6: {
|
|
- const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
|
|
- *bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
|
|
+ const ngtcp2_sockaddr_in6 *ai = (void *)a, *bi = (void *)b;
|
|
return ai->sin6_port == bi->sin6_port &&
|
|
memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0;
|
|
}
|
|
@@ -89,8 +90,7 @@ uint32_t ngtcp2_addr_cmp(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
|
|
|
|
switch (a->sa_family) {
|
|
case NGTCP2_AF_INET: {
|
|
- const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
|
|
- *bi = (const ngtcp2_sockaddr_in *)(void *)b;
|
|
+ const ngtcp2_sockaddr_in *ai = (void *)a, *bi = (void *)b;
|
|
if (memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr))) {
|
|
flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
|
|
}
|
|
@@ -100,8 +100,7 @@ uint32_t ngtcp2_addr_cmp(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
|
|
return flags;
|
|
}
|
|
case NGTCP2_AF_INET6: {
|
|
- const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
|
|
- *bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
|
|
+ const ngtcp2_sockaddr_in6 *ai = (void *)a, *bi = (void *)b;
|
|
if (memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr))) {
|
|
flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_addr.h b/third_party/ngtcp2/lib/ngtcp2_addr.h
|
|
index c2224f85cd9..6314b1afc81 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_addr.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_addr.h
|
|
@@ -46,14 +46,14 @@ void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src);
|
|
int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b);
|
|
|
|
/* NGTCP2_ADDR_CMP_FLAG_NONE indicates that no flag set. */
|
|
-#define NGTCP2_ADDR_CMP_FLAG_NONE 0x0u
|
|
+#define NGTCP2_ADDR_CMP_FLAG_NONE 0x0U
|
|
/* NGTCP2_ADDR_CMP_FLAG_ADDR indicates IP addresses do not match. */
|
|
-#define NGTCP2_ADDR_CMP_FLAG_ADDR 0x1u
|
|
+#define NGTCP2_ADDR_CMP_FLAG_ADDR 0x1U
|
|
/* NGTCP2_ADDR_CMP_FLAG_PORT indicates ports do not match. */
|
|
-#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2u
|
|
+#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2U
|
|
/* NGTCP2_ADDR_CMP_FLAG_FAMILY indicates address families do not
|
|
match. */
|
|
-#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4u
|
|
+#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4U
|
|
|
|
/*
|
|
* ngtcp2_addr_cmp compares address and port between |a| and |b|, and
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_balloc.c b/third_party/ngtcp2/lib/ngtcp2_balloc.c
|
|
index 4a6797689fc..fff7a9ef65b 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_balloc.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_balloc.c
|
|
@@ -30,7 +30,7 @@
|
|
|
|
void ngtcp2_balloc_init(ngtcp2_balloc *balloc, size_t blklen,
|
|
const ngtcp2_mem *mem) {
|
|
- assert((blklen & 0xfu) == 0);
|
|
+ assert((blklen & 0xFU) == 0);
|
|
|
|
balloc->mem = mem;
|
|
balloc->blklen = blklen;
|
|
@@ -66,25 +66,25 @@ int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n) {
|
|
|
|
if (ngtcp2_buf_left(&balloc->buf) < n) {
|
|
p = ngtcp2_mem_malloc(balloc->mem,
|
|
- sizeof(ngtcp2_memblock_hd) + 0x8u + balloc->blklen);
|
|
+ sizeof(ngtcp2_memblock_hd) + 0x8U + balloc->blklen);
|
|
if (p == NULL) {
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- hd = (ngtcp2_memblock_hd *)(void *)p;
|
|
+ hd = (void *)p;
|
|
hd->next = balloc->head;
|
|
balloc->head = hd;
|
|
ngtcp2_buf_init(
|
|
&balloc->buf,
|
|
- (uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xfu) &
|
|
- ~(uintptr_t)0xfu),
|
|
+ (uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xFU) &
|
|
+ ~(uintptr_t)0xFU),
|
|
balloc->blklen);
|
|
}
|
|
|
|
- assert(((uintptr_t)balloc->buf.last & 0xfu) == 0);
|
|
+ assert(((uintptr_t)balloc->buf.last & 0xFU) == 0);
|
|
|
|
*pbuf = balloc->buf.last;
|
|
- balloc->buf.last += (n + 0xfu) & ~(uintptr_t)0xfu;
|
|
+ balloc->buf.last += (n + 0xFU) & ~(uintptr_t)0xFU;
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_bbr.c b/third_party/ngtcp2/lib/ngtcp2_bbr.c
|
|
index 04612f11be4..3db6a9f2bff 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_bbr.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_bbr.c
|
|
@@ -33,6 +33,7 @@
|
|
#include "ngtcp2_rcvry.h"
|
|
#include "ngtcp2_rst.h"
|
|
#include "ngtcp2_conn_stat.h"
|
|
+#include "ngtcp2_pcg.h"
|
|
|
|
#define NGTCP2_BBR_MAX_BW_FILTERLEN 2
|
|
|
|
@@ -69,19 +70,21 @@ static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
|
|
static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr);
|
|
+static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr);
|
|
|
|
static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr);
|
|
|
|
static void bbr_reset_full_bw(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_init_pacing_rate(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat);
|
|
|
|
-static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
|
|
+static void bbr_set_pacing_rate_with_gain(const ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat,
|
|
uint64_t pacing_gain_h);
|
|
|
|
-static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_set_pacing_rate(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_enter_startup(ngtcp2_cc_bbr *bbr);
|
|
|
|
@@ -99,47 +102,47 @@ static void bbr_update_control_parameters(ngtcp2_cc_bbr *cc,
|
|
ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack);
|
|
|
|
-static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat,
|
|
- const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
|
|
-
|
|
static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack);
|
|
|
|
-static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+static void
|
|
+bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
-static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr);
|
|
|
|
static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack);
|
|
|
|
static void bbr_update_round(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack);
|
|
|
|
static void bbr_start_round(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr);
|
|
+static int bbr_is_in_probe_bw_state(const ngtcp2_cc_bbr *bbr);
|
|
|
|
-static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr);
|
|
+static int bbr_is_probing_bw(const ngtcp2_cc_bbr *bbr);
|
|
|
|
static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts);
|
|
|
|
static void bbr_enter_drain(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts);
|
|
|
|
static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts);
|
|
@@ -150,59 +153,70 @@ static void bbr_start_probe_bw_cruise(ngtcp2_cc_bbr *bbr);
|
|
|
|
static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts);
|
|
|
|
-static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_tstamp ts);
|
|
+static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
-static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
-static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
|
|
+static int bbr_has_elapsed_in_phase(const ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_duration interval, ngtcp2_tstamp ts);
|
|
|
|
-static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+static uint64_t bbr_inflight_with_headroom(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack);
|
|
|
|
-static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
- const ngtcp2_cc_ack *ack);
|
|
+static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_cc_ack *ack);
|
|
|
|
-static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts);
|
|
|
|
static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+static int bbr_is_reno_coexistence_probe_time(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
-static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+static uint64_t bbr_target_inflight(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
-static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr);
|
|
+static int bbr_is_inflight_too_high(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_rs *rs);
|
|
|
|
static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_tstamp ts);
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_rs *rs, ngtcp2_tstamp ts);
|
|
|
|
static void bbr_note_loss(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static void bbr_save_state_upon_loss(ngtcp2_cc_bbr *bbr);
|
|
+
|
|
+static void bbr_handle_spurious_loss_detection(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
+
|
|
+static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
|
|
|
|
-static uint64_t
|
|
-bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
|
|
- const ngtcp2_cc_pkt *pkt);
|
|
+static uint64_t bbr_inflight_at_loss(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_cc_pkt *pkt,
|
|
+ const ngtcp2_rs *rs);
|
|
|
|
static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts);
|
|
@@ -219,7 +233,7 @@ static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts);
|
|
|
|
static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts);
|
|
|
|
@@ -230,27 +244,28 @@ static void bbr_handle_restart_from_idle(ngtcp2_cc_bbr *bbr,
|
|
static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t gain_h);
|
|
|
|
static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
uint64_t inflight);
|
|
|
|
-static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
|
|
uint64_t gain_h);
|
|
|
|
static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat);
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static uint64_t min_pipe_cwnd(size_t max_udp_payload_size);
|
|
|
|
static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr);
|
|
|
|
-static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat);
|
|
|
|
-static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_restore_cwnd(const ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
|
|
-static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
|
|
static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat);
|
|
@@ -258,10 +273,11 @@ static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
|
|
static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack);
|
|
|
|
-static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr,
|
|
+static void bbr_bound_cwnd_for_model(const ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat);
|
|
|
|
-static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
|
|
+static void bbr_set_send_quantum(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat);
|
|
|
|
static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp sent_time);
|
|
@@ -288,7 +304,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
bbr->full_bw_reached = 0;
|
|
|
|
bbr_reset_congestion_signals(bbr);
|
|
- bbr_reset_lower_bounds(bbr);
|
|
+ bbr_reset_shortterm_model(bbr);
|
|
bbr_init_round_counting(bbr);
|
|
bbr_reset_full_bw(bbr);
|
|
bbr_init_pacing_rate(bbr, cstat);
|
|
@@ -333,9 +349,12 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
|
|
bbr->max_inflight = 0;
|
|
|
|
- bbr->congestion_recovery_start_ts = UINT64_MAX;
|
|
-
|
|
bbr->bdp = 0;
|
|
+
|
|
+ bbr->undo_state = 0;
|
|
+ bbr->undo_bw_shortterm = 0;
|
|
+ bbr->undo_inflight_shortterm = 0;
|
|
+ bbr->undo_inflight_longterm = 0;
|
|
}
|
|
|
|
static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
|
|
@@ -344,7 +363,7 @@ static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
|
|
bbr->inflight_latest = 0;
|
|
}
|
|
|
|
-static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) {
|
|
+static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr) {
|
|
bbr->bw_shortterm = UINT64_MAX;
|
|
bbr->inflight_shortterm = UINT64_MAX;
|
|
}
|
|
@@ -362,7 +381,7 @@ static void bbr_reset_full_bw(ngtcp2_cc_bbr *bbr) {
|
|
}
|
|
|
|
static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
if (bbr->full_bw_now || !bbr->round_start || bbr->rst->rs.is_app_limited) {
|
|
return;
|
|
}
|
|
@@ -383,15 +402,16 @@ static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr,
|
|
|
|
bbr->full_bw_reached = 1;
|
|
|
|
- ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "bbr reached full bandwidth, full_bw=%" PRIu64, bbr->full_bw);
|
|
+ ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "bbr reached full bandwidth, full_bw=%" PRIu64,
|
|
+ bbr->full_bw);
|
|
}
|
|
|
|
static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
|
|
if (bbr->full_bw_reached || bbr->loss_events_in_round <= 6 ||
|
|
(bbr->in_loss_recovery &&
|
|
bbr->round_count <= bbr->round_count_at_recovery) ||
|
|
- !bbr_is_inflight_too_high(bbr)) {
|
|
+ !bbr_is_inflight_too_high(bbr, &bbr->rst->rs)) {
|
|
return;
|
|
}
|
|
|
|
@@ -400,15 +420,17 @@ static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
|
|
bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), bbr->inflight_latest);
|
|
}
|
|
|
|
-static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
- cstat->pacing_interval_m =
|
|
+static void bbr_init_pacing_rate(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat) {
|
|
+ cstat->pacing_interval_m = ngtcp2_max_uint64(
|
|
((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
|
|
: cstat->smoothed_rtt)
|
|
<< 10) *
|
|
- 100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd;
|
|
+ 100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd,
|
|
+ 1);
|
|
}
|
|
|
|
-static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
|
|
+static void bbr_set_pacing_rate_with_gain(const ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat,
|
|
uint64_t pacing_gain_h) {
|
|
uint64_t interval_m;
|
|
@@ -426,7 +448,8 @@ static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
}
|
|
|
|
-static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static void bbr_set_pacing_rate(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat) {
|
|
bbr_set_pacing_rate_with_gain(bbr, cstat, bbr->pacing_gain_h);
|
|
}
|
|
|
|
@@ -482,13 +505,8 @@ static void bbr_update_control_parameters(ngtcp2_cc_bbr *bbr,
|
|
bbr_set_cwnd(bbr, cstat, ack);
|
|
}
|
|
|
|
-static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat,
|
|
- const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
|
|
- bbr_handle_lost_packet(cc, cstat, pkt, ts);
|
|
-}
|
|
-
|
|
static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
bbr->loss_round_start = 0;
|
|
bbr->bw_latest = ngtcp2_max_uint64(bbr->bw_latest, cstat->delivery_rate_sec);
|
|
bbr->inflight_latest =
|
|
@@ -501,7 +519,7 @@ static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
|
|
static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
if (bbr->loss_round_start) {
|
|
bbr->bw_latest = cstat->delivery_rate_sec;
|
|
bbr->inflight_latest = bbr->rst->rs.delivered;
|
|
@@ -509,7 +527,7 @@ static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
|
|
static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack) {
|
|
bbr_update_max_bw(bbr, cstat, ack);
|
|
|
|
@@ -527,8 +545,9 @@ static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr,
|
|
bbr->loss_in_round = 0;
|
|
}
|
|
|
|
-static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+static void
|
|
+bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
if (bbr_is_probing_bw(bbr)) {
|
|
return;
|
|
}
|
|
@@ -539,7 +558,8 @@ static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
}
|
|
|
|
-static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
if (bbr->bw_shortterm == UINT64_MAX) {
|
|
bbr->bw_shortterm = bbr->max_bw;
|
|
}
|
|
@@ -562,11 +582,12 @@ static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr) {
|
|
bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_shortterm);
|
|
}
|
|
|
|
-static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack) {
|
|
bbr_update_round(bbr, ack);
|
|
|
|
- if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) {
|
|
+ if (cstat->delivery_rate_sec && (cstat->delivery_rate_sec >= bbr->max_bw ||
|
|
+ !bbr->rst->rs.is_app_limited)) {
|
|
ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec,
|
|
bbr->cycle_count);
|
|
|
|
@@ -597,7 +618,7 @@ static void bbr_start_round(ngtcp2_cc_bbr *bbr) {
|
|
bbr->next_round_delivered = bbr->rst->delivered;
|
|
}
|
|
|
|
-static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr) {
|
|
+static int bbr_is_in_probe_bw_state(const ngtcp2_cc_bbr *bbr) {
|
|
switch (bbr->state) {
|
|
case NGTCP2_BBR_STATE_PROBE_BW_DOWN:
|
|
case NGTCP2_BBR_STATE_PROBE_BW_CRUISE:
|
|
@@ -609,7 +630,7 @@ static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr) {
|
|
}
|
|
}
|
|
|
|
-static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr) {
|
|
+static int bbr_is_probing_bw(const ngtcp2_cc_bbr *bbr) {
|
|
switch (bbr->state) {
|
|
case NGTCP2_BBR_STATE_STARTUP:
|
|
case NGTCP2_BBR_STATE_PROBE_BW_REFILL:
|
|
@@ -621,7 +642,7 @@ static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr) {
|
|
}
|
|
|
|
static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_duration interval = ts - bbr->extra_acked_interval_start;
|
|
@@ -663,7 +684,8 @@ static void bbr_enter_drain(ngtcp2_cc_bbr *bbr) {
|
|
bbr->cwnd_gain_h = NGTCP2_BBR_DEFAULT_CWND_GAIN_H;
|
|
}
|
|
|
|
-static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts) {
|
|
if (bbr->state == NGTCP2_BBR_STATE_DRAIN &&
|
|
cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
|
|
@@ -707,7 +729,7 @@ static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr) {
|
|
ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
"bbr start ProbeBW_REFILL");
|
|
|
|
- bbr_reset_lower_bounds(bbr);
|
|
+ bbr_reset_shortterm_model(bbr);
|
|
|
|
bbr->bw_probe_up_rounds = 0;
|
|
bbr->bw_probe_up_acks = 0;
|
|
@@ -720,7 +742,8 @@ static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr) {
|
|
bbr->cwnd_gain_h = NGTCP2_BBR_DEFAULT_CWND_GAIN_H;
|
|
}
|
|
|
|
-static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr start ProbeBW_UP");
|
|
|
|
bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING;
|
|
@@ -737,14 +760,14 @@ static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
}
|
|
|
|
static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts) {
|
|
if (!bbr->full_bw_reached) {
|
|
return;
|
|
}
|
|
|
|
- bbr_adapt_upper_bounds(bbr, cstat, ack);
|
|
+ bbr_adapt_longterm_model(bbr, cstat, ack);
|
|
|
|
if (!bbr_is_in_probe_bw_state(bbr)) {
|
|
return;
|
|
@@ -756,7 +779,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
|
|
return;
|
|
}
|
|
|
|
- if (bbr_is_time_to_cruise(bbr, cstat, ts)) {
|
|
+ if (bbr_is_time_to_cruise(bbr, cstat)) {
|
|
bbr_start_probe_bw_cruise(bbr);
|
|
}
|
|
|
|
@@ -785,40 +808,34 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
}
|
|
|
|
-static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_tstamp ts) {
|
|
- (void)ts;
|
|
-
|
|
- if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
|
|
- return 1;
|
|
- }
|
|
+static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
+ uint64_t inflight = ngtcp2_min_uint64(bbr_inflight_with_headroom(bbr, cstat),
|
|
+ bbr_inflight(bbr, cstat, 100));
|
|
|
|
- return 0;
|
|
+ return cstat->bytes_in_flight <= inflight;
|
|
}
|
|
|
|
-static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_longterm) {
|
|
bbr_reset_full_bw(bbr);
|
|
bbr->full_bw = cstat->delivery_rate_sec;
|
|
- } else if (bbr->full_bw_now) {
|
|
- return 1;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
- return 0;
|
|
+ return bbr->full_bw_now;
|
|
}
|
|
|
|
-static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
|
|
+static int bbr_has_elapsed_in_phase(const ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_duration interval,
|
|
ngtcp2_tstamp ts) {
|
|
return ts > bbr->cycle_stamp + interval;
|
|
}
|
|
|
|
-static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+static uint64_t bbr_inflight_with_headroom(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
uint64_t headroom;
|
|
uint64_t mpcwnd;
|
|
if (bbr->inflight_longterm == UINT64_MAX) {
|
|
@@ -839,7 +856,7 @@ static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
|
|
static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
uint64_t growth_this_round = cstat->max_tx_udp_payload_size
|
|
<< bbr->bw_probe_up_rounds;
|
|
|
|
@@ -848,7 +865,7 @@ static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
|
|
static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack) {
|
|
uint64_t delta;
|
|
|
|
@@ -871,8 +888,9 @@ static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
}
|
|
|
|
-static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
- const ngtcp2_cc_ack *ack) {
|
|
+static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_cc_ack *ack) {
|
|
if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING &&
|
|
bbr->round_start) {
|
|
bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK;
|
|
@@ -885,7 +903,7 @@ static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
}
|
|
}
|
|
|
|
- if (!bbr_is_inflight_too_high(bbr)) {
|
|
+ if (!bbr_is_inflight_too_high(bbr, &bbr->rst->rs)) {
|
|
if (bbr->inflight_longterm == UINT64_MAX) {
|
|
return;
|
|
}
|
|
@@ -900,7 +918,8 @@ static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
}
|
|
}
|
|
|
|
-static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts) {
|
|
if (bbr_has_elapsed_in_phase(bbr, bbr->bw_probe_wait, ts) ||
|
|
bbr_is_reno_coexistence_probe_time(bbr, cstat)) {
|
|
@@ -913,41 +932,35 @@ static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
}
|
|
|
|
static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) {
|
|
- uint8_t rand;
|
|
-
|
|
- bbr->rand(&rand, 1, &bbr->rand_ctx);
|
|
-
|
|
- bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256);
|
|
-
|
|
- bbr->rand(&rand, 1, &bbr->rand_ctx);
|
|
-
|
|
- bbr->bw_probe_wait = 2 * NGTCP2_SECONDS + NGTCP2_SECONDS * rand / 255;
|
|
+ bbr->rounds_since_bw_probe = ngtcp2_pcg32_rand_n(bbr->pcg, 2);
|
|
+ bbr->bw_probe_wait =
|
|
+ 2 * NGTCP2_SECONDS + ngtcp2_pcg32_rand_n(bbr->pcg, NGTCP2_SECONDS + 1);
|
|
}
|
|
|
|
-static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+static int bbr_is_reno_coexistence_probe_time(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
uint64_t reno_rounds =
|
|
bbr_target_inflight(bbr, cstat) / cstat->max_tx_udp_payload_size;
|
|
|
|
return bbr->rounds_since_bw_probe >= ngtcp2_min_uint64(reno_rounds, 63);
|
|
}
|
|
|
|
-static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+static uint64_t bbr_target_inflight(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd);
|
|
}
|
|
|
|
-static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr) {
|
|
- const ngtcp2_rs *rs = &bbr->rst->rs;
|
|
+static int bbr_is_inflight_too_high(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_rs *rs) {
|
|
+ (void)bbr;
|
|
return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM >
|
|
rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER;
|
|
}
|
|
|
|
static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_rs *rs,
|
|
ngtcp2_tstamp ts) {
|
|
- const ngtcp2_rs *rs = &bbr->rst->rs;
|
|
-
|
|
bbr->bw_probe_samples = 0;
|
|
|
|
if (!rs->is_app_limited) {
|
|
@@ -964,14 +977,51 @@ static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
|
|
static void bbr_note_loss(ngtcp2_cc_bbr *bbr) {
|
|
if (!bbr->loss_in_round) {
|
|
bbr->loss_round_delivered = bbr->rst->delivered;
|
|
+ bbr_save_state_upon_loss(bbr);
|
|
}
|
|
|
|
bbr->loss_in_round = 1;
|
|
}
|
|
|
|
-static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static void bbr_save_state_upon_loss(ngtcp2_cc_bbr *bbr) {
|
|
+ bbr->undo_state = bbr->state;
|
|
+ bbr->undo_bw_shortterm = bbr->bw_shortterm;
|
|
+ bbr->undo_inflight_shortterm = bbr->inflight_shortterm;
|
|
+ bbr->undo_inflight_longterm = bbr->inflight_longterm;
|
|
+}
|
|
+
|
|
+static void bbr_handle_spurious_loss_detection(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
+ bbr->loss_in_round = 0;
|
|
+
|
|
+ bbr_reset_full_bw(bbr);
|
|
+
|
|
+ bbr->bw_shortterm =
|
|
+ ngtcp2_max_uint64(bbr->bw_shortterm, bbr->undo_bw_shortterm);
|
|
+ bbr->inflight_shortterm =
|
|
+ ngtcp2_max_uint64(bbr->inflight_shortterm, bbr->undo_inflight_shortterm);
|
|
+ bbr->inflight_longterm =
|
|
+ ngtcp2_max_uint64(bbr->inflight_longterm, bbr->undo_inflight_longterm);
|
|
+
|
|
+ if (bbr->state != NGTCP2_BBR_STATE_PROBE_RTT &&
|
|
+ bbr->state != bbr->undo_state) {
|
|
+ switch (bbr->undo_state) {
|
|
+ case NGTCP2_BBR_STATE_STARTUP:
|
|
+ bbr_enter_startup(bbr);
|
|
+ break;
|
|
+ case NGTCP2_BBR_STATE_PROBE_BW_UP:
|
|
+ bbr_start_probe_bw_up(bbr, cstat);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
|
|
- ngtcp2_rs *rs = &bbr->rst->rs;
|
|
+ ngtcp2_rs rs = {0};
|
|
|
|
bbr_note_loss(bbr);
|
|
|
|
@@ -979,23 +1029,21 @@ static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
return;
|
|
}
|
|
|
|
- rs->tx_in_flight = pkt->tx_in_flight;
|
|
- /* bbr->rst->lost is not incremented for pkt yet */
|
|
- assert(bbr->rst->lost + pkt->pktlen >= pkt->lost);
|
|
- rs->lost = bbr->rst->lost + pkt->pktlen - pkt->lost;
|
|
- rs->is_app_limited = pkt->is_app_limited;
|
|
+ rs.tx_in_flight = pkt->tx_in_flight;
|
|
+ assert(bbr->rst->lost >= pkt->lost);
|
|
+ rs.lost = bbr->rst->lost - pkt->lost;
|
|
+ rs.is_app_limited = pkt->is_app_limited;
|
|
|
|
- if (bbr_is_inflight_too_high(bbr)) {
|
|
- rs->tx_in_flight = bbr_inflight_longterm_from_lost_packet(bbr, pkt);
|
|
+ if (bbr_is_inflight_too_high(bbr, &rs)) {
|
|
+ rs.tx_in_flight = bbr_inflight_at_loss(bbr, pkt, &rs);
|
|
|
|
- bbr_handle_inflight_too_high(bbr, cstat, ts);
|
|
+ bbr_handle_inflight_too_high(bbr, cstat, &rs, ts);
|
|
}
|
|
}
|
|
|
|
-static uint64_t
|
|
-bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
|
|
- const ngtcp2_cc_pkt *pkt) {
|
|
- ngtcp2_rs *rs = &bbr->rst->rs;
|
|
+static uint64_t bbr_inflight_at_loss(const ngtcp2_cc_bbr *bbr,
|
|
+ const ngtcp2_cc_pkt *pkt,
|
|
+ const ngtcp2_rs *rs) {
|
|
uint64_t inflight_prev, lost_prev, lost_prefix;
|
|
(void)bbr;
|
|
|
|
@@ -1038,8 +1086,8 @@ static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack,
|
|
bbr->min_rtt = bbr->probe_rtt_min_delay;
|
|
bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp;
|
|
|
|
- ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "bbr update min_rtt=%" PRIu64, bbr->min_rtt);
|
|
+ ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "bbr update min_rtt=%" PRIu64, bbr->min_rtt);
|
|
}
|
|
}
|
|
|
|
@@ -1110,18 +1158,13 @@ static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
|
|
static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
- uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight;
|
|
-
|
|
- if (app_limited) {
|
|
- bbr->rst->app_limited = app_limited;
|
|
- } else {
|
|
- bbr->rst->app_limited = cstat->max_tx_udp_payload_size;
|
|
- }
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
+ bbr->rst->app_limited =
|
|
+ ngtcp2_max_uint64(bbr->rst->delivered + cstat->bytes_in_flight, 1);
|
|
}
|
|
|
|
static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) {
|
|
- bbr_reset_lower_bounds(bbr);
|
|
+ bbr_reset_shortterm_model(bbr);
|
|
|
|
if (bbr->full_bw_reached) {
|
|
bbr_start_probe_bw_down(bbr, ts);
|
|
@@ -1163,7 +1206,7 @@ static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) {
|
|
}
|
|
|
|
static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
uint64_t inflight) {
|
|
bbr_update_offload_budget(bbr, cstat);
|
|
|
|
@@ -1178,7 +1221,7 @@ static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr,
|
|
return inflight;
|
|
}
|
|
|
|
-static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
+static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
|
|
uint64_t gain_h) {
|
|
uint64_t inflight = bbr_bdp_multiple(bbr, gain_h);
|
|
|
|
@@ -1186,7 +1229,7 @@ static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
}
|
|
|
|
static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
uint64_t inflight;
|
|
|
|
inflight = bbr_bdp_multiple(bbr, bbr->cwnd_gain_h) + bbr->extra_acked;
|
|
@@ -1194,7 +1237,7 @@ static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr,
|
|
}
|
|
|
|
static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
bbr->offload_budget = 3 * cstat->send_quantum;
|
|
}
|
|
|
|
@@ -1202,7 +1245,7 @@ static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr) {
|
|
++bbr->cycle_count;
|
|
}
|
|
|
|
-static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) {
|
|
if (!bbr->in_loss_recovery && bbr->state != NGTCP2_BBR_STATE_PROBE_RTT) {
|
|
bbr->prior_cwnd = cstat->cwnd;
|
|
return;
|
|
@@ -1211,12 +1254,13 @@ static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
bbr->prior_cwnd = ngtcp2_max_uint64(bbr->prior_cwnd, cstat->cwnd);
|
|
}
|
|
|
|
-static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static void bbr_restore_cwnd(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat) {
|
|
cstat->cwnd = ngtcp2_max_uint64(cstat->cwnd, bbr->prior_cwnd);
|
|
}
|
|
|
|
static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
|
|
- ngtcp2_conn_stat *cstat) {
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
uint64_t probe_rtt_cwnd =
|
|
bbr_bdp_multiple(bbr, NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H);
|
|
uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size);
|
|
@@ -1226,12 +1270,9 @@ static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
|
|
|
|
static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat) {
|
|
- uint64_t probe_rtt_cwnd;
|
|
-
|
|
if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) {
|
|
- probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat);
|
|
-
|
|
- cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, probe_rtt_cwnd);
|
|
+ cstat->cwnd =
|
|
+ ngtcp2_min_uint64(cstat->cwnd, bbr_probe_rtt_cwnd(bbr, cstat));
|
|
}
|
|
}
|
|
|
|
@@ -1256,7 +1297,7 @@ static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
bbr_bound_cwnd_for_model(bbr, cstat);
|
|
}
|
|
|
|
-static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr,
|
|
+static void bbr_bound_cwnd_for_model(const ngtcp2_cc_bbr *bbr,
|
|
ngtcp2_conn_stat *cstat) {
|
|
uint64_t cap = UINT64_MAX;
|
|
uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size);
|
|
@@ -1275,7 +1316,8 @@ static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr,
|
|
cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, cap);
|
|
}
|
|
|
|
-static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
|
+static void bbr_set_send_quantum(const ngtcp2_cc_bbr *bbr,
|
|
+ ngtcp2_conn_stat *cstat) {
|
|
size_t send_quantum = 64 * 1024;
|
|
(void)bbr;
|
|
|
|
@@ -1295,28 +1337,15 @@ static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
|
|
|
|
static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack) {
|
|
- if (bbr->in_loss_recovery) {
|
|
- if (ack->largest_pkt_sent_ts != UINT64_MAX &&
|
|
- !in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
|
- bbr->in_loss_recovery = 0;
|
|
- bbr->round_count_at_recovery = UINT64_MAX;
|
|
- bbr_restore_cwnd(bbr, cstat);
|
|
- }
|
|
-
|
|
+ if (!bbr->in_loss_recovery) {
|
|
return;
|
|
}
|
|
|
|
- if (bbr->congestion_recovery_start_ts != UINT64_MAX) {
|
|
- bbr->in_loss_recovery = 1;
|
|
- bbr->round_count_at_recovery =
|
|
- bbr->round_start ? bbr->round_count : bbr->round_count + 1;
|
|
- bbr_save_cwnd(bbr, cstat);
|
|
- cstat->cwnd =
|
|
- cstat->bytes_in_flight +
|
|
- ngtcp2_max_uint64(ack->bytes_delivered, cstat->max_tx_udp_payload_size);
|
|
-
|
|
- cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts;
|
|
- bbr->congestion_recovery_start_ts = UINT64_MAX;
|
|
+ if (ack->largest_pkt_sent_ts != UINT64_MAX &&
|
|
+ !in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
|
+ bbr->in_loss_recovery = 0;
|
|
+ bbr->round_count_at_recovery = UINT64_MAX;
|
|
+ bbr_restore_cwnd(bbr, cstat);
|
|
}
|
|
}
|
|
|
|
@@ -1324,22 +1353,26 @@ static void bbr_cc_on_pkt_lost(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
|
|
|
- bbr_update_on_loss(bbr, cstat, pkt, ts);
|
|
+ bbr_handle_lost_packet(bbr, cstat, pkt, ts);
|
|
}
|
|
|
|
static void bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_tstamp sent_ts, uint64_t bytes_lost,
|
|
+ ngtcp2_tstamp sent_ts,
|
|
+ const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
|
- (void)bytes_lost;
|
|
+ (void)ack;
|
|
|
|
- if (bbr->in_loss_recovery ||
|
|
- bbr->congestion_recovery_start_ts != UINT64_MAX ||
|
|
- in_congestion_recovery(cstat, sent_ts)) {
|
|
+ if (bbr->in_loss_recovery || in_congestion_recovery(cstat, sent_ts)) {
|
|
return;
|
|
}
|
|
|
|
- bbr->congestion_recovery_start_ts = ts;
|
|
+ bbr->in_loss_recovery = 1;
|
|
+ bbr->round_count_at_recovery =
|
|
+ bbr->round_start ? bbr->round_count : bbr->round_count + 1;
|
|
+ bbr_save_cwnd(bbr, cstat);
|
|
+
|
|
+ cstat->congestion_recovery_start_ts = ts;
|
|
}
|
|
|
|
static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
|
@@ -1348,14 +1381,13 @@ static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
|
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
|
(void)ts;
|
|
|
|
- bbr->congestion_recovery_start_ts = UINT64_MAX;
|
|
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
|
|
|
- if (bbr->in_loss_recovery) {
|
|
- bbr->in_loss_recovery = 0;
|
|
- bbr->round_count_at_recovery = UINT64_MAX;
|
|
- bbr_restore_cwnd(bbr, cstat);
|
|
- }
|
|
+ bbr->in_loss_recovery = 0;
|
|
+ bbr->round_count_at_recovery = UINT64_MAX;
|
|
+
|
|
+ bbr_restore_cwnd(bbr, cstat);
|
|
+ bbr_handle_spurious_loss_detection(bbr, cstat);
|
|
}
|
|
|
|
static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
|
@@ -1365,7 +1397,6 @@ static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
|
(void)ts;
|
|
|
|
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
|
- bbr->congestion_recovery_start_ts = UINT64_MAX;
|
|
bbr->in_loss_recovery = 0;
|
|
bbr->round_count_at_recovery = UINT64_MAX;
|
|
|
|
@@ -1380,6 +1411,11 @@ static void bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
|
|
|
bbr_handle_recovery(bbr, cstat, ack);
|
|
+
|
|
+ if (ack->bytes_delivered == 0) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
bbr_update_on_ack(bbr, cstat, ack, ts);
|
|
}
|
|
|
|
@@ -1399,23 +1435,23 @@ static void bbr_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
|
|
void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,
|
|
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
|
|
- ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
|
|
- const ngtcp2_rand_ctx *rand_ctx) {
|
|
- memset(bbr, 0, sizeof(*bbr));
|
|
-
|
|
- bbr->cc.log = log;
|
|
- bbr->cc.on_pkt_lost = bbr_cc_on_pkt_lost;
|
|
- bbr->cc.congestion_event = bbr_cc_congestion_event;
|
|
- bbr->cc.on_spurious_congestion = bbr_cc_on_spurious_congestion;
|
|
- bbr->cc.on_persistent_congestion = bbr_cc_on_persistent_congestion;
|
|
- bbr->cc.on_ack_recv = bbr_cc_on_ack_recv;
|
|
- bbr->cc.on_pkt_sent = bbr_cc_on_pkt_sent;
|
|
- bbr->cc.reset = bbr_cc_reset;
|
|
-
|
|
- bbr->rst = rst;
|
|
- bbr->rand = rand;
|
|
- bbr->rand_ctx = *rand_ctx;
|
|
- bbr->initial_cwnd = cstat->cwnd;
|
|
+ ngtcp2_tstamp initial_ts, ngtcp2_pcg32 *pcg) {
|
|
+ *bbr = (ngtcp2_cc_bbr){
|
|
+ .cc =
|
|
+ {
|
|
+ .log = log,
|
|
+ .on_pkt_lost = bbr_cc_on_pkt_lost,
|
|
+ .congestion_event = bbr_cc_congestion_event,
|
|
+ .on_spurious_congestion = bbr_cc_on_spurious_congestion,
|
|
+ .on_persistent_congestion = bbr_cc_on_persistent_congestion,
|
|
+ .on_ack_recv = bbr_cc_on_ack_recv,
|
|
+ .on_pkt_sent = bbr_cc_on_pkt_sent,
|
|
+ .reset = bbr_cc_reset,
|
|
+ },
|
|
+ .rst = rst,
|
|
+ .pcg = pcg,
|
|
+ .initial_cwnd = cstat->cwnd,
|
|
+ };
|
|
|
|
bbr_on_init(bbr, cstat, initial_ts);
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_bbr.h b/third_party/ngtcp2/lib/ngtcp2_bbr.h
|
|
index e823711a500..5177944b290 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_bbr.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_bbr.h
|
|
@@ -35,6 +35,7 @@
|
|
#include "ngtcp2_window_filter.h"
|
|
|
|
typedef struct ngtcp2_rst ngtcp2_rst;
|
|
+typedef struct ngtcp2_pcg32 ngtcp2_pcg32;
|
|
|
|
typedef enum ngtcp2_bbr_state {
|
|
NGTCP2_BBR_STATE_STARTUP,
|
|
@@ -62,8 +63,7 @@ typedef struct ngtcp2_cc_bbr {
|
|
|
|
uint64_t initial_cwnd;
|
|
ngtcp2_rst *rst;
|
|
- ngtcp2_rand rand;
|
|
- ngtcp2_rand_ctx rand_ctx;
|
|
+ ngtcp2_pcg32 *pcg;
|
|
|
|
/* max_bw_filter for tracking the maximum recent delivery rate
|
|
samples for estimating max_bw. */
|
|
@@ -75,8 +75,8 @@ typedef struct ngtcp2_cc_bbr {
|
|
ngtcp2_tstamp min_rtt_stamp;
|
|
ngtcp2_tstamp probe_rtt_done_stamp;
|
|
int probe_rtt_round_done;
|
|
- uint64_t prior_cwnd;
|
|
int idle_restart;
|
|
+ uint64_t prior_cwnd;
|
|
ngtcp2_tstamp extra_acked_interval_start;
|
|
uint64_t extra_acked_delivered;
|
|
|
|
@@ -91,8 +91,8 @@ typedef struct ngtcp2_cc_bbr {
|
|
|
|
/* Round counting */
|
|
uint64_t next_round_delivered;
|
|
- int round_start;
|
|
uint64_t round_count;
|
|
+ int round_start;
|
|
|
|
/* Full pipe */
|
|
uint64_t full_bw;
|
|
@@ -106,7 +106,12 @@ typedef struct ngtcp2_cc_bbr {
|
|
ngtcp2_bbr_state state;
|
|
uint64_t cwnd_gain_h;
|
|
|
|
- int loss_round_start;
|
|
+ /* Backup for spurious losses */
|
|
+ ngtcp2_bbr_state undo_state;
|
|
+ uint64_t undo_bw_shortterm;
|
|
+ uint64_t undo_inflight_shortterm;
|
|
+ uint64_t undo_inflight_longterm;
|
|
+
|
|
uint64_t loss_round_delivered;
|
|
uint64_t rounds_since_bw_probe;
|
|
uint64_t max_bw;
|
|
@@ -120,23 +125,22 @@ typedef struct ngtcp2_cc_bbr {
|
|
ngtcp2_tstamp cycle_stamp;
|
|
ngtcp2_bbr_ack_phase ack_phase;
|
|
ngtcp2_duration bw_probe_wait;
|
|
- int bw_probe_samples;
|
|
size_t bw_probe_up_rounds;
|
|
uint64_t bw_probe_up_acks;
|
|
uint64_t inflight_longterm;
|
|
- int probe_rtt_expired;
|
|
ngtcp2_duration probe_rtt_min_delay;
|
|
ngtcp2_tstamp probe_rtt_min_stamp;
|
|
- int in_loss_recovery;
|
|
uint64_t round_count_at_recovery;
|
|
uint64_t max_inflight;
|
|
- ngtcp2_tstamp congestion_recovery_start_ts;
|
|
uint64_t bdp;
|
|
+ int loss_round_start;
|
|
+ int bw_probe_samples;
|
|
+ int probe_rtt_expired;
|
|
+ int in_loss_recovery;
|
|
} ngtcp2_cc_bbr;
|
|
|
|
void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,
|
|
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
|
|
- ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
|
|
- const ngtcp2_rand_ctx *rand_ctx);
|
|
+ ngtcp2_tstamp initial_ts, ngtcp2_pcg32 *pcg);
|
|
|
|
#endif /* !defined(NGTCP2_BBR_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_buf.c b/third_party/ngtcp2/lib/ngtcp2_buf.c
|
|
index 75326d6b76b..083a766281b 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_buf.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_buf.c
|
|
@@ -26,8 +26,12 @@
|
|
#include "ngtcp2_mem.h"
|
|
|
|
void ngtcp2_buf_init(ngtcp2_buf *buf, uint8_t *begin, size_t len) {
|
|
- buf->begin = buf->pos = buf->last = begin;
|
|
- buf->end = begin + len;
|
|
+ *buf = (ngtcp2_buf){
|
|
+ .begin = begin,
|
|
+ .end = begin + len,
|
|
+ .pos = begin,
|
|
+ .last = begin,
|
|
+ };
|
|
}
|
|
|
|
void ngtcp2_buf_reset(ngtcp2_buf *buf) { buf->pos = buf->last = buf->begin; }
|
|
@@ -36,6 +40,12 @@ size_t ngtcp2_buf_cap(const ngtcp2_buf *buf) {
|
|
return (size_t)(buf->end - buf->begin);
|
|
}
|
|
|
|
+void ngtcp2_buf_trunc(ngtcp2_buf *buf, size_t len) {
|
|
+ if (ngtcp2_buf_len(buf) > len) {
|
|
+ buf->last = buf->pos + len;
|
|
+ }
|
|
+}
|
|
+
|
|
int ngtcp2_buf_chain_new(ngtcp2_buf_chain **pbufchain, size_t len,
|
|
const ngtcp2_mem *mem) {
|
|
*pbufchain = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_buf_chain) + len);
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_buf.h b/third_party/ngtcp2/lib/ngtcp2_buf.h
|
|
index e87adb11991..b59ac9a54b3 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_buf.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_buf.h
|
|
@@ -62,7 +62,9 @@ void ngtcp2_buf_reset(ngtcp2_buf *buf);
|
|
* written to the underlying buffer. In other words, it returns
|
|
* buf->end - buf->last.
|
|
*/
|
|
-#define ngtcp2_buf_left(BUF) (size_t)((BUF)->end - (BUF)->last)
|
|
+static inline size_t ngtcp2_buf_left(const ngtcp2_buf *buf) {
|
|
+ return (size_t)(buf->end - buf->last);
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_buf_len returns the number of bytes left to read. In other
|
|
@@ -76,6 +78,13 @@ void ngtcp2_buf_reset(ngtcp2_buf *buf);
|
|
*/
|
|
size_t ngtcp2_buf_cap(const ngtcp2_buf *buf);
|
|
|
|
+/*
|
|
+ * ngtcp2_buf_trunc truncates the number of bytes to read to at most
|
|
+ * |len|. In other words, it sets buf->last = buf->pos + len if
|
|
+ * ngtcp2_buf_len(buf) > len.
|
|
+ */
|
|
+void ngtcp2_buf_trunc(ngtcp2_buf *buf, size_t len);
|
|
+
|
|
/*
|
|
* ngtcp2_buf_chain is a linked list of ngtcp2_buf.
|
|
*/
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_callbacks.c b/third_party/ngtcp2/lib/ngtcp2_callbacks.c
|
|
new file mode 100644
|
|
index 00000000000..1d65d93d566
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_callbacks.c
|
|
@@ -0,0 +1,75 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#include "ngtcp2_callbacks.h"
|
|
+
|
|
+#include <string.h>
|
|
+#include <assert.h>
|
|
+
|
|
+#include "ngtcp2_unreachable.h"
|
|
+
|
|
+static void callbacks_copy(ngtcp2_callbacks *dest, const ngtcp2_callbacks *src,
|
|
+ int callbacks_version) {
|
|
+ assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
|
|
+
|
|
+ memcpy(dest, src, ngtcp2_callbackslen_version(callbacks_version));
|
|
+}
|
|
+
|
|
+const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
|
|
+ ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src) {
|
|
+ if (callbacks_version == NGTCP2_CALLBACKS_VERSION) {
|
|
+ return src;
|
|
+ }
|
|
+
|
|
+ *dest = (ngtcp2_callbacks){0};
|
|
+
|
|
+ callbacks_copy(dest, src, callbacks_version);
|
|
+
|
|
+ return dest;
|
|
+}
|
|
+
|
|
+void ngtcp2_callbacks_convert_to_old(int callbacks_version,
|
|
+ ngtcp2_callbacks *dest,
|
|
+ const ngtcp2_callbacks *src) {
|
|
+ assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
|
|
+
|
|
+ callbacks_copy(dest, src, callbacks_version);
|
|
+}
|
|
+
|
|
+size_t ngtcp2_callbackslen_version(int callbacks_version) {
|
|
+ ngtcp2_callbacks callbacks;
|
|
+
|
|
+ switch (callbacks_version) {
|
|
+ case NGTCP2_CALLBACKS_VERSION:
|
|
+ return sizeof(callbacks);
|
|
+ case NGTCP2_CALLBACKS_V2:
|
|
+ return offsetof(ngtcp2_callbacks, begin_path_validation) +
|
|
+ sizeof(callbacks.begin_path_validation);
|
|
+ case NGTCP2_CALLBACKS_V1:
|
|
+ return offsetof(ngtcp2_callbacks, tls_early_data_rejected) +
|
|
+ sizeof(callbacks.tls_early_data_rejected);
|
|
+ default:
|
|
+ ngtcp2_unreachable();
|
|
+ }
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_callbacks.h b/third_party/ngtcp2/lib/ngtcp2_callbacks.h
|
|
new file mode 100644
|
|
index 00000000000..751766bb83e
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_callbacks.h
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#ifndef NGTCP2_CALLBACKS_H
|
|
+#define NGTCP2_CALLBACKS_H
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include <config.h>
|
|
+#endif /* defined(HAVE_CONFIG_H) */
|
|
+
|
|
+#include <ngtcp2/ngtcp2.h>
|
|
+
|
|
+/*
|
|
+ * ngtcp2_callbacks_convert_to_latest converts |src| of version
|
|
+ * |callbacks_version| to the latest version NGTCP2_CALLBACKS_VERSION.
|
|
+ *
|
|
+ * |dest| must point to the latest version. |src| may be the older
|
|
+ * version, and if so, it may have fewer fields. Accessing those
|
|
+ * fields causes undefined behavior.
|
|
+ *
|
|
+ * If |callbacks_version| == NGTCP2_CALLBACKS_VERSION, no conversion
|
|
+ * is made, and |src| is returned. Otherwise, first |dest| is
|
|
+ * zero-initialized, and then all valid fields in |src| are copied
|
|
+ * into |dest|. Finally, |dest| is returned.
|
|
+ */
|
|
+const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
|
|
+ ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_callbacks_convert_to_old converts |src| of the latest
|
|
+ * version to |dest| of version |callbacks_version|.
|
|
+ *
|
|
+ * |callbacks_version| must not be the latest version
|
|
+ * NGTCP2_CALLBACKS_VERSION.
|
|
+ *
|
|
+ * |dest| points to the older version, and it may have fewer fields.
|
|
+ * Accessing those fields causes undefined behavior.
|
|
+ *
|
|
+ * This function copies all valid fields in version
|
|
+ * |callbacks_version| from |src| to |dest|.
|
|
+ */
|
|
+void ngtcp2_callbacks_convert_to_old(int callbacks_version,
|
|
+ ngtcp2_callbacks *dest,
|
|
+ const ngtcp2_callbacks *src);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_callbackslen_version returns the effective length of
|
|
+ * ngtcp2_callbacks at the version |callbacks_version|.
|
|
+ */
|
|
+size_t ngtcp2_callbackslen_version(int callbacks_version);
|
|
+
|
|
+#endif /* !defined(NGTCP2_CALLBACKS_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_cc.c b/third_party/ngtcp2/lib/ngtcp2_cc.c
|
|
index ad3665b6cf6..73dfde6904b 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_cc.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_cc.c
|
|
@@ -41,6 +41,40 @@ uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) {
|
|
return ngtcp2_min_uint64(10 * max_udp_payload_size, n);
|
|
}
|
|
|
|
+/* 1.25 is the under-utilization avoidance factor described in
|
|
+ https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */
|
|
+#define NGTCP2_CC_PACING_GAIN_H 125
|
|
+
|
|
+static void init_pacing_rate(ngtcp2_conn_stat *cstat) {
|
|
+ assert(cstat->cwnd);
|
|
+
|
|
+ cstat->pacing_interval_m = ngtcp2_max_uint64(
|
|
+ (NGTCP2_MILLISECONDS << 10) * 100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd,
|
|
+ 1);
|
|
+ cstat->send_quantum = 10 * cstat->max_tx_udp_payload_size;
|
|
+}
|
|
+
|
|
+static void set_pacing_rate(ngtcp2_conn_stat *cstat) {
|
|
+ size_t send_quantum = 64 * 1024;
|
|
+
|
|
+ assert(cstat->cwnd);
|
|
+
|
|
+ cstat->pacing_interval_m =
|
|
+ ((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
|
|
+ : cstat->smoothed_rtt)
|
|
+ << 10) *
|
|
+ 100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd;
|
|
+
|
|
+ cstat->pacing_interval_m = ngtcp2_max_uint64(cstat->pacing_interval_m, 1);
|
|
+
|
|
+ send_quantum =
|
|
+ ngtcp2_min_size(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) /
|
|
+ cstat->pacing_interval_m));
|
|
+
|
|
+ cstat->send_quantum =
|
|
+ ngtcp2_max_size(send_quantum, 10 * cstat->max_tx_udp_payload_size);
|
|
+}
|
|
+
|
|
ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
|
|
size_t pktlen, ngtcp2_pktns_id pktns_id,
|
|
ngtcp2_tstamp sent_ts, uint64_t lost,
|
|
@@ -56,19 +90,26 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
|
|
return pkt;
|
|
}
|
|
|
|
-static void reno_cc_reset(ngtcp2_cc_reno *reno) { reno->pending_add = 0; }
|
|
-
|
|
-void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) {
|
|
- memset(reno, 0, sizeof(*reno));
|
|
+static void reno_cc_reset(ngtcp2_cc_reno *reno, ngtcp2_conn_stat *cstat) {
|
|
+ reno->pending_add = 0;
|
|
|
|
- reno->cc.log = log;
|
|
- reno->cc.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked;
|
|
- reno->cc.congestion_event = ngtcp2_cc_reno_cc_congestion_event;
|
|
- reno->cc.on_persistent_congestion =
|
|
- ngtcp2_cc_reno_cc_on_persistent_congestion;
|
|
- reno->cc.reset = ngtcp2_cc_reno_cc_reset;
|
|
+ init_pacing_rate(cstat);
|
|
+}
|
|
|
|
- reno_cc_reset(reno);
|
|
+void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log,
|
|
+ ngtcp2_conn_stat *cstat) {
|
|
+ *reno = (ngtcp2_cc_reno){
|
|
+ .cc =
|
|
+ {
|
|
+ .log = log,
|
|
+ .on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked,
|
|
+ .congestion_event = ngtcp2_cc_reno_cc_congestion_event,
|
|
+ .on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion,
|
|
+ .reset = ngtcp2_cc_reno_cc_reset,
|
|
+ },
|
|
+ };
|
|
+
|
|
+ reno_cc_reset(reno, cstat);
|
|
}
|
|
|
|
static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
|
|
@@ -90,9 +131,12 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
|
|
if (cstat->cwnd < cstat->ssthresh) {
|
|
cstat->cwnd += pkt->pktlen;
|
|
- ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
|
|
- pkt->pkt_num, cstat->cwnd);
|
|
+
|
|
+ set_pacing_rate(cstat);
|
|
+
|
|
+ ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
|
|
+ pkt->pkt_num, cstat->cwnd);
|
|
return;
|
|
}
|
|
|
|
@@ -100,14 +144,17 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
reno->pending_add = m % cstat->cwnd;
|
|
|
|
cstat->cwnd += m / cstat->cwnd;
|
|
+
|
|
+ set_pacing_rate(cstat);
|
|
}
|
|
|
|
void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp sent_ts,
|
|
- uint64_t bytes_lost, ngtcp2_tstamp ts) {
|
|
+ const ngtcp2_cc_ack *ack,
|
|
+ ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc);
|
|
uint64_t min_cwnd;
|
|
- (void)bytes_lost;
|
|
+ (void)ack;
|
|
|
|
if (in_congestion_recovery(cstat, sent_ts)) {
|
|
return;
|
|
@@ -121,9 +168,11 @@ void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
|
|
reno->pending_add = 0;
|
|
|
|
- ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "reduce cwnd because of packet loss cwnd=%" PRIu64,
|
|
- cstat->cwnd);
|
|
+ set_pacing_rate(cstat);
|
|
+
|
|
+ ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "reduce cwnd because of packet loss cwnd=%" PRIu64,
|
|
+ cstat->cwnd);
|
|
}
|
|
|
|
void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
|
@@ -134,31 +183,32 @@ void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
|
|
|
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
|
|
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
|
+
|
|
+ set_pacing_rate(cstat);
|
|
}
|
|
|
|
void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc);
|
|
- (void)cstat;
|
|
(void)ts;
|
|
|
|
- reno_cc_reset(reno);
|
|
+ reno_cc_reset(reno, cstat);
|
|
}
|
|
|
|
static void cubic_vars_reset(ngtcp2_cubic_vars *v) {
|
|
v->cwnd_prior = 0;
|
|
v->w_max = 0;
|
|
- v->k = 0;
|
|
+ v->k_m = 0;
|
|
v->epoch_start = UINT64_MAX;
|
|
v->w_est = 0;
|
|
|
|
v->app_limited_start_ts = UINT64_MAX;
|
|
v->app_limited_duration = 0;
|
|
- v->pending_bytes_delivered = 0;
|
|
- v->pending_est_bytes_delivered = 0;
|
|
+ v->pending_bytes_acked = 0;
|
|
+ v->pending_est_bytes_acked = 0;
|
|
}
|
|
|
|
-static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
|
|
+static void cubic_cc_reset(ngtcp2_cc_cubic *cubic, ngtcp2_conn_stat *cstat) {
|
|
cubic_vars_reset(&cubic->current);
|
|
cubic_vars_reset(&cubic->undo.v);
|
|
cubic->undo.cwnd = 0;
|
|
@@ -172,23 +222,26 @@ static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
|
|
cubic->hs.css_round = 0;
|
|
|
|
cubic->next_round_delivered = 0;
|
|
+
|
|
+ init_pacing_rate(cstat);
|
|
}
|
|
|
|
void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log,
|
|
- ngtcp2_rst *rst) {
|
|
- memset(cubic, 0, sizeof(*cubic));
|
|
-
|
|
- cubic->cc.log = log;
|
|
- cubic->cc.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv;
|
|
- cubic->cc.congestion_event = ngtcp2_cc_cubic_cc_congestion_event;
|
|
- cubic->cc.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion;
|
|
- cubic->cc.on_persistent_congestion =
|
|
- ngtcp2_cc_cubic_cc_on_persistent_congestion;
|
|
- cubic->cc.reset = ngtcp2_cc_cubic_cc_reset;
|
|
-
|
|
- cubic->rst = rst;
|
|
-
|
|
- cubic_cc_reset(cubic);
|
|
+ ngtcp2_conn_stat *cstat, ngtcp2_rst *rst) {
|
|
+ *cubic = (ngtcp2_cc_cubic){
|
|
+ .cc =
|
|
+ {
|
|
+ .log = log,
|
|
+ .on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv,
|
|
+ .congestion_event = ngtcp2_cc_cubic_cc_congestion_event,
|
|
+ .on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion,
|
|
+ .on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion,
|
|
+ .reset = ngtcp2_cc_cubic_cc_reset,
|
|
+ },
|
|
+ .rst = rst,
|
|
+ };
|
|
+
|
|
+ cubic_cc_reset(cubic, cstat);
|
|
}
|
|
|
|
uint64_t ngtcp2_cbrt(uint64_t n) {
|
|
@@ -208,7 +261,6 @@ uint64_t ngtcp2_cbrt(uint64_t n) {
|
|
y <<= 1;
|
|
b = 3 * y * (y + 1) + 1;
|
|
if (n >= b) {
|
|
- n -= b;
|
|
y++;
|
|
}
|
|
|
|
@@ -223,30 +275,54 @@ uint64_t ngtcp2_cbrt(uint64_t n) {
|
|
#define NGTCP2_HS_CSS_GROWTH_DIVISOR 4
|
|
#define NGTCP2_HS_CSS_ROUNDS 5
|
|
|
|
-static int64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
|
|
- const ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_tstamp ts) {
|
|
+static uint64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
|
|
+ const ngtcp2_conn_stat *cstat,
|
|
+ ngtcp2_tstamp ts) {
|
|
ngtcp2_duration t = ts - cubic->current.epoch_start;
|
|
- int64_t tx = (int64_t)((t << 10) / NGTCP2_SECONDS);
|
|
- int64_t time_delta = ngtcp2_min_int64(tx - cubic->current.k, 3600 << 10);
|
|
- int64_t delta = ((((time_delta * time_delta) >> 10) * time_delta) >> 20) *
|
|
- (int64_t)cstat->max_tx_udp_payload_size * 4 / 10;
|
|
+ uint64_t tx_m = (t << 10) / NGTCP2_SECONDS;
|
|
+ int neg = tx_m < cubic->current.k_m;
|
|
+ uint64_t time_delta_m;
|
|
+ uint64_t delta;
|
|
+
|
|
+ /* Avoid signed bit-shift */
|
|
+ if (neg) {
|
|
+ time_delta_m = cubic->current.k_m - tx_m;
|
|
+ } else {
|
|
+ time_delta_m = tx_m - cubic->current.k_m;
|
|
+ }
|
|
+
|
|
+ time_delta_m = ngtcp2_min_uint64(time_delta_m, 3600 << 10);
|
|
+
|
|
+ delta = ((((time_delta_m * time_delta_m) >> 10) * time_delta_m) >> 10) *
|
|
+ cstat->max_tx_udp_payload_size * 4 / 10;
|
|
+ delta >>= 10;
|
|
+
|
|
+ if (neg) {
|
|
+ if (cubic->current.w_max < delta) {
|
|
+ /* Negative w_cubic is not interesting. */
|
|
+ return 0;
|
|
+ }
|
|
|
|
- return (int64_t)cubic->current.w_max + delta;
|
|
+ return cubic->current.w_max - delta;
|
|
+ }
|
|
+
|
|
+ return cubic->current.w_max + delta;
|
|
}
|
|
|
|
void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
|
- int64_t w_cubic, w_cubic_next;
|
|
+ uint64_t w_cubic, w_cubic_next;
|
|
uint64_t target, m;
|
|
+ uint64_t bytes_acked;
|
|
ngtcp2_duration rtt_thresh;
|
|
int round_start;
|
|
int is_app_limited =
|
|
cubic->rst->rs.is_app_limited && !cubic->rst->is_cwnd_limited;
|
|
|
|
- if (in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
|
+ if (ack->bytes_delivered == 0 ||
|
|
+ in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
|
return;
|
|
}
|
|
|
|
@@ -266,9 +342,11 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
cstat->cwnd += ack->bytes_delivered;
|
|
}
|
|
|
|
- ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
|
|
- ack->bytes_delivered, cstat->cwnd);
|
|
+ set_pacing_rate(cstat);
|
|
+
|
|
+ ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
|
|
+ ack->bytes_delivered, cstat->cwnd);
|
|
}
|
|
|
|
if (round_start) {
|
|
@@ -346,44 +424,54 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
cubic, cstat,
|
|
ts - cubic->current.app_limited_duration + cstat->smoothed_rtt);
|
|
|
|
- if (w_cubic_next < (int64_t)cstat->cwnd) {
|
|
+ if (w_cubic_next < cstat->cwnd) {
|
|
target = cstat->cwnd;
|
|
- } else if (2 * w_cubic_next > 3 * (int64_t)cstat->cwnd) {
|
|
+ } else if (2 * w_cubic_next > 3 * cstat->cwnd) {
|
|
target = cstat->cwnd * 3 / 2;
|
|
} else {
|
|
- assert(w_cubic_next >= 0);
|
|
- target = (uint64_t)w_cubic_next;
|
|
+ target = w_cubic_next;
|
|
}
|
|
|
|
- m = ack->bytes_delivered * cstat->max_tx_udp_payload_size +
|
|
- cubic->current.pending_est_bytes_delivered;
|
|
- cubic->current.pending_est_bytes_delivered = m % cstat->cwnd;
|
|
+ bytes_acked = ack->bytes_delivered * cstat->max_tx_udp_payload_size;
|
|
+ m = (bytes_acked + cubic->current.pending_est_bytes_acked) / cstat->cwnd;
|
|
+
|
|
+ cubic->current.pending_est_bytes_acked += bytes_acked;
|
|
+ cubic->current.pending_est_bytes_acked -= m * cstat->cwnd;
|
|
+
|
|
+ assert(cubic->current.pending_est_bytes_acked < cstat->cwnd);
|
|
|
|
if (cubic->current.w_est < cubic->current.cwnd_prior) {
|
|
- cubic->current.w_est += m * 9 / 17 / cstat->cwnd;
|
|
+ cubic->current.w_est += m * 9 / 17;
|
|
} else {
|
|
- cubic->current.w_est += m / cstat->cwnd;
|
|
+ cubic->current.w_est += m;
|
|
}
|
|
|
|
- if ((int64_t)cubic->current.w_est > w_cubic) {
|
|
+ if (cubic->current.w_est > w_cubic) {
|
|
cstat->cwnd = cubic->current.w_est;
|
|
} else {
|
|
- m = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size +
|
|
- cubic->current.pending_bytes_delivered;
|
|
- cstat->cwnd += m / cstat->cwnd;
|
|
- cubic->current.pending_bytes_delivered = m % cstat->cwnd;
|
|
+ bytes_acked = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size;
|
|
+ m = (bytes_acked + cubic->current.pending_bytes_acked) / cstat->cwnd;
|
|
+
|
|
+ cubic->current.pending_bytes_acked += bytes_acked;
|
|
+ cubic->current.pending_bytes_acked -= m * cstat->cwnd;
|
|
+
|
|
+ assert(cubic->current.pending_bytes_acked < cstat->cwnd);
|
|
+
|
|
+ cstat->cwnd += m;
|
|
}
|
|
|
|
- ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
|
|
- " k=%" PRIi64 " target=%" PRIu64 " w_est=%" PRIu64,
|
|
- ack->bytes_delivered, cstat->cwnd, cubic->current.k, target,
|
|
- cubic->current.w_est);
|
|
+ set_pacing_rate(cstat);
|
|
+
|
|
+ ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
|
|
+ " k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64,
|
|
+ ack->bytes_delivered, cstat->cwnd, cubic->current.k_m,
|
|
+ target, cubic->current.w_est);
|
|
}
|
|
|
|
void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp sent_ts,
|
|
- uint64_t bytes_lost,
|
|
+ const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
|
uint64_t flight_size;
|
|
@@ -404,8 +492,8 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
cubic->current.epoch_start = ts;
|
|
cubic->current.app_limited_start_ts = UINT64_MAX;
|
|
cubic->current.app_limited_duration = 0;
|
|
- cubic->current.pending_bytes_delivered = 0;
|
|
- cubic->current.pending_est_bytes_delivered = 0;
|
|
+ cubic->current.pending_bytes_acked = 0;
|
|
+ cubic->current.pending_est_bytes_acked = 0;
|
|
|
|
if (cstat->cwnd < cubic->current.w_max) {
|
|
cubic->current.w_max = cstat->cwnd * 17 / 20;
|
|
@@ -413,10 +501,13 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
cubic->current.w_max = cstat->cwnd;
|
|
}
|
|
|
|
+ cubic->current.w_max =
|
|
+ ngtcp2_max_uint64(cubic->current.w_max, 2 * cstat->max_tx_udp_payload_size);
|
|
+
|
|
cstat->ssthresh = cstat->cwnd * 7 / 10;
|
|
|
|
if (cubic->rst->rs.delivered * 2 < cstat->cwnd) {
|
|
- flight_size = cstat->bytes_in_flight + bytes_lost;
|
|
+ flight_size = cstat->bytes_in_flight + ack->bytes_lost;
|
|
cstat->ssthresh = ngtcp2_min_uint64(
|
|
cstat->ssthresh,
|
|
ngtcp2_max_uint64(cubic->rst->rs.delivered, flight_size));
|
|
@@ -430,21 +521,18 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
|
|
cubic->current.w_est = cstat->cwnd;
|
|
|
|
- if (cstat->cwnd < cubic->current.w_max) {
|
|
- cwnd_delta = cubic->current.w_max - cstat->cwnd;
|
|
- } else {
|
|
- cwnd_delta = cstat->cwnd - cubic->current.w_max;
|
|
- }
|
|
+ assert(cubic->current.w_max >= cstat->cwnd);
|
|
|
|
- cubic->current.k = (int64_t)ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 /
|
|
- cstat->max_tx_udp_payload_size);
|
|
- if (cstat->cwnd >= cubic->current.w_max) {
|
|
- cubic->current.k = -cubic->current.k;
|
|
- }
|
|
+ cwnd_delta = cubic->current.w_max - cstat->cwnd;
|
|
+
|
|
+ cubic->current.k_m =
|
|
+ ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 / cstat->max_tx_udp_payload_size);
|
|
|
|
- ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "reduce cwnd because of packet loss cwnd=%" PRIu64,
|
|
- cstat->cwnd);
|
|
+ set_pacing_rate(cstat);
|
|
+
|
|
+ ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "reduce cwnd because of packet loss cwnd=%" PRIu64,
|
|
+ cstat->cwnd);
|
|
}
|
|
|
|
void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
|
@@ -460,10 +548,12 @@ void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
|
cstat->cwnd = cubic->undo.cwnd;
|
|
cstat->ssthresh = cubic->undo.ssthresh;
|
|
|
|
- ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
- "spurious congestion is detected and congestion state is "
|
|
- "restored cwnd=%" PRIu64,
|
|
- cstat->cwnd);
|
|
+ set_pacing_rate(cstat);
|
|
+
|
|
+ ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
|
+ "spurious congestion is detected and congestion state is "
|
|
+ "restored cwnd=%" PRIu64,
|
|
+ cstat->cwnd);
|
|
}
|
|
|
|
cubic_vars_reset(&cubic->undo.v);
|
|
@@ -477,17 +567,18 @@ void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
|
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
|
(void)ts;
|
|
|
|
- cubic_cc_reset(cubic);
|
|
+ cubic_cc_reset(cubic, cstat);
|
|
|
|
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
|
|
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
|
+
|
|
+ set_pacing_rate(cstat);
|
|
}
|
|
|
|
void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
|
- (void)cstat;
|
|
(void)ts;
|
|
|
|
- cubic_cc_reset(cubic);
|
|
+ cubic_cc_reset(cubic, cstat);
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_cc.h b/third_party/ngtcp2/lib/ngtcp2_cc.h
|
|
index 296a1a433f1..a19e90b1d0d 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_cc.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_cc.h
|
|
@@ -88,11 +88,6 @@ typedef struct ngtcp2_cc_pkt {
|
|
* acknowledged and lost bytes.
|
|
*/
|
|
typedef struct ngtcp2_cc_ack {
|
|
- /**
|
|
- * :member:`prior_bytes_in_flight` is the in-flight bytes before
|
|
- * processing this ACK.
|
|
- */
|
|
- uint64_t prior_bytes_in_flight;
|
|
/**
|
|
* :member:`bytes_delivered` is the number of bytes acknowledged.
|
|
*/
|
|
@@ -143,13 +138,16 @@ typedef void (*ngtcp2_cc_on_pkt_lost)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
* @functypedef
|
|
*
|
|
* :type:`ngtcp2_cc_congestion_event` is a callback function which is
|
|
- * called when congestion event happens (e.g., when packet is lost).
|
|
- * |bytes_lost| is the number of bytes lost in this congestion event.
|
|
+ * called when congestion event happens (e.g., when packet is lost or
|
|
+ * due to ECN). |ack| contains information after ACK processing.
|
|
+ * This callback may be called from non-ACK processing context. In
|
|
+ * that case, the information only taken from |ack| processing has
|
|
+ * default values, like 0 or UINT64_MAX;
|
|
*/
|
|
typedef void (*ngtcp2_cc_congestion_event)(ngtcp2_cc *cc,
|
|
ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp sent_ts,
|
|
- uint64_t bytes_lost,
|
|
+ const ngtcp2_cc_ack *ack,
|
|
ngtcp2_tstamp ts);
|
|
|
|
/**
|
|
@@ -186,20 +184,12 @@ typedef void (*ngtcp2_cc_on_ack_recv)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
* @functypedef
|
|
*
|
|
* :type:`ngtcp2_cc_on_pkt_sent` is a callback function which is
|
|
- * called when an ack-eliciting packet is sent.
|
|
+ * called when an ack-eliciting packet is sent. The lost,
|
|
+ * tx_in_flight, and is_app_limited fields in |pkt| are set to 0.
|
|
*/
|
|
typedef void (*ngtcp2_cc_on_pkt_sent)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_pkt *pkt);
|
|
|
|
-/**
|
|
- * @functypedef
|
|
- *
|
|
- * :type:`ngtcp2_cc_new_rtt_sample` is a callback function which is
|
|
- * called when new RTT sample is obtained.
|
|
- */
|
|
-typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_tstamp ts);
|
|
-
|
|
/**
|
|
* @functypedef
|
|
*
|
|
@@ -209,28 +199,6 @@ typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
typedef void (*ngtcp2_cc_reset)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts);
|
|
|
|
-/**
|
|
- * @enum
|
|
- *
|
|
- * :type:`ngtcp2_cc_event_type` defines congestion control events.
|
|
- */
|
|
-typedef enum ngtcp2_cc_event_type {
|
|
- /**
|
|
- * :enum:`NGTCP2_CC_EVENT_TX_START` occurs when ack-eliciting packet
|
|
- * is sent and no other ack-eliciting packet is present.
|
|
- */
|
|
- NGTCP2_CC_EVENT_TYPE_TX_START
|
|
-} ngtcp2_cc_event_type;
|
|
-
|
|
-/**
|
|
- * @functypedef
|
|
- *
|
|
- * :type:`ngtcp2_cc_event` is a callback function which is called when
|
|
- * a specific event happens.
|
|
- */
|
|
-typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
- ngtcp2_cc_event_type event, ngtcp2_tstamp ts);
|
|
-
|
|
/**
|
|
* @struct
|
|
*
|
|
@@ -254,7 +222,7 @@ typedef struct ngtcp2_cc {
|
|
ngtcp2_cc_on_pkt_lost on_pkt_lost;
|
|
/**
|
|
* :member:`congestion_event` is a callback function which is called
|
|
- * when congestion event happens (.e.g, packet is lost).
|
|
+ * when congestion event happens (e.g., packet is lost).
|
|
*/
|
|
ngtcp2_cc_congestion_event congestion_event;
|
|
/**
|
|
@@ -277,21 +245,11 @@ typedef struct ngtcp2_cc {
|
|
* ack-eliciting packet is sent.
|
|
*/
|
|
ngtcp2_cc_on_pkt_sent on_pkt_sent;
|
|
- /**
|
|
- * :member:`new_rtt_sample` is a callback function which is called
|
|
- * when new RTT sample is obtained.
|
|
- */
|
|
- ngtcp2_cc_new_rtt_sample new_rtt_sample;
|
|
/**
|
|
* :member:`reset` is a callback function which is called when
|
|
* congestion control state must be reset.
|
|
*/
|
|
ngtcp2_cc_reset reset;
|
|
- /**
|
|
- * :member:`event` is a callback function which is called when a
|
|
- * specific event happens.
|
|
- */
|
|
- ngtcp2_cc_event event;
|
|
} ngtcp2_cc;
|
|
|
|
/*
|
|
@@ -310,14 +268,16 @@ typedef struct ngtcp2_cc_reno {
|
|
uint64_t pending_add;
|
|
} ngtcp2_cc_reno;
|
|
|
|
-void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log);
|
|
+void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log,
|
|
+ ngtcp2_conn_stat *cstat);
|
|
|
|
void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
|
|
|
|
void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp sent_ts,
|
|
- uint64_t bytes_lost, ngtcp2_tstamp ts);
|
|
+ const ngtcp2_cc_ack *ack,
|
|
+ ngtcp2_tstamp ts);
|
|
|
|
void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
|
ngtcp2_conn_stat *cstat,
|
|
@@ -329,7 +289,8 @@ void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
typedef struct ngtcp2_cubic_vars {
|
|
uint64_t cwnd_prior;
|
|
uint64_t w_max;
|
|
- int64_t k;
|
|
+ /* CUBIC K with 10 bits extra precision. */
|
|
+ uint64_t k_m;
|
|
ngtcp2_tstamp epoch_start;
|
|
uint64_t w_est;
|
|
|
|
@@ -339,8 +300,8 @@ typedef struct ngtcp2_cubic_vars {
|
|
/* app_limited_duration is the cumulative duration where a
|
|
connection is under app limited when ACK is received. */
|
|
ngtcp2_duration app_limited_duration;
|
|
- uint64_t pending_bytes_delivered;
|
|
- uint64_t pending_est_bytes_delivered;
|
|
+ uint64_t pending_bytes_acked;
|
|
+ uint64_t pending_est_bytes_acked;
|
|
} ngtcp2_cubic_vars;
|
|
|
|
/* ngtcp2_cc_cubic is CUBIC congestion controller. */
|
|
@@ -370,14 +331,15 @@ typedef struct ngtcp2_cc_cubic {
|
|
} ngtcp2_cc_cubic;
|
|
|
|
void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cc, ngtcp2_log *log,
|
|
- ngtcp2_rst *rst);
|
|
+ ngtcp2_conn_stat *cstat, ngtcp2_rst *rst);
|
|
|
|
void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
|
|
|
|
void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp sent_ts,
|
|
- uint64_t bytes_lost, ngtcp2_tstamp ts);
|
|
+ const ngtcp2_cc_ack *ack,
|
|
+ ngtcp2_tstamp ts);
|
|
|
|
void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx,
|
|
ngtcp2_conn_stat *cstat,
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_cid.c b/third_party/ngtcp2/lib/ngtcp2_cid.c
|
|
index acbee78aaf4..4eba2aaca5d 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_cid.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_cid.c
|
|
@@ -29,8 +29,9 @@
|
|
|
|
#include "ngtcp2_path.h"
|
|
#include "ngtcp2_str.h"
|
|
+#include "ngtcp2_pkt.h"
|
|
|
|
-void ngtcp2_cid_zero(ngtcp2_cid *cid) { memset(cid, 0, sizeof(*cid)); }
|
|
+void ngtcp2_cid_zero(ngtcp2_cid *cid) { *cid = (ngtcp2_cid){0}; }
|
|
|
|
void ngtcp2_cid_init(ngtcp2_cid *cid, const uint8_t *data, size_t datalen) {
|
|
assert(datalen <= NGTCP2_MAX_CIDLEN);
|
|
@@ -58,11 +59,13 @@ int ngtcp2_cid_less(const ngtcp2_cid *lhs, const ngtcp2_cid *rhs) {
|
|
int ngtcp2_cid_empty(const ngtcp2_cid *cid) { return cid->datalen == 0; }
|
|
|
|
void ngtcp2_scid_init(ngtcp2_scid *scid, uint64_t seq, const ngtcp2_cid *cid) {
|
|
- scid->pe.index = NGTCP2_PQ_BAD_INDEX;
|
|
- scid->seq = seq;
|
|
- scid->cid = *cid;
|
|
- scid->retired_ts = UINT64_MAX;
|
|
- scid->flags = NGTCP2_SCID_FLAG_NONE;
|
|
+ *scid = (ngtcp2_scid){
|
|
+ .pe.index = NGTCP2_PQ_BAD_INDEX,
|
|
+ .seq = seq,
|
|
+ .cid = *cid,
|
|
+ .retired_ts = UINT64_MAX,
|
|
+ .flags = NGTCP2_SCID_FLAG_NONE,
|
|
+ };
|
|
}
|
|
|
|
void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
|
|
@@ -72,12 +75,12 @@ void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
|
|
}
|
|
|
|
void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
|
|
- const uint8_t *token) {
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
dcid->seq = seq;
|
|
dcid->cid = *cid;
|
|
|
|
if (token) {
|
|
- memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ dcid->token = *token;
|
|
dcid->flags = NGTCP2_DCID_FLAG_TOKEN_PRESENT;
|
|
} else {
|
|
dcid->flags = NGTCP2_DCID_FLAG_NONE;
|
|
@@ -91,11 +94,12 @@ void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
|
|
dcid->max_udp_payload_size = NGTCP2_MAX_UDP_PAYLOAD_SIZE;
|
|
}
|
|
|
|
-void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token) {
|
|
+void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid,
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
assert(token);
|
|
|
|
dcid->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT;
|
|
- memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ dcid->token = *token;
|
|
}
|
|
|
|
void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path) {
|
|
@@ -104,7 +108,7 @@ void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path) {
|
|
|
|
void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
|
|
ngtcp2_dcid_init(dest, src->seq, &src->cid,
|
|
- (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? src->token
|
|
+ (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? &src->token
|
|
: NULL);
|
|
ngtcp2_path_copy(&dest->ps.path, &src->ps.path);
|
|
dest->retired_ts = src->retired_ts;
|
|
@@ -121,18 +125,19 @@ void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
|
|
|
|
if (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) {
|
|
dest->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT;
|
|
- memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ dest->token = src->token;
|
|
} else if (dest->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) {
|
|
dest->flags &= (uint8_t)~NGTCP2_DCID_FLAG_TOKEN_PRESENT;
|
|
}
|
|
}
|
|
|
|
int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
|
|
- const ngtcp2_cid *cid, const uint8_t *token) {
|
|
+ const ngtcp2_cid *cid,
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
if (dcid->seq == seq) {
|
|
return ngtcp2_cid_eq(&dcid->cid, cid) &&
|
|
(dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
|
|
- memcmp(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN) == 0
|
|
+ ngtcp2_stateless_reset_token_eq(&dcid->token, token)
|
|
? 0
|
|
: NGTCP2_ERR_PROTO;
|
|
}
|
|
@@ -140,12 +145,12 @@ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
|
|
return !ngtcp2_cid_eq(&dcid->cid, cid) ? 0 : NGTCP2_ERR_PROTO;
|
|
}
|
|
|
|
-int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
|
|
- const ngtcp2_path *path,
|
|
- const uint8_t *token) {
|
|
+int ngtcp2_dcid_verify_stateless_reset_token(
|
|
+ const ngtcp2_dcid *dcid, const ngtcp2_path *path,
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
return ngtcp2_path_eq(&dcid->ps.path, path) &&
|
|
(dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
|
|
- ngtcp2_cmemeq(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN)
|
|
+ ngtcp2_cmemeq(dcid->token.data, token->data, sizeof(token->data))
|
|
? 0
|
|
: NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_cid.h b/third_party/ngtcp2/lib/ngtcp2_cid.h
|
|
index 9321cfb64e6..f4956b0bac0 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_cid.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_cid.h
|
|
@@ -35,13 +35,13 @@
|
|
#include "ngtcp2_path.h"
|
|
|
|
/* NGTCP2_SCID_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_SCID_FLAG_NONE 0x00u
|
|
+#define NGTCP2_SCID_FLAG_NONE 0x00U
|
|
/* NGTCP2_SCID_FLAG_USED indicates that a local endpoint observed that
|
|
a remote endpoint uses this particular Connection ID. */
|
|
-#define NGTCP2_SCID_FLAG_USED 0x01u
|
|
+#define NGTCP2_SCID_FLAG_USED 0x01U
|
|
/* NGTCP2_SCID_FLAG_RETIRED indicates that this particular Connection
|
|
ID is retired. */
|
|
-#define NGTCP2_SCID_FLAG_RETIRED 0x02u
|
|
+#define NGTCP2_SCID_FLAG_RETIRED 0x02U
|
|
|
|
typedef struct ngtcp2_scid {
|
|
ngtcp2_pq_entry pe;
|
|
@@ -57,13 +57,13 @@ typedef struct ngtcp2_scid {
|
|
} ngtcp2_scid;
|
|
|
|
/* NGTCP2_DCID_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_DCID_FLAG_NONE 0x00u
|
|
+#define NGTCP2_DCID_FLAG_NONE 0x00U
|
|
/* NGTCP2_DCID_FLAG_PATH_VALIDATED indicates that an associated path
|
|
has been validated. */
|
|
-#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01u
|
|
+#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01U
|
|
/* NGTCP2_DCID_FLAG_TOKEN_PRESENT indicates that a stateless reset
|
|
token is set in token field. */
|
|
-#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02u
|
|
+#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02U
|
|
|
|
typedef struct ngtcp2_dcid {
|
|
/* seq is the sequence number associated to the Connection ID. */
|
|
@@ -93,7 +93,7 @@ typedef struct ngtcp2_dcid {
|
|
/* token is a stateless reset token received along with this
|
|
Connection ID. The stateless reset token is tied to the
|
|
connection, not to the particular Connection ID. */
|
|
- uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
|
|
+ ngtcp2_stateless_reset_token token;
|
|
} ngtcp2_dcid;
|
|
|
|
/* ngtcp2_cid_zero makes |cid| zero-length. */
|
|
@@ -123,17 +123,18 @@ void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src);
|
|
|
|
/*
|
|
* ngtcp2_dcid_init initializes |dcid| with the given parameters. If
|
|
- * |token| is NULL, the function fills dcid->token with 0. |token|
|
|
- * must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
|
|
+ * |token| is not NULL, the function sets
|
|
+ * NGTCP2_DCID_FLAG_TOKEN_PRESENT flag.
|
|
*/
|
|
void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
|
|
- const uint8_t *token);
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/*
|
|
* ngtcp2_dcid_set_token sets |token| to |dcid|. |token| must not be
|
|
- * NULL, and must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
|
|
+ * NULL.
|
|
*/
|
|
-void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token);
|
|
+void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid,
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/*
|
|
* ngtcp2_dcid_set_path sets |path| to |dcid|. It sets
|
|
@@ -160,7 +161,8 @@ void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src);
|
|
* |token|) tuple against |dcid|.
|
|
*/
|
|
int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
|
|
- const ngtcp2_cid *cid, const uint8_t *token);
|
|
+ const ngtcp2_cid *cid,
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/*
|
|
* ngtcp2_dcid_verify_stateless_reset_token verifies stateless reset
|
|
@@ -172,9 +174,9 @@ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
|
|
* NGTCP2_ERR_INVALID_ARGUMENT
|
|
* Tokens do not match; or |dcid| does not contain a token.
|
|
*/
|
|
-int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
|
|
- const ngtcp2_path *path,
|
|
- const uint8_t *token);
|
|
+int ngtcp2_dcid_verify_stateless_reset_token(
|
|
+ const ngtcp2_dcid *dcid, const ngtcp2_path *path,
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/* TODO It might be performance win if we store congestion state in
|
|
this entry, and restore it when migrate back to this path. */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_conn.c b/third_party/ngtcp2/lib/ngtcp2_conn.c
|
|
index 6abebee33a8..c470eb05b06 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_conn.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_conn.c
|
|
@@ -39,8 +39,10 @@
|
|
#include "ngtcp2_net.h"
|
|
#include "ngtcp2_transport_params.h"
|
|
#include "ngtcp2_settings.h"
|
|
+#include "ngtcp2_callbacks.h"
|
|
#include "ngtcp2_tstamp.h"
|
|
#include "ngtcp2_frame_chain.h"
|
|
+#include "ngtcp2_conn_info.h"
|
|
|
|
/* NGTCP2_FLOW_WINDOW_RTT_FACTOR is the factor of RTT when flow
|
|
control window auto-tuning is triggered. */
|
|
@@ -253,13 +255,20 @@ static int conn_call_extend_max_local_streams_uni(ngtcp2_conn *conn,
|
|
}
|
|
|
|
static int conn_call_get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
|
- uint8_t *token, size_t cidlen) {
|
|
+ ngtcp2_stateless_reset_token *token,
|
|
+ size_t cidlen) {
|
|
int rv;
|
|
|
|
- assert(conn->callbacks.get_new_connection_id);
|
|
+ if (conn->callbacks.get_new_connection_id2) {
|
|
+ rv = conn->callbacks.get_new_connection_id2(conn, cid, token, cidlen,
|
|
+ conn->user_data);
|
|
+ } else {
|
|
+ assert(conn->callbacks.get_new_connection_id);
|
|
+
|
|
+ rv = conn->callbacks.get_new_connection_id(conn, cid, token->data, cidlen,
|
|
+ conn->user_data);
|
|
+ }
|
|
|
|
- rv = conn->callbacks.get_new_connection_id(conn, cid, token, cidlen,
|
|
- conn->user_data);
|
|
if (rv != 0) {
|
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
}
|
|
@@ -283,11 +292,38 @@ static int conn_call_remove_connection_id(ngtcp2_conn *conn,
|
|
return 0;
|
|
}
|
|
|
|
+static int conn_call_begin_path_validation(ngtcp2_conn *conn,
|
|
+ const ngtcp2_pv *pv) {
|
|
+ int rv;
|
|
+ uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE;
|
|
+ const ngtcp2_path *fallback_path = NULL;
|
|
+
|
|
+ if (!pv || !conn->callbacks.begin_path_validation) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (pv->flags & NGTCP2_PV_FLAG_PREFERRED_ADDR) {
|
|
+ flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR;
|
|
+ }
|
|
+
|
|
+ if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) {
|
|
+ fallback_path = &pv->fallback_dcid.ps.path;
|
|
+ }
|
|
+
|
|
+ rv = conn->callbacks.begin_path_validation(conn, flags, &pv->dcid.ps.path,
|
|
+ fallback_path, conn->user_data);
|
|
+ if (rv != 0) {
|
|
+ return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv,
|
|
ngtcp2_path_validation_result res) {
|
|
int rv;
|
|
uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE;
|
|
- const ngtcp2_path *old_path = NULL;
|
|
+ const ngtcp2_path *fallback_path = NULL;
|
|
|
|
if (!conn->callbacks.path_validation) {
|
|
return 0;
|
|
@@ -298,17 +334,17 @@ static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv,
|
|
}
|
|
|
|
if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) {
|
|
- old_path = &pv->fallback_dcid.ps.path;
|
|
+ fallback_path = &pv->fallback_dcid.ps.path;
|
|
}
|
|
|
|
- if (conn->server && old_path &&
|
|
- (ngtcp2_addr_cmp(&pv->dcid.ps.path.remote, &old_path->remote) &
|
|
+ if (conn->server && fallback_path &&
|
|
+ (ngtcp2_addr_cmp(&pv->dcid.ps.path.remote, &fallback_path->remote) &
|
|
(NGTCP2_ADDR_CMP_FLAG_ADDR | NGTCP2_ADDR_CMP_FLAG_FAMILY))) {
|
|
flags |= NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN;
|
|
}
|
|
|
|
- rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, old_path,
|
|
- res, conn->user_data);
|
|
+ rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path,
|
|
+ fallback_path, res, conn->user_data);
|
|
if (rv != 0) {
|
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
}
|
|
@@ -395,14 +431,20 @@ static int conn_call_dcid_status(ngtcp2_conn *conn,
|
|
const ngtcp2_dcid *dcid) {
|
|
int rv;
|
|
|
|
- if (!conn->callbacks.dcid_status) {
|
|
+ if (conn->callbacks.dcid_status2) {
|
|
+ rv = conn->callbacks.dcid_status2(
|
|
+ conn, type, dcid->seq, &dcid->cid,
|
|
+ (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? &dcid->token : NULL,
|
|
+ conn->user_data);
|
|
+ } else if (conn->callbacks.dcid_status) {
|
|
+ rv = conn->callbacks.dcid_status(
|
|
+ conn, type, dcid->seq, &dcid->cid,
|
|
+ (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token.data : NULL,
|
|
+ conn->user_data);
|
|
+ } else {
|
|
return 0;
|
|
}
|
|
|
|
- rv = conn->callbacks.dcid_status(
|
|
- conn, type, dcid->seq, &dcid->cid,
|
|
- (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token : NULL,
|
|
- conn->user_data);
|
|
if (rv != 0) {
|
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
}
|
|
@@ -475,12 +517,19 @@ static int conn_call_client_initial(ngtcp2_conn *conn) {
|
|
return 0;
|
|
}
|
|
|
|
-static int conn_call_get_path_challenge_data(ngtcp2_conn *conn, uint8_t *data) {
|
|
+static int conn_call_get_path_challenge_data(ngtcp2_conn *conn,
|
|
+ ngtcp2_path_challenge_data *data) {
|
|
int rv;
|
|
|
|
- assert(conn->callbacks.get_path_challenge_data);
|
|
+ if (conn->callbacks.get_path_challenge_data2) {
|
|
+ rv = conn->callbacks.get_path_challenge_data2(conn, data, conn->user_data);
|
|
+ } else {
|
|
+ assert(conn->callbacks.get_path_challenge_data);
|
|
+
|
|
+ rv = conn->callbacks.get_path_challenge_data(conn, data->data,
|
|
+ conn->user_data);
|
|
+ }
|
|
|
|
- rv = conn->callbacks.get_path_challenge_data(conn, data, conn->user_data);
|
|
if (rv != 0) {
|
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
}
|
|
@@ -521,14 +570,24 @@ static int conn_call_recv_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) {
|
|
|
|
static int
|
|
conn_call_recv_stateless_reset(ngtcp2_conn *conn,
|
|
- const ngtcp2_pkt_stateless_reset *sr) {
|
|
+ const ngtcp2_pkt_stateless_reset2 *sr) {
|
|
int rv;
|
|
+ ngtcp2_pkt_stateless_reset legacy_sr;
|
|
|
|
- if (!conn->callbacks.recv_stateless_reset) {
|
|
+ if (conn->callbacks.recv_stateless_reset2) {
|
|
+ rv = conn->callbacks.recv_stateless_reset2(conn, sr, conn->user_data);
|
|
+ } else if (conn->callbacks.recv_stateless_reset) {
|
|
+ memcpy(legacy_sr.stateless_reset_token, sr->token.data,
|
|
+ sizeof(legacy_sr.stateless_reset_token));
|
|
+ legacy_sr.rand = sr->rand;
|
|
+ legacy_sr.randlen = sr->randlen;
|
|
+
|
|
+ rv =
|
|
+ conn->callbacks.recv_stateless_reset(conn, &legacy_sr, conn->user_data);
|
|
+ } else {
|
|
return 0;
|
|
}
|
|
|
|
- rv = conn->callbacks.recv_stateless_reset(conn, sr, conn->user_data);
|
|
if (rv != 0) {
|
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
}
|
|
@@ -668,13 +727,15 @@ static int conn_call_recv_tx_key(ngtcp2_conn *conn,
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * pktns_init initializes |pktns|. It assumes that the object pointed
|
|
+ * by |pktns| is zero-cleared.
|
|
+ */
|
|
static void pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id,
|
|
ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num,
|
|
ngtcp2_log *log, ngtcp2_qlog *qlog,
|
|
ngtcp2_objalloc *rtb_entry_objalloc,
|
|
ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
|
|
- memset(pktns, 0, sizeof(*pktns));
|
|
-
|
|
ngtcp2_gaptr_init(&pktns->rx.pngap, mem);
|
|
|
|
pktns->tx.last_pkt_num = initial_pkt_num - 1;
|
|
@@ -696,7 +757,7 @@ static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id,
|
|
ngtcp2_log *log, ngtcp2_qlog *qlog,
|
|
ngtcp2_objalloc *rtb_entry_objalloc,
|
|
ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
|
|
- *ppktns = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pktns));
|
|
+ *ppktns = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_pktns));
|
|
if (*ppktns == NULL) {
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
@@ -809,8 +870,8 @@ static void conn_reset_conn_stat_cc(ngtcp2_conn *conn,
|
|
*/
|
|
static void reset_conn_stat_recovery(ngtcp2_conn_stat *cstat) {
|
|
/* Initializes them with UINT64_MAX. */
|
|
- memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time));
|
|
- memset(cstat->last_tx_pkt_ts, 0xff, sizeof(cstat->last_tx_pkt_ts));
|
|
+ memset(cstat->loss_time, 0xFF, sizeof(cstat->loss_time));
|
|
+ memset(cstat->last_tx_pkt_ts, 0xFF, sizeof(cstat->last_tx_pkt_ts));
|
|
}
|
|
|
|
/*
|
|
@@ -1033,16 +1094,31 @@ conn_set_local_transport_params(ngtcp2_conn *conn,
|
|
}
|
|
|
|
static void conn_update_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns) {
|
|
- uint8_t gap;
|
|
+ const int64_t min_gap = 3;
|
|
+ uint8_t r;
|
|
+ int64_t gap;
|
|
+
|
|
+ assert(INT64_MAX != pktns->tx.skip_pkt.next_pkt_num);
|
|
+
|
|
+ conn->callbacks.rand(&r, 1, &conn->local.settings.rand_ctx);
|
|
+
|
|
+ if (1LL << pktns->tx.skip_pkt.exponent >
|
|
+ (NGTCP2_MAX_PKT_NUM - min_gap) / ((int64_t)r + 1)) {
|
|
+ pktns->tx.skip_pkt.next_pkt_num = INT64_MAX;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ gap = ((int64_t)r + 1) * (1LL << pktns->tx.skip_pkt.exponent++) + min_gap;
|
|
|
|
- conn->callbacks.rand(&gap, 1, &conn->local.settings.rand_ctx);
|
|
+ if (pktns->tx.last_pkt_num > NGTCP2_MAX_PKT_NUM - gap) {
|
|
+ pktns->tx.skip_pkt.next_pkt_num = INT64_MAX;
|
|
+ return;
|
|
+ }
|
|
|
|
- pktns->tx.skip_pkt.next_pkt_num =
|
|
- pktns->tx.last_pkt_num + 3 +
|
|
- (int64_t)gap * (1ll << pktns->tx.skip_pkt.exponent++);
|
|
+ pktns->tx.skip_pkt.next_pkt_num = pktns->tx.last_pkt_num + gap;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "next skip pkn=%" PRId64,
|
|
- pktns->tx.skip_pkt.next_pkt_num);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "next skip pkn=%" PRId64,
|
|
+ pktns->tx.skip_pkt.next_pkt_num);
|
|
}
|
|
|
|
static int conn_handle_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
@@ -1109,18 +1185,21 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
|
|
uint32_t *preferred_versions;
|
|
ngtcp2_settings settingsbuf;
|
|
ngtcp2_transport_params paramsbuf;
|
|
- (void)callbacks_version;
|
|
+ ngtcp2_callbacks callbacksbuf;
|
|
+ uint64_t seed;
|
|
(void)settings_version;
|
|
|
|
settings =
|
|
ngtcp2_settings_convert_to_latest(&settingsbuf, settings_version, settings);
|
|
params = ngtcp2_transport_params_convert_to_latest(
|
|
¶msbuf, transport_params_version, params);
|
|
+ callbacks = ngtcp2_callbacks_convert_to_latest(&callbacksbuf,
|
|
+ callbacks_version, callbacks);
|
|
|
|
assert(settings->max_window <= NGTCP2_MAX_VARINT);
|
|
assert(settings->max_stream_window <= NGTCP2_MAX_VARINT);
|
|
- assert(settings->max_tx_udp_payload_size);
|
|
- assert(settings->max_tx_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE);
|
|
+ assert(settings->max_tx_udp_payload_size >= NGTCP2_MAX_UDP_PAYLOAD_SIZE);
|
|
+ assert(settings->max_tx_udp_payload_size <= NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE);
|
|
assert(settings->initial_pkt_num <= INT32_MAX);
|
|
assert(settings->initial_rtt);
|
|
assert(params->active_connection_id_limit >=
|
|
@@ -1147,15 +1226,17 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
|
|
assert(callbacks->hp_mask);
|
|
assert(server || callbacks->recv_retry);
|
|
assert(callbacks->rand);
|
|
- assert(callbacks->get_new_connection_id);
|
|
+ assert(callbacks->get_new_connection_id2 || callbacks->get_new_connection_id);
|
|
assert(callbacks->update_key);
|
|
assert(callbacks->delete_crypto_aead_ctx);
|
|
assert(callbacks->delete_crypto_cipher_ctx);
|
|
- assert(callbacks->get_path_challenge_data);
|
|
+ assert(callbacks->get_path_challenge_data2 ||
|
|
+ callbacks->get_path_challenge_data);
|
|
assert(!server || !ngtcp2_is_reserved_version(client_chosen_version));
|
|
|
|
for (i = 0; i < settings->pmtud_probeslen; ++i) {
|
|
assert(settings->pmtud_probes[i] > NGTCP2_MAX_UDP_PAYLOAD_SIZE);
|
|
+ assert(settings->pmtud_probes[i] <= NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE);
|
|
}
|
|
|
|
if (mem == NULL) {
|
|
@@ -1217,7 +1298,11 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
|
|
|
|
ngtcp2_pq_init(&(*pconn)->scid.used, retired_ts_less, mem);
|
|
|
|
- ngtcp2_map_init(&(*pconn)->strms, mem);
|
|
+ callbacks->rand((uint8_t *)&seed, sizeof(seed), &settings->rand_ctx);
|
|
+ ngtcp2_map_init(&(*pconn)->strms, seed, mem);
|
|
+
|
|
+ callbacks->rand((uint8_t *)&seed, sizeof(seed), &settings->rand_ctx);
|
|
+ ngtcp2_pcg32_init(&(*pconn)->pcg, seed);
|
|
|
|
ngtcp2_pq_init(&(*pconn)->tx.strmq, cycle_less, mem);
|
|
|
|
@@ -1284,17 +1369,17 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
|
|
|
|
switch (settings->cc_algo) {
|
|
case NGTCP2_CC_ALGO_RENO:
|
|
- ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log);
|
|
+ ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log, &(*pconn)->cstat);
|
|
|
|
break;
|
|
case NGTCP2_CC_ALGO_CUBIC:
|
|
- ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log, &(*pconn)->rst);
|
|
+ ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log, &(*pconn)->cstat,
|
|
+ &(*pconn)->rst);
|
|
|
|
break;
|
|
case NGTCP2_CC_ALGO_BBR:
|
|
ngtcp2_cc_bbr_init(&(*pconn)->bbr, &(*pconn)->log, &(*pconn)->cstat,
|
|
- &(*pconn)->rst, settings->initial_ts, callbacks->rand,
|
|
- &settings->rand_ctx);
|
|
+ &(*pconn)->rst, settings->initial_ts, &(*pconn)->pcg);
|
|
|
|
break;
|
|
default:
|
|
@@ -1303,6 +1388,9 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
|
|
|
|
ngtcp2_static_ringbuf_path_history_init(&(*pconn)->path_history);
|
|
|
|
+ ngtcp2_ratelim_init(&(*pconn)->glitch_rlim, settings->glitch_ratelim_burst,
|
|
+ settings->glitch_ratelim_rate, settings->initial_ts);
|
|
+
|
|
(*pconn)->callbacks = *callbacks;
|
|
|
|
rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst,
|
|
@@ -1470,6 +1558,8 @@ fail_seqgap_push:
|
|
fail_token:
|
|
ngtcp2_mem_free(mem, *pconn);
|
|
|
|
+ *pconn = NULL;
|
|
+
|
|
return rv;
|
|
}
|
|
|
|
@@ -1492,10 +1582,13 @@ int ngtcp2_conn_client_new_versioned(
|
|
(*pconn)->state = NGTCP2_CS_CLIENT_INITIAL;
|
|
(*pconn)->local.bidi.next_stream_id = 0;
|
|
(*pconn)->local.uni.next_stream_id = 2;
|
|
+ (*pconn)->flags |= NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO;
|
|
|
|
rv = ngtcp2_conn_commit_local_transport_params(*pconn);
|
|
if (rv != 0) {
|
|
ngtcp2_conn_del(*pconn);
|
|
+ *pconn = NULL;
|
|
+
|
|
return rv;
|
|
}
|
|
|
|
@@ -1753,8 +1846,18 @@ static int conn_ppe_write_frame(ngtcp2_conn *conn, ngtcp2_ppe *ppe,
|
|
static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
ngtcp2_rtb_entry *ent) {
|
|
ngtcp2_rtb *rtb = &pktns->rtb;
|
|
+ ngtcp2_cc_pkt cc_pkt;
|
|
int rv;
|
|
|
|
+ if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
|
|
+ conn->cc.on_pkt_sent) {
|
|
+ conn->cc.on_pkt_sent(
|
|
+ &conn->cc, &conn->cstat,
|
|
+ ngtcp2_cc_pkt_init(&cc_pkt, ent->hd.pkt_num, ent->pktlen, pktns->id,
|
|
+ ent->ts, /* lost = */ 0,
|
|
+ /* tx_in_flight = */ 0, /* is_app_limited = */ 0));
|
|
+ }
|
|
+
|
|
/* This function implements OnPacketSent, but it handles only
|
|
non-ACK-only packet. */
|
|
rv = ngtcp2_rtb_add(rtb, ent, &conn->cstat);
|
|
@@ -1788,13 +1891,13 @@ static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) {
|
|
|
|
n = n * 2 - 1;
|
|
|
|
- if (n > 0xffffff) {
|
|
+ if (n > 0xFFFFFF) {
|
|
return 4;
|
|
}
|
|
- if (n > 0xffff) {
|
|
+ if (n > 0xFFFF) {
|
|
return 3;
|
|
}
|
|
- if (n > 0xff) {
|
|
+ if (n > 0xFF) {
|
|
return 2;
|
|
}
|
|
return 1;
|
|
@@ -1809,9 +1912,9 @@ static int conn_cwnd_is_zero(ngtcp2_conn *conn) {
|
|
uint64_t cwnd = conn->cstat.cwnd;
|
|
|
|
if (bytes_in_flight >= cwnd) {
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "cwnd limited bytes_in_flight=%lu cwnd=%lu",
|
|
- bytes_in_flight, cwnd);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "cwnd limited bytes_in_flight=%lu cwnd=%lu",
|
|
+ bytes_in_flight, cwnd);
|
|
}
|
|
|
|
return bytes_in_flight >= cwnd;
|
|
@@ -1902,6 +2005,16 @@ static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used,
|
|
return 0;
|
|
}
|
|
|
|
+static int conn_can_send_next_pkt(ngtcp2_conn *conn, size_t left,
|
|
+ uint64_t min_payloadlen) {
|
|
+ /* TODO the next packet type should be taken into account */
|
|
+ return left >=
|
|
+ /* TODO Assuming that pkt_num is encoded in 1 byte. */
|
|
+ NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen +
|
|
+ conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen +
|
|
+ NGTCP2_MAX_AEAD_OVERHEAD;
|
|
+}
|
|
+
|
|
/*
|
|
* conn_should_pad_pkt returns nonzero if the packet should be padded.
|
|
* |type| is the type of packet. |left| is the space left in packet
|
|
@@ -1948,26 +2061,30 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left,
|
|
return 1;
|
|
}
|
|
}
|
|
- } else {
|
|
- assert(type == NGTCP2_PKT_HANDSHAKE);
|
|
|
|
- if (!require_padding) {
|
|
- return 0;
|
|
- }
|
|
+ return !conn_can_send_next_pkt(conn, left, min_payloadlen);
|
|
+ }
|
|
|
|
- if (!conn->pktns.crypto.tx.ckm) {
|
|
- return 1;
|
|
- }
|
|
+ assert(type == NGTCP2_PKT_HANDSHAKE);
|
|
|
|
- min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN;
|
|
+ if (!require_padding) {
|
|
+ /* If we have 1RTT key, pad this Handshake packet so that the next
|
|
+ 1RTT packet can be squeezed into the same GSO buffer. */
|
|
+ return conn->pktns.crypto.tx.ckm &&
|
|
+ !conn_can_send_next_pkt(conn, left, NGTCP2_MIN_COALESCED_PAYLOADLEN);
|
|
}
|
|
|
|
- /* TODO the next packet type should be taken into account */
|
|
- return left <
|
|
- /* TODO Assuming that pkt_num is encoded in 1 byte. */
|
|
- NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen +
|
|
- conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen +
|
|
- NGTCP2_MAX_AEAD_OVERHEAD;
|
|
+ if (!conn->pktns.crypto.tx.ckm) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* We might send Handshake packet even if exceeding CWND. In that
|
|
+ case, we do not write non-probe 1RTT packet. */
|
|
+ if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return !conn_can_send_next_pkt(conn, left, NGTCP2_MIN_COALESCED_PAYLOADLEN);
|
|
}
|
|
|
|
static void conn_restart_timer_on_write(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
@@ -2095,6 +2212,215 @@ static uint8_t conn_pkt_flags_short(ngtcp2_conn *conn) {
|
|
: NGTCP2_PKT_FLAG_NONE));
|
|
}
|
|
|
|
+/*
|
|
+ * conn_cut_crypto_frame splits frc->fr.stream by removing
|
|
+ * |removed_data| from frc->fr.stream.data[0]. frc->fr.stream.data[0]
|
|
+ * must contain |removed_data|, and frc->fr.stream.datacnt >= 1. New
|
|
+ * ngtcp2_frame_chain object that contains |removed_data| is created,
|
|
+ * and pushed to |crypto_strm| via ngtcp2_strm_streamfrq_push. If
|
|
+ * there are data following the removed part of data, new
|
|
+ * ngtcp2_frame_chain object is created for it, and frc->next points
|
|
+ * to the object.
|
|
+ *
|
|
+ * This function returns 0 if it succeeds, or one of the following
|
|
+ * negative error codes:
|
|
+ *
|
|
+ * NGTCP2_ERR_NOMEM
|
|
+ * Out of memory
|
|
+ */
|
|
+static int conn_cut_crypto_frame(ngtcp2_conn *conn, ngtcp2_frame_chain *frc,
|
|
+ ngtcp2_strm *crypto_strm,
|
|
+ const ngtcp2_vec *removed_data) {
|
|
+ ngtcp2_vec *data = frc->fr.stream.data;
|
|
+ size_t datacnt = frc->fr.stream.datacnt;
|
|
+ size_t ndatacnt;
|
|
+ ngtcp2_frame_chain *right_frc = NULL, *removed_frc;
|
|
+ size_t offset;
|
|
+ int rv;
|
|
+
|
|
+ assert(datacnt);
|
|
+ assert(data[0].base < removed_data->base);
|
|
+ assert(ngtcp2_vec_end(removed_data) <= ngtcp2_vec_end(&data[0]));
|
|
+
|
|
+ offset = (size_t)(removed_data->base - data->base);
|
|
+
|
|
+ rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
+ &removed_frc, 1, &conn->frc_objalloc, conn->mem);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ /* ngtcp2_frame_chain for the removed data */
|
|
+ removed_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
|
|
+ removed_frc->fr.stream.flags = 0;
|
|
+ removed_frc->fr.stream.fin = 0;
|
|
+ removed_frc->fr.stream.stream_id = 0;
|
|
+ removed_frc->fr.stream.offset = frc->fr.stream.offset + offset;
|
|
+ removed_frc->fr.stream.datacnt = 1;
|
|
+ removed_frc->fr.stream.data[0] = (ngtcp2_vec){
|
|
+ .base = data->base + offset,
|
|
+ .len = removed_data->len,
|
|
+ };
|
|
+
|
|
+ rv = ngtcp2_strm_streamfrq_push(crypto_strm, removed_frc);
|
|
+ if (rv != 0) {
|
|
+ ngtcp2_frame_chain_objalloc_del(removed_frc, &conn->frc_objalloc,
|
|
+ conn->mem);
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ if (data[0].len == offset + removed_data->len) {
|
|
+ ndatacnt = datacnt - 1;
|
|
+ } else {
|
|
+ ndatacnt = datacnt;
|
|
+ }
|
|
+
|
|
+ if (ndatacnt) {
|
|
+ /* ngtcp2_frame_chain after the removed data */
|
|
+ rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
+ &right_frc, ndatacnt, &conn->frc_objalloc, conn->mem);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ right_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
|
|
+ right_frc->fr.stream.offset =
|
|
+ removed_frc->fr.stream.offset + removed_frc->fr.stream.data->len;
|
|
+ right_frc->fr.stream.datacnt = 0;
|
|
+ ngtcp2_vec_split(right_frc->fr.stream.data, &right_frc->fr.stream.datacnt,
|
|
+ data, &datacnt, offset + removed_data->len, ndatacnt);
|
|
+
|
|
+ assert(ndatacnt == right_frc->fr.stream.datacnt);
|
|
+ assert(1 == datacnt);
|
|
+ }
|
|
+
|
|
+ frc->fr.stream.datacnt = 1;
|
|
+ frc->fr.stream.data[0].len = offset;
|
|
+ frc->next = right_frc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * conn_crumble_initial_crypto splits CRYPTO frame (*pfrc)->fr.stream
|
|
+ * into pieces and adds PADDING and PING frames, and reorder those
|
|
+ * frames. Those frames are encoded in the buffer pointed by |data|
|
|
+ * and |offsets|. |data| is the pointer to the array of ngtcp2_vec of
|
|
+ * at least NGTCP2_MAX_STREAM_DATACNT. |offsets| contains the CRYPTO
|
|
+ * offset of the corresponding ngtcp2_vec in |data|, and it also
|
|
+ * should have the capacity at least NGTCP2_MAX_STREAM_DATACNT
|
|
+ * uint64_t. |left| is the number of bytes available for the current
|
|
+ * packet. |crypto_offset| is the next smallest CRYPTO offset.
|
|
+ * |crypto_strm| is the CRYPTO stream.
|
|
+ *
|
|
+ * This function returns the number of objects written to |data| and
|
|
+ * |offsets|, or one of the following negative error codes:
|
|
+ *
|
|
+ * NGTCP2_ERR_NOMEM
|
|
+ * Out of memory
|
|
+ */
|
|
+static ngtcp2_ssize
|
|
+conn_crumble_initial_crypto(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc,
|
|
+ ngtcp2_vec *data, uint64_t *offsets,
|
|
+ ngtcp2_strm *crypto_strm, size_t left,
|
|
+ uint64_t crypto_offset) {
|
|
+ ngtcp2_vec server_name;
|
|
+ ngtcp2_vec removed_data;
|
|
+ size_t max_add_frames = 10;
|
|
+ size_t single_crypto_overhead =
|
|
+ 1 + ngtcp2_put_uvarintlen(crypto_offset + left - 1) +
|
|
+ ngtcp2_put_uvarintlen(left);
|
|
+ size_t total_crypto_overhead = single_crypto_overhead * max_add_frames;
|
|
+ size_t datacnt;
|
|
+ size_t i;
|
|
+ int rv;
|
|
+
|
|
+ if (left <= total_crypto_overhead) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ left -= total_crypto_overhead;
|
|
+
|
|
+ left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
|
|
+ if (left == (size_t)-1) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rv = ngtcp2_strm_streamfrq_pop(crypto_strm, pfrc, left);
|
|
+ if (rv != 0) {
|
|
+ assert(ngtcp2_err_is_fatal(rv));
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ if (*pfrc == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ assert(crypto_offset == (*pfrc)->fr.stream.offset);
|
|
+
|
|
+ ngtcp2_vec_copy(data, (*pfrc)->fr.stream.data, (*pfrc)->fr.stream.datacnt);
|
|
+ datacnt = (*pfrc)->fr.stream.datacnt;
|
|
+
|
|
+ offsets[0] = (*pfrc)->fr.stream.offset;
|
|
+
|
|
+ for (i = 1; i < datacnt; ++i) {
|
|
+ offsets[i] = offsets[i - 1] + data[i - 1].len;
|
|
+ }
|
|
+
|
|
+ if (datacnt < NGTCP2_MAX_STREAM_DATACNT &&
|
|
+ ngtcp2_pkt_find_server_name(&server_name, data) && server_name.len > 1) {
|
|
+ if (ngtcp2_strm_streamfrq_empty(crypto_strm) ||
|
|
+ ngtcp2_strm_streamfrq_unacked_offset(crypto_strm) == (uint64_t)-1) {
|
|
+ datacnt = ngtcp2_pkt_split_vec_at(
|
|
+ data, datacnt, offsets,
|
|
+ (size_t)(server_name.base - data[0].base) + server_name.len / 2);
|
|
+ } else {
|
|
+ /* If we have another data to send (most likely in the another
|
|
+ packet), remove the part of SNI from this packet. */
|
|
+ datacnt = ngtcp2_pkt_remove_vec_partial(
|
|
+ &removed_data, data, datacnt, offsets, &conn->pcg, &server_name);
|
|
+
|
|
+ rv = conn_cut_crypto_frame(conn, *pfrc, crypto_strm, &removed_data);
|
|
+ if (rv != 0) {
|
|
+ ngtcp2_frame_chain_objalloc_del(*pfrc, &conn->frc_objalloc, conn->mem);
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ /* Add the length of removed data to total_crypto_overhead so
|
|
+ that we can use them for inter CRYPTO frames padding. */
|
|
+ total_crypto_overhead += removed_data.len;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (datacnt < max_add_frames + 1) {
|
|
+ max_add_frames -= datacnt - 1;
|
|
+
|
|
+ datacnt = ngtcp2_pkt_split_vec_rand(data, datacnt, offsets, &conn->pcg,
|
|
+ max_add_frames);
|
|
+ }
|
|
+
|
|
+ for (i = 1; i < datacnt; ++i) {
|
|
+ total_crypto_overhead -= 1 + ngtcp2_put_uvarintlen(offsets[i]) +
|
|
+ ngtcp2_put_uvarintlen(data[i].len);
|
|
+ }
|
|
+
|
|
+ datacnt = ngtcp2_pkt_append_ping_and_padding(data, datacnt, &conn->pcg,
|
|
+ total_crypto_overhead);
|
|
+
|
|
+ ngtcp2_pkt_permutate_vec(data, datacnt, offsets, &conn->pcg);
|
|
+
|
|
+ return (ngtcp2_ssize)datacnt;
|
|
+}
|
|
+
|
|
+static size_t conn_dgram_padding(ngtcp2_conn *conn, ngtcp2_ppe *ppe) {
|
|
+ if (conn->local.settings.no_tx_udp_payload_size_shaping) {
|
|
+ return ngtcp2_ppe_dgram_padding_size(
|
|
+ ppe, conn->local.settings.max_tx_udp_payload_size);
|
|
+ }
|
|
+
|
|
+ return ngtcp2_ppe_dgram_padding(ppe);
|
|
+}
|
|
+
|
|
static size_t conn_min_pktlen(ngtcp2_conn *conn);
|
|
|
|
/*
|
|
@@ -2125,8 +2451,8 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
ngtcp2_pkt_hd hd;
|
|
ngtcp2_frame_chain *frq = NULL, **pfrc = &frq;
|
|
ngtcp2_frame_chain *nfrc;
|
|
- ngtcp2_max_frame mfr;
|
|
- ngtcp2_frame *ackfr = NULL, lfr;
|
|
+ ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
|
|
+ ngtcp2_frame lfr;
|
|
ngtcp2_ssize spktlen;
|
|
ngtcp2_crypto_cc cc;
|
|
ngtcp2_rtb_entry *rtbent;
|
|
@@ -2201,16 +2527,16 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
return 0;
|
|
}
|
|
|
|
- ackfr = ngtcp2_acktr_create_ack_frame(&pktns->acktr, &mfr.fr, type, ts,
|
|
- /* ack_delay = */ 0,
|
|
- NGTCP2_DEFAULT_ACK_DELAY_EXPONENT);
|
|
- if (ackfr) {
|
|
- rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, ackfr);
|
|
+ lfr.ack.ranges = ack_ranges;
|
|
+ if (ngtcp2_acktr_create_ack_frame(&pktns->acktr, &lfr.ack, type, ts,
|
|
+ /* ack_delay = */ 0,
|
|
+ NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) == 0) {
|
|
+ rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
|
|
if (rv != 0) {
|
|
assert(NGTCP2_ERR_NOBUF == rv);
|
|
} else {
|
|
ngtcp2_acktr_commit_ack(&pktns->acktr);
|
|
- ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, ackfr->ack.largest_ack);
|
|
+ ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, lfr.ack.largest_ack);
|
|
pkt_empty = 0;
|
|
}
|
|
}
|
|
@@ -2221,38 +2547,94 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
|
|
build_pkt:
|
|
for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) {
|
|
- left = ngtcp2_ppe_left(&ppe);
|
|
-
|
|
crypto_offset = ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm);
|
|
if (crypto_offset == (uint64_t)-1) {
|
|
ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm);
|
|
break;
|
|
}
|
|
|
|
- left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
|
|
- if (left == (size_t)-1) {
|
|
+ left = ngtcp2_ppe_left(&ppe);
|
|
+ if (left == 0) {
|
|
break;
|
|
}
|
|
|
|
- rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left);
|
|
- if (rv != 0) {
|
|
- assert(ngtcp2_err_is_fatal(rv));
|
|
- ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
|
|
- conn->mem);
|
|
- return rv;
|
|
- }
|
|
+ if (type == NGTCP2_PKT_INITIAL &&
|
|
+ (conn->flags & NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO)) {
|
|
+ ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
|
|
+ uint64_t offsets[NGTCP2_MAX_STREAM_DATACNT];
|
|
+ ngtcp2_ssize datacnt;
|
|
+ size_t i;
|
|
|
|
- if (nfrc == NULL) {
|
|
- break;
|
|
- }
|
|
+ datacnt = conn_crumble_initial_crypto(
|
|
+ conn, &nfrc, data, offsets, &pktns->crypto.strm, left, crypto_offset);
|
|
+ if (datacnt < 0) {
|
|
+ assert(ngtcp2_err_is_fatal((int)datacnt));
|
|
+ ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
|
|
+ conn->mem);
|
|
|
|
- rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr);
|
|
- if (rv != 0) {
|
|
- ngtcp2_unreachable();
|
|
+ return datacnt;
|
|
+ }
|
|
+
|
|
+ if (datacnt == 0) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < (size_t)datacnt; ++i) {
|
|
+ if (data[i].base == NULL) {
|
|
+ if (data[i].len == 0) {
|
|
+ lfr.ping.type = NGTCP2_FRAME_PING;
|
|
+ } else {
|
|
+ lfr.padding = (ngtcp2_padding){
|
|
+ .type = NGTCP2_FRAME_PADDING,
|
|
+ .len = data[i].len,
|
|
+ };
|
|
+ }
|
|
+ } else {
|
|
+ lfr.stream = (ngtcp2_stream){
|
|
+ .type = NGTCP2_FRAME_CRYPTO,
|
|
+ .offset = offsets[i],
|
|
+ .datacnt = 1,
|
|
+ .data = &data[i],
|
|
+ };
|
|
+ }
|
|
+
|
|
+ rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
|
|
+ if (rv != 0) {
|
|
+ ngtcp2_unreachable();
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
|
|
+ if (left == (size_t)-1) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left);
|
|
+ if (rv != 0) {
|
|
+ assert(ngtcp2_err_is_fatal(rv));
|
|
+ ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
|
|
+ conn->mem);
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ if (nfrc == NULL) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ rv =
|
|
+ conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr);
|
|
+ if (rv != 0) {
|
|
+ ngtcp2_unreachable();
|
|
+ }
|
|
}
|
|
|
|
*pfrc = nfrc;
|
|
- pfrc = &(*pfrc)->next;
|
|
+
|
|
+ for (; nfrc->next;) {
|
|
+ nfrc = nfrc->next;
|
|
+ }
|
|
+
|
|
+ pfrc = &nfrc->next;
|
|
|
|
pkt_empty = 0;
|
|
rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
|
|
@@ -2262,7 +2644,9 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
|
|
if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
|
|
pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) {
|
|
- num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1);
|
|
+ num_reclaimed = ngtcp2_rtb_reclaim_on_pto(
|
|
+ &pktns->rtb, conn, pktns,
|
|
+ !conn->server && type == NGTCP2_PKT_INITIAL ? 2 : 1);
|
|
if (num_reclaimed < 0) {
|
|
ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
|
|
conn->mem);
|
|
@@ -2289,7 +2673,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
|
|
if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
|
|
pktns->rtb.probe_pkt_left) {
|
|
- lfr.type = NGTCP2_FRAME_PING;
|
|
+ lfr.ping.type = NGTCP2_FRAME_PING;
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
|
|
if (rv != 0) {
|
|
@@ -2305,7 +2689,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
|
|
if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts,
|
|
conn->cstat.smoothed_rtt, ts)) {
|
|
- lfr.type = NGTCP2_FRAME_PING;
|
|
+ lfr.ping.type = NGTCP2_FRAME_PING;
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
|
|
if (rv != 0) {
|
|
@@ -2334,12 +2718,12 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
conn, type, ngtcp2_ppe_left(&ppe), write_datalen,
|
|
(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) != 0,
|
|
require_padding)) {
|
|
- lfr.type = NGTCP2_FRAME_PADDING;
|
|
- lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
|
|
+ lfr.padding.type = NGTCP2_FRAME_PADDING;
|
|
+ lfr.padding.len = conn_dgram_padding(conn, &ppe);
|
|
} else if (pkt_empty) {
|
|
return 0;
|
|
} else {
|
|
- lfr.type = NGTCP2_FRAME_PADDING;
|
|
+ lfr.padding.type = NGTCP2_FRAME_PADDING;
|
|
lfr.padding.len = ngtcp2_ppe_padding_size(&ppe, conn_min_pktlen(conn));
|
|
min_padded = 1;
|
|
}
|
|
@@ -2402,6 +2786,9 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
|
|
conn->tx.pacing.pktlen += (size_t)spktlen;
|
|
|
|
+ ++conn->cstat.pkt_sent;
|
|
+ conn->cstat.bytes_sent += (uint64_t)spktlen;
|
|
+
|
|
ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
|
|
|
|
++pktns->tx.last_pkt_num;
|
|
@@ -2425,12 +2812,12 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
|
|
static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
uint8_t *dest, size_t destlen,
|
|
uint8_t type, ngtcp2_tstamp ts) {
|
|
- ngtcp2_frame *ackfr;
|
|
ngtcp2_pktns *pktns;
|
|
ngtcp2_duration ack_delay;
|
|
uint64_t ack_delay_exponent;
|
|
ngtcp2_ssize spktlen;
|
|
- ngtcp2_max_frame mfr;
|
|
+ ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
|
|
+ ngtcp2_frame fr;
|
|
|
|
assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING));
|
|
|
|
@@ -2459,15 +2846,15 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return 0;
|
|
}
|
|
|
|
- ackfr = ngtcp2_acktr_create_ack_frame(&pktns->acktr, &mfr.fr, type, ts,
|
|
- ack_delay, ack_delay_exponent);
|
|
- if (!ackfr) {
|
|
+ fr.ack.ranges = ack_ranges;
|
|
+ if (ngtcp2_acktr_create_ack_frame(&pktns->acktr, &fr.ack, type, ts, ack_delay,
|
|
+ ack_delay_exponent) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
spktlen = ngtcp2_conn_write_single_frame_pkt(
|
|
conn, pi, dest, destlen, type, NGTCP2_WRITE_PKT_FLAG_NONE,
|
|
- &conn->dcid.current.cid, ackfr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
|
|
+ &conn->dcid.current.cid, &fr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
|
|
|
|
if (spktlen <= 0) {
|
|
return spktlen;
|
|
@@ -2540,7 +2927,7 @@ static void conn_discard_early_key(ngtcp2_conn *conn) {
|
|
|
|
conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx);
|
|
conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx);
|
|
- memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx));
|
|
+ conn->early.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
|
|
|
|
ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
|
|
conn->early.ckm = NULL;
|
|
@@ -2730,21 +3117,16 @@ static ngtcp2_ssize conn_write_handshake_pkts(ngtcp2_conn *conn,
|
|
dest += nwrite;
|
|
destlen -= (size_t)nwrite;
|
|
|
|
- /* If initial packet size is at least
|
|
- NGTCP2_MAX_UDP_PAYLOAD_SIZE, no extra padding is needed in a
|
|
- subsequent packet. */
|
|
- if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
|
|
- if (conn->server) {
|
|
- it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
|
|
- if (!ngtcp2_ksl_it_end(&it)) {
|
|
- rtbent = ngtcp2_ksl_it_get(&it);
|
|
- if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
|
|
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
- }
|
|
+ if (conn->server) {
|
|
+ it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
|
|
+ if (!ngtcp2_ksl_it_end(&it)) {
|
|
+ rtbent = ngtcp2_ksl_it_get(&it);
|
|
+ if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
|
|
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
}
|
|
- } else {
|
|
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
}
|
|
+ } else {
|
|
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
}
|
|
}
|
|
}
|
|
@@ -2862,58 +3244,59 @@ static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) {
|
|
static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) {
|
|
size_t i, need = conn_required_num_new_connection_id(conn);
|
|
size_t cidlen = conn->oscid.datalen;
|
|
- ngtcp2_cid cid;
|
|
- uint64_t seq;
|
|
int rv;
|
|
- uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
|
|
ngtcp2_frame_chain *nfrc;
|
|
ngtcp2_pktns *pktns = &conn->pktns;
|
|
ngtcp2_scid *scid;
|
|
ngtcp2_ksl_it it;
|
|
|
|
for (i = 0; i < need; ++i) {
|
|
- rv = conn_call_get_new_connection_id(conn, &cid, token, cidlen);
|
|
+ rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
|
|
- if (cid.datalen != cidlen) {
|
|
- return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ nfrc->fr.new_connection_id.type = NGTCP2_FRAME_NEW_CONNECTION_ID;
|
|
+ nfrc->fr.new_connection_id.seq = ++conn->scid.last_seq;
|
|
+ nfrc->fr.new_connection_id.retire_prior_to = 0;
|
|
+
|
|
+ rv = conn_call_get_new_connection_id(conn, &nfrc->fr.new_connection_id.cid,
|
|
+ &nfrc->fr.new_connection_id.token,
|
|
+ cidlen);
|
|
+ if (rv != 0) {
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (nfrc->fr.new_connection_id.cid.datalen != cidlen) {
|
|
+ rv = NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ goto fail;
|
|
}
|
|
|
|
/* Assert uniqueness */
|
|
- it = ngtcp2_ksl_lower_bound(&conn->scid.set, &cid);
|
|
+ it =
|
|
+ ngtcp2_ksl_lower_bound(&conn->scid.set, &nfrc->fr.new_connection_id.cid);
|
|
if (!ngtcp2_ksl_it_end(&it) &&
|
|
- ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it), &cid)) {
|
|
- return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it),
|
|
+ &nfrc->fr.new_connection_id.cid)) {
|
|
+ rv = NGTCP2_ERR_CALLBACK_FAILURE;
|
|
+ goto fail;
|
|
}
|
|
|
|
- seq = ++conn->scid.last_seq;
|
|
-
|
|
scid = ngtcp2_mem_malloc(conn->mem, sizeof(*scid));
|
|
if (scid == NULL) {
|
|
- return NGTCP2_ERR_NOMEM;
|
|
+ rv = NGTCP2_ERR_NOMEM;
|
|
+ goto fail;
|
|
}
|
|
|
|
- ngtcp2_scid_init(scid, seq, &cid);
|
|
+ ngtcp2_scid_init(scid, nfrc->fr.new_connection_id.seq,
|
|
+ &nfrc->fr.new_connection_id.cid);
|
|
|
|
rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scid->cid, scid);
|
|
if (rv != 0) {
|
|
ngtcp2_mem_free(conn->mem, scid);
|
|
- return rv;
|
|
- }
|
|
-
|
|
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
+ goto fail;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_NEW_CONNECTION_ID;
|
|
- nfrc->fr.new_connection_id.seq = seq;
|
|
- nfrc->fr.new_connection_id.retire_prior_to = 0;
|
|
- nfrc->fr.new_connection_id.cid = cid;
|
|
- memcpy(nfrc->fr.new_connection_id.stateless_reset_token, token,
|
|
- sizeof(token));
|
|
nfrc->next = pktns->tx.frq;
|
|
pktns->tx.frq = nfrc;
|
|
|
|
@@ -2923,6 +3306,11 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) {
|
|
}
|
|
|
|
return 0;
|
|
+
|
|
+fail:
|
|
+ ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem);
|
|
+
|
|
+ return rv;
|
|
}
|
|
|
|
static int dcidtr_on_deactivate(const ngtcp2_dcid *dcid, void *user_data) {
|
|
@@ -3082,14 +3470,15 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
ngtcp2_crypto_cc *cc = &conn->pkt.cc;
|
|
ngtcp2_ppe *ppe = &conn->pkt.ppe;
|
|
ngtcp2_pkt_hd *hd = &conn->pkt.hd;
|
|
- ngtcp2_max_frame mfr;
|
|
- ngtcp2_frame *ackfr = NULL, lfr;
|
|
+ ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
|
|
+ ngtcp2_frame lfr;
|
|
ngtcp2_ssize nwrite;
|
|
ngtcp2_frame_chain **pfrc, *nfrc, *frc;
|
|
ngtcp2_rtb_entry *ent;
|
|
ngtcp2_strm *strm;
|
|
int pkt_empty = 1;
|
|
uint64_t ndatalen = 0;
|
|
+ uint64_t wdatalen;
|
|
int send_stream = 0;
|
|
int stream_blocked = 0;
|
|
int send_datagram = 0;
|
|
@@ -3108,11 +3497,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
size_t min_pktlen = conn_min_pktlen(conn);
|
|
int min_padded = 0;
|
|
int padded = 0;
|
|
- ngtcp2_cc_pkt cc_pkt;
|
|
uint64_t crypto_offset;
|
|
uint64_t stream_offset;
|
|
ngtcp2_ssize num_reclaimed;
|
|
- int fin;
|
|
uint64_t target_max_data;
|
|
ngtcp2_conn_stat *cstat = &conn->cstat;
|
|
uint64_t delta;
|
|
@@ -3225,8 +3612,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
|
|
conn->tx.last_max_data_ts = ts;
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_MAX_DATA;
|
|
- nfrc->fr.max_data.max_data = conn->rx.unsent_max_offset + delta;
|
|
+ nfrc->fr.max_data = (ngtcp2_max_data){
|
|
+ .type = NGTCP2_FRAME_MAX_DATA,
|
|
+ .max_data = conn->rx.unsent_max_offset + delta,
|
|
+ };
|
|
nfrc->next = pktns->tx.frq;
|
|
pktns->tx.frq = nfrc;
|
|
|
|
@@ -3261,9 +3650,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
/* PATH_RESPONSE is bound to the path that the corresponding
|
|
PATH_CHALLENGE is received. */
|
|
if (ngtcp2_path_eq(&conn->dcid.current.ps.path, &pcent->ps.path)) {
|
|
- lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
|
|
- memcpy(lfr.path_response.data, pcent->data,
|
|
- sizeof(lfr.path_response.data));
|
|
+ lfr.path_response = (ngtcp2_path_response){
|
|
+ .type = NGTCP2_FRAME_PATH_RESPONSE,
|
|
+ .data = pcent->data,
|
|
+ };
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
|
|
if (rv != 0) {
|
|
@@ -3282,7 +3672,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
|
|
An endpoint that receives a PATH_CHALLENGE on an active
|
|
path SHOULD send a non-probing packet in response. */
|
|
- lfr.type = NGTCP2_FRAME_PING;
|
|
+ lfr.ping.type = NGTCP2_FRAME_PING;
|
|
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
|
|
if (rv != 0) {
|
|
assert(NGTCP2_ERR_NOBUF == rv);
|
|
@@ -3291,20 +3681,19 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
}
|
|
}
|
|
|
|
- ackfr = ngtcp2_acktr_create_ack_frame(
|
|
- &pktns->acktr, &mfr.fr, type, ts, conn_compute_ack_delay(conn),
|
|
- conn->local.transport_params.ack_delay_exponent);
|
|
- if (ackfr) {
|
|
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, ackfr);
|
|
+ lfr.ack.ranges = ack_ranges;
|
|
+ if (ngtcp2_acktr_create_ack_frame(
|
|
+ &pktns->acktr, &lfr.ack, type, ts, conn_compute_ack_delay(conn),
|
|
+ conn->local.transport_params.ack_delay_exponent) == 0) {
|
|
+ rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
|
|
if (rv != 0) {
|
|
assert(NGTCP2_ERR_NOBUF == rv);
|
|
} else {
|
|
ngtcp2_acktr_commit_ack(&pktns->acktr);
|
|
- ngtcp2_acktr_add_ack(&pktns->acktr, hd->pkt_num,
|
|
- ackfr->ack.largest_ack);
|
|
+ ngtcp2_acktr_add_ack(&pktns->acktr, hd->pkt_num, lfr.ack.largest_ack);
|
|
assert(NGTCP2_PKT_1RTT == type);
|
|
- conn_handle_unconfirmed_key_update_from_remote(
|
|
- conn, ackfr->ack.largest_ack, ts);
|
|
+ conn_handle_unconfirmed_key_update_from_remote(conn,
|
|
+ lfr.ack.largest_ack, ts);
|
|
pkt_empty = 0;
|
|
}
|
|
}
|
|
@@ -3319,7 +3708,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
continue;
|
|
}
|
|
|
|
- switch ((*pfrc)->fr.type) {
|
|
+ switch ((*pfrc)->fr.hd.type) {
|
|
case NGTCP2_FRAME_RESET_STREAM:
|
|
strm =
|
|
ngtcp2_conn_find_stream(conn, (*pfrc)->fr.reset_stream.stream_id);
|
|
@@ -3469,11 +3858,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_RESET_STREAM;
|
|
- nfrc->fr.reset_stream.stream_id = strm->stream_id;
|
|
- nfrc->fr.reset_stream.app_error_code =
|
|
- strm->tx.reset_stream_app_error_code;
|
|
- nfrc->fr.reset_stream.final_size = strm->tx.offset;
|
|
+ nfrc->fr.reset_stream = (ngtcp2_reset_stream){
|
|
+ .type = NGTCP2_FRAME_RESET_STREAM,
|
|
+ .stream_id = strm->stream_id,
|
|
+ .app_error_code = strm->tx.reset_stream_app_error_code,
|
|
+ .final_size = strm->tx.offset,
|
|
+ };
|
|
*pfrc = nfrc;
|
|
|
|
strm->flags &= ~NGTCP2_STRM_FLAG_SEND_RESET_STREAM;
|
|
@@ -3512,10 +3902,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_STOP_SENDING;
|
|
- nfrc->fr.stop_sending.stream_id = strm->stream_id;
|
|
- nfrc->fr.stop_sending.app_error_code =
|
|
- strm->tx.stop_sending_app_error_code;
|
|
+ nfrc->fr.stop_sending = (ngtcp2_stop_sending){
|
|
+ .type = NGTCP2_FRAME_STOP_SENDING,
|
|
+ .stream_id = strm->stream_id,
|
|
+ .app_error_code = strm->tx.stop_sending_app_error_code,
|
|
+ };
|
|
*pfrc = nfrc;
|
|
|
|
strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING;
|
|
@@ -3543,9 +3934,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
|
|
- nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
|
|
- nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
|
|
+ nfrc->fr.stream_data_blocked = (ngtcp2_stream_data_blocked){
|
|
+ .type = NGTCP2_FRAME_STREAM_DATA_BLOCKED,
|
|
+ .stream_id = strm->stream_id,
|
|
+ .offset = strm->tx.max_offset,
|
|
+ };
|
|
*pfrc = nfrc;
|
|
|
|
strm->tx.last_blocked_offset = strm->tx.max_offset;
|
|
@@ -3597,10 +3990,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
|
|
strm->tx.last_max_stream_data_ts = ts;
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAM_DATA;
|
|
- nfrc->fr.max_stream_data.stream_id = strm->stream_id;
|
|
- nfrc->fr.max_stream_data.max_stream_data =
|
|
- strm->rx.unsent_max_offset + delta;
|
|
+ nfrc->fr.max_stream_data = (ngtcp2_max_stream_data){
|
|
+ .type = NGTCP2_FRAME_MAX_STREAM_DATA,
|
|
+ .stream_id = strm->stream_id,
|
|
+ .max_stream_data = strm->rx.unsent_max_offset + delta,
|
|
+ };
|
|
*pfrc = nfrc;
|
|
|
|
strm->rx.max_offset = strm->rx.unsent_max_offset =
|
|
@@ -3696,8 +4090,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
assert(ngtcp2_err_is_fatal(rv));
|
|
return rv;
|
|
}
|
|
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI;
|
|
- nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams;
|
|
+ nfrc->fr.max_streams = (ngtcp2_max_streams){
|
|
+ .type = NGTCP2_FRAME_MAX_STREAMS_BIDI,
|
|
+ .max_streams = conn->remote.bidi.unsent_max_streams,
|
|
+ };
|
|
*pfrc = nfrc;
|
|
|
|
conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams;
|
|
@@ -3728,8 +4124,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
assert(ngtcp2_err_is_fatal(rv));
|
|
return rv;
|
|
}
|
|
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI;
|
|
- nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams;
|
|
+ nfrc->fr.max_streams = (ngtcp2_max_streams){
|
|
+ .type = NGTCP2_FRAME_MAX_STREAMS_UNI,
|
|
+ .max_streams = conn->remote.uni.unsent_max_streams,
|
|
+ };
|
|
*pfrc = nfrc;
|
|
|
|
conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams;
|
|
@@ -3780,10 +4178,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
left = ngtcp2_ppe_left(ppe);
|
|
|
|
if (*pfrc == NULL && send_stream && ngtcp2_pq_empty(&conn->tx.strmq) &&
|
|
- (ndatalen = ngtcp2_pkt_stream_max_datalen(
|
|
+ (wdatalen = ngtcp2_pkt_stream_max_datalen(
|
|
vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen,
|
|
left)) != (size_t)-1 &&
|
|
- (ndatalen || datalen == 0)) {
|
|
+ (wdatalen == ndatalen || wdatalen >= NGTCP2_MIN_STREAM_DATALEN) &&
|
|
+ (wdatalen || datalen == 0)) {
|
|
+ ndatalen = wdatalen;
|
|
datacnt = ngtcp2_vec_copy_at_most(data, NGTCP2_MAX_STREAM_DATACNT,
|
|
vmsg->stream.data, vmsg->stream.datacnt,
|
|
(size_t)ndatalen);
|
|
@@ -3800,14 +4200,14 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
|
|
nfrc->fr.stream.type = NGTCP2_FRAME_STREAM;
|
|
nfrc->fr.stream.flags = 0;
|
|
+ nfrc->fr.stream.fin = 0;
|
|
nfrc->fr.stream.stream_id = vmsg->stream.strm->stream_id;
|
|
nfrc->fr.stream.offset = vmsg->stream.strm->tx.offset;
|
|
nfrc->fr.stream.datacnt = datacnt;
|
|
ngtcp2_vec_copy(nfrc->fr.stream.data, data, datacnt);
|
|
|
|
- fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
|
|
- ndatalen == datalen;
|
|
- nfrc->fr.stream.fin = (uint8_t)fin;
|
|
+ nfrc->fr.stream.fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
|
|
+ ndatalen == datalen;
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
|
|
if (rv != 0) {
|
|
@@ -3826,7 +4226,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
conn->tx.offset += ndatalen;
|
|
vmsg->stream.strm->flags |= NGTCP2_STRM_FLAG_ANY_SENT;
|
|
|
|
- if (fin) {
|
|
+ if (nfrc->fr.stream.fin) {
|
|
ngtcp2_strm_shutdown(vmsg->stream.strm, NGTCP2_STRM_FLAG_SHUT_WR);
|
|
}
|
|
|
|
@@ -3849,8 +4249,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED;
|
|
- nfrc->fr.data_blocked.offset = conn->tx.offset;
|
|
+ nfrc->fr.data_blocked = (ngtcp2_data_blocked){
|
|
+ .type = NGTCP2_FRAME_DATA_BLOCKED,
|
|
+ .offset = conn->tx.offset,
|
|
+ };
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
|
|
if (rv != 0) {
|
|
@@ -3881,9 +4283,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
|
|
- nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
|
|
- nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
|
|
+ nfrc->fr.stream_data_blocked = (ngtcp2_stream_data_blocked){
|
|
+ .type = NGTCP2_FRAME_STREAM_DATA_BLOCKED,
|
|
+ .stream_id = strm->stream_id,
|
|
+ .offset = strm->tx.max_offset,
|
|
+ };
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
|
|
if (rv != 0) {
|
|
@@ -4026,7 +4430,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts,
|
|
cstat->smoothed_rtt, ts) ||
|
|
keep_alive_expired || conn->pktns.rtb.probe_pkt_left) {
|
|
- lfr.type = NGTCP2_FRAME_PING;
|
|
+ lfr.ping.type = NGTCP2_FRAME_PING;
|
|
|
|
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
|
|
if (rv != 0) {
|
|
@@ -4041,7 +4445,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING;
|
|
}
|
|
pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
|
|
- pkt_empty = 0;
|
|
}
|
|
} else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) {
|
|
pktns->tx.non_ack_pkt_start_ts = ts;
|
|
@@ -4056,7 +4459,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
|
|
lfr.padding.len = ngtcp2_ppe_padding_size(ppe, destlen);
|
|
} else if (require_padding) {
|
|
- lfr.padding.len = ngtcp2_ppe_dgram_padding(ppe);
|
|
+ lfr.padding.len = conn_dgram_padding(conn, ppe);
|
|
} else {
|
|
lfr.padding.len = ngtcp2_ppe_padding_size(ppe, min_pktlen);
|
|
min_padded = 1;
|
|
@@ -4067,7 +4470,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
|
|
padded = 1;
|
|
}
|
|
- lfr.type = NGTCP2_FRAME_PADDING;
|
|
+ lfr.padding.type = NGTCP2_FRAME_PADDING;
|
|
ngtcp2_log_tx_fr(&conn->log, hd, &lfr);
|
|
ngtcp2_qlog_write_frame(&conn->qlog, &lfr);
|
|
}
|
|
@@ -4103,12 +4506,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
*pfrc = NULL;
|
|
}
|
|
|
|
- if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
|
|
- pktns->rtb.num_ack_eliciting == 0 && conn->cc.event) {
|
|
- conn->cc.event(&conn->cc, &conn->cstat, NGTCP2_CC_EVENT_TYPE_TX_START,
|
|
- ts);
|
|
- }
|
|
-
|
|
rv = conn_on_pkt_sent(conn, pktns, ent);
|
|
if (rv != 0) {
|
|
assert(ngtcp2_err_is_fatal(rv));
|
|
@@ -4117,18 +4514,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
return rv;
|
|
}
|
|
|
|
- if (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
|
|
- if (conn->cc.on_pkt_sent) {
|
|
- conn->cc.on_pkt_sent(
|
|
- &conn->cc, &conn->cstat,
|
|
- ngtcp2_cc_pkt_init(&cc_pkt, hd->pkt_num, (size_t)nwrite,
|
|
- NGTCP2_PKTNS_ID_APPLICATION, ts, ent->rst.lost,
|
|
- ent->rst.tx_in_flight, ent->rst.is_app_limited));
|
|
- }
|
|
-
|
|
- if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) {
|
|
- conn_restart_timer_on_write(conn, ts);
|
|
- }
|
|
+ if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
|
|
+ (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE)) {
|
|
+ conn_restart_timer_on_write(conn, ts);
|
|
}
|
|
} else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
|
|
conn_handle_tx_ecn(conn, pi, NULL, pktns, hd, ts);
|
|
@@ -4140,8 +4528,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
|
|
--pktns->rtb.probe_pkt_left;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
|
|
- nwrite);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
|
|
+ nwrite);
|
|
}
|
|
|
|
conn_update_keep_alive_last_ts(conn, ts);
|
|
@@ -4150,6 +4538,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
|
|
conn->tx.pacing.pktlen += (size_t)nwrite;
|
|
|
|
+ ++conn->cstat.pkt_sent;
|
|
+ conn->cstat.bytes_sent += (uint64_t)nwrite;
|
|
+
|
|
ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
|
|
|
|
++pktns->tx.last_pkt_num;
|
|
@@ -4248,17 +4639,17 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
|
return 0;
|
|
}
|
|
|
|
- lfr.type = NGTCP2_FRAME_PADDING;
|
|
+ lfr.padding.type = NGTCP2_FRAME_PADDING;
|
|
if (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL) {
|
|
lfr.padding.len = ngtcp2_ppe_dgram_padding_size(&ppe, destlen);
|
|
} else if (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) {
|
|
- lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
|
|
+ lfr.padding.len = conn_dgram_padding(conn, &ppe);
|
|
} else {
|
|
- switch (fr->type) {
|
|
+ switch (fr->hd.type) {
|
|
case NGTCP2_FRAME_PATH_CHALLENGE:
|
|
case NGTCP2_FRAME_PATH_RESPONSE:
|
|
if (!conn->server || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
|
|
- lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
|
|
+ lfr.padding.len = conn_dgram_padding(conn, &ppe);
|
|
} else {
|
|
lfr.padding.len = 0;
|
|
}
|
|
@@ -4285,7 +4676,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
|
ngtcp2_qlog_pkt_sent_end(&conn->qlog, &hd, (size_t)nwrite);
|
|
|
|
/* Do this when we are sure that there is no error. */
|
|
- switch (fr->type) {
|
|
+ switch (fr->hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
ngtcp2_acktr_commit_ack(&pktns->acktr);
|
|
@@ -4300,6 +4691,13 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
|
padded = 0;
|
|
}
|
|
|
|
+ break;
|
|
+ case NGTCP2_FRAME_CONNECTION_CLOSE:
|
|
+ case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
|
|
+ /* Clear padded so that we never store the terminal packet in
|
|
+ ngtcp2_rtb. */
|
|
+ padded = 0;
|
|
+
|
|
break;
|
|
}
|
|
|
|
@@ -4333,8 +4731,8 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
|
ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
|
|
--pktns->rtb.probe_pkt_left;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
|
|
- nwrite);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
|
|
+ nwrite);
|
|
}
|
|
}
|
|
} else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
|
|
@@ -4346,7 +4744,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
|
}
|
|
|
|
if (!padded) {
|
|
- switch (fr->type) {
|
|
+ switch (fr->hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
break;
|
|
@@ -4357,6 +4755,9 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
|
conn->tx.pacing.pktlen += (size_t)nwrite;
|
|
}
|
|
|
|
+ ++conn->cstat.pkt_sent;
|
|
+ conn->cstat.bytes_sent += (uint64_t)nwrite;
|
|
+
|
|
ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
|
|
|
|
++pktns->tx.last_pkt_num;
|
|
@@ -4423,8 +4824,10 @@ static int conn_enqueue_retire_connection_id(ngtcp2_conn *conn, uint64_t seq) {
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_RETIRE_CONNECTION_ID;
|
|
- nfrc->fr.retire_connection_id.seq = seq;
|
|
+ nfrc->fr.retire_connection_id = (ngtcp2_retire_connection_id){
|
|
+ .type = NGTCP2_FRAME_RETIRE_CONNECTION_ID,
|
|
+ .seq = seq,
|
|
+ };
|
|
nfrc->next = pktns->tx.frq;
|
|
pktns->tx.frq = nfrc;
|
|
|
|
@@ -4563,10 +4966,10 @@ static ngtcp2_ssize conn_write_pmtud_probe(ngtcp2_conn *conn,
|
|
return 0;
|
|
}
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "sending PMTUD probe packet len=%zu", probelen);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "sending PMTUD probe packet len=%zu", probelen);
|
|
|
|
- lfr.type = NGTCP2_FRAME_PING;
|
|
+ lfr.ping.type = NGTCP2_FRAME_PING;
|
|
|
|
nwrite = ngtcp2_conn_write_single_frame_pkt(
|
|
conn, pi, dest, probelen, NGTCP2_PKT_1RTT,
|
|
@@ -4764,12 +5167,12 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn,
|
|
return 0;
|
|
}
|
|
|
|
- rv = conn_call_get_path_challenge_data(conn, lfr.path_challenge.data);
|
|
+ rv = conn_call_get_path_challenge_data(conn, &lfr.path_challenge.data);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
|
|
- lfr.type = NGTCP2_FRAME_PATH_CHALLENGE;
|
|
+ lfr.path_challenge.type = NGTCP2_FRAME_PATH_CHALLENGE;
|
|
|
|
initial_pto = conn_compute_initial_pto(conn, &conn->pktns);
|
|
timeout = conn_compute_pto(conn, &conn->pktns);
|
|
@@ -4796,7 +5199,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn,
|
|
flags = NGTCP2_PV_ENTRY_FLAG_NONE;
|
|
}
|
|
|
|
- ngtcp2_pv_add_entry(pv, lfr.path_challenge.data, expiry, flags, ts);
|
|
+ ngtcp2_pv_add_entry(pv, &lfr.path_challenge.data, expiry, flags, ts);
|
|
|
|
nwrite = ngtcp2_conn_write_single_frame_pkt(
|
|
conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
|
|
@@ -4902,8 +5305,10 @@ static ngtcp2_ssize conn_write_path_response(ngtcp2_conn *conn,
|
|
}
|
|
}
|
|
|
|
- lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
|
|
- memcpy(lfr.path_response.data, pcent->data, sizeof(lfr.path_response.data));
|
|
+ lfr.path_response = (ngtcp2_path_response){
|
|
+ .type = NGTCP2_FRAME_PATH_RESPONSE,
|
|
+ .data = pcent->data,
|
|
+ };
|
|
|
|
nwrite = ngtcp2_conn_write_single_frame_pkt(
|
|
conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
|
|
@@ -5060,11 +5465,11 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
|
|
ngtcp2_pktns *in_pktns = conn->in_pktns;
|
|
ngtcp2_rtb *rtb = &conn->pktns.rtb;
|
|
ngtcp2_rtb *in_rtb;
|
|
- uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1];
|
|
+ char cidbuf[sizeof(retry.odcid.data) * 2 + 1];
|
|
uint8_t *token;
|
|
|
|
- if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) {
|
|
- return 0;
|
|
+ if (!in_pktns || (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY)) {
|
|
+ return NGTCP2_ERR_DISCARD_PKT;
|
|
}
|
|
|
|
in_rtb = &in_pktns->rtb;
|
|
@@ -5085,9 +5490,9 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
|
|
return rv;
|
|
}
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
|
|
- (const char *)ngtcp2_encode_hex(cidbuf, retry.odcid.data,
|
|
- retry.odcid.datalen));
|
|
+ ngtcp2_log_infof(
|
|
+ &conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(cidbuf, retry.odcid.data, retry.odcid.datalen));
|
|
|
|
if (retry.tokenlen == 0) {
|
|
return NGTCP2_ERR_PROTO;
|
|
@@ -5181,14 +5586,10 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr,
|
|
|
|
num_acked =
|
|
ngtcp2_rtb_recv_ack(&pktns->rtb, fr, &conn->cstat, conn, pktns, pkt_ts, ts);
|
|
- if (num_acked < 0) {
|
|
+ if (num_acked <= 0) {
|
|
return (int)num_acked;
|
|
}
|
|
|
|
- if (num_acked == 0) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
pktns->rtb.probe_pkt_left = 0;
|
|
|
|
if (cstat->pto_count &&
|
|
@@ -5235,9 +5636,12 @@ static void assign_recved_ack_delay_unscaled(ngtcp2_ack *fr,
|
|
* Stream ID exceeds allowed limit.
|
|
* NGTCP2_ERR_NOMEM
|
|
* Out of memory.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*/
|
|
static int conn_recv_max_stream_data(ngtcp2_conn *conn,
|
|
- const ngtcp2_max_stream_data *fr) {
|
|
+ const ngtcp2_max_stream_data *fr,
|
|
+ ngtcp2_tstamp ts) {
|
|
ngtcp2_strm *strm;
|
|
ngtcp2_idtr *idtr;
|
|
int local_stream = conn_local_stream(conn, fr->stream_id);
|
|
@@ -5267,6 +5671,10 @@ static int conn_recv_max_stream_data(ngtcp2_conn *conn,
|
|
if (strm == NULL) {
|
|
if (local_stream) {
|
|
/* Stream has been closed. */
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -5277,6 +5685,10 @@ static int conn_recv_max_stream_data(ngtcp2_conn *conn,
|
|
}
|
|
assert(rv == NGTCP2_ERR_STREAM_IN_USE);
|
|
/* Stream has been closed. */
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -5296,19 +5708,29 @@ static int conn_recv_max_stream_data(ngtcp2_conn *conn,
|
|
}
|
|
}
|
|
|
|
- if (strm->tx.max_offset < fr->max_stream_data) {
|
|
- strm->tx.max_offset = fr->max_stream_data;
|
|
-
|
|
- /* Don't call callback if stream is half-closed local */
|
|
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
|
|
- return 0;
|
|
+ if (strm->tx.max_offset >= fr->max_stream_data) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
}
|
|
|
|
- rv = conn_call_extend_max_stream_data(conn, strm, fr->stream_id,
|
|
- fr->max_stream_data);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ strm->tx.max_offset = fr->max_stream_data;
|
|
+
|
|
+ /* Don't call callback if stream is half-closed local */
|
|
+ if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
}
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rv = conn_call_extend_max_stream_data(conn, strm, fr->stream_id,
|
|
+ fr->max_stream_data);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
}
|
|
|
|
return 0;
|
|
@@ -5503,9 +5925,9 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
|
}
|
|
|
|
if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
|
|
- dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0f));
|
|
+ dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0F));
|
|
} else {
|
|
- dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1f));
|
|
+ dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1F));
|
|
if (dest[0] & NGTCP2_SHORT_KEY_PHASE_BIT) {
|
|
hd->flags |= NGTCP2_PKT_FLAG_KEY_PHASE;
|
|
}
|
|
@@ -5620,7 +6042,7 @@ static void conn_recv_path_challenge(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
}
|
|
|
|
ent = ngtcp2_ringbuf_push_front(&conn->rx.path_challenge.rb);
|
|
- ngtcp2_path_challenge_entry_init(ent, path, fr->data);
|
|
+ ngtcp2_path_challenge_entry_init(ent, path, &fr->data);
|
|
}
|
|
|
|
/*
|
|
@@ -5690,7 +6112,7 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
|
|
return 0;
|
|
}
|
|
|
|
- rv = ngtcp2_pv_validate(pv, &ent_flags, fr->data);
|
|
+ rv = ngtcp2_pv_validate(pv, &ent_flags, &fr->data);
|
|
if (rv != 0) {
|
|
assert(!ngtcp2_err_is_fatal(rv));
|
|
|
|
@@ -5786,7 +6208,7 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
|
|
|
|
conn->pv = npv;
|
|
|
|
- return 0;
|
|
+ return conn_call_begin_path_validation(conn, conn->pv);
|
|
}
|
|
|
|
/*
|
|
@@ -5941,7 +6363,8 @@ static int conn_verify_fixed_bit(ngtcp2_conn *conn, ngtcp2_pkt_hd *hd) {
|
|
|
|
static int conn_recv_crypto(ngtcp2_conn *conn,
|
|
ngtcp2_encryption_level encryption_level,
|
|
- ngtcp2_strm *strm, const ngtcp2_stream *fr);
|
|
+ ngtcp2_strm *strm, const ngtcp2_stream *fr,
|
|
+ ngtcp2_tstamp ts);
|
|
|
|
static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
const ngtcp2_pkt_info *pi, const uint8_t *pkt,
|
|
@@ -5980,6 +6403,8 @@ static int conn_process_buffered_protected_pkt(ngtcp2_conn *conn,
|
|
* TLS stack reported error.
|
|
* NGTCP2_ERR_PROTO
|
|
* Generic QUIC protocol error.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*
|
|
* In addition to the above error codes, error codes returned from
|
|
* conn_recv_pkt are also returned.
|
|
@@ -5991,8 +6416,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_ssize nread;
|
|
ngtcp2_pkt_hd hd;
|
|
- ngtcp2_max_frame mfr;
|
|
- ngtcp2_frame *fr = &mfr.fr;
|
|
+ ngtcp2_frame_decoder frd;
|
|
+ ngtcp2_frame fr;
|
|
int rv;
|
|
int require_ack = 0;
|
|
size_t hdpktlen;
|
|
@@ -6023,8 +6448,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
return 0;
|
|
}
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "buffering 1RTT packet len=%zu", pktlen);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "buffering 1RTT packet len=%zu", pktlen);
|
|
|
|
rv =
|
|
conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt, pktlen, dgramlen, ts);
|
|
@@ -6171,8 +6596,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
}
|
|
|
|
/* Buffer re-ordered 0-RTT packet. */
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "buffering 0-RTT packet len=%zu", pktlen);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "buffering 0-RTT packet len=%zu", pktlen);
|
|
|
|
rv = conn_buffer_pkt(conn, conn->in_pktns, path, pi, pkt, pktlen, dgramlen,
|
|
ts);
|
|
@@ -6194,10 +6619,10 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
|
|
if (conn->server) {
|
|
if (dgramlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
|
|
- ngtcp2_log_info(
|
|
+ ngtcp2_log_infof(
|
|
&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
"Initial packet was ignored because it is included in UDP datagram "
|
|
- "less than %zu bytes: %zu bytes",
|
|
+ "less than %d bytes: %zu bytes",
|
|
NGTCP2_MAX_UDP_PAYLOAD_SIZE, dgramlen);
|
|
return NGTCP2_ERR_DISCARD_PKT;
|
|
}
|
|
@@ -6277,8 +6702,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
"Handshake packet at this point is unexpected and discarded");
|
|
return (ngtcp2_ssize)pktlen;
|
|
}
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "buffering Handshake packet len=%zu", pktlen);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "buffering Handshake packet len=%zu", pktlen);
|
|
|
|
rv = conn_buffer_pkt(conn, conn->hs_pktns, path, pi, pkt, pktlen,
|
|
dgramlen, ts);
|
|
@@ -6332,8 +6757,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
hd.pkt_num = ngtcp2_pkt_adjust_pkt_num(pktns->acktr.max_pkt_num, hd.pkt_num,
|
|
hd.pkt_numlen);
|
|
if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) {
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
- "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
+ "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
|
|
return NGTCP2_ERR_DISCARD_PKT;
|
|
}
|
|
|
|
@@ -6380,9 +6805,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
!conn->negotiated_version) {
|
|
conn->negotiated_version = hd.version;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "the negotiated version is 0x%08x",
|
|
- conn->negotiated_version);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "the negotiated version is 0x%08x",
|
|
+ conn->negotiated_version);
|
|
}
|
|
|
|
payload = conn->crypto.decrypt_buf.base;
|
|
@@ -6438,7 +6863,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
ngtcp2_qlog_pkt_received_start(&conn->qlog);
|
|
|
|
for (; payloadlen;) {
|
|
- nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
|
|
+ nread = ngtcp2_frame_decoder_decode(&frd, &fr, payload, payloadlen);
|
|
if (nread < 0) {
|
|
return nread;
|
|
}
|
|
@@ -6446,14 +6871,14 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
payload += nread;
|
|
payloadlen -= (size_t)nread;
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
- fr->ack.ack_delay = 0;
|
|
- fr->ack.ack_delay_unscaled = 0;
|
|
+ fr.ack.ack_delay = 0;
|
|
+ fr.ack.ack_delay_unscaled = 0;
|
|
|
|
rv =
|
|
- ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
|
|
+ ngtcp2_pkt_validate_ack(&fr.ack, conn->local.settings.initial_pkt_num);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -6461,9 +6886,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
}
|
|
|
|
- ngtcp2_log_rx_fr(&conn->log, &hd, fr);
|
|
+ ngtcp2_log_rx_fr(&conn->log, &hd, &fr);
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
|
|
@@ -6472,7 +6897,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
if (!conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) {
|
|
conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
|
|
}
|
|
- rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
|
|
+ rv = conn_recv_ack(conn, pktns, &fr.ack, pkt_ts, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -6482,34 +6907,35 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
case NGTCP2_FRAME_CRYPTO:
|
|
if (!conn->server && !conn->negotiated_version &&
|
|
- ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt)) {
|
|
+ ngtcp2_vec_len(fr.stream.data, fr.stream.datacnt)) {
|
|
conn->negotiated_version = hd.version;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "the negotiated version is 0x%08x",
|
|
- conn->negotiated_version);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "the negotiated version is 0x%08x",
|
|
+ conn->negotiated_version);
|
|
}
|
|
|
|
- rv = conn_recv_crypto(conn, encryption_level, crypto, &fr->stream);
|
|
+ rv = conn_recv_crypto(conn, encryption_level, crypto, &fr.stream, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
require_ack = 1;
|
|
break;
|
|
case NGTCP2_FRAME_CONNECTION_CLOSE:
|
|
- rv = conn_recv_connection_close(conn, &fr->connection_close);
|
|
+ rv = conn_recv_connection_close(conn, &fr.connection_close);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
break;
|
|
case NGTCP2_FRAME_PING:
|
|
+ ++conn->cstat.ping_recv;
|
|
require_ack = 1;
|
|
break;
|
|
default:
|
|
return NGTCP2_ERR_PROTO;
|
|
}
|
|
|
|
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
|
|
+ ngtcp2_qlog_write_frame(&conn->qlog, &fr);
|
|
}
|
|
|
|
if (hd.type == NGTCP2_PKT_HANDSHAKE) {
|
|
@@ -6543,6 +6969,7 @@ static int is_unrecoverable_error(int liberr) {
|
|
case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
|
|
case NGTCP2_ERR_TRANSPORT_PARAM:
|
|
case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
|
|
+ case NGTCP2_ERR_INTERNAL:
|
|
return 1;
|
|
}
|
|
|
|
@@ -6568,6 +6995,10 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn,
|
|
const uint8_t *origpkt = pkt;
|
|
uint32_t version;
|
|
|
|
+ if (pktlen == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
if (ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
|
|
conn->dcid.current.bytes_recv += dgramlen;
|
|
}
|
|
@@ -6595,6 +7026,8 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn,
|
|
return nread;
|
|
}
|
|
|
|
+ ++conn->cstat.pkt_discarded;
|
|
+
|
|
/* If server discards first Initial, then drop connection
|
|
state. This is because SCID in packet might be corrupted
|
|
and the current connection state might wrongly discard
|
|
@@ -6612,11 +7045,15 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn,
|
|
unrecoverable, therefore drop connection. */
|
|
return nread;
|
|
}
|
|
+
|
|
+ ++conn->cstat.pkt_discarded;
|
|
+
|
|
return (ngtcp2_ssize)dgramlen;
|
|
}
|
|
}
|
|
|
|
if (nread == NGTCP2_ERR_DISCARD_PKT) {
|
|
+ ++conn->cstat.pkt_discarded;
|
|
return (ngtcp2_ssize)dgramlen;
|
|
}
|
|
|
|
@@ -6632,8 +7069,11 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn,
|
|
pkt += nread;
|
|
pktlen -= (size_t)nread;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
- "read packet %td left %zu", nread, pktlen);
|
|
+ ++conn->cstat.pkt_recv;
|
|
+ conn->cstat.bytes_recv += (uint64_t)nread;
|
|
+
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
+ "read packet %td left %zu", nread, pktlen);
|
|
}
|
|
|
|
return (ngtcp2_ssize)dgramlen;
|
|
@@ -6778,15 +7218,24 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm,
|
|
* The end offset exceeds the maximum value.
|
|
* NGTCP2_ERR_CALLBACK_FAILURE
|
|
* User-defined callback function failed.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*/
|
|
static int conn_recv_crypto(ngtcp2_conn *conn,
|
|
ngtcp2_encryption_level encryption_level,
|
|
- ngtcp2_strm *crypto, const ngtcp2_stream *fr) {
|
|
+ ngtcp2_strm *crypto, const ngtcp2_stream *fr,
|
|
+ ngtcp2_tstamp ts) {
|
|
uint64_t fr_end_offset;
|
|
uint64_t rx_offset;
|
|
int rv;
|
|
+ ngtcp2_ssize nwrite;
|
|
|
|
if (fr->datacnt == 0) {
|
|
+ if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL &&
|
|
+ ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -6799,6 +7248,11 @@ static int conn_recv_crypto(ngtcp2_conn *conn,
|
|
rx_offset = ngtcp2_strm_rx_offset(crypto);
|
|
|
|
if (fr_end_offset <= rx_offset) {
|
|
+ if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL &&
|
|
+ ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
if (conn->server &&
|
|
!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT) &&
|
|
encryption_level == NGTCP2_ENCRYPTION_LEVEL_INITIAL) {
|
|
@@ -6856,8 +7310,18 @@ static int conn_recv_crypto(ngtcp2_conn *conn,
|
|
return NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED;
|
|
}
|
|
|
|
- return ngtcp2_strm_recv_reordering(crypto, fr->data[0].base, fr->data[0].len,
|
|
- fr->offset);
|
|
+ nwrite = ngtcp2_strm_recv_reordering(crypto, fr->data[0].base,
|
|
+ fr->data[0].len, fr->offset);
|
|
+ if (nwrite < 0) {
|
|
+ return (int)nwrite;
|
|
+ }
|
|
+
|
|
+ if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL && nwrite == 0 &&
|
|
+ ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -6891,8 +7355,11 @@ static int conn_max_data_violated(ngtcp2_conn *conn, uint64_t datalen) {
|
|
* NGTCP2_ERR_FINAL_SIZE
|
|
* STREAM frame has strictly larger end offset than it is
|
|
* permitted.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*/
|
|
-static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
+static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr,
|
|
+ ngtcp2_tstamp ts) {
|
|
int rv;
|
|
ngtcp2_strm *strm;
|
|
ngtcp2_idtr *idtr;
|
|
@@ -6901,6 +7368,8 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
int bidi;
|
|
uint64_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
|
|
uint32_t sdflags = NGTCP2_STREAM_DATA_FLAG_NONE;
|
|
+ ngtcp2_ssize nwrite;
|
|
+ int new_strm = 0;
|
|
|
|
local_stream = conn_local_stream(conn, fr->stream_id);
|
|
bidi = bidi_stream(fr->stream_id);
|
|
@@ -6934,8 +7403,11 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
|
|
if (strm == NULL) {
|
|
if (local_stream) {
|
|
- /* TODO The stream has been closed. This should be responded
|
|
- with RESET_STREAM, or simply ignored. */
|
|
+ /* The stream has been closed. */
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -6945,8 +7417,11 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
return rv;
|
|
}
|
|
assert(rv == NGTCP2_ERR_STREAM_IN_USE);
|
|
- /* TODO The stream has been closed. This should be responded
|
|
- with RESET_STREAM, or simply ignored. */
|
|
+ /* The stream has been closed. */
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -6961,6 +7436,8 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
return rv;
|
|
}
|
|
|
|
+ new_strm = 1;
|
|
+
|
|
if (!bidi) {
|
|
ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR);
|
|
strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED;
|
|
@@ -7001,10 +7478,18 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
}
|
|
|
|
if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
if (rx_offset == fr_end_offset) {
|
|
+ if (!new_strm && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
} else if (strm->rx.last_offset > fr_end_offset) {
|
|
@@ -7024,10 +7509,18 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
ngtcp2_max_uint64(strm->rx.last_offset, fr_end_offset);
|
|
|
|
if (fr_end_offset <= rx_offset) {
|
|
+ if (!new_strm && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -7056,30 +7549,34 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
|
|
fin = (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
|
|
rx_offset == strm->rx.last_offset;
|
|
|
|
- if (fin || datalen) {
|
|
- if (fin) {
|
|
- sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
|
|
- }
|
|
- if (!conn_is_tls_handshake_completed(conn)) {
|
|
- sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
|
|
- }
|
|
- rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
|
|
- (size_t)datalen);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
- }
|
|
+ assert(fin || datalen);
|
|
|
|
- rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
- }
|
|
+ if (fin) {
|
|
+ sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
|
|
}
|
|
- } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
|
|
- rv = ngtcp2_strm_recv_reordering(strm, fr->data[0].base, fr->data[0].len,
|
|
- fr->offset);
|
|
+ if (!conn_is_tls_handshake_completed(conn)) {
|
|
+ sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
|
|
+ }
|
|
+ rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
|
|
+ (size_t)datalen);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
+ } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
|
|
+ nwrite = ngtcp2_strm_recv_reordering(strm, fr->data[0].base,
|
|
+ fr->data[0].len, fr->offset);
|
|
+ if (nwrite < 0) {
|
|
+ return (int)nwrite;
|
|
+ }
|
|
+
|
|
+ if (nwrite == 0 && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
}
|
|
return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
|
|
}
|
|
@@ -7175,9 +7672,12 @@ handle_max_remote_streams_extension(uint64_t *punsent_max_remote_streams,
|
|
* NGTCP2_MAX_VARINT.
|
|
* NGTCP2_ERR_FINAL_SIZE
|
|
* The final offset is strictly larger than it is permitted.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*/
|
|
static int conn_recv_reset_stream(ngtcp2_conn *conn,
|
|
- const ngtcp2_reset_stream *fr) {
|
|
+ const ngtcp2_reset_stream *fr,
|
|
+ ngtcp2_tstamp ts) {
|
|
ngtcp2_strm *strm;
|
|
int local_stream = conn_local_stream(conn, fr->stream_id);
|
|
int bidi = bidi_stream(fr->stream_id);
|
|
@@ -7215,6 +7715,10 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn,
|
|
strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
|
|
if (strm == NULL) {
|
|
if (local_stream) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -7224,6 +7728,11 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn,
|
|
return rv;
|
|
}
|
|
assert(rv == NGTCP2_ERR_STREAM_IN_USE);
|
|
+
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -7258,6 +7767,10 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn,
|
|
}
|
|
|
|
if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -7313,9 +7826,12 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn,
|
|
* Out of memory.
|
|
* NGTCP2_ERR_CALLBACK_FAILURE
|
|
* User-defined callback function failed.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*/
|
|
static int conn_recv_stop_sending(ngtcp2_conn *conn,
|
|
- const ngtcp2_stop_sending *fr) {
|
|
+ const ngtcp2_stop_sending *fr,
|
|
+ ngtcp2_tstamp ts) {
|
|
int rv;
|
|
ngtcp2_strm *strm;
|
|
ngtcp2_idtr *idtr;
|
|
@@ -7344,6 +7860,10 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn,
|
|
strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
|
|
if (strm == NULL) {
|
|
if (local_stream) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
rv = ngtcp2_idtr_open(idtr, fr->stream_id);
|
|
@@ -7352,6 +7872,11 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn,
|
|
return rv;
|
|
}
|
|
assert(rv == NGTCP2_ERR_STREAM_IN_USE);
|
|
+
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -7374,6 +7899,10 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn,
|
|
}
|
|
|
|
if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING_RECVED) {
|
|
+ if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -7405,9 +7934,8 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn,
|
|
*/
|
|
static int check_stateless_reset(const ngtcp2_dcid *dcid,
|
|
const ngtcp2_path *path,
|
|
- const ngtcp2_pkt_stateless_reset *sr) {
|
|
- return ngtcp2_dcid_verify_stateless_reset_token(
|
|
- dcid, path, sr->stateless_reset_token) == 0;
|
|
+ const ngtcp2_pkt_stateless_reset2 *sr) {
|
|
+ return ngtcp2_dcid_verify_stateless_reset_token(dcid, path, &sr->token) == 0;
|
|
}
|
|
|
|
/*
|
|
@@ -7431,7 +7959,7 @@ static int conn_on_stateless_reset(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
const uint8_t *payload, size_t payloadlen) {
|
|
int rv;
|
|
ngtcp2_pv *pv = conn->pv;
|
|
- ngtcp2_pkt_stateless_reset sr;
|
|
+ ngtcp2_pkt_stateless_reset2 sr;
|
|
|
|
rv = ngtcp2_pkt_decode_stateless_reset(&sr, payload, payloadlen);
|
|
if (rv != 0) {
|
|
@@ -7442,8 +7970,7 @@ static int conn_on_stateless_reset(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
(!pv || (!check_stateless_reset(&pv->dcid, path, &sr) &&
|
|
(!(pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) ||
|
|
!check_stateless_reset(&pv->fallback_dcid, path, &sr))))) {
|
|
- rv = ngtcp2_dcidtr_verify_stateless_reset(&conn->dcid.dtr, path,
|
|
- sr.stateless_reset_token);
|
|
+ rv = ngtcp2_dcidtr_verify_stateless_reset(&conn->dcid.dtr, path, &sr.token);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -7523,7 +8050,7 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn,
|
|
}
|
|
|
|
rv = ngtcp2_dcid_verify_uniqueness(&conn->dcid.current, fr->seq, &fr->cid,
|
|
- fr->stateless_reset_token);
|
|
+ &fr->token);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -7532,8 +8059,8 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn,
|
|
}
|
|
|
|
if (pv) {
|
|
- rv = ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid,
|
|
- fr->stateless_reset_token);
|
|
+ rv =
|
|
+ ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid, &fr->token);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -7542,8 +8069,8 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn,
|
|
}
|
|
}
|
|
|
|
- rv = ngtcp2_dcidtr_verify_token_uniqueness(
|
|
- &conn->dcid.dtr, &found, fr->seq, &fr->cid, fr->stateless_reset_token);
|
|
+ rv = ngtcp2_dcidtr_verify_token_uniqueness(&conn->dcid.dtr, &found, fr->seq,
|
|
+ &fr->cid, &fr->token);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -7621,8 +8148,7 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn,
|
|
return 0;
|
|
}
|
|
|
|
- ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, fr->seq, &fr->cid,
|
|
- fr->stateless_reset_token);
|
|
+ ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, fr->seq, &fr->cid, &fr->token);
|
|
|
|
return 0;
|
|
}
|
|
@@ -8030,7 +8556,12 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) {
|
|
|
|
conn->pv = pv;
|
|
|
|
- return conn_call_activate_dcid(conn, &pv->dcid);
|
|
+ rv = conn_call_activate_dcid(conn, &pv->dcid);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ return conn_call_begin_path_validation(conn, conn->pv);
|
|
}
|
|
|
|
/*
|
|
@@ -8258,7 +8789,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
|
|
ngtcp2_pv *pv = NULL;
|
|
int rv;
|
|
ngtcp2_duration pto;
|
|
- int require_new_cid;
|
|
int local_addr_eq;
|
|
int pref_addr_migration;
|
|
uint32_t remote_addr_cmp;
|
|
@@ -8316,9 +8846,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
|
|
* continue to use the current connection ID with the new remote
|
|
* address while still sending from the same local address.
|
|
*/
|
|
- require_new_cid = conn->dcid.current.cid.datalen &&
|
|
- ((new_cid_used && remote_addr_cmp) || !local_addr_eq);
|
|
-
|
|
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
"non-probing packet was received from new remote address");
|
|
|
|
@@ -8326,8 +8853,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
|
|
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
"Found DCID which has already been bound to the new path");
|
|
|
|
- require_new_cid = 0;
|
|
-
|
|
if (dcid.cid.datalen) {
|
|
rv = conn_call_activate_dcid(conn, &dcid);
|
|
if (rv != 0) {
|
|
@@ -8335,7 +8860,9 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
|
|
}
|
|
}
|
|
} else {
|
|
- if (require_new_cid) {
|
|
+ if (conn->dcid.current.cid.datalen &&
|
|
+ ((new_cid_used && remote_addr_cmp) || !local_addr_eq)) {
|
|
+ /* New DCID is required. */
|
|
if (ngtcp2_dcidtr_unused_empty(&conn->dcid.dtr)) {
|
|
return NGTCP2_ERR_CONN_ID_BLOCKED;
|
|
}
|
|
@@ -8421,7 +8948,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
|
|
|
|
conn->pv = pv;
|
|
|
|
- return 0;
|
|
+ return conn_call_begin_path_validation(conn, conn->pv);
|
|
}
|
|
|
|
/*
|
|
@@ -8500,8 +9027,8 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
const uint8_t *payload, size_t payloadlen,
|
|
ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) {
|
|
ngtcp2_ssize nread;
|
|
- ngtcp2_max_frame mfr;
|
|
- ngtcp2_frame *fr = &mfr.fr;
|
|
+ ngtcp2_frame_decoder frd;
|
|
+ ngtcp2_frame fr;
|
|
int rv;
|
|
int require_ack = 0;
|
|
ngtcp2_pktns *pktns;
|
|
@@ -8519,7 +9046,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
ngtcp2_qlog_pkt_received_start(&conn->qlog);
|
|
|
|
for (; payloadlen;) {
|
|
- nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
|
|
+ nread = ngtcp2_frame_decoder_decode(&frd, &fr, payload, payloadlen);
|
|
if (nread < 0) {
|
|
return (int)nread;
|
|
}
|
|
@@ -8527,14 +9054,14 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
payload += nread;
|
|
payloadlen -= (size_t)nread;
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
- fr->ack.ack_delay = 0;
|
|
- fr->ack.ack_delay_unscaled = 0;
|
|
+ fr.ack.ack_delay = 0;
|
|
+ fr.ack.ack_delay_unscaled = 0;
|
|
|
|
rv =
|
|
- ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
|
|
+ ngtcp2_pkt_validate_ack(&fr.ack, conn->local.settings.initial_pkt_num);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -8542,9 +9069,9 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
break;
|
|
}
|
|
|
|
- ngtcp2_log_rx_fr(&conn->log, hd, fr);
|
|
+ ngtcp2_log_rx_fr(&conn->log, hd, &fr);
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
|
|
@@ -8553,7 +9080,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
if (!conn->server) {
|
|
conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
|
|
}
|
|
- rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
|
|
+ rv = conn_recv_ack(conn, pktns, &fr.ack, pkt_ts, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -8562,20 +9089,22 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
case NGTCP2_FRAME_PADDING:
|
|
break;
|
|
case NGTCP2_FRAME_CONNECTION_CLOSE:
|
|
- rv = conn_recv_connection_close(conn, &fr->connection_close);
|
|
+ rv = conn_recv_connection_close(conn, &fr.connection_close);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
break;
|
|
- case NGTCP2_FRAME_CRYPTO:
|
|
case NGTCP2_FRAME_PING:
|
|
+ ++conn->cstat.ping_recv;
|
|
+ /* fall through */
|
|
+ case NGTCP2_FRAME_CRYPTO:
|
|
require_ack = 1;
|
|
break;
|
|
default:
|
|
return NGTCP2_ERR_PROTO;
|
|
}
|
|
|
|
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
|
|
+ ngtcp2_qlog_write_frame(&conn->qlog, &fr);
|
|
}
|
|
|
|
ngtcp2_qlog_pkt_received_end(&conn->qlog, hd, pktlen);
|
|
@@ -8630,6 +9159,8 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
|
|
* Flow control limit is violated.
|
|
* NGTCP2_ERR_FINAL_SIZE
|
|
* Frame has strictly larger end offset than it is permitted.
|
|
+ * NGTCP2_ERR_INTERNAL
|
|
+ * Suspicious remote endpoint activity exceeded threshold.
|
|
*/
|
|
static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
const ngtcp2_pkt_info *pi, const uint8_t *pkt,
|
|
@@ -8641,8 +9172,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
const uint8_t *payload;
|
|
size_t payloadlen;
|
|
ngtcp2_ssize nread, nwrite;
|
|
- ngtcp2_max_frame mfr;
|
|
- ngtcp2_frame *fr = &mfr.fr;
|
|
+ ngtcp2_frame_decoder frd;
|
|
+ ngtcp2_frame fr;
|
|
int require_ack = 0;
|
|
ngtcp2_crypto_aead *aead;
|
|
ngtcp2_crypto_cipher *hp;
|
|
@@ -8736,8 +9267,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
default:
|
|
ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
- "packet type 0x%02x was ignored", hd.type);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
+ "packet type 0x%02x was ignored", hd.type);
|
|
return (ngtcp2_ssize)pktlen;
|
|
}
|
|
} else {
|
|
@@ -8784,8 +9315,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
hd.pkt_num = ngtcp2_pkt_adjust_pkt_num(pktns->acktr.max_pkt_num, hd.pkt_num,
|
|
hd.pkt_numlen);
|
|
if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) {
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
- "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
+ "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
|
|
return NGTCP2_ERR_DISCARD_PKT;
|
|
}
|
|
|
|
@@ -8796,7 +9327,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
conn->rx.preferred_addr.pkt_num < hd.pkt_num &&
|
|
ngtcp2_sockaddr_eq((const ngtcp2_sockaddr *)&conn->hs_local_addr,
|
|
path->local.addr)) {
|
|
- ngtcp2_log_info(
|
|
+ ngtcp2_log_infof(
|
|
&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
"pkt=%" PRId64
|
|
" is discarded because it was received on handshake local "
|
|
@@ -8948,7 +9479,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
ngtcp2_qlog_pkt_received_start(&conn->qlog);
|
|
|
|
for (; payloadlen;) {
|
|
- nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
|
|
+ nread = ngtcp2_frame_decoder_decode(&frd, &fr, payload, payloadlen);
|
|
if (nread < 0) {
|
|
return nread;
|
|
}
|
|
@@ -8956,7 +9487,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
payload += nread;
|
|
payloadlen -= (size_t)nread;
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
if ((hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) &&
|
|
@@ -8965,10 +9496,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
}
|
|
assert(conn->remote.transport_params);
|
|
assign_recved_ack_delay_unscaled(
|
|
- &fr->ack, conn->remote.transport_params->ack_delay_exponent);
|
|
+ &fr.ack, conn->remote.transport_params->ack_delay_exponent);
|
|
|
|
rv =
|
|
- ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
|
|
+ ngtcp2_pkt_validate_ack(&fr.ack, conn->local.settings.initial_pkt_num);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -8976,10 +9507,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
}
|
|
|
|
- ngtcp2_log_rx_fr(&conn->log, &hd, fr);
|
|
+ ngtcp2_log_rx_fr(&conn->log, &hd, &fr);
|
|
|
|
if (hd.type == NGTCP2_PKT_0RTT) {
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_PADDING:
|
|
case NGTCP2_FRAME_PING:
|
|
case NGTCP2_FRAME_RESET_STREAM:
|
|
@@ -9005,7 +9536,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
}
|
|
}
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
case NGTCP2_FRAME_PADDING:
|
|
@@ -9016,7 +9547,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
require_ack = 1;
|
|
}
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr.hd.type) {
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
|
|
@@ -9025,7 +9556,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
if (!conn->server) {
|
|
conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
|
|
}
|
|
- rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
|
|
+ rv = conn_recv_ack(conn, pktns, &fr.ack, pkt_ts, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -9033,7 +9564,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
++num_ack_processed;
|
|
break;
|
|
case NGTCP2_FRAME_STREAM:
|
|
- rv = conn_recv_stream(conn, &fr->stream);
|
|
+ rv = conn_recv_stream(conn, &fr.stream, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -9041,40 +9572,40 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
case NGTCP2_FRAME_CRYPTO:
|
|
rv = conn_recv_crypto(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT,
|
|
- &pktns->crypto.strm, &fr->stream);
|
|
+ &pktns->crypto.strm, &fr.stream, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_RESET_STREAM:
|
|
- rv = conn_recv_reset_stream(conn, &fr->reset_stream);
|
|
+ rv = conn_recv_reset_stream(conn, &fr.reset_stream, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_STOP_SENDING:
|
|
- rv = conn_recv_stop_sending(conn, &fr->stop_sending);
|
|
+ rv = conn_recv_stop_sending(conn, &fr.stop_sending, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_MAX_STREAM_DATA:
|
|
- rv = conn_recv_max_stream_data(conn, &fr->max_stream_data);
|
|
+ rv = conn_recv_max_stream_data(conn, &fr.max_stream_data, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_MAX_DATA:
|
|
- conn_recv_max_data(conn, &fr->max_data);
|
|
+ conn_recv_max_data(conn, &fr.max_data);
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_MAX_STREAMS_BIDI:
|
|
case NGTCP2_FRAME_MAX_STREAMS_UNI:
|
|
- rv = conn_recv_max_streams(conn, &fr->max_streams);
|
|
+ rv = conn_recv_max_streams(conn, &fr.max_streams);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -9082,41 +9613,42 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
case NGTCP2_FRAME_CONNECTION_CLOSE:
|
|
case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
|
|
- rv = conn_recv_connection_close(conn, &fr->connection_close);
|
|
+ rv = conn_recv_connection_close(conn, &fr.connection_close);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
break;
|
|
case NGTCP2_FRAME_PING:
|
|
+ ++conn->cstat.ping_recv;
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_PATH_CHALLENGE:
|
|
- conn_recv_path_challenge(conn, path, &fr->path_challenge);
|
|
+ conn_recv_path_challenge(conn, path, &fr.path_challenge);
|
|
path_challenge_recved = 1;
|
|
break;
|
|
case NGTCP2_FRAME_PATH_RESPONSE:
|
|
- rv = conn_recv_path_response(conn, &hd, &fr->path_response, ts);
|
|
+ rv = conn_recv_path_response(conn, &hd, &fr.path_response, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
break;
|
|
case NGTCP2_FRAME_NEW_CONNECTION_ID:
|
|
- rv = conn_recv_new_connection_id(conn, &fr->new_connection_id);
|
|
+ rv = conn_recv_new_connection_id(conn, &fr.new_connection_id);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
recv_ncid = 1;
|
|
break;
|
|
case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
|
|
- rv = conn_recv_retire_connection_id(conn, &hd, &fr->retire_connection_id,
|
|
- ts);
|
|
+ rv =
|
|
+ conn_recv_retire_connection_id(conn, &hd, &fr.retire_connection_id, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_NEW_TOKEN:
|
|
- rv = conn_recv_new_token(conn, &fr->new_token);
|
|
+ rv = conn_recv_new_token(conn, &fr.new_token);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -9130,28 +9662,28 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_STREAMS_BLOCKED_BIDI:
|
|
- rv = conn_recv_streams_blocked_bidi(conn, &fr->streams_blocked);
|
|
+ rv = conn_recv_streams_blocked_bidi(conn, &fr.streams_blocked);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_STREAMS_BLOCKED_UNI:
|
|
- rv = conn_recv_streams_blocked_uni(conn, &fr->streams_blocked);
|
|
+ rv = conn_recv_streams_blocked_uni(conn, &fr.streams_blocked);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
|
|
- rv = conn_recv_stream_data_blocked(conn, &fr->stream_data_blocked);
|
|
+ rv = conn_recv_stream_data_blocked(conn, &fr.stream_data_blocked);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
non_probing_pkt = 1;
|
|
break;
|
|
case NGTCP2_FRAME_DATA_BLOCKED:
|
|
- rv = conn_recv_data_blocked(conn, &fr->data_blocked);
|
|
+ rv = conn_recv_data_blocked(conn, &fr.data_blocked);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -9163,7 +9695,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
conn->local.transport_params.max_datagram_frame_size) {
|
|
return NGTCP2_ERR_PROTO;
|
|
}
|
|
- rv = conn_recv_datagram(conn, &fr->datagram);
|
|
+ rv = conn_recv_datagram(conn, &fr.datagram);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -9171,7 +9703,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
break;
|
|
}
|
|
|
|
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
|
|
+ ngtcp2_qlog_write_frame(&conn->qlog, &fr);
|
|
}
|
|
|
|
ngtcp2_qlog_pkt_received_end(&conn->qlog, &hd, pktlen);
|
|
@@ -9286,6 +9818,7 @@ static int conn_process_buffered_protected_pkt(ngtcp2_conn *conn,
|
|
*ppc = next;
|
|
if (nread < 0) {
|
|
if (nread == NGTCP2_ERR_DISCARD_PKT) {
|
|
+ ++conn->cstat.pkt_discarded;
|
|
continue;
|
|
}
|
|
return (int)nread;
|
|
@@ -9320,6 +9853,7 @@ static int conn_process_buffered_handshake_pkt(ngtcp2_conn *conn,
|
|
*ppc = next;
|
|
if (nread < 0) {
|
|
if (nread == NGTCP2_ERR_DISCARD_PKT) {
|
|
+ ++conn->cstat.pkt_discarded;
|
|
continue;
|
|
}
|
|
return (int)nread;
|
|
@@ -9465,6 +9999,7 @@ static int conn_recv_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
}
|
|
}
|
|
if (nread == NGTCP2_ERR_DISCARD_PKT) {
|
|
+ ++conn->cstat.pkt_discarded;
|
|
return 0;
|
|
}
|
|
return (int)nread;
|
|
@@ -9474,8 +10009,11 @@ static int conn_recv_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
pkt += nread;
|
|
pktlen -= (size_t)nread;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
- "read packet %td left %zu", nread, pktlen);
|
|
+ ++conn->cstat.pkt_recv;
|
|
+ conn->cstat.bytes_recv += (uint64_t)nread;
|
|
+
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
|
|
+ "read packet %td left %zu", nread, pktlen);
|
|
}
|
|
|
|
return 0;
|
|
@@ -9497,7 +10035,7 @@ static int conn_enqueue_handshake_done(ngtcp2_conn *conn) {
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr.type = NGTCP2_FRAME_HANDSHAKE_DONE;
|
|
+ nfrc->fr.handshake_done.type = NGTCP2_FRAME_HANDSHAKE_DONE;
|
|
nfrc->next = pktns->tx.frq;
|
|
pktns->tx.frq = nfrc;
|
|
|
|
@@ -9647,9 +10185,9 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn,
|
|
if ((size_t)nread < pktlen) {
|
|
/* We have 1RTT packet and application rx key, but the
|
|
handshake has not completed yet. */
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "buffering 1RTT packet len=%zu",
|
|
- pktlen - (size_t)nread);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "buffering 1RTT packet len=%zu",
|
|
+ pktlen - (size_t)nread);
|
|
|
|
rv = conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt + nread,
|
|
pktlen - (size_t)nread, pktlen, ts);
|
|
@@ -9728,8 +10266,8 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
|
|
conn_update_timestamp(conn, ts);
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu",
|
|
- pktlen);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu",
|
|
+ pktlen);
|
|
|
|
if (pktlen == 0) {
|
|
return 0;
|
|
@@ -9741,6 +10279,8 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
!ngtcp2_dcidtr_check_path_retired(&conn->dcid.dtr, path)) {
|
|
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
"ignore packet from unknown path");
|
|
+ ++conn->cstat.pkt_discarded;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -9814,6 +10354,49 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
return conn_recv_cpkt(conn, path, pi, pkt, pktlen, ts);
|
|
}
|
|
|
|
+int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
+ int rv;
|
|
+ ngtcp2_encryption_level encryption_level;
|
|
+ uint64_t offset;
|
|
+
|
|
+ conn_update_timestamp(conn, ts);
|
|
+
|
|
+ switch (conn->state) {
|
|
+ case NGTCP2_CS_CLIENT_INITIAL:
|
|
+ case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE:
|
|
+ case NGTCP2_CS_SERVER_INITIAL:
|
|
+ case NGTCP2_CS_SERVER_WAIT_HANDSHAKE:
|
|
+ /* Most of the handshake interruption happens in Initial
|
|
+ encryption level, but this might not be the case depending on
|
|
+ the TLS stack and its functionality and where interruption
|
|
+ occurs. After all, we do not need to support all kinds of
|
|
+ interruptions. */
|
|
+ if (conn->in_pktns) {
|
|
+ encryption_level = NGTCP2_ENCRYPTION_LEVEL_INITIAL;
|
|
+ offset = ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm);
|
|
+ } else if (conn->hs_pktns) {
|
|
+ encryption_level = NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE;
|
|
+ offset = ngtcp2_strm_rx_offset(&conn->hs_pktns->crypto.strm);
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rv = conn_call_recv_crypto_data(conn, encryption_level, offset, NULL, 0);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ return (int)conn_read_handshake(conn, /* path = */ NULL, /* pi = */ NULL,
|
|
+ /* pkt = */ NULL, 0, ts);
|
|
+ case NGTCP2_CS_CLOSING:
|
|
+ return NGTCP2_ERR_CLOSING;
|
|
+ case NGTCP2_CS_DRAINING:
|
|
+ return NGTCP2_ERR_DRAINING;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* conn_check_pkt_num_exhausted returns nonzero if packet number is
|
|
* exhausted in at least one of packet number space.
|
|
@@ -9915,6 +10498,7 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
size_t origlen = destlen;
|
|
uint64_t pending_early_datalen;
|
|
ngtcp2_preferred_addr *paddr;
|
|
+ ngtcp2_stateless_reset_token token;
|
|
|
|
switch (conn->state) {
|
|
case NGTCP2_CS_CLIENT_INITIAL:
|
|
@@ -10042,8 +10626,8 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
assert(!ngtcp2_dcidtr_unused_full(&conn->dcid.dtr));
|
|
|
|
paddr = &conn->remote.transport_params->preferred_addr;
|
|
- ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, 1, &paddr->cid,
|
|
- paddr->stateless_reset_token);
|
|
+ memcpy(token.data, paddr->stateless_reset_token, sizeof(token.data));
|
|
+ ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, 1, &paddr->cid, &token);
|
|
|
|
rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, 1, 1);
|
|
if (rv != 0) {
|
|
@@ -10051,12 +10635,12 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
}
|
|
}
|
|
|
|
- if (conn->remote.transport_params->stateless_reset_token_present) {
|
|
- assert(conn->dcid.current.seq == 0);
|
|
+ if (conn->remote.transport_params->stateless_reset_token_present &&
|
|
+ conn->dcid.current.seq == 0) {
|
|
assert(!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT));
|
|
- ngtcp2_dcid_set_token(
|
|
- &conn->dcid.current,
|
|
- conn->remote.transport_params->stateless_reset_token);
|
|
+ memcpy(token.data, conn->remote.transport_params->stateless_reset_token,
|
|
+ sizeof(token.data));
|
|
+ ngtcp2_dcid_set_token(&conn->dcid.current, &token);
|
|
}
|
|
|
|
rv = conn_call_activate_dcid(conn, &conn->dcid.current);
|
|
@@ -10095,8 +10679,6 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
}
|
|
|
|
res += nwrite;
|
|
- dest += nwrite;
|
|
- destlen -= (size_t)nwrite;
|
|
}
|
|
|
|
if (res == 0) {
|
|
@@ -10106,8 +10688,6 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
}
|
|
|
|
res += nwrite;
|
|
- dest += nwrite;
|
|
- origlen -= (size_t)nwrite;
|
|
}
|
|
|
|
return res;
|
|
@@ -10343,6 +10923,9 @@ int ngtcp2_conn_install_initial_key(
|
|
rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
|
|
conn->mem);
|
|
if (rv != 0) {
|
|
+ ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
|
|
+ pktns->crypto.rx.ckm = NULL;
|
|
+
|
|
return rv;
|
|
}
|
|
|
|
@@ -10393,6 +10976,9 @@ int ngtcp2_conn_install_vneg_initial_key(
|
|
rv = ngtcp2_crypto_km_new(&conn->vneg.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
|
|
conn->mem);
|
|
if (rv != 0) {
|
|
+ ngtcp2_crypto_km_del(conn->vneg.rx.ckm, conn->mem);
|
|
+ conn->vneg.rx.ckm = NULL;
|
|
+
|
|
return rv;
|
|
}
|
|
|
|
@@ -10430,8 +11016,7 @@ int ngtcp2_conn_install_rx_handshake_key(
|
|
if (rv != 0) {
|
|
ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
|
|
pktns->crypto.rx.ckm = NULL;
|
|
-
|
|
- memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx));
|
|
+ pktns->crypto.rx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
|
|
|
|
return rv;
|
|
}
|
|
@@ -10461,21 +11046,26 @@ int ngtcp2_conn_install_tx_handshake_key(
|
|
if (conn->server) {
|
|
rv = ngtcp2_conn_commit_local_transport_params(conn);
|
|
if (rv != 0) {
|
|
- return rv;
|
|
+ goto fail;
|
|
}
|
|
}
|
|
|
|
rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE);
|
|
if (rv != 0) {
|
|
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
|
|
- pktns->crypto.tx.ckm = NULL;
|
|
-
|
|
- memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
|
|
-
|
|
- return rv;
|
|
+ goto fail;
|
|
}
|
|
|
|
return 0;
|
|
+
|
|
+fail:
|
|
+ /* If this function fails, aead_ctx and hp_ctx are still owned by
|
|
+ the caller. Delete the install key to remove the any reference
|
|
+ to them. */
|
|
+ ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
|
|
+ pktns->crypto.tx.ckm = NULL;
|
|
+ pktns->crypto.tx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
|
|
+
|
|
+ return rv;
|
|
}
|
|
|
|
int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn,
|
|
@@ -10506,8 +11096,7 @@ int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn,
|
|
if (rv != 0) {
|
|
ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
|
|
conn->early.ckm = NULL;
|
|
-
|
|
- memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx));
|
|
+ conn->early.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
|
|
|
|
return rv;
|
|
}
|
|
@@ -10554,8 +11143,7 @@ int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret,
|
|
if (rv != 0) {
|
|
ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
|
|
pktns->crypto.rx.ckm = NULL;
|
|
-
|
|
- memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx));
|
|
+ pktns->crypto.rx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
|
|
|
|
return rv;
|
|
}
|
|
@@ -10600,8 +11188,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret,
|
|
if (rv != 0) {
|
|
ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
|
|
pktns->crypto.tx.ckm = NULL;
|
|
-
|
|
- memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
|
|
+ pktns->crypto.tx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
|
|
|
|
return rv;
|
|
}
|
|
@@ -11059,9 +11646,9 @@ int ngtcp2_conn_set_remote_transport_params(
|
|
conn->local.transport_params.version_info.chosen_version =
|
|
conn->negotiated_version;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "the negotiated version is 0x%08x",
|
|
- conn->negotiated_version);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "the negotiated version is 0x%08x",
|
|
+ conn->negotiated_version);
|
|
} else {
|
|
rv = conn_client_validate_transport_params(conn, params);
|
|
if (rv != 0) {
|
|
@@ -11213,21 +11800,18 @@ int ngtcp2_conn_set_0rtt_remote_transport_params(
|
|
/* These parameters are treated specially. If server accepts early
|
|
data, it must not set values for these parameters that are
|
|
smaller than these remembered values. */
|
|
- conn->early.transport_params.initial_max_streams_bidi =
|
|
- params->initial_max_streams_bidi;
|
|
- conn->early.transport_params.initial_max_streams_uni =
|
|
- params->initial_max_streams_uni;
|
|
- conn->early.transport_params.initial_max_stream_data_bidi_local =
|
|
- params->initial_max_stream_data_bidi_local;
|
|
- conn->early.transport_params.initial_max_stream_data_bidi_remote =
|
|
- params->initial_max_stream_data_bidi_remote;
|
|
- conn->early.transport_params.initial_max_stream_data_uni =
|
|
- params->initial_max_stream_data_uni;
|
|
- conn->early.transport_params.initial_max_data = params->initial_max_data;
|
|
- conn->early.transport_params.active_connection_id_limit =
|
|
- params->active_connection_id_limit;
|
|
- conn->early.transport_params.max_datagram_frame_size =
|
|
- params->max_datagram_frame_size;
|
|
+ conn->early.transport_params = (ngtcp2_early_transport_params){
|
|
+ .initial_max_streams_bidi = params->initial_max_streams_bidi,
|
|
+ .initial_max_streams_uni = params->initial_max_streams_uni,
|
|
+ .initial_max_stream_data_bidi_local =
|
|
+ params->initial_max_stream_data_bidi_local,
|
|
+ .initial_max_stream_data_bidi_remote =
|
|
+ params->initial_max_stream_data_bidi_remote,
|
|
+ .initial_max_stream_data_uni = params->initial_max_stream_data_uni,
|
|
+ .initial_max_data = params->initial_max_data,
|
|
+ .active_connection_id_limit = params->active_connection_id_limit,
|
|
+ .max_datagram_frame_size = params->max_datagram_frame_size,
|
|
+ };
|
|
|
|
conn_sync_stream_id_limit(conn);
|
|
|
|
@@ -11417,17 +12001,20 @@ conn_write_vmsg_wrapper(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
return nwrite;
|
|
}
|
|
|
|
+ assert((size_t)nwrite <= destlen);
|
|
+
|
|
if (cstat->bytes_in_flight >= cstat->cwnd) {
|
|
conn->rst.is_cwnd_limited = 1;
|
|
} else if ((cstat->cwnd >= cstat->ssthresh ||
|
|
cstat->bytes_in_flight * 2 < cstat->cwnd) &&
|
|
nwrite == 0 && conn_pacing_pkt_tx_allowed(conn, ts) &&
|
|
- (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
|
|
- conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight;
|
|
-
|
|
- if (conn->rst.app_limited == 0) {
|
|
- conn->rst.app_limited = cstat->max_tx_udp_payload_size;
|
|
- }
|
|
+ (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) &&
|
|
+ /* Because NGTCP2_CONN_FLAG_AGGREGATE_PKTS is set after a
|
|
+ packet is produced, if it is set, we are sure that we
|
|
+ are not app-limited. */
|
|
+ !(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS)) {
|
|
+ conn->rst.app_limited =
|
|
+ ngtcp2_max_uint64(conn->rst.delivered + cstat->bytes_in_flight, 1);
|
|
}
|
|
|
|
return nwrite;
|
|
@@ -11471,12 +12058,17 @@ ngtcp2_ssize ngtcp2_conn_writev_stream_versioned(
|
|
return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
- vmsg.type = NGTCP2_VMSG_TYPE_STREAM;
|
|
- vmsg.stream.strm = strm;
|
|
- vmsg.stream.flags = flags;
|
|
- vmsg.stream.data = datav;
|
|
- vmsg.stream.datacnt = datavcnt;
|
|
- vmsg.stream.pdatalen = pdatalen;
|
|
+ vmsg = (ngtcp2_vmsg){
|
|
+ .type = NGTCP2_VMSG_TYPE_STREAM,
|
|
+ .stream =
|
|
+ {
|
|
+ .strm = strm,
|
|
+ .data = datav,
|
|
+ .datacnt = datavcnt,
|
|
+ .pdatalen = pdatalen,
|
|
+ .flags = flags,
|
|
+ },
|
|
+ };
|
|
|
|
pvmsg = &vmsg;
|
|
}
|
|
@@ -11549,12 +12141,17 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned(
|
|
return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
- vmsg.type = NGTCP2_VMSG_TYPE_DATAGRAM;
|
|
- vmsg.datagram.dgram_id = dgram_id;
|
|
- vmsg.datagram.flags = flags;
|
|
- vmsg.datagram.data = datav;
|
|
- vmsg.datagram.datacnt = datavcnt;
|
|
- vmsg.datagram.paccepted = paccepted;
|
|
+ vmsg = (ngtcp2_vmsg){
|
|
+ .type = NGTCP2_VMSG_TYPE_DATAGRAM,
|
|
+ .datagram =
|
|
+ {
|
|
+ .data = datav,
|
|
+ .datacnt = datavcnt,
|
|
+ .dgram_id = dgram_id,
|
|
+ .paccepted = paccepted,
|
|
+ .flags = flags,
|
|
+ },
|
|
+ };
|
|
|
|
if (flags & NGTCP2_WRITE_DATAGRAM_FLAG_PADDING) {
|
|
wflags = NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY;
|
|
@@ -11610,27 +12207,29 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
conn_client_write_handshake(conn, pi, dest, destlen, wflags, vmsg, ts);
|
|
/* We might be unable to write a packet because of depletion of
|
|
congestion window budget, perhaps due to packet loss that
|
|
- shrinks the window drastically. */
|
|
- if (nwrite <= 0) {
|
|
+ shrinks the window drastically. Then continue if we are in
|
|
+ post-handshake. There, we might be able to write packets
|
|
+ exceeding CWND to avoid deadlock. */
|
|
+ if (nwrite < 0) {
|
|
return nwrite;
|
|
}
|
|
if (conn->state != NGTCP2_CS_POST_HANDSHAKE) {
|
|
return nwrite;
|
|
}
|
|
|
|
- assert(nwrite);
|
|
- assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
|
|
- assert(conn->negotiated_version);
|
|
+ if (nwrite) {
|
|
+ assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
|
|
+ assert(conn->negotiated_version);
|
|
|
|
- if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE &&
|
|
- ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
|
|
+ if (ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
|
|
NGTCP2_PKT_INITIAL) {
|
|
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
- }
|
|
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
+ }
|
|
|
|
- res = nwrite;
|
|
- dest += nwrite;
|
|
- destlen -= (size_t)nwrite;
|
|
+ res = nwrite;
|
|
+ dest += nwrite;
|
|
+ destlen -= (size_t)nwrite;
|
|
+ }
|
|
/* Break here so that we can coalesces 1RTT packet. */
|
|
break;
|
|
case NGTCP2_CS_SERVER_INITIAL:
|
|
@@ -11685,7 +12284,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
dest += nwrite;
|
|
destlen -= (size_t)nwrite;
|
|
|
|
- if (res < NGTCP2_MAX_UDP_PAYLOAD_SIZE && conn->in_pktns && nwrite > 0) {
|
|
+ if (conn->in_pktns && nwrite > 0) {
|
|
it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
|
|
if (!ngtcp2_ksl_it_end(&it)) {
|
|
rtbent = ngtcp2_ksl_it_get(&it);
|
|
@@ -11770,7 +12369,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
if (!conn->pktns.rtb.probe_pkt_left && conn_cwnd_is_zero(conn)) {
|
|
destlen = 0;
|
|
} else {
|
|
- if (res == 0) {
|
|
+ if (res == 0 && !(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS)) {
|
|
nwrite =
|
|
conn_write_path_response(conn, path, pi, dest, origdestlen, ts);
|
|
if (nwrite) {
|
|
@@ -11832,9 +12431,22 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
return nwrite;
|
|
}
|
|
if (nwrite > 0) {
|
|
+ /* This makes 1RTT packet padded. If 1RTT packet is not going
|
|
+ to be sent, packet is already padded. */
|
|
+ if (ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
|
|
+ NGTCP2_PKT_INITIAL) {
|
|
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
|
|
+ }
|
|
+
|
|
res = nwrite;
|
|
dest += nwrite;
|
|
destlen -= (size_t)nwrite;
|
|
+
|
|
+ /* We only exceed CWND to avoid deadlock. Do no write 1RTT
|
|
+ packet if CWND is depleted. */
|
|
+ if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) {
|
|
+ return res;
|
|
+ }
|
|
} else if (destlen == 0) {
|
|
res = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
|
|
if (res) {
|
|
@@ -11845,9 +12457,9 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
|
|
}
|
|
|
|
if (conn->pktns.rtb.probe_pkt_left) {
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
- "transmit probe pkt left=%zu",
|
|
- conn->pktns.rtb.probe_pkt_left);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
|
|
+ "transmit probe pkt left=%zu",
|
|
+ conn->pktns.rtb.probe_pkt_left);
|
|
|
|
nwrite = conn_write_pkt(conn, pi, dest, destlen, (size_t)res, vmsg,
|
|
NGTCP2_PKT_1RTT, wflags, ts);
|
|
@@ -11901,11 +12513,12 @@ conn_write_connection_close(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
|
|
ngtcp2_frame fr;
|
|
uint8_t flags = NGTCP2_WRITE_PKT_FLAG_NONE;
|
|
|
|
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
|
|
- fr.connection_close.error_code = error_code;
|
|
- fr.connection_close.frame_type = 0;
|
|
- fr.connection_close.reasonlen = reasonlen;
|
|
- fr.connection_close.reason = (uint8_t *)reason;
|
|
+ fr.connection_close = (ngtcp2_connection_close){
|
|
+ .type = NGTCP2_FRAME_CONNECTION_CLOSE,
|
|
+ .error_code = error_code,
|
|
+ .reasonlen = reasonlen,
|
|
+ .reason = (uint8_t *)reason,
|
|
+ };
|
|
|
|
if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
|
|
pkt_type != NGTCP2_PKT_INITIAL) {
|
|
@@ -12080,11 +12693,12 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt(
|
|
|
|
assert(conn->pktns.crypto.tx.ckm);
|
|
|
|
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE_APP;
|
|
- fr.connection_close.error_code = app_error_code;
|
|
- fr.connection_close.frame_type = 0;
|
|
- fr.connection_close.reasonlen = reasonlen;
|
|
- fr.connection_close.reason = (uint8_t *)reason;
|
|
+ fr.connection_close = (ngtcp2_connection_close){
|
|
+ .type = NGTCP2_FRAME_CONNECTION_CLOSE_APP,
|
|
+ .error_code = app_error_code,
|
|
+ .reasonlen = reasonlen,
|
|
+ .reason = (uint8_t *)reason,
|
|
+ };
|
|
|
|
nwrite = ngtcp2_conn_write_single_frame_pkt(
|
|
conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
|
|
@@ -12108,11 +12722,12 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt(
|
|
static void ccerr_init(ngtcp2_ccerr *ccerr, ngtcp2_ccerr_type type,
|
|
uint64_t error_code, const uint8_t *reason,
|
|
size_t reasonlen) {
|
|
- ccerr->type = type;
|
|
- ccerr->error_code = error_code;
|
|
- ccerr->frame_type = 0;
|
|
- ccerr->reason = (uint8_t *)reason;
|
|
- ccerr->reasonlen = reasonlen;
|
|
+ *ccerr = (ngtcp2_ccerr){
|
|
+ .type = type,
|
|
+ .error_code = error_code,
|
|
+ .reason = (uint8_t *)reason,
|
|
+ .reasonlen = reasonlen,
|
|
+ };
|
|
}
|
|
|
|
void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr) {
|
|
@@ -12147,7 +12762,7 @@ void ngtcp2_ccerr_set_liberr(ngtcp2_ccerr *ccerr, int liberr,
|
|
reasonlen);
|
|
|
|
return;
|
|
- };
|
|
+ }
|
|
|
|
ngtcp2_ccerr_set_transport_error(
|
|
ccerr, ngtcp2_err_infer_quic_transport_error_code(liberr), reason,
|
|
@@ -12528,8 +13143,8 @@ int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn) {
|
|
return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0;
|
|
}
|
|
|
|
-int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
- ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
|
|
+void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
+ ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
|
|
ngtcp2_conn_stat *cstat = &conn->cstat;
|
|
|
|
assert(rtt > 0);
|
|
@@ -12550,13 +13165,13 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
rtt < cstat->min_rtt + ack_delay) {
|
|
/* Ignore RTT sample if adjusting ack_delay causes the sample
|
|
less than min_rtt before handshake confirmation. */
|
|
- ngtcp2_log_info(
|
|
+ ngtcp2_log_infof(
|
|
&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
"ignore rtt sample because ack_delay is too large latest_rtt=%" PRIu64
|
|
" min_rtt=%" PRIu64 " ack_delay=%" PRIu64,
|
|
rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS,
|
|
ack_delay / NGTCP2_MILLISECONDS);
|
|
- return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
+ return;
|
|
}
|
|
|
|
cstat->latest_rtt = rtt;
|
|
@@ -12573,7 +13188,7 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
cstat->smoothed_rtt = (cstat->smoothed_rtt * 7 + rtt) / 8;
|
|
}
|
|
|
|
- ngtcp2_log_info(
|
|
+ ngtcp2_log_infof(
|
|
&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
"latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64
|
|
" rttvar=%" PRIu64 " ack_delay=%" PRIu64,
|
|
@@ -12581,23 +13196,12 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
cstat->min_rtt / NGTCP2_MILLISECONDS,
|
|
cstat->smoothed_rtt / NGTCP2_MILLISECONDS,
|
|
cstat->rttvar / NGTCP2_MILLISECONDS, ack_delay / NGTCP2_MILLISECONDS);
|
|
-
|
|
- return 0;
|
|
}
|
|
|
|
void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn,
|
|
int conn_info_version,
|
|
ngtcp2_conn_info *cinfo) {
|
|
- const ngtcp2_conn_stat *cstat = &conn->cstat;
|
|
- (void)conn_info_version;
|
|
-
|
|
- cinfo->latest_rtt = cstat->latest_rtt;
|
|
- cinfo->min_rtt = cstat->min_rtt;
|
|
- cinfo->smoothed_rtt = cstat->smoothed_rtt;
|
|
- cinfo->rttvar = cstat->rttvar;
|
|
- cinfo->cwnd = cstat->cwnd;
|
|
- cinfo->ssthresh = cstat->ssthresh;
|
|
- cinfo->bytes_in_flight = cstat->bytes_in_flight;
|
|
+ ngtcp2_conn_info_init_versioned(conn_info_version, cinfo, &conn->cstat);
|
|
}
|
|
|
|
static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn,
|
|
@@ -12679,9 +13283,10 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
if (earliest_loss_time != UINT64_MAX) {
|
|
cstat->loss_detection_timer = earliest_loss_time;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "loss_detection_timer=%" PRIu64 " nonzero crypto loss time",
|
|
- cstat->loss_detection_timer);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "loss_detection_timer=%" PRIu64
|
|
+ " nonzero crypto loss time",
|
|
+ cstat->loss_detection_timer);
|
|
return;
|
|
}
|
|
|
|
@@ -12705,9 +13310,9 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
timeout =
|
|
cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64,
|
|
- cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64,
|
|
+ cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS);
|
|
}
|
|
|
|
void ngtcp2_conn_cancel_loss_detection_timer(ngtcp2_conn *conn) {
|
|
@@ -12779,8 +13384,8 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
|
|
++cstat->pto_count;
|
|
|
|
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu",
|
|
- cstat->pto_count);
|
|
+ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu",
|
|
+ cstat->pto_count);
|
|
|
|
ngtcp2_conn_set_loss_detection_timer(conn, ts);
|
|
|
|
@@ -12821,7 +13426,6 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn,
|
|
const uint8_t *data, const size_t datalen) {
|
|
ngtcp2_pktns *pktns;
|
|
ngtcp2_frame_chain *frc;
|
|
- ngtcp2_stream *fr;
|
|
int rv;
|
|
|
|
if (datalen == 0) {
|
|
@@ -12849,21 +13453,22 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn,
|
|
return rv;
|
|
}
|
|
|
|
- rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc);
|
|
+ rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
+ &frc, 1, &conn->frc_objalloc, conn->mem);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
|
|
- fr = &frc->fr.stream;
|
|
-
|
|
- fr->type = NGTCP2_FRAME_CRYPTO;
|
|
- fr->flags = 0;
|
|
- fr->fin = 0;
|
|
- fr->stream_id = 0;
|
|
- fr->offset = pktns->crypto.tx.offset;
|
|
- fr->datacnt = 1;
|
|
- fr->data[0].len = datalen;
|
|
- fr->data[0].base = (uint8_t *)data;
|
|
+ frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
|
|
+ frc->fr.stream.flags = 0;
|
|
+ frc->fr.stream.fin = 0;
|
|
+ frc->fr.stream.stream_id = 0;
|
|
+ frc->fr.stream.offset = pktns->crypto.tx.offset;
|
|
+ frc->fr.stream.datacnt = 1;
|
|
+ frc->fr.stream.data[0] = (ngtcp2_vec){
|
|
+ .base = (uint8_t *)data,
|
|
+ .len = datalen,
|
|
+ };
|
|
|
|
rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc);
|
|
if (rv != 0) {
|
|
@@ -12968,20 +13573,46 @@ static size_t conn_get_num_active_dcid(ngtcp2_conn *conn) {
|
|
return n;
|
|
}
|
|
|
|
-static void copy_dcid_to_cid_token(ngtcp2_cid_token *dest,
|
|
+size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) {
|
|
+ ngtcp2_cid_token2 cid_tokens[/* current */ 1 + /* pv */ 2 +
|
|
+ NGTCP2_DCIDTR_MAX_RETIRED_DCID_SIZE];
|
|
+ size_t n, i;
|
|
+
|
|
+ if (!dest) {
|
|
+ return ngtcp2_conn_get_active_dcid2(conn, NULL);
|
|
+ }
|
|
+
|
|
+ n = ngtcp2_conn_get_active_dcid2(conn, cid_tokens);
|
|
+
|
|
+ for (i = 0; i < n; ++i) {
|
|
+ dest[i].seq = cid_tokens[i].seq;
|
|
+ dest[i].cid = cid_tokens[i].cid;
|
|
+ ngtcp2_path_storage_init2(&dest[i].ps, &cid_tokens[i].ps.path);
|
|
+ dest[i].token_present = cid_tokens[i].token_present;
|
|
+
|
|
+ if (dest[i].token_present) {
|
|
+ memcpy(dest[i].token, cid_tokens[i].token.data, sizeof(dest[i].token));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return n;
|
|
+}
|
|
+
|
|
+static void copy_dcid_to_cid_token(ngtcp2_cid_token2 *dest,
|
|
const ngtcp2_dcid *src) {
|
|
dest->seq = src->seq;
|
|
dest->cid = src->cid;
|
|
ngtcp2_path_storage_init2(&dest->ps, &src->ps.path);
|
|
if ((dest->token_present =
|
|
(src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) != 0)) {
|
|
- memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ dest->token = src->token;
|
|
}
|
|
}
|
|
|
|
-size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) {
|
|
+size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn,
|
|
+ ngtcp2_cid_token2 *dest) {
|
|
ngtcp2_pv *pv = conn->pv;
|
|
- ngtcp2_cid_token *orig = dest;
|
|
+ ngtcp2_cid_token2 *orig = dest;
|
|
ngtcp2_dcid *dcid;
|
|
size_t len, i;
|
|
|
|
@@ -13138,7 +13769,12 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn,
|
|
conn->pv = pv;
|
|
}
|
|
|
|
- return conn_call_activate_dcid(conn, &conn->dcid.current);
|
|
+ rv = conn_call_activate_dcid(conn, &conn->dcid.current);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ return conn_call_begin_path_validation(conn, conn->pv);
|
|
}
|
|
|
|
int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
@@ -13178,7 +13814,12 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
|
|
conn->pv = pv;
|
|
|
|
- return conn_call_activate_dcid(conn, &pv->dcid);
|
|
+ rv = conn_call_activate_dcid(conn, &pv->dcid);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ return conn_call_begin_path_validation(conn, conn->pv);
|
|
}
|
|
|
|
uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) {
|
|
@@ -13354,8 +13995,17 @@ int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id,
|
|
return 0;
|
|
}
|
|
|
|
+void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn, int64_t stream_id) {
|
|
+ ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id);
|
|
+
|
|
+ if (strm == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return strm->stream_user_data;
|
|
+}
|
|
+
|
|
void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
- uint64_t pacing_interval_m;
|
|
ngtcp2_duration wait, d;
|
|
|
|
conn_update_timestamp(conn, ts);
|
|
@@ -13364,20 +14014,9 @@ void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
|
|
return;
|
|
}
|
|
|
|
- if (conn->cstat.pacing_interval_m) {
|
|
- pacing_interval_m = conn->cstat.pacing_interval_m;
|
|
- } else {
|
|
- /* 1.25 is the under-utilization avoidance factor described in
|
|
- https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */
|
|
- pacing_interval_m = ((conn->cstat.first_rtt_sample_ts == UINT64_MAX
|
|
- ? NGTCP2_MILLISECONDS
|
|
- : conn->cstat.smoothed_rtt)
|
|
- << 10) *
|
|
- 100 / 125 / conn->cstat.cwnd;
|
|
- pacing_interval_m = ngtcp2_max_uint64(pacing_interval_m, 1);
|
|
- }
|
|
-
|
|
- wait = (ngtcp2_duration)((conn->tx.pacing.pktlen * pacing_interval_m) >> 10);
|
|
+ wait = (ngtcp2_duration)((conn->tx.pacing.pktlen *
|
|
+ conn->cstat.pacing_interval_m) >>
|
|
+ 10);
|
|
|
|
d = ngtcp2_min_uint64(wait / 2, conn->tx.pacing.compensation);
|
|
wait -= d;
|
|
@@ -13411,6 +14050,115 @@ void ngtcp2_conn_add_path_history(ngtcp2_conn *conn, const ngtcp2_dcid *dcid,
|
|
ent->ts = ts;
|
|
}
|
|
|
|
+ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned(
|
|
+ ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
|
|
+ ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
|
|
+ ngtcp2_write_pkt write_pkt, ngtcp2_tstamp ts) {
|
|
+ ngtcp2_ssize nwrite;
|
|
+
|
|
+ buflen = ngtcp2_min_size(buflen, ngtcp2_conn_get_send_quantum(conn));
|
|
+
|
|
+ nwrite = ngtcp2_conn_write_aggregate_pkt2_versioned(
|
|
+ conn, path, pkt_info_version, pi, buf, buflen, pgsolen, write_pkt, 0, ts);
|
|
+ if (nwrite < 0) {
|
|
+ return nwrite;
|
|
+ }
|
|
+
|
|
+ ngtcp2_conn_update_pkt_tx_time(conn, ts);
|
|
+
|
|
+ return nwrite;
|
|
+}
|
|
+
|
|
+ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned(
|
|
+ ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
|
|
+ ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
|
|
+ ngtcp2_write_pkt write_pkt, size_t num_pkts, ngtcp2_tstamp ts) {
|
|
+ size_t max_udp_payloadlen = ngtcp2_conn_get_max_tx_udp_payload_size(conn);
|
|
+ size_t path_max_udp_payloadlen =
|
|
+ ngtcp2_conn_get_path_max_tx_udp_payload_size(conn);
|
|
+ ngtcp2_ssize nwrite;
|
|
+ uint8_t *wbuf = buf;
|
|
+ size_t wbuflen;
|
|
+ ngtcp2_ecn_state ecn_state;
|
|
+ int first_pkt;
|
|
+ ngtcp2_pkt_info pi_discard;
|
|
+ ngtcp2_path_storage path_discard;
|
|
+ (void)pkt_info_version;
|
|
+
|
|
+ assert(buflen >= path_max_udp_payloadlen);
|
|
+
|
|
+ if (num_pkts == 0) {
|
|
+ num_pkts = SIZE_MAX;
|
|
+ }
|
|
+
|
|
+ for (;;) {
|
|
+ ecn_state = conn->tx.ecn.state;
|
|
+
|
|
+ wbuflen = buflen >= max_udp_payloadlen ? max_udp_payloadlen
|
|
+ : path_max_udp_payloadlen;
|
|
+
|
|
+ nwrite = write_pkt(conn, path, pi, wbuf, wbuflen, ts, conn->user_data);
|
|
+ if (nwrite < 0) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (nwrite == 0) {
|
|
+ nwrite = wbuf - buf;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ first_pkt = buf == wbuf;
|
|
+ wbuf += nwrite;
|
|
+ buflen -= (size_t)nwrite;
|
|
+
|
|
+ --num_pkts;
|
|
+
|
|
+ if (first_pkt) {
|
|
+ assert(!(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS));
|
|
+
|
|
+ *pgsolen = (size_t)nwrite;
|
|
+
|
|
+ if ((size_t)nwrite != path_max_udp_payloadlen ||
|
|
+ buflen < path_max_udp_payloadlen || ecn_state != conn->tx.ecn.state ||
|
|
+ num_pkts == 0) {
|
|
+ nwrite = wbuf - buf;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* All aggregated packets should share the same path and pi.
|
|
+ Pass the placeholder values to the callback because they
|
|
+ might be overwritten by later calls, especially pi is set to
|
|
+ empty when no packet is produced. */
|
|
+ if (path) {
|
|
+ ngtcp2_path_storage_zero(&path_discard);
|
|
+ path = &path_discard.path;
|
|
+ }
|
|
+
|
|
+ if (pi) {
|
|
+ pi = &pi_discard;
|
|
+ }
|
|
+
|
|
+ conn->flags |= NGTCP2_CONN_FLAG_AGGREGATE_PKTS;
|
|
+
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (buflen < path_max_udp_payloadlen || (size_t)nwrite < *pgsolen ||
|
|
+ ecn_state != conn->tx.ecn.state || num_pkts == 0) {
|
|
+ nwrite = wbuf - buf;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ conn->flags &= ~NGTCP2_CONN_FLAG_AGGREGATE_PKTS;
|
|
+
|
|
+ return nwrite;
|
|
+}
|
|
+
|
|
+ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn) {
|
|
+ return conn->log.last_ts;
|
|
+}
|
|
+
|
|
const ngtcp2_path_history_entry *
|
|
ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
ngtcp2_tstamp ts) {
|
|
@@ -13434,9 +14182,9 @@ ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path,
|
|
|
|
void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
|
|
const ngtcp2_path *path,
|
|
- const uint8_t *data) {
|
|
+ const ngtcp2_path_challenge_data *data) {
|
|
ngtcp2_path_storage_init2(&pcent->ps, path);
|
|
- memcpy(pcent->data, data, sizeof(pcent->data));
|
|
+ pcent->data = *data;
|
|
}
|
|
|
|
/* The functions prefixed with ngtcp2_pkt_ are usually put inside
|
|
@@ -13454,7 +14202,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close(
|
|
ngtcp2_crypto_km ckm;
|
|
ngtcp2_crypto_cc cc;
|
|
ngtcp2_ppe ppe;
|
|
- ngtcp2_frame fr = {0};
|
|
+ ngtcp2_frame fr;
|
|
int rv;
|
|
|
|
ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_INITIAL, dcid,
|
|
@@ -13485,11 +14233,12 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close(
|
|
return NGTCP2_ERR_NOBUF;
|
|
}
|
|
|
|
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
|
|
- fr.connection_close.error_code = error_code;
|
|
- fr.connection_close.frame_type = 0;
|
|
- fr.connection_close.reasonlen = reasonlen;
|
|
- fr.connection_close.reason = (uint8_t *)reason;
|
|
+ fr.connection_close = (ngtcp2_connection_close){
|
|
+ .type = NGTCP2_FRAME_CONNECTION_CLOSE,
|
|
+ .error_code = error_code,
|
|
+ .reasonlen = reasonlen,
|
|
+ .reason = (uint8_t *)reason,
|
|
+ };
|
|
|
|
rv = ngtcp2_ppe_encode_frame(&ppe, &fr);
|
|
if (rv != 0) {
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_conn.h b/third_party/ngtcp2/lib/ngtcp2_conn.h
|
|
index 5979d39654b..47175736d42 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_conn.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_conn.h
|
|
@@ -52,6 +52,8 @@
|
|
#include "ngtcp2_rst.h"
|
|
#include "ngtcp2_conn_stat.h"
|
|
#include "ngtcp2_dcidtr.h"
|
|
+#include "ngtcp2_pcg.h"
|
|
+#include "ngtcp2_ratelim.h"
|
|
|
|
typedef enum {
|
|
/* Client specific handshake states */
|
|
@@ -75,10 +77,6 @@ typedef enum {
|
|
unreceived data. */
|
|
#define NGTCP2_MAX_REORDERED_CRYPTO_DATA 65536
|
|
|
|
-/* NGTCP2_MAX_RETRIES is the number of Retry packet which client can
|
|
- accept. */
|
|
-#define NGTCP2_MAX_RETRIES 3
|
|
-
|
|
/* NGTCP2_MAX_SCID_POOL_SIZE is the maximum number of source
|
|
connection ID the local endpoint provides to the remote endpoint.
|
|
The chosen value was described in old draft. Now a remote endpoint
|
|
@@ -96,48 +94,35 @@ typedef enum {
|
|
#define NGTCP2_CCERR_MAX_REASONLEN 1024
|
|
|
|
/* NGTCP2_WRITE_PKT_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_WRITE_PKT_FLAG_NONE 0x00u
|
|
+#define NGTCP2_WRITE_PKT_FLAG_NONE 0x00U
|
|
/* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING indicates that packet other
|
|
than Initial packet should be padded so that UDP datagram payload
|
|
is at least NGTCP2_MAX_UDP_PAYLOAD_SIZE bytes. Initial packet
|
|
might be padded based on QUIC requirement regardless of this
|
|
flag. */
|
|
-#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING 0x01u
|
|
+#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING 0x01U
|
|
/* NGTCP2_WRITE_PKT_FLAG_MORE indicates that more frames might come
|
|
and it should be encoded into the current packet. */
|
|
-#define NGTCP2_WRITE_PKT_FLAG_MORE 0x02u
|
|
+#define NGTCP2_WRITE_PKT_FLAG_MORE 0x02U
|
|
/* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL is just like
|
|
NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING, but it requests to add
|
|
padding to the full UDP datagram payload size. */
|
|
-#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04u
|
|
+#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04U
|
|
/* NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY adds padding to the QUIC
|
|
packet as much as possible if the packet is not empty. */
|
|
-#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08u
|
|
-
|
|
-/*
|
|
- * ngtcp2_max_frame is defined so that it covers the largest ACK
|
|
- * frame.
|
|
- */
|
|
-typedef union ngtcp2_max_frame {
|
|
- ngtcp2_frame fr;
|
|
- struct {
|
|
- ngtcp2_ack ack;
|
|
- /* ack includes 1 ngtcp2_ack_range. */
|
|
- ngtcp2_ack_range ranges[NGTCP2_MAX_ACK_RANGES - 1];
|
|
- } ackfr;
|
|
-} ngtcp2_max_frame;
|
|
+#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08U
|
|
|
|
typedef struct ngtcp2_path_challenge_entry {
|
|
ngtcp2_path_storage ps;
|
|
- uint8_t data[8];
|
|
+ ngtcp2_path_challenge_data data;
|
|
} ngtcp2_path_challenge_entry;
|
|
|
|
void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
|
|
const ngtcp2_path *path,
|
|
- const uint8_t *data);
|
|
+ const ngtcp2_path_challenge_data *data);
|
|
|
|
/* NGTCP2_CONN_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_CONN_FLAG_NONE 0x00u
|
|
+#define NGTCP2_CONN_FLAG_NONE 0x00U
|
|
/* NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED is set when TLS stack
|
|
declares that TLS handshake has completed. The condition of this
|
|
declaration varies between TLS implementations and this flag does
|
|
@@ -145,61 +130,69 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
|
|
implementations declare TLS handshake completion as server when
|
|
they write off Server Finished and before deriving application rx
|
|
secret. */
|
|
-#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01u
|
|
+#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01U
|
|
/* NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED is set when the first
|
|
Initial packet has successfully been processed. */
|
|
-#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02u
|
|
+#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02U
|
|
/* NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED is set if transport
|
|
parameters are received. */
|
|
-#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04u
|
|
+#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04U
|
|
/* NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED is set when a
|
|
local transport parameters are applied. */
|
|
-#define NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED 0x08u
|
|
+#define NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED 0x08U
|
|
/* NGTCP2_CONN_FLAG_RECV_RETRY is set when a client receives Retry
|
|
packet. */
|
|
-#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10u
|
|
+#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10U
|
|
/* NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED is set when 0-RTT packet is
|
|
rejected by a peer. */
|
|
-#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20u
|
|
+#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20U
|
|
/* NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED is set when the expired
|
|
keep-alive timer has been cancelled. */
|
|
-#define NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED 0x40u
|
|
+#define NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED 0x40U
|
|
/* NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED is set when an endpoint
|
|
confirmed completion of handshake. */
|
|
-#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80u
|
|
+#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80U
|
|
/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when the library
|
|
transitions its state to "post handshake". */
|
|
-#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100u
|
|
+#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100U
|
|
/* NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT is set when the early
|
|
handshake retransmission has done when server receives overlapping
|
|
Initial crypto data. */
|
|
-#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200u
|
|
+#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200U
|
|
/* NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT indicates that the local endpoint
|
|
sends a QUIC packet without Fixed Bit set if a remote endpoint
|
|
supports Greasing QUIC Bit extension. */
|
|
-#define NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT 0x0400u
|
|
+#define NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT 0x0400U
|
|
/* NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED is set when key update is
|
|
not confirmed by the local endpoint. That is, it has not received
|
|
ACK frame which acknowledges packet which is encrypted with new
|
|
key. */
|
|
-#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800u
|
|
+#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800U
|
|
/* NGTCP2_CONN_FLAG_PPE_PENDING is set when
|
|
NGTCP2_WRITE_STREAM_FLAG_MORE is used and the intermediate state of
|
|
ngtcp2_ppe is stored in pkt struct of ngtcp2_conn. */
|
|
-#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000u
|
|
+#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000U
|
|
/* NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE is set when idle timer
|
|
should be restarted on next write. */
|
|
-#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000u
|
|
+#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000U
|
|
/* NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED indicates that server as peer
|
|
verified client address. This flag is only used by client. */
|
|
-#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000u
|
|
+#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000U
|
|
/* NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED indicates that an early key is
|
|
installed. conn->early.ckm cannot be used for this purpose because
|
|
it might be discarded when a certain condition is met. */
|
|
-#define NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED 0x8000u
|
|
+#define NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED 0x8000U
|
|
/* NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR is set when the local
|
|
endpoint has initiated key update. */
|
|
-#define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000u
|
|
+#define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000U
|
|
+/* NGTCP2_CONN_FLAG_AGGREGATE_PKTS is set when
|
|
+ ngtcp2_conn_writev_stream is called inside the callback invoked by
|
|
+ ngtcp2_conn_write_aggregate_pkt. */
|
|
+#define NGTCP2_CONN_FLAG_AGGREGATE_PKTS 0x20000U
|
|
+/* NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO, if set, crumbles an
|
|
+ Initial CRYPTO frame into pieces as a countermeasure against Deep
|
|
+ Packet Inspection. */
|
|
+#define NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO 0x40000U
|
|
|
|
typedef struct ngtcp2_pktns {
|
|
struct {
|
|
@@ -394,14 +387,14 @@ struct ngtcp2_conn {
|
|
ngtcp2_tstamp last_max_data_ts;
|
|
|
|
struct {
|
|
- /* state is the state of ECN validation */
|
|
- ngtcp2_ecn_state state;
|
|
/* validation_start_ts is the timestamp when ECN validation is
|
|
started. It is UINT64_MAX if it has not started yet. */
|
|
ngtcp2_tstamp validation_start_ts;
|
|
/* dgram_sent is the number of UDP datagram sent during ECN
|
|
validation period. */
|
|
size_t dgram_sent;
|
|
+ /* state is the state of ECN validation */
|
|
+ ngtcp2_ecn_state state;
|
|
} ecn;
|
|
|
|
struct {
|
|
@@ -552,13 +545,13 @@ struct ngtcp2_conn {
|
|
/* retry_aead_ctx is AEAD cipher context to verify Retry packet
|
|
integrity. It is used by client only. */
|
|
ngtcp2_crypto_aead_ctx retry_aead_ctx;
|
|
+ /* decryption_failure_count is the number of received packets that
|
|
+ fail authentication. */
|
|
+ uint64_t decryption_failure_count;
|
|
/* tls_error is TLS related error. */
|
|
int tls_error;
|
|
/* tls_alert is TLS alert generated by the local endpoint. */
|
|
uint8_t tls_alert;
|
|
- /* decryption_failure_count is the number of received packets that
|
|
- fail authentication. */
|
|
- uint64_t decryption_failure_count;
|
|
} crypto;
|
|
|
|
/* pkt contains the packet intermediate construction data to support
|
|
@@ -568,13 +561,13 @@ struct ngtcp2_conn {
|
|
ngtcp2_pkt_hd hd;
|
|
ngtcp2_ppe ppe;
|
|
ngtcp2_frame_chain **pfrc;
|
|
+ ngtcp2_ssize hs_spktlen;
|
|
int pkt_empty;
|
|
int hd_logged;
|
|
+ int require_padding;
|
|
/* flags is bitwise OR of zero or more of
|
|
NGTCP2_RTB_ENTRY_FLAG_*. */
|
|
uint16_t rtb_entry_flags;
|
|
- ngtcp2_ssize hs_spktlen;
|
|
- int require_padding;
|
|
} pkt;
|
|
|
|
struct {
|
|
@@ -630,7 +623,6 @@ struct ngtcp2_conn {
|
|
ngtcp2_log log;
|
|
ngtcp2_qlog qlog;
|
|
ngtcp2_rst rst;
|
|
- ngtcp2_cc_algo cc_algo;
|
|
union {
|
|
ngtcp2_cc cc;
|
|
ngtcp2_cc_reno reno;
|
|
@@ -641,17 +633,23 @@ struct ngtcp2_conn {
|
|
successfully. The path is added to this history when a local
|
|
endpoint migrates to the another path. */
|
|
ngtcp2_static_ringbuf_path_history path_history;
|
|
+ /* glitch_rlim is the rate limit of glitches that can be tolerated.
|
|
+ If more than those glitches are detected, a connection is
|
|
+ closed. */
|
|
+ ngtcp2_ratelim glitch_rlim;
|
|
const ngtcp2_mem *mem;
|
|
/* idle_ts is the time instant when idle timer started. */
|
|
ngtcp2_tstamp idle_ts;
|
|
/* handshake_confirmed_ts is the time instant when handshake is
|
|
confirmed. For server, it is confirmed when completed. */
|
|
ngtcp2_tstamp handshake_confirmed_ts;
|
|
+ ngtcp2_pcg32 pcg;
|
|
void *user_data;
|
|
uint32_t client_chosen_version;
|
|
uint32_t negotiated_version;
|
|
/* flags is bitwise OR of zero or more of NGTCP2_CONN_FLAG_*. */
|
|
uint32_t flags;
|
|
+ ngtcp2_cc_algo cc_algo;
|
|
int server;
|
|
};
|
|
|
|
@@ -663,9 +661,6 @@ typedef enum ngtcp2_vmsg_type {
|
|
typedef struct ngtcp2_vmsg_stream {
|
|
/* strm is a stream that data is sent to. */
|
|
ngtcp2_strm *strm;
|
|
- /* flags is bitwise OR of zero or more of
|
|
- NGTCP2_WRITE_STREAM_FLAG_*. */
|
|
- uint32_t flags;
|
|
/* data is the pointer to ngtcp2_vec array which contains the stream
|
|
data to send. */
|
|
const ngtcp2_vec *data;
|
|
@@ -674,6 +669,9 @@ typedef struct ngtcp2_vmsg_stream {
|
|
/* pdatalen is the pointer to the variable which the number of bytes
|
|
written is assigned to if pdatalen is not NULL. */
|
|
ngtcp2_ssize *pdatalen;
|
|
+ /* flags is bitwise OR of zero or more of
|
|
+ NGTCP2_WRITE_STREAM_FLAG_*. */
|
|
+ uint32_t flags;
|
|
} ngtcp2_vmsg_stream;
|
|
|
|
typedef struct ngtcp2_vmsg_datagram {
|
|
@@ -684,12 +682,12 @@ typedef struct ngtcp2_vmsg_datagram {
|
|
size_t datacnt;
|
|
/* dgram_id is an opaque identifier chosen by an application. */
|
|
uint64_t dgram_id;
|
|
- /* flags is bitwise OR of zero or more of
|
|
- NGTCP2_WRITE_DATAGRAM_FLAG_*. */
|
|
- uint32_t flags;
|
|
/* paccepted is the pointer to the variable which, if it is not
|
|
NULL, is assigned nonzero if data is written to a packet. */
|
|
int *paccepted;
|
|
+ /* flags is bitwise OR of zero or more of
|
|
+ NGTCP2_WRITE_DATAGRAM_FLAG_*. */
|
|
+ uint32_t flags;
|
|
} ngtcp2_vmsg_datagram;
|
|
|
|
typedef struct ngtcp2_vmsg {
|
|
@@ -757,15 +755,9 @@ int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm);
|
|
* ack_delay included in ACK frame. |ack_delay| is actually tainted
|
|
* (sent by peer), so don't assume that |ack_delay| is always smaller
|
|
* than, or equals to |rtt|.
|
|
- *
|
|
- * This function returns 0 if it succeeds, or one of the following
|
|
- * negative error codes:
|
|
- *
|
|
- * NGTCP2_ERR_INVALID_ARGUMENT
|
|
- * RTT sample is ignored.
|
|
*/
|
|
-int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
- ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
|
|
+void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
|
+ ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
|
|
|
|
void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts);
|
|
|
|
@@ -951,7 +943,7 @@ ngtcp2_conn_server_negotiate_version(ngtcp2_conn *conn,
|
|
* @function
|
|
*
|
|
* `ngtcp2_conn_write_connection_close_pkt` writes a packet which
|
|
- * contains a CONNECTION_CLOSE frame (type 0x1c) in the buffer pointed
|
|
+ * contains a CONNECTION_CLOSE frame (type 0x1C) in the buffer pointed
|
|
* by |dest| whose capacity is |datalen|.
|
|
*
|
|
* If |path| is not ``NULL``, this function stores the network path
|
|
@@ -993,7 +985,7 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt(
|
|
* @function
|
|
*
|
|
* `ngtcp2_conn_write_application_close_pkt` writes a packet which
|
|
- * contains a CONNECTION_CLOSE frame (type 0x1d) in the buffer pointed
|
|
+ * contains a CONNECTION_CLOSE frame (type 0x1D) in the buffer pointed
|
|
* by |dest| whose capacity is |datalen|.
|
|
*
|
|
* If |path| is not ``NULL``, this function stores the network path
|
|
@@ -1006,7 +998,7 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt(
|
|
* if it succeeds. The metadata includes ECN markings.
|
|
*
|
|
* If handshake has not been confirmed yet, CONNECTION_CLOSE (type
|
|
- * 0x1c) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written
|
|
+ * 0x1C) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written
|
|
* instead.
|
|
*
|
|
* This function must not be called from inside the callback
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_conn_info.c b/third_party/ngtcp2/lib/ngtcp2_conn_info.c
|
|
new file mode 100644
|
|
index 00000000000..84bb8820f50
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_conn_info.c
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#include "ngtcp2_conn_info.h"
|
|
+#include "ngtcp2_conn_stat.h"
|
|
+
|
|
+void ngtcp2_conn_info_init_versioned(int conn_info_version,
|
|
+ ngtcp2_conn_info *cinfo,
|
|
+ const ngtcp2_conn_stat *cstat) {
|
|
+ cinfo->latest_rtt = cstat->latest_rtt;
|
|
+ cinfo->min_rtt = cstat->min_rtt;
|
|
+ cinfo->smoothed_rtt = cstat->smoothed_rtt;
|
|
+ cinfo->rttvar = cstat->rttvar;
|
|
+ cinfo->cwnd = cstat->cwnd;
|
|
+ cinfo->ssthresh = cstat->ssthresh;
|
|
+ cinfo->bytes_in_flight = cstat->bytes_in_flight;
|
|
+
|
|
+ switch (conn_info_version) {
|
|
+ case NGTCP2_CONN_INFO_V2:
|
|
+ cinfo->pkt_sent = cstat->pkt_sent;
|
|
+ cinfo->bytes_sent = cstat->bytes_sent;
|
|
+ cinfo->pkt_recv = cstat->pkt_recv;
|
|
+ cinfo->bytes_recv = cstat->bytes_recv;
|
|
+ cinfo->pkt_lost = cstat->pkt_lost;
|
|
+ cinfo->bytes_lost = cstat->bytes_lost;
|
|
+ cinfo->ping_recv = cstat->ping_recv;
|
|
+ cinfo->pkt_discarded = cstat->pkt_discarded;
|
|
+ }
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_conn_info.h b/third_party/ngtcp2/lib/ngtcp2_conn_info.h
|
|
new file mode 100644
|
|
index 00000000000..161309df304
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_conn_info.h
|
|
@@ -0,0 +1,45 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#ifndef NGTCP2_CONN_INFO_H
|
|
+#define NGTCP2_CONN_INFO_H
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include <config.h>
|
|
+#endif /* defined(HAVE_CONFIG_H) */
|
|
+
|
|
+#include <ngtcp2/ngtcp2.h>
|
|
+
|
|
+typedef struct ngtcp2_conn_stat ngtcp2_conn_stat;
|
|
+
|
|
+/*
|
|
+ * ngtcp2_conn_info_init_versioned initializes |cinfo| of version
|
|
+ * |conn_info_version| from |cstat|. This function only fills the
|
|
+ * fields of |cinfo| that are available in the specified version.
|
|
+ */
|
|
+void ngtcp2_conn_info_init_versioned(int conn_info_version,
|
|
+ ngtcp2_conn_info *cinfo,
|
|
+ const ngtcp2_conn_stat *cstat);
|
|
+
|
|
+#endif /* !defined(NGTCP2_CONN_INFO_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_conn_stat.h b/third_party/ngtcp2/lib/ngtcp2_conn_stat.h
|
|
index be041b90860..b5fea473910 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_conn_stat.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_conn_stat.h
|
|
@@ -31,6 +31,8 @@
|
|
|
|
#include <ngtcp2/ngtcp2.h>
|
|
|
|
+#include "ngtcp2_pktns_id.h"
|
|
+
|
|
/**
|
|
* @struct
|
|
*
|
|
@@ -128,6 +130,43 @@ typedef struct ngtcp2_conn_stat {
|
|
* scheduled and transmitted together.
|
|
*/
|
|
size_t send_quantum;
|
|
+ /*
|
|
+ * pkt_sent is the number of QUIC packets sent.
|
|
+ */
|
|
+ uint64_t pkt_sent;
|
|
+ /*
|
|
+ * bytes_sent is the number of bytes (the sum of QUIC packet length)
|
|
+ * sent.
|
|
+ */
|
|
+ uint64_t bytes_sent;
|
|
+ /*
|
|
+ * pkt_recv is the number of QUIC packets received, excluding
|
|
+ * discarded ones.
|
|
+ */
|
|
+ uint64_t pkt_recv;
|
|
+ /*
|
|
+ * bytes_recv is the number of bytes (the sum of QUIC packet length)
|
|
+ * received, excluding discarded ones.
|
|
+ */
|
|
+ uint64_t bytes_recv;
|
|
+ /*
|
|
+ * pkt_lost is the number of QUIC packets that are considered lost,
|
|
+ * excluding PMTUD packets.
|
|
+ */
|
|
+ uint64_t pkt_lost;
|
|
+ /*
|
|
+ * bytes_lost is the number of bytes (the sum of QUIC packet length)
|
|
+ * lost, excluding PMTUD packets.
|
|
+ */
|
|
+ uint64_t bytes_lost;
|
|
+ /*
|
|
+ * ping_recv is the number of PING frames received.
|
|
+ */
|
|
+ uint64_t ping_recv;
|
|
+ /*
|
|
+ * pkt_discarded is the number of QUIC packets discarded.
|
|
+ */
|
|
+ uint64_t pkt_discarded;
|
|
} ngtcp2_conn_stat;
|
|
|
|
#endif /* !defined(NGTCP2_CONN_STAT_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_conv.c b/third_party/ngtcp2/lib/ngtcp2_conv.c
|
|
index 6528011cc0e..a0cef0c8643 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_conv.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_conv.c
|
|
@@ -63,33 +63,33 @@ const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p) {
|
|
}
|
|
|
|
static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) {
|
|
- union {
|
|
- uint8_t n8;
|
|
- uint16_t n16;
|
|
- uint32_t n32;
|
|
- uint64_t n64;
|
|
- } n;
|
|
+ uint16_t n16;
|
|
+ uint32_t n32;
|
|
+ uint64_t n64;
|
|
|
|
switch (*p >> 6) {
|
|
case 0:
|
|
*dest = *p++;
|
|
return p;
|
|
case 1:
|
|
- memcpy(&n, p, 2);
|
|
- n.n8 &= 0x3f;
|
|
- *dest = ngtcp2_ntohs(n.n16);
|
|
+ memcpy(&n16, p, 2);
|
|
+ n16 = ngtcp2_ntohs(n16);
|
|
+ n16 &= 0x3FFF;
|
|
+ *dest = n16;
|
|
|
|
return p + 2;
|
|
case 2:
|
|
- memcpy(&n, p, 4);
|
|
- n.n8 &= 0x3f;
|
|
- *dest = ngtcp2_ntohl(n.n32);
|
|
+ memcpy(&n32, p, 4);
|
|
+ n32 = ngtcp2_ntohl(n32);
|
|
+ n32 &= 0x3FFFFFFF;
|
|
+ *dest = n32;
|
|
|
|
return p + 4;
|
|
case 3:
|
|
- memcpy(&n, p, 8);
|
|
- n.n8 &= 0x3f;
|
|
- *dest = ngtcp2_ntohl64(n.n64);
|
|
+ memcpy(&n64, p, 8);
|
|
+ n64 = ngtcp2_ntohl64(n64);
|
|
+ n64 &= 0x3FFFFFFFFFFFFFFF;
|
|
+ *dest = n64;
|
|
|
|
return p + 8;
|
|
default:
|
|
@@ -168,7 +168,7 @@ uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n) {
|
|
}
|
|
assert(n < 4611686018427387904ULL);
|
|
rv = ngtcp2_put_uint64be(p, n);
|
|
- *p |= 0xc0;
|
|
+ *p |= 0xC0;
|
|
return rv;
|
|
}
|
|
|
|
@@ -200,7 +200,7 @@ uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len) {
|
|
}
|
|
|
|
size_t ngtcp2_get_uvarintlen(const uint8_t *p) {
|
|
- return (size_t)(1u << (*p >> 6));
|
|
+ return (size_t)(1U << (*p >> 6));
|
|
}
|
|
|
|
size_t ngtcp2_put_uvarintlen(uint64_t n) {
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_crypto.c b/third_party/ngtcp2/lib/ngtcp2_crypto.c
|
|
index 1f74e8c5839..078568fde3b 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_crypto.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_crypto.c
|
|
@@ -65,15 +65,21 @@ int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
|
|
}
|
|
|
|
p = (uint8_t *)(*pckm) + sizeof(ngtcp2_crypto_km);
|
|
- (*pckm)->secret.base = p;
|
|
- (*pckm)->secret.len = secretlen;
|
|
- p += secretlen;
|
|
- (*pckm)->iv.base = p;
|
|
- (*pckm)->iv.len = ivlen;
|
|
- (*pckm)->aead_ctx.native_handle = NULL;
|
|
- (*pckm)->pkt_num = -1;
|
|
- (*pckm)->use_count = 0;
|
|
- (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
|
|
+
|
|
+ **pckm = (ngtcp2_crypto_km){
|
|
+ .secret =
|
|
+ {
|
|
+ .base = p,
|
|
+ .len = secretlen,
|
|
+ },
|
|
+ .iv =
|
|
+ {
|
|
+ .base = p + secretlen,
|
|
+ .len = ivlen,
|
|
+ },
|
|
+ .pkt_num = -1,
|
|
+ .flags = NGTCP2_CRYPTO_KM_FLAG_NONE,
|
|
+ };
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_crypto.h b/third_party/ngtcp2/lib/ngtcp2_crypto.h
|
|
index ca6d494846f..c1e786b5fc7 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_crypto.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_crypto.h
|
|
@@ -42,10 +42,10 @@
|
|
#define NGTCP2_MAX_AEAD_OVERHEAD 16
|
|
|
|
/* NGTCP2_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00u
|
|
+#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00U
|
|
/* NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE is set if key phase bit is
|
|
set. */
|
|
-#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01u
|
|
+#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01U
|
|
|
|
typedef struct ngtcp2_crypto_km {
|
|
ngtcp2_vec secret;
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_dcidtr.c b/third_party/ngtcp2/lib/ngtcp2_dcidtr.c
|
|
index 170b9f803cc..a312398bbfa 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_dcidtr.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_dcidtr.c
|
|
@@ -157,9 +157,9 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest,
|
|
return 0;
|
|
}
|
|
|
|
-int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
|
|
- const ngtcp2_path *path,
|
|
- const uint8_t *token) {
|
|
+int ngtcp2_dcidtr_verify_stateless_reset(
|
|
+ const ngtcp2_dcidtr *dtr, const ngtcp2_path *path,
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
const ngtcp2_dcid *dcid;
|
|
const ngtcp2_ringbuf *rb = &dtr->bound.rb;
|
|
size_t i, len = ngtcp2_ringbuf_len(rb);
|
|
@@ -176,7 +176,7 @@ int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
|
|
|
|
static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound,
|
|
uint64_t seq, const ngtcp2_cid *cid,
|
|
- const uint8_t *token) {
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
const ngtcp2_dcid *dcid;
|
|
size_t i, len = ngtcp2_ringbuf_len(rb);
|
|
int rv;
|
|
@@ -196,9 +196,9 @@ static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound,
|
|
return 0;
|
|
}
|
|
|
|
-int ngtcp2_dcidtr_verify_token_uniqueness(const ngtcp2_dcidtr *dtr, int *pfound,
|
|
- uint64_t seq, const ngtcp2_cid *cid,
|
|
- const uint8_t *token) {
|
|
+int ngtcp2_dcidtr_verify_token_uniqueness(
|
|
+ const ngtcp2_dcidtr *dtr, int *pfound, uint64_t seq, const ngtcp2_cid *cid,
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
int rv;
|
|
|
|
rv = verify_token_uniqueness(&dtr->bound.rb, pfound, seq, cid, token);
|
|
@@ -406,7 +406,8 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_retired_ts(const ngtcp2_dcidtr *dtr) {
|
|
}
|
|
|
|
void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq,
|
|
- const ngtcp2_cid *cid, const uint8_t *token) {
|
|
+ const ngtcp2_cid *cid,
|
|
+ const ngtcp2_stateless_reset_token *token) {
|
|
ngtcp2_dcid *dcid = ngtcp2_ringbuf_push_back(&dtr->unused.rb);
|
|
|
|
ngtcp2_dcid_init(dcid, seq, cid, token);
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_dcidtr.h b/third_party/ngtcp2/lib/ngtcp2_dcidtr.h
|
|
index 63043427bc0..945ed12bae1 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_dcidtr.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_dcidtr.h
|
|
@@ -154,9 +154,9 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest,
|
|
* There is no Destination Connection ID that matches the given
|
|
* |path| and |token|.
|
|
*/
|
|
-int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
|
|
- const ngtcp2_path *path,
|
|
- const uint8_t *token);
|
|
+int ngtcp2_dcidtr_verify_stateless_reset(
|
|
+ const ngtcp2_dcidtr *dtr, const ngtcp2_path *path,
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/*
|
|
* ngtcp2_dcidtr_verify_token_uniqueness verifies that the uniqueness
|
|
@@ -180,9 +180,9 @@ int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
|
|
* The given combination of values does not satisfy the above
|
|
* conditions.
|
|
*/
|
|
-int ngtcp2_dcidtr_verify_token_uniqueness(const ngtcp2_dcidtr *dtr, int *pfound,
|
|
- uint64_t seq, const ngtcp2_cid *cid,
|
|
- const uint8_t *token);
|
|
+int ngtcp2_dcidtr_verify_token_uniqueness(
|
|
+ const ngtcp2_dcidtr *dtr, int *pfound, uint64_t seq, const ngtcp2_cid *cid,
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/*
|
|
* ngtcp2_dcidtr_retire_inactive_dcid_prior_to retires inactive
|
|
@@ -273,7 +273,8 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_retired_ts(const ngtcp2_dcidtr *dtr);
|
|
* buffer space is full, the earliest ngtcp2_dcid is removed.
|
|
*/
|
|
void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq,
|
|
- const ngtcp2_cid *cid, const uint8_t *token);
|
|
+ const ngtcp2_cid *cid,
|
|
+ const ngtcp2_stateless_reset_token *token);
|
|
|
|
/*
|
|
* ngtcp2_dcidtr_pop_unused_cid_token removes an unused Destination
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_frame_chain.c b/third_party/ngtcp2/lib/ngtcp2_frame_chain.c
|
|
index 0f6b06a788d..ec0839b7a4d 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_frame_chain.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_frame_chain.c
|
|
@@ -36,7 +36,7 @@ int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- ngtcp2_frame_chain_init(*pfrc);
|
|
+ ngtcp2_frame_chain_init(*pfrc, NGTCP2_FRAME_CHAIN_FLAG_NONE);
|
|
|
|
return 0;
|
|
}
|
|
@@ -48,7 +48,7 @@ int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- ngtcp2_frame_chain_init(*pfrc);
|
|
+ ngtcp2_frame_chain_init(*pfrc, NGTCP2_FRAME_CHAIN_FLAG_MALLOC);
|
|
|
|
return 0;
|
|
}
|
|
@@ -57,14 +57,26 @@ int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
size_t datacnt,
|
|
ngtcp2_objalloc *objalloc,
|
|
const ngtcp2_mem *mem) {
|
|
+ int rv;
|
|
+
|
|
if (datacnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
|
|
- return ngtcp2_frame_chain_extralen_new(pfrc,
|
|
- sizeof(ngtcp2_vec) * (datacnt - 1) -
|
|
- NGTCP2_FRAME_CHAIN_STREAM_AVAIL,
|
|
- mem);
|
|
+ rv = ngtcp2_frame_chain_extralen_new(
|
|
+ pfrc,
|
|
+ sizeof(ngtcp2_vec) * (datacnt - NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES),
|
|
+ mem);
|
|
+ } else {
|
|
+ rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
|
|
+ }
|
|
+
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
}
|
|
|
|
- return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
|
|
+ (*pfrc)->fr.stream.data =
|
|
+ (ngtcp2_vec *)(void *)((uint8_t *)*pfrc +
|
|
+ offsetof(ngtcp2_frame_chain, buf));
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
@@ -87,9 +99,9 @@ int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
}
|
|
|
|
fr = &(*pfrc)->fr;
|
|
- fr->type = NGTCP2_FRAME_NEW_TOKEN;
|
|
+ fr->new_token.type = NGTCP2_FRAME_NEW_TOKEN;
|
|
|
|
- p = (uint8_t *)fr + sizeof(ngtcp2_new_token);
|
|
+ p = (uint8_t *)*pfrc + offsetof(ngtcp2_frame_chain, buf);
|
|
memcpy(p, token, tokenlen);
|
|
|
|
fr->new_token.token = p;
|
|
@@ -98,21 +110,6 @@ int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
return 0;
|
|
}
|
|
|
|
-void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) {
|
|
- ngtcp2_frame_chain_binder *binder;
|
|
-
|
|
- if (frc == NULL) {
|
|
- return;
|
|
- }
|
|
-
|
|
- binder = frc->binder;
|
|
- if (binder && --binder->refcount == 0) {
|
|
- ngtcp2_mem_free(mem, binder);
|
|
- }
|
|
-
|
|
- ngtcp2_mem_free(mem, frc);
|
|
-}
|
|
-
|
|
void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
|
|
ngtcp2_objalloc *objalloc,
|
|
const ngtcp2_mem *mem) {
|
|
@@ -122,39 +119,23 @@ void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
|
|
return;
|
|
}
|
|
|
|
- switch (frc->fr.type) {
|
|
- case NGTCP2_FRAME_CRYPTO:
|
|
- case NGTCP2_FRAME_STREAM:
|
|
- if (frc->fr.stream.datacnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
|
|
- ngtcp2_frame_chain_del(frc, mem);
|
|
-
|
|
- return;
|
|
- }
|
|
-
|
|
- break;
|
|
- case NGTCP2_FRAME_NEW_TOKEN:
|
|
- if (frc->fr.new_token.tokenlen > NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES) {
|
|
- ngtcp2_frame_chain_del(frc, mem);
|
|
-
|
|
- return;
|
|
- }
|
|
-
|
|
- break;
|
|
- }
|
|
-
|
|
binder = frc->binder;
|
|
if (binder && --binder->refcount == 0) {
|
|
ngtcp2_mem_free(mem, binder);
|
|
}
|
|
|
|
- frc->binder = NULL;
|
|
+ if (frc->flags & NGTCP2_FRAME_CHAIN_FLAG_MALLOC) {
|
|
+ ngtcp2_mem_free(mem, frc);
|
|
+ return;
|
|
+ }
|
|
|
|
ngtcp2_objalloc_frame_chain_release(objalloc, frc);
|
|
}
|
|
|
|
-void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) {
|
|
+void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc, uint32_t flags) {
|
|
frc->next = NULL;
|
|
frc->binder = NULL;
|
|
+ frc->flags = flags;
|
|
}
|
|
|
|
void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc,
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_frame_chain.h b/third_party/ngtcp2/lib/ngtcp2_frame_chain.h
|
|
index e7b33632529..c73100dbcba 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_frame_chain.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_frame_chain.h
|
|
@@ -36,10 +36,10 @@
|
|
|
|
/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is
|
|
set. */
|
|
-#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u
|
|
+#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00U
|
|
/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information
|
|
which a frame carries has been acknowledged. */
|
|
-#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u
|
|
+#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01U
|
|
|
|
/*
|
|
* ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to
|
|
@@ -57,6 +57,25 @@ typedef struct ngtcp2_frame_chain_binder {
|
|
int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder,
|
|
const ngtcp2_mem *mem);
|
|
|
|
+/* NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES is the number of datacnt
|
|
+ that changes allocation method. If datacnt is more than this
|
|
+ value, ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
|
+ Otherwise, it is allocated using ngtcp2_objalloc. */
|
|
+#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES 4
|
|
+
|
|
+/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
|
|
+ changes allocation method. If the length is more than this value,
|
|
+ ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
|
+ Otherwise, it is allocated using ngtcp2_objalloc. */
|
|
+#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES \
|
|
+ (NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES * sizeof(ngtcp2_vec))
|
|
+
|
|
+/* NGTCP2_FRAME_CHAIN_FLAG_NONE indicates no flag is set. */
|
|
+#define NGTCP2_FRAME_CHAIN_FLAG_NONE 0x0
|
|
+/* NGTCP2_FRAME_CHAIN_FLAG_MALLOC indicates that ngtcp2_frame_chain is
|
|
+ allocated by ngtcp2_mem_malloc. */
|
|
+#define NGTCP2_FRAME_CHAIN_FLAG_MALLOC 0x1
|
|
+
|
|
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
|
|
|
|
/*
|
|
@@ -67,7 +86,9 @@ struct ngtcp2_frame_chain {
|
|
struct {
|
|
ngtcp2_frame_chain *next;
|
|
ngtcp2_frame_chain_binder *binder;
|
|
+ uint32_t flags;
|
|
ngtcp2_frame fr;
|
|
+ uint8_t buf[sizeof(ngtcp2_vec) * NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES];
|
|
};
|
|
|
|
ngtcp2_opl_entry oplent;
|
|
@@ -90,10 +111,6 @@ ngtcp2_objalloc_decl(frame_chain, ngtcp2_frame_chain, oplent)
|
|
int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b,
|
|
const ngtcp2_mem *mem);
|
|
|
|
-/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that
|
|
- a ngtcp2_stream can include. */
|
|
-#define NGTCP2_MAX_STREAM_DATACNT 256
|
|
-
|
|
/*
|
|
* ngtcp2_frame_chain_objalloc_new allocates ngtcp2_frame_chain using
|
|
* |objalloc|.
|
|
@@ -108,26 +125,6 @@ int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
|
|
const ngtcp2_mem *mem);
|
|
|
|
-/* NGTCP2_FRAME_CHAIN_STREAM_AVAIL is the number of additional bytes
|
|
- available after ngtcp2_stream when it is embedded in
|
|
- ngtcp2_frame. */
|
|
-#define NGTCP2_FRAME_CHAIN_STREAM_AVAIL \
|
|
- (sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream))
|
|
-
|
|
-/* NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES is the number of datacnt
|
|
- that changes allocation method. If datacnt is more than this
|
|
- value, ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
|
- Otherwise, it is allocated using ngtcp2_objalloc. */
|
|
-#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES \
|
|
- (NGTCP2_FRAME_CHAIN_STREAM_AVAIL / sizeof(ngtcp2_vec) + 1)
|
|
-
|
|
-/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
|
|
- changes allocation method. If the length is more than this value,
|
|
- ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
|
- Otherwise, it is allocated using ngtcp2_objalloc. */
|
|
-#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES \
|
|
- (sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token))
|
|
-
|
|
/*
|
|
* ngtcp2_frame_chain_stream_datacnt_objalloc_new allocates enough
|
|
* data to store additional |datacnt| - 1 ngtcp2_vec object after
|
|
@@ -135,8 +132,6 @@ int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
|
|
* words, |datacnt| <= NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES,
|
|
* ngtcp2_frame_chain_objalloc_new is called internally. Otherwise,
|
|
* ngtcp2_frame_chain_extralen_new is used and objalloc is not used.
|
|
- * Therefore, it is important to call ngtcp2_frame_chain_objalloc_del
|
|
- * without changing datacnt field.
|
|
*/
|
|
int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
size_t datacnt,
|
|
@@ -157,24 +152,19 @@ int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
|
|
const ngtcp2_mem *mem);
|
|
|
|
/*
|
|
- * ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the
|
|
- * memory pointed by |frc|.
|
|
- */
|
|
-void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem);
|
|
-
|
|
-/*
|
|
- * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse.
|
|
- * It might just delete |frc| depending on the frame type and the size
|
|
- * of |frc|.
|
|
+ * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse
|
|
+ * if NGTCP2_FRAME_CHAIN_FLAG_MALLOC is not set in |frc|->flags.
|
|
+ * Otherwise, it deletes |frc|.
|
|
*/
|
|
void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
|
|
ngtcp2_objalloc *objalloc,
|
|
const ngtcp2_mem *mem);
|
|
|
|
/*
|
|
- * ngtcp2_frame_chain_init initializes |frc|.
|
|
+ * ngtcp2_frame_chain_init initializes |frc|. |flags| is bitwise-OR
|
|
+ * of zero or more of NGTCP2_FRAME_CHAIN_FLAG_*.
|
|
*/
|
|
-void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc);
|
|
+void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc, uint32_t flags);
|
|
|
|
/*
|
|
* ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_gaptr.c b/third_party/ngtcp2/lib/ngtcp2_gaptr.c
|
|
index d04b9634c20..267bd07225d 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_gaptr.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_gaptr.c
|
|
@@ -35,11 +35,11 @@ void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
|
|
}
|
|
|
|
static int gaptr_gap_init(ngtcp2_gaptr *gaptr) {
|
|
- ngtcp2_range range = {
|
|
- .end = UINT64_MAX,
|
|
- };
|
|
-
|
|
- return ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL);
|
|
+ return ngtcp2_ksl_insert(&gaptr->gap, NULL,
|
|
+ &(ngtcp2_range){
|
|
+ .end = UINT64_MAX,
|
|
+ },
|
|
+ NULL);
|
|
}
|
|
|
|
void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) {
|
|
@@ -116,10 +116,6 @@ uint64_t ngtcp2_gaptr_first_gap_offset(const ngtcp2_gaptr *gaptr) {
|
|
|
|
ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
|
|
uint64_t offset) {
|
|
- ngtcp2_range q = {
|
|
- .begin = offset,
|
|
- .end = offset + 1,
|
|
- };
|
|
ngtcp2_ksl_it it;
|
|
|
|
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
|
|
@@ -129,7 +125,11 @@ ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
|
|
return r;
|
|
}
|
|
|
|
- it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
|
|
+ it = ngtcp2_ksl_lower_bound_search(&gaptr->gap,
|
|
+ &(ngtcp2_range){
|
|
+ .begin = offset,
|
|
+ .end = offset + 1,
|
|
+ },
|
|
ngtcp2_ksl_range_exclusive_search);
|
|
|
|
assert(!ngtcp2_ksl_it_end(&it));
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ksl.c b/third_party/ngtcp2/lib/ngtcp2_ksl.c
|
|
index 22c131a1ac6..80000f42f9b 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_ksl.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ksl.c
|
|
@@ -31,71 +31,78 @@
|
|
|
|
#include "ngtcp2_macro.h"
|
|
#include "ngtcp2_mem.h"
|
|
-#include "ngtcp2_range.h"
|
|
|
|
static ngtcp2_ksl_blk null_blk;
|
|
|
|
ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent)
|
|
|
|
-static size_t ksl_nodelen(size_t keylen) {
|
|
- assert(keylen >= sizeof(uint64_t));
|
|
-
|
|
- return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0x7u) &
|
|
- ~(uintptr_t)0x7u;
|
|
-}
|
|
-
|
|
-static size_t ksl_blklen(size_t nodelen) {
|
|
- return sizeof(ngtcp2_ksl_blk) + nodelen * NGTCP2_KSL_MAX_NBLK -
|
|
- sizeof(uint64_t);
|
|
+static size_t ksl_blklen(size_t aligned_keylen) {
|
|
+ return sizeof(ngtcp2_ksl_blk) + NGTCP2_KSL_MAX_NBLK * aligned_keylen;
|
|
}
|
|
|
|
/*
|
|
- * ksl_node_set_key sets |key| to |node|.
|
|
+ * ksl_set_nth_key sets |key| to |n|th node under |blk|.
|
|
*/
|
|
-static void ksl_node_set_key(ngtcp2_ksl *ksl, ngtcp2_ksl_node *node,
|
|
- const void *key) {
|
|
- memcpy(node->key, key, ksl->keylen);
|
|
+static void ksl_set_nth_key(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
+ size_t n, const ngtcp2_ksl_key *key) {
|
|
+ memcpy(blk->keys + n * ksl->aligned_keylen, key, ksl->keylen);
|
|
}
|
|
|
|
void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar,
|
|
ngtcp2_ksl_search search, size_t keylen,
|
|
const ngtcp2_mem *mem) {
|
|
- size_t nodelen = ksl_nodelen(keylen);
|
|
+ size_t aligned_keylen;
|
|
+
|
|
+ assert(keylen >= sizeof(uint64_t));
|
|
+
|
|
+ aligned_keylen = (keylen + 0x7U) & ~0x7U;
|
|
+
|
|
+ assert(aligned_keylen <= UINT16_MAX);
|
|
|
|
ngtcp2_objalloc_init(&ksl->blkalloc,
|
|
- (ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu, mem);
|
|
+ (ksl_blklen(aligned_keylen) + 0xFU) & ~(uintptr_t)0xFU,
|
|
+ mem);
|
|
|
|
- ksl->head = NULL;
|
|
+ ksl->root = NULL;
|
|
ksl->front = ksl->back = NULL;
|
|
ksl->compar = compar;
|
|
ksl->search = search;
|
|
ksl->n = 0;
|
|
ksl->keylen = keylen;
|
|
- ksl->nodelen = nodelen;
|
|
+ ksl->aligned_keylen = aligned_keylen;
|
|
}
|
|
|
|
static ngtcp2_ksl_blk *ksl_blk_objalloc_new(ngtcp2_ksl *ksl) {
|
|
- return ngtcp2_objalloc_ksl_blk_len_get(&ksl->blkalloc,
|
|
- ksl_blklen(ksl->nodelen));
|
|
+ ngtcp2_ksl_blk *blk = ngtcp2_objalloc_ksl_blk_len_get(
|
|
+ &ksl->blkalloc, ksl_blklen(ksl->aligned_keylen));
|
|
+
|
|
+ if (!blk) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ blk->keys = (uint8_t *)blk + sizeof(*blk);
|
|
+ blk->aligned_keylen = (uint16_t)ksl->aligned_keylen;
|
|
+
|
|
+ return blk;
|
|
}
|
|
|
|
static void ksl_blk_objalloc_del(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
|
|
ngtcp2_objalloc_ksl_blk_release(&ksl->blkalloc, blk);
|
|
}
|
|
|
|
-static int ksl_head_init(ngtcp2_ksl *ksl) {
|
|
- ngtcp2_ksl_blk *head = ksl_blk_objalloc_new(ksl);
|
|
+static int ksl_root_init(ngtcp2_ksl *ksl) {
|
|
+ ngtcp2_ksl_blk *root = ksl_blk_objalloc_new(ksl);
|
|
|
|
- if (!head) {
|
|
+ if (!root) {
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- head->next = head->prev = NULL;
|
|
- head->n = 0;
|
|
- head->leaf = 1;
|
|
+ root->next = root->prev = NULL;
|
|
+ root->n = 0;
|
|
+ root->leaf = 1;
|
|
|
|
- ksl->head = head;
|
|
- ksl->front = ksl->back = head;
|
|
+ ksl->root = root;
|
|
+ ksl->front = ksl->back = root;
|
|
|
|
return 0;
|
|
}
|
|
@@ -109,7 +116,7 @@ static void ksl_free_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
|
|
|
|
if (!blk->leaf) {
|
|
for (i = 0; i < blk->n; ++i) {
|
|
- ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk);
|
|
+ ksl_free_blk(ksl, blk->nodes[i].blk);
|
|
}
|
|
}
|
|
|
|
@@ -118,12 +125,12 @@ static void ksl_free_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
|
|
#endif /* defined(NOMEMPOOL) */
|
|
|
|
void ngtcp2_ksl_free(ngtcp2_ksl *ksl) {
|
|
- if (!ksl || !ksl->head) {
|
|
+ if (!ksl || !ksl->root) {
|
|
return;
|
|
}
|
|
|
|
#ifdef NOMEMPOOL
|
|
- ksl_free_blk(ksl, ksl->head);
|
|
+ ksl_free_blk(ksl, ksl->root);
|
|
#endif /* defined(NOMEMPOOL) */
|
|
|
|
ngtcp2_objalloc_free(&ksl->blkalloc);
|
|
@@ -160,8 +167,10 @@ static ngtcp2_ksl_blk *ksl_split_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
|
|
rblk->n = blk->n / 2;
|
|
blk->n -= rblk->n;
|
|
|
|
- memcpy(rblk->nodes, blk->nodes + ksl->nodelen * blk->n,
|
|
- ksl->nodelen * rblk->n);
|
|
+ memcpy(rblk->nodes, blk->nodes + blk->n, rblk->n * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memcpy(rblk->keys, blk->keys + blk->n * ksl->aligned_keylen,
|
|
+ rblk->n * ksl->aligned_keylen);
|
|
|
|
assert(blk->n >= NGTCP2_KSL_MIN_NBLK);
|
|
assert(rblk->n >= NGTCP2_KSL_MIN_NBLK);
|
|
@@ -181,32 +190,31 @@ static ngtcp2_ksl_blk *ksl_split_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
|
|
* Out of memory.
|
|
*/
|
|
static int ksl_split_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
- ngtcp2_ksl_node *node;
|
|
- ngtcp2_ksl_blk *lblk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk, *rblk;
|
|
+ ngtcp2_ksl_blk *lblk = blk->nodes[i].blk, *rblk;
|
|
|
|
rblk = ksl_split_blk(ksl, lblk);
|
|
if (rblk == NULL) {
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- memmove(blk->nodes + (i + 2) * ksl->nodelen,
|
|
- blk->nodes + (i + 1) * ksl->nodelen,
|
|
- ksl->nodelen * (blk->n - (i + 1)));
|
|
+ memmove(blk->nodes + (i + 2), blk->nodes + (i + 1),
|
|
+ (blk->n - (i + 1)) * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memmove(blk->keys + (i + 1) * ksl->aligned_keylen,
|
|
+ blk->keys + i * ksl->aligned_keylen,
|
|
+ (blk->n - i) * ksl->aligned_keylen);
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
|
|
- node->blk = rblk;
|
|
+ blk->nodes[i + 1].blk = rblk;
|
|
++blk->n;
|
|
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
|
+ ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
- * ksl_split_head splits a head (root) block. It increases the height
|
|
- * of skip list by 1.
|
|
+ * ksl_split_root splits a root block. It increases the height of
|
|
+ * skip list by 1.
|
|
*
|
|
* It returns 0 if it succeeds, or one of the following negative error
|
|
* codes:
|
|
@@ -214,37 +222,34 @@ static int ksl_split_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
* NGTCP2_ERR_NOMEM
|
|
* Out of memory.
|
|
*/
|
|
-static int ksl_split_head(ngtcp2_ksl *ksl) {
|
|
- ngtcp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
|
|
- ngtcp2_ksl_node *node;
|
|
+static int ksl_split_root(ngtcp2_ksl *ksl) {
|
|
+ ngtcp2_ksl_blk *rblk = NULL, *lblk, *nroot = NULL;
|
|
|
|
- rblk = ksl_split_blk(ksl, ksl->head);
|
|
+ rblk = ksl_split_blk(ksl, ksl->root);
|
|
if (rblk == NULL) {
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- lblk = ksl->head;
|
|
+ lblk = ksl->root;
|
|
|
|
- nhead = ksl_blk_objalloc_new(ksl);
|
|
+ nroot = ksl_blk_objalloc_new(ksl);
|
|
|
|
- if (nhead == NULL) {
|
|
+ if (nroot == NULL) {
|
|
ksl_blk_objalloc_del(ksl, rblk);
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- nhead->next = nhead->prev = NULL;
|
|
- nhead->n = 2;
|
|
- nhead->leaf = 0;
|
|
+ nroot->next = nroot->prev = NULL;
|
|
+ nroot->n = 2;
|
|
+ nroot->leaf = 0;
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, nhead, 0);
|
|
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
|
- node->blk = lblk;
|
|
+ ksl_set_nth_key(ksl, nroot, 0, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
|
|
+ nroot->nodes[0].blk = lblk;
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, nhead, 1);
|
|
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
|
|
- node->blk = rblk;
|
|
+ ksl_set_nth_key(ksl, nroot, 1, ngtcp2_ksl_blk_nth_key(rblk, rblk->n - 1));
|
|
+ nroot->nodes[1].blk = rblk;
|
|
|
|
- ksl->head = nhead;
|
|
+ ksl->root = nroot;
|
|
|
|
return 0;
|
|
}
|
|
@@ -257,16 +262,17 @@ static int ksl_split_head(ngtcp2_ksl *ksl) {
|
|
*/
|
|
static void ksl_insert_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i,
|
|
const ngtcp2_ksl_key *key, void *data) {
|
|
- ngtcp2_ksl_node *node;
|
|
-
|
|
assert(blk->n < NGTCP2_KSL_MAX_NBLK);
|
|
|
|
- memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
|
|
- ksl->nodelen * (blk->n - i));
|
|
+ memmove(blk->nodes + (i + 1), blk->nodes + i,
|
|
+ (blk->n - i) * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memmove(blk->keys + (i + 1) * ksl->aligned_keylen,
|
|
+ blk->keys + i * ksl->aligned_keylen,
|
|
+ (blk->n - i) * ksl->aligned_keylen);
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
- ksl_node_set_key(ksl, node, key);
|
|
- node->data = data;
|
|
+ ksl_set_nth_key(ksl, blk, i, key);
|
|
+ blk->nodes[i].data = data;
|
|
|
|
++blk->n;
|
|
}
|
|
@@ -278,28 +284,27 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
size_t i;
|
|
int rv;
|
|
|
|
- if (!ksl->head) {
|
|
- rv = ksl_head_init(ksl);
|
|
+ if (!ksl->root) {
|
|
+ rv = ksl_root_init(ksl);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
- if (ksl->head->n == NGTCP2_KSL_MAX_NBLK) {
|
|
- rv = ksl_split_head(ksl);
|
|
+ if (ksl->root->n == NGTCP2_KSL_MAX_NBLK) {
|
|
+ rv = ksl_split_root(ksl);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
- blk = ksl->head;
|
|
+ blk = ksl->root;
|
|
|
|
for (;;) {
|
|
i = ksl->search(ksl, blk, key);
|
|
|
|
if (blk->leaf) {
|
|
- if (i < blk->n &&
|
|
- !ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
|
|
+ if (i < blk->n && !ksl->compar(key, ngtcp2_ksl_blk_nth_key(blk, i))) {
|
|
if (it) {
|
|
*it = ngtcp2_ksl_end(ksl);
|
|
}
|
|
@@ -311,7 +316,7 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
++ksl->n;
|
|
|
|
if (it) {
|
|
- ngtcp2_ksl_it_init(it, ksl, blk, i);
|
|
+ ngtcp2_ksl_it_init(it, blk, i);
|
|
}
|
|
|
|
return 0;
|
|
@@ -320,17 +325,17 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
if (i == blk->n) {
|
|
/* This insertion extends the largest key in this subtree. */
|
|
for (; !blk->leaf;) {
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1);
|
|
+ node = &blk->nodes[blk->n - 1];
|
|
if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
|
|
rv = ksl_split_node(ksl, blk, blk->n - 1);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1);
|
|
+ node = &blk->nodes[blk->n - 1];
|
|
}
|
|
|
|
- ksl_node_set_key(ksl, node, key);
|
|
+ ksl_set_nth_key(ksl, blk, blk->n - 1, key);
|
|
blk = node->blk;
|
|
}
|
|
|
|
@@ -338,13 +343,13 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
++ksl->n;
|
|
|
|
if (it) {
|
|
- ngtcp2_ksl_it_init(it, ksl, blk, blk->n - 1);
|
|
+ ngtcp2_ksl_it_init(it, blk, blk->n - 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
+ node = &blk->nodes[i];
|
|
|
|
if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
|
|
rv = ksl_split_node(ksl, blk, i);
|
|
@@ -352,12 +357,8 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
return rv;
|
|
}
|
|
|
|
- if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) {
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
|
|
-
|
|
- if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) {
|
|
- ksl_node_set_key(ksl, node, key);
|
|
- }
|
|
+ if (ksl->compar(ngtcp2_ksl_blk_nth_key(blk, i), key)) {
|
|
+ node = &blk->nodes[i + 1];
|
|
}
|
|
}
|
|
|
|
@@ -370,8 +371,12 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
* |i|.
|
|
*/
|
|
static void ksl_remove_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
- memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
|
|
- ksl->nodelen * (blk->n - (i + 1)));
|
|
+ memmove(blk->nodes + i, blk->nodes + (i + 1),
|
|
+ (blk->n - (i + 1)) * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memmove(blk->keys + i * ksl->aligned_keylen,
|
|
+ blk->keys + (i + 1) * ksl->aligned_keylen,
|
|
+ (blk->n - (i + 1)) * ksl->aligned_keylen);
|
|
|
|
--blk->n;
|
|
}
|
|
@@ -380,9 +385,9 @@ static void ksl_remove_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
* ksl_merge_node merges 2 nodes which are the nodes at the index of
|
|
* |i| and |i + 1|.
|
|
*
|
|
- * If |blk| is the head (root) block and it contains just 2 nodes
|
|
- * before merging nodes, the merged block becomes head block, which
|
|
- * decreases the height of |ksl| by 1.
|
|
+ * If |blk| is the root block and it contains just 2 nodes before
|
|
+ * merging nodes, the merged block becomes root block, which decreases
|
|
+ * the height of |ksl| by 1.
|
|
*
|
|
* This function returns the pointer to the merged block.
|
|
*/
|
|
@@ -393,15 +398,17 @@ static ngtcp2_ksl_blk *ksl_merge_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
|
|
assert(i + 1 < blk->n);
|
|
|
|
- lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
+ lnode = &blk->nodes[i];
|
|
|
|
lblk = lnode->blk;
|
|
- rblk = ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk;
|
|
+ rblk = blk->nodes[i + 1].blk;
|
|
|
|
- assert(lblk->n + rblk->n < NGTCP2_KSL_MAX_NBLK);
|
|
+ assert(lblk->n + rblk->n <= NGTCP2_KSL_MAX_NBLK);
|
|
|
|
- memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
|
|
- ksl->nodelen * rblk->n);
|
|
+ memcpy(lblk->nodes + lblk->n, rblk->nodes, rblk->n * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
|
|
+ rblk->n * ksl->aligned_keylen);
|
|
|
|
lblk->n += rblk->n;
|
|
lblk->next = rblk->next;
|
|
@@ -414,13 +421,12 @@ static ngtcp2_ksl_blk *ksl_merge_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
|
|
ksl_blk_objalloc_del(ksl, rblk);
|
|
|
|
- if (ksl->head == blk && blk->n == 2) {
|
|
- ksl_blk_objalloc_del(ksl, ksl->head);
|
|
- ksl->head = lblk;
|
|
+ if (ksl->root == blk && blk->n == 2) {
|
|
+ ksl_blk_objalloc_del(ksl, ksl->root);
|
|
+ ksl->root = lblk;
|
|
} else {
|
|
ksl_remove_node(ksl, blk, i + 1);
|
|
- ksl_node_set_key(ksl, lnode,
|
|
- ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
|
+ ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
|
|
}
|
|
|
|
return lblk;
|
|
@@ -438,8 +444,8 @@ static void ksl_shift_left(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
|
|
assert(i > 0);
|
|
|
|
- lnode = ngtcp2_ksl_nth_node(ksl, blk, i - 1);
|
|
- rnode = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
+ lnode = &blk->nodes[i - 1];
|
|
+ rnode = &blk->nodes[i];
|
|
|
|
lblk = lnode->blk;
|
|
rblk = rnode->blk;
|
|
@@ -453,15 +459,20 @@ static void ksl_shift_left(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
assert(lblk->n <= NGTCP2_KSL_MAX_NBLK - n);
|
|
assert(rblk->n >= NGTCP2_KSL_MIN_NBLK + n);
|
|
|
|
- memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes, ksl->nodelen * n);
|
|
+ memcpy(lblk->nodes + lblk->n, rblk->nodes, n * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
|
|
+ n * ksl->aligned_keylen);
|
|
|
|
lblk->n += (uint32_t)n;
|
|
rblk->n -= (uint32_t)n;
|
|
|
|
- ksl_node_set_key(ksl, lnode,
|
|
- ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
|
+ ksl_set_nth_key(ksl, blk, i - 1, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
|
|
+
|
|
+ memmove(rblk->nodes, rblk->nodes + n, rblk->n * sizeof(ngtcp2_ksl_node));
|
|
|
|
- memmove(rblk->nodes, rblk->nodes + ksl->nodelen * n, ksl->nodelen * rblk->n);
|
|
+ memmove(rblk->keys, rblk->keys + n * ksl->aligned_keylen,
|
|
+ rblk->n * ksl->aligned_keylen);
|
|
}
|
|
|
|
/*
|
|
@@ -476,8 +487,8 @@ static void ksl_shift_right(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
|
|
assert(i < blk->n - 1);
|
|
|
|
- lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
- rnode = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
|
|
+ lnode = &blk->nodes[i];
|
|
+ rnode = &blk->nodes[i + 1];
|
|
|
|
lblk = lnode->blk;
|
|
rblk = rnode->blk;
|
|
@@ -491,15 +502,20 @@ static void ksl_shift_right(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
|
|
assert(lblk->n >= NGTCP2_KSL_MIN_NBLK + n);
|
|
assert(rblk->n <= NGTCP2_KSL_MAX_NBLK - n);
|
|
|
|
- memmove(rblk->nodes + ksl->nodelen * n, rblk->nodes, ksl->nodelen * rblk->n);
|
|
+ memmove(rblk->nodes + n, rblk->nodes, rblk->n * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memmove(rblk->keys + n * ksl->aligned_keylen, rblk->keys,
|
|
+ rblk->n * ksl->aligned_keylen);
|
|
|
|
rblk->n += (uint32_t)n;
|
|
lblk->n -= (uint32_t)n;
|
|
|
|
- memcpy(rblk->nodes, lblk->nodes + ksl->nodelen * lblk->n, ksl->nodelen * n);
|
|
+ memcpy(rblk->nodes, lblk->nodes + lblk->n, n * sizeof(ngtcp2_ksl_node));
|
|
+
|
|
+ memcpy(rblk->keys, lblk->keys + lblk->n * ksl->aligned_keylen,
|
|
+ n * ksl->aligned_keylen);
|
|
|
|
- ksl_node_set_key(ksl, lnode,
|
|
- ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
|
+ ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
|
|
}
|
|
|
|
/*
|
|
@@ -516,9 +532,9 @@ int ngtcp2_ksl_remove_hint(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
const ngtcp2_ksl_key *key) {
|
|
ngtcp2_ksl_blk *blk = hint->blk;
|
|
|
|
- assert(ksl->head);
|
|
+ assert(ksl->root);
|
|
|
|
- if (blk->n <= NGTCP2_KSL_MIN_NBLK) {
|
|
+ if (blk != ksl->root && blk->n == NGTCP2_KSL_MIN_NBLK) {
|
|
return ngtcp2_ksl_remove(ksl, it, key);
|
|
}
|
|
|
|
@@ -528,9 +544,9 @@ int ngtcp2_ksl_remove_hint(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
|
|
if (it) {
|
|
if (hint->i == blk->n && blk->next) {
|
|
- ngtcp2_ksl_it_init(it, ksl, blk->next, 0);
|
|
+ ngtcp2_ksl_it_init(it, blk->next, 0);
|
|
} else {
|
|
- ngtcp2_ksl_it_init(it, ksl, blk, hint->i);
|
|
+ ngtcp2_ksl_it_init(it, blk, hint->i);
|
|
}
|
|
}
|
|
|
|
@@ -539,7 +555,7 @@ int ngtcp2_ksl_remove_hint(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
|
|
int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
const ngtcp2_ksl_key *key) {
|
|
- ngtcp2_ksl_blk *blk = ksl->head;
|
|
+ ngtcp2_ksl_blk *blk = ksl->root;
|
|
ngtcp2_ksl_node *node;
|
|
size_t i;
|
|
|
|
@@ -548,8 +564,8 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
}
|
|
|
|
if (!blk->leaf && blk->n == 2 &&
|
|
- ngtcp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGTCP2_KSL_MIN_NBLK &&
|
|
- ngtcp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGTCP2_KSL_MIN_NBLK) {
|
|
+ blk->nodes[0].blk->n == NGTCP2_KSL_MIN_NBLK &&
|
|
+ blk->nodes[1].blk->n == NGTCP2_KSL_MIN_NBLK) {
|
|
blk = ksl_merge_node(ksl, blk, 0);
|
|
}
|
|
|
|
@@ -565,7 +581,7 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
}
|
|
|
|
if (blk->leaf) {
|
|
- if (ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
|
|
+ if (ksl->compar(key, ngtcp2_ksl_blk_nth_key(blk, i))) {
|
|
if (it) {
|
|
*it = ngtcp2_ksl_end(ksl);
|
|
}
|
|
@@ -578,16 +594,16 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
|
|
if (it) {
|
|
if (blk->n == i && blk->next) {
|
|
- ngtcp2_ksl_it_init(it, ksl, blk->next, 0);
|
|
+ ngtcp2_ksl_it_init(it, blk->next, 0);
|
|
} else {
|
|
- ngtcp2_ksl_it_init(it, ksl, blk, i);
|
|
+ ngtcp2_ksl_it_init(it, blk, i);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
+ node = &blk->nodes[i];
|
|
|
|
if (node->blk->n > NGTCP2_KSL_MIN_NBLK) {
|
|
blk = node->blk;
|
|
@@ -596,16 +612,14 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
|
|
|
assert(node->blk->n == NGTCP2_KSL_MIN_NBLK);
|
|
|
|
- if (i + 1 < blk->n &&
|
|
- ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGTCP2_KSL_MIN_NBLK) {
|
|
+ if (i + 1 < blk->n && blk->nodes[i + 1].blk->n > NGTCP2_KSL_MIN_NBLK) {
|
|
ksl_shift_left(ksl, blk, i + 1);
|
|
blk = node->blk;
|
|
|
|
continue;
|
|
}
|
|
|
|
- if (i > 0 &&
|
|
- ngtcp2_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGTCP2_KSL_MIN_NBLK) {
|
|
+ if (i > 0 && blk->nodes[i - 1].blk->n > NGTCP2_KSL_MIN_NBLK) {
|
|
ksl_shift_right(ksl, blk, i - 1);
|
|
blk = node->blk;
|
|
|
|
@@ -631,12 +645,12 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound(const ngtcp2_ksl *ksl,
|
|
ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
|
|
const ngtcp2_ksl_key *key,
|
|
ngtcp2_ksl_search search) {
|
|
- ngtcp2_ksl_blk *blk = ksl->head;
|
|
+ ngtcp2_ksl_blk *blk = ksl->root;
|
|
ngtcp2_ksl_it it;
|
|
size_t i;
|
|
|
|
if (!blk) {
|
|
- ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
|
|
+ ngtcp2_ksl_it_init(&it, &null_blk, 0);
|
|
return it;
|
|
}
|
|
|
|
@@ -649,7 +663,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
|
|
i = 0;
|
|
}
|
|
|
|
- ngtcp2_ksl_it_init(&it, ksl, blk, i);
|
|
+ ngtcp2_ksl_it_init(&it, blk, i);
|
|
|
|
return it;
|
|
}
|
|
@@ -657,7 +671,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
|
|
if (i == blk->n) {
|
|
/* This happens if descendant has smaller key. Fast forward to
|
|
find last node in this subtree. */
|
|
- for (; !blk->leaf; blk = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
|
|
+ for (; !blk->leaf; blk = blk->nodes[blk->n - 1].blk)
|
|
;
|
|
|
|
if (blk->next) {
|
|
@@ -667,39 +681,41 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
|
|
i = blk->n;
|
|
}
|
|
|
|
- ngtcp2_ksl_it_init(&it, ksl, blk, i);
|
|
+ ngtcp2_ksl_it_init(&it, blk, i);
|
|
|
|
return it;
|
|
}
|
|
|
|
- blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk;
|
|
+ blk = blk->nodes[i].blk;
|
|
}
|
|
}
|
|
|
|
void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key,
|
|
const ngtcp2_ksl_key *new_key) {
|
|
- ngtcp2_ksl_blk *blk = ksl->head;
|
|
+ ngtcp2_ksl_blk *blk = ksl->root;
|
|
ngtcp2_ksl_node *node;
|
|
+ const ngtcp2_ksl_key *node_key;
|
|
size_t i;
|
|
|
|
- assert(ksl->head);
|
|
+ assert(ksl->root);
|
|
|
|
for (;;) {
|
|
i = ksl->search(ksl, blk, old_key);
|
|
|
|
assert(i < blk->n);
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
+ node = &blk->nodes[i];
|
|
+ node_key = ngtcp2_ksl_blk_nth_key(blk, i);
|
|
|
|
if (blk->leaf) {
|
|
- assert(key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key));
|
|
- ksl_node_set_key(ksl, node, new_key);
|
|
+ assert(key_equal(ksl->compar, node_key, old_key));
|
|
+ ksl_set_nth_key(ksl, blk, i, new_key);
|
|
|
|
return;
|
|
}
|
|
|
|
- if (key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key) ||
|
|
- ksl->compar((ngtcp2_ksl_key *)node->key, new_key)) {
|
|
- ksl_node_set_key(ksl, node, new_key);
|
|
+ if (key_equal(ksl->compar, node_key, old_key) ||
|
|
+ ksl->compar(node_key, new_key)) {
|
|
+ ksl_set_nth_key(ksl, blk, i, new_key);
|
|
}
|
|
|
|
blk = node->blk;
|
|
@@ -709,15 +725,15 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key,
|
|
size_t ngtcp2_ksl_len(const ngtcp2_ksl *ksl) { return ksl->n; }
|
|
|
|
void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) {
|
|
- if (!ksl->head) {
|
|
+ if (!ksl->root) {
|
|
return;
|
|
}
|
|
|
|
#ifdef NOMEMPOOL
|
|
- ksl_free_blk(ksl, ksl->head);
|
|
+ ksl_free_blk(ksl, ksl->root);
|
|
#endif /* defined(NOMEMPOOL) */
|
|
|
|
- ksl->front = ksl->back = ksl->head = NULL;
|
|
+ ksl->front = ksl->back = ksl->root = NULL;
|
|
ksl->n = 0;
|
|
|
|
ngtcp2_objalloc_clear(&ksl->blkalloc);
|
|
@@ -727,14 +743,12 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) {
|
|
static void ksl_print(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
size_t level) {
|
|
size_t i;
|
|
- ngtcp2_ksl_node *node;
|
|
|
|
fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
|
|
|
|
if (blk->leaf) {
|
|
for (i = 0; i < blk->n; ++i) {
|
|
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
|
|
- fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
|
|
+ fprintf(stderr, " %" PRId64, *(int64_t *)ngtcp2_ksl_blk_nth_key(blk, i));
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
@@ -743,26 +757,26 @@ static void ksl_print(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
}
|
|
|
|
for (i = 0; i < blk->n; ++i) {
|
|
- ksl_print(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
|
|
+ ksl_print(ksl, blk->nodes[i].blk, level + 1);
|
|
}
|
|
}
|
|
|
|
void ngtcp2_ksl_print(const ngtcp2_ksl *ksl) {
|
|
- if (!ksl->head) {
|
|
+ if (!ksl->root) {
|
|
return;
|
|
}
|
|
|
|
- ksl_print(ksl, ksl->head, 0);
|
|
+ ksl_print(ksl, ksl->root, 0);
|
|
}
|
|
#endif /* !defined(WIN32) */
|
|
|
|
ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) {
|
|
ngtcp2_ksl_it it;
|
|
|
|
- if (ksl->head) {
|
|
- ngtcp2_ksl_it_init(&it, ksl, ksl->front, 0);
|
|
+ if (ksl->root) {
|
|
+ ngtcp2_ksl_it_init(&it, ksl->front, 0);
|
|
} else {
|
|
- ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
|
|
+ ngtcp2_ksl_it_init(&it, &null_blk, 0);
|
|
}
|
|
|
|
return it;
|
|
@@ -771,18 +785,16 @@ ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) {
|
|
ngtcp2_ksl_it ngtcp2_ksl_end(const ngtcp2_ksl *ksl) {
|
|
ngtcp2_ksl_it it;
|
|
|
|
- if (ksl->head) {
|
|
- ngtcp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
|
|
+ if (ksl->root) {
|
|
+ ngtcp2_ksl_it_init(&it, ksl->back, ksl->back->n);
|
|
} else {
|
|
- ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
|
|
+ ngtcp2_ksl_it_init(&it, &null_blk, 0);
|
|
}
|
|
|
|
return it;
|
|
}
|
|
|
|
-void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
|
|
- ngtcp2_ksl_blk *blk, size_t i) {
|
|
- it->ksl = ksl;
|
|
+void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, ngtcp2_ksl_blk *blk, size_t i) {
|
|
it->blk = blk;
|
|
it->i = i;
|
|
}
|
|
@@ -802,12 +814,6 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it) {
|
|
return it->i == 0 && it->blk->prev == NULL;
|
|
}
|
|
|
|
-int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs) {
|
|
- const ngtcp2_range *a = lhs, *b = rhs;
|
|
- return a->begin < b->begin;
|
|
-}
|
|
-
|
|
ngtcp2_ksl_search_def(range, ngtcp2_ksl_range_compar)
|
|
|
|
size_t ngtcp2_ksl_range_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
@@ -815,13 +821,6 @@ size_t ngtcp2_ksl_range_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
return ksl_range_search(ksl, blk, key);
|
|
}
|
|
|
|
-int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs) {
|
|
- const ngtcp2_range *a = lhs, *b = rhs;
|
|
- return a->begin < b->begin && !(ngtcp2_max_uint64(a->begin, b->begin) <
|
|
- ngtcp2_min_uint64(a->end, b->end));
|
|
-}
|
|
-
|
|
ngtcp2_ksl_search_def(range_exclusive, ngtcp2_ksl_range_exclusive_compar)
|
|
|
|
size_t ngtcp2_ksl_range_exclusive_search(const ngtcp2_ksl *ksl,
|
|
@@ -830,11 +829,6 @@ size_t ngtcp2_ksl_range_exclusive_search(const ngtcp2_ksl *ksl,
|
|
return ksl_range_exclusive_search(ksl, blk, key);
|
|
}
|
|
|
|
-int ngtcp2_ksl_uint64_less(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs) {
|
|
- return *(uint64_t *)lhs < *(uint64_t *)rhs;
|
|
-}
|
|
-
|
|
ngtcp2_ksl_search_def(uint64_less, ngtcp2_ksl_uint64_less)
|
|
|
|
size_t ngtcp2_ksl_uint64_less_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
@@ -842,11 +836,6 @@ size_t ngtcp2_ksl_uint64_less_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
return ksl_uint64_less_search(ksl, blk, key);
|
|
}
|
|
|
|
-int ngtcp2_ksl_int64_greater(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs) {
|
|
- return *(int64_t *)lhs > *(int64_t *)rhs;
|
|
-}
|
|
-
|
|
ngtcp2_ksl_search_def(int64_greater, ngtcp2_ksl_int64_greater)
|
|
|
|
size_t ngtcp2_ksl_int64_greater_search(const ngtcp2_ksl *ksl,
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ksl.h b/third_party/ngtcp2/lib/ngtcp2_ksl.h
|
|
index de78bcb8070..8024a360cdb 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_ksl.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ksl.h
|
|
@@ -34,14 +34,15 @@
|
|
#include <ngtcp2/ngtcp2.h>
|
|
|
|
#include "ngtcp2_objalloc.h"
|
|
+#include "ngtcp2_range.h"
|
|
|
|
#define NGTCP2_KSL_DEGR 16
|
|
/* NGTCP2_KSL_MAX_NBLK is the maximum number of nodes which a single
|
|
block can contain. */
|
|
-#define NGTCP2_KSL_MAX_NBLK (2 * NGTCP2_KSL_DEGR - 1)
|
|
+#define NGTCP2_KSL_MAX_NBLK (2 * NGTCP2_KSL_DEGR)
|
|
/* NGTCP2_KSL_MIN_NBLK is the minimum number of nodes which a single
|
|
block other than root must contain. */
|
|
-#define NGTCP2_KSL_MIN_NBLK (NGTCP2_KSL_DEGR - 1)
|
|
+#define NGTCP2_KSL_MIN_NBLK NGTCP2_KSL_DEGR
|
|
|
|
/*
|
|
* ngtcp2_ksl_key represents key in ngtcp2_ksl.
|
|
@@ -55,22 +56,13 @@ typedef struct ngtcp2_ksl_blk ngtcp2_ksl_blk;
|
|
/*
|
|
* ngtcp2_ksl_node is a node which contains either ngtcp2_ksl_blk or
|
|
* opaque data. If a node is an internal node, it contains
|
|
- * ngtcp2_ksl_blk. Otherwise, it has data. The key is stored at the
|
|
- * location starting at key.
|
|
+ * ngtcp2_ksl_blk. Otherwise, it has data.
|
|
*/
|
|
struct ngtcp2_ksl_node {
|
|
union {
|
|
ngtcp2_ksl_blk *blk;
|
|
void *data;
|
|
};
|
|
- union {
|
|
- uint64_t align;
|
|
- /* key is a buffer to include key associated to this node.
|
|
- Because the length of key is unknown until ngtcp2_ksl_init is
|
|
- called, the actual buffer will be allocated after this
|
|
- field. */
|
|
- uint8_t key[1];
|
|
- };
|
|
};
|
|
|
|
/*
|
|
@@ -84,19 +76,19 @@ struct ngtcp2_ksl_blk {
|
|
/* prev points to the previous block if leaf field is
|
|
nonzero. */
|
|
ngtcp2_ksl_blk *prev;
|
|
+ ngtcp2_ksl_node nodes[NGTCP2_KSL_MAX_NBLK];
|
|
+ /* keys is a pointer to the buffer to include
|
|
+ NGTCP2_KSL_MAX_NBLK keys. Because the length of key is
|
|
+ unknown until ngtcp2_ksl_init is called, the actual buffer
|
|
+ will be allocated after this object. */
|
|
+ uint8_t *keys;
|
|
/* n is the number of nodes this object contains in nodes. */
|
|
uint32_t n;
|
|
+ /* aligned_keylen is the length of the single key including
|
|
+ alignment. */
|
|
+ uint16_t aligned_keylen;
|
|
/* leaf is nonzero if this block contains leaf nodes. */
|
|
- uint32_t leaf;
|
|
- union {
|
|
- uint64_t align;
|
|
- /* nodes is a buffer to contain NGTCP2_KSL_MAX_NBLK
|
|
- ngtcp2_ksl_node objects. Because ngtcp2_ksl_node object is
|
|
- allocated along with the additional variable length key
|
|
- storage, the size of buffer is unknown until ngtcp2_ksl_init is
|
|
- called. */
|
|
- uint8_t nodes[1];
|
|
- };
|
|
+ uint8_t leaf;
|
|
};
|
|
|
|
ngtcp2_opl_entry oplent;
|
|
@@ -131,11 +123,10 @@ typedef size_t (*ngtcp2_ksl_search)(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
static size_t ksl_##NAME##_search( \
|
|
const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, const ngtcp2_ksl_key *key) { \
|
|
size_t i; \
|
|
- ngtcp2_ksl_node *node; \
|
|
+ uint8_t *node_key; \
|
|
\
|
|
- for (i = 0, node = (ngtcp2_ksl_node *)(void *)blk->nodes; \
|
|
- i < blk->n && COMPAR((ngtcp2_ksl_key *)node->key, key); ++i, \
|
|
- node = (ngtcp2_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) \
|
|
+ for (i = 0, node_key = blk->keys; i < blk->n && COMPAR(node_key, key); \
|
|
+ ++i, node_key += ksl->aligned_keylen) \
|
|
; \
|
|
\
|
|
return i; \
|
|
@@ -147,7 +138,6 @@ typedef struct ngtcp2_ksl_it ngtcp2_ksl_it;
|
|
* ngtcp2_ksl_it is a bidirectional iterator to iterate nodes.
|
|
*/
|
|
struct ngtcp2_ksl_it {
|
|
- const ngtcp2_ksl *ksl;
|
|
ngtcp2_ksl_blk *blk;
|
|
size_t i;
|
|
};
|
|
@@ -157,8 +147,8 @@ struct ngtcp2_ksl_it {
|
|
*/
|
|
struct ngtcp2_ksl {
|
|
ngtcp2_objalloc blkalloc;
|
|
- /* head points to the root block. */
|
|
- ngtcp2_ksl_blk *head;
|
|
+ /* root points to the root block. */
|
|
+ ngtcp2_ksl_blk *root;
|
|
/* front points to the first leaf block. */
|
|
ngtcp2_ksl_blk *front;
|
|
/* back points to the last leaf block. */
|
|
@@ -169,9 +159,7 @@ struct ngtcp2_ksl {
|
|
size_t n;
|
|
/* keylen is the size of key */
|
|
size_t keylen;
|
|
- /* nodelen is the actual size of ngtcp2_ksl_node including key
|
|
- storage. */
|
|
- size_t nodelen;
|
|
+ size_t aligned_keylen;
|
|
};
|
|
|
|
/*
|
|
@@ -290,10 +278,12 @@ size_t ngtcp2_ksl_len(const ngtcp2_ksl *ksl);
|
|
void ngtcp2_ksl_clear(ngtcp2_ksl *ksl);
|
|
|
|
/*
|
|
- * ngtcp2_ksl_nth_node returns the |n|th node under |blk|.
|
|
+ * ngtcp2_ksl_blk_nth_key returns the |n|th key under |blk|.
|
|
*/
|
|
-#define ngtcp2_ksl_nth_node(KSL, BLK, N) \
|
|
- ((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
|
|
+static inline const ngtcp2_ksl_key *
|
|
+ngtcp2_ksl_blk_nth_key(const ngtcp2_ksl_blk *blk, size_t n) {
|
|
+ return blk->keys + n * blk->aligned_keylen;
|
|
+}
|
|
|
|
#ifndef WIN32
|
|
/*
|
|
@@ -307,26 +297,28 @@ void ngtcp2_ksl_print(const ngtcp2_ksl *ksl);
|
|
/*
|
|
* ngtcp2_ksl_it_init initializes |it|.
|
|
*/
|
|
-void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
|
|
- ngtcp2_ksl_blk *blk, size_t i);
|
|
+void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, ngtcp2_ksl_blk *blk, size_t i);
|
|
|
|
/*
|
|
* ngtcp2_ksl_it_get returns the data associated to the node which
|
|
* |it| points to. It is undefined to call this function when
|
|
* ngtcp2_ksl_it_end(it) returns nonzero.
|
|
*/
|
|
-#define ngtcp2_ksl_it_get(IT) \
|
|
- ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
|
|
+static inline void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it) {
|
|
+ return it->blk->nodes[it->i].data;
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_it_next advances the iterator by one. It is undefined
|
|
* if this function is called when ngtcp2_ksl_it_end(it) returns
|
|
* nonzero.
|
|
*/
|
|
-#define ngtcp2_ksl_it_next(IT) \
|
|
- (++(IT)->i == (IT)->blk->n && (IT)->blk->next \
|
|
- ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
|
|
- : 0)
|
|
+static inline void ngtcp2_ksl_it_next(ngtcp2_ksl_it *it) {
|
|
+ if (++it->i == it->blk->n && it->blk->next) {
|
|
+ it->blk = it->blk->next;
|
|
+ it->i = 0;
|
|
+ }
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_it_prev moves backward the iterator by one. It is
|
|
@@ -339,8 +331,9 @@ void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it);
|
|
* ngtcp2_ksl_it_end returns nonzero if |it| points to the one beyond
|
|
* the last node.
|
|
*/
|
|
-#define ngtcp2_ksl_it_end(IT) \
|
|
- ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
|
|
+static inline int ngtcp2_ksl_it_end(const ngtcp2_ksl_it *it) {
|
|
+ return it->blk->n == it->i && it->blk->next == NULL;
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_it_begin returns nonzero if |it| points to the first
|
|
@@ -354,8 +347,9 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it);
|
|
* It is undefined to call this function when ngtcp2_ksl_it_end(it)
|
|
* returns nonzero.
|
|
*/
|
|
-#define ngtcp2_ksl_it_key(IT) \
|
|
- ((ngtcp2_ksl_key *)ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
|
|
+static inline const ngtcp2_ksl_key *ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) {
|
|
+ return ngtcp2_ksl_blk_nth_key(it->blk, it->i);
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar.
|
|
@@ -363,8 +357,12 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it);
|
|
* returns nonzero if ((const ngtcp2_range *)lhs)->begin < ((const
|
|
* ngtcp2_range *)rhs)->begin.
|
|
*/
|
|
-int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs);
|
|
+static inline int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
|
|
+ const ngtcp2_ksl_key *rhs) {
|
|
+ const ngtcp2_range *a = (const ngtcp2_range *)lhs,
|
|
+ *b = (const ngtcp2_range *)rhs;
|
|
+ return a->begin < b->begin;
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_range_search is an implementation of ngtcp2_ksl_search
|
|
@@ -380,8 +378,13 @@ size_t ngtcp2_ksl_range_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
* *)lhs)->begin < ((const ngtcp2_range *)rhs)->begin, and the 2
|
|
* ranges do not intersect.
|
|
*/
|
|
-int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs);
|
|
+static inline int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
|
|
+ const ngtcp2_ksl_key *rhs) {
|
|
+ const ngtcp2_range *a = (const ngtcp2_range *)lhs,
|
|
+ *b = (const ngtcp2_range *)rhs;
|
|
+ return a->begin < b->begin && !(ngtcp2_max_uint64(a->begin, b->begin) <
|
|
+ ngtcp2_min_uint64(a->end, b->end));
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_range_exclusive_search is an implementation of
|
|
@@ -396,8 +399,10 @@ size_t ngtcp2_ksl_range_exclusive_search(const ngtcp2_ksl *ksl,
|
|
* |lhs| and |rhs| must point to uint64_t objects, and the function
|
|
* returns nonzero if *(uint64_t *)|lhs| < *(uint64_t *)|rhs|.
|
|
*/
|
|
-int ngtcp2_ksl_uint64_less(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs);
|
|
+static inline int ngtcp2_ksl_uint64_less(const ngtcp2_ksl_key *lhs,
|
|
+ const ngtcp2_ksl_key *rhs) {
|
|
+ return *(const uint64_t *)lhs < *(const uint64_t *)rhs;
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_uint64_less_search is an implementation of
|
|
@@ -411,8 +416,10 @@ size_t ngtcp2_ksl_uint64_less_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
|
|
* |lhs| and |rhs| must point to int64_t objects, and the function
|
|
* returns nonzero if *(int64_t *)|lhs| > *(int64_t *)|rhs|.
|
|
*/
|
|
-int ngtcp2_ksl_int64_greater(const ngtcp2_ksl_key *lhs,
|
|
- const ngtcp2_ksl_key *rhs);
|
|
+static inline int ngtcp2_ksl_int64_greater(const ngtcp2_ksl_key *lhs,
|
|
+ const ngtcp2_ksl_key *rhs) {
|
|
+ return *(const int64_t *)lhs > *(const int64_t *)rhs;
|
|
+}
|
|
|
|
/*
|
|
* ngtcp2_ksl_int64_greater_search is an implementation of
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_log.c b/third_party/ngtcp2/lib/ngtcp2_log.c
|
|
index fc4eb443517..191c64430b5 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_log.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_log.c
|
|
@@ -42,12 +42,12 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid,
|
|
ngtcp2_printf log_printf, ngtcp2_tstamp ts,
|
|
void *user_data) {
|
|
if (scid) {
|
|
- ngtcp2_encode_hex(log->scid, scid->data, scid->datalen);
|
|
+ ngtcp2_encode_hex_cstr(log->scid, scid->data, scid->datalen);
|
|
} else {
|
|
log->scid[0] = '\0';
|
|
}
|
|
log->log_printf = log_printf;
|
|
- log->events = 0xff;
|
|
+ log->events = 0xFF;
|
|
log->ts = log->last_ts = ts;
|
|
log->user_data = user_data;
|
|
}
|
|
@@ -90,23 +90,10 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid,
|
|
* Frame type in hex string.
|
|
*/
|
|
|
|
-#define NGTCP2_LOG_BUFLEN 4096
|
|
+#define NGTCP2_LOG_PKT "%s %" PRId64 " %s"
|
|
+#define NGTCP2_LOG_TP "remote transport_parameters"
|
|
|
|
-/* TODO Split second and remaining fraction with comma */
|
|
-#define NGTCP2_LOG_HD "I%08" PRIu64 " 0x%s %s"
|
|
-#define NGTCP2_LOG_PKT NGTCP2_LOG_HD " %s %" PRId64 " %s"
|
|
-#define NGTCP2_LOG_TP NGTCP2_LOG_HD " remote transport_parameters"
|
|
-
|
|
-#define NGTCP2_LOG_FRM_HD_FIELDS(DIR) \
|
|
- timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "frm", \
|
|
- (DIR), hd->pkt_num, strpkttype(hd)
|
|
-
|
|
-#define NGTCP2_LOG_PKT_HD_FIELDS(DIR) \
|
|
- timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "pkt", \
|
|
- (DIR), hd->pkt_num, strpkttype(hd)
|
|
-
|
|
-#define NGTCP2_LOG_TP_HD_FIELDS \
|
|
- timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "cry"
|
|
+#define NGTCP2_LOG_PKT_HD_FIELDS(DIR) (DIR), hd->pkt_num, strpkttype(hd)
|
|
|
|
static const char *strerrorcode(uint64_t error_code) {
|
|
switch (error_code) {
|
|
@@ -140,10 +127,14 @@ static const char *strerrorcode(uint64_t error_code) {
|
|
return "CRYPTO_BUFFER_EXCEEDED";
|
|
case NGTCP2_KEY_UPDATE_ERROR:
|
|
return "KEY_UPDATE_ERROR";
|
|
+ case NGTCP2_AEAD_LIMIT_REACHED:
|
|
+ return "AEAD_LIMIT_REACHED";
|
|
+ case NGTCP2_NO_VIABLE_PATH:
|
|
+ return "NO_VIABLE_PATH";
|
|
case NGTCP2_VERSION_NEGOTIATION_ERROR:
|
|
return "VERSION_NEGOTIATION_ERROR";
|
|
default:
|
|
- if (0x100u <= error_code && error_code <= 0x1ffu) {
|
|
+ if (0x100U <= error_code && error_code <= 0x1FFU) {
|
|
return "CRYPTO_ERROR";
|
|
}
|
|
return "(unknown)";
|
|
@@ -155,78 +146,41 @@ static const char *strapperrorcode(uint64_t app_error_code) {
|
|
return "(unknown)";
|
|
}
|
|
|
|
-static const char *strpkttype_long(uint8_t type) {
|
|
- switch (type) {
|
|
+static const char *strpkttype(const ngtcp2_pkt_hd *hd) {
|
|
+ switch (hd->type) {
|
|
case NGTCP2_PKT_INITIAL:
|
|
return "Initial";
|
|
- case NGTCP2_PKT_RETRY:
|
|
- return "Retry";
|
|
- case NGTCP2_PKT_HANDSHAKE:
|
|
- return "Handshake";
|
|
case NGTCP2_PKT_0RTT:
|
|
return "0RTT";
|
|
- default:
|
|
- return "(unknown)";
|
|
- }
|
|
-}
|
|
-
|
|
-static const char *strpkttype(const ngtcp2_pkt_hd *hd) {
|
|
- if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
|
|
- return strpkttype_long(hd->type);
|
|
- }
|
|
-
|
|
- switch (hd->type) {
|
|
+ case NGTCP2_PKT_HANDSHAKE:
|
|
+ return "Handshake";
|
|
+ case NGTCP2_PKT_RETRY:
|
|
+ return "Retry";
|
|
+ case NGTCP2_PKT_1RTT:
|
|
+ return "1RTT";
|
|
case NGTCP2_PKT_VERSION_NEGOTIATION:
|
|
return "VN";
|
|
case NGTCP2_PKT_STATELESS_RESET:
|
|
return "SR";
|
|
- case NGTCP2_PKT_1RTT:
|
|
- return "1RTT";
|
|
default:
|
|
return "(unknown)";
|
|
}
|
|
}
|
|
|
|
static const char *strpkttype_type_flags(uint8_t type, uint8_t flags) {
|
|
- ngtcp2_pkt_hd hd = {0};
|
|
-
|
|
- hd.type = type;
|
|
- hd.flags = flags;
|
|
-
|
|
- return strpkttype(&hd);
|
|
-}
|
|
-
|
|
-static const char *strevent(ngtcp2_log_event ev) {
|
|
- switch (ev) {
|
|
- case NGTCP2_LOG_EVENT_CON:
|
|
- return "con";
|
|
- case NGTCP2_LOG_EVENT_PKT:
|
|
- return "pkt";
|
|
- case NGTCP2_LOG_EVENT_FRM:
|
|
- return "frm";
|
|
- case NGTCP2_LOG_EVENT_LDC:
|
|
- return "ldc";
|
|
- case NGTCP2_LOG_EVENT_CRY:
|
|
- return "cry";
|
|
- case NGTCP2_LOG_EVENT_PTV:
|
|
- return "ptv";
|
|
- case NGTCP2_LOG_EVENT_CCA:
|
|
- return "cca";
|
|
- case NGTCP2_LOG_EVENT_NONE:
|
|
- default:
|
|
- return "non";
|
|
- }
|
|
+ return strpkttype(&(ngtcp2_pkt_hd){
|
|
+ .type = type,
|
|
+ .flags = flags,
|
|
+ });
|
|
}
|
|
|
|
-static uint64_t timestamp_cast(uint64_t ns) { return ns / NGTCP2_MILLISECONDS; }
|
|
-
|
|
static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_stream *fr, const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
|
|
- " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, fr->fin,
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
|
|
+ " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, fr->fin,
|
|
fr->offset, ngtcp2_vec_len(fr->data, fr->datacnt),
|
|
(fr->stream_id & 0x2) != 0);
|
|
}
|
|
@@ -236,58 +190,58 @@ static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
int64_t largest_ack, min_ack;
|
|
size_t i;
|
|
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64
|
|
- " ack_delay=%" PRIu64 "(%" PRIu64 ") ack_range_count=%zu"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->largest_ack,
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64
|
|
+ " ack_delay=%" PRIu64 "(%" PRIu64 ") ack_range_count=%zu",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->largest_ack,
|
|
fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay, fr->rangecnt);
|
|
|
|
largest_ack = fr->largest_ack;
|
|
min_ack = fr->largest_ack - (int64_t)fr->first_ack_range;
|
|
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
|
|
- "..%" PRId64 "] len=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, min_ack,
|
|
- fr->first_ack_range);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
|
|
+ "..%" PRId64 "] len=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, largest_ack,
|
|
+ min_ack, fr->first_ack_range);
|
|
|
|
for (i = 0; i < fr->rangecnt; ++i) {
|
|
const ngtcp2_ack_range *range = &fr->ranges[i];
|
|
largest_ack = min_ack - (int64_t)range->gap - 2;
|
|
min_ack = largest_ack - (int64_t)range->len;
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
|
|
- "..%" PRId64 "] gap=%" PRIu64
|
|
- " len=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack,
|
|
- min_ack, range->gap, range->len);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
|
|
+ "..%" PRId64 "] gap=%" PRIu64
|
|
+ " len=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, largest_ack,
|
|
+ min_ack, range->gap, range->len);
|
|
}
|
|
|
|
if (fr->type == NGTCP2_FRAME_ACK_ECN) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64
|
|
- " ect1=%" PRIu64 " ce=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->ecn.ect0,
|
|
- fr->ecn.ect1, fr->ecn.ce);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64
|
|
+ " ect1=%" PRIu64 " ce=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->ecn.ect0,
|
|
+ fr->ecn.ect1, fr->ecn.ce);
|
|
}
|
|
}
|
|
|
|
static void log_fr_padding(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_padding *fr, const char *dir) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->len);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->len);
|
|
}
|
|
|
|
static void log_fr_reset_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_reset_stream *fr,
|
|
const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
|
|
- " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
|
|
+ " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
strapperrorcode(fr->app_error_code), fr->app_error_code, fr->final_size);
|
|
}
|
|
|
|
@@ -297,189 +251,191 @@ static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
char reason[256];
|
|
size_t reasonlen = ngtcp2_min_size(sizeof(reason) - 1, fr->reasonlen);
|
|
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64
|
|
- ") error_code=%s(0x%" PRIx64 ") "
|
|
- "frame_type=%" PRIx64 " reason_len=%zu reason=[%s]"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64 ") error_code=%s(0x%" PRIx64
|
|
+ ") "
|
|
+ "frame_type=0x%" PRIx64 " reason_len=%zu reason=[%s]",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
|
|
fr->type == NGTCP2_FRAME_CONNECTION_CLOSE ? strerrorcode(fr->error_code)
|
|
: strapperrorcode(fr->error_code),
|
|
fr->error_code, fr->frame_type, fr->reasonlen,
|
|
- ngtcp2_encode_printable_ascii(reason, fr->reason, reasonlen));
|
|
+ ngtcp2_encode_printable_ascii_cstr(reason, fr->reason, reasonlen));
|
|
}
|
|
|
|
static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_max_data *fr, const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64 ") max_data=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_data);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64
|
|
+ ") max_data=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_data);
|
|
}
|
|
|
|
static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_max_stream_data *fr,
|
|
const char *dir) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64
|
|
- ") id=0x%" PRIx64
|
|
- " max_stream_data=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
- fr->max_stream_data);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64
|
|
+ ") id=0x%" PRIx64
|
|
+ " max_stream_data=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
+ fr->max_stream_data);
|
|
}
|
|
|
|
static void log_fr_max_streams(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_max_streams *fr, const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams);
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_streams);
|
|
}
|
|
|
|
static void log_fr_ping(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_ping *fr, const char *dir) {
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type);
|
|
}
|
|
|
|
static void log_fr_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_data_blocked *fr,
|
|
const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64 ") offset=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64
|
|
+ ") offset=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->offset);
|
|
}
|
|
|
|
static void log_fr_stream_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_stream_data_blocked *fr,
|
|
const char *dir) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64
|
|
- ") id=0x%" PRIx64 " offset=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
- fr->offset);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64
|
|
+ ") id=0x%" PRIx64 " offset=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
+ fr->offset);
|
|
}
|
|
|
|
static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_streams_blocked *fr,
|
|
const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams);
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_streams);
|
|
}
|
|
|
|
static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_new_connection_id *fr,
|
|
const char *dir) {
|
|
- uint8_t buf[sizeof(fr->stateless_reset_token) * 2 + 1];
|
|
- uint8_t cid[sizeof(fr->cid.data) * 2 + 1];
|
|
-
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64
|
|
- " cid=0x%s retire_prior_to=%" PRIu64
|
|
- " stateless_reset_token=0x%s"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq,
|
|
- (const char *)ngtcp2_encode_hex(cid, fr->cid.data, fr->cid.datalen),
|
|
+ char buf[sizeof(fr->token.data) * 2 + 1];
|
|
+ char cid[sizeof(fr->cid.data) * 2 + 1];
|
|
+
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64
|
|
+ " cid=0x%s retire_prior_to=%" PRIu64
|
|
+ " stateless_reset_token=0x%s",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq,
|
|
+ ngtcp2_encode_hex_cstr(cid, fr->cid.data, fr->cid.datalen),
|
|
fr->retire_prior_to,
|
|
- (const char *)ngtcp2_encode_hex(buf, fr->stateless_reset_token,
|
|
- sizeof(fr->stateless_reset_token)));
|
|
+ ngtcp2_encode_hex_cstr(buf, fr->token.data, sizeof(fr->token.data)));
|
|
}
|
|
|
|
static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_stop_sending *fr,
|
|
const char *dir) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64 ") id=0x%" PRIx64
|
|
- " app_error_code=%s(0x%" PRIx64 ")"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
- strapperrorcode(fr->app_error_code), fr->app_error_code);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64
|
|
+ ") id=0x%" PRIx64
|
|
+ " app_error_code=%s(0x%" PRIx64 ")",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
|
|
+ strapperrorcode(fr->app_error_code), fr->app_error_code);
|
|
}
|
|
|
|
static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_path_challenge *fr,
|
|
const char *dir) {
|
|
- uint8_t buf[sizeof(fr->data) * 2 + 1];
|
|
+ char buf[sizeof(fr->data.data) * 2 + 1];
|
|
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
|
|
- (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
|
|
+ ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data)));
|
|
}
|
|
|
|
static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_path_response *fr,
|
|
const char *dir) {
|
|
- uint8_t buf[sizeof(fr->data) * 2 + 1];
|
|
+ char buf[sizeof(fr->data.data) * 2 + 1];
|
|
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
|
|
- (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
|
|
+ ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data)));
|
|
}
|
|
|
|
static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_stream *fr, const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64 " len=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset,
|
|
- ngtcp2_vec_len(fr->data, fr->datacnt));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64
|
|
+ " len=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->offset,
|
|
+ ngtcp2_vec_len(fr->data, fr->datacnt));
|
|
}
|
|
|
|
static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_new_token *fr, const char *dir) {
|
|
/* Show at most first 64 bytes of token. If token is longer than 64
|
|
bytes, log first 64 bytes and then append "*" */
|
|
- uint8_t buf[128 + 1 + 1];
|
|
- uint8_t *p;
|
|
+ char buf[128 + 1 + 1];
|
|
+ char *p;
|
|
|
|
if (fr->tokenlen > 64) {
|
|
- p = ngtcp2_encode_hex(buf, fr->token, 64);
|
|
+ p = ngtcp2_encode_hex_cstr(buf, fr->token, 64);
|
|
p[128] = '*';
|
|
p[129] = '\0';
|
|
} else {
|
|
- p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen);
|
|
+ p = ngtcp2_encode_hex_cstr(buf, fr->token, fr->tokenlen);
|
|
}
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->tokenlen);
|
|
+
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, p, fr->tokenlen);
|
|
}
|
|
|
|
static void log_fr_retire_connection_id(ngtcp2_log *log,
|
|
const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_retire_connection_id *fr,
|
|
const char *dir) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64
|
|
+ ") seq=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq);
|
|
}
|
|
|
|
static void log_fr_handshake_done(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_handshake_done *fr,
|
|
const char *dir) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")"),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type);
|
|
}
|
|
|
|
static void log_fr_datagram(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_datagram *fr, const char *dir) {
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64),
|
|
- NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
|
|
- ngtcp2_vec_len(fr->data, fr->datacnt));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
|
|
+ NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64,
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
|
|
+ ngtcp2_vec_len(fr->data, fr->datacnt));
|
|
}
|
|
|
|
static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const ngtcp2_frame *fr, const char *dir) {
|
|
- switch (fr->type) {
|
|
+ switch (fr->hd.type) {
|
|
case NGTCP2_FRAME_STREAM:
|
|
log_fr_stream(log, hd, &fr->stream, dir);
|
|
break;
|
|
@@ -580,13 +536,13 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
}
|
|
|
|
for (i = 0; i < nsv; ++i) {
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_PKT " v=0x%08x"),
|
|
- NGTCP2_LOG_PKT_HD_FIELDS("rx"), sv[i]);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " v=0x%08x",
|
|
+ NGTCP2_LOG_PKT_HD_FIELDS("rx"), sv[i]);
|
|
}
|
|
}
|
|
|
|
-void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
|
|
- uint8_t buf[sizeof(sr->stateless_reset_token) * 2 + 1];
|
|
+void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr) {
|
|
+ char buf[sizeof(sr->token.data) * 2 + 1];
|
|
ngtcp2_pkt_hd shd;
|
|
ngtcp2_pkt_hd *hd = &shd;
|
|
|
|
@@ -594,23 +550,22 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
|
|
return;
|
|
}
|
|
|
|
- memset(&shd, 0, sizeof(shd));
|
|
-
|
|
- shd.type = NGTCP2_PKT_STATELESS_RESET;
|
|
+ shd = (ngtcp2_pkt_hd){
|
|
+ .type = NGTCP2_PKT_STATELESS_RESET,
|
|
+ };
|
|
|
|
- log->log_printf(
|
|
- log->user_data, (NGTCP2_LOG_PKT " token=0x%s randlen=%zu"),
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " token=0x%s randlen=%zu",
|
|
NGTCP2_LOG_PKT_HD_FIELDS("rx"),
|
|
- (const char *)ngtcp2_encode_hex(buf, sr->stateless_reset_token,
|
|
- sizeof(sr->stateless_reset_token)),
|
|
+ ngtcp2_encode_hex_cstr(buf, sr->token.data, sizeof(sr->token.data)),
|
|
sr->randlen);
|
|
}
|
|
|
|
void ngtcp2_log_remote_tp(ngtcp2_log *log,
|
|
const ngtcp2_transport_params *params) {
|
|
- uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1];
|
|
- uint8_t addr[16 * 2 + 7 + 1];
|
|
- uint8_t cid[NGTCP2_MAX_CIDLEN * 2 + 1];
|
|
+ char token[sizeof(params->stateless_reset_token) * 2 + 1];
|
|
+ char addr[16 * 2 + 7 + 1];
|
|
+ char cid[NGTCP2_MAX_CIDLEN * 2 + 1];
|
|
size_t i;
|
|
const ngtcp2_sockaddr_in *sa_in;
|
|
const ngtcp2_sockaddr_in6 *sa_in6;
|
|
@@ -622,127 +577,121 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log,
|
|
}
|
|
|
|
if (params->stateless_reset_token_present) {
|
|
- log->log_printf(
|
|
- log->user_data, (NGTCP2_LOG_TP " stateless_reset_token=0x%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_hex(token, params->stateless_reset_token,
|
|
- sizeof(params->stateless_reset_token)));
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " stateless_reset_token=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(token, params->stateless_reset_token,
|
|
+ sizeof(params->stateless_reset_token)));
|
|
}
|
|
|
|
if (params->preferred_addr_present) {
|
|
if (params->preferred_addr.ipv4_present) {
|
|
sa_in = ¶ms->preferred_addr.ipv4;
|
|
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_ipv4(
|
|
- addr, (const uint8_t *)&sa_in->sin_addr));
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in->sin_port));
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s",
|
|
+ ngtcp2_encode_ipv4_cstr(addr, (const uint8_t *)&sa_in->sin_addr));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " preferred_address.ipv4_port=%u",
|
|
+ ngtcp2_ntohs(sa_in->sin_port));
|
|
}
|
|
|
|
if (params->preferred_addr.ipv6_present) {
|
|
sa_in6 = ¶ms->preferred_addr.ipv6;
|
|
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_ipv6(
|
|
- addr, (const uint8_t *)&sa_in6->sin6_addr));
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in6->sin6_port));
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s",
|
|
+ ngtcp2_encode_ipv6_cstr(addr, (const uint8_t *)&sa_in6->sin6_addr));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " preferred_address.ipv6_port=%u",
|
|
+ ngtcp2_ntohs(sa_in6->sin6_port));
|
|
}
|
|
|
|
- log->log_printf(
|
|
- log->user_data, (NGTCP2_LOG_TP " preferred_address.cid=0x%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_hex(cid, params->preferred_addr.cid.data,
|
|
- params->preferred_addr.cid.datalen));
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_hex(
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " preferred_address.cid=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(cid, params->preferred_addr.cid.data,
|
|
+ params->preferred_addr.cid.datalen));
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(
|
|
token, params->preferred_addr.stateless_reset_token,
|
|
sizeof(params->preferred_addr.stateless_reset_token)));
|
|
}
|
|
|
|
if (params->original_dcid_present) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_TP " original_destination_connection_id=0x%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_hex(cid, params->original_dcid.data,
|
|
- params->original_dcid.datalen));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP
|
|
+ " original_destination_connection_id=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(cid, params->original_dcid.data,
|
|
+ params->original_dcid.datalen));
|
|
}
|
|
|
|
if (params->retry_scid_present) {
|
|
- log->log_printf(
|
|
- log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data,
|
|
- params->retry_scid.datalen));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " retry_source_connection_id=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(cid, params->retry_scid.data,
|
|
+ params->retry_scid.datalen));
|
|
}
|
|
|
|
if (params->initial_scid_present) {
|
|
- log->log_printf(
|
|
- log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data,
|
|
- params->initial_scid.datalen));
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " initial_source_connection_id=0x%s",
|
|
+ ngtcp2_encode_hex_cstr(cid, params->initial_scid.data,
|
|
+ params->initial_scid.datalen));
|
|
}
|
|
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_TP " initial_max_stream_data_bidi_local=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_local);
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_TP " initial_max_stream_data_bidi_remote=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_remote);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_uni);
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_TP " initial_max_data=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_data);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " initial_max_streams_bidi=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_bidi);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " initial_max_streams_uni=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_uni);
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- params->max_idle_timeout / NGTCP2_MILLISECONDS);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->max_udp_payload_size);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->ack_delay_exponent);
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_ack_delay=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS,
|
|
- params->max_ack_delay / NGTCP2_MILLISECONDS);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " active_connection_id_limit=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->active_connection_id_limit);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " disable_active_migration=%d"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->disable_active_migration);
|
|
- log->log_printf(log->user_data,
|
|
- (NGTCP2_LOG_TP " max_datagram_frame_size=%" PRIu64),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->max_datagram_frame_size);
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_TP " grease_quic_bit=%d"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->grease_quic_bit);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP
|
|
+ " initial_max_stream_data_bidi_local=%" PRIu64,
|
|
+ params->initial_max_stream_data_bidi_local);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP
|
|
+ " initial_max_stream_data_bidi_remote=%" PRIu64,
|
|
+ params->initial_max_stream_data_bidi_remote);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64,
|
|
+ params->initial_max_stream_data_uni);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " initial_max_data=%" PRIu64,
|
|
+ params->initial_max_data);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " initial_max_streams_bidi=%" PRIu64,
|
|
+ params->initial_max_streams_bidi);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " initial_max_streams_uni=%" PRIu64,
|
|
+ params->initial_max_streams_uni);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64,
|
|
+ params->max_idle_timeout / NGTCP2_MILLISECONDS);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64,
|
|
+ params->max_udp_payload_size);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64,
|
|
+ params->ack_delay_exponent);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " max_ack_delay=%" PRIu64,
|
|
+ params->max_ack_delay / NGTCP2_MILLISECONDS);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " active_connection_id_limit=%" PRIu64,
|
|
+ params->active_connection_id_limit);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " disable_active_migration=%d",
|
|
+ params->disable_active_migration);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " max_datagram_frame_size=%" PRIu64,
|
|
+ params->max_datagram_frame_size);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " grease_quic_bit=%d",
|
|
+ params->grease_quic_bit);
|
|
|
|
if (params->version_info_present) {
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_TP " version_information.chosen_version=0x%08x"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, params->version_info.chosen_version);
|
|
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP
|
|
+ " version_information.chosen_version=0x%08x",
|
|
+ params->version_info.chosen_version);
|
|
|
|
assert(!(params->version_info.available_versionslen & 0x3));
|
|
|
|
@@ -751,10 +700,10 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log,
|
|
i += sizeof(uint32_t)) {
|
|
p = ngtcp2_get_uint32be(&version, p);
|
|
|
|
- log->log_printf(
|
|
- log->user_data,
|
|
- (NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x"),
|
|
- NGTCP2_LOG_TP_HD_FIELDS, i >> 2, version);
|
|
+ ngtcp2_log_infof_raw(
|
|
+ log, NGTCP2_LOG_EVENT_CRY,
|
|
+ NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x",
|
|
+ i >> 2, version);
|
|
}
|
|
}
|
|
}
|
|
@@ -765,33 +714,33 @@ void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type,
|
|
return;
|
|
}
|
|
|
|
- ngtcp2_log_info(log, NGTCP2_LOG_EVENT_LDC,
|
|
- "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num,
|
|
- strpkttype_type_flags(type, flags), sent_ts);
|
|
+ ngtcp2_log_infof(log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num,
|
|
+ strpkttype_type_flags(type, flags), sent_ts);
|
|
}
|
|
|
|
static void log_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const char *dir) {
|
|
- uint8_t dcid[sizeof(hd->dcid.data) * 2 + 1];
|
|
- uint8_t scid[sizeof(hd->scid.data) * 2 + 1];
|
|
+ char dcid[sizeof(hd->dcid.data) * 2 + 1];
|
|
+ char scid[sizeof(hd->scid.data) * 2 + 1];
|
|
|
|
if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) {
|
|
return;
|
|
}
|
|
|
|
if (hd->type == NGTCP2_PKT_1RTT) {
|
|
- ngtcp2_log_info(
|
|
+ ngtcp2_log_infof(
|
|
log, NGTCP2_LOG_EVENT_PKT, "%s pkn=%" PRId64 " dcid=0x%s type=%s k=%d",
|
|
dir, hd->pkt_num,
|
|
- (const char *)ngtcp2_encode_hex(dcid, hd->dcid.data, hd->dcid.datalen),
|
|
+ ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen),
|
|
strpkttype(hd), (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0);
|
|
} else {
|
|
- ngtcp2_log_info(
|
|
+ ngtcp2_log_infof(
|
|
log, NGTCP2_LOG_EVENT_PKT,
|
|
"%s pkn=%" PRId64 " dcid=0x%s scid=0x%s version=0x%08x type=%s len=%zu",
|
|
dir, hd->pkt_num,
|
|
- (const char *)ngtcp2_encode_hex(dcid, hd->dcid.data, hd->dcid.datalen),
|
|
- (const char *)ngtcp2_encode_hex(scid, hd->scid.data, hd->scid.datalen),
|
|
+ ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen),
|
|
+ ngtcp2_encode_hex_cstr(scid, hd->scid.data, hd->scid.datalen),
|
|
hd->version, strpkttype(hd), hd->len);
|
|
}
|
|
}
|
|
@@ -804,31 +753,6 @@ void ngtcp2_log_tx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) {
|
|
log_pkt_hd(log, hd, "tx");
|
|
}
|
|
|
|
-void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt,
|
|
- ...) {
|
|
- va_list ap;
|
|
- int n;
|
|
- char buf[NGTCP2_LOG_BUFLEN];
|
|
-
|
|
- if (!log->log_printf || !(log->events & ev)) {
|
|
- return;
|
|
- }
|
|
-
|
|
- va_start(ap, fmt);
|
|
- n = vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
- va_end(ap);
|
|
-
|
|
- if (n < 0 || (size_t)n >= sizeof(buf)) {
|
|
- return;
|
|
- }
|
|
-
|
|
- log->log_printf(log->user_data, (NGTCP2_LOG_HD " %s"),
|
|
- timestamp_cast(log->last_ts - log->ts), log->scid,
|
|
- strevent(ev), buf);
|
|
-}
|
|
-
|
|
-void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) {
|
|
- ngtcp2_log_info(log, NGTCP2_LOG_EVENT_PKT,
|
|
- "cancel tx pkn=%" PRId64 " type=%s", hd->pkt_num,
|
|
- strpkttype(hd));
|
|
+uint64_t ngtcp2_log_timestamp(const ngtcp2_log *log) {
|
|
+ return (log->last_ts - log->ts) / NGTCP2_MILLISECONDS;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_log.h b/third_party/ngtcp2/lib/ngtcp2_log.h
|
|
index 13fb81a72e1..b8bccb9d09e 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_log.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_log.h
|
|
@@ -49,7 +49,7 @@ typedef struct ngtcp2_log {
|
|
log_pritnf. */
|
|
void *user_data;
|
|
/* scid is SCID encoded as NULL-terminated hex string. */
|
|
- uint8_t scid[NGTCP2_MAX_CIDLEN * 2 + 1];
|
|
+ char scid[NGTCP2_MAX_CIDLEN * 2 + 1];
|
|
} ngtcp2_log;
|
|
|
|
/**
|
|
@@ -107,7 +107,7 @@ void ngtcp2_log_tx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
|
|
const uint32_t *sv, size_t nsv);
|
|
|
|
-void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr);
|
|
+void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr);
|
|
|
|
void ngtcp2_log_remote_tp(ngtcp2_log *log,
|
|
const ngtcp2_transport_params *params);
|
|
@@ -119,14 +119,71 @@ void ngtcp2_log_rx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
|
|
|
|
void ngtcp2_log_tx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
|
|
|
|
-void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
|
|
+#define NGTCP2_LOG_HD "I%08" PRIu64 " 0x%s %s"
|
|
+
|
|
+uint64_t ngtcp2_log_timestamp(const ngtcp2_log *log);
|
|
+
|
|
+static inline const char *ngtcp2_log_event_str(ngtcp2_log_event ev) {
|
|
+ switch (ev) {
|
|
+ case NGTCP2_LOG_EVENT_CON:
|
|
+ return "con";
|
|
+ case NGTCP2_LOG_EVENT_PKT:
|
|
+ return "pkt";
|
|
+ case NGTCP2_LOG_EVENT_FRM:
|
|
+ return "frm";
|
|
+ case NGTCP2_LOG_EVENT_LDC:
|
|
+ return "ldc";
|
|
+ case NGTCP2_LOG_EVENT_CRY:
|
|
+ return "cry";
|
|
+ case NGTCP2_LOG_EVENT_PTV:
|
|
+ return "ptv";
|
|
+ case NGTCP2_LOG_EVENT_CCA:
|
|
+ return "cca";
|
|
+ case NGTCP2_LOG_EVENT_NONE:
|
|
+ default:
|
|
+ return "non";
|
|
+ }
|
|
+}
|
|
+
|
|
+#define ngtcp2_log_infof_raw(LOG, EV, FMT, ...) \
|
|
+ (LOG)->log_printf((LOG)->user_data, NGTCP2_LOG_HD " " FMT, \
|
|
+ ngtcp2_log_timestamp(LOG), (LOG)->scid, \
|
|
+ ngtcp2_log_event_str(EV), __VA_ARGS__);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
- * `ngtcp2_log_info` writes info level log.
|
|
+ * `ngtcp2_log_infof` writes info level log with printf like
|
|
+ * formatting.
|
|
*/
|
|
-void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt,
|
|
- ...);
|
|
+#define ngtcp2_log_infof(LOG, EV, FMT, ...) \
|
|
+ do { \
|
|
+ if (!(LOG)->log_printf || !((LOG)->events & (EV))) { \
|
|
+ break; \
|
|
+ } \
|
|
+ \
|
|
+ ngtcp2_log_infof_raw((LOG), (EV), FMT, __VA_ARGS__); \
|
|
+ } while (0)
|
|
+
|
|
+#define ngtcp2_log_info_raw(LOG, EV, FMT) \
|
|
+ (LOG)->log_printf((LOG)->user_data, NGTCP2_LOG_HD " " FMT, \
|
|
+ ngtcp2_log_timestamp(LOG), (LOG)->scid, \
|
|
+ ngtcp2_log_event_str(EV))
|
|
+
|
|
+/**
|
|
+ * @function
|
|
+ *
|
|
+ * `ngtcp2_log_info` writes info level log. FMT should not contain
|
|
+ * formatting directive. This function exists to workaround the issue
|
|
+ * that __VA_ARGS__ cannot be empty.
|
|
+ */
|
|
+#define ngtcp2_log_info(LOG, EV, FMT) \
|
|
+ do { \
|
|
+ if (!(LOG)->log_printf || !((LOG)->events & (EV))) { \
|
|
+ break; \
|
|
+ } \
|
|
+ \
|
|
+ ngtcp2_log_info_raw((LOG), (EV), FMT); \
|
|
+ } while (0)
|
|
|
|
#endif /* !defined(NGTCP2_LOG_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_macro.h b/third_party/ngtcp2/lib/ngtcp2_macro.h
|
|
index dfe5e0aed22..12cba12719a 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_macro.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_macro.h
|
|
@@ -52,6 +52,13 @@
|
|
*/
|
|
#define ngtcp2_arraylen(A) (sizeof(A) / sizeof(A[0]))
|
|
|
|
+/*
|
|
+ * ngtcp2_strlen_lit returns the length of string literal |S|. This
|
|
+ * macro assumes |S| is NULL-terminated string literal. It must not
|
|
+ * be used with pointers.
|
|
+ */
|
|
+#define ngtcp2_strlen_lit(S) (sizeof(S) - 1)
|
|
+
|
|
#define ngtcp2_max_def(SUFFIX, T) \
|
|
static inline T ngtcp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; }
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_map.c b/third_party/ngtcp2/lib/ngtcp2_map.c
|
|
index 5e4726e63ff..3ad4b9f1ef0 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_map.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_map.c
|
|
@@ -33,11 +33,11 @@
|
|
|
|
#define NGTCP2_INITIAL_HASHBITS 4
|
|
|
|
-void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
|
|
- map->mem = mem;
|
|
- map->hashbits = 0;
|
|
- map->table = NULL;
|
|
- map->size = 0;
|
|
+void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem) {
|
|
+ *map = (ngtcp2_map){
|
|
+ .mem = mem,
|
|
+ .seed = seed,
|
|
+ };
|
|
}
|
|
|
|
void ngtcp2_map_free(ngtcp2_map *map) {
|
|
@@ -45,30 +45,27 @@ void ngtcp2_map_free(ngtcp2_map *map) {
|
|
return;
|
|
}
|
|
|
|
- ngtcp2_mem_free(map->mem, map->table);
|
|
+ ngtcp2_mem_free(map->mem, map->keys);
|
|
}
|
|
|
|
int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr),
|
|
void *ptr) {
|
|
int rv;
|
|
size_t i;
|
|
- ngtcp2_map_bucket *bkt;
|
|
size_t tablelen;
|
|
|
|
if (map->size == 0) {
|
|
return 0;
|
|
}
|
|
|
|
- tablelen = 1u << map->hashbits;
|
|
+ tablelen = (size_t)1 << map->hashbits;
|
|
|
|
for (i = 0; i < tablelen; ++i) {
|
|
- bkt = &map->table[i];
|
|
-
|
|
- if (bkt->data == NULL) {
|
|
+ if (map->psl[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
- rv = func(bkt->data, ptr);
|
|
+ rv = func(map->data[i], ptr);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
@@ -77,168 +74,228 @@ int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr),
|
|
return 0;
|
|
}
|
|
|
|
-static size_t hash(ngtcp2_map_key_type key, size_t bits) {
|
|
- return (size_t)((key * 11400714819323198485llu) >> (64 - bits));
|
|
-}
|
|
-
|
|
-static void map_bucket_swap(ngtcp2_map_bucket *a, ngtcp2_map_bucket *b) {
|
|
- ngtcp2_map_bucket c = *a;
|
|
-
|
|
- *a = *b;
|
|
- *b = c;
|
|
+/* Hasher from
|
|
+ https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
|
|
+ to maximize the output's sensitivity to all input bits. */
|
|
+#define NGTCP2_MAP_HASHER 0xF1357AEA2E62A9C5ULL
|
|
+/* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get
|
|
+ the high bits with the good distribution. */
|
|
+#define NGTCP2_MAP_FIBO 0x9E3779B97F4A7C15ULL
|
|
+
|
|
+static size_t map_index(const ngtcp2_map *map, ngtcp2_map_key_type key) {
|
|
+ key += map->seed;
|
|
+ key *= NGTCP2_MAP_HASHER;
|
|
+ return (size_t)((key * NGTCP2_MAP_FIBO) >> (64 - map->hashbits));
|
|
}
|
|
|
|
#ifndef WIN32
|
|
void ngtcp2_map_print_distance(const ngtcp2_map *map) {
|
|
size_t i;
|
|
size_t idx;
|
|
- ngtcp2_map_bucket *bkt;
|
|
size_t tablelen;
|
|
|
|
if (map->size == 0) {
|
|
return;
|
|
}
|
|
|
|
- tablelen = 1u << map->hashbits;
|
|
+ tablelen = (size_t)1 << map->hashbits;
|
|
|
|
for (i = 0; i < tablelen; ++i) {
|
|
- bkt = &map->table[i];
|
|
-
|
|
- if (bkt->data == NULL) {
|
|
+ if (map->psl[i] == 0) {
|
|
fprintf(stderr, "@%zu <EMPTY>\n", i);
|
|
continue;
|
|
}
|
|
|
|
- idx = hash(bkt->key, map->hashbits);
|
|
- fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
|
|
- hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl);
|
|
+ idx = map_index(map, map->keys[i]);
|
|
+ fprintf(stderr, "@%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
|
|
+ map->keys[i], idx, map->psl[i] - 1);
|
|
}
|
|
}
|
|
#endif /* !defined(WIN32) */
|
|
|
|
-static int insert(ngtcp2_map_bucket *table, size_t hashbits,
|
|
- ngtcp2_map_key_type key, void *data) {
|
|
- size_t idx = hash(key, hashbits);
|
|
- ngtcp2_map_bucket b = {
|
|
- .key = key,
|
|
- .data = data,
|
|
- };
|
|
- ngtcp2_map_bucket *bkt;
|
|
- size_t mask = (1u << hashbits) - 1;
|
|
+static void map_set_entry(ngtcp2_map *map, size_t idx, ngtcp2_map_key_type key,
|
|
+ void *data, size_t psl) {
|
|
+ map->keys[idx] = key;
|
|
+ map->data[idx] = data;
|
|
+ map->psl[idx] = (uint8_t)psl;
|
|
+}
|
|
+
|
|
+#define NGTCP2_SWAP(TYPE, A, B) \
|
|
+ do { \
|
|
+ TYPE t = (TYPE) * (A); \
|
|
+ \
|
|
+ *(A) = *(B); \
|
|
+ *(B) = t; \
|
|
+ } while (0)
|
|
+
|
|
+/*
|
|
+ * map_insert inserts |key| and |data| to |map|, and returns the index
|
|
+ * where the pair is stored if it succeeds. Otherwise, it returns one
|
|
+ * of the following negative error codes:
|
|
+ *
|
|
+ * NGTCP2_ERR_INVALID_ARGUMENT
|
|
+ * The another data associated to |key| is already present.
|
|
+ */
|
|
+static ngtcp2_ssize map_insert(ngtcp2_map *map, ngtcp2_map_key_type key,
|
|
+ void *data) {
|
|
+ size_t idx = map_index(map, key);
|
|
+ size_t mask = ((size_t)1 << map->hashbits) - 1;
|
|
+ size_t psl = 1;
|
|
+ size_t kpsl;
|
|
|
|
for (;;) {
|
|
- bkt = &table[idx];
|
|
+ kpsl = map->psl[idx];
|
|
|
|
- if (bkt->data == NULL) {
|
|
- *bkt = b;
|
|
- return 0;
|
|
+ if (kpsl == 0) {
|
|
+ map_set_entry(map, idx, key, data, psl);
|
|
+ ++map->size;
|
|
+
|
|
+ return (ngtcp2_ssize)idx;
|
|
}
|
|
|
|
- if (b.psl > bkt->psl) {
|
|
- map_bucket_swap(bkt, &b);
|
|
- } else if (bkt->key == key) {
|
|
- /* TODO This check is just a waste after first swap or if this
|
|
- function is called from map_resize. That said, there is no
|
|
- difference with or without this conditional in performance
|
|
- wise. */
|
|
+ if (psl > kpsl) {
|
|
+ NGTCP2_SWAP(ngtcp2_map_key_type, &key, &map->keys[idx]);
|
|
+ NGTCP2_SWAP(void *, &data, &map->data[idx]);
|
|
+ NGTCP2_SWAP(uint8_t, &psl, &map->psl[idx]);
|
|
+ } else if (map->keys[idx] == key) {
|
|
+ /* This check ensures that no duplicate keys are inserted. But
|
|
+ it is just a waste after first swap or if this function is
|
|
+ called from map_resize. That said, there is no difference
|
|
+ with or without this conditional in performance wise. */
|
|
return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
- ++b.psl;
|
|
+ ++psl;
|
|
idx = (idx + 1) & mask;
|
|
}
|
|
}
|
|
|
|
+/* NGTCP2_MAP_MAX_HASHBITS is the maximum number of bits used for hash
|
|
+ table. The theoretical limit of the maximum number of keys that
|
|
+ can be stored is 1 << NGTCP2_MAP_MAX_HASHBITS. */
|
|
+#define NGTCP2_MAP_MAX_HASHBITS (sizeof(size_t) * 8 - 1)
|
|
+
|
|
static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
|
|
size_t i;
|
|
- ngtcp2_map_bucket *new_table;
|
|
- ngtcp2_map_bucket *bkt;
|
|
size_t tablelen;
|
|
- int rv;
|
|
- (void)rv;
|
|
+ ngtcp2_ssize idx;
|
|
+ ngtcp2_map new_map = {
|
|
+ .mem = map->mem,
|
|
+ .seed = map->seed,
|
|
+ .hashbits = new_hashbits,
|
|
+ };
|
|
+ void *buf;
|
|
+ (void)idx;
|
|
+
|
|
+ if (new_hashbits > NGTCP2_MAP_MAX_HASHBITS) {
|
|
+ return NGTCP2_ERR_NOMEM;
|
|
+ }
|
|
+
|
|
+ tablelen = (size_t)1 << new_hashbits;
|
|
|
|
- new_table =
|
|
- ngtcp2_mem_calloc(map->mem, 1u << new_hashbits, sizeof(ngtcp2_map_bucket));
|
|
- if (new_table == NULL) {
|
|
+ buf = ngtcp2_mem_calloc(map->mem, tablelen,
|
|
+ sizeof(ngtcp2_map_key_type) + sizeof(void *) +
|
|
+ sizeof(uint8_t));
|
|
+ if (buf == NULL) {
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
+ new_map.keys = buf;
|
|
+ new_map.data =
|
|
+ (void *)((uint8_t *)new_map.keys + tablelen * sizeof(ngtcp2_map_key_type));
|
|
+ new_map.psl = (uint8_t *)new_map.data + tablelen * sizeof(void *);
|
|
+
|
|
if (map->size) {
|
|
- tablelen = 1u << map->hashbits;
|
|
+ tablelen = (size_t)1 << map->hashbits;
|
|
|
|
for (i = 0; i < tablelen; ++i) {
|
|
- bkt = &map->table[i];
|
|
- if (bkt->data == NULL) {
|
|
+ if (map->psl[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
- rv = insert(new_table, new_hashbits, bkt->key, bkt->data);
|
|
+ idx = map_insert(&new_map, map->keys[i], map->data[i]);
|
|
|
|
- assert(0 == rv);
|
|
+ /* map_insert must not fail because all keys are unique during
|
|
+ resize. */
|
|
+ assert(idx >= 0);
|
|
}
|
|
}
|
|
|
|
- ngtcp2_mem_free(map->mem, map->table);
|
|
+ ngtcp2_mem_free(map->mem, map->keys);
|
|
+ map->keys = new_map.keys;
|
|
+ map->data = new_map.data;
|
|
+ map->psl = new_map.psl;
|
|
map->hashbits = new_hashbits;
|
|
- map->table = new_table;
|
|
|
|
return 0;
|
|
}
|
|
|
|
+/* NGTCP2_MAX_PSL_RESIZE_THRESH is the maximum psl threshold. If
|
|
+ reached, resize the table. */
|
|
+#define NGTCP2_MAX_PSL_RESIZE_THRESH 128
|
|
+
|
|
int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
|
|
int rv;
|
|
+ size_t tablelen;
|
|
+ ngtcp2_ssize idx;
|
|
|
|
assert(data);
|
|
|
|
- /* Load factor is 0.75 */
|
|
- /* Under the very initial condition, that is map->size == 0 and
|
|
- map->hashbits == 0, 4 > 3 still holds nicely. */
|
|
- if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) {
|
|
- if (map->hashbits) {
|
|
- rv = map_resize(map, map->hashbits + 1);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
- }
|
|
- } else {
|
|
- rv = map_resize(map, NGTCP2_INITIAL_HASHBITS);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
- }
|
|
+ /* tablelen is incorrect if map->hashbits == 0 which leads to
|
|
+ tablelen = 1, but it is only used to check the load factor, and
|
|
+ it works in this special case. */
|
|
+ tablelen = (size_t)1 << map->hashbits;
|
|
+
|
|
+ /* Load factor is 7 / 8. Because tablelen is power of 2, (tablelen
|
|
+ - (tablelen >> 3)) computes tablelen * 7 / 8. */
|
|
+ if (map->size + 1 >= (tablelen - (tablelen >> 3))) {
|
|
+ rv = map_resize(map, map->hashbits ? map->hashbits + 1
|
|
+ : NGTCP2_INITIAL_HASHBITS);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
}
|
|
+
|
|
+ idx = map_insert(map, key, data);
|
|
+ if (idx < 0) {
|
|
+ return (int)idx;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
- rv = insert(map->table, map->hashbits, key, data);
|
|
- if (rv != 0) {
|
|
- return rv;
|
|
+ idx = map_insert(map, key, data);
|
|
+ if (idx < 0) {
|
|
+ return (int)idx;
|
|
}
|
|
|
|
- ++map->size;
|
|
+ /* Resize if psl reaches really large value which is almost
|
|
+ improbable, but just in case. */
|
|
+ if (map->psl[idx] - 1 < NGTCP2_MAX_PSL_RESIZE_THRESH) {
|
|
+ return 0;
|
|
+ }
|
|
|
|
- return 0;
|
|
+ return map_resize(map, map->hashbits + 1);
|
|
}
|
|
|
|
void *ngtcp2_map_find(const ngtcp2_map *map, ngtcp2_map_key_type key) {
|
|
size_t idx;
|
|
- ngtcp2_map_bucket *bkt;
|
|
- size_t psl = 0;
|
|
+ size_t psl = 1;
|
|
size_t mask;
|
|
|
|
if (map->size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
- idx = hash(key, map->hashbits);
|
|
- mask = (1u << map->hashbits) - 1;
|
|
+ idx = map_index(map, key);
|
|
+ mask = ((size_t)1 << map->hashbits) - 1;
|
|
|
|
for (;;) {
|
|
- bkt = &map->table[idx];
|
|
-
|
|
- if (bkt->data == NULL || psl > bkt->psl) {
|
|
+ if (psl > map->psl[idx]) {
|
|
return NULL;
|
|
}
|
|
|
|
- if (bkt->key == key) {
|
|
- return bkt->data;
|
|
+ if (map->keys[idx] == key) {
|
|
+ return map->data[idx];
|
|
}
|
|
|
|
++psl;
|
|
@@ -248,38 +305,36 @@ void *ngtcp2_map_find(const ngtcp2_map *map, ngtcp2_map_key_type key) {
|
|
|
|
int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key) {
|
|
size_t idx;
|
|
- ngtcp2_map_bucket *b, *bkt;
|
|
- size_t psl = 0;
|
|
+ size_t dest;
|
|
+ size_t psl = 1, kpsl;
|
|
size_t mask;
|
|
|
|
if (map->size == 0) {
|
|
return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
- idx = hash(key, map->hashbits);
|
|
- mask = (1u << map->hashbits) - 1;
|
|
+ idx = map_index(map, key);
|
|
+ mask = ((size_t)1 << map->hashbits) - 1;
|
|
|
|
for (;;) {
|
|
- bkt = &map->table[idx];
|
|
-
|
|
- if (bkt->data == NULL || psl > bkt->psl) {
|
|
+ if (psl > map->psl[idx]) {
|
|
return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
- if (bkt->key == key) {
|
|
- b = bkt;
|
|
+ if (map->keys[idx] == key) {
|
|
+ dest = idx;
|
|
idx = (idx + 1) & mask;
|
|
|
|
for (;;) {
|
|
- bkt = &map->table[idx];
|
|
- if (bkt->data == NULL || bkt->psl == 0) {
|
|
- b->data = NULL;
|
|
+ kpsl = map->psl[idx];
|
|
+ if (kpsl <= 1) {
|
|
+ map->psl[dest] = 0;
|
|
break;
|
|
}
|
|
|
|
- --bkt->psl;
|
|
- *b = *bkt;
|
|
- b = bkt;
|
|
+ map_set_entry(map, dest, map->keys[idx], map->data[idx], kpsl - 1);
|
|
+
|
|
+ dest = idx;
|
|
|
|
idx = (idx + 1) & mask;
|
|
}
|
|
@@ -299,7 +354,7 @@ void ngtcp2_map_clear(ngtcp2_map *map) {
|
|
return;
|
|
}
|
|
|
|
- memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits));
|
|
+ memset(map->psl, 0, sizeof(*map->psl) * ((size_t)1 << map->hashbits));
|
|
map->size = 0;
|
|
}
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_map.h b/third_party/ngtcp2/lib/ngtcp2_map.h
|
|
index 9d882fb2008..1afe3167e65 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_map.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_map.h
|
|
@@ -38,15 +38,15 @@
|
|
|
|
typedef uint64_t ngtcp2_map_key_type;
|
|
|
|
-typedef struct ngtcp2_map_bucket {
|
|
- uint32_t psl;
|
|
- ngtcp2_map_key_type key;
|
|
- void *data;
|
|
-} ngtcp2_map_bucket;
|
|
-
|
|
typedef struct ngtcp2_map {
|
|
- ngtcp2_map_bucket *table;
|
|
+ ngtcp2_map_key_type *keys;
|
|
+ void **data;
|
|
+ /* psl is the Probe Sequence Length. 0 has special meaning that the
|
|
+ element is not stored at i-th position if psl[i] == 0. Because
|
|
+ of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
|
|
+ uint8_t *psl;
|
|
const ngtcp2_mem *mem;
|
|
+ uint64_t seed;
|
|
size_t size;
|
|
size_t hashbits;
|
|
} ngtcp2_map;
|
|
@@ -54,7 +54,7 @@ typedef struct ngtcp2_map {
|
|
/*
|
|
* ngtcp2_map_init initializes the map |map|.
|
|
*/
|
|
-void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem);
|
|
+void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem);
|
|
|
|
/*
|
|
* ngtcp2_map_free deallocates any resources allocated for |map|. The
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_net.h b/third_party/ngtcp2/lib/ngtcp2_net.h
|
|
index 103a2fb2d80..35a807f9fed 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_net.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_net.h
|
|
@@ -97,9 +97,9 @@ STIN uint32_t ngtcp2_htonl(uint32_t hostlong) {
|
|
uint32_t res;
|
|
unsigned char *p = (unsigned char *)&res;
|
|
*p++ = (unsigned char)(hostlong >> 24);
|
|
- *p++ = (hostlong >> 16) & 0xffu;
|
|
- *p++ = (hostlong >> 8) & 0xffu;
|
|
- *p = hostlong & 0xffu;
|
|
+ *p++ = (hostlong >> 16) & 0xFFU;
|
|
+ *p++ = (hostlong >> 8) & 0xFFU;
|
|
+ *p = hostlong & 0xFFU;
|
|
return res;
|
|
}
|
|
|
|
@@ -107,7 +107,7 @@ STIN uint16_t ngtcp2_htons(uint16_t hostshort) {
|
|
uint16_t res;
|
|
unsigned char *p = (unsigned char *)&res;
|
|
*p++ = (unsigned char)(hostshort >> 8);
|
|
- *p = hostshort & 0xffu;
|
|
+ *p = hostshort & 0xFFU;
|
|
return res;
|
|
}
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_objalloc.h b/third_party/ngtcp2/lib/ngtcp2_objalloc.h
|
|
index cf23de7b2b7..4b6df53857a 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_objalloc.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_objalloc.h
|
|
@@ -69,7 +69,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc);
|
|
inline static void ngtcp2_objalloc_##NAME##_init( \
|
|
ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \
|
|
ngtcp2_objalloc_init( \
|
|
- objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \
|
|
+ objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem); \
|
|
} \
|
|
\
|
|
TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc); \
|
|
@@ -123,7 +123,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc);
|
|
inline static void ngtcp2_objalloc_##NAME##_init( \
|
|
ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \
|
|
ngtcp2_objalloc_init( \
|
|
- objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \
|
|
+ objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem); \
|
|
} \
|
|
\
|
|
inline static TYPE *ngtcp2_objalloc_##NAME##_get( \
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_path.c b/third_party/ngtcp2/lib/ngtcp2_path.c
|
|
index 83238730033..c9636a8db9a 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_path.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_path.c
|
|
@@ -28,12 +28,6 @@
|
|
|
|
#include "ngtcp2_addr.h"
|
|
|
|
-void ngtcp2_path_init(ngtcp2_path *path, const ngtcp2_addr *local,
|
|
- const ngtcp2_addr *remote) {
|
|
- path->local = *local;
|
|
- path->remote = *remote;
|
|
-}
|
|
-
|
|
void ngtcp2_path_copy(ngtcp2_path *dest, const ngtcp2_path *src) {
|
|
ngtcp2_addr_copy(&dest->local, &src->local);
|
|
ngtcp2_addr_copy(&dest->remote, &src->remote);
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_path.h b/third_party/ngtcp2/lib/ngtcp2_path.h
|
|
index a708378db32..9d4205cee22 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_path.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_path.h
|
|
@@ -31,14 +31,6 @@
|
|
|
|
#include <ngtcp2/ngtcp2.h>
|
|
|
|
-/*
|
|
- * ngtcp2_path_init initializes |path| with the given addresses. Note
|
|
- * that the buffer pointed by local->addr and remote->addr are not
|
|
- * copied. Their pointer values are assigned instead.
|
|
- */
|
|
-void ngtcp2_path_init(ngtcp2_path *path, const ngtcp2_addr *local,
|
|
- const ngtcp2_addr *remote);
|
|
-
|
|
/*
|
|
* ngtcp2_path_storage_init2 initializes |ps| using |path| as initial
|
|
* data.
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_pcg.c b/third_party/ngtcp2/lib/ngtcp2_pcg.c
|
|
new file mode 100644
|
|
index 00000000000..ddaf94a779a
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_pcg.c
|
|
@@ -0,0 +1,88 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#include "ngtcp2_pcg.h"
|
|
+
|
|
+#include <assert.h>
|
|
+
|
|
+/*
|
|
+ * PCG implementation from
|
|
+ * https://github.com/imneme/pcg-c/blob/83252d9c23df9c82ecb42210afed61a7b42402d7/include/pcg_variants.h
|
|
+ *
|
|
+ * PCG Random Number Generation for C.
|
|
+ *
|
|
+ * Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>,
|
|
+ * and the PCG Project contributors.
|
|
+ *
|
|
+ * SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (provided in
|
|
+ * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
|
|
+ * or under the MIT license (provided in LICENSE-MIT.txt and at
|
|
+ * http://opensource.org/licenses/MIT), at your option. This file may not
|
|
+ * be copied, modified, or distributed except according to those terms.
|
|
+ *
|
|
+ * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
|
|
+ * express or implied. See your chosen license for details.
|
|
+ *
|
|
+ * For additional information about the PCG random number generation scheme,
|
|
+ * visit http://www.pcg-random.org/.
|
|
+ */
|
|
+
|
|
+#define NGTCP2_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL
|
|
+#define NGTCP2_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL
|
|
+
|
|
+static void pcg_oneseq_64_step_r(ngtcp2_pcg32 *pcg) {
|
|
+ pcg->state = pcg->state * NGTCP2_PCG_DEFAULT_MULTIPLIER_64 +
|
|
+ NGTCP2_PCG_DEFAULT_INCREMENT_64;
|
|
+}
|
|
+
|
|
+void ngtcp2_pcg32_init(ngtcp2_pcg32 *pcg, uint64_t seed) {
|
|
+ pcg->state = 0;
|
|
+ pcg_oneseq_64_step_r(pcg);
|
|
+ pcg->state += seed;
|
|
+ pcg_oneseq_64_step_r(pcg);
|
|
+}
|
|
+
|
|
+static uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) {
|
|
+ return (value >> rot) | (value << ((32 - rot) & 31));
|
|
+}
|
|
+
|
|
+static uint32_t pcg_output_xsh_rr_64_32(uint64_t state) {
|
|
+ return pcg_rotr_32((uint32_t)(((state >> 18U) ^ state) >> 27U),
|
|
+ (unsigned int)(state >> 59U));
|
|
+}
|
|
+
|
|
+uint32_t ngtcp2_pcg32_rand(ngtcp2_pcg32 *pcg) {
|
|
+ uint64_t oldstate = pcg->state;
|
|
+
|
|
+ pcg_oneseq_64_step_r(pcg);
|
|
+
|
|
+ return pcg_output_xsh_rr_64_32(oldstate);
|
|
+}
|
|
+
|
|
+uint32_t ngtcp2_pcg32_rand_n(ngtcp2_pcg32 *pcg, uint32_t n) {
|
|
+ assert(n);
|
|
+ return (uint32_t)(((uint64_t)ngtcp2_pcg32_rand(pcg) * n) >> 32);
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_pcg.h b/third_party/ngtcp2/lib/ngtcp2_pcg.h
|
|
new file mode 100644
|
|
index 00000000000..a637183efc1
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_pcg.h
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#ifndef NGTCP2_PCG_H
|
|
+#define NGTCP2_PCG_H
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include <config.h>
|
|
+#endif /* defined(HAVE_CONFIG_H) */
|
|
+
|
|
+#include <ngtcp2/ngtcp2.h>
|
|
+
|
|
+typedef struct ngtcp2_pcg32 {
|
|
+ uint64_t state;
|
|
+} ngtcp2_pcg32;
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pcg32_init initializes |pcg| with |seed|.
|
|
+ */
|
|
+void ngtcp2_pcg32_init(ngtcp2_pcg32 *pcg, uint64_t seed);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pcg32_rand returns a random value in [0, UINT32_MAX].
|
|
+ */
|
|
+uint32_t ngtcp2_pcg32_rand(ngtcp2_pcg32 *pcg);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pcg32_rand_n returns a random value in [0, n). |n| must not
|
|
+ * be zero.
|
|
+ */
|
|
+uint32_t ngtcp2_pcg32_rand_n(ngtcp2_pcg32 *pcg, uint32_t n);
|
|
+
|
|
+#endif /* !defined(NGTCP2_PCG_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_pkt.c b/third_party/ngtcp2/lib/ngtcp2_pkt.c
|
|
index af8a059d08f..f86e65118df 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_pkt.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_pkt.c
|
|
@@ -33,7 +33,9 @@
|
|
#include "ngtcp2_cid.h"
|
|
#include "ngtcp2_mem.h"
|
|
#include "ngtcp2_vec.h"
|
|
+#include "ngtcp2_buf.h"
|
|
#include "ngtcp2_unreachable.h"
|
|
+#include "ngtcp2_pcg.h"
|
|
|
|
int ngtcp2_pkt_chain_new(ngtcp2_pkt_chain **ppc, const ngtcp2_path *path,
|
|
const ngtcp2_pkt_info *pi, const uint8_t *pkt,
|
|
@@ -480,8 +482,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_short(uint8_t *out, size_t outlen,
|
|
return (ngtcp2_ssize)len;
|
|
}
|
|
|
|
-ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
|
|
- size_t payloadlen) {
|
|
+ngtcp2_ssize ngtcp2_frame_decoder_decode(ngtcp2_frame_decoder *frd,
|
|
+ ngtcp2_frame *dest,
|
|
+ const uint8_t *payload,
|
|
+ size_t payloadlen) {
|
|
uint8_t type;
|
|
|
|
if (payloadlen == 0) {
|
|
@@ -530,6 +534,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
|
|
payloadlen);
|
|
case NGTCP2_FRAME_ACK:
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
+ dest->ack.ranges = frd->buf.ack_ranges;
|
|
return ngtcp2_pkt_decode_ack_frame(&dest->ack, payload, payloadlen);
|
|
case NGTCP2_FRAME_PATH_CHALLENGE:
|
|
return ngtcp2_pkt_decode_path_challenge_frame(&dest->path_challenge,
|
|
@@ -538,6 +543,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
|
|
return ngtcp2_pkt_decode_path_response_frame(&dest->path_response, payload,
|
|
payloadlen);
|
|
case NGTCP2_FRAME_CRYPTO:
|
|
+ dest->stream.data = &frd->buf.data;
|
|
return ngtcp2_pkt_decode_crypto_frame(&dest->stream, payload, payloadlen);
|
|
case NGTCP2_FRAME_NEW_TOKEN:
|
|
return ngtcp2_pkt_decode_new_token_frame(&dest->new_token, payload,
|
|
@@ -550,14 +556,16 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
|
|
payload, payloadlen);
|
|
case NGTCP2_FRAME_DATAGRAM:
|
|
case NGTCP2_FRAME_DATAGRAM_LEN:
|
|
+ dest->datagram.data = &frd->buf.data;
|
|
return ngtcp2_pkt_decode_datagram_frame(&dest->datagram, payload,
|
|
payloadlen);
|
|
default:
|
|
if ((type & ~(NGTCP2_FRAME_STREAM - 1)) == NGTCP2_FRAME_STREAM) {
|
|
+ dest->stream.data = &frd->buf.data;
|
|
return ngtcp2_pkt_decode_stream_frame(&dest->stream, payload, payloadlen);
|
|
}
|
|
|
|
- /* For frame types > 0xff, use ngtcp2_get_uvarintlen and
|
|
+ /* For frame types > 0xFF, use ngtcp2_get_uvarintlen and
|
|
ngtcp2_get_uvarint to get a frame type, and then switch over
|
|
it. Verify that payloadlen >= ngtcp2_get_uvarintlen(payload)
|
|
before calling ngtcp2_get_uvarint(payload). */
|
|
@@ -916,7 +924,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame(
|
|
return NGTCP2_ERR_FRAME_ENCODING;
|
|
}
|
|
|
|
- p = ngtcp2_get_uvarint(&vi, p);
|
|
+ ngtcp2_get_uvarint(&vi, p);
|
|
if (payloadlen - len < vi) {
|
|
return NGTCP2_ERR_FRAME_ENCODING;
|
|
}
|
|
@@ -1051,6 +1059,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_ping_frame(ngtcp2_ping *dest,
|
|
(void)payload;
|
|
(void)payloadlen;
|
|
|
|
+ assert(payloadlen > 0);
|
|
+
|
|
dest->type = NGTCP2_FRAME_PING;
|
|
return 1;
|
|
}
|
|
@@ -1198,8 +1208,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame(
|
|
++p;
|
|
ngtcp2_cid_init(&dest->cid, p, cil);
|
|
p += cil;
|
|
- p = ngtcp2_get_bytes(dest->stateless_reset_token, p,
|
|
- NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ p = ngtcp2_get_bytes(dest->token.data, p, sizeof(dest->token.data));
|
|
|
|
assert((size_t)(p - payload) == len);
|
|
|
|
@@ -1258,7 +1267,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_challenge_frame(ngtcp2_path_challenge *dest,
|
|
p = payload + 1;
|
|
|
|
dest->type = NGTCP2_FRAME_PATH_CHALLENGE;
|
|
- ngtcp2_cpymem(dest->data, p, sizeof(dest->data));
|
|
+ ngtcp2_cpymem(dest->data.data, p, sizeof(dest->data.data));
|
|
p += sizeof(dest->data);
|
|
|
|
assert((size_t)(p - payload) == len);
|
|
@@ -1279,7 +1288,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_response_frame(ngtcp2_path_response *dest,
|
|
p = payload + 1;
|
|
|
|
dest->type = NGTCP2_FRAME_PATH_RESPONSE;
|
|
- ngtcp2_cpymem(dest->data, p, sizeof(dest->data));
|
|
+ ngtcp2_cpymem(dest->data.data, p, sizeof(dest->data.data));
|
|
p += sizeof(dest->data);
|
|
|
|
assert((size_t)(p - payload) == len);
|
|
@@ -1319,7 +1328,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_stream *dest,
|
|
return NGTCP2_ERR_FRAME_ENCODING;
|
|
}
|
|
|
|
- p = ngtcp2_get_uvarint(&vi, p);
|
|
+ ngtcp2_get_uvarint(&vi, p);
|
|
if (payloadlen - len < vi) {
|
|
return NGTCP2_ERR_FRAME_ENCODING;
|
|
}
|
|
@@ -1426,6 +1435,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_handshake_done_frame(ngtcp2_handshake_done *dest,
|
|
(void)payload;
|
|
(void)payloadlen;
|
|
|
|
+ assert(payloadlen > 0);
|
|
+
|
|
dest->type = NGTCP2_FRAME_HANDSHAKE_DONE;
|
|
return 1;
|
|
}
|
|
@@ -1440,9 +1451,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest,
|
|
size_t n;
|
|
uint64_t vi;
|
|
|
|
- if (payloadlen < len) {
|
|
- return NGTCP2_ERR_FRAME_ENCODING;
|
|
- }
|
|
+ assert(payloadlen > 0);
|
|
|
|
type = payload[0];
|
|
|
|
@@ -1481,16 +1490,13 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest,
|
|
|
|
dest->type = type;
|
|
|
|
- if (datalen == 0) {
|
|
- dest->datacnt = 0;
|
|
- dest->data = NULL;
|
|
- } else {
|
|
+ if (datalen) {
|
|
+ dest->data[0].len = datalen;
|
|
+ dest->data[0].base = (uint8_t *)p;
|
|
dest->datacnt = 1;
|
|
- dest->data = dest->rdata;
|
|
- dest->rdata[0].len = datalen;
|
|
-
|
|
- dest->rdata[0].base = (uint8_t *)p;
|
|
p += datalen;
|
|
+ } else {
|
|
+ dest->datacnt = 0;
|
|
}
|
|
|
|
assert((size_t)(p - payload) == len);
|
|
@@ -1500,7 +1506,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest,
|
|
|
|
ngtcp2_ssize ngtcp2_pkt_encode_frame(uint8_t *out, size_t outlen,
|
|
ngtcp2_frame *fr) {
|
|
- switch (fr->type) {
|
|
+ switch (fr->hd.type) {
|
|
case NGTCP2_FRAME_STREAM:
|
|
return ngtcp2_pkt_encode_stream_frame(out, outlen, &fr->stream);
|
|
case NGTCP2_FRAME_ACK:
|
|
@@ -1876,7 +1882,7 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen,
|
|
const ngtcp2_new_connection_id *fr) {
|
|
size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq) +
|
|
ngtcp2_put_uvarintlen(fr->retire_prior_to) + 1 +
|
|
- fr->cid.datalen + NGTCP2_STATELESS_RESET_TOKENLEN;
|
|
+ fr->cid.datalen + sizeof(fr->token.data);
|
|
uint8_t *p;
|
|
|
|
if (outlen < len) {
|
|
@@ -1890,8 +1896,7 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen,
|
|
p = ngtcp2_put_uvarint(p, fr->retire_prior_to);
|
|
*p++ = (uint8_t)fr->cid.datalen;
|
|
p = ngtcp2_cpymem(p, fr->cid.data, fr->cid.datalen);
|
|
- p = ngtcp2_cpymem(p, fr->stateless_reset_token,
|
|
- NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ p = ngtcp2_cpymem(p, fr->token.data, sizeof(fr->token.data));
|
|
|
|
assert((size_t)(p - out) == len);
|
|
|
|
@@ -1933,7 +1938,7 @@ ngtcp2_pkt_encode_path_challenge_frame(uint8_t *out, size_t outlen,
|
|
p = out;
|
|
|
|
*p++ = NGTCP2_FRAME_PATH_CHALLENGE;
|
|
- p = ngtcp2_cpymem(p, fr->data, sizeof(fr->data));
|
|
+ p = ngtcp2_cpymem(p, fr->data.data, sizeof(fr->data.data));
|
|
|
|
assert((size_t)(p - out) == len);
|
|
|
|
@@ -1953,7 +1958,7 @@ ngtcp2_pkt_encode_path_response_frame(uint8_t *out, size_t outlen,
|
|
p = out;
|
|
|
|
*p++ = NGTCP2_FRAME_PATH_RESPONSE;
|
|
- p = ngtcp2_cpymem(p, fr->data, sizeof(fr->data));
|
|
+ p = ngtcp2_cpymem(p, fr->data.data, sizeof(fr->data.data));
|
|
|
|
assert((size_t)(p - out) == len);
|
|
|
|
@@ -2109,7 +2114,7 @@ ngtcp2_ssize ngtcp2_pkt_write_version_negotiation(
|
|
|
|
p = dest;
|
|
|
|
- *p++ = 0xc0 | unused_random;
|
|
+ *p++ = 0xC0 | unused_random;
|
|
p = ngtcp2_put_uint32be(p, 0);
|
|
*p++ = (uint8_t)dcidlen;
|
|
|
|
@@ -2146,20 +2151,20 @@ size_t ngtcp2_pkt_decode_version_negotiation(uint32_t *dest,
|
|
return payloadlen / sizeof(uint32_t);
|
|
}
|
|
|
|
-int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset *sr,
|
|
+int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset2 *sr,
|
|
const uint8_t *payload,
|
|
size_t payloadlen) {
|
|
const uint8_t *p = payload;
|
|
|
|
if (payloadlen <
|
|
- NGTCP2_MIN_STATELESS_RESET_RANDLEN + NGTCP2_STATELESS_RESET_TOKENLEN) {
|
|
+ NGTCP2_MIN_STATELESS_RESET_RANDLEN + sizeof(sr->token.data)) {
|
|
return NGTCP2_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
sr->rand = p;
|
|
- sr->randlen = payloadlen - NGTCP2_STATELESS_RESET_TOKENLEN;
|
|
+ sr->randlen = payloadlen - sizeof(sr->token.data);
|
|
p += sr->randlen;
|
|
- memcpy(sr->stateless_reset_token, p, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ memcpy(sr->token.data, p, sizeof(sr->token.data));
|
|
|
|
return 0;
|
|
}
|
|
@@ -2238,10 +2243,21 @@ ngtcp2_ssize
|
|
ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen,
|
|
const uint8_t *stateless_reset_token,
|
|
const uint8_t *rand, size_t randlen) {
|
|
+ ngtcp2_stateless_reset_token token;
|
|
+
|
|
+ memcpy(token.data, stateless_reset_token, sizeof(token.data));
|
|
+
|
|
+ return ngtcp2_pkt_write_stateless_reset2(dest, destlen, &token, rand,
|
|
+ randlen);
|
|
+}
|
|
+
|
|
+ngtcp2_ssize
|
|
+ngtcp2_pkt_write_stateless_reset2(uint8_t *dest, size_t destlen,
|
|
+ const ngtcp2_stateless_reset_token *token,
|
|
+ const uint8_t *rand, size_t randlen) {
|
|
uint8_t *p;
|
|
|
|
- if (destlen <
|
|
- NGTCP2_MIN_STATELESS_RESET_RANDLEN + NGTCP2_STATELESS_RESET_TOKENLEN) {
|
|
+ if (destlen < NGTCP2_MIN_STATELESS_RESET_RANDLEN + sizeof(token->data)) {
|
|
return NGTCP2_ERR_NOBUF;
|
|
}
|
|
|
|
@@ -2251,11 +2267,11 @@ ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen,
|
|
|
|
p = dest;
|
|
|
|
- randlen = ngtcp2_min_size(destlen - NGTCP2_STATELESS_RESET_TOKENLEN, randlen);
|
|
+ randlen = ngtcp2_min_size(destlen - sizeof(token->data), randlen);
|
|
|
|
p = ngtcp2_cpymem(p, rand, randlen);
|
|
- p = ngtcp2_cpymem(p, stateless_reset_token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
- *dest = (uint8_t)((*dest & 0x7fu) | 0x40u);
|
|
+ p = ngtcp2_cpymem(p, token->data, sizeof(token->data));
|
|
+ *dest = (uint8_t)((*dest & 0x3FU) | 0x40U);
|
|
|
|
return p - dest;
|
|
}
|
|
@@ -2299,11 +2315,11 @@ ngtcp2_ssize ngtcp2_pkt_write_retry(
|
|
case NGTCP2_PROTO_VER_V1:
|
|
default:
|
|
nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1;
|
|
- noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
|
|
+ noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
|
|
break;
|
|
case NGTCP2_PROTO_VER_V2:
|
|
nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2;
|
|
- noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
|
|
+ noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
|
|
break;
|
|
}
|
|
|
|
@@ -2349,7 +2365,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry(
|
|
return NGTCP2_ERR_NOBUF;
|
|
}
|
|
|
|
- *p &= 0xf0;
|
|
+ *p &= 0xF0;
|
|
*p |= unused;
|
|
|
|
p += nwrite;
|
|
@@ -2389,11 +2405,11 @@ int ngtcp2_pkt_verify_retry_tag(uint32_t version, const ngtcp2_pkt_retry *retry,
|
|
case NGTCP2_PROTO_VER_V1:
|
|
default:
|
|
nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1;
|
|
- noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
|
|
+ noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
|
|
break;
|
|
case NGTCP2_PROTO_VER_V2:
|
|
nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2;
|
|
- noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
|
|
+ noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
|
|
break;
|
|
}
|
|
|
|
@@ -2423,7 +2439,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset,
|
|
left -= n;
|
|
|
|
if (left > 8 + 1073741823 && len > 1073741823) {
|
|
- len = ngtcp2_min_uint64(len, 4611686018427387903lu);
|
|
+ len = ngtcp2_min_uint64(len, 4611686018427387903UL);
|
|
return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8));
|
|
}
|
|
|
|
@@ -2454,7 +2470,7 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) {
|
|
|
|
if (left > 8 + 1073741823 && len > 1073741823) {
|
|
#if SIZE_MAX == UINT64_MAX
|
|
- len = ngtcp2_min_size(len, 4611686018427387903lu);
|
|
+ len = ngtcp2_min_size(len, 4611686018427387903UL);
|
|
#endif /* SIZE_MAX == UINT64_MAX */
|
|
return ngtcp2_min_size(len, left - 8);
|
|
}
|
|
@@ -2571,3 +2587,299 @@ int ngtcp2_pkt_verify_reserved_bits(uint8_t c) {
|
|
|
|
return (c & NGTCP2_SHORT_RESERVED_BIT_MASK) == 0 ? 0 : NGTCP2_ERR_PROTO;
|
|
}
|
|
+
|
|
+size_t ngtcp2_pkt_split_vec_rand(ngtcp2_vec *data, size_t datacnt,
|
|
+ uint64_t *offsets, ngtcp2_pcg32 *pcg,
|
|
+ size_t max_add) {
|
|
+ ngtcp2_vec *v;
|
|
+ size_t idx;
|
|
+ size_t len;
|
|
+
|
|
+ for (; max_add; --max_add) {
|
|
+ idx = ngtcp2_pcg32_rand_n(pcg, (uint32_t)datacnt);
|
|
+ assert(idx < datacnt);
|
|
+
|
|
+ v = &data[idx];
|
|
+
|
|
+ if (v->len <= 1) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ len = v->len / 2;
|
|
+
|
|
+ ngtcp2_vec_split_at(&data[datacnt], v, len);
|
|
+
|
|
+ offsets[datacnt] = offsets[idx] + len;
|
|
+
|
|
+ ++datacnt;
|
|
+ }
|
|
+
|
|
+ return datacnt;
|
|
+}
|
|
+
|
|
+size_t ngtcp2_pkt_split_vec_at(ngtcp2_vec *data, size_t datacnt,
|
|
+ uint64_t *offsets, size_t at) {
|
|
+ assert(at < data[0].len);
|
|
+
|
|
+ ngtcp2_vec_split_at(&data[datacnt], &data[0], at);
|
|
+
|
|
+ offsets[datacnt] = offsets[0] + at;
|
|
+
|
|
+ return datacnt + 1;
|
|
+}
|
|
+
|
|
+static int pkt_tls_skip8(ngtcp2_buf *buf) {
|
|
+ size_t len;
|
|
+
|
|
+ if (ngtcp2_buf_len(buf) < 1) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len = *buf->pos++;
|
|
+
|
|
+ if (ngtcp2_buf_len(buf) < len) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ buf->pos += len;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pkt_tls_skip16(ngtcp2_buf *buf) {
|
|
+ uint16_t len;
|
|
+
|
|
+ if (ngtcp2_buf_len(buf) < sizeof(len)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ buf->pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf->pos);
|
|
+
|
|
+ if (ngtcp2_buf_len(buf) < len) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ buf->pos += len;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ngtcp2_pkt_find_server_name(ngtcp2_vec *server_name, const ngtcp2_vec *v) {
|
|
+ ngtcp2_buf buf;
|
|
+ uint32_t msglen;
|
|
+ uint16_t len;
|
|
+ uint16_t legacy_ver;
|
|
+ uint16_t ext_type;
|
|
+
|
|
+ assert(v->len);
|
|
+
|
|
+ ngtcp2_buf_init(&buf, v->base, v->len);
|
|
+ buf.last += v->len;
|
|
+
|
|
+ /* Handshake msg_type and length */
|
|
+ if (ngtcp2_buf_len(&buf) < 1 + 3) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Keep parsing only when msg_type is client_hello(1). */
|
|
+ if (*buf.pos++ != 1) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint24be(&msglen, buf.pos);
|
|
+
|
|
+ /* Truncate the buffer to msglen */
|
|
+ ngtcp2_buf_trunc(&buf, msglen);
|
|
+
|
|
+ /* legacy_version(0x0303) */
|
|
+ if (ngtcp2_buf_len(&buf) < sizeof(uint16_t)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint16be(&legacy_ver, buf.pos);
|
|
+ if (legacy_ver != 0x0303) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* random */
|
|
+ if (ngtcp2_buf_len(&buf) < 32) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ buf.pos += 32;
|
|
+
|
|
+ /* legacy_session_id */
|
|
+ if (pkt_tls_skip8(&buf) != 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* cipher_suites */
|
|
+ if (pkt_tls_skip16(&buf) != 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* legacy_compression_methods */
|
|
+ if (pkt_tls_skip8(&buf) != 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* extensions */
|
|
+ if (ngtcp2_buf_len(&buf) < sizeof(uint16_t)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
|
|
+
|
|
+ /* Truncate the buffer to extensions length */
|
|
+ ngtcp2_buf_trunc(&buf, len);
|
|
+
|
|
+ for (;;) {
|
|
+ /* Verify that extension_type and length of extension_data are
|
|
+ available */
|
|
+ if (ngtcp2_buf_len(&buf) < sizeof(uint16_t) * 2) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* extension_type */
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint16be(&ext_type, buf.pos);
|
|
+ if (ext_type != 0) {
|
|
+ /* extension_data */
|
|
+ if (pkt_tls_skip16(&buf) != 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Server Name Indication extension(0) */
|
|
+
|
|
+ /* extension_data */
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
|
|
+ if (ngtcp2_buf_len(&buf) < len || len < 2) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Truncate the buffer to extension_data length */
|
|
+ ngtcp2_buf_trunc(&buf, len);
|
|
+
|
|
+ /* server_name_list */
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
|
|
+ if (ngtcp2_buf_len(&buf) < len || len < 1 + 2) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* We deliberately do not check server_name_list length + 2 ==
|
|
+ extension_data length. They most likely match, and even if
|
|
+ not, no problem at all. */
|
|
+
|
|
+ /* Truncate the buffer to server_name_list length */
|
|
+ ngtcp2_buf_trunc(&buf, len);
|
|
+
|
|
+ /* name_type */
|
|
+ if (*buf.pos++ != 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* name */
|
|
+ buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
|
|
+ if (ngtcp2_buf_len(&buf) < len) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ server_name->base = buf.pos;
|
|
+ server_name->len = len;
|
|
+
|
|
+ return 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+size_t ngtcp2_pkt_append_ping_and_padding(ngtcp2_vec *data, size_t datacnt,
|
|
+ ngtcp2_pcg32 *pcg, size_t n) {
|
|
+ uint32_t k;
|
|
+
|
|
+ for (; n && datacnt < NGTCP2_MAX_STREAM_DATACNT;) {
|
|
+ k = ngtcp2_pcg32_rand_n(pcg, (uint32_t)n + 1);
|
|
+ if (k == 0) {
|
|
+ /* PING */
|
|
+ data[datacnt] = (ngtcp2_vec){
|
|
+ .base = NULL,
|
|
+ .len = 0,
|
|
+ };
|
|
+
|
|
+ ++k;
|
|
+ } else {
|
|
+ /* PADDING of k length */
|
|
+ data[datacnt] = (ngtcp2_vec){
|
|
+ .base = NULL,
|
|
+ .len = k,
|
|
+ };
|
|
+ }
|
|
+
|
|
+ ++datacnt;
|
|
+ n -= k;
|
|
+ }
|
|
+
|
|
+ return datacnt;
|
|
+}
|
|
+
|
|
+void ngtcp2_pkt_permutate_vec(ngtcp2_vec *data, size_t datacnt,
|
|
+ uint64_t *offsets, ngtcp2_pcg32 *pcg) {
|
|
+ size_t i, j;
|
|
+ ngtcp2_vec v;
|
|
+ uint64_t o;
|
|
+
|
|
+ if (datacnt < 2) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = datacnt - 1; i > 0; --i) {
|
|
+ j = ngtcp2_pcg32_rand_n(pcg, (uint32_t)i);
|
|
+
|
|
+ if (i == j) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ v = data[i];
|
|
+ data[i] = data[j];
|
|
+ data[j] = v;
|
|
+
|
|
+ o = offsets[i];
|
|
+ offsets[i] = offsets[j];
|
|
+ offsets[j] = o;
|
|
+ }
|
|
+}
|
|
+
|
|
+size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data,
|
|
+ size_t datacnt, uint64_t *offsets,
|
|
+ ngtcp2_pcg32 *pcg,
|
|
+ const ngtcp2_vec *part) {
|
|
+ ngtcp2_vec *v = &data[0];
|
|
+ size_t len;
|
|
+
|
|
+ assert(datacnt);
|
|
+ assert(v->base < part->base);
|
|
+ assert(ngtcp2_vec_end(part) <= ngtcp2_vec_end(v));
|
|
+
|
|
+ len = (size_t)(part->base - v->base) + part->len / 2;
|
|
+
|
|
+ ngtcp2_vec_split_at(removed_data, v, len);
|
|
+
|
|
+ if (removed_data->len == 1) {
|
|
+ return datacnt;
|
|
+ }
|
|
+
|
|
+ len = 1 + ngtcp2_pcg32_rand_n(
|
|
+ pcg, (uint32_t)ngtcp2_min_size(30, removed_data->len - 1));
|
|
+ assert(len < removed_data->len);
|
|
+
|
|
+ ngtcp2_vec_split_at(&data[datacnt], removed_data, len);
|
|
+
|
|
+ offsets[datacnt] = offsets[0] + v->len + removed_data->len;
|
|
+
|
|
+ return datacnt + 1;
|
|
+}
|
|
+
|
|
+int ngtcp2_stateless_reset_token_eq(const ngtcp2_stateless_reset_token *a,
|
|
+ const ngtcp2_stateless_reset_token *b) {
|
|
+ return memcmp(a->data, b->data, sizeof(a->data)) == 0;
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_pkt.h b/third_party/ngtcp2/lib/ngtcp2_pkt.h
|
|
index 756076e7a7f..bfdb065b74c 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_pkt.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_pkt.h
|
|
@@ -38,14 +38,14 @@
|
|
|
|
/* Long header specific macros */
|
|
#define NGTCP2_LONG_TYPE_MASK 0x30
|
|
-#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0c
|
|
+#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0C
|
|
|
|
/* Short header specific macros */
|
|
#define NGTCP2_SHORT_RESERVED_BIT_MASK 0x18
|
|
#define NGTCP2_SHORT_KEY_PHASE_BIT 0x04
|
|
|
|
/* NGTCP2_SR_TYPE is a Type field of Stateless Reset. */
|
|
-#define NGTCP2_SR_TYPE 0x1f
|
|
+#define NGTCP2_SR_TYPE 0x1F
|
|
|
|
/* NGTCP2_MIN_LONG_HEADERLEN is the minimum length of long header.
|
|
That is (1|1|TT|RR|PP)<1> + VERSION<4> + DCIL<1> + SCIL<1> +
|
|
@@ -78,23 +78,23 @@
|
|
|
|
/* NGTCP2_MAX_SERVER_STREAM_ID_BIDI is the maximum bidirectional
|
|
server stream ID. */
|
|
-#define NGTCP2_MAX_SERVER_STREAM_ID_BIDI ((int64_t)0x3ffffffffffffffdll)
|
|
+#define NGTCP2_MAX_SERVER_STREAM_ID_BIDI ((int64_t)0x3FFFFFFFFFFFFFFDLL)
|
|
/* NGTCP2_MAX_CLIENT_STREAM_ID_BIDI is the maximum bidirectional
|
|
client stream ID. */
|
|
-#define NGTCP2_MAX_CLIENT_STREAM_ID_BIDI ((int64_t)0x3ffffffffffffffcll)
|
|
+#define NGTCP2_MAX_CLIENT_STREAM_ID_BIDI ((int64_t)0x3FFFFFFFFFFFFFFCLL)
|
|
/* NGTCP2_MAX_SERVER_STREAM_ID_UNI is the maximum unidirectional
|
|
server stream ID. */
|
|
-#define NGTCP2_MAX_SERVER_STREAM_ID_UNI ((int64_t)0x3fffffffffffffffll)
|
|
+#define NGTCP2_MAX_SERVER_STREAM_ID_UNI ((int64_t)0x3FFFFFFFFFFFFFFFLL)
|
|
/* NGTCP2_MAX_CLIENT_STREAM_ID_UNI is the maximum unidirectional
|
|
client stream ID. */
|
|
-#define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3ffffffffffffffell)
|
|
+#define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3FFFFFFFFFFFFFFELL)
|
|
|
|
/* NGTCP2_MAX_NUM_ACK_RANGES is the maximum number of Additional ACK
|
|
ranges which this library can create, or decode. */
|
|
#define NGTCP2_MAX_ACK_RANGES 32
|
|
|
|
/* NGTCP2_MAX_PKT_NUM is the maximum packet number. */
|
|
-#define NGTCP2_MAX_PKT_NUM ((int64_t)((1ll << 62) - 1))
|
|
+#define NGTCP2_MAX_PKT_NUM ((int64_t)((1LL << 62) - 1))
|
|
|
|
/* NGTCP2_MIN_PKT_EXPANDLEN is the minimum packet size expansion to
|
|
hide/trigger Stateless Reset. */
|
|
@@ -103,10 +103,6 @@
|
|
/* NGTCP2_RETRY_TAGLEN is the length of Retry packet integrity tag. */
|
|
#define NGTCP2_RETRY_TAGLEN 16
|
|
|
|
-/* NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE is the maximum UDP datagram
|
|
- payload size that this library can write. */
|
|
-#define NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE ((1 << 24) - 1)
|
|
-
|
|
/* NGTCP2_PKT_LENGTHLEN is the number of bytes that is occupied by
|
|
Length field in Long packet header. */
|
|
#define NGTCP2_PKT_LENGTHLEN 4
|
|
@@ -137,6 +133,19 @@
|
|
v2. */
|
|
#define NGTCP2_PKT_TYPE_RETRY_V2 0x0
|
|
|
|
+/* NGTCP2_MIN_STREAM_DATALEN is the minimum length of STREAM frame to
|
|
+ avoid too small frame. It is not always enforced for various
|
|
+ reasons. For example, due to flow control, we might have fewer
|
|
+ bytes available to send. Therefore, it is only applied when the
|
|
+ length of data to send is larger than this limit. */
|
|
+#define NGTCP2_MIN_STREAM_DATALEN 256
|
|
+
|
|
+/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that
|
|
+ a ngtcp2_stream can include. */
|
|
+#define NGTCP2_MAX_STREAM_DATACNT 256
|
|
+
|
|
+typedef struct ngtcp2_pcg32 ngtcp2_pcg32;
|
|
+
|
|
typedef struct ngtcp2_pkt_retry {
|
|
ngtcp2_cid odcid;
|
|
uint8_t *token;
|
|
@@ -163,14 +172,18 @@ typedef struct ngtcp2_pkt_retry {
|
|
#define NGTCP2_FRAME_STREAMS_BLOCKED_UNI 0x17
|
|
#define NGTCP2_FRAME_NEW_CONNECTION_ID 0x18
|
|
#define NGTCP2_FRAME_RETIRE_CONNECTION_ID 0x19
|
|
-#define NGTCP2_FRAME_PATH_CHALLENGE 0x1a
|
|
-#define NGTCP2_FRAME_PATH_RESPONSE 0x1b
|
|
-#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1c
|
|
-#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1d
|
|
-#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1e
|
|
+#define NGTCP2_FRAME_PATH_CHALLENGE 0x1A
|
|
+#define NGTCP2_FRAME_PATH_RESPONSE 0x1B
|
|
+#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1C
|
|
+#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1D
|
|
+#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1E
|
|
#define NGTCP2_FRAME_DATAGRAM 0x30
|
|
#define NGTCP2_FRAME_DATAGRAM_LEN 0x31
|
|
|
|
+typedef struct ngtcp2_frame_hd {
|
|
+ uint64_t type;
|
|
+} ngtcp2_frame_hd;
|
|
+
|
|
/* ngtcp2_stream represents STREAM and CRYPTO frames. */
|
|
typedef struct ngtcp2_stream {
|
|
uint64_t type;
|
|
@@ -182,7 +195,7 @@ typedef struct ngtcp2_stream {
|
|
uint8_t flags;
|
|
/* CRYPTO frame does not include this field, and must set it to
|
|
0. */
|
|
- uint8_t fin;
|
|
+ int fin;
|
|
/* CRYPTO frame does not include this field, and must set it to
|
|
0. */
|
|
int64_t stream_id;
|
|
@@ -191,8 +204,9 @@ typedef struct ngtcp2_stream {
|
|
the length of data is 1 in this definition, the library may
|
|
allocate extra bytes to hold more elements. */
|
|
size_t datacnt;
|
|
- /* data is the array of ngtcp2_vec which references data. */
|
|
- ngtcp2_vec data[1];
|
|
+ /* data points to ngtcp2_vec array which references data. If
|
|
+ datacnt == 0, this field may be NULL. */
|
|
+ ngtcp2_vec *data;
|
|
} ngtcp2_stream;
|
|
|
|
typedef struct ngtcp2_ack_range {
|
|
@@ -216,7 +230,7 @@ typedef struct ngtcp2_ack {
|
|
} ecn;
|
|
uint64_t first_ack_range;
|
|
size_t rangecnt;
|
|
- ngtcp2_ack_range ranges[1];
|
|
+ ngtcp2_ack_range *ranges;
|
|
} ngtcp2_ack;
|
|
|
|
typedef struct ngtcp2_padding {
|
|
@@ -286,7 +300,7 @@ typedef struct ngtcp2_new_connection_id {
|
|
uint64_t seq;
|
|
uint64_t retire_prior_to;
|
|
ngtcp2_cid cid;
|
|
- uint8_t stateless_reset_token[NGTCP2_STATELESS_RESET_TOKENLEN];
|
|
+ ngtcp2_stateless_reset_token token;
|
|
} ngtcp2_new_connection_id;
|
|
|
|
typedef struct ngtcp2_stop_sending {
|
|
@@ -297,12 +311,12 @@ typedef struct ngtcp2_stop_sending {
|
|
|
|
typedef struct ngtcp2_path_challenge {
|
|
uint64_t type;
|
|
- uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN];
|
|
+ ngtcp2_path_challenge_data data;
|
|
} ngtcp2_path_challenge;
|
|
|
|
typedef struct ngtcp2_path_response {
|
|
uint64_t type;
|
|
- uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN];
|
|
+ ngtcp2_path_challenge_data data;
|
|
} ngtcp2_path_response;
|
|
|
|
typedef struct ngtcp2_new_token {
|
|
@@ -326,17 +340,13 @@ typedef struct ngtcp2_datagram {
|
|
uint64_t dgram_id;
|
|
/* datacnt is the number of elements that data contains. */
|
|
size_t datacnt;
|
|
- /* data is a pointer to ngtcp2_vec array that stores data. */
|
|
+ /* data is a pointer to ngtcp2_vec array that stores data. If
|
|
+ datacnt == 0, this field may be NULL.*/
|
|
ngtcp2_vec *data;
|
|
- /* rdata is conveniently embedded to ngtcp2_datagram, so that data
|
|
- field can just point to the address of this field to store a
|
|
- single vector which is the case when DATAGRAM is received from a
|
|
- remote endpoint. */
|
|
- ngtcp2_vec rdata[1];
|
|
} ngtcp2_datagram;
|
|
|
|
typedef union ngtcp2_frame {
|
|
- uint64_t type;
|
|
+ ngtcp2_frame_hd hd;
|
|
ngtcp2_stream stream;
|
|
ngtcp2_ack ack;
|
|
ngtcp2_padding padding;
|
|
@@ -357,11 +367,6 @@ typedef union ngtcp2_frame {
|
|
ngtcp2_retire_connection_id retire_connection_id;
|
|
ngtcp2_handshake_done handshake_done;
|
|
ngtcp2_datagram datagram;
|
|
- /* Extend ngtcp2_frame so that ngtcp2_stream has at least additional
|
|
- 3 ngtcp2_vec, totaling 4 slots, which can store HEADERS header,
|
|
- HEADERS payload, DATA header, and DATA payload in the standard
|
|
- sized ngtcp2_frame_chain. */
|
|
- uint8_t pad[sizeof(ngtcp2_stream) + sizeof(ngtcp2_vec) * 3];
|
|
} ngtcp2_frame;
|
|
|
|
typedef struct ngtcp2_pkt_chain ngtcp2_pkt_chain;
|
|
@@ -441,10 +446,22 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(uint8_t *out, size_t outlen,
|
|
ngtcp2_ssize ngtcp2_pkt_encode_hd_short(uint8_t *out, size_t outlen,
|
|
const ngtcp2_pkt_hd *hd);
|
|
|
|
+/*
|
|
+ * ngtcp2_frame_decoder is QUIC frame decoder. For frames that
|
|
+ * require the external buffers (e.g., ngtcp2_stream and ngtcp2_ack),
|
|
+ * it provides those buffers on demand.
|
|
+ */
|
|
+typedef struct ngtcp2_frame_decoder {
|
|
+ union {
|
|
+ ngtcp2_vec data;
|
|
+ ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
|
|
+ } buf;
|
|
+} ngtcp2_frame_decoder;
|
|
+
|
|
/**
|
|
* @function
|
|
*
|
|
- * `ngtcp2_pkt_decode_frame` decodes a QUIC frame from the buffer
|
|
+ * `ngtcp2_frame_decoder_decode` decodes a QUIC frame from the buffer
|
|
* pointed by |payload| whose length is |payloadlen|.
|
|
*
|
|
* This function returns the number of bytes read to decode a single
|
|
@@ -454,8 +471,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_short(uint8_t *out, size_t outlen,
|
|
* Frame is badly formatted; or frame type is unknown; or
|
|
* |payloadlen| is 0.
|
|
*/
|
|
-ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
|
|
- size_t payloadlen);
|
|
+ngtcp2_ssize ngtcp2_frame_decoder_decode(ngtcp2_frame_decoder *frd,
|
|
+ ngtcp2_frame *dest,
|
|
+ const uint8_t *payload,
|
|
+ size_t payloadlen);
|
|
|
|
/**
|
|
* @function
|
|
@@ -495,7 +514,7 @@ size_t ngtcp2_pkt_decode_version_negotiation(uint32_t *dest,
|
|
* NGTCP2_ERR_INVALID_ARGUMENT
|
|
* Payloadlen is too short.
|
|
*/
|
|
-int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset *sr,
|
|
+int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset2 *sr,
|
|
const uint8_t *payload,
|
|
size_t payloadlen);
|
|
|
|
@@ -1227,4 +1246,88 @@ uint8_t ngtcp2_pkt_versioned_type(uint32_t version, uint32_t pkt_type);
|
|
*/
|
|
uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c);
|
|
|
|
+/*
|
|
+ * ngtcp2_pkt_split_vec_rand appends ngtcp2_vec at most |max_add|
|
|
+ * times to the array pointed by |data| of length |datacnt| by
|
|
+ * splitting the existing ngtcp2_vec into two. Which ngtcp2_vec to
|
|
+ * split is chosen randomly. |offsets| contains the offset of each
|
|
+ * ngtcp2_vec pointed by |data|. |offsets| is also updated. The
|
|
+ * arrays must have the capacity at least |datacnt| + |max_add|.
|
|
+ * |pcg| is a random number generator.
|
|
+ *
|
|
+ * This function returns |datacnt| plus the number of ngtcp2_vec that
|
|
+ * are appended.
|
|
+ */
|
|
+size_t ngtcp2_pkt_split_vec_rand(ngtcp2_vec *data, size_t datacnt,
|
|
+ uint64_t *offsets, ngtcp2_pcg32 *pcg,
|
|
+ size_t max_add);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pkt_split_vec_at splits data[0] at offset |at|, and the
|
|
+ * right side of ngtcp2_vec is assigned to data[datacnt]. Similarly,
|
|
+ * offsets[0] + |at| is assigned to offsets[datacnt]. |data| must
|
|
+ * point to the array of ngtcp2_vec of length |datacnt|, and |datacnt|
|
|
+ * must be greater than 0. |at| must be strictly less than data->len.
|
|
+ *
|
|
+ * This function returns |datacnt| + 1.
|
|
+ */
|
|
+size_t ngtcp2_pkt_split_vec_at(ngtcp2_vec *data, size_t datacnt,
|
|
+ uint64_t *offsets, size_t at);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pkt_find_server_name searches TLS Server Name Indication
|
|
+ * extension in |v|. If it is found, assign the portion of server
|
|
+ * name to the object pointed by |server_name|, and returns nonzero.
|
|
+ * Otherwise, it returns 0. If |v| contains the extension partially,
|
|
+ * the function returns 0. |v| must not be empty.
|
|
+ */
|
|
+int ngtcp2_pkt_find_server_name(ngtcp2_vec *server_name, const ngtcp2_vec *v);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pkt_append_ping_and_padding appends PING and PADDING frames
|
|
+ * to the array pointed by |data| of length |datacnt|. The capacity
|
|
+ * of array must be at least NGTCP2_MAX_STREAM_DATACNT. |n| is the
|
|
+ * number of bytes available for serialized PING and PADDING frames.
|
|
+ * |pcg| is a random number generator. Which frames to add is
|
|
+ * determined randomly.
|
|
+ *
|
|
+ * The special encoding of PING and PADDING frames into ngtcp2_vec:
|
|
+ *
|
|
+ * - .base is NULL.
|
|
+ * - If .len is 0, it represents PING. Otherwise, PADDING of .len
|
|
+ * length.
|
|
+ *
|
|
+ * This function returns |datacnt| plus the number of frames added.
|
|
+ */
|
|
+size_t ngtcp2_pkt_append_ping_and_padding(ngtcp2_vec *data, size_t datacnt,
|
|
+ ngtcp2_pcg32 *pcg, size_t n);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pkt_permutate_vec permutates |data| and |offsets|, both have
|
|
+ * the |datacnt| elements. |pcg| is a random number generator.
|
|
+ */
|
|
+void ngtcp2_pkt_permutate_vec(ngtcp2_vec *data, size_t datacnt,
|
|
+ uint64_t *offsets, ngtcp2_pcg32 *pcg);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_pkt_remove_vec_partial removes the portion of data that
|
|
+ * contains part of |part| from data[0]. This function does not
|
|
+ * remove whole range of |part|. The length of removed data is chosen
|
|
+ * randomly. The removed portion of data is assigned to the object
|
|
+ * pointed by |removed_data|. If there is data located after the
|
|
+ * removed data, it will be assigned to data[datacnt].
|
|
+ * offsets[datacnt] is also updated, and the function returns
|
|
+ * |datacnt| + 1. Otherwise, this function returns |datacnt|.
|
|
+ */
|
|
+size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data,
|
|
+ size_t datacnt, uint64_t *offsets,
|
|
+ ngtcp2_pcg32 *pcg, const ngtcp2_vec *part);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_stateless_reset_token_eq returns nonzero if |a| and |b|
|
|
+ * share the same token.
|
|
+ */
|
|
+int ngtcp2_stateless_reset_token_eq(const ngtcp2_stateless_reset_token *a,
|
|
+ const ngtcp2_stateless_reset_token *b);
|
|
+
|
|
#endif /* !defined(NGTCP2_PKT_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ppe.c b/third_party/ngtcp2/lib/ngtcp2_ppe.c
|
|
index 4d193125ae8..3054732db04 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_ppe.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ppe.c
|
|
@@ -154,9 +154,9 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) {
|
|
|
|
p = buf->begin;
|
|
if (*p & NGTCP2_HEADER_FORM_BIT) {
|
|
- *p = (uint8_t)(*p ^ (mask[0] & 0x0f));
|
|
+ *p = (uint8_t)(*p ^ (mask[0] & 0x0F));
|
|
} else {
|
|
- *p = (uint8_t)(*p ^ (mask[0] & 0x1f));
|
|
+ *p = (uint8_t)(*p ^ (mask[0] & 0x1F));
|
|
}
|
|
|
|
p = buf->begin + ppe->pkt_num_offset;
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_pv.c b/third_party/ngtcp2/lib/ngtcp2_pv.c
|
|
index 471f84c7644..972c27f395a 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_pv.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_pv.c
|
|
@@ -31,12 +31,16 @@
|
|
#include "ngtcp2_log.h"
|
|
#include "ngtcp2_macro.h"
|
|
#include "ngtcp2_addr.h"
|
|
+#include "ngtcp2_str.h"
|
|
|
|
-void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
|
|
+void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent,
|
|
+ const ngtcp2_path_challenge_data *data,
|
|
ngtcp2_tstamp expiry, uint8_t flags) {
|
|
- memcpy(pvent->data, data, sizeof(pvent->data));
|
|
- pvent->expiry = expiry;
|
|
- pvent->flags = flags;
|
|
+ *pvent = (ngtcp2_pv_entry){
|
|
+ .expiry = expiry,
|
|
+ .flags = flags,
|
|
+ .data = *data,
|
|
+ };
|
|
}
|
|
|
|
int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid,
|
|
@@ -70,7 +74,7 @@ void ngtcp2_pv_del(ngtcp2_pv *pv) {
|
|
ngtcp2_mem_free(pv->mem, pv);
|
|
}
|
|
|
|
-void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
|
|
+void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data,
|
|
ngtcp2_tstamp expiry, uint8_t flags,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_pv_entry *ent;
|
|
@@ -88,7 +92,8 @@ void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
|
|
--pv->probe_pkt_left;
|
|
}
|
|
|
|
-int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data) {
|
|
+int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags,
|
|
+ const ngtcp2_path_challenge_data *data) {
|
|
size_t len = ngtcp2_ringbuf_len(&pv->ents.rb);
|
|
size_t i;
|
|
ngtcp2_pv_entry *ent;
|
|
@@ -99,7 +104,7 @@ int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data) {
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
ent = ngtcp2_ringbuf_get(&pv->ents.rb, i);
|
|
- if (memcmp(ent->data, data, sizeof(ent->data)) == 0) {
|
|
+ if (ngtcp2_cmemeq(ent->data.data, data->data, sizeof(ent->data.data))) {
|
|
*pflags = ent->flags;
|
|
ngtcp2_log_info(pv->log, NGTCP2_LOG_EVENT_PTV, "path has been validated");
|
|
return 0;
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_pv.h b/third_party/ngtcp2/lib/ngtcp2_pv.h
|
|
index 2d07e41648d..28bdf722b20 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_pv.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_pv.h
|
|
@@ -46,10 +46,10 @@ typedef struct ngtcp2_log ngtcp2_log;
|
|
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
|
|
|
|
/* NGTCP2_PV_ENTRY_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00u
|
|
+#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00U
|
|
/* NGTCP2_PV_ENTRY_FLAG_UNDERSIZED indicates that UDP datagram which
|
|
contains PATH_CHALLENGE is undersized (< 1200 bytes) */
|
|
-#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01u
|
|
+#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01U
|
|
|
|
typedef struct ngtcp2_pv_entry {
|
|
/* expiry is the timestamp when this PATH_CHALLENGE expires. */
|
|
@@ -57,30 +57,31 @@ typedef struct ngtcp2_pv_entry {
|
|
/* flags is zero or more of NGTCP2_PV_ENTRY_FLAG_*. */
|
|
uint8_t flags;
|
|
/* data is a byte string included in PATH_CHALLENGE. */
|
|
- uint8_t data[8];
|
|
+ ngtcp2_path_challenge_data data;
|
|
} ngtcp2_pv_entry;
|
|
|
|
-void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
|
|
+void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent,
|
|
+ const ngtcp2_path_challenge_data *data,
|
|
ngtcp2_tstamp expiry, uint8_t flags);
|
|
|
|
/* NGTCP2_PV_FLAG_NONE indicates no flag is set. */
|
|
-#define NGTCP2_PV_FLAG_NONE 0x00u
|
|
+#define NGTCP2_PV_FLAG_NONE 0x00U
|
|
/* NGTCP2_PV_FLAG_DONT_CARE indicates that the outcome of path
|
|
validation should be ignored entirely. */
|
|
-#define NGTCP2_PV_FLAG_DONT_CARE 0x01u
|
|
+#define NGTCP2_PV_FLAG_DONT_CARE 0x01U
|
|
/* NGTCP2_PV_FLAG_CANCEL_TIMER indicates that the expiry timer is
|
|
cancelled. */
|
|
-#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02u
|
|
+#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02U
|
|
/* NGTCP2_PV_FLAG_FALLBACK_PRESENT indicates that a fallback
|
|
Destination Connection ID and PTO are available in ngtcp2_pv. If
|
|
path validation fails, then fallback to them. If path validation
|
|
succeeds, the fallback Destination Connection ID is retired if it
|
|
is not zero length, and does not equal to the current Destination
|
|
Connection ID. */
|
|
-#define NGTCP2_PV_FLAG_FALLBACK_PRESENT 0x04u
|
|
+#define NGTCP2_PV_FLAG_FALLBACK_PRESENT 0x04U
|
|
/* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to
|
|
server's preferred address. This flag is only used by client. */
|
|
-#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10u
|
|
+#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10U
|
|
|
|
typedef struct ngtcp2_pv ngtcp2_pv;
|
|
|
|
@@ -141,7 +142,7 @@ void ngtcp2_pv_del(ngtcp2_pv *pv);
|
|
* ngtcp2_pv_add_entry adds new entry with |data|. |expiry| is the
|
|
* expiry time of the entry.
|
|
*/
|
|
-void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
|
|
+void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data,
|
|
ngtcp2_tstamp expiry, uint8_t flags, ngtcp2_tstamp ts);
|
|
|
|
/*
|
|
@@ -164,7 +165,8 @@ int ngtcp2_pv_full(ngtcp2_pv *pv);
|
|
* NGTCP2_ERR_INVALID_ARGUMENT
|
|
* |pv| does not have an entry which has |data| and |path|
|
|
*/
|
|
-int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data);
|
|
+int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags,
|
|
+ const ngtcp2_path_challenge_data *data);
|
|
|
|
/*
|
|
* ngtcp2_pv_handle_entry_expiry checks expiry of existing entries.
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_qlog.c b/third_party/ngtcp2/lib/ngtcp2_qlog.c
|
|
index c0f920746a4..42609481ec4 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_qlog.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_qlog.c
|
|
@@ -40,7 +40,7 @@ void ngtcp2_qlog_init(ngtcp2_qlog *qlog, ngtcp2_qlog_write write,
|
|
qlog->user_data = user_data;
|
|
}
|
|
|
|
-#define write_verbatim(DEST, S) ngtcp2_cpymem((DEST), (S), sizeof(S) - 1)
|
|
+#define write_verbatim(DEST, S) ngtcp2_cpymem((DEST), (S), ngtcp2_strlen_lit(S))
|
|
|
|
static uint8_t *write_string_impl(uint8_t *p, const uint8_t *data,
|
|
size_t datalen) {
|
|
@@ -53,17 +53,11 @@ static uint8_t *write_string_impl(uint8_t *p, const uint8_t *data,
|
|
}
|
|
|
|
#define write_string(DEST, S) \
|
|
- write_string_impl((DEST), (const uint8_t *)(S), sizeof(S) - 1)
|
|
-
|
|
-#define NGTCP2_LOWER_XDIGITS "0123456789abcdef"
|
|
+ write_string_impl((DEST), (const uint8_t *)(S), ngtcp2_strlen_lit(S))
|
|
|
|
static uint8_t *write_hex(uint8_t *p, const uint8_t *data, size_t datalen) {
|
|
- const uint8_t *b = data, *end = data + datalen;
|
|
*p++ = '"';
|
|
- for (; b != end; ++b) {
|
|
- *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b >> 4];
|
|
- *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b & 0xf];
|
|
- }
|
|
+ p = ngtcp2_encode_hex(p, data, datalen);
|
|
*p++ = '"';
|
|
return p;
|
|
}
|
|
@@ -72,38 +66,19 @@ static uint8_t *write_cid(uint8_t *p, const ngtcp2_cid *cid) {
|
|
return write_hex(p, cid->data, cid->datalen);
|
|
}
|
|
|
|
-static uint8_t *write_number(uint8_t *p, uint64_t n) {
|
|
- size_t nlen = 0;
|
|
- uint64_t t;
|
|
- uint8_t *res;
|
|
-
|
|
- if (n == 0) {
|
|
- *p++ = '0';
|
|
- return p;
|
|
- }
|
|
- for (t = n; t; t /= 10, ++nlen)
|
|
- ;
|
|
- p += nlen;
|
|
- res = p;
|
|
- for (; n; n /= 10) {
|
|
- *--p = (uint8_t)((n % 10) + '0');
|
|
- }
|
|
- return res;
|
|
-}
|
|
-
|
|
static uint8_t *write_tstamp(uint8_t *p, ngtcp2_tstamp ts) {
|
|
- return write_number(p, ts / NGTCP2_MILLISECONDS);
|
|
+ return ngtcp2_encode_uint(p, ts / NGTCP2_MILLISECONDS);
|
|
}
|
|
|
|
static uint8_t *write_duration(uint8_t *p, ngtcp2_duration duration) {
|
|
- return write_number(p, duration / NGTCP2_MILLISECONDS);
|
|
+ return ngtcp2_encode_uint(p, duration / NGTCP2_MILLISECONDS);
|
|
}
|
|
|
|
static uint8_t *write_bool(uint8_t *p, int b) {
|
|
if (b) {
|
|
- return ngtcp2_cpymem(p, "true", sizeof("true") - 1);
|
|
+ return ngtcp2_cpymem(p, "true", ngtcp2_strlen_lit("true"));
|
|
}
|
|
- return ngtcp2_cpymem(p, "false", sizeof("false") - 1);
|
|
+ return ngtcp2_cpymem(p, "false", ngtcp2_strlen_lit("false"));
|
|
}
|
|
|
|
static uint8_t *write_pair_impl(uint8_t *p, const uint8_t *name, size_t namelen,
|
|
@@ -114,7 +89,8 @@ static uint8_t *write_pair_impl(uint8_t *p, const uint8_t *name, size_t namelen,
|
|
}
|
|
|
|
#define write_pair(DEST, NAME, VALUE) \
|
|
- write_pair_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, (VALUE))
|
|
+ write_pair_impl((DEST), (const uint8_t *)(NAME), ngtcp2_strlen_lit(NAME), \
|
|
+ (VALUE))
|
|
|
|
static uint8_t *write_pair_hex_impl(uint8_t *p, const uint8_t *name,
|
|
size_t namelen, const uint8_t *value,
|
|
@@ -125,19 +101,19 @@ static uint8_t *write_pair_hex_impl(uint8_t *p, const uint8_t *name,
|
|
}
|
|
|
|
#define write_pair_hex(DEST, NAME, VALUE, VALUELEN) \
|
|
- write_pair_hex_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, \
|
|
- (VALUE), (VALUELEN))
|
|
+ write_pair_hex_impl((DEST), (const uint8_t *)(NAME), \
|
|
+ ngtcp2_strlen_lit(NAME), (VALUE), (VALUELEN))
|
|
|
|
static uint8_t *write_pair_number_impl(uint8_t *p, const uint8_t *name,
|
|
size_t namelen, uint64_t value) {
|
|
p = write_string_impl(p, name, namelen);
|
|
*p++ = ':';
|
|
- return write_number(p, value);
|
|
+ return ngtcp2_encode_uint(p, value);
|
|
}
|
|
|
|
#define write_pair_number(DEST, NAME, VALUE) \
|
|
- write_pair_number_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, \
|
|
- (VALUE))
|
|
+ write_pair_number_impl((DEST), (const uint8_t *)(NAME), \
|
|
+ ngtcp2_strlen_lit(NAME), (VALUE))
|
|
|
|
static uint8_t *write_pair_duration_impl(uint8_t *p, const uint8_t *name,
|
|
size_t namelen,
|
|
@@ -148,8 +124,8 @@ static uint8_t *write_pair_duration_impl(uint8_t *p, const uint8_t *name,
|
|
}
|
|
|
|
#define write_pair_duration(DEST, NAME, VALUE) \
|
|
- write_pair_duration_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, \
|
|
- (VALUE))
|
|
+ write_pair_duration_impl((DEST), (const uint8_t *)(NAME), \
|
|
+ ngtcp2_strlen_lit(NAME), (VALUE))
|
|
|
|
static uint8_t *write_pair_tstamp_impl(uint8_t *p, const uint8_t *name,
|
|
size_t namelen, ngtcp2_tstamp ts) {
|
|
@@ -159,8 +135,8 @@ static uint8_t *write_pair_tstamp_impl(uint8_t *p, const uint8_t *name,
|
|
}
|
|
|
|
#define write_pair_tstamp(DEST, NAME, VALUE) \
|
|
- write_pair_tstamp_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, \
|
|
- (VALUE))
|
|
+ write_pair_tstamp_impl((DEST), (const uint8_t *)(NAME), \
|
|
+ ngtcp2_strlen_lit(NAME), (VALUE))
|
|
|
|
static uint8_t *write_pair_bool_impl(uint8_t *p, const uint8_t *name,
|
|
size_t namelen, int b) {
|
|
@@ -170,8 +146,8 @@ static uint8_t *write_pair_bool_impl(uint8_t *p, const uint8_t *name,
|
|
}
|
|
|
|
#define write_pair_bool(DEST, NAME, VALUE) \
|
|
- write_pair_bool_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, \
|
|
- (VALUE))
|
|
+ write_pair_bool_impl((DEST), (const uint8_t *)(NAME), \
|
|
+ ngtcp2_strlen_lit(NAME), (VALUE))
|
|
|
|
static uint8_t *write_pair_cid_impl(uint8_t *p, const uint8_t *name,
|
|
size_t namelen, const ngtcp2_cid *cid) {
|
|
@@ -181,10 +157,10 @@ static uint8_t *write_pair_cid_impl(uint8_t *p, const uint8_t *name,
|
|
}
|
|
|
|
#define write_pair_cid(DEST, NAME, VALUE) \
|
|
- write_pair_cid_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, \
|
|
- (VALUE))
|
|
+ write_pair_cid_impl((DEST), (const uint8_t *)(NAME), \
|
|
+ ngtcp2_strlen_lit(NAME), (VALUE))
|
|
|
|
-#define ngtcp2_make_vec_lit(S) {(uint8_t *)(S), sizeof((S)) - 1}
|
|
+#define ngtcp2_make_vec_lit(S) {(uint8_t *)(S), ngtcp2_strlen_lit((S))}
|
|
|
|
static uint8_t *write_common_fields(uint8_t *p, const ngtcp2_cid *odcid) {
|
|
p = write_verbatim(
|
|
@@ -218,7 +194,7 @@ void ngtcp2_qlog_start(ngtcp2_qlog *qlog, const ngtcp2_cid *odcid, int server) {
|
|
}
|
|
|
|
p = write_verbatim(
|
|
- p, "\x1e{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\",");
|
|
+ p, "\x1E{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\",");
|
|
p = write_trace(p, server, odcid);
|
|
p = write_verbatim(p, "}\n");
|
|
|
|
@@ -227,49 +203,41 @@ void ngtcp2_qlog_start(ngtcp2_qlog *qlog, const ngtcp2_cid *odcid, int server) {
|
|
}
|
|
|
|
void ngtcp2_qlog_end(ngtcp2_qlog *qlog) {
|
|
- uint8_t buf[1] = {0};
|
|
-
|
|
if (!qlog->write) {
|
|
return;
|
|
}
|
|
|
|
- qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_FIN, &buf, 0);
|
|
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_FIN, "", 0);
|
|
}
|
|
|
|
-static ngtcp2_vec vec_pkt_type_initial = ngtcp2_make_vec_lit("initial");
|
|
-static ngtcp2_vec vec_pkt_type_handshake = ngtcp2_make_vec_lit("handshake");
|
|
-static ngtcp2_vec vec_pkt_type_0rtt = ngtcp2_make_vec_lit("0RTT");
|
|
-static ngtcp2_vec vec_pkt_type_1rtt = ngtcp2_make_vec_lit("1RTT");
|
|
-static ngtcp2_vec vec_pkt_type_retry = ngtcp2_make_vec_lit("retry");
|
|
-static ngtcp2_vec vec_pkt_type_version_negotiation =
|
|
+static const ngtcp2_vec vec_pkt_type_initial = ngtcp2_make_vec_lit("initial");
|
|
+static const ngtcp2_vec vec_pkt_type_handshake =
|
|
+ ngtcp2_make_vec_lit("handshake");
|
|
+static const ngtcp2_vec vec_pkt_type_0rtt = ngtcp2_make_vec_lit("0RTT");
|
|
+static const ngtcp2_vec vec_pkt_type_1rtt = ngtcp2_make_vec_lit("1RTT");
|
|
+static const ngtcp2_vec vec_pkt_type_retry = ngtcp2_make_vec_lit("retry");
|
|
+static const ngtcp2_vec vec_pkt_type_version_negotiation =
|
|
ngtcp2_make_vec_lit("version_negotiation");
|
|
-static ngtcp2_vec vec_pkt_type_stateless_reset =
|
|
+static const ngtcp2_vec vec_pkt_type_stateless_reset =
|
|
ngtcp2_make_vec_lit("stateless_reset");
|
|
-static ngtcp2_vec vec_pkt_type_unknown = ngtcp2_make_vec_lit("unknown");
|
|
+static const ngtcp2_vec vec_pkt_type_unknown = ngtcp2_make_vec_lit("unknown");
|
|
|
|
static const ngtcp2_vec *qlog_pkt_type(const ngtcp2_pkt_hd *hd) {
|
|
- if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
|
|
- switch (hd->type) {
|
|
- case NGTCP2_PKT_INITIAL:
|
|
- return &vec_pkt_type_initial;
|
|
- case NGTCP2_PKT_HANDSHAKE:
|
|
- return &vec_pkt_type_handshake;
|
|
- case NGTCP2_PKT_0RTT:
|
|
- return &vec_pkt_type_0rtt;
|
|
- case NGTCP2_PKT_RETRY:
|
|
- return &vec_pkt_type_retry;
|
|
- default:
|
|
- return &vec_pkt_type_unknown;
|
|
- }
|
|
- }
|
|
-
|
|
switch (hd->type) {
|
|
+ case NGTCP2_PKT_INITIAL:
|
|
+ return &vec_pkt_type_initial;
|
|
+ case NGTCP2_PKT_0RTT:
|
|
+ return &vec_pkt_type_0rtt;
|
|
+ case NGTCP2_PKT_HANDSHAKE:
|
|
+ return &vec_pkt_type_handshake;
|
|
+ case NGTCP2_PKT_RETRY:
|
|
+ return &vec_pkt_type_retry;
|
|
+ case NGTCP2_PKT_1RTT:
|
|
+ return &vec_pkt_type_1rtt;
|
|
case NGTCP2_PKT_VERSION_NEGOTIATION:
|
|
return &vec_pkt_type_version_negotiation;
|
|
case NGTCP2_PKT_STATELESS_RESET:
|
|
return &vec_pkt_type_stateless_reset;
|
|
- case NGTCP2_PKT_1RTT:
|
|
- return &vec_pkt_type_1rtt;
|
|
default:
|
|
return &vec_pkt_type_unknown;
|
|
}
|
|
@@ -340,10 +308,10 @@ static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) {
|
|
min_ack = fr->largest_ack - (int64_t)fr->first_ack_range;
|
|
|
|
*p++ = '[';
|
|
- p = write_number(p, (uint64_t)min_ack);
|
|
+ p = ngtcp2_encode_uint(p, (uint64_t)min_ack);
|
|
if (largest_ack != min_ack) {
|
|
*p++ = ',';
|
|
- p = write_number(p, (uint64_t)largest_ack);
|
|
+ p = ngtcp2_encode_uint(p, (uint64_t)largest_ack);
|
|
}
|
|
*p++ = ']';
|
|
|
|
@@ -353,10 +321,10 @@ static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) {
|
|
min_ack = largest_ack - (int64_t)range->len;
|
|
*p++ = ',';
|
|
*p++ = '[';
|
|
- p = write_number(p, (uint64_t)min_ack);
|
|
+ p = ngtcp2_encode_uint(p, (uint64_t)min_ack);
|
|
if (largest_ack != min_ack) {
|
|
*p++ = ',';
|
|
- p = write_number(p, (uint64_t)largest_ack);
|
|
+ p = ngtcp2_encode_uint(p, (uint64_t)largest_ack);
|
|
}
|
|
*p++ = ']';
|
|
}
|
|
@@ -579,8 +547,7 @@ write_new_connection_id_frame(uint8_t *p, const ngtcp2_new_connection_id *fr) {
|
|
*p++ = ',';
|
|
p = write_pair_cid(p, "connection_id", &fr->cid);
|
|
p = write_verbatim(p, ",\"stateless_reset_token\":{");
|
|
- p = write_pair_hex(p, "data", fr->stateless_reset_token,
|
|
- sizeof(fr->stateless_reset_token));
|
|
+ p = write_pair_hex(p, "data", fr->token.data, sizeof(fr->token.data));
|
|
*p++ = '}';
|
|
*p++ = '}';
|
|
|
|
@@ -610,7 +577,7 @@ static uint8_t *write_path_challenge_frame(uint8_t *p,
|
|
#define NGTCP2_QLOG_PATH_CHALLENGE_FRAME_OVERHEAD 57
|
|
|
|
p = write_verbatim(p, "{\"frame_type\":\"path_challenge\",");
|
|
- p = write_pair_hex(p, "data", fr->data, sizeof(fr->data));
|
|
+ p = write_pair_hex(p, "data", fr->data.data, sizeof(fr->data.data));
|
|
*p++ = '}';
|
|
|
|
return p;
|
|
@@ -624,7 +591,7 @@ static uint8_t *write_path_response_frame(uint8_t *p,
|
|
#define NGTCP2_QLOG_PATH_RESPONSE_FRAME_OVERHEAD 56
|
|
|
|
p = write_verbatim(p, "{\"frame_type\":\"path_response\",");
|
|
- p = write_pair_hex(p, "data", fr->data, sizeof(fr->data));
|
|
+ p = write_pair_hex(p, "data", fr->data.data, sizeof(fr->data.data));
|
|
*p++ = '}';
|
|
|
|
return p;
|
|
@@ -694,7 +661,7 @@ static void qlog_pkt_write_start(ngtcp2_qlog *qlog, int sent) {
|
|
ngtcp2_buf_reset(&qlog->buf);
|
|
p = qlog->buf.last;
|
|
|
|
- *p++ = '\x1e';
|
|
+ *p++ = '\x1E';
|
|
*p++ = '{';
|
|
p = qlog_write_time(qlog, p);
|
|
p = write_verbatim(p, ",\"name\":");
|
|
@@ -738,7 +705,7 @@ static void qlog_pkt_write_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
|
|
p = write_verbatim(p, "],\"header\":");
|
|
p = write_pkt_hd(p, hd);
|
|
p = write_verbatim(p, ",\"raw\":{\"length\":");
|
|
- p = write_number(p, pktlen);
|
|
+ p = ngtcp2_encode_uint(p, pktlen);
|
|
p = write_verbatim(p, "}}}\n");
|
|
|
|
qlog->buf.last = p;
|
|
@@ -754,7 +721,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) {
|
|
return;
|
|
}
|
|
|
|
- switch (fr->type) {
|
|
+ switch (fr->hd.type) {
|
|
case NGTCP2_FRAME_PADDING:
|
|
if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_PADDING_FRAME_OVERHEAD + 1) {
|
|
return;
|
|
@@ -771,7 +738,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) {
|
|
case NGTCP2_FRAME_ACK_ECN:
|
|
if (ngtcp2_buf_left(&qlog->buf) <
|
|
NGTCP2_QLOG_ACK_FRAME_BASE_OVERHEAD +
|
|
- (size_t)(fr->type == NGTCP2_FRAME_ACK_ECN
|
|
+ (size_t)(fr->ack.type == NGTCP2_FRAME_ACK_ECN
|
|
? NGTCP2_QLOG_ACK_FRAME_ECN_OVERHEAD
|
|
: 0) +
|
|
NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.rangecnt) + 1) {
|
|
@@ -935,7 +902,7 @@ void ngtcp2_qlog_pkt_sent_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
|
|
void ngtcp2_qlog_parameters_set_transport_params(
|
|
ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int server,
|
|
ngtcp2_qlog_side side) {
|
|
- uint8_t buf[1024];
|
|
+ uint8_t buf[2048];
|
|
uint8_t *p = buf;
|
|
const ngtcp2_preferred_addr *paddr;
|
|
const ngtcp2_sockaddr_in *sa_in;
|
|
@@ -945,7 +912,7 @@ void ngtcp2_qlog_parameters_set_transport_params(
|
|
return;
|
|
}
|
|
|
|
- *p++ = '\x1e';
|
|
+ *p++ = '\x1E';
|
|
*p++ = '{';
|
|
p = qlog_write_time(qlog, p);
|
|
p = write_verbatim(
|
|
@@ -1061,7 +1028,7 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog,
|
|
return;
|
|
}
|
|
|
|
- *p++ = '\x1e';
|
|
+ *p++ = '\x1E';
|
|
*p++ = '{';
|
|
p = qlog_write_time(qlog, p);
|
|
p = write_verbatim(p, ",\"name\":\"recovery:metrics_updated\",\"data\":{");
|
|
@@ -1095,23 +1062,22 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog,
|
|
void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent) {
|
|
uint8_t buf[256];
|
|
uint8_t *p = buf;
|
|
- ngtcp2_pkt_hd hd = {0};
|
|
|
|
if (!qlog->write) {
|
|
return;
|
|
}
|
|
|
|
- *p++ = '\x1e';
|
|
+ *p++ = '\x1E';
|
|
*p++ = '{';
|
|
p = qlog_write_time(qlog, p);
|
|
p = write_verbatim(
|
|
p, ",\"name\":\"recovery:packet_lost\",\"data\":{\"header\":");
|
|
|
|
- hd.type = ent->hd.type;
|
|
- hd.flags = ent->hd.flags;
|
|
- hd.pkt_num = ent->hd.pkt_num;
|
|
-
|
|
- p = write_pkt_hd(p, &hd);
|
|
+ p = write_pkt_hd(p, &(ngtcp2_pkt_hd){
|
|
+ .pkt_num = ent->hd.pkt_num,
|
|
+ .type = ent->hd.type,
|
|
+ .flags = ent->hd.flags,
|
|
+ });
|
|
p = write_verbatim(p, "}}\n");
|
|
|
|
qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
|
|
@@ -1129,7 +1095,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
|
|
|
|
ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf));
|
|
|
|
- *buf.last++ = '\x1e';
|
|
+ *buf.last++ = '\x1E';
|
|
*buf.last++ = '{';
|
|
buf.last = qlog_write_time(qlog, buf.last);
|
|
buf.last = write_verbatim(
|
|
@@ -1151,26 +1117,25 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
|
|
}
|
|
|
|
void ngtcp2_qlog_stateless_reset_pkt_received(
|
|
- ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr) {
|
|
+ ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr) {
|
|
uint8_t buf[256];
|
|
uint8_t *p = buf;
|
|
- ngtcp2_pkt_hd hd = {0};
|
|
|
|
if (!qlog->write) {
|
|
return;
|
|
}
|
|
|
|
- hd.type = NGTCP2_PKT_STATELESS_RESET;
|
|
-
|
|
- *p++ = '\x1e';
|
|
+ *p++ = '\x1E';
|
|
*p++ = '{';
|
|
p = qlog_write_time(qlog, p);
|
|
p = write_verbatim(
|
|
p, ",\"name\":\"transport:packet_received\",\"data\":{\"header\":");
|
|
- p = write_pkt_hd(p, &hd);
|
|
+ p = write_pkt_hd(p, &(ngtcp2_pkt_hd){
|
|
+ .type = NGTCP2_PKT_STATELESS_RESET,
|
|
+ });
|
|
*p++ = ',';
|
|
- p = write_pair_hex(p, "stateless_reset_token", sr->stateless_reset_token,
|
|
- NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
+ p = write_pair_hex(p, "stateless_reset_token", sr->token.data,
|
|
+ sizeof(sr->token.data));
|
|
p = write_verbatim(p, "}}\n");
|
|
|
|
qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
|
|
@@ -1192,7 +1157,7 @@ void ngtcp2_qlog_version_negotiation_pkt_received(ngtcp2_qlog *qlog,
|
|
|
|
ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf));
|
|
|
|
- *buf.last++ = '\x1e';
|
|
+ *buf.last++ = '\x1E';
|
|
*buf.last++ = '{';
|
|
buf.last = qlog_write_time(qlog, buf.last);
|
|
buf.last = write_verbatim(
|
|
@@ -1201,8 +1166,8 @@ void ngtcp2_qlog_version_negotiation_pkt_received(ngtcp2_qlog *qlog,
|
|
buf.last = write_verbatim(buf.last, ",\"supported_versions\":[");
|
|
|
|
if (nsv) {
|
|
- if (ngtcp2_buf_left(&buf) <
|
|
- (sizeof("\"xxxxxxxx\",") - 1) * nsv - 1 + sizeof("]}}\n") - 1) {
|
|
+ if (ngtcp2_buf_left(&buf) < ngtcp2_strlen_lit("\"xxxxxxxx\",") * nsv - 1 +
|
|
+ ngtcp2_strlen_lit("]}}\n")) {
|
|
return;
|
|
}
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_qlog.h b/third_party/ngtcp2/lib/ngtcp2_qlog.h
|
|
index d2a5f1038c0..17668a50233 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_qlog.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_qlog.h
|
|
@@ -147,7 +147,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
|
|
* event for a received Stateless Reset packet.
|
|
*/
|
|
void ngtcp2_qlog_stateless_reset_pkt_received(
|
|
- ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr);
|
|
+ ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr);
|
|
|
|
/*
|
|
* ngtcp2_qlog_version_negotiation_pkt_received writes packet_received
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_range.c b/third_party/ngtcp2/lib/ngtcp2_range.c
|
|
index e8989153293..a949a657338 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_range.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_range.c
|
|
@@ -26,18 +26,22 @@
|
|
#include "ngtcp2_macro.h"
|
|
|
|
void ngtcp2_range_init(ngtcp2_range *r, uint64_t begin, uint64_t end) {
|
|
- r->begin = begin;
|
|
- r->end = end;
|
|
+ *r = (ngtcp2_range){
|
|
+ .begin = begin,
|
|
+ .end = end,
|
|
+ };
|
|
}
|
|
|
|
ngtcp2_range ngtcp2_range_intersect(const ngtcp2_range *a,
|
|
const ngtcp2_range *b) {
|
|
- ngtcp2_range r = {0};
|
|
+ ngtcp2_range r;
|
|
uint64_t begin = ngtcp2_max_uint64(a->begin, b->begin);
|
|
uint64_t end = ngtcp2_min_uint64(a->end, b->end);
|
|
|
|
if (begin < end) {
|
|
ngtcp2_range_init(&r, begin, end);
|
|
+ } else {
|
|
+ r = (ngtcp2_range){0};
|
|
}
|
|
|
|
return r;
|
|
@@ -52,10 +56,14 @@ int ngtcp2_range_eq(const ngtcp2_range *a, const ngtcp2_range *b) {
|
|
void ngtcp2_range_cut(ngtcp2_range *left, ngtcp2_range *right,
|
|
const ngtcp2_range *a, const ngtcp2_range *b) {
|
|
/* Assume that b is included in a */
|
|
- left->begin = a->begin;
|
|
- left->end = b->begin;
|
|
- right->begin = b->end;
|
|
- right->end = a->end;
|
|
+ *left = (ngtcp2_range){
|
|
+ .begin = a->begin,
|
|
+ .end = b->begin,
|
|
+ };
|
|
+ *right = (ngtcp2_range){
|
|
+ .begin = b->end,
|
|
+ .end = a->end,
|
|
+ };
|
|
}
|
|
|
|
int ngtcp2_range_not_after(const ngtcp2_range *a, const ngtcp2_range *b) {
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ratelim.c b/third_party/ngtcp2/lib/ngtcp2_ratelim.c
|
|
new file mode 100644
|
|
index 00000000000..d13ed9a14aa
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ratelim.c
|
|
@@ -0,0 +1,84 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ * Copyright (c) 2023 nghttp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#include "ngtcp2_ratelim.h"
|
|
+
|
|
+#include <assert.h>
|
|
+
|
|
+#include "ngtcp2_macro.h"
|
|
+
|
|
+void ngtcp2_ratelim_init(ngtcp2_ratelim *rlim, uint64_t burst, uint64_t rate,
|
|
+ ngtcp2_tstamp ts) {
|
|
+ *rlim = (ngtcp2_ratelim){
|
|
+ .burst = burst,
|
|
+ .rate = rate,
|
|
+ .tokens = burst,
|
|
+ .ts = ts,
|
|
+ };
|
|
+}
|
|
+
|
|
+/* ratelim_update updates rlim->tokens with the current |ts|. */
|
|
+static void ratelim_update(ngtcp2_ratelim *rlim, ngtcp2_tstamp ts) {
|
|
+ uint64_t d, gain, gps;
|
|
+
|
|
+ assert(ts >= rlim->ts);
|
|
+
|
|
+ if (ts == rlim->ts) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ d = ts - rlim->ts;
|
|
+ rlim->ts = ts;
|
|
+
|
|
+ if (rlim->rate > (UINT64_MAX - rlim->carry) / d) {
|
|
+ gain = UINT64_MAX;
|
|
+ } else {
|
|
+ gain = rlim->rate * d + rlim->carry;
|
|
+ }
|
|
+
|
|
+ gps = gain / NGTCP2_SECONDS;
|
|
+
|
|
+ if (gps < rlim->burst && rlim->tokens < rlim->burst - gps) {
|
|
+ rlim->tokens += gps;
|
|
+ rlim->carry = gain % NGTCP2_SECONDS;
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ rlim->tokens = rlim->burst;
|
|
+ rlim->carry = 0;
|
|
+}
|
|
+
|
|
+int ngtcp2_ratelim_drain(ngtcp2_ratelim *rlim, uint64_t n, ngtcp2_tstamp ts) {
|
|
+ ratelim_update(rlim, ts);
|
|
+
|
|
+ if (rlim->tokens < n) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ rlim->tokens -= n;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ratelim.h b/third_party/ngtcp2/lib/ngtcp2_ratelim.h
|
|
new file mode 100644
|
|
index 00000000000..231f5d1b018
|
|
--- /dev/null
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ratelim.h
|
|
@@ -0,0 +1,59 @@
|
|
+/*
|
|
+ * ngtcp2
|
|
+ *
|
|
+ * Copyright (c) 2025 ngtcp2 contributors
|
|
+ * Copyright (c) 2023 nghttp2 contributors
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#ifndef NGTCP2_RATELIM_H
|
|
+#define NGTCP2_RATELIM_H
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include <config.h>
|
|
+#endif /* defined(HAVE_CONFIG_H) */
|
|
+
|
|
+#include <ngtcp2/ngtcp2.h>
|
|
+
|
|
+typedef struct ngtcp2_ratelim {
|
|
+ /* burst is the maximum number of tokens. */
|
|
+ uint64_t burst;
|
|
+ /* rate is the rate of token generation measured by token /
|
|
+ second. */
|
|
+ uint64_t rate;
|
|
+ /* tokens is the amount of tokens available to drain. */
|
|
+ uint64_t tokens;
|
|
+ /* carry is the partial token gained in sub-second period. It is
|
|
+ added to the computation in the next update round. */
|
|
+ uint64_t carry;
|
|
+ /* ts is the last timestamp that is known to this object. */
|
|
+ ngtcp2_tstamp ts;
|
|
+} ngtcp2_ratelim;
|
|
+
|
|
+/* ngtcp2_ratelim_init initializes |rlim| with the given
|
|
+ parameters. */
|
|
+void ngtcp2_ratelim_init(ngtcp2_ratelim *rlim, uint64_t burst, uint64_t rate,
|
|
+ ngtcp2_tstamp ts);
|
|
+
|
|
+/* ngtcp2_ratelim_drain drains |n| from rlim->tokens. It returns 0 if
|
|
+ it succeeds, or -1. */
|
|
+int ngtcp2_ratelim_drain(ngtcp2_ratelim *rlim, uint64_t n, ngtcp2_tstamp ts);
|
|
+
|
|
+#endif /* !defined(NGTCP2_RATELIM_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ringbuf.c b/third_party/ngtcp2/lib/ngtcp2_ringbuf.c
|
|
index 353afca4d48..40c25f2a3d1 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_ringbuf.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ringbuf.c
|
|
@@ -32,18 +32,8 @@
|
|
#include "ngtcp2_macro.h"
|
|
|
|
#ifndef NDEBUG
|
|
-static int ispow2(size_t n) {
|
|
-# if defined(_MSC_VER) && !defined(__clang__) && \
|
|
- (defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941))
|
|
- return n && !(n & (n - 1));
|
|
-# elif defined(WIN32)
|
|
- return 1 == __popcnt((unsigned int)n);
|
|
-# else /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
|
|
- (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
|
|
- return 1 == __builtin_popcount((unsigned int)n);
|
|
-# endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
|
|
- (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
|
|
-}
|
|
+/* Power-of-two test; simple portable bit trick. */
|
|
+static int ispow2(size_t n) { return n && !(n & (n - 1)); }
|
|
#endif /* !defined(NDEBUG) */
|
|
|
|
int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_ringbuf.h b/third_party/ngtcp2/lib/ngtcp2_ringbuf.h
|
|
index d490524805b..73efb5255fc 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_ringbuf.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_ringbuf.h
|
|
@@ -110,7 +110,9 @@ void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len);
|
|
void *ngtcp2_ringbuf_get(const ngtcp2_ringbuf *rb, size_t offset);
|
|
|
|
/* ngtcp2_ringbuf_len returns the number of elements stored. */
|
|
-#define ngtcp2_ringbuf_len(RB) ((RB)->len)
|
|
+static inline size_t ngtcp2_ringbuf_len(const ngtcp2_ringbuf *rb) {
|
|
+ return rb->len;
|
|
+}
|
|
|
|
/* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
|
|
int ngtcp2_ringbuf_full(const ngtcp2_ringbuf *rb);
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_rob.c b/third_party/ngtcp2/lib/ngtcp2_rob.c
|
|
index 853f1d650ea..20eae1d8819 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_rob.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_rob.c
|
|
@@ -36,8 +36,13 @@ int ngtcp2_rob_gap_new(ngtcp2_rob_gap **pg, uint64_t begin, uint64_t end,
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- (*pg)->range.begin = begin;
|
|
- (*pg)->range.end = end;
|
|
+ **pg = (ngtcp2_rob_gap){
|
|
+ .range =
|
|
+ {
|
|
+ .begin = begin,
|
|
+ .end = end,
|
|
+ },
|
|
+ };
|
|
|
|
return 0;
|
|
}
|
|
@@ -53,9 +58,14 @@ int ngtcp2_rob_data_new(ngtcp2_rob_data **pd, uint64_t offset, size_t chunk,
|
|
return NGTCP2_ERR_NOMEM;
|
|
}
|
|
|
|
- (*pd)->range.begin = offset;
|
|
- (*pd)->range.end = offset + chunk;
|
|
- (*pd)->begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data);
|
|
+ **pd = (ngtcp2_rob_data){
|
|
+ .range =
|
|
+ {
|
|
+ .begin = offset,
|
|
+ .end = offset + chunk,
|
|
+ },
|
|
+ .begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data),
|
|
+ };
|
|
|
|
return 0;
|
|
}
|
|
@@ -162,8 +172,8 @@ static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
return 0;
|
|
}
|
|
|
|
-int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
- size_t datalen) {
|
|
+ngtcp2_ssize ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset,
|
|
+ const uint8_t *data, size_t datalen) {
|
|
int rv;
|
|
ngtcp2_rob_gap *g;
|
|
ngtcp2_range m, l, r;
|
|
@@ -172,6 +182,8 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
.end = offset + datalen,
|
|
};
|
|
ngtcp2_ksl_it it;
|
|
+ ngtcp2_ssize nwrite = 0;
|
|
+ size_t mlen;
|
|
|
|
it = ngtcp2_ksl_lower_bound_search(&rob->gapksl, &q,
|
|
ngtcp2_ksl_range_exclusive_search);
|
|
@@ -180,7 +192,9 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
g = ngtcp2_ksl_it_get(&it);
|
|
|
|
m = ngtcp2_range_intersect(&q, &g->range);
|
|
- if (!ngtcp2_range_len(&m)) {
|
|
+
|
|
+ mlen = (size_t)ngtcp2_range_len(&m);
|
|
+ if (mlen == 0) {
|
|
break;
|
|
}
|
|
|
|
@@ -188,12 +202,13 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
ngtcp2_ksl_remove_hint(&rob->gapksl, &it, &it, &g->range);
|
|
ngtcp2_rob_gap_del(g, rob->mem);
|
|
|
|
- rv = rob_write_data(rob, m.begin, data + (m.begin - offset),
|
|
- (size_t)ngtcp2_range_len(&m));
|
|
+ rv = rob_write_data(rob, m.begin, data + (m.begin - offset), mlen);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
|
|
+ nwrite += (ngtcp2_ssize)mlen;
|
|
+
|
|
continue;
|
|
}
|
|
|
|
@@ -222,16 +237,17 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
g->range = r;
|
|
}
|
|
|
|
- rv = rob_write_data(rob, m.begin, data + (m.begin - offset),
|
|
- (size_t)ngtcp2_range_len(&m));
|
|
+ rv = rob_write_data(rob, m.begin, data + (m.begin - offset), mlen);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
|
|
+ nwrite += (ngtcp2_ssize)mlen;
|
|
+
|
|
ngtcp2_ksl_it_next(&it);
|
|
}
|
|
|
|
- return 0;
|
|
+ return nwrite;
|
|
}
|
|
|
|
void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) {
|
|
@@ -248,9 +264,11 @@ void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) {
|
|
}
|
|
|
|
if (offset < g->range.end) {
|
|
- ngtcp2_range r = {offset, g->range.end};
|
|
-
|
|
- ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r);
|
|
+ ngtcp2_ksl_update_key(&rob->gapksl, &g->range,
|
|
+ &(ngtcp2_range){
|
|
+ .begin = offset,
|
|
+ .end = g->range.end,
|
|
+ });
|
|
g->range.begin = offset;
|
|
|
|
break;
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_rob.h b/third_party/ngtcp2/lib/ngtcp2_rob.h
|
|
index d53b5160b10..60a1c5b46a0 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_rob.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_rob.h
|
|
@@ -138,14 +138,14 @@ void ngtcp2_rob_free(ngtcp2_rob *rob);
|
|
* ngtcp2_rob_push adds new data pointed by |data| of length |datalen|
|
|
* at the stream offset |offset|.
|
|
*
|
|
- * This function returns 0 if it succeeds, or one of the following
|
|
- * negative error codes:
|
|
+ * This function returns the number of data newly buffered if it
|
|
+ * succeeds, or one of the following negative error codes:
|
|
*
|
|
* NGTCP2_ERR_NOMEM
|
|
* Out of memory
|
|
*/
|
|
-int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
|
|
- size_t datalen);
|
|
+ngtcp2_ssize ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset,
|
|
+ const uint8_t *data, size_t datalen);
|
|
|
|
/*
|
|
* ngtcp2_rob_remove_prefix removes gap up to |offset|, exclusive. It
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_rst.c b/third_party/ngtcp2/lib/ngtcp2_rst.c
|
|
index 181691f3e69..89b395cd954 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_rst.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_rst.c
|
|
@@ -32,17 +32,11 @@
|
|
#include "ngtcp2_conn_stat.h"
|
|
|
|
void ngtcp2_rs_init(ngtcp2_rs *rs) {
|
|
- rs->interval = UINT64_MAX;
|
|
- rs->delivered = 0;
|
|
- rs->prior_delivered = 0;
|
|
- rs->prior_ts = UINT64_MAX;
|
|
- rs->tx_in_flight = 0;
|
|
- rs->lost = 0;
|
|
- rs->prior_lost = 0;
|
|
- rs->send_elapsed = 0;
|
|
- rs->ack_elapsed = 0;
|
|
- rs->last_end_seq = -1;
|
|
- rs->is_app_limited = 0;
|
|
+ *rs = (ngtcp2_rs){
|
|
+ .interval = UINT64_MAX,
|
|
+ .prior_ts = UINT64_MAX,
|
|
+ .last_end_seq = -1,
|
|
+ };
|
|
}
|
|
|
|
void ngtcp2_rst_init(ngtcp2_rst *rst) {
|
|
@@ -58,19 +52,29 @@ void ngtcp2_rst_reset(ngtcp2_rst *rst) {
|
|
rst->app_limited = 0;
|
|
rst->is_cwnd_limited = 0;
|
|
rst->lost = 0;
|
|
- rst->valid_after_seq = rst->last_seq;
|
|
+}
|
|
+
|
|
+void ngtcp2_rst_reset_rate_sample(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
|
|
+ ngtcp2_rs *rs = &rst->rs;
|
|
+
|
|
+ rs->interval = UINT64_MAX;
|
|
+ rs->prior_ts = UINT64_MAX;
|
|
+
|
|
+ cstat->delivery_rate_sec = 0;
|
|
}
|
|
|
|
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
|
|
const ngtcp2_conn_stat *cstat) {
|
|
- if (cstat->bytes_in_flight == 0) {
|
|
+ /* cstat->bytes_in_flight includes ent->pktlen. If they are the
|
|
+ same, there is no in-flight packets. */
|
|
+ if (cstat->bytes_in_flight == ent->pktlen) {
|
|
rst->first_sent_ts = rst->delivered_ts = ent->ts;
|
|
}
|
|
ent->rst.first_sent_ts = rst->first_sent_ts;
|
|
ent->rst.delivered_ts = rst->delivered_ts;
|
|
ent->rst.delivered = rst->delivered;
|
|
ent->rst.is_app_limited = rst->app_limited != 0;
|
|
- ent->rst.tx_in_flight = cstat->bytes_in_flight + ent->pktlen;
|
|
+ ent->rst.tx_in_flight = cstat->bytes_in_flight;
|
|
ent->rst.lost = rst->lost;
|
|
ent->rst.end_seq = ++rst->last_seq;
|
|
}
|
|
@@ -89,10 +93,8 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
|
|
rs->interval = ngtcp2_max_uint64(rs->send_elapsed, rs->ack_elapsed);
|
|
|
|
rs->delivered = rst->delivered - rs->prior_delivered;
|
|
- rs->lost = rst->lost - rs->prior_lost;
|
|
|
|
if (rs->interval < cstat->min_rtt) {
|
|
- rs->interval = UINT64_MAX;
|
|
return;
|
|
}
|
|
|
|
@@ -103,31 +105,23 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
|
|
cstat->delivery_rate_sec = rs->delivered * NGTCP2_SECONDS / rs->interval;
|
|
}
|
|
|
|
-static int rst_is_newest_pkt(const ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
|
|
- const ngtcp2_rs *rs) {
|
|
- return ent->ts > rst->first_sent_ts ||
|
|
- (ent->ts == rst->first_sent_ts && ent->rst.end_seq > rs->last_end_seq);
|
|
+static int is_newest_pkt(const ngtcp2_rtb_entry *ent, const ngtcp2_rs *rs) {
|
|
+ return ent->rst.end_seq > rs->last_end_seq;
|
|
}
|
|
|
|
void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
|
|
ngtcp2_tstamp ts) {
|
|
ngtcp2_rs *rs = &rst->rs;
|
|
|
|
- if (ent->rst.end_seq <= rst->valid_after_seq) {
|
|
- return;
|
|
- }
|
|
-
|
|
rst->delivered += ent->pktlen;
|
|
rst->delivered_ts = ts;
|
|
|
|
- if (rs->prior_ts == UINT64_MAX || rst_is_newest_pkt(rst, ent, rs)) {
|
|
+ if (rs->prior_ts == UINT64_MAX || is_newest_pkt(ent, rs)) {
|
|
rs->prior_delivered = ent->rst.delivered;
|
|
rs->prior_ts = ent->rst.delivered_ts;
|
|
rs->is_app_limited = ent->rst.is_app_limited;
|
|
rs->send_elapsed = ent->ts - ent->rst.first_sent_ts;
|
|
rs->ack_elapsed = rst->delivered_ts - ent->rst.delivered_ts;
|
|
- rs->tx_in_flight = ent->rst.tx_in_flight;
|
|
- rs->prior_lost = ent->rst.lost;
|
|
rs->last_end_seq = ent->rst.end_seq;
|
|
rst->first_sent_ts = ent->ts;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_rst.h b/third_party/ngtcp2/lib/ngtcp2_rst.h
|
|
index c2580306cc5..b0bc2d06c9c 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_rst.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_rst.h
|
|
@@ -48,7 +48,6 @@ typedef struct ngtcp2_rs {
|
|
ngtcp2_tstamp prior_ts;
|
|
uint64_t tx_in_flight;
|
|
uint64_t lost;
|
|
- uint64_t prior_lost;
|
|
ngtcp2_duration send_elapsed;
|
|
ngtcp2_duration ack_elapsed;
|
|
int64_t last_end_seq;
|
|
@@ -73,10 +72,6 @@ typedef struct ngtcp2_rst {
|
|
across all packet number spaces, we can replace this with a
|
|
packet number. */
|
|
int64_t last_seq;
|
|
- /* valid_after_seq is the sequence number, and ignore a packet if
|
|
- the sequence number of the packet is less than or equal to this
|
|
- number. */
|
|
- int64_t valid_after_seq;
|
|
int is_cwnd_limited;
|
|
} ngtcp2_rst;
|
|
|
|
@@ -84,6 +79,8 @@ void ngtcp2_rst_init(ngtcp2_rst *rst);
|
|
|
|
void ngtcp2_rst_reset(ngtcp2_rst *rst);
|
|
|
|
+void ngtcp2_rst_reset_rate_sample(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat);
|
|
+
|
|
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
|
|
const ngtcp2_conn_stat *cstat);
|
|
void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat);
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_rtb.c b/third_party/ngtcp2/lib/ngtcp2_rtb.c
|
|
index 101dcaa99f8..67aaa049302 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_rtb.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_rtb.c
|
|
@@ -43,16 +43,19 @@ ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent)
|
|
static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd,
|
|
ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
|
|
size_t pktlen, uint16_t flags) {
|
|
- memset(ent, 0, sizeof(*ent));
|
|
-
|
|
- ent->hd.pkt_num = hd->pkt_num;
|
|
- ent->hd.type = hd->type;
|
|
- ent->hd.flags = hd->flags;
|
|
- ent->frc = frc;
|
|
- ent->ts = ts;
|
|
- ent->lost_ts = UINT64_MAX;
|
|
- ent->pktlen = pktlen;
|
|
- ent->flags = flags;
|
|
+ *ent = (ngtcp2_rtb_entry){
|
|
+ .hd =
|
|
+ {
|
|
+ .pkt_num = hd->pkt_num,
|
|
+ .type = hd->type,
|
|
+ .flags = hd->flags,
|
|
+ },
|
|
+ .frc = frc,
|
|
+ .ts = ts,
|
|
+ .lost_ts = UINT64_MAX,
|
|
+ .pktlen = pktlen,
|
|
+ .flags = flags,
|
|
+ };
|
|
}
|
|
|
|
int ngtcp2_rtb_entry_objalloc_new(ngtcp2_rtb_entry **pent,
|
|
@@ -125,13 +128,12 @@ void ngtcp2_rtb_free(ngtcp2_rtb *rtb) {
|
|
|
|
static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
|
|
ngtcp2_conn_stat *cstat) {
|
|
- ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat);
|
|
-
|
|
assert(rtb->cc_pkt_num <= ent->hd.pkt_num);
|
|
|
|
cstat->bytes_in_flight += ent->pktlen;
|
|
rtb->cc_bytes_in_flight += ent->pktlen;
|
|
|
|
+ ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat);
|
|
ngtcp2_rst_update_app_limited(rtb->rst, cstat);
|
|
|
|
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
|
|
@@ -198,10 +200,10 @@ static size_t rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
|
|
}
|
|
|
|
/* NGTCP2_RECLAIM_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_RECLAIM_FLAG_NONE 0x00u
|
|
+#define NGTCP2_RECLAIM_FLAG_NONE 0x00U
|
|
/* NGTCP2_RECLAIM_FLAG_ON_LOSS indicates that frames are reclaimed
|
|
because of the packet loss.*/
|
|
-#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01u
|
|
+#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01U
|
|
|
|
/*
|
|
* rtb_reclaim_frame copies and queues frames included in |ent| for
|
|
@@ -231,7 +233,7 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags,
|
|
continue;
|
|
}
|
|
|
|
- switch (frc->fr.type) {
|
|
+ switch (frc->fr.hd.type) {
|
|
case NGTCP2_FRAME_STREAM:
|
|
strm = ngtcp2_conn_find_stream(conn, fr->stream.stream_id);
|
|
if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM)) {
|
|
@@ -269,7 +271,12 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr = *fr;
|
|
+ nfrc->fr.stream.type = fr->stream.type;
|
|
+ nfrc->fr.stream.flags = fr->stream.flags;
|
|
+ nfrc->fr.stream.fin = fr->stream.fin;
|
|
+ nfrc->fr.stream.stream_id = fr->stream.stream_id;
|
|
+ nfrc->fr.stream.offset = fr->stream.offset;
|
|
+ nfrc->fr.stream.datacnt = fr->stream.datacnt;
|
|
ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
|
|
fr->stream.datacnt);
|
|
|
|
@@ -312,7 +319,12 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags,
|
|
return rv;
|
|
}
|
|
|
|
- nfrc->fr = *fr;
|
|
+ nfrc->fr.stream.type = fr->stream.type;
|
|
+ nfrc->fr.stream.flags = 0;
|
|
+ nfrc->fr.stream.fin = 0;
|
|
+ nfrc->fr.stream.stream_id = 0;
|
|
+ nfrc->fr.stream.offset = fr->stream.offset;
|
|
+ nfrc->fr.stream.datacnt = fr->stream.datacnt;
|
|
ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
|
|
fr->stream.datacnt);
|
|
|
|
@@ -413,7 +425,7 @@ static int conn_process_lost_datagram(ngtcp2_conn *conn,
|
|
int rv;
|
|
|
|
for (frc = ent->frc; frc; frc = frc->next) {
|
|
- switch (frc->fr.type) {
|
|
+ switch (frc->fr.hd.type) {
|
|
case NGTCP2_FRAME_DATAGRAM:
|
|
case NGTCP2_FRAME_DATAGRAM_LEN:
|
|
assert(conn->callbacks.lost_datagram);
|
|
@@ -451,19 +463,28 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
|
|
if (ent->flags &
|
|
(NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
|
|
++rtb->num_lost_ignore_pkts;
|
|
- } else if (rtb->cc->on_pkt_lost) {
|
|
- cc->on_pkt_lost(cc, cstat,
|
|
- ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
|
|
- pktns->id, ent->ts, ent->rst.lost,
|
|
- ent->rst.tx_in_flight,
|
|
- ent->rst.is_app_limited),
|
|
- ts);
|
|
+ } else {
|
|
+ ++cstat->pkt_lost;
|
|
+ cstat->bytes_lost += ent->pktlen;
|
|
+
|
|
+ if (ent->hd.pkt_num >= rtb->cc_pkt_num) {
|
|
+ rtb->rst->lost += ent->pktlen;
|
|
+
|
|
+ if (rtb->cc->on_pkt_lost) {
|
|
+ cc->on_pkt_lost(cc, cstat,
|
|
+ ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
|
|
+ pktns->id, ent->ts, ent->rst.lost,
|
|
+ ent->rst.tx_in_flight,
|
|
+ ent->rst.is_app_limited),
|
|
+ ts);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
|
|
- ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "pkn=%" PRId64 " has already been reclaimed on PTO",
|
|
- ent->hd.pkt_num);
|
|
+ ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "pkn=%" PRId64 " has already been reclaimed on PTO",
|
|
+ ent->hd.pkt_num);
|
|
assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED));
|
|
assert(UINT64_MAX == ent->lost_ts);
|
|
} else {
|
|
@@ -520,9 +541,10 @@ static void rtb_remove(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it,
|
|
int rv;
|
|
(void)rv;
|
|
|
|
+ rtb_on_remove(rtb, ent, cstat);
|
|
+
|
|
rv = ngtcp2_ksl_remove_hint(&rtb->ents, it, it, &ent->hd.pkt_num);
|
|
assert(0 == rv);
|
|
- rtb_on_remove(rtb, ent, cstat);
|
|
|
|
assert(ent->next == NULL);
|
|
|
|
@@ -591,7 +613,7 @@ static int process_acked_pkt(ngtcp2_rtb_entry *ent, ngtcp2_conn *conn,
|
|
frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK;
|
|
}
|
|
|
|
- switch (frc->fr.type) {
|
|
+ switch (frc->fr.hd.type) {
|
|
case NGTCP2_FRAME_STREAM:
|
|
strm = ngtcp2_conn_find_stream(conn, frc->fr.stream.stream_id);
|
|
if (strm == NULL) {
|
|
@@ -704,6 +726,8 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
|
|
ngtcp2_cc *cc = rtb->cc;
|
|
ngtcp2_cc_pkt pkt;
|
|
|
|
+ assert(ent->hd.pkt_num >= rtb->cc_pkt_num);
|
|
+
|
|
ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts);
|
|
|
|
if (cc->on_pkt_acked) {
|
|
@@ -724,8 +748,7 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
|
|
static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
|
const ngtcp2_ack *fr, size_t ecn_acked,
|
|
- ngtcp2_tstamp largest_pkt_sent_ts,
|
|
- ngtcp2_tstamp ts) {
|
|
+ const ngtcp2_cc_ack *cc_ack, ngtcp2_tstamp ts) {
|
|
if (conn->tx.ecn.state == NGTCP2_ECN_STATE_FAILED) {
|
|
return;
|
|
}
|
|
@@ -752,9 +775,9 @@ static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
}
|
|
|
|
if (fr->type == NGTCP2_FRAME_ACK_ECN) {
|
|
- if (cc->congestion_event && largest_pkt_sent_ts != UINT64_MAX &&
|
|
+ if (cc->congestion_event && cc_ack->largest_pkt_sent_ts != UINT64_MAX &&
|
|
fr->ecn.ce > pktns->acktr.ecn.ack.ce) {
|
|
- cc->congestion_event(cc, cstat, largest_pkt_sent_ts, 0, ts);
|
|
+ cc->congestion_event(cc, cstat, cc_ack->largest_pkt_sent_ts, cc_ack, ts);
|
|
}
|
|
|
|
pktns->acktr.ecn.ack.ect0 = fr->ecn.ect0;
|
|
@@ -763,7 +786,7 @@ static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
}
|
|
}
|
|
|
|
-static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
|
|
+static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack,
|
|
ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts);
|
|
|
|
@@ -777,24 +800,23 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
int rv;
|
|
ngtcp2_ksl_it it;
|
|
size_t num_acked = 0;
|
|
- ngtcp2_tstamp largest_pkt_sent_ts = UINT64_MAX;
|
|
int64_t pkt_num;
|
|
ngtcp2_cc *cc = rtb->cc;
|
|
ngtcp2_rtb_entry *acked_ent = NULL;
|
|
int ack_eliciting_pkt_acked = 0;
|
|
size_t ecn_acked = 0;
|
|
int verify_ecn = 0;
|
|
- ngtcp2_cc_ack cc_ack = {0};
|
|
+ ngtcp2_cc_ack cc_ack = {
|
|
+ .largest_pkt_sent_ts = UINT64_MAX,
|
|
+ .rtt = UINT64_MAX,
|
|
+ };
|
|
size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_ignore_pkts;
|
|
|
|
- cc_ack.prior_bytes_in_flight = cstat->bytes_in_flight;
|
|
- cc_ack.rtt = UINT64_MAX;
|
|
-
|
|
if (conn && (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) &&
|
|
(conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR) &&
|
|
largest_ack >= conn->pktns.crypto.tx.ckm->pkt_num) {
|
|
- conn->flags &= (uint32_t) ~(NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED |
|
|
- NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR);
|
|
+ conn->flags &= (uint32_t)~(NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED |
|
|
+ NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR);
|
|
conn->crypto.key_update.confirmed_ts = ts;
|
|
|
|
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed");
|
|
@@ -805,12 +827,17 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
verify_ecn = 1;
|
|
}
|
|
|
|
+ ngtcp2_rst_reset_rate_sample(rtb->rst, cstat);
|
|
+
|
|
/* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
|
|
it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack);
|
|
if (ngtcp2_ksl_it_end(&it)) {
|
|
if (conn && verify_ecn) {
|
|
- conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked,
|
|
- largest_pkt_sent_ts, ts);
|
|
+ conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, &cc_ack, ts);
|
|
+ }
|
|
+
|
|
+ if (cc->on_ack_recv) {
|
|
+ cc->on_ack_recv(cc, cstat, &cc_ack, ts);
|
|
}
|
|
|
|
return 0;
|
|
@@ -834,8 +861,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
goto fail;
|
|
}
|
|
|
|
- if (largest_ack == pkt_num) {
|
|
- largest_pkt_sent_ts = ent->ts;
|
|
+ if (rtb->largest_acked_tx_pkt_num == pkt_num) {
|
|
+ cc_ack.largest_pkt_sent_ts = ent->ts;
|
|
}
|
|
|
|
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
|
|
@@ -843,7 +870,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
}
|
|
|
|
rtb_remove(rtb, &it, &acked_ent, ent, cstat);
|
|
- ++num_acked;
|
|
}
|
|
|
|
for (i = 0; i < fr->rangecnt; ++i) {
|
|
@@ -873,18 +899,14 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
}
|
|
|
|
rtb_remove(rtb, &it, &acked_ent, ent, cstat);
|
|
- ++num_acked;
|
|
}
|
|
}
|
|
|
|
- if (largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
|
|
- cc_ack.rtt =
|
|
- ngtcp2_max_uint64(pkt_ts - largest_pkt_sent_ts, NGTCP2_NANOSECONDS);
|
|
+ if (cc_ack.largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
|
|
+ cc_ack.rtt = ngtcp2_max_uint64(pkt_ts - cc_ack.largest_pkt_sent_ts,
|
|
+ NGTCP2_NANOSECONDS);
|
|
|
|
- rv = ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
|
|
- if (rv == 0 && cc->new_rtt_sample) {
|
|
- cc->new_rtt_sample(cc, cstat, ts);
|
|
- }
|
|
+ ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
|
|
}
|
|
|
|
if (conn) {
|
|
@@ -904,23 +926,22 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
|
|
cc_ack.bytes_delivered += ent->pktlen;
|
|
cc_ack.pkt_delivered = ent->rst.delivered;
|
|
+
|
|
+ rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
|
|
+
|
|
+ ++num_acked;
|
|
}
|
|
|
|
- rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
|
|
acked_ent = ent->next;
|
|
ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
|
|
rtb->frc_objalloc, rtb->mem);
|
|
}
|
|
-
|
|
- if (verify_ecn) {
|
|
- conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked,
|
|
- largest_pkt_sent_ts, ts);
|
|
- }
|
|
} else {
|
|
/* For unit tests */
|
|
for (ent = acked_ent; ent; ent = acked_ent) {
|
|
rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
|
|
acked_ent = ent->next;
|
|
+ ++num_acked;
|
|
ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
|
|
rtb->frc_objalloc, rtb->mem);
|
|
}
|
|
@@ -935,17 +956,18 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
|
|
ngtcp2_rst_on_ack_recv(rtb->rst, cstat);
|
|
|
|
if (conn) {
|
|
- rv = rtb_detect_lost_pkt(rtb, &cc_ack.bytes_lost, conn, pktns, cstat, ts);
|
|
+ rv = rtb_detect_lost_pkt(rtb, &cc_ack, conn, pktns, cstat, ts);
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
|
|
- rtb->rst->lost += cc_ack.bytes_lost;
|
|
+ if (conn && verify_ecn) {
|
|
+ conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, &cc_ack, ts);
|
|
+ }
|
|
|
|
- cc_ack.largest_pkt_sent_ts = largest_pkt_sent_ts;
|
|
- if (num_acked && cc->on_ack_recv) {
|
|
+ if (cc->on_ack_recv) {
|
|
cc->on_ack_recv(cc, cstat, &cc_ack, ts);
|
|
}
|
|
|
|
@@ -1011,7 +1033,11 @@ static int conn_all_ecn_pkt_lost(ngtcp2_conn *conn) {
|
|
pktns->tx.ecn.validation_pkt_sent == pktns->tx.ecn.validation_pkt_lost;
|
|
}
|
|
|
|
-static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
|
|
+/*
|
|
+ * This function assigns the number of bytes lost to
|
|
+ * |cc_ack|->bytes_lost if any.
|
|
+ */
|
|
+static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack,
|
|
ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
|
ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) {
|
|
ngtcp2_rtb_entry *ent;
|
|
@@ -1129,8 +1155,10 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
|
|
break;
|
|
}
|
|
|
|
+ cc_ack->bytes_lost = bytes_lost;
|
|
+
|
|
if (cc->congestion_event) {
|
|
- cc->congestion_event(cc, cstat, latest_ts, bytes_lost, ts);
|
|
+ cc->congestion_event(cc, cstat, latest_ts, cc_ack, ts);
|
|
}
|
|
|
|
loss_window = latest_ts - oldest_ts;
|
|
@@ -1143,10 +1171,10 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
|
|
*/
|
|
if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION && loss_window &&
|
|
loss_window >= congestion_period) {
|
|
- ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "persistent congestion loss_window=%" PRIu64
|
|
- " congestion_period=%" PRIu64,
|
|
- loss_window, congestion_period);
|
|
+ ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "persistent congestion loss_window=%" PRIu64
|
|
+ " congestion_period=%" PRIu64,
|
|
+ loss_window, congestion_period);
|
|
|
|
/* Reset min_rtt, srtt, and rttvar here. Next new RTT
|
|
sample will be used to recalculate these values. */
|
|
@@ -1166,18 +1194,18 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
|
|
|
|
ngtcp2_rtb_remove_excessive_lost_pkt(rtb, (size_t)pkt_thres);
|
|
|
|
- if (ppkt_lost) {
|
|
- *ppkt_lost = bytes_lost;
|
|
- }
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
|
|
ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
|
|
ngtcp2_tstamp ts) {
|
|
- return rtb_detect_lost_pkt(rtb, /* ppkt_lost = */ NULL, conn, pktns, cstat,
|
|
- ts);
|
|
+ return rtb_detect_lost_pkt(rtb,
|
|
+ &(ngtcp2_cc_ack){
|
|
+ .largest_pkt_sent_ts = UINT64_MAX,
|
|
+ .rtt = UINT64_MAX,
|
|
+ },
|
|
+ conn, pktns, cstat, ts);
|
|
}
|
|
|
|
void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
|
|
@@ -1193,8 +1221,8 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
|
|
|
|
assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
|
|
|
|
- ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
|
|
+ ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
|
|
|
|
--rtb->num_lost_pkts;
|
|
|
|
@@ -1230,13 +1258,14 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb,
|
|
ngtcp2_ksl_it_prev(&it);
|
|
ent = ngtcp2_ksl_it_get(&it);
|
|
|
|
- if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) ||
|
|
- ts - ent->lost_ts < timeout) {
|
|
+ assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
|
|
+
|
|
+ if (ts - ent->lost_ts < timeout) {
|
|
return;
|
|
}
|
|
|
|
- ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
|
|
+ ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
|
|
|
|
--rtb->num_lost_pkts;
|
|
|
|
@@ -1280,7 +1309,7 @@ static int rtb_reclaim_frame_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
|
|
int rv;
|
|
|
|
for (; *pfrc;) {
|
|
- switch ((*pfrc)->fr.type) {
|
|
+ switch ((*pfrc)->fr.hd.type) {
|
|
case NGTCP2_FRAME_STREAM:
|
|
frc = *pfrc;
|
|
|
|
@@ -1388,15 +1417,22 @@ int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
|
|
assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE));
|
|
|
|
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
|
|
- ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
- "pkn=%" PRId64 " has already been reclaimed on PTO",
|
|
- ent->hd.pkt_num);
|
|
+ ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
|
|
+ "pkn=%" PRId64 " has already been reclaimed on PTO",
|
|
+ ent->hd.pkt_num);
|
|
+
|
|
+ ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
|
|
+ rtb->frc_objalloc, rtb->mem);
|
|
+
|
|
continue;
|
|
}
|
|
|
|
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
|
|
(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) ||
|
|
!conn->callbacks.lost_datagram)) {
|
|
+ ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
|
|
+ rtb->frc_objalloc, rtb->mem);
|
|
+
|
|
continue;
|
|
}
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_rtb.h b/third_party/ngtcp2/lib/ngtcp2_rtb.h
|
|
index 14684a458a6..62bcb381fa1 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_rtb.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_rtb.h
|
|
@@ -48,41 +48,41 @@ typedef struct ngtcp2_conn_stat ngtcp2_conn_stat;
|
|
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
|
|
|
|
/* NGTCP2_RTB_ENTRY_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_PROBE indicates that the entry includes a
|
|
probe packet. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE indicates that the entry
|
|
includes a frame which must be retransmitted until it is
|
|
acknowledged. In most cases, this flag is used along with
|
|
NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING and
|
|
NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING indicates that the entry
|
|
elicits acknowledgement. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED indicates that the packet has
|
|
been reclaimed on PTO. It is not marked lost yet and still
|
|
consumes congestion window. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED indicates that the entry
|
|
has been marked lost and, optionally, scheduled to retransmit. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_ECN indicates that the entry is included in a
|
|
UDP datagram with ECN marking. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_DATAGRAM indicates that the entry includes
|
|
DATAGRAM frame. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE indicates that the entry includes
|
|
a PMTUD probe packet. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING indicates that the entry
|
|
includes a packet which elicits PTO probe packets. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100U
|
|
/* NGTCP2_RTB_ENTRY_FLAG_SKIP indicates that the entry has the skipped
|
|
packet number. */
|
|
-#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200u
|
|
+#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200U
|
|
|
|
typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry;
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_settings.c b/third_party/ngtcp2/lib/ngtcp2_settings.c
|
|
index 77a68bd112e..f774504282e 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_settings.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_settings.c
|
|
@@ -37,6 +37,10 @@ void ngtcp2_settings_default_versioned(int settings_version,
|
|
|
|
switch (settings_version) {
|
|
case NGTCP2_SETTINGS_VERSION:
|
|
+ settings->glitch_ratelim_burst = NGTCP2_DEFAULT_GLITCH_RATELIM_BURST;
|
|
+ settings->glitch_ratelim_rate = NGTCP2_DEFAULT_GLITCH_RATELIM_RATE;
|
|
+ /* fall through */
|
|
+ case NGTCP2_SETTINGS_V2:
|
|
case NGTCP2_SETTINGS_V1:
|
|
settings->cc_algo = NGTCP2_CC_ALGO_CUBIC;
|
|
settings->initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
|
|
@@ -82,6 +86,9 @@ size_t ngtcp2_settingslen_version(int settings_version) {
|
|
switch (settings_version) {
|
|
case NGTCP2_SETTINGS_VERSION:
|
|
return sizeof(settings);
|
|
+ case NGTCP2_SETTINGS_V2:
|
|
+ return offsetof(ngtcp2_settings, pmtud_probeslen) +
|
|
+ sizeof(settings.pmtud_probeslen);
|
|
case NGTCP2_SETTINGS_V1:
|
|
return offsetof(ngtcp2_settings, initial_pkt_num) +
|
|
sizeof(settings.initial_pkt_num);
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_settings.h b/third_party/ngtcp2/lib/ngtcp2_settings.h
|
|
index 80466d43e47..b40b6c4a895 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_settings.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_settings.h
|
|
@@ -31,6 +31,13 @@
|
|
|
|
#include <ngtcp2/ngtcp2.h>
|
|
|
|
+/* NGTCP2_DEFAULT_GLITCH_RATELIM_BURST is the maximum number of tokens
|
|
+ in glitch rate limiter. It is also the initial value. */
|
|
+#define NGTCP2_DEFAULT_GLITCH_RATELIM_BURST 10000
|
|
+/* NGTCP2_DEFAULT_GLITCH_RATELIM_RATE is the rate of tokens generated
|
|
+ per second for glitch rate limiter. */
|
|
+#define NGTCP2_DEFAULT_GLITCH_RATELIM_RATE 330
|
|
+
|
|
/*
|
|
* ngtcp2_settings_convert_to_latest converts |src| of version
|
|
* |settings_version| to the latest version NGTCP2_SETTINGS_VERSION.
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_str.c b/third_party/ngtcp2/lib/ngtcp2_str.c
|
|
index a61636d188f..2726571a504 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_str.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_str.c
|
|
@@ -47,27 +47,32 @@ const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n) {
|
|
|
|
uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) {
|
|
size_t i;
|
|
- uint8_t *p = dest;
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
- *p++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4];
|
|
- *p++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xf];
|
|
+ *dest++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4];
|
|
+ *dest++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xF];
|
|
}
|
|
|
|
+ return dest;
|
|
+}
|
|
+
|
|
+char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len) {
|
|
+ uint8_t *p = ngtcp2_encode_hex((uint8_t *)dest, data, len);
|
|
+
|
|
*p = '\0';
|
|
|
|
return dest;
|
|
}
|
|
|
|
-char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
|
|
- size_t len) {
|
|
+char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data,
|
|
+ size_t len) {
|
|
size_t i;
|
|
char *p = dest;
|
|
uint8_t c;
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
c = data[i];
|
|
- if (0x20 <= c && c <= 0x7e) {
|
|
+ if (0x20 <= c && c <= 0x7E) {
|
|
*p++ = (char)c;
|
|
} else {
|
|
*p++ = '.';
|
|
@@ -79,40 +84,15 @@ char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
|
|
return dest;
|
|
}
|
|
|
|
-/*
|
|
- * write_uint writes |n| to the buffer pointed by |p| in decimal
|
|
- * representation. It returns |p| plus the number of bytes written.
|
|
- * The function assumes that the buffer has enough capacity to contain
|
|
- * a string.
|
|
- */
|
|
-static uint8_t *write_uint(uint8_t *p, uint64_t n) {
|
|
- size_t nlen = 0;
|
|
- uint64_t t;
|
|
- uint8_t *res;
|
|
-
|
|
- if (n == 0) {
|
|
- *p++ = '0';
|
|
- return p;
|
|
- }
|
|
- for (t = n; t; t /= 10, ++nlen)
|
|
- ;
|
|
- p += nlen;
|
|
- res = p;
|
|
- for (; n; n /= 10) {
|
|
- *--p = (uint8_t)((n % 10) + '0');
|
|
- }
|
|
- return res;
|
|
-}
|
|
-
|
|
-uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr) {
|
|
+char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr) {
|
|
size_t i;
|
|
- uint8_t *p = dest;
|
|
+ char *p = dest;
|
|
|
|
- p = write_uint(p, addr[0]);
|
|
+ p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[0]);
|
|
|
|
for (i = 1; i < 4; ++i) {
|
|
*p++ = '.';
|
|
- p = write_uint(p, addr[i]);
|
|
+ p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[i]);
|
|
}
|
|
|
|
*p = '\0';
|
|
@@ -125,9 +105,9 @@ uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr) {
|
|
* length |len| to |dest| in hex string. Any leading zeros are
|
|
* suppressed. It returns |dest| plus the number of bytes written.
|
|
*/
|
|
-static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) {
|
|
+static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) {
|
|
size_t i;
|
|
- uint8_t *p = dest;
|
|
+ char *p = dest;
|
|
uint8_t d;
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
@@ -136,10 +116,10 @@ static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) {
|
|
break;
|
|
}
|
|
|
|
- d &= 0xf;
|
|
+ d &= 0xF;
|
|
|
|
if (d) {
|
|
- *p++ = (uint8_t)LOWER_XDIGITS[d];
|
|
+ *p++ = LOWER_XDIGITS[d];
|
|
++i;
|
|
break;
|
|
}
|
|
@@ -152,19 +132,19 @@ static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) {
|
|
|
|
for (; i < len; ++i) {
|
|
d = data[i];
|
|
- *p++ = (uint8_t)LOWER_XDIGITS[d >> 4];
|
|
- *p++ = (uint8_t)LOWER_XDIGITS[d & 0xf];
|
|
+ *p++ = LOWER_XDIGITS[d >> 4];
|
|
+ *p++ = LOWER_XDIGITS[d & 0xF];
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
-uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr) {
|
|
+char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr) {
|
|
uint16_t blks[8];
|
|
size_t i;
|
|
size_t zlen, zoff;
|
|
size_t max_zlen = 0, max_zoff = 8;
|
|
- uint8_t *p = dest;
|
|
+ char *p = dest;
|
|
|
|
for (i = 0; i < 16; i += sizeof(uint16_t)) {
|
|
/* Copy in network byte order. */
|
|
@@ -231,3 +211,124 @@ int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n) {
|
|
|
|
return rv == 0;
|
|
}
|
|
+
|
|
+/* countl_zero counts the number of leading zeros in |x|. It is
|
|
+ undefined if |x| is 0. */
|
|
+static int countl_zero(uint64_t x) {
|
|
+#ifdef __GNUC__
|
|
+ return __builtin_clzll(x);
|
|
+#else /* !defined(__GNUC__) */
|
|
+ /* This is the same implementation of Go's LeadingZeros64 in
|
|
+ math/bits package. */
|
|
+ static const uint8_t len8tab[] = {
|
|
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
+ 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
+ };
|
|
+ int n = 0;
|
|
+
|
|
+ if (x >= 1ULL << 32) {
|
|
+ x >>= 32;
|
|
+ n += 32;
|
|
+ }
|
|
+
|
|
+ if (x >= 1 << 16) {
|
|
+ x >>= 16;
|
|
+ n += 16;
|
|
+ }
|
|
+
|
|
+ if (x >= 1 << 8) {
|
|
+ x >>= 8;
|
|
+ n += 8;
|
|
+ }
|
|
+
|
|
+ return 64 - (n + len8tab[x]);
|
|
+#endif /* !defined(__GNUC__) */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * count_digit returns the minimum number of digits to represent |x|
|
|
+ * in base 10.
|
|
+ *
|
|
+ * credit:
|
|
+ * https://lemire.me/blog/2025/01/07/counting-the-digits-of-64-bit-integers/
|
|
+ */
|
|
+static size_t count_digit(uint64_t x) {
|
|
+ static const uint64_t count_digit_tbl[] = {
|
|
+ 9ULL,
|
|
+ 99ULL,
|
|
+ 999ULL,
|
|
+ 9999ULL,
|
|
+ 99999ULL,
|
|
+ 999999ULL,
|
|
+ 9999999ULL,
|
|
+ 99999999ULL,
|
|
+ 999999999ULL,
|
|
+ 9999999999ULL,
|
|
+ 99999999999ULL,
|
|
+ 999999999999ULL,
|
|
+ 9999999999999ULL,
|
|
+ 99999999999999ULL,
|
|
+ 999999999999999ULL,
|
|
+ 9999999999999999ULL,
|
|
+ 99999999999999999ULL,
|
|
+ 999999999999999999ULL,
|
|
+ 9999999999999999999ULL,
|
|
+ };
|
|
+ size_t y = (size_t)(19 * (63 - countl_zero(x | 1)) >> 6);
|
|
+
|
|
+ y += x > count_digit_tbl[y];
|
|
+
|
|
+ return y + 1;
|
|
+}
|
|
+
|
|
+uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n) {
|
|
+ static const uint8_t uint_digits[] =
|
|
+ "00010203040506070809101112131415161718192021222324252627282930313233343536"
|
|
+ "37383940414243444546474849505152535455565758596061626364656667686970717273"
|
|
+ "7475767778798081828384858687888990919293949596979899";
|
|
+ uint8_t *p;
|
|
+ const uint8_t *tp;
|
|
+
|
|
+ if (n < 10) {
|
|
+ *dest++ = (uint8_t)('0' + n);
|
|
+ return dest;
|
|
+ }
|
|
+
|
|
+ if (n < 100) {
|
|
+ tp = &uint_digits[n * 2];
|
|
+ *dest++ = *tp++;
|
|
+ *dest++ = *tp;
|
|
+ return dest;
|
|
+ }
|
|
+
|
|
+ dest += count_digit(n);
|
|
+ p = dest;
|
|
+
|
|
+ for (; n >= 100; n /= 100) {
|
|
+ p -= 2;
|
|
+ tp = &uint_digits[(n % 100) * 2];
|
|
+ p[0] = *tp++;
|
|
+ p[1] = *tp;
|
|
+ }
|
|
+
|
|
+ if (n < 10) {
|
|
+ *--p = (uint8_t)('0' + n);
|
|
+ return dest;
|
|
+ }
|
|
+
|
|
+ p -= 2;
|
|
+ tp = &uint_digits[n * 2];
|
|
+ p[0] = *tp++;
|
|
+ p[1] = *tp;
|
|
+
|
|
+ return dest;
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_str.h b/third_party/ngtcp2/lib/ngtcp2_str.h
|
|
index f970c153e80..051053d75b7 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_str.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_str.h
|
|
@@ -46,24 +46,31 @@ uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n);
|
|
const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n);
|
|
|
|
/*
|
|
- * ngtcp2_encode_hex encodes |data| of length |len| in hex string. It
|
|
- * writes additional NULL bytes at the end of the buffer. The buffer
|
|
- * pointed by |dest| must have at least |len| * 2 + 1 bytes space.
|
|
- * This function returns |dest|.
|
|
+ * ngtcp2_encode_hex encodes |data| of length |len| in hex string.
|
|
+ * The buffer pointed by |dest| must have at least |len| * 2 bytes
|
|
+ * space. This function returns |dest| + |len| * 2.
|
|
*/
|
|
uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len);
|
|
|
|
/*
|
|
- * ngtcp2_encode_ipv4 encodes binary form IPv4 address stored in
|
|
+ * ngtcp2_encode_hex_cstr encodes |data| of length |len| in hex
|
|
+ * string. It writes additional NULL bytes at the end of the buffer.
|
|
+ * The buffer pointed by |dest| must have at least |len| * 2 + 1 bytes
|
|
+ * space. This function returns |dest|.
|
|
+ */
|
|
+char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_encode_ipv4_cstr encodes binary form IPv4 address stored in
|
|
* |addr| to human readable text form in the buffer pointed by |dest|.
|
|
* The capacity of buffer must have enough length to store a text form
|
|
* plus a terminating NULL byte. The resulting text form ends with
|
|
* NULL byte. The function returns |dest|.
|
|
*/
|
|
-uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr);
|
|
+char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr);
|
|
|
|
/*
|
|
- * ngtcp2_encode_ipv6 encodes binary form IPv6 address stored in
|
|
+ * ngtcp2_encode_ipv6_cstr encodes binary form IPv6 address stored in
|
|
* |addr| to human readable text form in the buffer pointed by |dest|.
|
|
* The capacity of buffer must have enough length to store a text form
|
|
* plus a terminating NULL byte. The resulting text form ends with
|
|
@@ -72,7 +79,7 @@ uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr);
|
|
* https://tools.ietf.org/html/rfc5952#section-4. The function
|
|
* returns |dest|.
|
|
*/
|
|
-uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr);
|
|
+char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr);
|
|
|
|
/*
|
|
* ngtcp2_encode_printable_ascii encodes |data| of length |len| in
|
|
@@ -81,8 +88,8 @@ uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr);
|
|
* writes additional NULL bytes at the end of the buffer. |dest| must
|
|
* have at least |len| + 1 bytes. This function returns |dest|.
|
|
*/
|
|
-char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
|
|
- size_t len);
|
|
+char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data,
|
|
+ size_t len);
|
|
|
|
/*
|
|
* ngtcp2_cmemeq returns nonzero if the first |n| bytes of the buffers
|
|
@@ -91,4 +98,12 @@ char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
|
|
*/
|
|
int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n);
|
|
|
|
+/*
|
|
+ * ngtcp2_encode_uint encodes |n| as a decimal integer to the buffer
|
|
+ * pointed by |dest|. This function assumes that the buffer contains
|
|
+ * the sufficient capacity to write the number. This function returns
|
|
+ * the pointer to the buffer past the last byte written.
|
|
+ */
|
|
+uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n);
|
|
+
|
|
#endif /* !defined(NGTCP2_STR_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_strm.c b/third_party/ngtcp2/lib/ngtcp2_strm.c
|
|
index 8ea969c4add..70aa8933a3b 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_strm.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_strm.c
|
|
@@ -36,30 +36,27 @@ void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
|
|
uint64_t max_rx_offset, uint64_t max_tx_offset,
|
|
void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
|
|
const ngtcp2_mem *mem) {
|
|
- strm->pe.index = NGTCP2_PQ_BAD_INDEX;
|
|
- strm->cycle = 0;
|
|
- strm->frc_objalloc = frc_objalloc;
|
|
- strm->tx.acked_offset = NULL;
|
|
- strm->tx.cont_acked_offset = 0;
|
|
- strm->tx.streamfrq = NULL;
|
|
- strm->tx.offset = 0;
|
|
- strm->tx.max_offset = max_tx_offset;
|
|
- strm->tx.last_blocked_offset = UINT64_MAX;
|
|
- strm->tx.last_max_stream_data_ts = UINT64_MAX;
|
|
- strm->tx.loss_count = 0;
|
|
- strm->tx.last_lost_pkt_num = -1;
|
|
- strm->tx.stop_sending_app_error_code = 0;
|
|
- strm->tx.reset_stream_app_error_code = 0;
|
|
- strm->rx.rob = NULL;
|
|
- strm->rx.cont_offset = 0;
|
|
- strm->rx.last_offset = 0;
|
|
- strm->rx.max_offset = strm->rx.unsent_max_offset = strm->rx.window =
|
|
- max_rx_offset;
|
|
- strm->mem = mem;
|
|
- strm->stream_id = stream_id;
|
|
- strm->stream_user_data = stream_user_data;
|
|
- strm->flags = flags;
|
|
- strm->app_error_code = 0;
|
|
+ *strm = (ngtcp2_strm){
|
|
+ .pe.index = NGTCP2_PQ_BAD_INDEX,
|
|
+ .frc_objalloc = frc_objalloc,
|
|
+ .tx =
|
|
+ {
|
|
+ .max_offset = max_tx_offset,
|
|
+ .last_blocked_offset = UINT64_MAX,
|
|
+ .last_max_stream_data_ts = UINT64_MAX,
|
|
+ .last_lost_pkt_num = -1,
|
|
+ },
|
|
+ .rx =
|
|
+ {
|
|
+ .max_offset = max_rx_offset,
|
|
+ .unsent_max_offset = max_rx_offset,
|
|
+ .window = max_rx_offset,
|
|
+ },
|
|
+ .mem = mem,
|
|
+ .stream_id = stream_id,
|
|
+ .stream_user_data = stream_user_data,
|
|
+ .flags = flags,
|
|
+ };
|
|
}
|
|
|
|
void ngtcp2_strm_free(ngtcp2_strm *strm) {
|
|
@@ -120,12 +117,13 @@ uint64_t ngtcp2_strm_rx_offset(const ngtcp2_strm *strm) {
|
|
/* strm_rob_heavily_fragmented returns nonzero if the number of gaps
|
|
in |rob| exceeds the limit. */
|
|
static int strm_rob_heavily_fragmented(const ngtcp2_rob *rob) {
|
|
- return ngtcp2_ksl_len(&rob->gapksl) >= 5000;
|
|
+ return ngtcp2_ksl_len(&rob->gapksl) >= 4000;
|
|
}
|
|
|
|
-int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
|
|
- size_t datalen, uint64_t offset) {
|
|
+ngtcp2_ssize ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
|
|
+ size_t datalen, uint64_t offset) {
|
|
int rv;
|
|
+ ngtcp2_ssize nwrite;
|
|
|
|
if (strm->rx.rob == NULL) {
|
|
rv = strm_rob_init(strm);
|
|
@@ -138,11 +136,16 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
|
|
}
|
|
}
|
|
|
|
+ nwrite = ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
|
|
+ if (nwrite < 0) {
|
|
+ return nwrite;
|
|
+ }
|
|
+
|
|
if (strm_rob_heavily_fragmented(strm->rx.rob)) {
|
|
return NGTCP2_ERR_INTERNAL;
|
|
}
|
|
|
|
- return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
|
|
+ return nwrite;
|
|
}
|
|
|
|
void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
|
|
@@ -187,8 +190,8 @@ static int strm_streamfrq_init(ngtcp2_strm *strm) {
|
|
int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
|
|
int rv;
|
|
|
|
- assert(frc->fr.type == NGTCP2_FRAME_STREAM ||
|
|
- frc->fr.type == NGTCP2_FRAME_CRYPTO);
|
|
+ assert(frc->fr.hd.type == NGTCP2_FRAME_STREAM ||
|
|
+ frc->fr.hd.type == NGTCP2_FRAME_CRYPTO);
|
|
assert(frc->next == NULL);
|
|
|
|
if (strm->tx.streamfrq == NULL) {
|
|
@@ -196,6 +199,8 @@ int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
|
|
if (rv != 0) {
|
|
return rv;
|
|
}
|
|
+ } else if (ngtcp2_ksl_len(strm->tx.streamfrq) >= 8000) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
}
|
|
|
|
return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
|
|
@@ -300,8 +305,7 @@ static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
|
|
|
|
fr->offset = offset + base_offset;
|
|
fr->datacnt = end_idx - idx;
|
|
- fr->data[0].base += base_offset;
|
|
- fr->data[0].len -= (size_t)base_offset;
|
|
+ ngtcp2_vec_drop(&fr->data[0], (size_t)base_offset);
|
|
|
|
*pfrc = frc;
|
|
|
|
@@ -327,8 +331,7 @@ static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
|
|
nfr->stream_id = fr->stream_id;
|
|
nfr->offset = end_offset + end_base_offset;
|
|
nfr->datacnt = fr->datacnt - end_idx;
|
|
- nfr->data[0].base += end_base_offset;
|
|
- nfr->data[0].len -= (size_t)end_base_offset;
|
|
+ ngtcp2_vec_drop(&nfr->data[0], (size_t)end_base_offset);
|
|
|
|
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
|
|
if (rv != 0) {
|
|
@@ -356,8 +359,7 @@ static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
|
|
fr->data[fr->datacnt - 1].len = (size_t)end_base_offset;
|
|
}
|
|
|
|
- fr->data[0].base += base_offset;
|
|
- fr->data[0].len -= (size_t)base_offset;
|
|
+ ngtcp2_vec_drop(&fr->data[0], (size_t)base_offset);
|
|
|
|
*pfrc = frc;
|
|
|
|
@@ -370,13 +372,12 @@ static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
|
|
int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
size_t left) {
|
|
ngtcp2_stream *fr, *nfr;
|
|
- ngtcp2_frame_chain *frc, *nfrc, *sfrc;
|
|
+ ngtcp2_frame_chain *frc, *nfrc;
|
|
int rv;
|
|
size_t nmerged;
|
|
uint64_t datalen;
|
|
- ngtcp2_vec a[NGTCP2_MAX_STREAM_DATACNT];
|
|
- ngtcp2_vec b[NGTCP2_MAX_STREAM_DATACNT];
|
|
- size_t acnt, bcnt;
|
|
+ ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
|
|
+ size_t datacnt;
|
|
uint64_t unacked_offset;
|
|
|
|
if (strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0) {
|
|
@@ -398,7 +399,11 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
|
|
|
|
/* datalen could be zero if 0 length STREAM has been sent */
|
|
- if (left == 0 && datalen) {
|
|
+ /* We might see more data in the queue, then left < datalen could be
|
|
+ true. We only see the first one for now. */
|
|
+ if ((fr->type == NGTCP2_FRAME_STREAM &&
|
|
+ (left < datalen && left < NGTCP2_MIN_STREAM_DATALEN)) ||
|
|
+ (left == 0 && datalen)) {
|
|
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
|
|
if (rv != 0) {
|
|
assert(ngtcp2_err_is_fatal(rv));
|
|
@@ -412,17 +417,15 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
}
|
|
|
|
if (datalen > left) {
|
|
- ngtcp2_vec_copy(a, fr->data, fr->datacnt);
|
|
- acnt = fr->datacnt;
|
|
-
|
|
- bcnt = 0;
|
|
- ngtcp2_vec_split(b, &bcnt, a, &acnt, left, NGTCP2_MAX_STREAM_DATACNT);
|
|
+ datacnt = 0;
|
|
+ ngtcp2_vec_split(data, &datacnt, fr->data, &fr->datacnt, left,
|
|
+ NGTCP2_MAX_STREAM_DATACNT);
|
|
|
|
- assert(acnt > 0);
|
|
- assert(bcnt > 0);
|
|
+ assert(fr->datacnt > 0);
|
|
+ assert(datacnt > 0);
|
|
|
|
rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
- &nfrc, bcnt, strm->frc_objalloc, strm->mem);
|
|
+ &nfrc, datacnt, strm->frc_objalloc, strm->mem);
|
|
if (rv != 0) {
|
|
assert(ngtcp2_err_is_fatal(rv));
|
|
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
@@ -435,8 +438,8 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
nfr->fin = fr->fin;
|
|
nfr->stream_id = fr->stream_id;
|
|
nfr->offset = fr->offset + left;
|
|
- nfr->datacnt = bcnt;
|
|
- ngtcp2_vec_copy(nfr->data, b, bcnt);
|
|
+ nfr->datacnt = datacnt;
|
|
+ ngtcp2_vec_copy(nfr->data, data, datacnt);
|
|
|
|
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
|
|
if (rv != 0) {
|
|
@@ -447,31 +450,17 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
return rv;
|
|
}
|
|
|
|
- rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
- &nfrc, acnt, strm->frc_objalloc, strm->mem);
|
|
- if (rv != 0) {
|
|
- assert(ngtcp2_err_is_fatal(rv));
|
|
- ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
- return rv;
|
|
- }
|
|
-
|
|
- nfr = &nfrc->fr.stream;
|
|
- *nfr = *fr;
|
|
- nfr->fin = 0;
|
|
- nfr->datacnt = acnt;
|
|
- ngtcp2_vec_copy(nfr->data, a, acnt);
|
|
-
|
|
- ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
+ fr->fin = 0;
|
|
|
|
- *pfrc = nfrc;
|
|
+ *pfrc = frc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
left -= (size_t)datalen;
|
|
|
|
- ngtcp2_vec_copy(a, fr->data, fr->datacnt);
|
|
- acnt = fr->datacnt;
|
|
+ ngtcp2_vec_copy(data, fr->data, fr->datacnt);
|
|
+ datacnt = fr->datacnt;
|
|
|
|
for (; left && ngtcp2_ksl_len(strm->tx.streamfrq);) {
|
|
unacked_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
|
|
@@ -498,9 +487,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
break;
|
|
}
|
|
|
|
- bcnt = nfr->datacnt;
|
|
-
|
|
- nmerged = ngtcp2_vec_merge(a, &acnt, nfr->data, &bcnt, left,
|
|
+ nmerged = ngtcp2_vec_merge(data, &datacnt, nfr->data, &nfr->datacnt, left,
|
|
NGTCP2_MAX_STREAM_DATACNT);
|
|
if (nmerged == 0) {
|
|
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
|
|
@@ -518,54 +505,27 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
datalen += nmerged;
|
|
left -= nmerged;
|
|
|
|
- if (bcnt == 0) {
|
|
+ if (nfr->datacnt == 0) {
|
|
fr->fin = nfr->fin;
|
|
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
|
|
continue;
|
|
}
|
|
|
|
- if (nfr->datacnt <= NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES ||
|
|
- bcnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
|
|
- nfr->offset += nmerged;
|
|
- nfr->datacnt = bcnt;
|
|
-
|
|
- rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
|
|
- if (rv != 0) {
|
|
- ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
|
|
- ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
- return rv;
|
|
- }
|
|
- } else {
|
|
- rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
- &sfrc, bcnt, strm->frc_objalloc, strm->mem);
|
|
- if (rv != 0) {
|
|
- ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
|
|
- ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
- return rv;
|
|
- }
|
|
-
|
|
- sfrc->fr.stream = nfrc->fr.stream;
|
|
- sfrc->fr.stream.offset += nmerged;
|
|
- sfrc->fr.stream.datacnt = bcnt;
|
|
- ngtcp2_vec_copy(sfrc->fr.stream.data, nfrc->fr.stream.data, bcnt);
|
|
+ nfr->offset += nmerged;
|
|
|
|
+ rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
|
|
+ if (rv != 0) {
|
|
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
|
|
-
|
|
- rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &sfrc->fr.stream.offset,
|
|
- sfrc);
|
|
- if (rv != 0) {
|
|
- ngtcp2_frame_chain_objalloc_del(sfrc, strm->frc_objalloc, strm->mem);
|
|
- ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
- return rv;
|
|
- }
|
|
+ ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
+ return rv;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
- if (acnt == fr->datacnt) {
|
|
- if (acnt > 0) {
|
|
- fr->data[acnt - 1] = a[acnt - 1];
|
|
+ if (datacnt == fr->datacnt) {
|
|
+ if (datacnt > 0) {
|
|
+ fr->data[datacnt - 1] = data[datacnt - 1];
|
|
}
|
|
|
|
*pfrc = frc;
|
|
@@ -573,19 +533,23 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
|
|
return 0;
|
|
}
|
|
|
|
- assert(acnt > fr->datacnt);
|
|
+ assert(datacnt > fr->datacnt);
|
|
|
|
rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
|
|
- &nfrc, acnt, strm->frc_objalloc, strm->mem);
|
|
+ &nfrc, datacnt, strm->frc_objalloc, strm->mem);
|
|
if (rv != 0) {
|
|
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
return rv;
|
|
}
|
|
|
|
nfr = &nfrc->fr.stream;
|
|
- *nfr = *fr;
|
|
- nfr->datacnt = acnt;
|
|
- ngtcp2_vec_copy(nfr->data, a, acnt);
|
|
+ nfr->type = fr->type;
|
|
+ nfr->flags = fr->flags;
|
|
+ nfr->fin = fr->fin;
|
|
+ nfr->stream_id = fr->stream_id;
|
|
+ nfr->offset = fr->offset;
|
|
+ nfr->datacnt = datacnt;
|
|
+ ngtcp2_vec_copy(nfr->data, data, datacnt);
|
|
|
|
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
|
|
|
|
@@ -682,12 +646,11 @@ int ngtcp2_strm_is_all_tx_data_fin_acked(const ngtcp2_strm *strm) {
|
|
|
|
ngtcp2_range ngtcp2_strm_get_unacked_range_after(const ngtcp2_strm *strm,
|
|
uint64_t offset) {
|
|
- ngtcp2_range gap;
|
|
-
|
|
if (strm->tx.acked_offset == NULL) {
|
|
- gap.begin = strm->tx.cont_acked_offset;
|
|
- gap.end = UINT64_MAX;
|
|
- return gap;
|
|
+ return (ngtcp2_range){
|
|
+ .begin = strm->tx.cont_acked_offset,
|
|
+ .end = UINT64_MAX,
|
|
+ };
|
|
}
|
|
|
|
return ngtcp2_gaptr_get_first_gap_after(strm->tx.acked_offset, offset);
|
|
@@ -737,7 +700,16 @@ int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) {
|
|
}
|
|
}
|
|
|
|
- return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
|
|
+ rv = ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
|
|
+ if (rv != 0) {
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 4000) {
|
|
+ return NGTCP2_ERR_INTERNAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm,
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_strm.h b/third_party/ngtcp2/lib/ngtcp2_strm.h
|
|
index c72f8b9dc89..0d5d8a63a62 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_strm.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_strm.h
|
|
@@ -41,54 +41,54 @@
|
|
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
|
|
|
|
/* NGTCP2_STRM_FLAG_NONE indicates that no flag is set. */
|
|
-#define NGTCP2_STRM_FLAG_NONE 0x00u
|
|
+#define NGTCP2_STRM_FLAG_NONE 0x00U
|
|
/* NGTCP2_STRM_FLAG_SHUT_RD indicates that further reception of stream
|
|
data is not allowed. */
|
|
-#define NGTCP2_STRM_FLAG_SHUT_RD 0x01u
|
|
+#define NGTCP2_STRM_FLAG_SHUT_RD 0x01U
|
|
/* NGTCP2_STRM_FLAG_SHUT_WR indicates that further transmission of
|
|
stream data is not allowed. */
|
|
-#define NGTCP2_STRM_FLAG_SHUT_WR 0x02u
|
|
+#define NGTCP2_STRM_FLAG_SHUT_WR 0x02U
|
|
#define NGTCP2_STRM_FLAG_SHUT_RDWR \
|
|
(NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_SHUT_WR)
|
|
/* NGTCP2_STRM_FLAG_RESET_STREAM indicates that RESET_STREAM is sent
|
|
from the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is
|
|
also set. */
|
|
-#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04u
|
|
+#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04U
|
|
/* NGTCP2_STRM_FLAG_RESET_STREAM_RECVED indicates that RESET_STREAM is
|
|
received from the remote endpoint. In this case,
|
|
NGTCP2_STRM_FLAG_SHUT_RD is also set. */
|
|
-#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08u
|
|
+#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08U
|
|
/* NGTCP2_STRM_FLAG_STOP_SENDING indicates that STOP_SENDING is sent
|
|
from the local endpoint. */
|
|
-#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10u
|
|
+#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10U
|
|
/* NGTCP2_STRM_FLAG_RESET_STREAM_ACKED indicates that the outgoing
|
|
RESET_STREAM is acknowledged by peer. */
|
|
-#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20u
|
|
+#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20U
|
|
/* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit set
|
|
is acknowledged by a remote endpoint. */
|
|
-#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40u
|
|
+#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40U
|
|
/* NGTCP2_STRM_FLAG_ANY_ACKED indicates that any portion of stream
|
|
data, including 0 length segment, is acknowledged. */
|
|
-#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80u
|
|
+#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80U
|
|
/* NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET indicates that app_error_code
|
|
field is set. This resolves the ambiguity that the initial
|
|
app_error_code value 0 might be a proper application error code.
|
|
In this case, without this flag, we are unable to distinguish
|
|
assigned value from unassigned one. */
|
|
-#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100u
|
|
+#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100U
|
|
/* NGTCP2_STRM_FLAG_SEND_STOP_SENDING is set when STOP_SENDING frame
|
|
should be sent. */
|
|
-#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200u
|
|
+#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200U
|
|
/* NGTCP2_STRM_FLAG_SEND_RESET_STREAM is set when RESET_STREAM frame
|
|
should be sent. */
|
|
-#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400u
|
|
+#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400U
|
|
/* NGTCP2_STRM_FLAG_STOP_SENDING_RECVED indicates that STOP_SENDING is
|
|
received from the remote endpoint. In this case,
|
|
NGTCP2_STRM_FLAG_SHUT_WR is also set. */
|
|
-#define NGTCP2_STRM_FLAG_STOP_SENDING_RECVED 0x800u
|
|
+#define NGTCP2_STRM_FLAG_STOP_SENDING_RECVED 0x800U
|
|
/* NGTCP2_STRM_FLAG_ANY_SENT indicates that any STREAM frame,
|
|
including empty one, has been sent. */
|
|
-#define NGTCP2_STRM_FLAG_ANY_SENT 0x1000u
|
|
+#define NGTCP2_STRM_FLAG_ANY_SENT 0x1000U
|
|
|
|
typedef struct ngtcp2_strm ngtcp2_strm;
|
|
|
|
@@ -171,14 +171,14 @@ struct ngtcp2_strm {
|
|
const ngtcp2_mem *mem;
|
|
int64_t stream_id;
|
|
void *stream_user_data;
|
|
- /* flags is bit-wise OR of zero or more of NGTCP2_STRM_FLAG_*. */
|
|
- uint32_t flags;
|
|
/* app_error_code is an error code the local endpoint sent in
|
|
RESET_STREAM or STOP_SENDING, or received from a remote endpoint
|
|
in RESET_STREAM or STOP_SENDING. First application error code is
|
|
chosen and when set, NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET flag is
|
|
set in flags field. */
|
|
uint64_t app_error_code;
|
|
+ /* flags is bit-wise OR of zero or more of NGTCP2_STRM_FLAG_*. */
|
|
+ uint32_t flags;
|
|
};
|
|
|
|
ngtcp2_opl_entry oplent;
|
|
@@ -208,14 +208,14 @@ uint64_t ngtcp2_strm_rx_offset(const ngtcp2_strm *strm);
|
|
/*
|
|
* ngtcp2_strm_recv_reordering handles reordered data.
|
|
*
|
|
- * It returns 0 if it succeeds, or one of the following negative error
|
|
- * codes:
|
|
+ * It returns the number of bytes newly buffered if it succeeds, or
|
|
+ * one of the following negative error codes:
|
|
*
|
|
* NGTCP2_ERR_NOMEM
|
|
* Out of memory
|
|
*/
|
|
-int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
|
|
- size_t datalen, uint64_t offset);
|
|
+ngtcp2_ssize ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
|
|
+ size_t datalen, uint64_t offset);
|
|
|
|
/*
|
|
* ngtcp2_strm_update_rx_offset tells that data up to |offset| bytes
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_transport_params.c b/third_party/ngtcp2/lib/ngtcp2_transport_params.c
|
|
index ca517532e3a..5d378176e16 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_transport_params.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_transport_params.c
|
|
@@ -150,8 +150,8 @@ ngtcp2_ssize ngtcp2_transport_params_encode_versioned(
|
|
|
|
if (params->stateless_reset_token_present) {
|
|
len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) +
|
|
- ngtcp2_put_uvarintlen(NGTCP2_STATELESS_RESET_TOKENLEN) +
|
|
- NGTCP2_STATELESS_RESET_TOKENLEN;
|
|
+ ngtcp2_put_uvarintlen(sizeof(params->stateless_reset_token)) +
|
|
+ sizeof(params->stateless_reset_token);
|
|
}
|
|
|
|
if (params->preferred_addr_present) {
|
|
@@ -160,7 +160,7 @@ ngtcp2_ssize ngtcp2_transport_params_encode_versioned(
|
|
preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ +
|
|
16 /* ipv6Address */ + 2 /* ipv6Port */
|
|
+ 1 + params->preferred_addr.cid.datalen /* CID */ +
|
|
- NGTCP2_STATELESS_RESET_TOKENLEN;
|
|
+ sizeof(params->preferred_addr.stateless_reset_token);
|
|
len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) +
|
|
ngtcp2_put_uvarintlen(preferred_addrlen) + preferred_addrlen;
|
|
}
|
|
@@ -523,12 +523,12 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version,
|
|
}
|
|
|
|
/* Set default values */
|
|
- memset(params, 0, sizeof(*params));
|
|
- params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
|
|
- params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
|
|
- params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
|
|
- params->active_connection_id_limit =
|
|
- NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
|
|
+ *params = (ngtcp2_transport_params){
|
|
+ .max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE,
|
|
+ .ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT,
|
|
+ .max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY,
|
|
+ .active_connection_id_limit = NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT,
|
|
+ };
|
|
|
|
p = end = data;
|
|
|
|
@@ -626,7 +626,8 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version,
|
|
}
|
|
len = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ +
|
|
2 /* ipv6Port */
|
|
- + 1 /* cid length */ + NGTCP2_STATELESS_RESET_TOKENLEN;
|
|
+ + 1 /* cid length */ +
|
|
+ sizeof(params->preferred_addr.stateless_reset_token);
|
|
if (valuelen < len) {
|
|
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
|
}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_transport_params.h b/third_party/ngtcp2/lib/ngtcp2_transport_params.h
|
|
index c077f06a9dd..d98d034b3c2 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_transport_params.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_transport_params.h
|
|
@@ -45,16 +45,16 @@ typedef uint64_t ngtcp2_transport_param_id;
|
|
#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI 0x07
|
|
#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI 0x08
|
|
#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI 0x09
|
|
-#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0a
|
|
-#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0b
|
|
-#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0c
|
|
-#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0d
|
|
-#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0e
|
|
-#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0f
|
|
+#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0A
|
|
+#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0B
|
|
+#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0C
|
|
+#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0D
|
|
+#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0E
|
|
+#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0F
|
|
#define NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID 0x10
|
|
/* https://datatracker.ietf.org/doc/html/rfc9221 */
|
|
#define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20
|
|
-#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2ab2
|
|
+#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2AB2
|
|
/* https://datatracker.ietf.org/doc/html/rfc9368 */
|
|
#define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11
|
|
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_vec.c b/third_party/ngtcp2/lib/ngtcp2_vec.c
|
|
index dbca8691d64..f94c6218d53 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_vec.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_vec.c
|
|
@@ -30,8 +30,11 @@
|
|
#include "ngtcp2_str.h"
|
|
|
|
ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len) {
|
|
- vec->base = (uint8_t *)base;
|
|
- vec->len = len;
|
|
+ *vec = (ngtcp2_vec){
|
|
+ .base = (uint8_t *)base,
|
|
+ .len = len,
|
|
+ };
|
|
+
|
|
return vec;
|
|
}
|
|
|
|
@@ -102,8 +105,7 @@ ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src,
|
|
memcpy(dst, src + i, sizeof(ngtcp2_vec) * nmove);
|
|
}
|
|
|
|
- dst[0].len -= left;
|
|
- dst[0].base += left;
|
|
+ ngtcp2_vec_drop(&dst[0], left);
|
|
src[i].len = left;
|
|
|
|
if (nmove == 0) {
|
|
@@ -136,8 +138,7 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src,
|
|
a->len = left;
|
|
a->base = b->base;
|
|
|
|
- b->len -= left;
|
|
- b->base += left;
|
|
+ ngtcp2_vec_drop(b, left);
|
|
|
|
return left;
|
|
}
|
|
@@ -158,13 +159,14 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src,
|
|
} else if (*pdstcnt == maxcnt) {
|
|
break;
|
|
} else {
|
|
- dst[*pdstcnt].len = left;
|
|
- dst[*pdstcnt].base = b->base;
|
|
+ dst[*pdstcnt] = (ngtcp2_vec){
|
|
+ .base = b->base,
|
|
+ .len = left,
|
|
+ };
|
|
++*pdstcnt;
|
|
}
|
|
|
|
- b->len -= left;
|
|
- b->base += left;
|
|
+ ngtcp2_vec_drop(b, left);
|
|
left = 0;
|
|
|
|
break;
|
|
@@ -199,8 +201,10 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
|
|
}
|
|
|
|
if (src[i].len > left) {
|
|
- dst[j].base = src[i].base;
|
|
- dst[j].len = left;
|
|
+ dst[j] = (ngtcp2_vec){
|
|
+ .base = src[i].base,
|
|
+ .len = left,
|
|
+ };
|
|
|
|
return j + 1;
|
|
}
|
|
@@ -217,3 +221,14 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
|
|
void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt) {
|
|
memcpy(dst, src, sizeof(ngtcp2_vec) * cnt);
|
|
}
|
|
+
|
|
+void ngtcp2_vec_split_at(ngtcp2_vec *dst, ngtcp2_vec *src, size_t offset) {
|
|
+ assert(offset < src->len);
|
|
+
|
|
+ *dst = (ngtcp2_vec){
|
|
+ .base = src->base + offset,
|
|
+ .len = src->len - offset,
|
|
+ };
|
|
+
|
|
+ src->len = offset;
|
|
+}
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_vec.h b/third_party/ngtcp2/lib/ngtcp2_vec.h
|
|
index 55e735d164e..fe6a47a029a 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_vec.h
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_vec.h
|
|
@@ -33,13 +33,6 @@
|
|
|
|
#include "ngtcp2_mem.h"
|
|
|
|
-/*
|
|
- * ngtcp2_vec_lit is a convenient macro to fill the object pointed by
|
|
- * |DEST| with the literal string |LIT|.
|
|
- */
|
|
-#define ngtcp2_vec_lit(DEST, LIT) \
|
|
- ((DEST)->base = (uint8_t *)(LIT), (DEST)->len = sizeof(LIT) - 1, (DEST))
|
|
-
|
|
/*
|
|
* ngtcp2_vec_init initializes |vec| with the given parameters. It
|
|
* returns |vec|.
|
|
@@ -103,4 +96,28 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
|
|
*/
|
|
void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt);
|
|
|
|
+/*
|
|
+ * ngtcp2_vec_split_at splits |src| at the |offset|. Caller must
|
|
+ * ensure that offset < src->len. This function assigns the right
|
|
+ * part of vector into |dst|.
|
|
+ */
|
|
+void ngtcp2_vec_split_at(ngtcp2_vec *dst, ngtcp2_vec *src, size_t offset);
|
|
+
|
|
+/*
|
|
+ * ngtcp2_vec_end returns the one beyond the last offset of |v|.
|
|
+ */
|
|
+static inline uint8_t *ngtcp2_vec_end(const ngtcp2_vec *v) {
|
|
+ return v->base + v->len;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * ngtcp2_vec_drop removes the first |n| bytes from |v| by adjusting
|
|
+ * its base and len fields. This function assumes |v|->len > 0 &&
|
|
+ * |v|->len >= n.
|
|
+ */
|
|
+static inline void ngtcp2_vec_drop(ngtcp2_vec *v, size_t n) {
|
|
+ v->base += n;
|
|
+ v->len -= n;
|
|
+}
|
|
+
|
|
#endif /* !defined(NGTCP2_VEC_H) */
|
|
diff --git a/third_party/ngtcp2/lib/ngtcp2_window_filter.c b/third_party/ngtcp2/lib/ngtcp2_window_filter.c
|
|
index 39f3d408a74..707cd570799 100644
|
|
--- a/third_party/ngtcp2/lib/ngtcp2_window_filter.c
|
|
+++ b/third_party/ngtcp2/lib/ngtcp2_window_filter.c
|
|
@@ -39,7 +39,7 @@
|
|
void ngtcp2_window_filter_init(ngtcp2_window_filter *wf,
|
|
uint64_t window_length) {
|
|
wf->window_length = window_length;
|
|
- memset(wf->estimates, 0xff, sizeof(wf->estimates));
|
|
+ memset(wf->estimates, 0xFF, sizeof(wf->estimates));
|
|
}
|
|
|
|
void ngtcp2_window_filter_update(ngtcp2_window_filter *wf, uint64_t new_sample,
|
|
diff --git a/third_party/ngtcp2/wscript b/third_party/ngtcp2/wscript
|
|
index f4cfd1c7064..399790c50c1 100644
|
|
--- a/third_party/ngtcp2/wscript
|
|
+++ b/third_party/ngtcp2/wscript
|
|
@@ -72,9 +72,11 @@ def build(bld):
|
|
lib/ngtcp2_balloc.c
|
|
lib/ngtcp2_bbr.c
|
|
lib/ngtcp2_buf.c
|
|
+ lib/ngtcp2_callbacks.c
|
|
lib/ngtcp2_cc.c
|
|
lib/ngtcp2_cid.c
|
|
lib/ngtcp2_conn.c
|
|
+ lib/ngtcp2_conn_info.c
|
|
lib/ngtcp2_conv.c
|
|
lib/ngtcp2_crypto.c
|
|
lib/ngtcp2_dcidtr.c
|
|
@@ -89,6 +91,7 @@ def build(bld):
|
|
lib/ngtcp2_objalloc.c
|
|
lib/ngtcp2_opl.c
|
|
lib/ngtcp2_path.c
|
|
+ lib/ngtcp2_pcg.c
|
|
lib/ngtcp2_pkt.c
|
|
lib/ngtcp2_pmtud.c
|
|
lib/ngtcp2_ppe.c
|
|
@@ -96,6 +99,7 @@ def build(bld):
|
|
lib/ngtcp2_pv.c
|
|
lib/ngtcp2_qlog.c
|
|
lib/ngtcp2_range.c
|
|
+ lib/ngtcp2_ratelim.c
|
|
lib/ngtcp2_ringbuf.c
|
|
lib/ngtcp2_rob.c
|
|
lib/ngtcp2_rst.c
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From c42695f12eea3b3d113114e535be0de950333278 Mon Sep 17 00:00:00 2001
|
|
From: Andreas Schneider <asn@samba.org>
|
|
Date: Tue, 24 Mar 2026 15:00:21 +0100
|
|
Subject: [PATCH 66/66] wafsamba: Add -D_FORTIFY_SOURCE=3 when stack protector
|
|
is enabled
|
|
|
|
The capability check in SAMBA_CONFIG_H() already tests that the compiler
|
|
accepts both -Wp,-D_FORTIFY_SOURCE and the stack protector flag
|
|
together, but only the stack protector flag was added to EXTRA_CFLAGS on
|
|
success.
|
|
|
|
The glibc normally silently downgrades to the supported level if the on
|
|
specified is not supported.
|
|
|
|
Note that -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 only sets it if not
|
|
already defined.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16040
|
|
|
|
Signed-off-by: Andreas Schneider <asn@samba.org>
|
|
Reviewed-by: Anoop C S <anoopcs@samba.org>
|
|
|
|
Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
|
|
Autobuild-Date(master): Fri Mar 27 08:33:09 UTC 2026 on atb-devel-224
|
|
|
|
(cherry picked from commit 333ac047c3fc151222e5ee6aaa75452276b0031e)
|
|
---
|
|
buildtools/wafsamba/samba_autoconf.py | 7 ++++++-
|
|
script/autobuild.py | 6 ------
|
|
2 files changed, 6 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
|
|
index b777391a038..979d5a3972f 100644
|
|
--- a/buildtools/wafsamba/samba_autoconf.py
|
|
+++ b/buildtools/wafsamba/samba_autoconf.py
|
|
@@ -733,11 +733,16 @@ def SAMBA_CONFIG_H(conf, path=None):
|
|
}
|
|
''',
|
|
execute=0,
|
|
- cflags=[ '-Werror', '-Wp,-D_FORTIFY_SOURCE=2', stack_protect_flag],
|
|
+ cflags=[
|
|
+ '-Werror',
|
|
+ '-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3',
|
|
+ stack_protect_flag
|
|
+ ],
|
|
mandatory=False,
|
|
msg='Checking if compiler accepts %s' % (stack_protect_flag))
|
|
if flag_supported:
|
|
conf.ADD_CFLAGS('%s' % (stack_protect_flag))
|
|
+ conf.ADD_CFLAGS('-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3')
|
|
break
|
|
|
|
flag_supported = conf.check(fragment='''
|
|
diff --git a/script/autobuild.py b/script/autobuild.py
|
|
index 97d44a07ee4..1324c9b8c2e 100755
|
|
--- a/script/autobuild.py
|
|
+++ b/script/autobuild.py
|
|
@@ -206,13 +206,7 @@ try:
|
|
except ImportError:
|
|
pass
|
|
|
|
-# on ubuntu gcc implies _FORTIFY_SOURCE
|
|
-# before 24.04 it was _FORTIFY_SOURCE=2
|
|
-# and 24.04 has _FORTIFY_SOURCE=3
|
|
-# so we do not specify it explicitly.
|
|
samba_o3_cflags = "-O3"
|
|
-if not is_ubuntu:
|
|
- samba_o3_cflags += " -Wp,-D_FORTIFY_SOURCE=2"
|
|
|
|
def format_option(name, value=None):
|
|
"""Format option as str list."""
|
|
--
|
|
2.53.0
|
|
|