From: Andrew Dinh Date: Wed, 8 Jul 2026 04:10:18 +0000 (+0700) Subject: Port script_20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77511e1baa038c2faf0c10d930c08ea87305dbec;p=thirdparty%2Fopenssl.git Port script_20 Assisted-by: Claude:claude-sonnet-5 Reviewed-by: Saša Nedvědický Reviewed-by: Bob Beck MergeDate: Thu Jul 30 06:12:39 2026 (Merged from https://github.com/openssl/openssl/pull/32003) --- diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index a921f136100..8e74e83a706 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -2068,98 +2068,8 @@ static const struct script_op script_19[] = { }; /* 20. Multiple threads accept stream with socket forcibly closed (error test) */ -static int script_20_trigger(struct helper *h, volatile uint64_t *counter) -{ -#if defined(OPENSSL_THREADS) - ossl_crypto_mutex_lock(h->misc_m); - ++*counter; - ossl_crypto_condvar_broadcast(h->misc_cv); - ossl_crypto_mutex_unlock(h->misc_m); -#endif - return 1; -} - -static int script_20_wait(struct helper *h, volatile uint64_t *counter, uint64_t threshold) -{ -#if defined(OPENSSL_THREADS) - int stop = 0; - - ossl_crypto_mutex_lock(h->misc_m); - while (!stop) { - stop = (*counter >= threshold); - if (stop) - break; - - ossl_crypto_condvar_wait(h->misc_cv, h->misc_m); - } - - ossl_crypto_mutex_unlock(h->misc_m); -#endif - return 1; -} - -static int script_20_trigger1(struct helper *h, struct helper_local *hl) -{ - return script_20_trigger(h, &h->scratch0); -} - -static int script_20_wait1(struct helper *h, struct helper_local *hl) -{ - return script_20_wait(h, &h->scratch0, hl->check_op->arg2); -} - -static int script_20_trigger2(struct helper *h, struct helper_local *hl) -{ - return script_20_trigger(h, &h->scratch1); -} - -static int script_20_wait2(struct helper *h, struct helper_local *hl) -{ - return script_20_wait(h, &h->scratch1, hl->check_op->arg2); -} - -static const struct script_op script_20_child[] = { - OP_C_ACCEPT_STREAM_WAIT(a), - OP_C_READ_EXPECT(a, "foo", 3), - - OP_CHECK(script_20_trigger1, 0), - OP_CHECK(script_20_wait2, 1), - - OP_C_READ_FAIL_WAIT(a), - OP_C_EXPECT_SSL_ERR(a, SSL_ERROR_SYSCALL), - - OP_EXPECT_ERR_LIB(ERR_LIB_SSL), - OP_EXPECT_ERR_REASON(SSL_R_PROTOCOL_IS_SHUTDOWN), - - OP_POP_ERR(), - OP_EXPECT_ERR_LIB(ERR_LIB_SSL), - OP_EXPECT_ERR_REASON(SSL_R_QUIC_NETWORK_ERROR), - - OP_C_FREE_STREAM(a), - - OP_END -}; - static const struct script_op script_20[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_NEW_THREAD(5, script_20_child), - - OP_BEGIN_REPEAT(5), - - OP_S_NEW_STREAM_BIDI(a, ANY_ID), - OP_S_WRITE(a, "foo", 3), - OP_S_UNBIND_STREAM_ID(a), - - OP_END_REPEAT(), - - OP_CHECK(script_20_wait1, 5), - - OP_C_CLOSE_SOCKET(), - OP_CHECK(script_20_trigger2, 0), - + /* test moved to test/radix/quic_tests.c */ OP_END }; diff --git a/test/radix/quic_bindings.c b/test/radix/quic_bindings.c index 63bcecad99b..fb87c2245d1 100644 --- a/test/radix/quic_bindings.c +++ b/test/radix/quic_bindings.c @@ -68,6 +68,7 @@ typedef struct radix_process_st { CRYPTO_MUTEX *gm; /* global mutex */ LHASH_OF(RADIX_OBJ) *objs; /* protected by gm */ BIO *keylog_out; /* protected by gm */ + uint64_t counter[2]; /* protected by gm */ CRYPTO_MUTEX *time_m; OSSL_TIME base_time; /* set once at init, constant thereafter */ @@ -107,7 +108,7 @@ typedef struct radix_thread_st { DEFINE_STACK_OF(RADIX_THREAD) -/* ssl reference is transferred. name is copied and is required. */ +/* name is copied and is required. Created with no SSL object bound yet. */ static RADIX_OBJ *RADIX_OBJ_new_empty(const char *name) { RADIX_OBJ *obj; @@ -135,6 +136,7 @@ static RADIX_OBJ *RADIX_OBJ_new_empty(const char *name) return obj; } +/* ssl reference is transferred. name is copied and is required. */ static RADIX_OBJ *RADIX_OBJ_new(const char *name, SSL *ssl) { RADIX_OBJ *obj; @@ -142,8 +144,7 @@ static RADIX_OBJ *RADIX_OBJ_new(const char *name, SSL *ssl) if (!TEST_ptr(ssl)) return NULL; - obj = RADIX_OBJ_new_empty(name); - if (!TEST_ptr(obj)) + if (!TEST_ptr(obj = RADIX_OBJ_new_empty(name))) return NULL; obj->ssl = ssl; @@ -712,7 +713,7 @@ static void radix_skip_time(OSSL_TIME t) static void per_op_tick_obj(RADIX_OBJ *obj) { ossl_crypto_mutex_lock(obj->mx); - if (obj->active && obj->ssl) + if (obj->active && obj->ssl != NULL) SSL_handle_events(obj->ssl); ossl_crypto_mutex_unlock(obj->mx); } diff --git a/test/radix/quic_ops.c b/test/radix/quic_ops.c index ed129d0ff7f..6d7daa01484 100644 --- a/test/radix/quic_ops.c +++ b/test/radix/quic_ops.c @@ -29,20 +29,21 @@ err: DEF_FUNC(hf_bind) { + int ok = 0; const char *name; RADIX_OBJ *empty_obj; F_POP(name); - empty_obj = RADIX_OBJ_new_empty(name); - if (empty_obj == NULL) - return 0; - - RADIX_PROCESS_set_obj(RP(), name, empty_obj); + if (!TEST_ptr(empty_obj = RADIX_OBJ_new_empty(name)) + || !TEST_true(RADIX_PROCESS_set_obj(RP(), name, empty_obj))) { + RADIX_OBJ_free(empty_obj); + goto err; + } - return 1; + ok = 1; err: - return 0; + return ok; } static int ssl_ctx_select_alpn(SSL *ssl, @@ -292,8 +293,9 @@ DEF_FUNC(hf_new_stream) if (replace == 0) { if (!TEST_ptr_null(stream_obj)) goto err; - } else if (TEST_ptr_null(stream_obj)) + } else if (TEST_ptr_null(stream_obj)) { goto err; + } if (do_accept) { stream = SSL_accept_stream(conn, flags & OP_F_MASK); @@ -1049,6 +1051,62 @@ err: return ok; } +DEF_FUNC(hf_close_socket) +{ + int ok = 0; + SSL *ssl; + BIO *bio; + int fd = -1; + + REQUIRE_SSL(ssl); + + bio = SSL_get_rbio(ssl); + if (!TEST_ptr(bio) || !TEST_true(BIO_get_fd(bio, &fd)) || !TEST_int_ge(fd, 0)) + goto err; + + BIO_closesocket(fd); + + ok = 1; +err: + return ok; +} + +/* Process-global counters (RP()->counter[idx]), used for cross-thread sync. */ +DEF_FUNC(hf_trigger_counter) +{ + int ok = 0; + uint64_t idx; + + F_POP(idx); + + ossl_crypto_mutex_lock(RP()->gm); + ++RP()->counter[idx]; + ossl_crypto_mutex_unlock(RP()->gm); + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_wait_counter) +{ + int ok = 0; + uint64_t idx, threshold, current; + + F_POP2(idx, threshold); + + ossl_crypto_mutex_lock(RP()->gm); + current = RP()->counter[idx]; + ossl_crypto_mutex_unlock(RP()->gm); + + if (current < threshold) + F_SPIN_AGAIN(); + + ok = 1; +err: + return ok; +} + #define OP_UNBIND(name) \ (OP_PUSH_PZ(#name), \ OP_FUNC(hf_unbind)) @@ -1295,3 +1353,16 @@ err: (OP_SELECT_SSL(0, name), \ OP_PUSH_U64(update_type), \ OP_FUNC(hf_trigger_key_update)) + +#define OP_CLOSE_SOCKET(name) \ + (OP_SELECT_SSL(0, name), \ + OP_FUNC(hf_close_socket)) + +#define OP_TRIGGER_COUNTER(idx) \ + (OP_PUSH_U64(idx), \ + OP_FUNC(hf_trigger_counter)) + +#define OP_WAIT_COUNTER(idx, threshold) \ + (OP_PUSH_U64(idx), \ + OP_PUSH_U64(threshold), \ + OP_FUNC(hf_wait_counter)) diff --git a/test/radix/quic_tests.c b/test/radix/quic_tests.c index f1abcce1185..40d3290adc7 100644 --- a/test/radix/quic_tests.c +++ b/test/radix/quic_tests.c @@ -1630,8 +1630,119 @@ DEF_SCRIPT(script_19, "Key update test - artificially triggered") OP_CHECK_KEY_UPDATE_GE(C, 1); } -DEF_SCRIPT(script_20, "place holder for multistrem script_20") +/* 20. Multiple threads accept stream with socket forcibly closed (error test) */ +DEF_SCRIPT(script_20_child_0, + "child: accept stream, read, signal ready, wait, expect read failure") { + OP_ACCEPT_STREAM_WAIT(C, Ca, OP_F_REPLACE_STREAM /* bidirectional */); + OP_READ_EXPECT_B(Ca, "foo"); + + OP_TRIGGER_COUNTER(0); + OP_WAIT_COUNTER(1, 1); + + OP_READ_FAIL_WAIT(Ca); + OP_EXPECT_SSL_ERR(Ca, SSL_ERROR_SYSCALL); +} + +DEF_SCRIPT(script_20_child_1, + "child: accept stream, read, signal ready, wait, expect read failure") +{ + OP_ACCEPT_STREAM_WAIT(C, Cb, OP_F_REPLACE_STREAM /* bidirectional */); + OP_READ_EXPECT_B(Cb, "foo"); + + OP_TRIGGER_COUNTER(0); + OP_WAIT_COUNTER(1, 1); + + OP_READ_FAIL_WAIT(Cb); + OP_EXPECT_SSL_ERR(Cb, SSL_ERROR_SYSCALL); +} + +DEF_SCRIPT(script_20_child_2, + "child: accept stream, read, signal ready, wait, expect read failure") +{ + OP_ACCEPT_STREAM_WAIT(C, Cc, OP_F_REPLACE_STREAM /* bidirectional */); + OP_READ_EXPECT_B(Cc, "foo"); + + OP_TRIGGER_COUNTER(0); + OP_WAIT_COUNTER(1, 1); + + OP_READ_FAIL_WAIT(Cc); + OP_EXPECT_SSL_ERR(Cc, SSL_ERROR_SYSCALL); +} + +DEF_SCRIPT(script_20_child_3, + "child: accept stream, read, signal ready, wait, expect read failure") +{ + OP_ACCEPT_STREAM_WAIT(C, Cd, OP_F_REPLACE_STREAM /* bidirectional */); + OP_READ_EXPECT_B(Cd, "foo"); + + OP_TRIGGER_COUNTER(0); + OP_WAIT_COUNTER(1, 1); + + OP_READ_FAIL_WAIT(Cd); + OP_EXPECT_SSL_ERR(Cd, SSL_ERROR_SYSCALL); +} + +DEF_SCRIPT(script_20_child_4, + "child: accept stream, read, signal ready, wait, expect read failure") +{ + OP_ACCEPT_STREAM_WAIT(C, Ce, OP_F_REPLACE_STREAM /* bidirectional */); + OP_READ_EXPECT_B(Ce, "foo"); + + OP_TRIGGER_COUNTER(0); + OP_WAIT_COUNTER(1, 1); + + OP_READ_FAIL_WAIT(Ce); + OP_EXPECT_SSL_ERR(Ce, SSL_ERROR_SYSCALL); +} + +DEF_SCRIPT(script_20, "Multiple threads accept stream with socket forcibly closed (error test)") +{ + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_BIND(Ca); + OP_BIND(Cb); + OP_BIND(Cc); + OP_BIND(Cd); + OP_BIND(Ce); + OP_BIND(Sa); + OP_BIND(Sb); + OP_BIND(Sc); + OP_BIND(Sd); + OP_BIND(Se); + + OP_SPAWN_THREAD(script_20_child_0); + OP_SPAWN_THREAD(script_20_child_1); + OP_SPAWN_THREAD(script_20_child_2); + OP_SPAWN_THREAD(script_20_child_3); + OP_SPAWN_THREAD(script_20_child_4); + + OP_NEW_STREAM(S, Sa, OP_F_REPLACE_STREAM /* bidirectional */); + OP_WRITE_B(Sa, "foo"); + OP_CONCLUDE(Sa); + + OP_NEW_STREAM(S, Sb, OP_F_REPLACE_STREAM /* bidirectional */); + OP_WRITE_B(Sb, "foo"); + OP_CONCLUDE(Sb); + + OP_NEW_STREAM(S, Sc, OP_F_REPLACE_STREAM /* bidirectional */); + OP_WRITE_B(Sc, "foo"); + OP_CONCLUDE(Sc); + + OP_NEW_STREAM(S, Sd, OP_F_REPLACE_STREAM /* bidirectional */); + OP_WRITE_B(Sd, "foo"); + OP_CONCLUDE(Sd); + + OP_NEW_STREAM(S, Se, OP_F_REPLACE_STREAM /* bidirectional */); + OP_WRITE_B(Se, "foo"); + OP_CONCLUDE(Se); + + OP_WAIT_COUNTER(0, 5); + + OP_CLOSE_SOCKET(C); + + OP_TRIGGER_COUNTER(1); } DEF_SCRIPT(script_21, "place holder for multistrem script_21")