diff --git a/UnitTest1/unittest1.cpp b/UnitTest1/unittest1.cpp index 3bc25927f1811df56f362b51f27b2250ab235918..d89c0dd94cd63df80763cb31227867914d6a9401 100644 --- a/UnitTest1/unittest1.cpp +++ b/UnitTest1/unittest1.cpp @@ -181,6 +181,13 @@ namespace UnitTest1 { int ret = pn_enc_1rtt_test(); + Assert::AreEqual(ret, 0); + } + + TEST_METHOD(test_cnxid_stash) + { + int ret = cnxid_stash_test(); + Assert::AreEqual(ret, 0); } diff --git a/picoquic.sln b/picoquic.sln index 9c4f021e8b21ec0538bf5199c81760635bd288ed..75056e50167343d932d1c363ad296c9c5b74220a 100644 --- a/picoquic.sln +++ b/picoquic.sln @@ -25,9 +25,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "picoquic_t", "picoquic_t\pi EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A71B5718-FDFC-4047-A76C-15EA7A78ED6B}" - ProjectSection(SolutionItems) = preProject - picoquic\picosocks.c = picoquic\picosocks.c - EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -81,4 +78,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9046935D-F459-4ADB-850E-C60A378EB224} + EndGlobalSection EndGlobal diff --git a/picoquic/frames.c b/picoquic/frames.c index ce4b22803b8fc7f564d974b5e9a5efff1a3e871f..f23f9a29fa40e1335bc8eb36371764b21610e279 100644 --- a/picoquic/frames.c +++ b/picoquic/frames.c @@ -403,7 +403,6 @@ uint8_t* picoquic_skip_connection_id_frame(uint8_t* bytes, const uint8_t* bytes_ return bytes; } - uint8_t* picoquic_decode_connection_id_frame(picoquic_cnx_t* cnx, uint8_t* bytes, const uint8_t* bytes_max) { /* store the connection ID in order to support migration. */ diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c index c34ed6f527bbda1832dc6ecd896d67439cba0435..633253cb3488a3c2af5ed47a5b8fb5c8754e312f 100644 --- a/picoquic/quicctx.c +++ b/picoquic/quicctx.c @@ -719,12 +719,16 @@ picoquic_cnxid_stash_t * picoquic_enqueue_cnxid_stash(picoquic_cnx_t * cnx, (void)picoquic_parse_connection_id(cnxid_bytes, cid_length, &stashed->cnx_id); stashed->sequence = sequence; memcpy(stashed->reset_secret, secret_bytes, PICOQUIC_RESET_SECRET_SIZE); - stashed->next_in_stash = cnx->cnxid_stash_last; - cnx->cnxid_stash_last = stashed; + stashed->next_in_stash = NULL; - if (cnx->cnxid_stash_first == NULL) { - cnx->cnxid_stash_last = stashed; + if (cnx->cnxid_stash_last == NULL) { + cnx->cnxid_stash_first = stashed; + } + else { + cnx->cnxid_stash_last->next_in_stash = stashed; } + + cnx->cnxid_stash_last = stashed; } return stashed; } diff --git a/picoquic_t/picoquic_t.c b/picoquic_t/picoquic_t.c index 31023ee8d3f112611f3a2a6a165ba7368751f5e6..032c257f6a595703453f167b5af4781d9b1802ee 100644 --- a/picoquic_t/picoquic_t.c +++ b/picoquic_t/picoquic_t.c @@ -65,6 +65,7 @@ static const picoquic_test_def_t test_table[] = { { "cleartext_pn_enc", cleartext_pn_enc_test }, { "draft13_vector", draft13_vector_test }, { "pn_enc_1rtt", pn_enc_1rtt_test }, + { "cnxid_stash", cnxid_stash_test }, { "tls_api", tls_api_test }, { "silence_test", tls_api_silence_test }, { "tls_api_version_negotiation", tls_api_version_negotiation_test }, diff --git a/picoquictest/picoquictest.h b/picoquictest/picoquictest.h index 4e5774fa4595442847bd8182b52126c2ed22ae0c..b22b6170876a842fef26b62768fa6736f7edf50d 100644 --- a/picoquictest/picoquictest.h +++ b/picoquictest/picoquictest.h @@ -121,6 +121,7 @@ int TlsStreamFrameTest(); int draft13_vector_test(); int fuzz_test(); int random_tester_test(); +int cnxid_stash_test(); #ifdef __cplusplus } diff --git a/picoquictest/skip_frame_test.c b/picoquictest/skip_frame_test.c index ac28353087fb0d810fb5a71ba5e6799b79c511f9..2e5e108750e38fe6b8206c444cf7e41b819a4232 100644 --- a/picoquictest/skip_frame_test.c +++ b/picoquictest/skip_frame_test.c @@ -649,3 +649,112 @@ int logger_test() return ret; } + + +/* Basic test of connection ID stash, part of migration support */ +static const picoquic_cnxid_stash_t stash_test_case[] = { + { NULL, 1,{ { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4 }, +{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } }, +{ NULL, 2,{ { 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4 }, +{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } }, +{ NULL, 3,{ { 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4 }, +{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 } } +}; + +static const size_t nb_stash_test_case = sizeof(stash_test_case) / sizeof(picoquic_cnxid_stash_t); + +static int cnxid_stash_compare(int test_mode, picoquic_cnxid_stash_t * stashed, size_t i) +{ + int ret = 0; + + if (stashed == NULL) { + DBG_PRINTF("Test %d, cannot dequeue cnxid %d.\n", test_mode, i); + ret = -1; + } + else if (stashed->sequence != stash_test_case[i].sequence) { + DBG_PRINTF("Test %d, cnxid %d, sequence %d instead of %d.\n", test_mode, i, + stashed->sequence, stash_test_case[i].sequence); + ret = -1; + } + else if (picoquic_compare_connection_id(&stashed->cnx_id, &stash_test_case[i].cnx_id) != 0) { + DBG_PRINTF("Test %d, cnxid %d, CNXID values do not match.\n", test_mode, i); + ret = -1; + } + else if (memcmp(&stashed->reset_secret, &stash_test_case[i].reset_secret, PICOQUIC_RESET_SECRET_SIZE) != 0) { + DBG_PRINTF("Test %d, cnxid %d, secrets do not match.\n", test_mode, i); + ret = -1; + } + + return ret; +} + +int cnxid_stash_test() +{ + int ret = 0; + uint64_t simulated_time = 0; + struct sockaddr_in saddr; + picoquic_quic_t * qclient = picoquic_create(8, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, simulated_time, + &simulated_time, NULL, NULL, 0); + + + memset(&saddr, 0, sizeof(struct sockaddr_in)); + if (qclient == NULL) { + DBG_PRINTF("%s", "Cannot create QUIC context\n"); + ret = -1; + } + + /* First test: enqueue and dequeue immediately */ + /* Second test: enqueue all and then dequeue - verify order */ + /* Third test: enqueue all and then delete the connection */ + for (int test_mode = 0; ret == 0 && test_mode < 3; test_mode++) { + picoquic_cnx_t * cnx = picoquic_create_cnx(qclient, + picoquic_null_connection_id, picoquic_null_connection_id, (struct sockaddr *) &saddr, + simulated_time, 0, "test-sni", "test-alpn", 1); + picoquic_cnxid_stash_t * stashed = NULL; + + if (cnx == NULL) { + DBG_PRINTF("%s", "Cannot create QUIC CNX context\n"); + ret = -1; + } + + for (size_t i = 0; ret == 0 && i < nb_stash_test_case; i++) { + stashed = picoquic_enqueue_cnxid_stash(cnx, + stash_test_case[i].sequence, stash_test_case[i].cnx_id.id_len, + stash_test_case[i].cnx_id.id, stash_test_case[i].reset_secret); + if (stashed == NULL) { + DBG_PRINTF("Test %d, cannot stash cnxid %d.\n", test_mode, i); + ret = -1; + } else if (test_mode == 0) { + stashed = picoquic_dequeue_cnxid_stash(cnx); + ret = cnxid_stash_compare(test_mode, stashed, i); + } + } + + /* Dequeue all in mode 1, verify order */ + if (test_mode == 1) { + for (size_t i = 0; ret == 0 && i < nb_stash_test_case; i++) { + stashed = picoquic_dequeue_cnxid_stash(cnx); + ret = cnxid_stash_compare(test_mode, stashed, i); + } + } + + /* Verify nothing left in queue in mode 0, 1 */ + if (test_mode < 2) { + stashed = picoquic_dequeue_cnxid_stash(cnx); + if (stashed != NULL) { + DBG_PRINTF("Test %d, unexpected cnxid left, #%d.\n", test_mode, (int)stashed->sequence); + ret = -1; + } + } + + /* Delete the connecton and free the stash */ + picoquic_delete_cnx(cnx); + } + + if (qclient != NULL) { + picoquic_free(qclient); + } + + return ret; +} \ No newline at end of file diff --git a/picoquictest/tls_api_test.c b/picoquictest/tls_api_test.c index 7c7f754c7b5f5eefebe988e1706233242e6c48fd..5faae37f201d97e2dcaf4c7f94ffa68ca4b376b4 100644 --- a/picoquictest/tls_api_test.c +++ b/picoquictest/tls_api_test.c @@ -3427,4 +3427,4 @@ int client_error_test() } return ret; -} +} \ No newline at end of file