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) 36 static void cleanup_test_data(void *p) 37 { 38 OPENSSL_free(p); 39 } 40 #endif 41 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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