| /* |
| * test-bio.c - BIO layer for testing |
| * |
| * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * This is a 'source/sink' BIO which supports synthetic inputs and outputs, and |
| * can be used to drive filter BIOs through a state machine. It buffers all |
| * output sent to it, which can be retrieved with BIO_test_get_output(), and |
| * input sent to it, which is handed back in response to BIO_read() by the |
| * filter BIO. |
| */ |
| |
| #include <assert.h> |
| #include <string.h> |
| |
| #include "src/test-bio.h" |
| #include "src/util.h" |
| |
| int verbose; |
| int verbose_debug; |
| |
| static const unsigned int kMagic = 0x5f8d3f15; |
| |
| struct test_ctx |
| { |
| unsigned int magic; |
| unsigned char *out; |
| size_t outsz; |
| unsigned char *in; |
| size_t insz; |
| }; |
| |
| static struct test_ctx *bio_ctx (BIO *b) |
| { |
| struct test_ctx *ctx = b->ptr; |
| assert (ctx->magic == kMagic); |
| return ctx; |
| } |
| |
| static size_t buf_drain (unsigned char **buf, size_t *bufsz, |
| unsigned char *out, size_t outsz) |
| { |
| if (*bufsz < outsz) |
| outsz = *bufsz; |
| memcpy (out, *buf, outsz); |
| if (*bufsz > outsz) |
| memmove (*buf, *buf + outsz, *bufsz - outsz); |
| *bufsz -= outsz; |
| *buf = realloc (*buf, *bufsz); |
| return outsz; |
| } |
| |
| static void buf_fill (unsigned char **buf, size_t *bufsz, |
| const unsigned char *in, size_t insz) |
| { |
| *buf = realloc (*buf, *bufsz + insz); |
| memcpy (*buf + *bufsz, in, insz); |
| *bufsz += insz; |
| } |
| |
| int test_new (BIO *b) |
| { |
| struct test_ctx *ctx = malloc (sizeof *ctx); |
| if (!ctx) |
| return 0; |
| ctx->magic = kMagic; |
| ctx->in = NULL; |
| ctx->insz = 0; |
| ctx->out = NULL; |
| ctx->outsz = 0; |
| b->init = 1; |
| b->flags = 0; |
| b->ptr = ctx; |
| return 1; |
| } |
| |
| int test_free (BIO *b) |
| { |
| struct test_ctx *ctx; |
| if (!b || !b->ptr) |
| return 1; |
| ctx = bio_ctx (b); |
| free (ctx->in); |
| free (ctx->out); |
| return 1; |
| } |
| |
| int test_write (BIO *b, const char *buf, int sz) |
| { |
| struct test_ctx *ctx = bio_ctx (b); |
| if (sz <= 0) |
| return 0; |
| buf_fill (&ctx->out, &ctx->outsz, (unsigned char *) buf, sz); |
| return sz; |
| } |
| |
| int test_read (BIO *b, char *buf, int sz) |
| { |
| struct test_ctx *ctx = bio_ctx (b); |
| if (sz <= 0) |
| return 0; |
| return buf_drain (&ctx->in, &ctx->insz, (unsigned char *) buf, sz); |
| } |
| |
| long test_ctrl (BIO *b, int cmd, long num, void *ptr) |
| { |
| return 0; |
| } |
| |
| long test_callback_ctrl (BIO *b, int cmd, bio_info_cb fp) |
| { |
| return 0; |
| } |
| |
| BIO_METHOD test_methods = |
| { |
| BIO_TYPE_SOCKET, |
| "test", |
| test_write, |
| test_read, |
| NULL, |
| NULL, |
| test_ctrl, |
| test_new, |
| test_free, |
| test_callback_ctrl, |
| }; |
| |
| BIO_METHOD *BIO_s_test() |
| { |
| return &test_methods; |
| } |
| |
| BIO API *BIO_new_test() |
| { |
| return BIO_new (BIO_s_test()); |
| } |
| |
| size_t API BIO_test_output_left (BIO *b) |
| { |
| return bio_ctx (b)->outsz; |
| } |
| |
| size_t API BIO_test_get_output (BIO *b, unsigned char *buf, size_t bufsz) |
| { |
| struct test_ctx *c = bio_ctx (b); |
| return buf_drain (&c->out, &c->outsz, buf, bufsz); |
| } |
| |
| void API BIO_test_add_input (BIO *b, const unsigned char *buf, size_t bufsz) |
| { |
| struct test_ctx *c = bio_ctx (b); |
| return buf_fill (&c->in, &c->insz, buf, bufsz); |
| } |