2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-05 00:55:24 +00:00
Files
bind/lib/isc/tests/tlsdns_test.c
Ondřej Surý 36ddefacb4 Change the isc_nm_(get|set)timeouts() to work with milliseconds
The RFC7828 specifies the keepalive interval to be 16-bit, specified in
units of 100 milliseconds and the configuration options tcp-*-timeouts
are following the suit.  The units of 100 milliseconds are very
unintuitive and while we can't change the configuration and presentation
format, we should not follow this weird unit in the API.

This commit changes the isc_nm_(get|set)timeouts() functions to work
with milliseconds and convert the values to milliseconds before passing
them to the function, not just internally.
2021-03-18 16:37:57 +01:00

904 lines
21 KiB
C

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#if HAVE_CMOCKA
#include <sched.h> /* IWYU pragma: keep */
#include <setjmp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <uv.h>
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/mutex.h>
#include <isc/netmgr.h>
#include <isc/nonce.h>
#include <isc/os.h>
#include <isc/refcount.h>
#include <isc/sockaddr.h>
#include <isc/thread.h>
#include "../netmgr/netmgr-int.h"
#include "isctest.h"
#define MAX_NM 2
static isc_sockaddr_t tlsdns_listen_addr;
static isc_tlsctx_t *tlsdns_listen_ctx = NULL;
static isc_tlsctx_t *tlsdns_connect_ctx = NULL;
static uint64_t send_magic = 0;
static uint64_t stop_magic = 0;
static uv_buf_t send_msg = { .base = (char *)&send_magic,
.len = sizeof(send_magic) };
static uv_buf_t stop_msg = { .base = (char *)&stop_magic,
.len = sizeof(stop_magic) };
static atomic_uint_fast64_t nsends;
static atomic_uint_fast64_t ssends;
static atomic_uint_fast64_t sreads;
static atomic_uint_fast64_t cconnects;
static atomic_uint_fast64_t csends;
static atomic_uint_fast64_t creads;
static atomic_uint_fast64_t ctimeouts;
static unsigned int workers = 1;
static bool reuse_supported = true;
#define NSENDS 100
#define NWRITES 10
#define CHECK_RANGE_FULL(v) \
{ \
int __v = atomic_load(&v); \
assert_true(__v > 1); \
assert_true(__v <= NSENDS * NWRITES * 110 / 100); \
}
#define CHECK_RANGE_HALF(v) \
{ \
int __v = atomic_load(&v); \
assert_true(__v > 1); \
assert_true(__v <= NSENDS * NWRITES * 60 / 100); \
}
/* Enable this to print values while running tests */
#undef PRINT_DEBUG
#ifdef PRINT_DEBUG
#define X(v) fprintf(stderr, #v " = %" PRIu64 "\n", atomic_load(&v))
#else
#define X(v)
#endif
static int
setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
isc_result_t result;
socklen_t addrlen = sizeof(*addr);
int fd;
int r;
isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
fd = socket(AF_INET6, family, 0);
if (fd < 0) {
perror("setup_ephemeral_port: socket()");
return (-1);
}
r = bind(fd, (const struct sockaddr *)&addr->type.sa,
sizeof(addr->type.sin6));
if (r != 0) {
perror("setup_ephemeral_port: bind()");
close(fd);
return (r);
}
r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
if (r != 0) {
perror("setup_ephemeral_port: getsockname()");
close(fd);
return (r);
}
result = isc__nm_socket_reuse(fd);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
fprintf(stderr,
"setup_ephemeral_port: isc__nm_socket_reuse(): %s",
isc_result_totext(result));
close(fd);
return (-1);
}
result = isc__nm_socket_reuse_lb(fd);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
fprintf(stderr,
"setup_ephemeral_port: isc__nm_socket_reuse_lb(): %s",
isc_result_totext(result));
close(fd);
return (-1);
}
if (result == ISC_R_NOTIMPLEMENTED) {
reuse_supported = false;
}
#if IPV6_RECVERR
#define setsockopt_on(socket, level, name) \
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
if (r != 0) {
perror("setup_ephemeral_port");
close(fd);
return (r);
}
#endif
return (fd);
}
static int
_setup(void **state) {
UNUSED(state);
/* workers = isc_os_ncpus(); */
if (isc_test_begin(NULL, true, workers) != ISC_R_SUCCESS) {
return (-1);
}
signal(SIGPIPE, SIG_IGN);
return (0);
}
static int
_teardown(void **state) {
UNUSED(state);
isc_test_end();
return (0);
}
/* Generic */
static void
noop_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *cbarg) {
UNUSED(handle);
UNUSED(eresult);
UNUSED(region);
UNUSED(cbarg);
}
static unsigned int
noop_accept_cb(isc_nmhandle_t *handle, unsigned int result, void *cbarg) {
UNUSED(handle);
UNUSED(result);
UNUSED(cbarg);
return (0);
}
static void
noop_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
UNUSED(handle);
UNUSED(result);
UNUSED(cbarg);
}
thread_local uint8_t tlsdns_buffer_storage[4096];
thread_local size_t tlsdns_buffer_length = 0;
static int
nm_setup(void **state) {
size_t nworkers = ISC_MAX(ISC_MIN(workers, 32), 1);
int tlsdns_listen_sock = -1;
isc_nm_t **nm = NULL;
if (isc_tlsctx_createserver(NULL, NULL, &tlsdns_listen_ctx) !=
ISC_R_SUCCESS) {
return (-1);
}
if (isc_tlsctx_createclient(&tlsdns_connect_ctx) != ISC_R_SUCCESS) {
return (-1);
}
tlsdns_listen_addr = (isc_sockaddr_t){ .length = 0 };
tlsdns_listen_sock = setup_ephemeral_port(&tlsdns_listen_addr,
SOCK_STREAM);
if (tlsdns_listen_sock < 0) {
return (-1);
}
close(tlsdns_listen_sock);
tlsdns_listen_sock = -1;
atomic_store(&nsends, NSENDS * NWRITES);
atomic_store(&csends, 0);
atomic_store(&creads, 0);
atomic_store(&sreads, 0);
atomic_store(&ssends, 0);
atomic_store(&ctimeouts, 0);
atomic_store(&cconnects, 0);
isc_nonce_buf(&send_magic, sizeof(send_magic));
isc_nonce_buf(&stop_magic, sizeof(stop_magic));
if (send_magic == stop_magic) {
return (-1);
}
nm = isc_mem_get(test_mctx, MAX_NM * sizeof(nm[0]));
for (size_t i = 0; i < MAX_NM; i++) {
nm[i] = isc_nm_start(test_mctx, nworkers);
assert_non_null(nm[i]);
}
*state = nm;
return (0);
}
static int
nm_teardown(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
for (size_t i = 0; i < MAX_NM; i++) {
isc_nm_destroy(&nm[i]);
assert_null(nm[i]);
}
isc_mem_put(test_mctx, nm, MAX_NM * sizeof(nm[0]));
isc_tlsctx_free(&tlsdns_connect_ctx);
isc_tlsctx_free(&tlsdns_listen_ctx);
return (0);
}
thread_local size_t nwrites = NWRITES;
/* TLSDNS */
static void
tlsdns_connect_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg);
static void
tlsdns_connect_send(isc_nmhandle_t *handle);
static void
tlsdns_connect_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
assert_non_null(handle);
UNUSED(cbarg);
if (eresult == ISC_R_SUCCESS) {
atomic_fetch_add(&csends, 1);
} else {
/* Send failed, we need to stop reading too */
isc_nm_cancelread(handle);
}
}
static void
tlsdns_connect_send(isc_nmhandle_t *handle) {
uint_fast64_t sends = atomic_load(&nsends);
/* Continue until we subtract or we are sent them all */
while (sends > 0) {
if (atomic_compare_exchange_weak(&nsends, &sends, sends - 1)) {
sends--;
break;
}
}
if (sends == 0) {
isc_nm_send(handle, (isc_region_t *)&stop_msg,
tlsdns_connect_send_cb, NULL);
} else {
isc_nm_send(handle, (isc_region_t *)&send_msg,
tlsdns_connect_send_cb, NULL);
}
}
static void
tlsdns_connect_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
uint64_t magic = 0;
UNUSED(cbarg);
assert_non_null(handle);
if (eresult != ISC_R_SUCCESS) {
goto unref;
}
assert_int_equal(region->length, sizeof(magic));
atomic_fetch_add(&creads, 1);
memmove(&magic, region->base, sizeof(magic));
assert_true(magic == stop_magic || magic == send_magic);
unref:
isc_nmhandle_detach(&handle);
}
static void
tlsdns_connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
isc_nmhandle_t *readhandle = NULL;
UNUSED(cbarg);
if (eresult != ISC_R_SUCCESS) {
uint_fast64_t sends = atomic_load(&nsends);
/* We failed to connect; try again */
while (sends > 0) {
/* Continue until we subtract or we are done */
if (atomic_compare_exchange_weak(&nsends, &sends,
sends - 1)) {
sends--;
break;
}
}
return;
}
atomic_fetch_add(&cconnects, 1);
isc_nmhandle_attach(handle, &readhandle);
isc_nm_read(handle, tlsdns_connect_read_cb, NULL);
tlsdns_connect_send(handle);
}
static void
tlsdns_noop(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr, noop_recv_cb,
NULL, noop_accept_cb, NULL, 0, 0, NULL, tlsdns_listen_ctx,
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, noop_connect_cb, NULL,
1000, 0, tlsdns_connect_ctx);
isc_nm_closedown(connect_nm);
assert_int_equal(0, atomic_load(&cconnects));
assert_int_equal(0, atomic_load(&csends));
assert_int_equal(0, atomic_load(&creads));
assert_int_equal(0, atomic_load(&ctimeouts));
assert_int_equal(0, atomic_load(&sreads));
assert_int_equal(0, atomic_load(&ssends));
}
static void
tlsdns_noresponse(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr, noop_recv_cb,
NULL, noop_accept_cb, NULL, 0, 0, NULL, tlsdns_listen_ctx,
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
assert_true(atomic_load(&cconnects) <= 1);
assert_true(atomic_load(&csends) <= 1);
assert_int_equal(0, atomic_load(&creads));
assert_int_equal(0, atomic_load(&ctimeouts));
assert_int_equal(0, atomic_load(&sreads));
assert_int_equal(0, atomic_load(&ssends));
}
static void
tlsdns_listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg);
static void
tlsdns_listen_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
UNUSED(cbarg);
UNUSED(eresult);
assert_non_null(handle);
if (eresult != ISC_R_SUCCESS) {
return;
}
atomic_fetch_add(&ssends, 1);
}
static void
tlsdns_listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
uint64_t magic = 0;
UNUSED(cbarg);
assert_non_null(handle);
if (eresult != ISC_R_SUCCESS) {
return;
}
atomic_fetch_add(&sreads, 1);
assert_int_equal(region->length, sizeof(magic));
memmove(&magic, region->base, sizeof(magic));
assert_true(magic == stop_magic || magic == send_magic);
if (magic == send_magic) {
isc_nm_send(handle, region, tlsdns_listen_send_cb, NULL);
return;
} else if (magic == stop_magic) {
/* We are done, we don't send anything back */
}
}
static isc_result_t
tlsdns_listen_accept_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
UNUSED(handle);
UNUSED(cbarg);
return (eresult);
}
static isc_threadresult_t
tlsdns_connect_thread(isc_threadarg_t arg) {
isc_nm_t *connect_nm = (isc_nm_t *)arg;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
while (atomic_load(&nsends) > 0) {
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_connect_connect_cb, NULL, 1000, 0,
tlsdns_connect_ctx);
}
return ((isc_threadresult_t)0);
}
static void
tlsdns_recv_one(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
atomic_store(&nsends, 1);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
while (atomic_load(&nsends) > 0) {
isc_thread_yield();
}
while (atomic_load(&cconnects) != 1 || atomic_load(&ssends) != 0 ||
atomic_load(&sreads) != 1 || atomic_load(&creads) != 0 ||
atomic_load(&csends) != 1)
{
isc_thread_yield();
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
assert_int_equal(atomic_load(&cconnects), 1);
assert_int_equal(atomic_load(&csends), 1);
assert_int_equal(atomic_load(&creads), 0);
assert_int_equal(atomic_load(&ctimeouts), 0);
assert_int_equal(atomic_load(&sreads), 1);
assert_int_equal(atomic_load(&ssends), 0);
}
static void
tlsdns_recv_two(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
if (!reuse_supported) {
skip();
return;
}
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
atomic_store(&nsends, 2);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_settimeouts(connect_nm, 1000, 1000, 1000, 1000);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
assert_int_equal(result, ISC_R_SUCCESS);
while (atomic_load(&nsends) > 0) {
isc_thread_yield();
}
while (atomic_load(&sreads) != 2 || atomic_load(&ssends) != 1 ||
atomic_load(&csends) != 2 || atomic_load(&creads) != 1)
{
isc_thread_yield();
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
assert_int_equal(atomic_load(&cconnects), 2);
assert_int_equal(atomic_load(&csends), 2);
assert_int_equal(atomic_load(&creads), 1);
assert_int_equal(atomic_load(&ctimeouts), 0);
assert_int_equal(atomic_load(&sreads), 2);
assert_int_equal(atomic_load(&ssends), 1);
}
static void
tlsdns_recv_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
isc_nm_closedown(connect_nm);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_FULL(csends);
CHECK_RANGE_FULL(creads);
CHECK_RANGE_FULL(sreads);
CHECK_RANGE_FULL(ssends);
}
#if 0
static void
tlsdns_recv_half_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
while (atomic_load(&nsends) >= (NSENDS * NWRITES) / 2) {
isc_thread_yield();
}
isc_nm_closedown(connect_nm);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_HALF(csends);
CHECK_RANGE_HALF(creads);
CHECK_RANGE_HALF(sreads);
CHECK_RANGE_HALF(ssends);
}
static void
tlsdns_half_recv_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
while (atomic_load(&nsends) >= (NSENDS * NWRITES) / 2) {
isc_thread_yield();
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_HALF(csends);
CHECK_RANGE_HALF(creads);
CHECK_RANGE_HALF(sreads);
CHECK_RANGE_HALF(ssends);
}
static void
tlsdns_half_recv_half_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
while (atomic_load(&nsends) >= (NSENDS * NWRITES) / 2) {
isc_thread_yield();
}
isc_nm_closedown(connect_nm);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_HALF(csends);
CHECK_RANGE_HALF(creads);
CHECK_RANGE_HALF(sreads);
CHECK_RANGE_HALF(ssends);
}
#endif
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(tlsdns_recv_one, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_recv_two, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_noop, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_noresponse, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_recv_send, nm_setup,
nm_teardown),
#if 0
cmocka_unit_test_setup_teardown(tlsdns_recv_half_send, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_half_recv_send, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_half_recv_half_send,
nm_setup, nm_teardown),
#endif
};
return (cmocka_run_group_tests(tests, _setup, _teardown));
}
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: cmocka not available\n");
return (SKIPPED_TEST_EXIT_CODE);
}
#endif /* if HAVE_CMOCKA */