]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add a test using the bandwidth limit filter
authorTomas Mraz <tomas@openssl.org>
Wed, 14 Feb 2024 11:45:15 +0000 (12:45 +0100)
committerTomas Mraz <tomas@openssl.org>
Fri, 15 Mar 2024 09:19:19 +0000 (10:19 +0100)
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23588)

test/helpers/quictestlib.c
test/helpers/quictestlib.h
test/quicapitest.c

index 403e1f4384cf5bfa949b656480b203b5610eb98e..0454e332cf3e701cf92bac1fd709f5ee5a950285 100644 (file)
@@ -80,6 +80,7 @@ static void qtest_reset_time(void);
 static int using_fake_time = 0;
 static OSSL_TIME fake_now;
 static CRYPTO_RWLOCK *fake_now_lock = NULL;
+static OSSL_TIME start_time;
 
 static OSSL_TIME fake_now_cb(void *arg)
 {
@@ -220,6 +221,7 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
 
     if ((flags & QTEST_FLAG_NOISE) != 0) {
         BIO *noisebio;
+        struct bio_noise_now_cb_st now_cb = { fake_now_cb, NULL };
 
         /*
          * It is an error to not have a QTEST_FAULT object when introducing noise
@@ -232,12 +234,22 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
         if (!TEST_ptr(noisebio))
             goto err;
         cbio = BIO_push(noisebio, cbio);
+        if ((flags & QTEST_FLAG_FAKE_TIME) != 0) {
+            if (!TEST_int_eq(BIO_ctrl(cbio, BIO_CTRL_NOISE_SET_NOW_CB,
+                                      0, &now_cb), 1))
+                goto err;
+        }
 
         noisebio = BIO_new(bio_f_noisy_dgram_filter());
 
         if (!TEST_ptr(noisebio))
             goto err;
         sbio = BIO_push(noisebio, sbio);
+        if ((flags & QTEST_FLAG_FAKE_TIME) != 0) {
+            if (!TEST_int_eq(BIO_ctrl(sbio, BIO_CTRL_NOISE_SET_NOW_CB,
+                                      0, &now_cb), 1))
+                goto err;
+        }
         /*
          * TODO(QUIC SERVER):
          *    Currently the simplistic handler of the quic tserver cannot cope
@@ -364,6 +376,16 @@ static void qtest_reset_time(void)
     qtest_add_time(1);
 }
 
+void qtest_start_stopwatch(void)
+{
+    start_time = qtest_get_time();
+}
+
+uint64_t qtest_get_stopwatch_time(void)
+{
+    return ossl_time2ms(ossl_time_subtract(qtest_get_time(), start_time));
+}
+
 QTEST_FAULT *qtest_create_injector(QUIC_TSERVER *ts)
 {
     QTEST_FAULT *f;
@@ -1207,6 +1229,30 @@ int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen)
     return 1;
 }
 
+int qtest_fault_set_bw_limit(QTEST_FAULT *fault,
+                             size_t ctos_bw, size_t stoc_bw,
+                             int noise_rate)
+{
+    BIO *sbio = fault->noiseargs.sbio;
+    BIO *cbio = fault->noiseargs.cbio;
+
+    if (!TEST_ptr(sbio) || !TEST_ptr(cbio))
+        return 0;
+    if (!TEST_int_eq(BIO_ctrl(sbio, BIO_CTRL_NOISE_RATE, noise_rate, NULL), 1))
+        return 0;
+    if (!TEST_int_eq(BIO_ctrl(cbio, BIO_CTRL_NOISE_RATE, noise_rate, NULL), 1))
+        return 0;
+    /* We set the bandwidth limit on the sending side */
+    if (!TEST_int_eq(BIO_ctrl(cbio, BIO_CTRL_NOISE_SEND_BANDWIDTH,
+                              (long)ctos_bw, NULL), 1))
+        return 0;
+    if (!TEST_int_eq(BIO_ctrl(sbio, BIO_CTRL_NOISE_SEND_BANDWIDTH,
+                              (long)stoc_bw, NULL), 1))
+        return 0;
+    return 1;
+}
+
+
 int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src)
 {
     /*
index 228d396f41c25c73d9333e8d324d1e06d90b52b1..d9d01f7fc1586c7c56b167713d04a0865371a26e 100644 (file)
@@ -49,6 +49,11 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
 /* Where QTEST_FLAG_FAKE_TIME is used, add millis to the current time */
 void qtest_add_time(uint64_t millis);
 
+/* Starts time measurement */
+void qtest_start_stopwatch(void);
+/* Returns the duration from the start in millis */
+uint64_t qtest_get_stopwatch_time(void);
+
 QTEST_FAULT *qtest_create_injector(QUIC_TSERVER *ts);
 
 BIO_METHOD *qtest_get_bio_method(void);
@@ -244,6 +249,15 @@ int qtest_fault_set_datagram_listener(QTEST_FAULT *fault,
  */
 int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen);
 
+/*
+ * Set bandwidth and noise rate on noisy dgram filter.
+ * Arguments with values of 0 mean no limit/no noise.
+ */
+
+int qtest_fault_set_bw_limit(QTEST_FAULT *fault,
+                             size_t ctos_bw, size_t stoc_bw,
+                             int noise_rate);
+
 /* Copy a BIO_MSG */
 int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src);
 
index 098e1a9b396af32e4e4d9815c010d7b199eb642e..2b6c2fc6e0f03ad0ebd9ded8303941459e9759d1 100644 (file)
@@ -1566,6 +1566,98 @@ static int test_noisy_dgram(int idx)
     return testresult;
 }
 
+/*
+ * Create a connection and send some big data using a transport with limited bandwidth.
+ */
+
+#define TEST_TRANSFER_DATA_SIZE (2*1024*1024)    /* 2 MBytes */
+#define TEST_SINGLE_WRITE_SIZE (16*1024)        /* 16 kBytes */
+#define TEST_BW_LIMIT 1000                      /* 1000 Bytes/ms */
+static int test_bw_limit(void)
+{
+    SSL_CTX *cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method());
+    SSL *clientquic = NULL;
+    QUIC_TSERVER *qtserv = NULL;
+    int testresult = 0;
+    unsigned char *msg = NULL, *recvbuf = NULL;
+    size_t sendlen = TEST_TRANSFER_DATA_SIZE;
+    size_t recvlen = TEST_TRANSFER_DATA_SIZE;
+    size_t written, readbytes;
+    int flags = QTEST_FLAG_NOISE | QTEST_FLAG_FAKE_TIME;
+    QTEST_FAULT *fault = NULL;
+    uint64_t real_bw;
+
+    if (!TEST_ptr(cctx)
+            || !TEST_true(qtest_create_quic_objects(libctx, cctx, NULL, cert,
+                                                    privkey, flags,
+                                                    &qtserv,
+                                                    &clientquic, &fault, NULL)))
+        goto err;
+
+    if (!TEST_ptr(msg = OPENSSL_zalloc(TEST_SINGLE_WRITE_SIZE))
+        || !TEST_ptr(recvbuf = OPENSSL_zalloc(TEST_SINGLE_WRITE_SIZE)))
+        goto err;
+
+    /* Set BW to 1000 Bytes/ms -> 1MByte/s both ways */
+    if (!TEST_true(qtest_fault_set_bw_limit(fault, 1000, 1000, 0)))
+        goto err;
+
+    if (!TEST_true(qtest_create_quic_connection(qtserv, clientquic)))
+            goto err;
+
+    qtest_start_stopwatch();
+
+    while (recvlen > 0) {
+        qtest_add_time(1);
+
+        if (sendlen > 0) {
+            if (!SSL_write_ex(clientquic, msg,
+                              sendlen > TEST_SINGLE_WRITE_SIZE ? TEST_SINGLE_WRITE_SIZE
+                                                               : sendlen,
+                              &written)) {
+                TEST_info("Retrying to send: %llu", (unsigned long long) sendlen);
+                if (!TEST_int_eq(SSL_get_error(clientquic, 0), SSL_ERROR_WANT_WRITE))
+                    goto err;
+            } else {
+                sendlen -= written;
+                TEST_info("Remaining to send: %llu", (unsigned long long) sendlen);
+            }
+        } else {
+            SSL_handle_events(clientquic);
+        }
+
+        if (ossl_quic_tserver_read(qtserv, 0, recvbuf,
+                                   recvlen > TEST_SINGLE_WRITE_SIZE ? TEST_SINGLE_WRITE_SIZE
+                                                                    : recvlen,
+                                   &readbytes)
+            && readbytes > 1) {
+            recvlen -= readbytes;
+            TEST_info("Remaining to recv: %llu", (unsigned long long) recvlen);
+        } else {
+            TEST_info("No progress on recv: %llu", (unsigned long long) recvlen);
+        }
+        ossl_quic_tserver_tick(qtserv);
+    }
+    real_bw = TEST_TRANSFER_DATA_SIZE / qtest_get_stopwatch_time();
+
+    TEST_info("BW limit: %d Bytes/ms Real bandwidth reached: %llu Bytes/ms",
+              TEST_BW_LIMIT, (unsigned long long)real_bw);
+
+    if (!TEST_uint64_t_lt(real_bw, TEST_BW_LIMIT))
+        goto err;
+
+    testresult = 1;
+ err:
+    OPENSSL_free(msg);
+    OPENSSL_free(recvbuf);
+    ossl_quic_tserver_free(qtserv);
+    SSL_free(clientquic);
+    SSL_CTX_free(cctx);
+    qtest_fault_free(fault);
+
+    return testresult;
+}
+
 enum {
     TPARAM_OP_DUP,
     TPARAM_OP_DROP,
@@ -2165,6 +2257,7 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_client_auth, 3);
     ADD_ALL_TESTS(test_alpn, 2);
     ADD_ALL_TESTS(test_noisy_dgram, 2);
+    ADD_TEST(test_bw_limit);
     ADD_TEST(test_get_shutdown);
     ADD_ALL_TESTS(test_tparam, OSSL_NELEM(tparam_tests));