/*
- * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
# include "../threadstest.h"
#endif
+#include "internal/quic_ssl.h"
#include "internal/quic_wire_pkt.h"
#include "internal/quic_record_tx.h"
#include "internal/quic_error.h"
#include "internal/packet.h"
+#include "internal/tsan_assist.h"
#define GROWTH_ALLOWANCE 1024
}
int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
- char *certfile, char *keyfile,
+ SSL_CTX *serverctx, char *certfile, char *keyfile,
int flags, QUIC_TSERVER **qtserv, SSL **cssl,
QTEST_FAULT **fault)
{
(flags & QTEST_FLAG_BLOCK) != 0 ? 1 : 0)))
goto err;
- if (!TEST_true(SSL_set_initial_peer_addr(*cssl, peeraddr)))
+ if (!TEST_true(SSL_set1_initial_peer_addr(*cssl, peeraddr)))
goto err;
if (fault != NULL) {
tserver_args.net_rbio = sbio;
tserver_args.net_wbio = fisbio;
tserver_args.alpn = NULL;
- tserver_args.ctx = NULL;
+ if (serverctx != NULL && !TEST_true(SSL_CTX_up_ref(serverctx)))
+ goto err;
+ tserver_args.ctx = serverctx;
if ((flags & QTEST_FLAG_FAKE_TIME) != 0) {
fake_now = ossl_time_zero();
+ /* zero time can have a special meaning, bump it */
+ qtest_add_time(1);
tserver_args.now_cb = fake_now_cb;
+ (void)ossl_quic_conn_set_override_now_cb(*cssl, fake_now_cb, NULL);
}
if (!TEST_ptr(*qtserv = ossl_quic_tserver_new(&tserver_args, certfile,
return 1;
err:
+ SSL_CTX_free(tserver_args.ctx);
BIO_ADDR_free(peeraddr);
BIO_free(cbio);
BIO_free(fisbio);
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
static int globserverret = 0;
+static TSAN_QUALIFIER int abortserverthread = 0;
static QUIC_TSERVER *globtserv;
static const thread_t thread_zero;
}
#endif
-int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
+int qtest_create_quic_connection_ex(QUIC_TSERVER *qtserv, SSL *clientssl,
+ int wanterr)
{
- int retc = -1, rets = 0, err, abortctr = 0, ret = 0;
+ int retc = -1, rets = 0, abortctr = 0, ret = 0;
int clienterr = 0, servererr = 0;
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
/*
* t uninitialised
*/
thread_t t = thread_zero;
+
+ if (clientssl != NULL)
+ abortserverthread = 0;
#endif
if (!TEST_ptr(qtserv)) {
}
do {
- err = SSL_ERROR_WANT_WRITE;
- while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
+ if (!clienterr && retc <= 0) {
+ int err;
+
retc = SSL_connect(clientssl);
- if (retc <= 0)
+ if (retc <= 0) {
err = SSL_get_error(clientssl, retc);
- }
- if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) {
- TEST_info("SSL_connect() failed %d, %d", retc, err);
- TEST_openssl_errors();
- clienterr = 1;
+ if (err == wanterr) {
+ retc = 1;
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ if (qtserv == NULL && rets > 0)
+ tsan_store(&abortserverthread, 1);
+ else
+#endif
+ rets = 1;
+ } else {
+ if (err != SSL_ERROR_WANT_READ
+ && err != SSL_ERROR_WANT_WRITE) {
+ TEST_info("SSL_connect() failed %d, %d", retc, err);
+ TEST_openssl_errors();
+ clienterr = 1;
+ }
+ }
+ }
}
/*
*/
if (!clienterr && retc <= 0)
SSL_handle_events(clientssl);
+
if (!servererr && rets <= 0) {
qtest_add_time(1);
ossl_quic_tserver_tick(qtserv);
TEST_info("No progress made");
goto err;
}
- } while ((retc <= 0 && !clienterr) || (rets <= 0 && !servererr));
+ } while ((retc <= 0 && !clienterr)
+ || (rets <= 0 && !servererr
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ && !tsan_load(&abortserverthread)
+#endif
+ ));
if (qtserv == NULL && rets > 0) {
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
return ret;
}
+int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
+{
+ return qtest_create_quic_connection_ex(qtserv, clientssl, SSL_ERROR_NONE);
+}
+
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+static TSAN_QUALIFIER int shutdowndone;
+
+static void run_server_shutdown_thread(void)
+{
+ /*
+ * This will operate in a busy loop because the server does not block,
+ * but should be acceptable because it is local and we expect this to be
+ * fast
+ */
+ do {
+ ossl_quic_tserver_tick(globtserv);
+ } while(!tsan_load(&shutdowndone));
+}
+#endif
+
int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl)
{
+ int tickserver = 1;
+ int ret = 0;
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ /*
+ * Pointless initialisation to avoid bogus compiler warnings about using
+ * t uninitialised
+ */
+ thread_t t = thread_zero;
+#endif
+
+ if (SSL_get_blocking_mode(clientssl) > 0) {
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ /*
+ * clientssl is blocking. We will need a thread to complete the
+ * connection
+ */
+ globtserv = qtserv;
+ shutdowndone = 0;
+ if (!TEST_true(run_thread(&t, run_server_shutdown_thread)))
+ return 0;
+
+ tickserver = 0;
+#else
+ TEST_error("No thread support in this build");
+ return 0;
+#endif
+ }
+
/* Busy loop in non-blocking mode. It should be quick because its local */
for (;;) {
int rc = SSL_shutdown(clientssl);
- if (rc == 1)
+ if (rc == 1) {
+ ret = 1;
break;
+ }
if (rc < 0)
- return 0;
+ break;
- ossl_quic_tserver_tick(qtserv);
+ if (tickserver)
+ ossl_quic_tserver_tick(qtserv);
}
- return 1;
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ tsan_store(&shutdowndone, 1);
+ if (!tickserver) {
+ if (!TEST_true(wait_for_thread(t)))
+ ret = 0;
+ }
+#endif
+
+ return ret;
}
int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code)
do {
if (!ossl_quic_wire_decode_pkt_hdr(&pkt,
- 0 /* TODO(QUIC): Not sure how this should be set*/, 1,
+ /*
+ * TODO(QUIC SERVER):
+ * Needs to be set to the actual short header CID length
+ * when testing the server implementation.
+ */
+ 0,
+ 1,
0, &hdr, NULL))
goto out;
goto out;
/*
- * TODO(QUIC): At the moment modifications to hdr by the callback
+ * At the moment modifications to hdr by the callback
* are ignored. We might need to rewrite the QUIC header to
* enable tests to change this. We also don't yet have a
* mechanism for the callback to change the encrypted data