diff options
author | Matt Caswell <matt@openssl.org> | 2023-09-15 15:35:56 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2023-09-22 13:56:43 +0100 |
commit | d3a8daca587157dda52991448258800e9cf1f657 (patch) | |
tree | 7dd48a8390c4d90ce2b7027d818da34a09e23c26 /test | |
parent | 19d79bb2ba45729a49cbac9f98bd916190be0b4b (diff) |
Use test_random() to introduce better noise into the noisy dgram BIO
We drop some datagrams, and we delay some datagrams. We can also duplicate
some datagrams.
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22157)
Diffstat (limited to 'test')
-rw-r--r-- | test/helpers/noisydgrambio.c | 162 | ||||
-rw-r--r-- | test/quicapitest.c | 2 |
2 files changed, 128 insertions, 36 deletions
diff --git a/test/helpers/noisydgrambio.c b/test/helpers/noisydgrambio.c index f55be83616..c1eb141ee5 100644 --- a/test/helpers/noisydgrambio.c +++ b/test/helpers/noisydgrambio.c @@ -11,8 +11,12 @@ #include "quictestlib.h" #include "../testutil.h" +#define MSG_DATA_LEN_MAX 1472 + struct noisy_dgram_st { - size_t this_dgram; + uint64_t this_dgram; + BIO_MSG msg; + uint64_t delayed_dgram; }; static int noisy_dgram_read(BIO *bio, char *out, int outl) @@ -74,21 +78,31 @@ static int noisy_dgram_sendmmsg(BIO *bio, BIO_MSG *msg, size_t stride, return BIO_sendmmsg(next, msg, stride, num_msg, flags, msgs_processed); } -static int should_drop(BIO *bio) +static void get_noise(uint64_t *delay, int *should_drop) { - struct noisy_dgram_st *data = BIO_get_data(bio); + uint32_t type; - if (data == NULL) - return 0; + /* 20% of all datagrams should be noisy */ + if (test_random() % 5 != 0) { + *delay = 0; + *should_drop = 0; + return; + } + + type = test_random() % 3; + + /* Of noisy datagrams, 33% drop only, 33% delay only, 33% drop and delay */ + + *should_drop = (type == 0 || type == 1); + + /* Where a delay occurs we delay by 1 - 4 datagrams */ + *delay = (type == 0) ? 0 : (uint64_t)((test_random() % 4) + 1); /* - * Drop datagram 1 for now. - * TODO(QUIC): Provide more control over this behaviour. + * No point in delaying by 1 datagram if we are also dropping, so we delay + * by an extra datagram in that case */ - if (data->this_dgram == 1) - return 1; - - return 0; + *delay += (uint64_t)(*should_drop); } /* There isn't a public function to do BIO_ADDR_copy() so we create one */ @@ -129,13 +143,36 @@ static int bio_addr_copy(BIO_ADDR *dst, BIO_ADDR *src) return res; } +static int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src) +{ + /* + * Note it is assumed that the originally allocated data sizes for dst and + * src are the same + */ + memcpy(dst->data, src->data, src->data_len); + dst->data_len = src->data_len; + dst->flags = src->flags; + if (dst->local != NULL) { + if (src->local != NULL) { + if (!TEST_true(bio_addr_copy(dst->local, src->local))) + return 0; + } else { + BIO_ADDR_clear(dst->local); + } + } + if (!TEST_true(bio_addr_copy(dst->peer, src->peer))) + return 0; + + return 1; +} + static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, size_t num_msg, uint64_t flags, size_t *msgs_processed) { BIO *next = BIO_next(bio); - size_t i, data_len = 0, drop_cnt = 0; - BIO_MSG *src, *dst; + size_t i, j, data_len = 0, msg_cnt = 0; + BIO_MSG *thismsg; struct noisy_dgram_st *data; if (!TEST_ptr(next)) @@ -153,42 +190,76 @@ static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, * code). We test the invariant here. */ for (i = 0; i < num_msg; i++) { - if (i == 0) + if (i == 0) { data_len = msg[i].data_len; - else if (!TEST_size_t_eq(msg[i].data_len, data_len)) + if (!TEST_size_t_le(data_len, MSG_DATA_LEN_MAX)) + return 0; + } else if (!TEST_size_t_eq(msg[i].data_len, data_len)) { return 0; + } } if (!BIO_recvmmsg(next, msg, stride, num_msg, flags, msgs_processed)) return 0; - /* Drop any messages */ - for (i = 0, src = msg, dst = msg; - i < *msgs_processed; - i++, src++, data->this_dgram++) { - if (should_drop(bio)) { - drop_cnt++; - continue; + msg_cnt = *msgs_processed; + + /* Introduce noise */ + for (i = 0, thismsg = msg; + i < msg_cnt; + i++, thismsg++, data->this_dgram++) { + uint64_t delay; + int should_drop; + + /* If we have a delayed message ready insert it now */ + if (data->delayed_dgram > 0 + && data->delayed_dgram == data->this_dgram) { + if (msg_cnt < num_msg) { + /* Make space for the inserted message */ + for (j = msg_cnt; j > i; j--) { + if (!bio_msg_copy(&msg[j], &msg[j - 1])) + return 0; + } + if (!bio_msg_copy(thismsg, &data->msg)) + return 0; + msg_cnt++; + data->delayed_dgram = 0; + continue; + } /* else we have no space for the insertion, so just drop it */ + data->delayed_dgram = 0; } - if (src != dst) { - /* Copy the src BIO_MSG to the dst BIO_MSG */ - memcpy(dst->data, src->data, src->data_len); - dst->data_len = src->data_len; - dst->flags = src->flags; - if (src->local != NULL - && !TEST_true(bio_addr_copy(dst->local, src->local))) - return 0; - if (!TEST_true(bio_addr_copy(dst->peer, src->peer))) + get_noise(&delay, &should_drop); + + /* We ignore delay if a message is already delayed */ + if (delay > 0 && data->delayed_dgram == 0) { + /* + * Note that a message may be delayed *and* dropped, or delayed + * and *not* dropped. + * Delayed and dropped means the message will not be sent now and + * will only be sent after the delay. + * Delayed and not dropped means the message will be sent now and + * a duplicate will also be sent after the delay. + */ + + if (!bio_msg_copy(&data->msg, thismsg)) return 0; + + data->delayed_dgram = data->this_dgram + delay; } - dst++; + if (should_drop) { + for (j = i + 1; j < msg_cnt; j++) { + if (!bio_msg_copy(&msg[j - 1], &msg[j])) + return 0; + } + msg_cnt--; + } } - *msgs_processed -= drop_cnt; + *msgs_processed = msg_cnt; - if (*msgs_processed == 0) { + if (msg_cnt == 0) { ERR_raise(ERR_LIB_BIO, BIO_R_NON_FATAL); return 0; } @@ -196,6 +267,17 @@ static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, return 1; } +static void data_free(struct noisy_dgram_st *data) +{ + if (data == NULL) + return; + + OPENSSL_free(data->msg.data); + BIO_ADDR_free(data->msg.peer); + BIO_ADDR_free(data->msg.local); + OPENSSL_free(data); +} + static int noisy_dgram_new(BIO *bio) { struct noisy_dgram_st *data = OPENSSL_zalloc(sizeof(*data)); @@ -203,6 +285,16 @@ static int noisy_dgram_new(BIO *bio) if (!TEST_ptr(data)) return 0; + data->msg.data = OPENSSL_malloc(MSG_DATA_LEN_MAX); + data->msg.peer = BIO_ADDR_new(); + data->msg.local = BIO_ADDR_new(); + if (data->msg.data == NULL + || data->msg.peer == NULL + || data->msg.local == NULL) { + data_free(data); + return 0; + } + BIO_set_data(bio, data); BIO_set_init(bio, 1); @@ -211,7 +303,7 @@ static int noisy_dgram_new(BIO *bio) static int noisy_dgram_free(BIO *bio) { - OPENSSL_free(BIO_get_data(bio)); + data_free(BIO_get_data(bio)); BIO_set_data(bio, NULL); BIO_set_init(bio, 0); diff --git a/test/quicapitest.c b/test/quicapitest.c index 19b59951f6..0030c31082 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -1250,7 +1250,7 @@ static int test_alpn(int idx) return testresult; } -#define MAX_LOOPS 40 +#define MAX_LOOPS 2000 /* * Keep retrying SSL_read_ex until it succeeds or we give up. Accept a stream |