From 1cc713226169c90181af1dc2073739093228fa3a Mon Sep 17 00:00:00 2001
From: huitema <huitema@huitema.net>
Date: Thu, 4 Oct 2018 19:02:51 -0700
Subject: [PATCH] server receives connection close in initial

---
 UnitTest1/unittest1.cpp     |  8 ++++-
 picoquic/frames.c           |  3 +-
 picoquic_t/picoquic_t.c     |  1 +
 picoquictest/picoquictest.h |  1 +
 picoquictest/tls_api_test.c | 60 ++++++++++++++++++++++++++++++++++---
 5 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/UnitTest1/unittest1.cpp b/UnitTest1/unittest1.cpp
index 23ff7c84..e791b5e4 100644
--- a/UnitTest1/unittest1.cpp
+++ b/UnitTest1/unittest1.cpp
@@ -673,13 +673,19 @@ namespace UnitTest1
             Assert::AreEqual(ret, 0);
         }
 
-
         TEST_METHOD(test_server_busy)
         {
             int ret = server_busy_test();
 
             Assert::AreEqual(ret, 0);
         }
+
+        TEST_METHOD(test_initial_close)
+        {
+            int ret = initial_close_test();
+
+            Assert::AreEqual(ret, 0);
+        }
         
         TEST_METHOD(stress)
         {
diff --git a/picoquic/frames.c b/picoquic/frames.c
index 6dbecdf3..4e40f8cb 100644
--- a/picoquic/frames.c
+++ b/picoquic/frames.c
@@ -2046,7 +2046,8 @@ uint8_t* picoquic_decode_connection_close_frame(picoquic_cnx_t* cnx, uint8_t* by
         picoquic_connection_error(cnx, PICOQUIC_TRANSPORT_FRAME_FORMAT_ERROR, 
             picoquic_frame_type_connection_close);
     } else {
-        cnx->cnx_state = (cnx->cnx_state < picoquic_state_client_ready) ? picoquic_state_disconnected : picoquic_state_closing_received;
+        cnx->cnx_state = (cnx->cnx_state < picoquic_state_client_ready || cnx->crypto_context[3].aead_decrypt == NULL) ? picoquic_state_disconnected : picoquic_state_closing_received;
+
         if (cnx->callback_fn) {
             (cnx->callback_fn)(cnx, 0, NULL, 0, picoquic_callback_close, cnx->callback_ctx);
         }
diff --git a/picoquic_t/picoquic_t.c b/picoquic_t/picoquic_t.c
index c618ff80..af0a543d 100644
--- a/picoquic_t/picoquic_t.c
+++ b/picoquic_t/picoquic_t.c
@@ -137,6 +137,7 @@ static const picoquic_test_def_t test_table[] = {
     { "cnxid_renewal",  cnxid_renewal_test },
     { "retire_cnxid", retire_cnxid_test },
     { "server_busy", server_busy_test },
+    { "initial_close", initial_close_test },
     { "stress", stress_test },
     { "fuzz", fuzz_test }
 };
diff --git a/picoquictest/picoquictest.h b/picoquictest/picoquictest.h
index 2ef2f49c..26bfbd28 100644
--- a/picoquictest/picoquictest.h
+++ b/picoquictest/picoquictest.h
@@ -134,6 +134,7 @@ int migration_test_loss();
 int cnxid_renewal_test();
 int retire_cnxid_test();
 int server_busy_test();
+int initial_close_test();
 
 #ifdef __cplusplus
 }
diff --git a/picoquictest/tls_api_test.c b/picoquictest/tls_api_test.c
index 97987fb1..7c516c0e 100644
--- a/picoquictest/tls_api_test.c
+++ b/picoquictest/tls_api_test.c
@@ -4167,15 +4167,12 @@ int server_busy_test()
 {
     uint64_t loss_mask = 0;
     uint64_t simulated_time = 0;
-    uint64_t next_time = 0;
     picoquic_test_tls_api_ctx_t* test_ctx = NULL;
     int ret = tls_api_init_ctx(&test_ctx, 0, PICOQUIC_TEST_SNI, PICOQUIC_TEST_ALPN, &simulated_time, NULL, 0, 0, 0);
 
     if (ret == 0) {
-        int c_ret;
-
         test_ctx->qserver->flags |= picoquic_context_server_busy;
-        c_ret = tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time);
+        (void) tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time);
 
         if (test_ctx->cnx_server != NULL &&
             test_ctx->cnx_server->cnx_state != picoquic_state_disconnected) {
@@ -4231,5 +4228,60 @@ int server_busy_test()
         test_ctx = NULL;
     }
 
+    return ret;
+}
+
+/*
+ * Initial close test. Check what happens when the client closes a connection without waiting for the full establishment
+ */
+
+int initial_close_test()
+{
+    uint64_t loss_mask = 0;
+    uint64_t simulated_time = 0;
+    int was_active = 0;
+    picoquic_test_tls_api_ctx_t* test_ctx = NULL;
+    int ret = tls_api_init_ctx(&test_ctx, 0, PICOQUIC_TEST_SNI, PICOQUIC_TEST_ALPN, &simulated_time, NULL, 0, 0, 0);
+
+    if (ret == 0) {
+        /* Send the initial packet, but no more than that */
+        ret = tls_api_one_sim_round(test_ctx, &simulated_time, 0, &was_active);
+
+        if (ret == 0) {
+            test_ctx->cnx_client->cnx_state = picoquic_state_handshake_failure;
+            test_ctx->cnx_client->local_error = 0xDEAD;
+            picoquic_cnx_set_next_wake_time(test_ctx->cnx_client, simulated_time);
+        }
+    }
+
+    if (ret == 0) {
+        for (int i = 0; i < 128; i++) {
+            ret = tls_api_one_sim_round(test_ctx, &simulated_time, 0, &was_active);
+            if (test_ctx->cnx_server != NULL) {
+                break;
+            }
+        }
+        ret = tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time);
+
+        if (test_ctx->cnx_server != NULL &&
+            test_ctx->cnx_server->cnx_state != picoquic_state_disconnected) {
+            DBG_PRINTF("Server state: %d, remote error: %x\n", test_ctx->cnx_server->cnx_state, test_ctx->cnx_server->remote_error);
+            ret = -1;
+        }
+        else if (test_ctx->cnx_client->cnx_state != picoquic_state_disconnected) {
+            DBG_PRINTF("Client state: %d, local error: %x", test_ctx->cnx_client->cnx_state, test_ctx->cnx_client->local_error);
+            ret = -1;
+        }
+        else if (simulated_time > 50000ull) {
+            DBG_PRINTF("Simulated time: %llu", (unsigned long long)simulated_time);
+            ret = -1;
+        }
+    }
+
+    if (test_ctx != NULL) {
+        tls_api_delete_ctx(test_ctx);
+        test_ctx = NULL;
+    }
+
     return ret;
 }
\ No newline at end of file
-- 
GitLab