Home | History | Annotate | Line # | Download | only in testutil
      1 /*
      2  * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
      3  * Copyright (c) 2017, Oracle and/or its affiliates.  All rights reserved.
      4  *
      5  * Licensed under the OpenSSL license (the "License").  You may not use
      6  * this file except in compliance with the License.  You can obtain a copy
      7  * in the file LICENSE in the source distribution or at
      8  * https://www.openssl.org/source/license.html
      9  */
     10 
     11 #include <string.h>
     12 #include "tu_local.h"
     13 
     14 static int tap_write_ex(BIO *b, const char *buf, size_t size, size_t *in_size);
     15 static int tap_read_ex(BIO *b, char *buf, size_t size, size_t *out_size);
     16 static int tap_puts(BIO *b, const char *str);
     17 static int tap_gets(BIO *b, char *str, int size);
     18 static long tap_ctrl(BIO *b, int cmd, long arg1, void *arg2);
     19 static int tap_new(BIO *b);
     20 static int tap_free(BIO *b);
     21 static long tap_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
     22 
     23 const BIO_METHOD *BIO_f_tap(void)
     24 {
     25     static BIO_METHOD *tap = NULL;
     26 
     27     if (tap == NULL) {
     28         tap = BIO_meth_new(BIO_TYPE_START | BIO_TYPE_FILTER, "tap");
     29         if (tap != NULL) {
     30             BIO_meth_set_write_ex(tap, tap_write_ex);
     31             BIO_meth_set_read_ex(tap, tap_read_ex);
     32             BIO_meth_set_puts(tap, tap_puts);
     33             BIO_meth_set_gets(tap, tap_gets);
     34             BIO_meth_set_ctrl(tap, tap_ctrl);
     35             BIO_meth_set_create(tap, tap_new);
     36             BIO_meth_set_destroy(tap, tap_free);
     37             BIO_meth_set_callback_ctrl(tap, tap_callback_ctrl);
     38         }
     39     }
     40     return tap;
     41 }
     42 
     43 static int tap_new(BIO *b)
     44 {
     45     BIO_set_data(b, NULL);
     46     BIO_set_init(b, 1);
     47     return 1;
     48 }
     49 
     50 static int tap_free(BIO *b)
     51 {
     52     if (b == NULL)
     53         return 0;
     54     BIO_set_data(b, NULL);
     55     BIO_set_init(b, 0);
     56     return 1;
     57 }
     58 
     59 static int tap_read_ex(BIO *b, char *buf, size_t size, size_t *out_size)
     60 {
     61     BIO *next = BIO_next(b);
     62     int ret = 0;
     63 
     64     ret = BIO_read_ex(next, buf, size, out_size);
     65     BIO_clear_retry_flags(b);
     66     BIO_copy_next_retry(b);
     67     return ret;
     68 }
     69 
     70 /*
     71  * Output a string to the specified bio and return 1 if successful.
     72  */
     73 static int write_string(BIO *b, const char *buf, size_t n)
     74 {
     75     size_t m;
     76 
     77     return BIO_write_ex(b, buf, n, &m) != 0 && m == n;
     78 }
     79 
     80 /*
     81  * Write some data.
     82  *
     83  * This function implements a simple state machine that detects new lines.
     84  * It indents the output and prefixes it with a '#' character.
     85  *
     86  * It returns the number of input characters that were output in in_size.
     87  * More characters than this will likely have been output however any calling
     88  * code will be unable to correctly assess the actual number of characters
     89  * emitted and would be prone to failure if the actual number were returned.
     90  *
     91  * The BIO_data field is used as our state.  If it is NULL, we've just
     92  * seen a new line.  If it is not NULL, we're processing characters in a line.
     93  */
     94 static int tap_write_ex(BIO *b, const char *buf, size_t size, size_t *in_size)
     95 {
     96     BIO *next = BIO_next(b);
     97     size_t i;
     98     int j;
     99     char EMPTY[] = "";
    100 
    101     for (i = 0; i < size; i++) {
    102         if (BIO_get_data(b) == NULL) {
    103             BIO_set_data(b, EMPTY);
    104             for (j = 0; j < subtest_level(); j++)
    105                 if (!write_string(next, " ", 1))
    106                     goto err;
    107             if (!write_string(next, "# ", 2))
    108                 goto err;
    109         }
    110         if (!write_string(next, buf + i, 1))
    111             goto err;
    112         if (buf[i] == '\n')
    113             BIO_set_data(b, NULL);
    114     }
    115     *in_size = i;
    116     return 1;
    117 
    118 err:
    119     *in_size = i;
    120     return 0;
    121 }
    122 
    123 static long tap_ctrl(BIO *b, int cmd, long num, void *ptr)
    124 {
    125     BIO *next = BIO_next(b);
    126 
    127     switch (cmd) {
    128     case BIO_CTRL_RESET:
    129         BIO_set_data(b, NULL);
    130         break;
    131 
    132     default:
    133         break;
    134     }
    135     return BIO_ctrl(next, cmd, num, ptr);
    136 }
    137 
    138 static long tap_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
    139 {
    140     return BIO_callback_ctrl(BIO_next(b), cmd, fp);
    141 }
    142 
    143 static int tap_gets(BIO *b, char *buf, int size)
    144 {
    145     return BIO_gets(BIO_next(b), buf, size);
    146 }
    147 
    148 static int tap_puts(BIO *b, const char *str)
    149 {
    150     size_t m;
    151 
    152     if (!tap_write_ex(b, str, strlen(str), &m))
    153         return 0;
    154     return m;
    155 }
    156