xref: /freebsd/crypto/openssl/test/radix/quic_bindings.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery #include <openssl/lhash.h>
10*e7be843bSPierre Pronchery #include <assert.h>
11*e7be843bSPierre Pronchery 
12*e7be843bSPierre Pronchery #include "internal/quic_engine.h"
13*e7be843bSPierre Pronchery #include "internal/quic_channel.h"
14*e7be843bSPierre Pronchery #include "internal/quic_ssl.h"
15*e7be843bSPierre Pronchery #include "internal/quic_error.h"
16*e7be843bSPierre Pronchery 
17*e7be843bSPierre Pronchery /*
18*e7be843bSPierre Pronchery  * RADIX 6D QUIC Test Framework
19*e7be843bSPierre Pronchery  * =============================================================================
20*e7be843bSPierre Pronchery  *
21*e7be843bSPierre Pronchery  * The radix test framework is a six-dimension script-driven facility to support
22*e7be843bSPierre Pronchery  * execution of
23*e7be843bSPierre Pronchery  *
24*e7be843bSPierre Pronchery  *   multi-stream
25*e7be843bSPierre Pronchery  *   multi-client
26*e7be843bSPierre Pronchery  *   multi-server
27*e7be843bSPierre Pronchery  *   multi-thread
28*e7be843bSPierre Pronchery  *   multi-process
29*e7be843bSPierre Pronchery  *   multi-node
30*e7be843bSPierre Pronchery  *
31*e7be843bSPierre Pronchery  * test vignettes for QUIC. Unlike the older multistream test framework, it does
32*e7be843bSPierre Pronchery  * not assume a single client and a single server. Examples of vignettes
33*e7be843bSPierre Pronchery  * designed to be supported by the radix test framework in future include:
34*e7be843bSPierre Pronchery  *
35*e7be843bSPierre Pronchery  *      single client    <-> single server
36*e7be843bSPierre Pronchery  *      multiple clients <-> single server
37*e7be843bSPierre Pronchery  *      single client    <-> multiple servers
38*e7be843bSPierre Pronchery  *      multiple clients <-> multiple servers
39*e7be843bSPierre Pronchery  *
40*e7be843bSPierre Pronchery  * 'Multi-process' and 'multi-node' means there has been some consideration
41*e7be843bSPierre Pronchery  * given to support of multi-process and multi-node testing in the future,
42*e7be843bSPierre Pronchery  * though this is not currently supported.
43*e7be843bSPierre Pronchery  */
44*e7be843bSPierre Pronchery 
45*e7be843bSPierre Pronchery /*
46*e7be843bSPierre Pronchery  * An object is something associated with a name in the process-level state. The
47*e7be843bSPierre Pronchery  * process-level state primarily revolves around a global dictionary of SSL
48*e7be843bSPierre Pronchery  * objects.
49*e7be843bSPierre Pronchery  */
50*e7be843bSPierre Pronchery typedef struct radix_obj_st {
51*e7be843bSPierre Pronchery     char                *name;  /* owned, zero-terminated */
52*e7be843bSPierre Pronchery     SSL                 *ssl;   /* owns one reference */
53*e7be843bSPierre Pronchery     unsigned int        registered      : 1; /* in LHASH? */
54*e7be843bSPierre Pronchery     unsigned int        active          : 1; /* tick? */
55*e7be843bSPierre Pronchery } RADIX_OBJ;
56*e7be843bSPierre Pronchery 
57*e7be843bSPierre Pronchery DEFINE_LHASH_OF_EX(RADIX_OBJ);
58*e7be843bSPierre Pronchery 
59*e7be843bSPierre Pronchery /* Process-level state (i.e. "globals" in the normal sense of the word) */
60*e7be843bSPierre Pronchery typedef struct radix_process_st {
61*e7be843bSPierre Pronchery     size_t                  node_idx;
62*e7be843bSPierre Pronchery     size_t                  process_idx;
63*e7be843bSPierre Pronchery     size_t                  next_thread_idx;
64*e7be843bSPierre Pronchery     STACK_OF(RADIX_THREAD)  *threads;
65*e7be843bSPierre Pronchery 
66*e7be843bSPierre Pronchery     /* Process-global state. */
67*e7be843bSPierre Pronchery     CRYPTO_MUTEX            *gm;            /* global mutex */
68*e7be843bSPierre Pronchery     LHASH_OF(RADIX_OBJ)     *objs;          /* protected by gm */
69*e7be843bSPierre Pronchery     OSSL_TIME               time_slip;      /* protected by gm */
70*e7be843bSPierre Pronchery     BIO                     *keylog_out;    /* protected by gm */
71*e7be843bSPierre Pronchery 
72*e7be843bSPierre Pronchery     int                     done_join_all_threads;
73*e7be843bSPierre Pronchery 
74*e7be843bSPierre Pronchery     /*
75*e7be843bSPierre Pronchery      * Valid if done_join_all threads. Logical AND of all child worker results.
76*e7be843bSPierre Pronchery      */
77*e7be843bSPierre Pronchery     int                     thread_composite_testresult;
78*e7be843bSPierre Pronchery } RADIX_PROCESS;
79*e7be843bSPierre Pronchery 
80*e7be843bSPierre Pronchery #define NUM_SLOTS       8
81*e7be843bSPierre Pronchery 
82*e7be843bSPierre Pronchery /* Thread-level state within a process */
83*e7be843bSPierre Pronchery typedef struct radix_thread_st {
84*e7be843bSPierre Pronchery     RADIX_PROCESS       *rp;
85*e7be843bSPierre Pronchery     CRYPTO_THREAD       *t;
86*e7be843bSPierre Pronchery     unsigned char       *tmp_buf;
87*e7be843bSPierre Pronchery     size_t              tmp_buf_offset;
88*e7be843bSPierre Pronchery     size_t              thread_idx; /* 0=main thread */
89*e7be843bSPierre Pronchery     RADIX_OBJ           *slot[NUM_SLOTS];
90*e7be843bSPierre Pronchery     SSL                 *ssl[NUM_SLOTS];
91*e7be843bSPierre Pronchery 
92*e7be843bSPierre Pronchery     /* child thread spawn arguments */
93*e7be843bSPierre Pronchery     SCRIPT_INFO         *child_script_info;
94*e7be843bSPierre Pronchery     BIO                 *debug_bio;
95*e7be843bSPierre Pronchery 
96*e7be843bSPierre Pronchery     /* m protects all of the below values */
97*e7be843bSPierre Pronchery     CRYPTO_MUTEX        *m;
98*e7be843bSPierre Pronchery     int                 done;
99*e7be843bSPierre Pronchery     int                 testresult; /* valid if done */
100*e7be843bSPierre Pronchery 
101*e7be843bSPierre Pronchery     uint64_t            scratch0;
102*e7be843bSPierre Pronchery } RADIX_THREAD;
103*e7be843bSPierre Pronchery 
DEFINE_STACK_OF(RADIX_THREAD)104*e7be843bSPierre Pronchery DEFINE_STACK_OF(RADIX_THREAD)
105*e7be843bSPierre Pronchery 
106*e7be843bSPierre Pronchery /* ssl reference is transferred. name is copied and is required. */
107*e7be843bSPierre Pronchery static RADIX_OBJ *RADIX_OBJ_new(const char *name, SSL *ssl)
108*e7be843bSPierre Pronchery {
109*e7be843bSPierre Pronchery     RADIX_OBJ *obj;
110*e7be843bSPierre Pronchery 
111*e7be843bSPierre Pronchery     if (!TEST_ptr(name) || !TEST_ptr(ssl))
112*e7be843bSPierre Pronchery         return NULL;
113*e7be843bSPierre Pronchery 
114*e7be843bSPierre Pronchery     if (!TEST_ptr(obj = OPENSSL_zalloc(sizeof(*obj))))
115*e7be843bSPierre Pronchery        return NULL;
116*e7be843bSPierre Pronchery 
117*e7be843bSPierre Pronchery     if (!TEST_ptr(obj->name = OPENSSL_strdup(name))) {
118*e7be843bSPierre Pronchery         OPENSSL_free(obj);
119*e7be843bSPierre Pronchery         return NULL;
120*e7be843bSPierre Pronchery     }
121*e7be843bSPierre Pronchery 
122*e7be843bSPierre Pronchery     obj->ssl  = ssl;
123*e7be843bSPierre Pronchery     return obj;
124*e7be843bSPierre Pronchery }
125*e7be843bSPierre Pronchery 
RADIX_OBJ_free(RADIX_OBJ * obj)126*e7be843bSPierre Pronchery static void RADIX_OBJ_free(RADIX_OBJ *obj)
127*e7be843bSPierre Pronchery {
128*e7be843bSPierre Pronchery     if (obj == NULL)
129*e7be843bSPierre Pronchery         return;
130*e7be843bSPierre Pronchery 
131*e7be843bSPierre Pronchery     assert(!obj->registered);
132*e7be843bSPierre Pronchery 
133*e7be843bSPierre Pronchery     SSL_free(obj->ssl);
134*e7be843bSPierre Pronchery     OPENSSL_free(obj->name);
135*e7be843bSPierre Pronchery     OPENSSL_free(obj);
136*e7be843bSPierre Pronchery }
137*e7be843bSPierre Pronchery 
RADIX_OBJ_hash(const RADIX_OBJ * obj)138*e7be843bSPierre Pronchery static unsigned long RADIX_OBJ_hash(const RADIX_OBJ *obj)
139*e7be843bSPierre Pronchery {
140*e7be843bSPierre Pronchery     return OPENSSL_LH_strhash(obj->name);
141*e7be843bSPierre Pronchery }
142*e7be843bSPierre Pronchery 
RADIX_OBJ_cmp(const RADIX_OBJ * a,const RADIX_OBJ * b)143*e7be843bSPierre Pronchery static int RADIX_OBJ_cmp(const RADIX_OBJ *a, const RADIX_OBJ *b)
144*e7be843bSPierre Pronchery {
145*e7be843bSPierre Pronchery     return strcmp(a->name, b->name);
146*e7be843bSPierre Pronchery }
147*e7be843bSPierre Pronchery 
RADIX_PROCESS_init(RADIX_PROCESS * rp,size_t node_idx,size_t process_idx)148*e7be843bSPierre Pronchery static int RADIX_PROCESS_init(RADIX_PROCESS *rp, size_t node_idx, size_t process_idx)
149*e7be843bSPierre Pronchery {
150*e7be843bSPierre Pronchery     const char *keylog_path;
151*e7be843bSPierre Pronchery 
152*e7be843bSPierre Pronchery #if defined(OPENSSL_THREADS)
153*e7be843bSPierre Pronchery     if (!TEST_ptr(rp->gm = ossl_crypto_mutex_new()))
154*e7be843bSPierre Pronchery         goto err;
155*e7be843bSPierre Pronchery #endif
156*e7be843bSPierre Pronchery 
157*e7be843bSPierre Pronchery     if (!TEST_ptr(rp->objs = lh_RADIX_OBJ_new(RADIX_OBJ_hash, RADIX_OBJ_cmp)))
158*e7be843bSPierre Pronchery         goto err;
159*e7be843bSPierre Pronchery 
160*e7be843bSPierre Pronchery     if (!TEST_ptr(rp->threads = sk_RADIX_THREAD_new(NULL)))
161*e7be843bSPierre Pronchery         goto err;
162*e7be843bSPierre Pronchery 
163*e7be843bSPierre Pronchery     rp->keylog_out = NULL;
164*e7be843bSPierre Pronchery     keylog_path = ossl_safe_getenv("SSLKEYLOGFILE");
165*e7be843bSPierre Pronchery     if (keylog_path != NULL && *keylog_path != '\0'
166*e7be843bSPierre Pronchery         && !TEST_ptr(rp->keylog_out = BIO_new_file(keylog_path, "a")))
167*e7be843bSPierre Pronchery         goto err;
168*e7be843bSPierre Pronchery 
169*e7be843bSPierre Pronchery     rp->node_idx                = node_idx;
170*e7be843bSPierre Pronchery     rp->process_idx             = process_idx;
171*e7be843bSPierre Pronchery     rp->done_join_all_threads   = 0;
172*e7be843bSPierre Pronchery     rp->next_thread_idx         = 0;
173*e7be843bSPierre Pronchery     return 1;
174*e7be843bSPierre Pronchery 
175*e7be843bSPierre Pronchery err:
176*e7be843bSPierre Pronchery     lh_RADIX_OBJ_free(rp->objs);
177*e7be843bSPierre Pronchery     rp->objs = NULL;
178*e7be843bSPierre Pronchery     ossl_crypto_mutex_free(&rp->gm);
179*e7be843bSPierre Pronchery     return 0;
180*e7be843bSPierre Pronchery }
181*e7be843bSPierre Pronchery 
stream_state_to_str(int state)182*e7be843bSPierre Pronchery static const char *stream_state_to_str(int state)
183*e7be843bSPierre Pronchery {
184*e7be843bSPierre Pronchery     switch (state) {
185*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_NONE:
186*e7be843bSPierre Pronchery         return "none";
187*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_OK:
188*e7be843bSPierre Pronchery         return "OK";
189*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_WRONG_DIR:
190*e7be843bSPierre Pronchery         return "wrong-dir";
191*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_FINISHED:
192*e7be843bSPierre Pronchery         return "finished";
193*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_RESET_LOCAL:
194*e7be843bSPierre Pronchery         return "reset-local";
195*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_RESET_REMOTE:
196*e7be843bSPierre Pronchery         return "reset-remote";
197*e7be843bSPierre Pronchery     case SSL_STREAM_STATE_CONN_CLOSED:
198*e7be843bSPierre Pronchery         return "conn-closed";
199*e7be843bSPierre Pronchery     default:
200*e7be843bSPierre Pronchery         return "?";
201*e7be843bSPierre Pronchery     }
202*e7be843bSPierre Pronchery }
203*e7be843bSPierre Pronchery 
report_ssl_state(BIO * bio,const char * pfx,int is_write,int state,uint64_t ec)204*e7be843bSPierre Pronchery static void report_ssl_state(BIO *bio, const char *pfx, int is_write,
205*e7be843bSPierre Pronchery                              int state, uint64_t ec)
206*e7be843bSPierre Pronchery {
207*e7be843bSPierre Pronchery     const char *state_s = stream_state_to_str(state);
208*e7be843bSPierre Pronchery 
209*e7be843bSPierre Pronchery     BIO_printf(bio, "%s%-15s%s(%d)", pfx, is_write ? "Write state: " : "Read state: ",
210*e7be843bSPierre Pronchery         state_s, state);
211*e7be843bSPierre Pronchery     if (ec != UINT64_MAX)
212*e7be843bSPierre Pronchery         BIO_printf(bio, ", %llu", (unsigned long long)ec);
213*e7be843bSPierre Pronchery     BIO_printf(bio, "\n");
214*e7be843bSPierre Pronchery }
215*e7be843bSPierre Pronchery 
report_ssl(SSL * ssl,BIO * bio,const char * pfx)216*e7be843bSPierre Pronchery static void report_ssl(SSL *ssl, BIO *bio, const char *pfx)
217*e7be843bSPierre Pronchery {
218*e7be843bSPierre Pronchery     const char *type = "SSL";
219*e7be843bSPierre Pronchery     int is_quic = SSL_is_quic(ssl), is_conn = 0, is_listener = 0;
220*e7be843bSPierre Pronchery     SSL_CONN_CLOSE_INFO cc_info = {0};
221*e7be843bSPierre Pronchery     const char *e_str, *f_str;
222*e7be843bSPierre Pronchery 
223*e7be843bSPierre Pronchery     if (is_quic) {
224*e7be843bSPierre Pronchery         is_conn = SSL_is_connection(ssl);
225*e7be843bSPierre Pronchery         is_listener = SSL_is_listener(ssl);
226*e7be843bSPierre Pronchery 
227*e7be843bSPierre Pronchery         if (is_listener)
228*e7be843bSPierre Pronchery             type = "QLSO";
229*e7be843bSPierre Pronchery         else if (is_conn)
230*e7be843bSPierre Pronchery             type = "QCSO";
231*e7be843bSPierre Pronchery         else
232*e7be843bSPierre Pronchery             type = "QSSO";
233*e7be843bSPierre Pronchery     }
234*e7be843bSPierre Pronchery 
235*e7be843bSPierre Pronchery     BIO_printf(bio, "%sType:          %s\n", pfx, type);
236*e7be843bSPierre Pronchery 
237*e7be843bSPierre Pronchery     if (is_quic && is_conn
238*e7be843bSPierre Pronchery         && SSL_get_conn_close_info(ssl, &cc_info, sizeof(cc_info))) {
239*e7be843bSPierre Pronchery 
240*e7be843bSPierre Pronchery         e_str = ossl_quic_err_to_string(cc_info.error_code);
241*e7be843bSPierre Pronchery         f_str = ossl_quic_frame_type_to_string(cc_info.frame_type);
242*e7be843bSPierre Pronchery 
243*e7be843bSPierre Pronchery         if (e_str == NULL)
244*e7be843bSPierre Pronchery             e_str = "?";
245*e7be843bSPierre Pronchery         if (f_str == NULL)
246*e7be843bSPierre Pronchery             f_str = "?";
247*e7be843bSPierre Pronchery 
248*e7be843bSPierre Pronchery         BIO_printf(bio, "%sConnection is closed: %s(%llu)/%s(%llu), "
249*e7be843bSPierre Pronchery                    "%s, %s, reason: \"%s\"\n",
250*e7be843bSPierre Pronchery                    pfx,
251*e7be843bSPierre Pronchery                    e_str,
252*e7be843bSPierre Pronchery                    (unsigned long long)cc_info.error_code,
253*e7be843bSPierre Pronchery                    f_str,
254*e7be843bSPierre Pronchery                    (unsigned long long)cc_info.frame_type,
255*e7be843bSPierre Pronchery                    (cc_info.flags & SSL_CONN_CLOSE_FLAG_LOCAL) != 0
256*e7be843bSPierre Pronchery                      ? "local" : "remote",
257*e7be843bSPierre Pronchery                    (cc_info.flags & SSL_CONN_CLOSE_FLAG_TRANSPORT) != 0
258*e7be843bSPierre Pronchery                      ? "transport" : "app",
259*e7be843bSPierre Pronchery                    cc_info.reason != NULL ? cc_info.reason : "-");
260*e7be843bSPierre Pronchery     }
261*e7be843bSPierre Pronchery 
262*e7be843bSPierre Pronchery     if (is_quic && !is_listener) {
263*e7be843bSPierre Pronchery         uint64_t stream_id = SSL_get_stream_id(ssl), rec, wec;
264*e7be843bSPierre Pronchery         int rstate, wstate;
265*e7be843bSPierre Pronchery 
266*e7be843bSPierre Pronchery         if (stream_id != UINT64_MAX)
267*e7be843bSPierre Pronchery             BIO_printf(bio, "%sStream ID: %llu\n", pfx,
268*e7be843bSPierre Pronchery                        (unsigned long long)stream_id);
269*e7be843bSPierre Pronchery 
270*e7be843bSPierre Pronchery         rstate = SSL_get_stream_read_state(ssl);
271*e7be843bSPierre Pronchery         wstate = SSL_get_stream_write_state(ssl);
272*e7be843bSPierre Pronchery 
273*e7be843bSPierre Pronchery         if (SSL_get_stream_read_error_code(ssl, &rec) != 1)
274*e7be843bSPierre Pronchery             rec = UINT64_MAX;
275*e7be843bSPierre Pronchery 
276*e7be843bSPierre Pronchery         if (SSL_get_stream_write_error_code(ssl, &wec) != 1)
277*e7be843bSPierre Pronchery             wec = UINT64_MAX;
278*e7be843bSPierre Pronchery 
279*e7be843bSPierre Pronchery         report_ssl_state(bio, pfx, 0, rstate, rec);
280*e7be843bSPierre Pronchery         report_ssl_state(bio, pfx, 1, wstate, wec);
281*e7be843bSPierre Pronchery     }
282*e7be843bSPierre Pronchery }
283*e7be843bSPierre Pronchery 
report_obj(RADIX_OBJ * obj,void * arg)284*e7be843bSPierre Pronchery static void report_obj(RADIX_OBJ *obj, void *arg)
285*e7be843bSPierre Pronchery {
286*e7be843bSPierre Pronchery     BIO *bio = arg;
287*e7be843bSPierre Pronchery     SSL *ssl = obj->ssl;
288*e7be843bSPierre Pronchery 
289*e7be843bSPierre Pronchery     BIO_printf(bio, "      - %-16s @ %p\n", obj->name, (void *)obj->ssl);
290*e7be843bSPierre Pronchery     ERR_set_mark();
291*e7be843bSPierre Pronchery     report_ssl(ssl, bio, "          ");
292*e7be843bSPierre Pronchery     ERR_pop_to_mark();
293*e7be843bSPierre Pronchery }
294*e7be843bSPierre Pronchery 
RADIX_THREAD_report_state(RADIX_THREAD * rt,BIO * bio)295*e7be843bSPierre Pronchery static void RADIX_THREAD_report_state(RADIX_THREAD *rt, BIO *bio)
296*e7be843bSPierre Pronchery {
297*e7be843bSPierre Pronchery     size_t i;
298*e7be843bSPierre Pronchery 
299*e7be843bSPierre Pronchery     BIO_printf(bio, "  Slots:\n");
300*e7be843bSPierre Pronchery     for (i = 0; i < NUM_SLOTS; ++i)
301*e7be843bSPierre Pronchery         if (rt->slot[i] == NULL)
302*e7be843bSPierre Pronchery             BIO_printf(bio, "  %3zu) <NULL>\n", i);
303*e7be843bSPierre Pronchery         else
304*e7be843bSPierre Pronchery             BIO_printf(bio, "  %3zu) '%s' (SSL: %p)\n", i,
305*e7be843bSPierre Pronchery                        rt->slot[i]->name,
306*e7be843bSPierre Pronchery                        (void *)rt->ssl[i]);
307*e7be843bSPierre Pronchery }
308*e7be843bSPierre Pronchery 
RADIX_PROCESS_report_state(RADIX_PROCESS * rp,BIO * bio,int verbose)309*e7be843bSPierre Pronchery static void RADIX_PROCESS_report_state(RADIX_PROCESS *rp, BIO *bio,
310*e7be843bSPierre Pronchery                                        int verbose)
311*e7be843bSPierre Pronchery {
312*e7be843bSPierre Pronchery     BIO_printf(bio, "Final process state for node %zu, process %zu:\n",
313*e7be843bSPierre Pronchery                rp->node_idx, rp->process_idx);
314*e7be843bSPierre Pronchery 
315*e7be843bSPierre Pronchery     BIO_printf(bio, "  Threads (incl. main):        %zu\n",
316*e7be843bSPierre Pronchery                rp->next_thread_idx);
317*e7be843bSPierre Pronchery     BIO_printf(bio, "  Time slip:                   %llu ms\n",
318*e7be843bSPierre Pronchery                (unsigned long long)ossl_time2ms(rp->time_slip));
319*e7be843bSPierre Pronchery 
320*e7be843bSPierre Pronchery     BIO_printf(bio, "  Objects:\n");
321*e7be843bSPierre Pronchery     lh_RADIX_OBJ_doall_arg(rp->objs, report_obj, bio);
322*e7be843bSPierre Pronchery 
323*e7be843bSPierre Pronchery     if (verbose)
324*e7be843bSPierre Pronchery         RADIX_THREAD_report_state(sk_RADIX_THREAD_value(rp->threads, 0),
325*e7be843bSPierre Pronchery                                   bio_err);
326*e7be843bSPierre Pronchery 
327*e7be843bSPierre Pronchery     BIO_printf(bio, "\n==========================================="
328*e7be843bSPierre Pronchery                "===========================\n");
329*e7be843bSPierre Pronchery }
330*e7be843bSPierre Pronchery 
RADIX_PROCESS_report_thread_results(RADIX_PROCESS * rp,BIO * bio)331*e7be843bSPierre Pronchery static void RADIX_PROCESS_report_thread_results(RADIX_PROCESS *rp, BIO *bio)
332*e7be843bSPierre Pronchery {
333*e7be843bSPierre Pronchery     size_t i;
334*e7be843bSPierre Pronchery     RADIX_THREAD *rt;
335*e7be843bSPierre Pronchery     char *p;
336*e7be843bSPierre Pronchery     long l;
337*e7be843bSPierre Pronchery     char pfx_buf[64];
338*e7be843bSPierre Pronchery     int rt_testresult;
339*e7be843bSPierre Pronchery 
340*e7be843bSPierre Pronchery     for (i = 1; i < (size_t)sk_RADIX_THREAD_num(rp->threads); ++i) {
341*e7be843bSPierre Pronchery         rt = sk_RADIX_THREAD_value(rp->threads, i);
342*e7be843bSPierre Pronchery 
343*e7be843bSPierre Pronchery         ossl_crypto_mutex_lock(rt->m);
344*e7be843bSPierre Pronchery         assert(rt->done);
345*e7be843bSPierre Pronchery         rt_testresult = rt->testresult;
346*e7be843bSPierre Pronchery         ossl_crypto_mutex_unlock(rt->m);
347*e7be843bSPierre Pronchery 
348*e7be843bSPierre Pronchery         BIO_printf(bio, "\n====(n%zu/p%zu/t%zu)============================"
349*e7be843bSPierre Pronchery                    "===========================\n"
350*e7be843bSPierre Pronchery                    "Result for child thread with index %zu:\n",
351*e7be843bSPierre Pronchery                    rp->node_idx, rp->process_idx, rt->thread_idx, rt->thread_idx);
352*e7be843bSPierre Pronchery 
353*e7be843bSPierre Pronchery         BIO_snprintf(pfx_buf, sizeof(pfx_buf), "#  -T-%2zu:\t# ", rt->thread_idx);
354*e7be843bSPierre Pronchery         BIO_set_prefix(bio_err, pfx_buf);
355*e7be843bSPierre Pronchery 
356*e7be843bSPierre Pronchery         l = BIO_get_mem_data(rt->debug_bio, &p);
357*e7be843bSPierre Pronchery         BIO_write(bio, p, l);
358*e7be843bSPierre Pronchery         BIO_printf(bio, "\n");
359*e7be843bSPierre Pronchery         BIO_set_prefix(bio_err, "# ");
360*e7be843bSPierre Pronchery         BIO_printf(bio, "==> Child thread with index %zu exited with %d\n",
361*e7be843bSPierre Pronchery                    rt->thread_idx, rt_testresult);
362*e7be843bSPierre Pronchery         if (!rt_testresult)
363*e7be843bSPierre Pronchery             RADIX_THREAD_report_state(rt, bio);
364*e7be843bSPierre Pronchery     }
365*e7be843bSPierre Pronchery 
366*e7be843bSPierre Pronchery     BIO_printf(bio, "\n==========================================="
367*e7be843bSPierre Pronchery                "===========================\n");
368*e7be843bSPierre Pronchery }
369*e7be843bSPierre Pronchery 
370*e7be843bSPierre Pronchery static int RADIX_THREAD_join(RADIX_THREAD *rt);
371*e7be843bSPierre Pronchery 
RADIX_PROCESS_join_all_threads(RADIX_PROCESS * rp,int * testresult)372*e7be843bSPierre Pronchery static int RADIX_PROCESS_join_all_threads(RADIX_PROCESS *rp, int *testresult)
373*e7be843bSPierre Pronchery {
374*e7be843bSPierre Pronchery     int ok = 1;
375*e7be843bSPierre Pronchery     size_t i;
376*e7be843bSPierre Pronchery     RADIX_THREAD *rt;
377*e7be843bSPierre Pronchery     int composite_testresult = 1;
378*e7be843bSPierre Pronchery 
379*e7be843bSPierre Pronchery     if (rp->done_join_all_threads) {
380*e7be843bSPierre Pronchery         *testresult = rp->thread_composite_testresult;
381*e7be843bSPierre Pronchery         return 1;
382*e7be843bSPierre Pronchery     }
383*e7be843bSPierre Pronchery 
384*e7be843bSPierre Pronchery     for (i = 1; i < (size_t)sk_RADIX_THREAD_num(rp->threads); ++i) {
385*e7be843bSPierre Pronchery         rt = sk_RADIX_THREAD_value(rp->threads, i);
386*e7be843bSPierre Pronchery 
387*e7be843bSPierre Pronchery         BIO_printf(bio_err, "==> Joining thread %zu\n", i);
388*e7be843bSPierre Pronchery 
389*e7be843bSPierre Pronchery         if (!TEST_true(RADIX_THREAD_join(rt)))
390*e7be843bSPierre Pronchery             ok = 0;
391*e7be843bSPierre Pronchery 
392*e7be843bSPierre Pronchery         if (!rt->testresult)
393*e7be843bSPierre Pronchery             composite_testresult = 0;
394*e7be843bSPierre Pronchery     }
395*e7be843bSPierre Pronchery 
396*e7be843bSPierre Pronchery     rp->thread_composite_testresult = composite_testresult;
397*e7be843bSPierre Pronchery     *testresult                     = composite_testresult;
398*e7be843bSPierre Pronchery     rp->done_join_all_threads       = 1;
399*e7be843bSPierre Pronchery 
400*e7be843bSPierre Pronchery     RADIX_PROCESS_report_thread_results(rp, bio_err);
401*e7be843bSPierre Pronchery     return ok;
402*e7be843bSPierre Pronchery }
403*e7be843bSPierre Pronchery 
cleanup_one(RADIX_OBJ * obj)404*e7be843bSPierre Pronchery static void cleanup_one(RADIX_OBJ *obj)
405*e7be843bSPierre Pronchery {
406*e7be843bSPierre Pronchery     obj->registered = 0;
407*e7be843bSPierre Pronchery     RADIX_OBJ_free(obj);
408*e7be843bSPierre Pronchery }
409*e7be843bSPierre Pronchery 
410*e7be843bSPierre Pronchery static void RADIX_THREAD_free(RADIX_THREAD *rt);
411*e7be843bSPierre Pronchery 
RADIX_PROCESS_cleanup(RADIX_PROCESS * rp)412*e7be843bSPierre Pronchery static void RADIX_PROCESS_cleanup(RADIX_PROCESS *rp)
413*e7be843bSPierre Pronchery {
414*e7be843bSPierre Pronchery     size_t i;
415*e7be843bSPierre Pronchery 
416*e7be843bSPierre Pronchery     assert(rp->done_join_all_threads);
417*e7be843bSPierre Pronchery 
418*e7be843bSPierre Pronchery     for (i = 0; i < (size_t)sk_RADIX_THREAD_num(rp->threads); ++i)
419*e7be843bSPierre Pronchery         RADIX_THREAD_free(sk_RADIX_THREAD_value(rp->threads, i));
420*e7be843bSPierre Pronchery 
421*e7be843bSPierre Pronchery     sk_RADIX_THREAD_free(rp->threads);
422*e7be843bSPierre Pronchery     rp->threads = NULL;
423*e7be843bSPierre Pronchery 
424*e7be843bSPierre Pronchery     lh_RADIX_OBJ_doall(rp->objs, cleanup_one);
425*e7be843bSPierre Pronchery     lh_RADIX_OBJ_free(rp->objs);
426*e7be843bSPierre Pronchery     rp->objs = NULL;
427*e7be843bSPierre Pronchery 
428*e7be843bSPierre Pronchery     BIO_free_all(rp->keylog_out);
429*e7be843bSPierre Pronchery     rp->keylog_out = NULL;
430*e7be843bSPierre Pronchery     ossl_crypto_mutex_free(&rp->gm);
431*e7be843bSPierre Pronchery }
432*e7be843bSPierre Pronchery 
RADIX_PROCESS_get_obj(RADIX_PROCESS * rp,const char * name)433*e7be843bSPierre Pronchery static RADIX_OBJ *RADIX_PROCESS_get_obj(RADIX_PROCESS *rp, const char *name)
434*e7be843bSPierre Pronchery {
435*e7be843bSPierre Pronchery     RADIX_OBJ key;
436*e7be843bSPierre Pronchery 
437*e7be843bSPierre Pronchery     key.name = (char *)name;
438*e7be843bSPierre Pronchery     return lh_RADIX_OBJ_retrieve(rp->objs, &key);
439*e7be843bSPierre Pronchery }
440*e7be843bSPierre Pronchery 
RADIX_PROCESS_set_obj(RADIX_PROCESS * rp,const char * name,RADIX_OBJ * obj)441*e7be843bSPierre Pronchery static int RADIX_PROCESS_set_obj(RADIX_PROCESS *rp,
442*e7be843bSPierre Pronchery                                  const char *name, RADIX_OBJ *obj)
443*e7be843bSPierre Pronchery {
444*e7be843bSPierre Pronchery     RADIX_OBJ *existing;
445*e7be843bSPierre Pronchery 
446*e7be843bSPierre Pronchery     if (obj != NULL && !TEST_false(obj->registered))
447*e7be843bSPierre Pronchery         return 0;
448*e7be843bSPierre Pronchery 
449*e7be843bSPierre Pronchery     existing = RADIX_PROCESS_get_obj(rp, name);
450*e7be843bSPierre Pronchery     if (existing != NULL && obj != existing) {
451*e7be843bSPierre Pronchery         if (!TEST_true(existing->registered))
452*e7be843bSPierre Pronchery             return 0;
453*e7be843bSPierre Pronchery 
454*e7be843bSPierre Pronchery         lh_RADIX_OBJ_delete(rp->objs, existing);
455*e7be843bSPierre Pronchery         existing->registered = 0;
456*e7be843bSPierre Pronchery         RADIX_OBJ_free(existing);
457*e7be843bSPierre Pronchery     }
458*e7be843bSPierre Pronchery 
459*e7be843bSPierre Pronchery     if (obj != NULL) {
460*e7be843bSPierre Pronchery         lh_RADIX_OBJ_insert(rp->objs, obj);
461*e7be843bSPierre Pronchery         obj->registered = 1;
462*e7be843bSPierre Pronchery     }
463*e7be843bSPierre Pronchery 
464*e7be843bSPierre Pronchery     return 1;
465*e7be843bSPierre Pronchery }
466*e7be843bSPierre Pronchery 
RADIX_PROCESS_set_ssl(RADIX_PROCESS * rp,const char * name,SSL * ssl)467*e7be843bSPierre Pronchery static int RADIX_PROCESS_set_ssl(RADIX_PROCESS *rp, const char *name, SSL *ssl)
468*e7be843bSPierre Pronchery {
469*e7be843bSPierre Pronchery     RADIX_OBJ *obj;
470*e7be843bSPierre Pronchery 
471*e7be843bSPierre Pronchery     if (!TEST_ptr(obj = RADIX_OBJ_new(name, ssl)))
472*e7be843bSPierre Pronchery         return 0;
473*e7be843bSPierre Pronchery 
474*e7be843bSPierre Pronchery     if (!TEST_true(RADIX_PROCESS_set_obj(rp, name, obj))) {
475*e7be843bSPierre Pronchery         RADIX_OBJ_free(obj);
476*e7be843bSPierre Pronchery         return 0;
477*e7be843bSPierre Pronchery     }
478*e7be843bSPierre Pronchery 
479*e7be843bSPierre Pronchery     return 1;
480*e7be843bSPierre Pronchery }
481*e7be843bSPierre Pronchery 
RADIX_PROCESS_get_ssl(RADIX_PROCESS * rp,const char * name)482*e7be843bSPierre Pronchery static SSL *RADIX_PROCESS_get_ssl(RADIX_PROCESS *rp, const char *name)
483*e7be843bSPierre Pronchery {
484*e7be843bSPierre Pronchery     RADIX_OBJ *obj = RADIX_PROCESS_get_obj(rp, name);
485*e7be843bSPierre Pronchery 
486*e7be843bSPierre Pronchery     if (obj == NULL)
487*e7be843bSPierre Pronchery         return NULL;
488*e7be843bSPierre Pronchery 
489*e7be843bSPierre Pronchery     return obj->ssl;
490*e7be843bSPierre Pronchery }
491*e7be843bSPierre Pronchery 
RADIX_THREAD_new(RADIX_PROCESS * rp)492*e7be843bSPierre Pronchery static RADIX_THREAD *RADIX_THREAD_new(RADIX_PROCESS *rp)
493*e7be843bSPierre Pronchery {
494*e7be843bSPierre Pronchery     RADIX_THREAD *rt;
495*e7be843bSPierre Pronchery 
496*e7be843bSPierre Pronchery     if (!TEST_ptr(rp)
497*e7be843bSPierre Pronchery         || !TEST_ptr(rt = OPENSSL_zalloc(sizeof(*rt))))
498*e7be843bSPierre Pronchery         return 0;
499*e7be843bSPierre Pronchery 
500*e7be843bSPierre Pronchery     rt->rp          = rp;
501*e7be843bSPierre Pronchery 
502*e7be843bSPierre Pronchery #if defined(OPENSSL_THREADS)
503*e7be843bSPierre Pronchery     if (!TEST_ptr(rt->m = ossl_crypto_mutex_new())) {
504*e7be843bSPierre Pronchery         OPENSSL_free(rt);
505*e7be843bSPierre Pronchery         return 0;
506*e7be843bSPierre Pronchery     }
507*e7be843bSPierre Pronchery #endif
508*e7be843bSPierre Pronchery 
509*e7be843bSPierre Pronchery     if (!TEST_true(sk_RADIX_THREAD_push(rp->threads, rt))) {
510*e7be843bSPierre Pronchery         OPENSSL_free(rt);
511*e7be843bSPierre Pronchery         return 0;
512*e7be843bSPierre Pronchery     }
513*e7be843bSPierre Pronchery 
514*e7be843bSPierre Pronchery     rt->thread_idx  = rp->next_thread_idx++;
515*e7be843bSPierre Pronchery     assert(rt->thread_idx + 1 == (size_t)sk_RADIX_THREAD_num(rp->threads));
516*e7be843bSPierre Pronchery     return rt;
517*e7be843bSPierre Pronchery }
518*e7be843bSPierre Pronchery 
RADIX_THREAD_free(RADIX_THREAD * rt)519*e7be843bSPierre Pronchery static void RADIX_THREAD_free(RADIX_THREAD *rt)
520*e7be843bSPierre Pronchery {
521*e7be843bSPierre Pronchery     if (rt == NULL)
522*e7be843bSPierre Pronchery         return;
523*e7be843bSPierre Pronchery 
524*e7be843bSPierre Pronchery     assert(rt->t == NULL);
525*e7be843bSPierre Pronchery     BIO_free_all(rt->debug_bio);
526*e7be843bSPierre Pronchery     OPENSSL_free(rt->tmp_buf);
527*e7be843bSPierre Pronchery     ossl_crypto_mutex_free(&rt->m);
528*e7be843bSPierre Pronchery     OPENSSL_free(rt);
529*e7be843bSPierre Pronchery }
530*e7be843bSPierre Pronchery 
RADIX_THREAD_join(RADIX_THREAD * rt)531*e7be843bSPierre Pronchery static int RADIX_THREAD_join(RADIX_THREAD *rt)
532*e7be843bSPierre Pronchery {
533*e7be843bSPierre Pronchery     CRYPTO_THREAD_RETVAL rv;
534*e7be843bSPierre Pronchery 
535*e7be843bSPierre Pronchery     if (rt->t != NULL)
536*e7be843bSPierre Pronchery         ossl_crypto_thread_native_join(rt->t, &rv);
537*e7be843bSPierre Pronchery 
538*e7be843bSPierre Pronchery     ossl_crypto_thread_native_clean(rt->t);
539*e7be843bSPierre Pronchery     rt->t = NULL;
540*e7be843bSPierre Pronchery 
541*e7be843bSPierre Pronchery     if (!TEST_true(rt->done))
542*e7be843bSPierre Pronchery         return 0;
543*e7be843bSPierre Pronchery 
544*e7be843bSPierre Pronchery     return 1;
545*e7be843bSPierre Pronchery }
546*e7be843bSPierre Pronchery 
547*e7be843bSPierre Pronchery static RADIX_PROCESS        radix_process;
548*e7be843bSPierre Pronchery static CRYPTO_THREAD_LOCAL  radix_thread;
549*e7be843bSPierre Pronchery 
radix_thread_cleanup_tl(void * p)550*e7be843bSPierre Pronchery static void radix_thread_cleanup_tl(void *p)
551*e7be843bSPierre Pronchery {
552*e7be843bSPierre Pronchery     /* Should already have been cleaned up. */
553*e7be843bSPierre Pronchery     if (!TEST_ptr_null(p))
554*e7be843bSPierre Pronchery         abort();
555*e7be843bSPierre Pronchery }
556*e7be843bSPierre Pronchery 
radix_get_thread(void)557*e7be843bSPierre Pronchery static RADIX_THREAD *radix_get_thread(void)
558*e7be843bSPierre Pronchery {
559*e7be843bSPierre Pronchery     return CRYPTO_THREAD_get_local(&radix_thread);
560*e7be843bSPierre Pronchery }
561*e7be843bSPierre Pronchery 
radix_thread_init(RADIX_THREAD * rt)562*e7be843bSPierre Pronchery static int radix_thread_init(RADIX_THREAD *rt)
563*e7be843bSPierre Pronchery {
564*e7be843bSPierre Pronchery     if (!TEST_ptr(rt)
565*e7be843bSPierre Pronchery         || !TEST_ptr_null(CRYPTO_THREAD_get_local(&radix_thread)))
566*e7be843bSPierre Pronchery         return 0;
567*e7be843bSPierre Pronchery 
568*e7be843bSPierre Pronchery     if (!TEST_true(CRYPTO_THREAD_set_local(&radix_thread, rt)))
569*e7be843bSPierre Pronchery         return 0;
570*e7be843bSPierre Pronchery 
571*e7be843bSPierre Pronchery     set_override_bio_out(rt->debug_bio);
572*e7be843bSPierre Pronchery     set_override_bio_err(rt->debug_bio);
573*e7be843bSPierre Pronchery     return 1;
574*e7be843bSPierre Pronchery }
575*e7be843bSPierre Pronchery 
radix_thread_cleanup(void)576*e7be843bSPierre Pronchery static void radix_thread_cleanup(void)
577*e7be843bSPierre Pronchery {
578*e7be843bSPierre Pronchery     RADIX_THREAD *rt = radix_get_thread();
579*e7be843bSPierre Pronchery 
580*e7be843bSPierre Pronchery     if (!TEST_ptr(rt))
581*e7be843bSPierre Pronchery         return;
582*e7be843bSPierre Pronchery 
583*e7be843bSPierre Pronchery     if (!TEST_true(CRYPTO_THREAD_set_local(&radix_thread, NULL)))
584*e7be843bSPierre Pronchery         return;
585*e7be843bSPierre Pronchery }
586*e7be843bSPierre Pronchery 
bindings_process_init(size_t node_idx,size_t process_idx)587*e7be843bSPierre Pronchery static int bindings_process_init(size_t node_idx, size_t process_idx)
588*e7be843bSPierre Pronchery {
589*e7be843bSPierre Pronchery     RADIX_THREAD *rt;
590*e7be843bSPierre Pronchery 
591*e7be843bSPierre Pronchery     if (!TEST_true(RADIX_PROCESS_init(&radix_process, node_idx, process_idx)))
592*e7be843bSPierre Pronchery         return 0;
593*e7be843bSPierre Pronchery 
594*e7be843bSPierre Pronchery     if (!TEST_true(CRYPTO_THREAD_init_local(&radix_thread,
595*e7be843bSPierre Pronchery                                             radix_thread_cleanup_tl)))
596*e7be843bSPierre Pronchery         return 0;
597*e7be843bSPierre Pronchery 
598*e7be843bSPierre Pronchery     if (!TEST_ptr(rt = RADIX_THREAD_new(&radix_process)))
599*e7be843bSPierre Pronchery         return 0;
600*e7be843bSPierre Pronchery 
601*e7be843bSPierre Pronchery     /* Allocate structures for main thread. */
602*e7be843bSPierre Pronchery     return radix_thread_init(rt);
603*e7be843bSPierre Pronchery }
604*e7be843bSPierre Pronchery 
bindings_process_finish(int testresult_main)605*e7be843bSPierre Pronchery static int bindings_process_finish(int testresult_main)
606*e7be843bSPierre Pronchery {
607*e7be843bSPierre Pronchery     int testresult, testresult_child;
608*e7be843bSPierre Pronchery 
609*e7be843bSPierre Pronchery     if (!TEST_true(RADIX_PROCESS_join_all_threads(&radix_process,
610*e7be843bSPierre Pronchery                                                   &testresult_child)))
611*e7be843bSPierre Pronchery         return 0;
612*e7be843bSPierre Pronchery 
613*e7be843bSPierre Pronchery     testresult = testresult_main && testresult_child;
614*e7be843bSPierre Pronchery     RADIX_PROCESS_report_state(&radix_process, bio_err,
615*e7be843bSPierre Pronchery                                /*verbose=*/!testresult);
616*e7be843bSPierre Pronchery     radix_thread_cleanup(); /* cleanup main thread */
617*e7be843bSPierre Pronchery     RADIX_PROCESS_cleanup(&radix_process);
618*e7be843bSPierre Pronchery 
619*e7be843bSPierre Pronchery     if (testresult)
620*e7be843bSPierre Pronchery         BIO_printf(bio_err, "==> OK\n\n");
621*e7be843bSPierre Pronchery     else
622*e7be843bSPierre Pronchery         BIO_printf(bio_err, "==> ERROR (main=%d, children=%d)\n\n",
623*e7be843bSPierre Pronchery                    testresult_main, testresult_child);
624*e7be843bSPierre Pronchery 
625*e7be843bSPierre Pronchery     return testresult;
626*e7be843bSPierre Pronchery }
627*e7be843bSPierre Pronchery 
628*e7be843bSPierre Pronchery #define RP()    (&radix_process)
629*e7be843bSPierre Pronchery #define RT()    (radix_get_thread())
630*e7be843bSPierre Pronchery 
get_time(void * arg)631*e7be843bSPierre Pronchery static OSSL_TIME get_time(void *arg)
632*e7be843bSPierre Pronchery {
633*e7be843bSPierre Pronchery     OSSL_TIME time_slip;
634*e7be843bSPierre Pronchery 
635*e7be843bSPierre Pronchery     ossl_crypto_mutex_lock(RP()->gm);
636*e7be843bSPierre Pronchery     time_slip = RP()->time_slip;
637*e7be843bSPierre Pronchery     ossl_crypto_mutex_unlock(RP()->gm);
638*e7be843bSPierre Pronchery 
639*e7be843bSPierre Pronchery     return ossl_time_add(ossl_time_now(), time_slip);
640*e7be843bSPierre Pronchery }
641*e7be843bSPierre Pronchery 
radix_skip_time(OSSL_TIME t)642*e7be843bSPierre Pronchery ossl_unused static void radix_skip_time(OSSL_TIME t)
643*e7be843bSPierre Pronchery {
644*e7be843bSPierre Pronchery     ossl_crypto_mutex_lock(RP()->gm);
645*e7be843bSPierre Pronchery     RP()->time_slip = ossl_time_add(RP()->time_slip, t);
646*e7be843bSPierre Pronchery     ossl_crypto_mutex_unlock(RP()->gm);
647*e7be843bSPierre Pronchery }
648*e7be843bSPierre Pronchery 
per_op_tick_obj(RADIX_OBJ * obj)649*e7be843bSPierre Pronchery static void per_op_tick_obj(RADIX_OBJ *obj)
650*e7be843bSPierre Pronchery {
651*e7be843bSPierre Pronchery     if (obj->active)
652*e7be843bSPierre Pronchery         SSL_handle_events(obj->ssl);
653*e7be843bSPierre Pronchery }
654*e7be843bSPierre Pronchery 
do_per_op(TERP * terp,void * arg)655*e7be843bSPierre Pronchery static int do_per_op(TERP *terp, void *arg)
656*e7be843bSPierre Pronchery {
657*e7be843bSPierre Pronchery     lh_RADIX_OBJ_doall(RP()->objs, per_op_tick_obj);
658*e7be843bSPierre Pronchery     return 1;
659*e7be843bSPierre Pronchery }
660*e7be843bSPierre Pronchery 
bindings_adjust_terp_config(TERP_CONFIG * cfg)661*e7be843bSPierre Pronchery static int bindings_adjust_terp_config(TERP_CONFIG *cfg)
662*e7be843bSPierre Pronchery {
663*e7be843bSPierre Pronchery     cfg->now_cb     = get_time;
664*e7be843bSPierre Pronchery     cfg->per_op_cb  = do_per_op;
665*e7be843bSPierre Pronchery     return 1;
666*e7be843bSPierre Pronchery }
667*e7be843bSPierre Pronchery 
expect_slot_ssl(FUNC_CTX * fctx,size_t idx,SSL ** p_ssl)668*e7be843bSPierre Pronchery static int expect_slot_ssl(FUNC_CTX *fctx, size_t idx, SSL **p_ssl)
669*e7be843bSPierre Pronchery {
670*e7be843bSPierre Pronchery     if (!TEST_size_t_lt(idx, NUM_SLOTS)
671*e7be843bSPierre Pronchery         || !TEST_ptr(*p_ssl = RT()->ssl[idx]))
672*e7be843bSPierre Pronchery         return 0;
673*e7be843bSPierre Pronchery 
674*e7be843bSPierre Pronchery     return 1;
675*e7be843bSPierre Pronchery }
676*e7be843bSPierre Pronchery 
677*e7be843bSPierre Pronchery #define REQUIRE_SSL_N(idx, ssl)                                 \
678*e7be843bSPierre Pronchery     do {                                                        \
679*e7be843bSPierre Pronchery         (ssl) = NULL; /* quiet uninitialized warnings */        \
680*e7be843bSPierre Pronchery         if (!TEST_true(expect_slot_ssl(fctx, (idx), &(ssl))))   \
681*e7be843bSPierre Pronchery             goto err;                                           \
682*e7be843bSPierre Pronchery     } while (0)
683*e7be843bSPierre Pronchery #define REQUIRE_SSL(ssl)    REQUIRE_SSL_N(0, (ssl))
684*e7be843bSPierre Pronchery 
685*e7be843bSPierre Pronchery #define REQUIRE_SSL_2(a, b)                                     \
686*e7be843bSPierre Pronchery     do {                                                        \
687*e7be843bSPierre Pronchery         REQUIRE_SSL_N(0, (a));                                  \
688*e7be843bSPierre Pronchery         REQUIRE_SSL_N(1, (b));                                  \
689*e7be843bSPierre Pronchery     } while (0)
690*e7be843bSPierre Pronchery 
691*e7be843bSPierre Pronchery #define REQUIRE_SSL_3(a, b, c)                                  \
692*e7be843bSPierre Pronchery     do {                                                        \
693*e7be843bSPierre Pronchery         REQUIRE_SSL_N(0, (a));                                  \
694*e7be843bSPierre Pronchery         REQUIRE_SSL_N(1, (b));                                  \
695*e7be843bSPierre Pronchery         REQUIRE_SSL_N(2, (c));                                  \
696*e7be843bSPierre Pronchery     } while (0)
697*e7be843bSPierre Pronchery 
698*e7be843bSPierre Pronchery #define REQUIRE_SSL_4(a, b, c, d)                               \
699*e7be843bSPierre Pronchery     do {                                                        \
700*e7be843bSPierre Pronchery         REQUIRE_SSL_N(0, (a));                                  \
701*e7be843bSPierre Pronchery         REQUIRE_SSL_N(1, (b));                                  \
702*e7be843bSPierre Pronchery         REQUIRE_SSL_N(2, (c));                                  \
703*e7be843bSPierre Pronchery         REQUIRE_SSL_N(3, (d));                                  \
704*e7be843bSPierre Pronchery     } while (0)
705*e7be843bSPierre Pronchery 
706*e7be843bSPierre Pronchery #define REQUIRE_SSL_5(a, b, c, d, e)                            \
707*e7be843bSPierre Pronchery     do {                                                        \
708*e7be843bSPierre Pronchery         REQUIRE_SSL_N(0, (a));                                  \
709*e7be843bSPierre Pronchery         REQUIRE_SSL_N(1, (b));                                  \
710*e7be843bSPierre Pronchery         REQUIRE_SSL_N(2, (c));                                  \
711*e7be843bSPierre Pronchery         REQUIRE_SSL_N(3, (d));                                  \
712*e7be843bSPierre Pronchery         REQUIRE_SSL_N(4, (e));                                  \
713*e7be843bSPierre Pronchery     } while (0)
714*e7be843bSPierre Pronchery 
715*e7be843bSPierre Pronchery #define C_BIDI_ID(ordinal) \
716*e7be843bSPierre Pronchery     (((ordinal) << 2) | QUIC_STREAM_INITIATOR_CLIENT | QUIC_STREAM_DIR_BIDI)
717*e7be843bSPierre Pronchery #define S_BIDI_ID(ordinal) \
718*e7be843bSPierre Pronchery     (((ordinal) << 2) | QUIC_STREAM_INITIATOR_SERVER | QUIC_STREAM_DIR_BIDI)
719*e7be843bSPierre Pronchery #define C_UNI_ID(ordinal) \
720*e7be843bSPierre Pronchery     (((ordinal) << 2) | QUIC_STREAM_INITIATOR_CLIENT | QUIC_STREAM_DIR_UNI)
721*e7be843bSPierre Pronchery #define S_UNI_ID(ordinal) \
722*e7be843bSPierre Pronchery     (((ordinal) << 2) | QUIC_STREAM_INITIATOR_SERVER | QUIC_STREAM_DIR_UNI)
723*e7be843bSPierre Pronchery 
724*e7be843bSPierre Pronchery #if defined(OPENSSL_THREADS)
725*e7be843bSPierre Pronchery 
RADIX_THREAD_worker_run(RADIX_THREAD * rt)726*e7be843bSPierre Pronchery static int RADIX_THREAD_worker_run(RADIX_THREAD *rt)
727*e7be843bSPierre Pronchery {
728*e7be843bSPierre Pronchery     int ok = 0;
729*e7be843bSPierre Pronchery     TERP_CONFIG cfg = {0};
730*e7be843bSPierre Pronchery 
731*e7be843bSPierre Pronchery     cfg.debug_bio = rt->debug_bio;
732*e7be843bSPierre Pronchery     if (!TEST_true(bindings_adjust_terp_config(&cfg)))
733*e7be843bSPierre Pronchery         goto err;
734*e7be843bSPierre Pronchery 
735*e7be843bSPierre Pronchery     if (!TERP_run(rt->child_script_info, &cfg))
736*e7be843bSPierre Pronchery         goto err;
737*e7be843bSPierre Pronchery 
738*e7be843bSPierre Pronchery     ok = 1;
739*e7be843bSPierre Pronchery err:
740*e7be843bSPierre Pronchery     return ok;
741*e7be843bSPierre Pronchery }
742*e7be843bSPierre Pronchery 
RADIX_THREAD_worker_main(void * p)743*e7be843bSPierre Pronchery static unsigned int RADIX_THREAD_worker_main(void *p)
744*e7be843bSPierre Pronchery {
745*e7be843bSPierre Pronchery     int testresult = 0;
746*e7be843bSPierre Pronchery     RADIX_THREAD *rt = p;
747*e7be843bSPierre Pronchery 
748*e7be843bSPierre Pronchery     if (!TEST_true(radix_thread_init(rt)))
749*e7be843bSPierre Pronchery         return 0;
750*e7be843bSPierre Pronchery 
751*e7be843bSPierre Pronchery     /* Wait until thread-specific init is done (e.g. setting rt->t) */
752*e7be843bSPierre Pronchery     ossl_crypto_mutex_lock(rt->m);
753*e7be843bSPierre Pronchery     ossl_crypto_mutex_unlock(rt->m);
754*e7be843bSPierre Pronchery 
755*e7be843bSPierre Pronchery     testresult = RADIX_THREAD_worker_run(rt);
756*e7be843bSPierre Pronchery 
757*e7be843bSPierre Pronchery     ossl_crypto_mutex_lock(rt->m);
758*e7be843bSPierre Pronchery     rt->testresult  = testresult;
759*e7be843bSPierre Pronchery     rt->done        = 1;
760*e7be843bSPierre Pronchery     ossl_crypto_mutex_unlock(rt->m);
761*e7be843bSPierre Pronchery 
762*e7be843bSPierre Pronchery     radix_thread_cleanup();
763*e7be843bSPierre Pronchery     return 1;
764*e7be843bSPierre Pronchery }
765*e7be843bSPierre Pronchery 
766*e7be843bSPierre Pronchery #endif
767*e7be843bSPierre Pronchery 
radix_activate_obj(RADIX_OBJ * obj)768*e7be843bSPierre Pronchery static void radix_activate_obj(RADIX_OBJ *obj)
769*e7be843bSPierre Pronchery {
770*e7be843bSPierre Pronchery     if (obj != NULL)
771*e7be843bSPierre Pronchery         obj->active = 1;
772*e7be843bSPierre Pronchery }
773*e7be843bSPierre Pronchery 
radix_activate_slot(size_t idx)774*e7be843bSPierre Pronchery static void radix_activate_slot(size_t idx)
775*e7be843bSPierre Pronchery {
776*e7be843bSPierre Pronchery     if (idx >= NUM_SLOTS)
777*e7be843bSPierre Pronchery         return;
778*e7be843bSPierre Pronchery 
779*e7be843bSPierre Pronchery     radix_activate_obj(RT()->slot[idx]);
780*e7be843bSPierre Pronchery }
781*e7be843bSPierre Pronchery 
DEF_FUNC(hf_spawn_thread)782*e7be843bSPierre Pronchery DEF_FUNC(hf_spawn_thread)
783*e7be843bSPierre Pronchery {
784*e7be843bSPierre Pronchery     int ok = 0;
785*e7be843bSPierre Pronchery     RADIX_THREAD *child_rt = NULL;
786*e7be843bSPierre Pronchery     SCRIPT_INFO *script_info = NULL;
787*e7be843bSPierre Pronchery 
788*e7be843bSPierre Pronchery     F_POP(script_info);
789*e7be843bSPierre Pronchery     if (!TEST_ptr(script_info))
790*e7be843bSPierre Pronchery         goto err;
791*e7be843bSPierre Pronchery 
792*e7be843bSPierre Pronchery #if !defined(OPENSSL_THREADS)
793*e7be843bSPierre Pronchery     TEST_skip("threading not supported, skipping");
794*e7be843bSPierre Pronchery     F_SKIP_REST();
795*e7be843bSPierre Pronchery #else
796*e7be843bSPierre Pronchery     if (!TEST_ptr(child_rt = RADIX_THREAD_new(&radix_process)))
797*e7be843bSPierre Pronchery         return 0;
798*e7be843bSPierre Pronchery 
799*e7be843bSPierre Pronchery     if (!TEST_ptr(child_rt->debug_bio = BIO_new(BIO_s_mem())))
800*e7be843bSPierre Pronchery         goto err;
801*e7be843bSPierre Pronchery 
802*e7be843bSPierre Pronchery     ossl_crypto_mutex_lock(child_rt->m);
803*e7be843bSPierre Pronchery 
804*e7be843bSPierre Pronchery     child_rt->child_script_info = script_info;
805*e7be843bSPierre Pronchery     if (!TEST_ptr(child_rt->t = ossl_crypto_thread_native_start(RADIX_THREAD_worker_main,
806*e7be843bSPierre Pronchery                                                                 child_rt, 1))) {
807*e7be843bSPierre Pronchery         ossl_crypto_mutex_unlock(child_rt->m);
808*e7be843bSPierre Pronchery         goto err;
809*e7be843bSPierre Pronchery     }
810*e7be843bSPierre Pronchery 
811*e7be843bSPierre Pronchery     ossl_crypto_mutex_unlock(child_rt->m);
812*e7be843bSPierre Pronchery     ok = 1;
813*e7be843bSPierre Pronchery #endif
814*e7be843bSPierre Pronchery err:
815*e7be843bSPierre Pronchery     if (!ok)
816*e7be843bSPierre Pronchery         RADIX_THREAD_free(child_rt);
817*e7be843bSPierre Pronchery 
818*e7be843bSPierre Pronchery     return ok;
819*e7be843bSPierre Pronchery }
820*e7be843bSPierre Pronchery 
DEF_FUNC(hf_clear)821*e7be843bSPierre Pronchery DEF_FUNC(hf_clear)
822*e7be843bSPierre Pronchery {
823*e7be843bSPierre Pronchery     RADIX_THREAD *rt = RT();
824*e7be843bSPierre Pronchery     size_t i;
825*e7be843bSPierre Pronchery 
826*e7be843bSPierre Pronchery     ossl_crypto_mutex_lock(RP()->gm);
827*e7be843bSPierre Pronchery 
828*e7be843bSPierre Pronchery     lh_RADIX_OBJ_doall(RP()->objs, cleanup_one);
829*e7be843bSPierre Pronchery     lh_RADIX_OBJ_flush(RP()->objs);
830*e7be843bSPierre Pronchery 
831*e7be843bSPierre Pronchery     for (i = 0; i < NUM_SLOTS; ++i) {
832*e7be843bSPierre Pronchery         rt->slot[i] = NULL;
833*e7be843bSPierre Pronchery         rt->ssl[i]  = NULL;
834*e7be843bSPierre Pronchery     }
835*e7be843bSPierre Pronchery 
836*e7be843bSPierre Pronchery     ossl_crypto_mutex_unlock(RP()->gm);
837*e7be843bSPierre Pronchery     return 1;
838*e7be843bSPierre Pronchery }
839*e7be843bSPierre Pronchery 
840*e7be843bSPierre Pronchery #define OP_SPAWN_THREAD(script_name)                            \
841*e7be843bSPierre Pronchery     (OP_PUSH_P(SCRIPT(script_name)), OP_FUNC(hf_spawn_thread))
842*e7be843bSPierre Pronchery #define OP_CLEAR()                                              \
843*e7be843bSPierre Pronchery     (OP_FUNC(hf_clear))
844