📄 bss_bio.c
字号:
/* crypto/bio/bss_bio.c -*- Mode: C; c-file-style: "eay" -*- *//* ==================================================================== * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * *//* Special method for a BIO where the other endpoint is also a BIO * of this kind, handled by the same thread (i.e. the "peer" is actually * ourselves, wearing a different hat). * Such "BIO pairs" are mainly for using the SSL library with I/O interfaces * for which no specific BIO method is available. * See ssl/ssltest.c for some hints on how this can be used. *//* BIO_DEBUG implies BIO_PAIR_DEBUG */#ifdef BIO_DEBUG# ifndef BIO_PAIR_DEBUG# define BIO_PAIR_DEBUG# endif#endif/* disable assert() unless BIO_PAIR_DEBUG has been defined */#ifndef BIO_PAIR_DEBUG# ifndef NDEBUG# define NDEBUG# endif#endif#include <assert.h>#include <limits.h>#include <stdlib.h>#include <string.h>#include <openssl/bio.h>#include <openssl/err.h>#include <openssl/crypto.h>#include "e_os.h"/* VxWorks defines SSIZE_MAX with an empty value causing compile errors */#if defined(OPENSSL_SYS_VXWORKS)# undef SSIZE_MAX#endif#ifndef SSIZE_MAX# define SSIZE_MAX INT_MAX#endifstatic int bio_new(BIO *bio);static int bio_free(BIO *bio);static int bio_read(BIO *bio, char *buf, int size);static int bio_write(BIO *bio, const char *buf, int num);static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);static int bio_puts(BIO *bio, const char *str);static int bio_make_pair(BIO *bio1, BIO *bio2);static void bio_destroy_pair(BIO *bio);static BIO_METHOD methods_biop ={ BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new, bio_free, NULL /* no bio_callback_ctrl */};BIO_METHOD *BIO_s_bio(void) { return &methods_biop; }struct bio_bio_st{ BIO *peer; /* NULL if buf == NULL. * If peer != NULL, then peer->ptr is also a bio_bio_st, * and its "peer" member points back to us. * peer != NULL iff init != 0 in the BIO. */ /* This is for what we write (i.e. reading uses peer's struct): */ int closed; /* valid iff peer != NULL */ size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ size_t size; char *buf; /* "size" elements (if != NULL) */ size_t request; /* valid iff peer != NULL; 0 if len != 0, * otherwise set by peer to number of bytes * it (unsuccessfully) tried to read, * never more than buffer space (size-len) warrants. */};static int bio_new(BIO *bio) { struct bio_bio_st *b; b = OPENSSL_malloc(sizeof *b); if (b == NULL) return 0; b->peer = NULL; b->size = 17*1024; /* enough for one TLS record (just a default) */ b->buf = NULL; bio->ptr = b; return 1; }static int bio_free(BIO *bio) { struct bio_bio_st *b; if (bio == NULL) return 0; b = bio->ptr; assert(b != NULL); if (b->peer) bio_destroy_pair(bio); if (b->buf != NULL) { OPENSSL_free(b->buf); } OPENSSL_free(b); return 1; }static int bio_read(BIO *bio, char *buf, int size_) { size_t size = size_; size_t rest; struct bio_bio_st *b, *peer_b; BIO_clear_retry_flags(bio); if (!bio->init) return 0; b = bio->ptr; assert(b != NULL); assert(b->peer != NULL); peer_b = b->peer->ptr; assert(peer_b != NULL); assert(peer_b->buf != NULL); peer_b->request = 0; /* will be set in "retry_read" situation */ if (buf == NULL || size == 0) return 0; if (peer_b->len == 0) { if (peer_b->closed) return 0; /* writer has closed, and no data is left */ else { BIO_set_retry_read(bio); /* buffer is empty */ if (size <= peer_b->size) peer_b->request = size; else /* don't ask for more than the peer can * deliver in one write */ peer_b->request = peer_b->size; return -1; } } /* we can read */ if (peer_b->len < size) size = peer_b->len; /* now read "size" bytes */ rest = size; assert(rest > 0); do /* one or two iterations */ { size_t chunk; assert(rest <= peer_b->len); if (peer_b->offset + rest <= peer_b->size) chunk = rest; else /* wrap around ring buffer */ chunk = peer_b->size - peer_b->offset; assert(peer_b->offset + chunk <= peer_b->size); memcpy(buf, peer_b->buf + peer_b->offset, chunk); peer_b->len -= chunk; if (peer_b->len) { peer_b->offset += chunk; assert(peer_b->offset <= peer_b->size); if (peer_b->offset == peer_b->size) peer_b->offset = 0; buf += chunk; } else { /* buffer now empty, no need to advance "buf" */ assert(chunk == rest); peer_b->offset = 0; } rest -= chunk; } while (rest); return size; }/* non-copying interface: provide pointer to available data in buffer * bio_nread0: return number of available bytes * bio_nread: also advance index * (example usage: bio_nread0(), read from buffer, bio_nread() * or just bio_nread(), read from buffer) *//* WARNING: The non-copying interface is largely untested as of yet * and may contain bugs. */static ssize_t bio_nread0(BIO *bio, char **buf) { struct bio_bio_st *b, *peer_b; ssize_t num; BIO_clear_retry_flags(bio); if (!bio->init) return 0; b = bio->ptr; assert(b != NULL); assert(b->peer != NULL); peer_b = b->peer->ptr; assert(peer_b != NULL); assert(peer_b->buf != NULL); peer_b->request = 0; if (peer_b->len == 0) { char dummy; /* avoid code duplication -- nothing available for reading */ return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ } num = peer_b->len; if (peer_b->size < peer_b->offset + num) /* no ring buffer wrap-around for non-copying interface */ num = peer_b->size - peer_b->offset; assert(num > 0); if (buf != NULL) *buf = peer_b->buf + peer_b->offset; return num; }static ssize_t bio_nread(BIO *bio, char **buf, size_t num_) { struct bio_bio_st *b, *peer_b; ssize_t num, available; if (num_ > SSIZE_MAX) num = SSIZE_MAX; else num = (ssize_t)num_; available = bio_nread0(bio, buf); if (num > available) num = available; if (num <= 0) return num; b = bio->ptr; peer_b = b->peer->ptr; peer_b->len -= num; if (peer_b->len) { peer_b->offset += num; assert(peer_b->offset <= peer_b->size); if (peer_b->offset == peer_b->size) peer_b->offset = 0; } else peer_b->offset = 0; return num; }static int bio_write(BIO *bio, const char *buf, int num_) { size_t num = num_; size_t rest; struct bio_bio_st *b; BIO_clear_retry_flags(bio); if (!bio->init || buf == NULL || num == 0) return 0; b = bio->ptr; assert(b != NULL); assert(b->peer != NULL); assert(b->buf != NULL); b->request = 0; if (b->closed) { /* we already closed */ BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); return -1; } assert(b->len <= b->size); if (b->len == b->size) { BIO_set_retry_write(bio); /* buffer is full */ return -1; } /* we can write */ if (num > b->size - b->len) num = b->size - b->len; /* now write "num" bytes */ rest = num; assert(rest > 0); do /* one or two iterations */ { size_t write_offset; size_t chunk; assert(b->len + rest <= b->size); write_offset = b->offset + b->len; if (write_offset >= b->size) write_offset -= b->size; /* b->buf[write_offset] is the first byte we can write to. */ if (write_offset + rest <= b->size) chunk = rest; else /* wrap around ring buffer */ chunk = b->size - write_offset; memcpy(b->buf + write_offset, buf, chunk); b->len += chunk; assert(b->len <= b->size); rest -= chunk; buf += chunk; } while (rest); return num; }/* non-copying interface: provide pointer to region to write to * bio_nwrite0: check how much space is available * bio_nwrite: also increase length * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() * or just bio_nwrite(), write to buffer) */static ssize_t bio_nwrite0(BIO *bio, char **buf) { struct bio_bio_st *b; size_t num; size_t write_offset; BIO_clear_retry_flags(bio); if (!bio->init) return 0; b = bio->ptr; assert(b != NULL); assert(b->peer != NULL); assert(b->buf != NULL); b->request = 0; if (b->closed) { BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); return -1; } assert(b->len <= b->size); if (b->len == b->size) { BIO_set_retry_write(bio); return -1; } num = b->size - b->len; write_offset = b->offset + b->len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -