Home | History | Annotate | Line # | Download | only in testutil
      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