1 /*
2 * Copyright 2017-2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include "../testutil.h"
11 #include "output.h"
12 #include "tu_local.h"
13
14 #include <openssl/crypto.h>
15 #include <openssl/bio.h>
16
17 /* These are available for any test program */
18 BIO *bio_out = NULL;
19 BIO *bio_err = NULL;
20
21 /* These are available for TAP output only (internally) */
22 static BIO *tap_out = NULL;
23 static BIO *tap_err = NULL;
24
25 typedef struct local_test_data_st {
26 BIO *override_bio_out, *override_bio_err;
27 } LOCAL_TEST_DATA;
28
29 #if defined(OPENSSL_THREADS)
30 static CRYPTO_THREAD_LOCAL local_test_data; /* (LOCAL_TEST_DATA *) */
31
32 static CRYPTO_RWLOCK *io_lock = NULL;
33 #endif
34
35 #if defined(OPENSSL_THREADS)
cleanup_test_data(void * p)36 static void cleanup_test_data(void *p)
37 {
38 OPENSSL_free(p);
39 }
40 #endif
41
init_local_test_data(void)42 static int init_local_test_data(void)
43 {
44 #if defined(OPENSSL_THREADS)
45 if (!CRYPTO_THREAD_init_local(&local_test_data, cleanup_test_data))
46 return 0;
47 #endif
48
49 return 1;
50 }
51
get_local_test_data(void)52 static LOCAL_TEST_DATA *get_local_test_data(void)
53 {
54 #if defined(OPENSSL_THREADS)
55 LOCAL_TEST_DATA *p;
56
57 p = CRYPTO_THREAD_get_local(&local_test_data);
58 if (p != NULL)
59 return p;
60
61 if ((p = OPENSSL_zalloc(sizeof(*p))) == NULL)
62 return NULL;
63
64 if (!CRYPTO_THREAD_set_local(&local_test_data, p)) {
65 OPENSSL_free(p);
66 return NULL;
67 }
68
69 return p;
70 #else
71 return NULL;
72 #endif
73 }
74
cleanup_local_test_data(void)75 static void cleanup_local_test_data(void)
76 {
77 #if defined(OPENSSL_THREADS)
78 LOCAL_TEST_DATA *p;
79
80 p = CRYPTO_THREAD_get_local(&local_test_data);
81 if (p == NULL)
82 return;
83
84 CRYPTO_THREAD_set_local(&local_test_data, NULL);
85 OPENSSL_free(p);
86 #endif
87 }
88
set_override_bio_out(BIO * bio)89 int set_override_bio_out(BIO *bio)
90 {
91 LOCAL_TEST_DATA *data = get_local_test_data();
92
93 if (data == NULL)
94 return 0;
95
96 data->override_bio_out = bio;
97 return 1;
98 }
99
set_override_bio_err(BIO * bio)100 int set_override_bio_err(BIO *bio)
101 {
102 LOCAL_TEST_DATA *data = get_local_test_data();
103
104 if (data == NULL)
105 return 0;
106
107 data->override_bio_err = bio;
108 return 1;
109 }
110
get_bio_out(void)111 static BIO *get_bio_out(void)
112 {
113 LOCAL_TEST_DATA *data = get_local_test_data();
114
115 if (data != NULL && data->override_bio_out != NULL)
116 return data->override_bio_out;
117
118 return bio_out;
119 }
120
get_bio_err(void)121 static BIO *get_bio_err(void)
122 {
123 LOCAL_TEST_DATA *data = get_local_test_data();
124
125 if (data != NULL && data->override_bio_err != NULL)
126 return data->override_bio_err;
127
128 return bio_err;
129 }
130
test_open_streams(void)131 void test_open_streams(void)
132 {
133 int ok;
134
135 ok = init_local_test_data();
136
137 tap_out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
138 tap_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
139 #ifdef __VMS
140 tap_out = BIO_push(BIO_new(BIO_f_linebuffer()), tap_out);
141 tap_err = BIO_push(BIO_new(BIO_f_linebuffer()), tap_err);
142 #endif
143 tap_out = BIO_push(BIO_new(BIO_f_prefix()), tap_out);
144 tap_err = BIO_push(BIO_new(BIO_f_prefix()), tap_err);
145
146 bio_out = BIO_push(BIO_new(BIO_f_prefix()), tap_out);
147 bio_err = BIO_push(BIO_new(BIO_f_prefix()), tap_err);
148 BIO_set_prefix(bio_out, "# ");
149 BIO_set_prefix(bio_err, "# ");
150
151 #if defined(OPENSSL_THREADS)
152 io_lock = CRYPTO_THREAD_lock_new();
153 #endif
154
155 OPENSSL_assert(ok);
156 OPENSSL_assert(bio_out != NULL);
157 OPENSSL_assert(bio_err != NULL);
158 #if defined(OPENSSL_THREADS)
159 OPENSSL_assert(io_lock != NULL);
160 #endif
161 }
162
test_adjust_streams_tap_level(int level)163 void test_adjust_streams_tap_level(int level)
164 {
165 BIO_set_indent(tap_out, level);
166 BIO_set_indent(tap_err, level);
167 }
168
test_close_streams(void)169 void test_close_streams(void)
170 {
171 /*
172 * The rest of the chain is freed by the BIO_free_all() calls below, so
173 * we only need to free the last one in the bio_out and bio_err chains.
174 */
175 BIO_free(bio_out);
176 BIO_free(bio_err);
177
178 BIO_free_all(tap_out);
179 BIO_free_all(tap_err);
180
181 cleanup_local_test_data();
182
183 #if defined(OPENSSL_THREADS)
184 CRYPTO_THREAD_lock_free(io_lock);
185 #endif
186 }
187
test_io_lock(void)188 static ossl_inline void test_io_lock(void)
189 {
190 #if defined(OPENSSL_THREADS)
191 OPENSSL_assert(CRYPTO_THREAD_write_lock(io_lock) > 0);
192 #endif
193 }
194
test_io_unlock(void)195 static ossl_inline void test_io_unlock(void)
196 {
197 #if defined(OPENSSL_THREADS)
198 CRYPTO_THREAD_unlock(io_lock);
199 #endif
200 }
201
test_vprintf_stdout(const char * fmt,va_list ap)202 int test_vprintf_stdout(const char *fmt, va_list ap)
203 {
204 int r;
205
206 test_io_lock();
207 r = BIO_vprintf(get_bio_out(), fmt, ap);
208 test_io_unlock();
209
210 return r;
211 }
212
test_vprintf_stderr(const char * fmt,va_list ap)213 int test_vprintf_stderr(const char *fmt, va_list ap)
214 {
215 int r;
216
217 test_io_lock();
218 r = BIO_vprintf(get_bio_err(), fmt, ap);
219 test_io_unlock();
220
221 return r;
222 }
223
test_flush_stdout(void)224 int test_flush_stdout(void)
225 {
226 int r;
227
228 test_io_lock();
229 r = BIO_flush(get_bio_out());
230 test_io_unlock();
231
232 return r;
233 }
234
test_flush_stderr(void)235 int test_flush_stderr(void)
236 {
237 int r;
238
239 test_io_lock();
240 r = BIO_flush(get_bio_err());
241 test_io_unlock();
242
243 return r;
244 }
245
test_vprintf_tapout(const char * fmt,va_list ap)246 int test_vprintf_tapout(const char *fmt, va_list ap)
247 {
248 int r;
249
250 test_io_lock();
251 r = BIO_vprintf(tap_out, fmt, ap);
252 test_io_unlock();
253
254 return r;
255 }
256
test_vprintf_taperr(const char * fmt,va_list ap)257 int test_vprintf_taperr(const char *fmt, va_list ap)
258 {
259 int r;
260
261 test_io_lock();
262 r = BIO_vprintf(tap_err, fmt, ap);
263 test_io_unlock();
264
265 return r;
266 }
267
test_flush_tapout(void)268 int test_flush_tapout(void)
269 {
270 int r;
271
272 test_io_lock();
273 r = BIO_flush(tap_out);
274 test_io_unlock();
275
276 return r;
277 }
278
test_flush_taperr(void)279 int test_flush_taperr(void)
280 {
281 int r;
282
283 test_io_lock();
284 r = BIO_flush(tap_err);
285 test_io_unlock();
286
287 return r;
288 }
289