summaryrefslogtreecommitdiffstats
path: root/src/crypto/bio
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/bio')
-rw-r--r--src/crypto/bio/CMakeLists.txt31
-rw-r--r--src/crypto/bio/bio.c477
-rw-r--r--src/crypto/bio/bio_error.c59
-rw-r--r--src/crypto/bio/bio_mem.c327
-rw-r--r--src/crypto/bio/bio_test.c362
-rw-r--r--src/crypto/bio/buffer.c499
-rw-r--r--src/crypto/bio/connect.c541
-rw-r--r--src/crypto/bio/fd.c270
-rw-r--r--src/crypto/bio/file.c350
-rw-r--r--src/crypto/bio/hexdump.c192
-rw-r--r--src/crypto/bio/internal.h108
-rw-r--r--src/crypto/bio/pair.c821
-rw-r--r--src/crypto/bio/printf.c115
-rw-r--r--src/crypto/bio/socket.c191
-rw-r--r--src/crypto/bio/socket_helper.c112
15 files changed, 4455 insertions, 0 deletions
diff --git a/src/crypto/bio/CMakeLists.txt b/src/crypto/bio/CMakeLists.txt
new file mode 100644
index 0000000..6211e85
--- /dev/null
+++ b/src/crypto/bio/CMakeLists.txt
@@ -0,0 +1,31 @@
+include_directories(. .. ../../include)
+
+add_library(
+ bio
+
+ OBJECT
+
+ bio.c
+ bio_error.c
+ bio_mem.c
+ buffer.c
+ connect.c
+ fd.c
+ file.c
+ hexdump.c
+ pair.c
+ printf.c
+ socket.c
+ socket_helper.c
+)
+
+add_executable(
+ bio_test
+
+ bio_test.c
+)
+
+target_link_libraries(bio_test crypto)
+if (WIN32)
+ target_link_libraries(bio_test ws2_32)
+endif()
diff --git a/src/crypto/bio/bio.c b/src/crypto/bio/bio.c
new file mode 100644
index 0000000..4d947a6
--- /dev/null
+++ b/src/crypto/bio/bio.c
@@ -0,0 +1,477 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+
+/* BIO_set initialises a BIO structure to have the given type and sets the
+ * reference count to one. It returns one on success or zero on error. */
+static int bio_set(BIO *bio, const BIO_METHOD *method) {
+ /* This function can be called with a stack allocated |BIO| so we have to
+ * assume that the contents of |BIO| are arbitary. This also means that it'll
+ * leak memory if you call |BIO_set| twice on the same BIO. */
+ memset(bio, 0, sizeof(BIO));
+
+ bio->method = method;
+ bio->shutdown = 1;
+ bio->references = 1;
+
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) {
+ return 0;
+ }
+
+ if (method->create != NULL) {
+ if (!method->create(bio)) {
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+BIO *BIO_new(const BIO_METHOD *method) {
+ BIO *ret = OPENSSL_malloc(sizeof(BIO));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(BIO, BIO_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if (!bio_set(ret, method)) {
+ OPENSSL_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+int BIO_free(BIO *bio) {
+ BIO *next_bio;
+
+ for (; bio != NULL; bio = next_bio) {
+ int refs = CRYPTO_add(&bio->references, -1, CRYPTO_LOCK_BIO);
+ if (refs > 0) {
+ return 0;
+ }
+
+ if (bio->callback != NULL) {
+ int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1);
+ if (i <= 0) {
+ return i;
+ }
+ }
+
+ next_bio = BIO_pop(bio);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
+
+ if (bio->method != NULL && bio->method->destroy != NULL) {
+ bio->method->destroy(bio);
+ }
+
+ OPENSSL_free(bio);
+ }
+ return 1;
+}
+
+void BIO_vfree(BIO *bio) {
+ BIO_free(bio);
+}
+
+void BIO_free_all(BIO *bio) {
+ BIO_free(bio);
+}
+
+static int bio_io(BIO *bio, void *buf, int len, size_t method_offset,
+ int callback_flags, size_t *num) {
+ int i;
+ typedef int (*io_func_t)(BIO *, char *, int);
+ io_func_t io_func = NULL;
+
+ if (bio != NULL && bio->method != NULL) {
+ io_func =
+ *((const io_func_t *)(((const uint8_t *)bio->method) + method_offset));
+ }
+
+ if (io_func == NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNSUPPORTED_METHOD);
+ return -2;
+ }
+
+ if (bio->callback != NULL) {
+ i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L);
+ if (i <= 0) {
+ return i;
+ }
+ }
+
+ if (!bio->init) {
+ OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNINITIALIZED);
+ return -2;
+ }
+
+ i = 0;
+ if (buf != NULL && len > 0) {
+ i = io_func(bio, buf, len);
+ }
+
+ if (i > 0) {
+ *num += i;
+ }
+
+ if (bio->callback != NULL) {
+ i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L,
+ (long)i));
+ }
+
+ return i;
+}
+
+int BIO_read(BIO *bio, void *buf, int len) {
+ return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ,
+ &bio->num_read);
+}
+
+int BIO_gets(BIO *bio, char *buf, int len) {
+ return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS,
+ &bio->num_read);
+}
+
+int BIO_write(BIO *bio, const void *in, int inl) {
+ return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite),
+ BIO_CB_WRITE, &bio->num_write);
+}
+
+int BIO_puts(BIO *bio, const char *in) {
+ return BIO_write(bio, in, strlen(in));
+}
+
+int BIO_flush(BIO *bio) {
+ return BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL);
+}
+
+long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) {
+ long ret;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->method == NULL || bio->method->ctrl == NULL) {
+ OPENSSL_PUT_ERROR(BIO, BIO_ctrl, BIO_R_UNSUPPORTED_METHOD);
+ return -2;
+ }
+
+ if (bio->callback != NULL) {
+ ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ ret = bio->method->ctrl(bio, cmd, larg, parg);
+
+ if (bio->callback != NULL) {
+ ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret);
+ }
+
+ return ret;
+}
+
+char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) {
+ char *p = NULL;
+
+ if (BIO_ctrl(b, cmd, larg, (void *)&p) <= 0) {
+ return NULL;
+ }
+
+ return p;
+}
+
+long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) {
+ int i = iarg;
+
+ return BIO_ctrl(b, cmd, larg, (void *)&i);
+}
+
+int BIO_reset(BIO *bio) {
+ return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL);
+}
+
+void BIO_set_flags(BIO *bio, int flags) {
+ bio->flags |= flags;
+}
+
+int BIO_test_flags(const BIO *bio, int flags) {
+ return bio->flags & flags;
+}
+
+int BIO_should_read(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_READ);
+}
+
+int BIO_should_write(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_WRITE);
+}
+
+int BIO_should_retry(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_SHOULD_RETRY);
+}
+
+int BIO_should_io_special(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_IO_SPECIAL);
+}
+
+int BIO_get_retry_reason(const BIO *bio) { return bio->retry_reason; }
+
+void BIO_clear_flags(BIO *bio, int flags) {
+ bio->flags &= ~flags;
+}
+
+void BIO_set_retry_read(BIO *bio) {
+ bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY;
+}
+
+void BIO_set_retry_write(BIO *bio) {
+ bio->flags |= BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY;
+}
+
+static const int kRetryFlags = BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY;
+
+int BIO_get_retry_flags(BIO *bio) {
+ return bio->flags & kRetryFlags;
+}
+
+void BIO_clear_retry_flags(BIO *bio) {
+ bio->flags &= ~kRetryFlags;
+ bio->retry_reason = 0;
+}
+
+int BIO_method_type(const BIO *bio) { return bio->method->type; }
+
+void BIO_copy_next_retry(BIO *bio) {
+ BIO_clear_retry_flags(bio);
+ BIO_set_flags(bio, BIO_get_retry_flags(bio->next_bio));
+ bio->retry_reason = bio->next_bio->retry_reason;
+}
+
+long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
+ long ret;
+ bio_info_cb cb;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->method == NULL || bio->method->callback_ctrl == NULL) {
+ OPENSSL_PUT_ERROR(BIO, BIO_callback_ctrl, BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ cb = bio->callback;
+
+ if (cb != NULL) {
+ ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ ret = bio->method->callback_ctrl(bio, cmd, fp);
+
+ if (cb != NULL) {
+ ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret);
+ }
+
+ return ret;
+}
+
+size_t BIO_pending(const BIO *bio) {
+ return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
+}
+
+size_t BIO_ctrl_pending(const BIO *bio) {
+ return BIO_pending(bio);
+}
+
+size_t BIO_wpending(const BIO *bio) {
+ return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
+}
+
+int BIO_set_close(BIO *bio, int close_flag) {
+ return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL);
+}
+
+void BIO_set_callback(BIO *bio, bio_info_cb callback_func) {
+ bio->callback = callback_func;
+}
+
+void BIO_set_callback_arg(BIO *bio, char *arg) {
+ bio->cb_arg = arg;
+}
+
+char *BIO_get_callback_arg(const BIO *bio) {
+ return bio->cb_arg;
+}
+
+OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio) {
+ return bio->num_read;
+}
+
+OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio) {
+ return bio->num_write;
+}
+
+BIO *BIO_push(BIO *bio, BIO *appended_bio) {
+ BIO *last_bio;
+
+ if (bio == NULL) {
+ return bio;
+ }
+
+ last_bio = bio;
+ while (last_bio->next_bio != NULL) {
+ last_bio = last_bio->next_bio;
+ }
+
+ last_bio->next_bio = appended_bio;
+ /* TODO(fork): this seems very suspect. If we got rid of BIO SSL, we could
+ * get rid of this. */
+ BIO_ctrl(bio, BIO_CTRL_PUSH, 0, bio);
+
+ return bio;
+}
+
+BIO *BIO_pop(BIO *bio) {
+ BIO *ret;
+
+ if (bio == NULL) {
+ return NULL;
+ }
+ ret = bio->next_bio;
+ BIO_ctrl(bio, BIO_CTRL_POP, 0, bio);
+ bio->next_bio = NULL;
+ return ret;
+}
+
+BIO *BIO_next(BIO *bio) {
+ if (!bio) {
+ return NULL;
+ }
+ return bio->next_bio;
+}
+
+BIO *BIO_find_type(BIO *bio, int type) {
+ int method_type, mask;
+
+ if (!bio) {
+ return NULL;
+ }
+ mask = type & 0xff;
+
+ do {
+ if (bio->method != NULL) {
+ method_type = bio->method->type;
+
+ if (!mask) {
+ if (method_type & type) {
+ return bio;
+ }
+ } else if (method_type == type) {
+ return bio;
+ }
+ }
+ bio = bio->next_bio;
+ } while (bio != NULL);
+
+ return NULL;
+}
+
+int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent) {
+ if (indent > max_indent) {
+ indent = max_indent;
+ }
+
+ while (indent--) {
+ if (BIO_puts(bio, " ") != 1) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void BIO_print_errors_fp(FILE *out) {
+ BIO *bio = BIO_new_fp(out, BIO_NOCLOSE);
+ BIO_print_errors(bio);
+ BIO_free(bio);
+}
+
+static int print_bio(const char *str, size_t len, void *bio) {
+ return BIO_write((BIO *)bio, str, len);
+}
+
+void BIO_print_errors(BIO *bio) {
+ ERR_print_errors_cb(print_bio, bio);
+}
diff --git a/src/crypto/bio/bio_error.c b/src/crypto/bio/bio_error.c
new file mode 100644
index 0000000..09585e4
--- /dev/null
+++ b/src/crypto/bio/bio_error.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include <openssl/bio.h>
+
+const ERR_STRING_DATA BIO_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_callback_ctrl, 0), "BIO_callback_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ctrl, 0), "BIO_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new, 0), "BIO_new"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new_file, 0), "BIO_new_file"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new_mem_buf, 0), "BIO_new_mem_buf"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_zero_copy_get_read_buf, 0), "BIO_zero_copy_get_read_buf"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_zero_copy_get_read_buf_done, 0), "BIO_zero_copy_get_read_buf_done"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_zero_copy_get_write_buf, 0), "BIO_zero_copy_get_write_buf"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_zero_copy_get_write_buf_done, 0), "BIO_zero_copy_get_write_buf_done"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_ctrl, 0), "bio_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_io, 0), "bio_io"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_ip_and_port_to_socket_and_addr, 0), "bio_ip_and_port_to_socket_and_addr"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_make_pair, 0), "bio_make_pair"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_write, 0), "bio_write"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_buffer_ctrl, 0), "buffer_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_conn_ctrl, 0), "conn_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_conn_state, 0), "conn_state"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_file_ctrl, 0), "file_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_file_read, 0), "file_read"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_mem_write, 0), "mem_write"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ASN1_OBJECT_TOO_LONG), "ASN1_OBJECT_TOO_LONG"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BAD_FOPEN_MODE), "BAD_FOPEN_MODE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BROKEN_PIPE), "BROKEN_PIPE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_CONNECT_ERROR), "CONNECT_ERROR"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ERROR_SETTING_NBIO), "ERROR_SETTING_NBIO"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_ARGUMENT), "INVALID_ARGUMENT"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_IN_USE), "IN_USE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_KEEPALIVE), "KEEPALIVE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NBIO_CONNECT_ERROR), "NBIO_CONNECT_ERROR"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_HOSTNAME_SPECIFIED), "NO_HOSTNAME_SPECIFIED"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_SPECIFIED), "NO_PORT_SPECIFIED"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "NO_SUCH_FILE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NULL_PARAMETER), "NULL_PARAMETER"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_SYS_LIB), "SYS_LIB"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_CREATE_SOCKET), "UNABLE_TO_CREATE_SOCKET"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "UNINITIALIZED"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_METHOD), "UNSUPPORTED_METHOD"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WRITE_TO_READ_ONLY_BIO), "WRITE_TO_READ_ONLY_BIO"},
+ {0, NULL},
+};
diff --git a/src/crypto/bio/bio_mem.c b/src/crypto/bio/bio_mem.c
new file mode 100644
index 0000000..f3aad6f
--- /dev/null
+++ b/src/crypto/bio/bio_mem.c
@@ -0,0 +1,327 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+BIO *BIO_new_mem_buf(void *buf, int len) {
+ BIO *ret;
+ BUF_MEM *b;
+ const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len;
+
+ if (!buf && len != 0) {
+ OPENSSL_PUT_ERROR(BIO, BIO_new_mem_buf, BIO_R_NULL_PARAMETER);
+ return NULL;
+ }
+
+ ret = BIO_new(BIO_s_mem());
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ b = (BUF_MEM *)ret->ptr;
+ b->data = buf;
+ b->length = size;
+ b->max = size;
+
+ ret->flags |= BIO_FLAGS_MEM_RDONLY;
+
+ /* |num| is used to store the value that this BIO will return when it runs
+ * out of data. If it's negative then the retry flags will also be set. Since
+ * this is static data, retrying wont help */
+ ret->num = 0;
+
+ return ret;
+}
+
+static int mem_new(BIO *bio) {
+ BUF_MEM *b;
+
+ b = BUF_MEM_new();
+ if (b == NULL) {
+ return 0;
+ }
+
+ /* |shutdown| is used to store the close flag: whether the BIO has ownership
+ * of the BUF_MEM. */
+ bio->shutdown = 1;
+ bio->init = 1;
+ bio->num = -1;
+ bio->ptr = (char *)b;
+
+ return 1;
+}
+
+static int mem_free(BIO *bio) {
+ BUF_MEM *b;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (!bio->shutdown || !bio->init || bio->ptr == NULL) {
+ return 1;
+ }
+
+ b = (BUF_MEM *)bio->ptr;
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ b->data = NULL;
+ }
+ BUF_MEM_free(b);
+ bio->ptr = NULL;
+ return 1;
+}
+
+static int mem_read(BIO *bio, char *out, int outl) {
+ int ret;
+ BUF_MEM *b = (BUF_MEM*) bio->ptr;
+
+ BIO_clear_retry_flags(bio);
+ ret = outl;
+ if (b->length < INT_MAX && ret > (int)b->length) {
+ ret = b->length;
+ }
+
+ if (ret > 0) {
+ memcpy(out, b->data, ret);
+ b->length -= ret;
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ b->data += ret;
+ } else {
+ memmove(b->data, &b->data[ret], b->length);
+ }
+ } else if (b->length == 0) {
+ ret = bio->num;
+ if (ret != 0) {
+ BIO_set_retry_read(bio);
+ }
+ }
+ return ret;
+}
+
+static int mem_write(BIO *bio, const char *in, int inl) {
+ int ret = -1;
+ int blen;
+ BUF_MEM *b;
+
+ b = (BUF_MEM *)bio->ptr;
+
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ OPENSSL_PUT_ERROR(BIO, mem_write, BIO_R_WRITE_TO_READ_ONLY_BIO);
+ goto err;
+ }
+
+ BIO_clear_retry_flags(bio);
+ blen = b->length;
+ if (INT_MAX - blen < inl) {
+ goto err;
+ }
+ if (BUF_MEM_grow_clean(b, blen + inl) != (blen + inl)) {
+ goto err;
+ }
+ memcpy(&b->data[blen], in, inl);
+ ret = inl;
+
+err:
+ return ret;
+}
+
+static int mem_puts(BIO *bp, const char *str) {
+ return mem_write(bp, str, strlen(str));
+}
+
+static int mem_gets(BIO *bio, char *buf, int size) {
+ int i, j;
+ char *p;
+ BUF_MEM *b = (BUF_MEM *)bio->ptr;
+
+ BIO_clear_retry_flags(bio);
+ j = b->length;
+ if (size - 1 < j) {
+ j = size - 1;
+ }
+ if (j <= 0) {
+ if (size > 0) {
+ *buf = 0;
+ }
+ return 0;
+ }
+
+ p = b->data;
+ for (i = 0; i < j; i++) {
+ if (p[i] == '\n') {
+ i++;
+ break;
+ }
+ }
+
+ /* i is now the max num of bytes to copy, either j or up to and including the
+ * first newline */
+
+ i = mem_read(bio, buf, i);
+ if (i > 0) {
+ buf[i] = '\0';
+ }
+ return i;
+}
+
+static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ long ret = 1;
+ char **pptr;
+
+ BUF_MEM *b = (BUF_MEM *)bio->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ if (b->data != NULL) {
+ /* For read only case reset to the start again */
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ b->data -= b->max - b->length;
+ b->length = b->max;
+ } else {
+ memset(b->data, 0, b->max);
+ b->length = 0;
+ }
+ }
+ break;
+ case BIO_CTRL_EOF:
+ ret = (long)(b->length == 0);
+ break;
+ case BIO_C_SET_BUF_MEM_EOF_RETURN:
+ bio->num = (int)num;
+ break;
+ case BIO_CTRL_INFO:
+ ret = (long)b->length;
+ if (ptr != NULL) {
+ pptr = (char **)ptr;
+ *pptr = (char *)&b->data[0];
+ }
+ break;
+ case BIO_C_SET_BUF_MEM:
+ mem_free(bio);
+ bio->shutdown = (int)num;
+ bio->ptr = ptr;
+ break;
+ case BIO_C_GET_BUF_MEM_PTR:
+ if (ptr != NULL) {
+ pptr = (char **)ptr;
+ *pptr = (char *)b;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)bio->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = (int)num;
+ break;
+
+ case BIO_CTRL_WPENDING:
+ ret = 0L;
+ break;
+ case BIO_CTRL_PENDING:
+ ret = (long)b->length;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static const BIO_METHOD mem_method = {
+ BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts,
+ mem_gets, mem_ctrl, mem_new, mem_free, NULL, };
+
+const BIO_METHOD *BIO_s_mem(void) { return &mem_method; }
+
+int BIO_mem_contents(const BIO *bio, const uint8_t **out_contents,
+ size_t *out_len) {
+ const BUF_MEM *b;
+ if (bio->method != &mem_method) {
+ return 0;
+ }
+
+ b = (BUF_MEM *)bio->ptr;
+ *out_contents = (uint8_t *)b->data;
+ *out_len = b->length;
+ return 1;
+}
+
+long BIO_get_mem_data(BIO *bio, char **contents) {
+ return BIO_ctrl(bio, BIO_CTRL_INFO, 0, (char *) contents);
+}
+
+int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) {
+ return BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, (char *) out);
+}
+
+int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) {
+ return BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, (char *) b);
+}
+
+int BIO_set_mem_eof_return(BIO *bio, int eof_value) {
+ return BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, NULL);
+}
diff --git a/src/crypto/bio/bio_test.c b/src/crypto/bio/bio_test.c
new file mode 100644
index 0000000..cad4cf3
--- /dev/null
+++ b/src/crypto/bio/bio_test.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 201410L
+#endif
+
+#include <openssl/base.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#include <io.h>
+#pragma warning(push, 3)
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+#pragma warning(pop)
+#endif
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#define MIN(a, b) ((a < b) ? a : b)
+
+#if !defined(OPENSSL_WINDOWS)
+static int closesocket(int sock) {
+ return close(sock);
+}
+
+static void print_socket_error(const char *func) {
+ perror(func);
+}
+#else
+static void print_socket_error(const char *func) {
+ fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
+}
+#endif
+
+static int test_socket_connect(void) {
+ int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
+ int sock;
+ struct sockaddr_in sin;
+ socklen_t sockaddr_len = sizeof(sin);
+ static const char kTestMessage[] = "test";
+ char hostname[80], buf[5];
+ BIO *bio;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
+ print_socket_error("inet_pton");
+ return 0;
+ }
+
+ if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
+ print_socket_error("bind");
+ return 0;
+ }
+
+ if (listen(listening_sock, 1)) {
+ print_socket_error("listen");
+ return 0;
+ }
+
+ if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
+ sockaddr_len != sizeof(sin)) {
+ print_socket_error("getsockname");
+ return 0;
+ }
+
+ BIO_snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
+ ntohs(sin.sin_port));
+ bio = BIO_new_connect(hostname);
+ if (!bio) {
+ fprintf(stderr, "BIO_new_connect failed.\n");
+ return 0;
+ }
+
+ if (BIO_write(bio, kTestMessage, sizeof(kTestMessage)) !=
+ sizeof(kTestMessage)) {
+ fprintf(stderr, "BIO_write failed.\n");
+ BIO_print_errors_fp(stderr);
+ return 0;
+ }
+
+ sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
+ if (sock < 0) {
+ print_socket_error("accept");
+ return 0;
+ }
+
+ if (recv(sock, buf, sizeof(buf), 0) != sizeof(kTestMessage)) {
+ print_socket_error("read");
+ return 0;
+ }
+
+ if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
+ return 0;
+ }
+
+ closesocket(sock);
+ closesocket(listening_sock);
+ BIO_free(bio);
+
+ return 1;
+}
+
+
+/* bio_read_zero_copy_wrapper is a wrapper around the zero-copy APIs to make
+ * testing easier. */
+static size_t bio_read_zero_copy_wrapper(BIO *bio, uint8_t *data, size_t len) {
+ uint8_t *read_buf;
+ size_t read_buf_offset;
+ size_t available_bytes;
+ size_t len_read = 0;
+
+ do {
+ if (!BIO_zero_copy_get_read_buf(bio, &read_buf, &read_buf_offset,
+ &available_bytes)) {
+ return 0;
+ }
+
+ available_bytes = MIN(available_bytes, len - len_read);
+ memmove(data + len_read, read_buf + read_buf_offset, available_bytes);
+
+ BIO_zero_copy_get_read_buf_done(bio, available_bytes);
+
+ len_read += available_bytes;
+ } while (len - len_read > 0 && available_bytes > 0);
+
+ return len_read;
+}
+
+/* bio_write_zero_copy_wrapper is a wrapper around the zero-copy APIs to make
+ * testing easier. */
+static size_t bio_write_zero_copy_wrapper(BIO *bio, const uint8_t *data,
+ size_t len) {
+ uint8_t *write_buf;
+ size_t write_buf_offset;
+ size_t available_bytes;
+ size_t len_written = 0;
+
+ do {
+ if (!BIO_zero_copy_get_write_buf(bio, &write_buf, &write_buf_offset,
+ &available_bytes)) {
+ return 0;
+ }
+
+ available_bytes = MIN(available_bytes, len - len_written);
+ memmove(write_buf + write_buf_offset, data + len_written, available_bytes);
+
+ BIO_zero_copy_get_write_buf_done(bio, available_bytes);
+
+ len_written += available_bytes;
+ } while (len - len_written > 0 && available_bytes > 0);
+
+ return len_written;
+}
+
+static int test_zero_copy_bio_pairs(void) {
+ /* Test read and write, especially triggering the ring buffer wrap-around.*/
+ BIO* bio1;
+ BIO* bio2;
+ size_t i, j;
+ uint8_t bio1_application_send_buffer[1024];
+ uint8_t bio2_application_recv_buffer[1024];
+ size_t total_read = 0;
+ size_t total_write = 0;
+ uint8_t* write_buf;
+ size_t write_buf_offset;
+ size_t available_bytes;
+ size_t bytes_left;
+
+ const size_t kLengths[] = {254, 255, 256, 257, 510, 511, 512, 513};
+
+ /* These trigger ring buffer wrap around. */
+ const size_t kPartialLengths[] = {0, 1, 2, 3, 128, 255, 256, 257, 511, 512};
+
+ static const size_t kBufferSize = 512;
+
+ srand(1);
+ for (i = 0; i < sizeof(bio1_application_send_buffer); i++) {
+ bio1_application_send_buffer[i] = rand() & 255;
+ }
+
+ /* Transfer bytes from bio1_application_send_buffer to
+ * bio2_application_recv_buffer in various ways. */
+ for (i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
+ for (j = 0; j < sizeof(kPartialLengths) / sizeof(kPartialLengths[0]); j++) {
+ total_write = 0;
+ total_read = 0;
+
+ BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize);
+
+ total_write += bio_write_zero_copy_wrapper(
+ bio1, bio1_application_send_buffer, kLengths[i]);
+
+ /* This tests interleaved read/write calls. Do a read between zero copy
+ * write calls. */
+ if (!BIO_zero_copy_get_write_buf(bio1, &write_buf, &write_buf_offset,
+ &available_bytes)) {
+ return 0;
+ }
+
+ /* Free kPartialLengths[j] bytes in the beginning of bio1 write buffer.
+ * This enables ring buffer wrap around for the next write. */
+ total_read += BIO_read(bio2, bio2_application_recv_buffer + total_read,
+ kPartialLengths[j]);
+
+ size_t interleaved_write_len = MIN(kPartialLengths[j], available_bytes);
+
+ /* Write the data for the interleaved write call. If the buffer becomes
+ * empty after a read, the write offset is normally set to 0. Check that
+ * this does not happen for interleaved read/write and that
+ * |write_buf_offset| is still valid. */
+ memcpy(write_buf + write_buf_offset,
+ bio1_application_send_buffer + total_write, interleaved_write_len);
+ if (BIO_zero_copy_get_write_buf_done(bio1, interleaved_write_len)) {
+ total_write += interleaved_write_len;
+ }
+
+ /* Do another write in case |write_buf_offset| was wrapped */
+ total_write += bio_write_zero_copy_wrapper(
+ bio1, bio1_application_send_buffer + total_write,
+ kPartialLengths[j] - interleaved_write_len);
+
+ /* Drain the rest. */
+ bytes_left = BIO_pending(bio2);
+ total_read += bio_read_zero_copy_wrapper(
+ bio2, bio2_application_recv_buffer + total_read, bytes_left);
+
+ BIO_free(bio1);
+ BIO_free(bio2);
+
+ if (total_read != total_write) {
+ fprintf(stderr, "Lengths not equal in round (%u, %u)\n", (unsigned)i,
+ (unsigned)j);
+ return 0;
+ }
+ if (total_read > kLengths[i] + kPartialLengths[j]) {
+ fprintf(stderr, "Bad lengths in round (%u, %u)\n", (unsigned)i,
+ (unsigned)j);
+ return 0;
+ }
+ if (memcmp(bio1_application_send_buffer, bio2_application_recv_buffer,
+ total_read) != 0) {
+ fprintf(stderr, "Buffers not equal in round (%u, %u)\n", (unsigned)i,
+ (unsigned)j);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int test_printf(void) {
+ /* Test a short output, a very long one, and various sizes around
+ * 256 (the size of the buffer) to ensure edge cases are correct. */
+ static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
+ BIO *bio;
+ char string[1024];
+ int ret;
+ const uint8_t *contents;
+ size_t i, len;
+
+ bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ fprintf(stderr, "BIO_new failed\n");
+ return 0;
+ }
+
+ for (i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
+ if (kLengths[i] >= sizeof(string)) {
+ fprintf(stderr, "Bad test string length\n");
+ return 0;
+ }
+ memset(string, 'a', sizeof(string));
+ string[kLengths[i]] = '\0';
+
+ ret = BIO_printf(bio, "test %s", string);
+ if (ret != 5 + kLengths[i]) {
+ fprintf(stderr, "BIO_printf failed: %d\n", ret);
+ return 0;
+ }
+ if (!BIO_mem_contents(bio, &contents, &len)) {
+ fprintf(stderr, "BIO_mem_contents failed\n");
+ return 0;
+ }
+ if (len != 5 + kLengths[i] ||
+ strncmp((const char *)contents, "test ", 5) != 0 ||
+ strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
+ fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
+ return 0;
+ }
+
+ if (!BIO_reset(bio)) {
+ fprintf(stderr, "BIO_reset failed\n");
+ return 0;
+ }
+ }
+
+ BIO_free(bio);
+ return 1;
+}
+
+int main(void) {
+#if defined(OPENSSL_WINDOWS)
+ WSADATA wsa_data;
+ WORD wsa_version;
+ int wsa_err;
+#endif
+
+ CRYPTO_library_init();
+ ERR_load_crypto_strings();
+
+#if defined(OPENSSL_WINDOWS)
+ /* Initialize Winsock. */
+ wsa_version = MAKEWORD(2, 2);
+ wsa_err = WSAStartup(wsa_version, &wsa_data);
+ if (wsa_err != 0) {
+ fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
+ return 1;
+ }
+ if (wsa_data.wVersion != wsa_version) {
+ fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
+ return 1;
+ }
+#endif
+
+ if (!test_socket_connect()) {
+ return 1;
+ }
+
+ if (!test_printf()) {
+ return 1;
+ }
+
+ if (!test_zero_copy_bio_pairs()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/src/crypto/bio/buffer.c b/src/crypto/bio/buffer.c
new file mode 100644
index 0000000..5e423a1
--- /dev/null
+++ b/src/crypto/bio/buffer.c
@@ -0,0 +1,499 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+#define DEFAULT_BUFFER_SIZE 4096
+
+typedef struct bio_f_buffer_ctx_struct {
+ /* Buffers are setup like this:
+ *
+ * <---------------------- size ----------------------->
+ * +---------------------------------------------------+
+ * | consumed | remaining | free space |
+ * +---------------------------------------------------+
+ * <-- off --><------- len ------->
+ */
+
+ int ibuf_size; /* how big is the input buffer */
+ int obuf_size; /* how big is the output buffer */
+
+ char *ibuf; /* the char array */
+ int ibuf_len; /* how many bytes are in it */
+ int ibuf_off; /* write/read offset */
+
+ char *obuf; /* the char array */
+ int obuf_len; /* how many bytes are in it */
+ int obuf_off; /* write/read offset */
+} BIO_F_BUFFER_CTX;
+
+static int buffer_new(BIO *bio) {
+ BIO_F_BUFFER_CTX *ctx;
+
+ ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
+ if (ctx == NULL) {
+ return 0;
+ }
+ memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX));
+
+ ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
+ if (ctx->ibuf == NULL) {
+ goto err1;
+ }
+ ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
+ if (ctx->obuf == NULL) {
+ goto err2;
+ }
+ ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
+ ctx->obuf_size = DEFAULT_BUFFER_SIZE;
+
+ bio->init = 1;
+ bio->ptr = (char *)ctx;
+ return 1;
+
+err2:
+ OPENSSL_free(ctx->ibuf);
+
+err1:
+ OPENSSL_free(ctx);
+ return 0;
+}
+
+static int buffer_free(BIO *bio) {
+ BIO_F_BUFFER_CTX *ctx;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
+ if (ctx->ibuf != NULL) {
+ OPENSSL_free(ctx->ibuf);
+ }
+ if (ctx->obuf != NULL) {
+ OPENSSL_free(ctx->obuf);
+ }
+ OPENSSL_free(bio->ptr);
+
+ bio->ptr = NULL;
+ bio->init = 0;
+ bio->flags = 0;
+
+ return 1;
+}
+
+static int buffer_read(BIO *bio, char *out, int outl) {
+ int i, num = 0;
+ BIO_F_BUFFER_CTX *ctx;
+
+ ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
+
+ if (ctx == NULL || bio->next_bio == NULL) {
+ return 0;
+ }
+
+ num = 0;
+ BIO_clear_retry_flags(bio);
+
+ for (;;) {
+ i = ctx->ibuf_len;
+ /* If there is stuff left over, grab it */
+ if (i != 0) {
+ if (i > outl) {
+ i = outl;
+ }
+ memcpy(out, &ctx->ibuf[ctx->ibuf_off], i);
+ ctx->ibuf_off += i;
+ ctx->ibuf_len -= i;
+ num += i;
+ if (outl == i) {
+ return num;
+ }
+ outl -= i;
+ out += i;
+ }
+
+ /* We may have done a partial read. Try to do more. We have nothing in the
+ * buffer. If we get an error and have read some data, just return it and
+ * let them retry to get the error again. Copy direct to parent address
+ * space */
+ if (outl > ctx->ibuf_size) {
+ for (;;) {
+ i = BIO_read(bio->next_bio, out, outl);
+ if (i <= 0) {
+ BIO_copy_next_retry(bio);
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ num += i;
+ if (outl == i) {
+ return num;
+ }
+ out += i;
+ outl -= i;
+ }
+ }
+ /* else */
+
+ /* we are going to be doing some buffering */
+ i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size);
+ if (i <= 0) {
+ BIO_copy_next_retry(bio);
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ ctx->ibuf_off = 0;
+ ctx->ibuf_len = i;
+ }
+}
+
+static int buffer_write(BIO *b, const char *in, int inl) {
+ int i, num = 0;
+ BIO_F_BUFFER_CTX *ctx;
+
+ ctx = (BIO_F_BUFFER_CTX *)b->ptr;
+ if (ctx == NULL || b->next_bio == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(b);
+
+ for (;;) {
+ i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len);
+ /* add to buffer and return */
+ if (i >= inl) {
+ memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl);
+ ctx->obuf_len += inl;
+ return num + inl;
+ }
+ /* else */
+ /* stuff already in buffer, so add to it first, then flush */
+ if (ctx->obuf_len != 0) {
+ if (i > 0) {
+ memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i);
+ in += i;
+ inl -= i;
+ num += i;
+ ctx->obuf_len += i;
+ }
+
+ /* we now have a full buffer needing flushing */
+ for (;;) {
+ i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len);
+ if (i <= 0) {
+ BIO_copy_next_retry(b);
+
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ ctx->obuf_off += i;
+ ctx->obuf_len -= i;
+ if (ctx->obuf_len == 0) {
+ break;
+ }
+ }
+ }
+
+ /* we only get here if the buffer has been flushed and we
+ * still have stuff to write */
+ ctx->obuf_off = 0;
+
+ /* we now have inl bytes to write */
+ while (inl >= ctx->obuf_size) {
+ i = BIO_write(b->next_bio, in, inl);
+ if (i <= 0) {
+ BIO_copy_next_retry(b);
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ num += i;
+ in += i;
+ inl -= i;
+ if (inl == 0) {
+ return num;
+ }
+ }
+
+ /* copy the rest into the buffer since we have only a small
+ * amount left */
+ }
+}
+
+static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ BIO_F_BUFFER_CTX *ctx;
+ long ret = 1;
+ char *p1, *p2;
+ int r, *ip;
+ int ibs, obs;
+
+ ctx = (BIO_F_BUFFER_CTX *)b->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ ctx->ibuf_off = 0;
+ ctx->ibuf_len = 0;
+ ctx->obuf_off = 0;
+ ctx->obuf_len = 0;
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ break;
+
+ case BIO_CTRL_INFO:
+ ret = ctx->obuf_len;
+ break;
+
+ case BIO_CTRL_WPENDING:
+ ret = (long)ctx->obuf_len;
+ if (ret == 0) {
+ if (b->next_bio == NULL)
+ return 0;
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ }
+ break;
+
+ case BIO_CTRL_PENDING:
+ ret = (long)ctx->ibuf_len;
+ if (ret == 0) {
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ }
+ break;
+
+ case BIO_C_SET_BUFF_SIZE:
+ ip = (int *)ptr;
+ if (*ip == 0) {
+ ibs = (int)num;
+ obs = ctx->obuf_size;
+ } else /* if (*ip == 1) */ {
+ ibs = ctx->ibuf_size;
+ obs = (int)num;
+ }
+ p1 = ctx->ibuf;
+ p2 = ctx->obuf;
+ if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) {
+ p1 = (char *)OPENSSL_malloc(ibs);
+ if (p1 == NULL) {
+ goto malloc_error;
+ }
+ }
+ if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) {
+ p2 = (char *)OPENSSL_malloc(obs);
+ if (p2 == NULL) {
+ if (p1 != ctx->ibuf) {
+ OPENSSL_free(p1);
+ }
+ goto malloc_error;
+ }
+ }
+
+ if (ctx->ibuf != p1) {
+ OPENSSL_free(ctx->ibuf);
+ ctx->ibuf = p1;
+ ctx->ibuf_size = ibs;
+ }
+ ctx->ibuf_off = 0;
+ ctx->ibuf_len = 0;
+
+ if (ctx->obuf != p2) {
+ OPENSSL_free(ctx->obuf);
+ ctx->obuf = p2;
+ ctx->obuf_size = obs;
+ }
+ ctx->obuf_off = 0;
+ ctx->obuf_len = 0;
+ break;
+
+ case BIO_CTRL_FLUSH:
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+
+ while (ctx->obuf_len > 0) {
+ BIO_clear_retry_flags(b);
+ r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
+ ctx->obuf_len);
+ BIO_copy_next_retry(b);
+ if (r <= 0) {
+ return r;
+ }
+ ctx->obuf_off += r;
+ ctx->obuf_len -= r;
+ }
+
+ ctx->obuf_len = 0;
+ ctx->obuf_off = 0;
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ break;
+
+ default:
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+ BIO_clear_retry_flags(b);
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ BIO_copy_next_retry(b);
+ break;
+ }
+ return ret;
+
+malloc_error:
+ OPENSSL_PUT_ERROR(BIO, buffer_ctrl, ERR_R_MALLOC_FAILURE);
+ return 0;
+}
+
+static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
+ long ret = 1;
+
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+
+ switch (cmd) {
+ default:
+ ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
+ break;
+ }
+ return ret;
+}
+
+static int buffer_gets(BIO *b, char *buf, int size) {
+ BIO_F_BUFFER_CTX *ctx;
+ int num = 0, i, flag;
+ char *p;
+
+ ctx = (BIO_F_BUFFER_CTX *)b->ptr;
+ if (buf == NULL || size <= 0) {
+ return 0;
+ }
+
+ size--; /* reserve space for a '\0' */
+ BIO_clear_retry_flags(b);
+
+ for (;;) {
+ if (ctx->ibuf_len > 0) {
+ p = &ctx->ibuf[ctx->ibuf_off];
+ flag = 0;
+ for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
+ *(buf++) = p[i];
+ if (p[i] == '\n') {
+ flag = 1;
+ i++;
+ break;
+ }
+ }
+ num += i;
+ size -= i;
+ ctx->ibuf_len -= i;
+ ctx->ibuf_off += i;
+ if (flag || size == 0) {
+ *buf = '\0';
+ return num;
+ }
+ } else /* read another chunk */
+ {
+ i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
+ if (i <= 0) {
+ BIO_copy_next_retry(b);
+ *buf = '\0';
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ ctx->ibuf_len = i;
+ ctx->ibuf_off = 0;
+ }
+ }
+}
+
+static int buffer_puts(BIO *b, const char *str) {
+ return buffer_write(b, str, strlen(str));
+}
+
+static const BIO_METHOD methods_buffer = {
+ BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read,
+ buffer_puts, buffer_gets, buffer_ctrl, buffer_new,
+ buffer_free, buffer_callback_ctrl,
+};
+
+const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; }
+
+int BIO_set_read_buffer_size(BIO *bio, int buffer_size) {
+ return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0);
+}
+
+int BIO_set_write_buffer_size(BIO *bio, int buffer_size) {
+ return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1);
+}
diff --git a/src/crypto/bio/connect.c b/src/crypto/bio/connect.c
new file mode 100644
index 0000000..66ac3a7
--- /dev/null
+++ b/src/crypto/bio/connect.c
@@ -0,0 +1,541 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#else
+#pragma warning(push, 3)
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+#pragma warning(pop)
+#endif
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+enum {
+ BIO_CONN_S_BEFORE,
+ BIO_CONN_S_BLOCKED_CONNECT,
+ BIO_CONN_S_OK,
+};
+
+typedef struct bio_connect_st {
+ int state;
+
+ char *param_hostname;
+ char *param_port;
+ int nbio;
+
+ uint8_t ip[4];
+ unsigned short port;
+
+ struct sockaddr_storage them;
+ socklen_t them_length;
+
+ /* the file descriptor is kept in bio->num in order to match the socket
+ * BIO. */
+
+ /* info_callback is called when the connection is initially made
+ * callback(BIO,state,ret); The callback should return 'ret', state is for
+ * compatibility with the SSL info_callback. */
+ int (*info_callback)(const BIO *bio, int state, int ret);
+} BIO_CONNECT;
+
+#if !defined(OPENSSL_WINDOWS)
+static int closesocket(int sock) {
+ return close(sock);
+}
+#endif
+
+/* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in
+ * big-endian order), if |ss| contains an IPv4 socket address. */
+static void maybe_copy_ipv4_address(uint8_t *ipv4,
+ const struct sockaddr_storage *ss) {
+ const struct sockaddr_in *sin;
+
+ if (ss->ss_family != AF_INET) {
+ return;
+ }
+
+ sin = (const struct sockaddr_in*) ss;
+ memcpy(ipv4, &sin->sin_addr, 4);
+}
+
+static int conn_state(BIO *bio, BIO_CONNECT *c) {
+ int ret = -1, i;
+ char *p, *q;
+ int (*cb)(const BIO *, int, int) = NULL;
+
+ if (c->info_callback != NULL) {
+ cb = c->info_callback;
+ }
+
+ for (;;) {
+ switch (c->state) {
+ case BIO_CONN_S_BEFORE:
+ p = c->param_hostname;
+ if (p == NULL) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_HOSTNAME_SPECIFIED);
+ goto exit_loop;
+ }
+ for (; *p != 0; p++) {
+ if (*p == ':' || *p == '/') {
+ break;
+ }
+ }
+
+ i = *p;
+ if (i == ':' || i == '/') {
+ *(p++) = 0;
+ if (i == ':') {
+ for (q = p; *q; q++) {
+ if (*q == '/') {
+ *q = 0;
+ break;
+ }
+ }
+ if (c->param_port != NULL) {
+ OPENSSL_free(c->param_port);
+ }
+ c->param_port = BUF_strdup(p);
+ }
+ }
+
+ if (c->param_port == NULL) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_PORT_SPECIFIED);
+ ERR_add_error_data(2, "host=", c->param_hostname);
+ goto exit_loop;
+ }
+
+ if (!bio_ip_and_port_to_socket_and_addr(
+ &bio->num, &c->them, &c->them_length, c->param_hostname,
+ c->param_port)) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_UNABLE_TO_CREATE_SOCKET);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
+ goto exit_loop;
+ }
+
+ memset(c->ip, 0, 4);
+ maybe_copy_ipv4_address(c->ip, &c->them);
+
+ if (c->nbio) {
+ if (!bio_socket_nbio(bio->num, 1)) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_ERROR_SETTING_NBIO);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":",
+ c->param_port);
+ goto exit_loop;
+ }
+ }
+
+ i = 1;
+ ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
+ sizeof(i));
+ if (ret < 0) {
+ OPENSSL_PUT_SYSTEM_ERROR(setsockopt);
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_KEEPALIVE);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
+ goto exit_loop;
+ }
+
+ BIO_clear_retry_flags(bio);
+ ret = connect(bio->num, (struct sockaddr*) &c->them, c->them_length);
+ if (ret < 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
+ c->state = BIO_CONN_S_BLOCKED_CONNECT;
+ bio->retry_reason = BIO_RR_CONNECT;
+ } else {
+ OPENSSL_PUT_SYSTEM_ERROR(connect);
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_CONNECT_ERROR);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":",
+ c->param_port);
+ }
+ goto exit_loop;
+ } else {
+ c->state = BIO_CONN_S_OK;
+ }
+ break;
+
+ case BIO_CONN_S_BLOCKED_CONNECT:
+ i = bio_sock_error(bio->num);
+ if (i) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
+ c->state = BIO_CONN_S_BLOCKED_CONNECT;
+ bio->retry_reason = BIO_RR_CONNECT;
+ ret = -1;
+ } else {
+ BIO_clear_retry_flags(bio);
+ OPENSSL_PUT_SYSTEM_ERROR(connect);
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NBIO_CONNECT_ERROR);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
+ ret = 0;
+ }
+ goto exit_loop;
+ } else {
+ c->state = BIO_CONN_S_OK;
+ }
+ break;
+
+ case BIO_CONN_S_OK:
+ ret = 1;
+ goto exit_loop;
+ default:
+ assert(0);
+ goto exit_loop;
+ }
+
+ if (cb != NULL) {
+ ret = cb((BIO *)bio, c->state, ret);
+ if (ret == 0) {
+ goto end;
+ }
+ }
+ }
+
+exit_loop:
+ if (cb != NULL) {
+ ret = cb((BIO *)bio, c->state, ret);
+ }
+
+end:
+ return ret;
+}
+
+static BIO_CONNECT *BIO_CONNECT_new(void) {
+ BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT));
+
+ if (ret == NULL) {
+ return NULL;
+ }
+ memset(ret, 0, sizeof(BIO_CONNECT));
+
+ ret->state = BIO_CONN_S_BEFORE;
+ return ret;
+}
+
+static void BIO_CONNECT_free(BIO_CONNECT *c) {
+ if (c == NULL) {
+ return;
+ }
+
+ if (c->param_hostname != NULL) {
+ OPENSSL_free(c->param_hostname);
+ }
+ if (c->param_port != NULL) {
+ OPENSSL_free(c->param_port);
+ }
+ OPENSSL_free(c);
+}
+
+static int conn_new(BIO *bio) {
+ bio->init = 0;
+ bio->num = -1;
+ bio->flags = 0;
+ bio->ptr = (char *)BIO_CONNECT_new();
+ return bio->ptr != NULL;
+}
+
+static void conn_close_socket(BIO *bio) {
+ BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr;
+
+ if (bio->num == -1) {
+ return;
+ }
+
+ /* Only do a shutdown if things were established */
+ if (c->state == BIO_CONN_S_OK) {
+ shutdown(bio->num, 2);
+ }
+ closesocket(bio->num);
+ bio->num = -1;
+}
+
+static int conn_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->shutdown) {
+ conn_close_socket(bio);
+ }
+
+ BIO_CONNECT_free((BIO_CONNECT*) bio->ptr);
+
+ return 1;
+}
+
+static int conn_read(BIO *bio, char *out, int out_len) {
+ int ret = 0;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+ if (data->state != BIO_CONN_S_OK) {
+ ret = conn_state(bio, data);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ bio_clear_socket_error();
+ ret = recv(bio->num, out, out_len, 0);
+ BIO_clear_retry_flags(bio);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_read(bio);
+ }
+ }
+
+ return ret;
+}
+
+static int conn_write(BIO *bio, const char *in, int in_len) {
+ int ret;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+ if (data->state != BIO_CONN_S_OK) {
+ ret = conn_state(bio, data);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ bio_clear_socket_error();
+ ret = send(bio->num, in, in_len, 0);
+ BIO_clear_retry_flags(bio);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_write(bio);
+ }
+ }
+
+ return ret;
+}
+
+static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ int *ip;
+ const char **pptr;
+ long ret = 1;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ ret = 0;
+ data->state = BIO_CONN_S_BEFORE;
+ conn_close_socket(bio);
+ bio->flags = 0;
+ break;
+ case BIO_C_DO_STATE_MACHINE:
+ /* use this one to start the connection */
+ if (data->state != BIO_CONN_S_OK)
+ ret = (long)conn_state(bio, data);
+ else
+ ret = 1;
+ break;
+ case BIO_C_GET_CONNECT:
+ /* TODO(fork): can this be removed? (Or maybe this whole file). */
+ if (ptr != NULL) {
+ pptr = (const char **)ptr;
+ if (num == 0) {
+ *pptr = data->param_hostname;
+ } else if (num == 1) {
+ *pptr = data->param_port;
+ } else if (num == 2) {
+ *pptr = (char *) &data->ip[0];
+ } else if (num == 3) {
+ *((int *)ptr) = data->port;
+ }
+ if (!bio->init) {
+ *pptr = "not initialized";
+ }
+ ret = 1;
+ }
+ break;
+ case BIO_C_SET_CONNECT:
+ if (ptr != NULL) {
+ bio->init = 1;
+ if (num == 0) {
+ if (data->param_hostname != NULL) {
+ OPENSSL_free(data->param_hostname);
+ }
+ data->param_hostname = BUF_strdup(ptr);
+ } else if (num == 1) {
+ if (data->param_port != NULL) {
+ OPENSSL_free(data->param_port);
+ }
+ data->param_port = BUF_strdup(ptr);
+ } else {
+ ret = 0;
+ }
+ }
+ break;
+ case BIO_C_SET_NBIO:
+ data->nbio = (int)num;
+ break;
+ case BIO_C_GET_FD:
+ if (bio->init) {
+ ip = (int *)ptr;
+ if (ip != NULL) {
+ *ip = bio->num;
+ }
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = bio->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = (int)num;
+ break;
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ break;
+ case BIO_CTRL_FLUSH:
+ break;
+ case BIO_CTRL_SET_CALLBACK: {
+#if 0 /* FIXME: Should this be used? -- Richard Levitte */
+ OPENSSL_PUT_ERROR(BIO, XXX, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ ret = -1;
+#else
+ ret = 0;
+#endif
+ } break;
+ case BIO_CTRL_GET_CALLBACK: {
+ int (**fptr)(const BIO *bio, int state, int xret);
+ fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
+ *fptr = data->info_callback;
+ } break;
+ default:
+ ret = 0;
+ break;
+ }
+ return (ret);
+}
+
+static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
+ long ret = 1;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_SET_CALLBACK: {
+ data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
+ } break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int conn_puts(BIO *bp, const char *str) {
+ return conn_write(bp, str, strlen(str));
+}
+
+BIO *BIO_new_connect(const char *hostname) {
+ BIO *ret;
+
+ ret = BIO_new(BIO_s_connect());
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (!BIO_set_conn_hostname(ret, hostname)) {
+ BIO_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+static const BIO_METHOD methods_connectp = {
+ BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read,
+ conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new,
+ conn_free, conn_callback_ctrl,
+};
+
+const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; }
+
+int BIO_set_conn_hostname(BIO *bio, const char *name) {
+ return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name);
+}
+
+int BIO_set_conn_port(BIO *bio, const char *port_str) {
+ return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
+}
+
+int BIO_set_nbio(BIO *bio, int on) {
+ return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
+}
diff --git a/src/crypto/bio/fd.c b/src/crypto/bio/fd.c
new file mode 100644
index 0000000..6b70eac
--- /dev/null
+++ b/src/crypto/bio/fd.c
@@ -0,0 +1,270 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <unistd.h>
+#else
+#include <io.h>
+#pragma warning(push, 3)
+#include <Windows.h>
+#pragma warning(pop)
+#endif
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int bio_fd_non_fatal_error(int err) {
+ if (
+#ifdef EWOULDBLOCK
+ err == EWOULDBLOCK ||
+#endif
+#ifdef WSAEWOULDBLOCK
+ err == WSAEWOULDBLOCK ||
+#endif
+#ifdef ENOTCONN
+ err == ENOTCONN ||
+#endif
+#ifdef EINTR
+ err == EINTR ||
+#endif
+#ifdef EAGAIN
+ err == EAGAIN ||
+#endif
+#ifdef EPROTO
+ err == EPROTO ||
+#endif
+#ifdef EINPROGRESS
+ err == EINPROGRESS ||
+#endif
+#ifdef EALREADY
+ err == EALREADY ||
+#endif
+ 0) {
+ return 1;
+ }
+ return 0;
+}
+
+#if defined(OPENSSL_WINDOWS)
+int bio_fd_should_retry(int i) {
+ if (i == -1) {
+ return bio_fd_non_fatal_error((int)GetLastError());
+ }
+ return 0;
+}
+#else
+int bio_fd_should_retry(int i) {
+ if (i == -1) {
+ return bio_fd_non_fatal_error(errno);
+ }
+ return 0;
+}
+#endif
+
+BIO *BIO_new_fd(int fd, int close_flag) {
+ BIO *ret = BIO_new(BIO_s_fd());
+ if (ret == NULL) {
+ return NULL;
+ }
+ BIO_set_fd(ret, fd, close_flag);
+ return ret;
+}
+
+static int fd_new(BIO *bio) {
+ /* num is used to store the file descriptor. */
+ bio->num = -1;
+ return 1;
+}
+
+static int fd_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->shutdown) {
+ if (bio->init) {
+ close(bio->num);
+ }
+ bio->init = 0;
+ }
+ return 1;
+}
+
+static int fd_read(BIO *b, char *out, int outl) {
+ int ret = 0;
+
+ ret = read(b->num, out, outl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_read(b);
+ }
+ }
+
+ return ret;
+}
+
+static int fd_write(BIO *b, const char *in, int inl) {
+ int ret = write(b->num, in, inl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_write(b);
+ }
+ }
+
+ return ret;
+}
+
+static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ long ret = 1;
+ int *ip;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ num = 0;
+ case BIO_C_FILE_SEEK:
+ ret = 0;
+ if (b->init) {
+ ret = (long)lseek(b->num, num, SEEK_SET);
+ }
+ break;
+ case BIO_C_FILE_TELL:
+ case BIO_CTRL_INFO:
+ ret = 0;
+ if (b->init) {
+ ret = (long)lseek(b->num, 0, SEEK_CUR);
+ }
+ break;
+ case BIO_C_SET_FD:
+ fd_free(b);
+ b->num = *((int *)ptr);
+ b->shutdown = (int)num;
+ b->init = 1;
+ break;
+ case BIO_C_GET_FD:
+ if (b->init) {
+ ip = (int *)ptr;
+ if (ip != NULL) {
+ *ip = b->num;
+ }
+ return 1;
+ } else {
+ ret = 0;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown = (int)num;
+ break;
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int fd_puts(BIO *bp, const char *str) {
+ return fd_write(bp, str, strlen(str));
+}
+
+static int fd_gets(BIO *bp, char *buf, int size) {
+ char *ptr = buf;
+ char *end = buf + size - 1;
+
+ if (size <= 0) {
+ return 0;
+ }
+
+ while (ptr < end && fd_read(bp, ptr, 1) > 0 && ptr[0] != '\n') {
+ ptr++;
+ }
+
+ ptr[0] = '\0';
+
+ return ptr - buf;
+}
+
+static const BIO_METHOD methods_fdp = {
+ BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts,
+ fd_gets, fd_ctrl, fd_new, fd_free, NULL, };
+
+const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; }
+
+int BIO_set_fd(BIO *bio, int fd, int close_flag) {
+ return BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd);
+}
+
+int BIO_get_fd(BIO *bio, int *out_fd) {
+ return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd);
+}
diff --git a/src/crypto/bio/file.c b/src/crypto/bio/file.c
new file mode 100644
index 0000000..7f57aad
--- /dev/null
+++ b/src/crypto/bio/file.c
@@ -0,0 +1,350 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#if defined(__linux) || defined(__sun) || defined(__hpux)
+/* Following definition aliases fopen to fopen64 on above mentioned
+ * platforms. This makes it possible to open and sequentially access
+ * files larger than 2GB from 32-bit application. It does not allow to
+ * traverse them beyond 2GB with fseek/ftell, but on the other hand *no*
+ * 32-bit platform permits that, not with fseek/ftell. Not to mention
+ * that breaking 2GB limit for seeking would require surgery to *our*
+ * API. But sequential access suffices for practical cases when you
+ * can run into large files, such as fingerprinting, so we can let API
+ * alone. For reference, the list of 32-bit platforms which allow for
+ * sequential access of large files without extra "magic" comprise *BSD,
+ * Darwin, IRIX...
+ */
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+#endif
+
+#include <openssl/bio.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+#define BIO_FP_READ 0x02
+#define BIO_FP_WRITE 0x04
+#define BIO_FP_APPEND 0x08
+
+static FILE *open_file(const char *filename, const char *mode) {
+#if defined(_WIN32) && defined(CP_UTF8)
+ int sz, len_0 = (int)strlen(filename) + 1;
+ DWORD flags;
+
+ /* Basically there are three cases to cover: a) filename is pure ASCII
+ * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one
+ * containing 8-bit characters that are meaningful in current system locale.
+ * If filename is pure ASCII or real UTF-8 encoded string,
+ * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized
+ * string, chances are that MultiByteToWideChar fails reporting
+ * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */
+ if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS),
+ filename, len_0, NULL, 0)) > 0 ||
+ (GetLastError() == ERROR_INVALID_FLAGS &&
+ (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL,
+ 0)) > 0)) {
+ WCHAR wmode[8];
+ WCHAR *wfilename = _alloca(sz * sizeof(WCHAR));
+
+ if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) &&
+ MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode,
+ sizeof(wmode) / sizeof(wmode[0])) &&
+ (file = _wfopen(wfilename, wmode)) == NULL &&
+ (errno == ENOENT ||
+ errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename
+ * could still have been locale-ized... */
+ return fopen(filename, mode);
+ } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+ return fopen(filename, mode);
+ }
+#else
+ return fopen(filename, mode);
+#endif
+}
+
+BIO *BIO_new_file(const char *filename, const char *mode) {
+ BIO *ret;
+ FILE *file;
+
+ file = open_file(filename, mode);
+ if (file == NULL) {
+ OPENSSL_PUT_SYSTEM_ERROR(fopen);
+
+ ERR_add_error_data(5, "fopen('", filename, "','", mode, "')");
+ if (errno == ENOENT) {
+ OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_NO_SUCH_FILE);
+ } else {
+ OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_SYS_LIB);
+ }
+ return NULL;
+ }
+
+ ret = BIO_new(BIO_s_file());
+ if (ret == NULL) {
+ fclose(file);
+ return NULL;
+ }
+
+ BIO_set_fp(ret, file, BIO_CLOSE);
+ return ret;
+}
+
+BIO *BIO_new_fp(FILE *stream, int close_flag) {
+ BIO *ret = BIO_new(BIO_s_file());
+
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ BIO_set_fp(ret, stream, close_flag);
+ return ret;
+}
+
+static int file_new(BIO *bio) { return 1; }
+
+static int file_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (!bio->shutdown) {
+ return 1;
+ }
+
+ if (bio->init && bio->ptr != NULL) {
+ fclose(bio->ptr);
+ bio->ptr = NULL;
+ }
+ bio->init = 0;
+
+ return 1;
+}
+
+static int file_read(BIO *b, char *out, int outl) {
+ int ret = 0;
+
+ if (!b->init) {
+ return 0;
+ }
+
+ ret = fread(out, 1, outl, (FILE *)b->ptr);
+ if (ret == 0 && ferror((FILE *)b->ptr)) {
+ OPENSSL_PUT_SYSTEM_ERROR(fread);
+ OPENSSL_PUT_ERROR(BIO, file_read, ERR_R_SYS_LIB);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int file_write(BIO *b, const char *in, int inl) {
+ int ret = 0;
+
+ if (!b->init) {
+ return 0;
+ }
+
+ ret = fwrite(in, inl, 1, (FILE *)b->ptr);
+ if (ret > 0) {
+ ret = inl;
+ }
+ return ret;
+}
+
+static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ long ret = 1;
+ FILE *fp = (FILE *)b->ptr;
+ FILE **fpp;
+ char p[4];
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ num = 0;
+ case BIO_C_FILE_SEEK:
+ ret = (long)fseek(fp, num, 0);
+ break;
+ case BIO_CTRL_EOF:
+ ret = (long)feof(fp);
+ break;
+ case BIO_C_FILE_TELL:
+ case BIO_CTRL_INFO:
+ ret = ftell(fp);
+ break;
+ case BIO_C_SET_FILE_PTR:
+ file_free(b);
+ b->shutdown = (int)num & BIO_CLOSE;
+ b->ptr = ptr;
+ b->init = 1;
+ break;
+ case BIO_C_SET_FILENAME:
+ file_free(b);
+ b->shutdown = (int)num & BIO_CLOSE;
+ if (num & BIO_FP_APPEND) {
+ if (num & BIO_FP_READ) {
+ BUF_strlcpy(p, "a+", sizeof(p));
+ } else {
+ BUF_strlcpy(p, "a", sizeof(p));
+ }
+ } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) {
+ BUF_strlcpy(p, "r+", sizeof(p));
+ } else if (num & BIO_FP_WRITE) {
+ BUF_strlcpy(p, "w", sizeof(p));
+ } else if (num & BIO_FP_READ) {
+ BUF_strlcpy(p, "r", sizeof(p));
+ } else {
+ OPENSSL_PUT_ERROR(BIO, file_ctrl, BIO_R_BAD_FOPEN_MODE);
+ ret = 0;
+ break;
+ }
+ fp = open_file(ptr, p);
+ if (fp == NULL) {
+ OPENSSL_PUT_SYSTEM_ERROR(fopen);
+ ERR_add_error_data(5, "fopen('", ptr, "','", p, "')");
+ OPENSSL_PUT_ERROR(BIO, file_ctrl, ERR_R_SYS_LIB);
+ ret = 0;
+ break;
+ }
+ b->ptr = fp;
+ b->init = 1;
+ break;
+ case BIO_C_GET_FILE_PTR:
+ /* the ptr parameter is actually a FILE ** in this case. */
+ if (ptr != NULL) {
+ fpp = (FILE **)ptr;
+ *fpp = (FILE *)b->ptr;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown = (int)num;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 0 == fflush((FILE *)b->ptr);
+ break;
+ case BIO_CTRL_WPENDING:
+ case BIO_CTRL_PENDING:
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int file_gets(BIO *bp, char *buf, int size) {
+ int ret = 0;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (!fgets(buf, size, (FILE *)bp->ptr)) {
+ buf[0] = 0;
+ goto err;
+ }
+ ret = strlen(buf);
+
+err:
+ return ret;
+}
+
+static int file_puts(BIO *bp, const char *str) {
+ return file_write(bp, str, strlen(str));
+}
+
+static const BIO_METHOD methods_filep = {
+ BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts,
+ file_gets, file_ctrl, file_new, file_free, NULL, };
+
+const BIO_METHOD *BIO_s_file(void) { return &methods_filep; }
+
+
+int BIO_get_fp(BIO *bio, FILE **out_file) {
+ return BIO_ctrl(bio, BIO_C_GET_FILE_PTR, 0, (char*) out_file);
+}
+
+int BIO_set_fp(BIO *bio, FILE *file, int close_flag) {
+ return BIO_ctrl(bio, BIO_C_SET_FILE_PTR, close_flag, (char *) file);
+}
+
+int BIO_read_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ,
+ (char *)filename);
+}
+
+int BIO_write_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE,
+ (char *)filename);
+}
+
+int BIO_append_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_APPEND,
+ (char *)filename);
+}
+
+int BIO_rw_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME,
+ BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, (char *)filename);
+}
diff --git a/src/crypto/bio/hexdump.c b/src/crypto/bio/hexdump.c
new file mode 100644
index 0000000..17f5518
--- /dev/null
+++ b/src/crypto/bio/hexdump.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <limits.h>
+#include <string.h>
+
+
+/* hexdump_ctx contains the state of a hexdump. */
+struct hexdump_ctx {
+ BIO *bio;
+ char right_chars[18]; /* the contents of the right-hand side, ASCII dump. */
+ unsigned used; /* number of bytes in the current line. */
+ size_t n; /* number of bytes total. */
+ unsigned indent;
+};
+
+static void hexbyte(char *out, uint8_t b) {
+ static const char hextable[] = "0123456789abcdef";
+ out[0] = hextable[b>>4];
+ out[1] = hextable[b&0x0f];
+}
+
+static char to_char(uint8_t b) {
+ if (b < 32 || b > 126) {
+ return '.';
+ }
+ return b;
+}
+
+/* hexdump_write adds |len| bytes of |data| to the current hex dump described by
+ * |ctx|. */
+static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data,
+ size_t len) {
+ size_t i;
+ char buf[10];
+ unsigned l;
+
+ /* Output lines look like:
+ * 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=|
+ * ^ offset ^ extra space ^ ASCII of line
+ */
+
+ for (i = 0; i < len; i++) {
+ if (ctx->used == 0) {
+ /* The beginning of a line. */
+ BIO_indent(ctx->bio, ctx->indent, UINT_MAX);
+
+ hexbyte(&buf[0], ctx->n >> 24);
+ hexbyte(&buf[2], ctx->n >> 16);
+ hexbyte(&buf[4], ctx->n >> 8);
+ hexbyte(&buf[6], ctx->n);
+ buf[8] = buf[9] = ' ';
+ if (BIO_write(ctx->bio, buf, 10) < 0) {
+ return 0;
+ }
+ }
+
+ hexbyte(buf, data[i]);
+ buf[2] = ' ';
+ l = 3;
+ if (ctx->used == 7) {
+ /* There's an additional space after the 8th byte. */
+ buf[3] = ' ';
+ l = 4;
+ } else if (ctx->used == 15) {
+ /* At the end of the line there's an extra space and the bar for the
+ * right column. */
+ buf[3] = ' ';
+ buf[4] = '|';
+ l = 5;
+ }
+
+ if (BIO_write(ctx->bio, buf, l) < 0) {
+ return 0;
+ }
+ ctx->right_chars[ctx->used] = to_char(data[i]);
+ ctx->used++;
+ ctx->n++;
+ if (ctx->used == 16) {
+ ctx->right_chars[16] = '|';
+ ctx->right_chars[17] = '\n';
+ if (BIO_write(ctx->bio, ctx->right_chars, sizeof(ctx->right_chars)) < 0) {
+ return 0;
+ }
+ ctx->used = 0;
+ }
+ }
+
+ return 1;
+}
+
+/* finish flushes any buffered data in |ctx|. */
+static int finish(struct hexdump_ctx *ctx) {
+ /* See the comments in |hexdump| for the details of this format. */
+ const unsigned n_bytes = ctx->used;
+ unsigned l;
+ char buf[5];
+
+ if (n_bytes == 0) {
+ return 1;
+ }
+
+ memset(buf, ' ', 4);
+ buf[4] = '|';
+
+ for (; ctx->used < 16; ctx->used++) {
+ l = 3;
+ if (ctx->used == 7) {
+ l = 4;
+ } else if (ctx->used == 15) {
+ l = 5;
+ }
+ if (BIO_write(ctx->bio, buf, l) < 0) {
+ return 0;
+ }
+ }
+
+ ctx->right_chars[n_bytes] = '|';
+ ctx->right_chars[n_bytes + 1] = '\n';
+ if (BIO_write(ctx->bio, ctx->right_chars, n_bytes + 2) < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) {
+ struct hexdump_ctx ctx;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.bio = bio;
+ ctx.indent = indent;
+
+ if (!hexdump_write(&ctx, data, len) || !finish(&ctx)) {
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/src/crypto/bio/internal.h b/src/crypto/bio/internal.h
new file mode 100644
index 0000000..d9a34f1
--- /dev/null
+++ b/src/crypto/bio/internal.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_BIO_INTERNAL_H
+#define OPENSSL_HEADER_BIO_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#if defined(OPENSSL_PNACL)
+/* newlib uses u_short in socket.h without defining it. */
+typedef unsigned short u_short;
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#else
+typedef int socklen_t;
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr|
+ * and |*out_addr_length| with the correct values for connecting to |hostname|
+ * on |port_str|. It returns one on success or zero on error. */
+int bio_ip_and_port_to_socket_and_addr(int *out_sock,
+ struct sockaddr_storage *out_addr,
+ socklen_t *out_addr_length,
+ const char *hostname,
+ const char *port_str);
+
+/* BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on
+ * success and zero otherwise. */
+int bio_socket_nbio(int sock, int on);
+
+/* BIO_clear_socket_error clears the last system socket error.
+ *
+ * TODO(fork): remove all callers of this. */
+void bio_clear_socket_error(void);
+
+/* BIO_sock_error returns the last socket error on |sock|. */
+int bio_sock_error(int sock);
+
+/* BIO_fd_should_retry returns non-zero if |return_value| indicates an error
+ * and |errno| indicates that it's non-fatal. */
+int bio_fd_should_retry(int return_value);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_BIO_INTERNAL_H */
diff --git a/src/crypto/bio/pair.c b/src/crypto/bio/pair.c
new file mode 100644
index 0000000..de2b4cb
--- /dev/null
+++ b/src/crypto/bio/pair.c
@@ -0,0 +1,821 @@
+/* ====================================================================
+ * 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). */
+
+#include <openssl/bio.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+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;
+ uint8_t *buf; /* "size" elements (if != NULL) */
+ char buf_externally_allocated; /* true iff buf was externally allocated. */
+
+ char zero_copy_read_lock; /* true iff a zero copy read operation
+ * is in progress. */
+ char zero_copy_write_lock; /* true iff a zero copy write operation
+ * is in progress. */
+
+ 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;
+ }
+ memset(b, 0, sizeof(struct bio_bio_st));
+
+ b->size = 17 * 1024; /* enough for one TLS record (just a default) */
+ bio->ptr = b;
+ return 1;
+}
+
+static void bio_destroy_pair(BIO *bio) {
+ struct bio_bio_st *b = bio->ptr;
+ BIO *peer_bio;
+ struct bio_bio_st *peer_b;
+
+ if (b == NULL) {
+ return;
+ }
+
+ peer_bio = b->peer;
+ if (peer_bio == NULL) {
+ return;
+ }
+
+ peer_b = peer_bio->ptr;
+
+ assert(peer_b != NULL);
+ assert(peer_b->peer == bio);
+
+ peer_b->peer = NULL;
+ peer_bio->init = 0;
+ assert(peer_b->buf != NULL);
+ peer_b->len = 0;
+ peer_b->offset = 0;
+
+ b->peer = NULL;
+ bio->init = 0;
+ assert(b->buf != NULL);
+ b->len = 0;
+ b->offset = 0;
+}
+
+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 && !b->buf_externally_allocated) {
+ OPENSSL_free(b->buf);
+ }
+
+ OPENSSL_free(b);
+
+ return 1;
+}
+
+static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b,
+ uint8_t** out_read_buf,
+ size_t* out_buf_offset) {
+ size_t max_available;
+ if (peer_b->len > peer_b->size - peer_b->offset) {
+ /* Only the first half of the ring buffer can be read. */
+ max_available = peer_b->size - peer_b->offset;
+ } else {
+ max_available = peer_b->len;
+ }
+
+ *out_read_buf = peer_b->buf;
+ *out_buf_offset = peer_b->offset;
+ return max_available;
+}
+
+int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf,
+ size_t* out_buf_offset,
+ size_t* out_available_bytes) {
+ struct bio_bio_st* b;
+ struct bio_bio_st* peer_b;
+ size_t max_available;
+ *out_available_bytes = 0;
+
+ BIO_clear_retry_flags(bio);
+
+ if (!bio->init) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_UNINITIALIZED);
+ return 0;
+ }
+
+ b = bio->ptr;
+
+ if (!b || !b->peer) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ peer_b = b->peer->ptr;
+ if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ if (peer_b->zero_copy_read_lock) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ peer_b->request = 0; /* Is not used by zero-copy API. */
+
+ max_available =
+ bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset);
+
+ assert(peer_b->buf != NULL);
+ if (max_available > 0) {
+ peer_b->zero_copy_read_lock = 1;
+ }
+
+ *out_available_bytes = max_available;
+ return 1;
+}
+
+int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) {
+ struct bio_bio_st* b;
+ struct bio_bio_st* peer_b;
+ size_t max_available;
+ size_t dummy_read_offset;
+ uint8_t* dummy_read_buf;
+
+ assert(BIO_get_retry_flags(bio) == 0);
+
+ if (!bio->init) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
+ BIO_R_UNINITIALIZED);
+ return 0;
+ }
+
+ b = bio->ptr;
+
+ if (!b || !b->peer) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ peer_b = b->peer->ptr;
+ if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ if (!peer_b->zero_copy_read_lock) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
+ BIO_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ max_available =
+ bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset);
+ if (bytes_read > max_available) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
+ BIO_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ peer_b->len -= bytes_read;
+ assert(peer_b->len >= 0);
+ assert(peer_b->offset + bytes_read <= peer_b->size);
+
+ /* Move read offset. If zero_copy_write_lock == 1 we must advance the
+ * offset even if buffer becomes empty, to make sure
+ * write_offset = (offset + len) mod size does not change. */
+ if (peer_b->offset + bytes_read == peer_b->size ||
+ (!peer_b->zero_copy_write_lock && peer_b->len == 0)) {
+ peer_b->offset = 0;
+ } else {
+ peer_b->offset += bytes_read;
+ }
+
+ bio->num_read += bytes_read;
+ peer_b->zero_copy_read_lock = 0;
+ return 1;
+}
+
+static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b,
+ uint8_t** out_write_buf,
+ size_t* out_buf_offset) {
+ size_t write_offset;
+ size_t max_available;
+
+ assert(b->len <= b->size);
+
+ write_offset = b->offset + b->len;
+
+ if (write_offset >= b->size) {
+ /* Only the first half of the ring buffer can be written to. */
+ write_offset -= b->size;
+ /* write up to the start of the ring buffer. */
+ max_available = b->offset - write_offset;
+ } else {
+ /* write up to the end the buffer. */
+ max_available = b->size - write_offset;
+ }
+
+ *out_write_buf = b->buf;
+ *out_buf_offset = write_offset;
+ return max_available;
+}
+
+int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf,
+ size_t* out_buf_offset,
+ size_t* out_available_bytes) {
+ struct bio_bio_st* b;
+ struct bio_bio_st* peer_b;
+ size_t max_available;
+
+ *out_available_bytes = 0;
+ BIO_clear_retry_flags(bio);
+
+ if (!bio->init) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf, BIO_R_UNINITIALIZED);
+ return 0;
+ }
+
+ b = bio->ptr;
+
+ if (!b || !b->buf || !b->peer) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+ peer_b = b->peer->ptr;
+ if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ assert(b->buf != NULL);
+
+ if (b->zero_copy_write_lock) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf, BIO_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ b->request = 0;
+ if (b->closed) {
+ /* Bio is already closed. */
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf, BIO_R_BROKEN_PIPE);
+ return 0;
+ }
+
+ max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset);
+
+ if (max_available > 0) {
+ b->zero_copy_write_lock = 1;
+ }
+
+ *out_available_bytes = max_available;
+ return 1;
+}
+
+int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) {
+ struct bio_bio_st* b;
+ struct bio_bio_st* peer_b;
+
+ size_t rest;
+ size_t dummy_write_offset;
+ uint8_t* dummy_write_buf;
+
+ if (!bio->init) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
+ BIO_R_UNINITIALIZED);
+ return 0;
+ }
+
+ b = bio->ptr;
+
+ if (!b || !b->buf || !b->peer) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+ peer_b = b->peer->ptr;
+ if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
+ BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ b->request = 0;
+ if (b->closed) {
+ /* BIO is already closed. */
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done, BIO_R_BROKEN_PIPE);
+ return 0;
+ }
+
+ if (!b->zero_copy_write_lock) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
+ BIO_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset);
+
+ if (bytes_written > rest) {
+ OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
+ BIO_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ bio->num_write += bytes_written;
+ /* Move write offset. */
+ b->len += bytes_written;
+ b->zero_copy_write_lock = 0;
+ 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 || peer_b->zero_copy_read_lock) {
+ 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);
+ /* one or two iterations */
+ do {
+ 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 zero_copy_write_lock == 1 we must advance the offset even if buffer
+ * becomes empty, to make sure write_offset = (offset + len) % size
+ * does not change. */
+ if (peer_b->len || peer_b->zero_copy_write_lock) {
+ 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;
+}
+
+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);
+
+ if (b->zero_copy_write_lock) {
+ return 0;
+ }
+
+ b->request = 0;
+ if (b->closed) {
+ /* we already closed */
+ OPENSSL_PUT_ERROR(BIO, 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);
+ /* one or two iterations */
+ do {
+ 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;
+}
+
+static int bio_make_pair(BIO* bio1, BIO* bio2,
+ size_t writebuf1_len, uint8_t* ext_writebuf1,
+ size_t writebuf2_len, uint8_t* ext_writebuf2) {
+ struct bio_bio_st *b1, *b2;
+
+ assert(bio1 != NULL);
+ assert(bio2 != NULL);
+
+ b1 = bio1->ptr;
+ b2 = bio2->ptr;
+
+ if (b1->peer != NULL || b2->peer != NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_make_pair, BIO_R_IN_USE);
+ return 0;
+ }
+
+ assert(b1->buf_externally_allocated == 0);
+ assert(b2->buf_externally_allocated == 0);
+
+ if (b1->buf == NULL) {
+ if (writebuf1_len) {
+ b1->size = writebuf1_len;
+ }
+ if (!ext_writebuf1) {
+ b1->buf_externally_allocated = 0;
+ b1->buf = OPENSSL_malloc(b1->size);
+ if (b1->buf == NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else {
+ b1->buf = ext_writebuf1;
+ b1->buf_externally_allocated = 1;
+ }
+ b1->len = 0;
+ b1->offset = 0;
+ }
+
+ if (b2->buf == NULL) {
+ if (writebuf2_len) {
+ b2->size = writebuf2_len;
+ }
+ if (!ext_writebuf2) {
+ b2->buf_externally_allocated = 0;
+ b2->buf = OPENSSL_malloc(b2->size);
+ if (b2->buf == NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else {
+ b2->buf = ext_writebuf2;
+ b2->buf_externally_allocated = 1;
+ }
+ b2->len = 0;
+ b2->offset = 0;
+ }
+
+ b1->peer = bio2;
+ b1->closed = 0;
+ b1->request = 0;
+ b1->zero_copy_read_lock = 0;
+ b1->zero_copy_write_lock = 0;
+ b2->peer = bio1;
+ b2->closed = 0;
+ b2->request = 0;
+ b2->zero_copy_read_lock = 0;
+ b2->zero_copy_write_lock = 0;
+
+ bio1->init = 1;
+ bio2->init = 1;
+
+ return 1;
+}
+
+static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ long ret;
+ struct bio_bio_st *b = bio->ptr;
+
+ assert(b != NULL);
+
+ switch (cmd) {
+ /* specific CTRL codes */
+
+ case BIO_C_GET_WRITE_BUF_SIZE:
+ ret = (long)b->size;
+ break;
+
+ case BIO_C_GET_WRITE_GUARANTEE:
+ /* How many bytes can the caller feed to the next write
+ * without having to keep any? */
+ if (b->peer == NULL || b->closed) {
+ ret = 0;
+ } else {
+ ret = (long)b->size - b->len;
+ }
+ break;
+
+ case BIO_C_GET_READ_REQUEST:
+ /* If the peer unsuccessfully tried to read, how many bytes
+ * were requested? (As with BIO_CTRL_PENDING, that number
+ * can usually be treated as boolean.) */
+ ret = (long)b->request;
+ break;
+
+ case BIO_C_RESET_READ_REQUEST:
+ /* Reset request. (Can be useful after read attempts
+ * at the other side that are meant to be non-blocking,
+ * e.g. when probing SSL_read to see if any data is
+ * available.) */
+ b->request = 0;
+ ret = 1;
+ break;
+
+ case BIO_C_SHUTDOWN_WR:
+ /* similar to shutdown(..., SHUT_WR) */
+ b->closed = 1;
+ ret = 1;
+ break;
+
+ /* standard CTRL codes follow */
+
+ case BIO_CTRL_GET_CLOSE:
+ ret = bio->shutdown;
+ break;
+
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = (int)num;
+ ret = 1;
+ break;
+
+ case BIO_CTRL_PENDING:
+ if (b->peer != NULL) {
+ struct bio_bio_st *peer_b = b->peer->ptr;
+ ret = (long)peer_b->len;
+ } else {
+ ret = 0;
+ }
+ break;
+
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ if (b->buf != NULL) {
+ ret = (long)b->len;
+ }
+ break;
+
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+
+ case BIO_CTRL_EOF: {
+ BIO *other_bio = ptr;
+
+ if (other_bio) {
+ struct bio_bio_st *other_b = other_bio->ptr;
+ assert(other_b != NULL);
+ ret = other_b->len == 0 && other_b->closed;
+ } else {
+ ret = 1;
+ }
+ } break;
+
+ default:
+ ret = 0;
+ }
+ return ret;
+}
+
+static int bio_puts(BIO *bio, const char *str) {
+ return bio_write(bio, str, strlen(str));
+}
+
+static const 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 */
+};
+
+const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
+
+int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1,
+ BIO** bio2_p, size_t writebuf2) {
+ return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p,
+ writebuf2, NULL);
+}
+
+int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len,
+ uint8_t* ext_writebuf1,
+ BIO** bio2_p, size_t writebuf2_len,
+ uint8_t* ext_writebuf2) {
+ BIO *bio1 = NULL, *bio2 = NULL;
+ int ret = 0;
+
+ /* External buffers must have sizes greater than 0. */
+ if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) {
+ goto err;
+ }
+
+ bio1 = BIO_new(bio_s_bio());
+ if (bio1 == NULL) {
+ goto err;
+ }
+ bio2 = BIO_new(bio_s_bio());
+ if (bio2 == NULL) {
+ goto err;
+ }
+
+ if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len,
+ ext_writebuf2)) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ if (ret == 0) {
+ if (bio1) {
+ BIO_free(bio1);
+ bio1 = NULL;
+ }
+ if (bio2) {
+ BIO_free(bio2);
+ bio2 = NULL;
+ }
+ }
+
+ *bio1_p = bio1;
+ *bio2_p = bio2;
+ return ret;
+}
+
+size_t BIO_ctrl_get_read_request(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
+}
+
+size_t BIO_ctrl_get_write_guarantee(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
+}
+
+int BIO_shutdown_wr(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL);
+}
diff --git a/src/crypto/bio/printf.c b/src/crypto/bio/printf.c
new file mode 100644
index 0000000..3638915
--- /dev/null
+++ b/src/crypto/bio/printf.c
@@ -0,0 +1,115 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 201410L /* for snprintf, vprintf etc */
+#endif
+
+#include <openssl/bio.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <openssl/mem.h>
+
+int BIO_printf(BIO *bio, const char *format, ...) {
+ va_list args;
+ char buf[256], *out, out_malloced = 0;
+ int out_len, ret;
+
+ va_start(args, format);
+ out_len = vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+
+#if defined(OPENSSL_WINDOWS)
+ /* On Windows, vsnprintf returns -1 rather than the requested length on
+ * truncation */
+ if (out_len < 0) {
+ va_start(args, format);
+ out_len = _vscprintf(format, args);
+ va_end(args);
+ assert(out_len >= sizeof(buf));
+ }
+#endif
+
+ if (out_len >= sizeof(buf)) {
+ const int requested_len = out_len;
+ /* The output was truncated. Note that vsnprintf's return value
+ * does not include a trailing NUL, but the buffer must be sized
+ * for it. */
+ out = OPENSSL_malloc(requested_len + 1);
+ out_malloced = 1;
+ if (out == NULL) {
+ /* Unclear what can be done in this situation. OpenSSL has historically
+ * crashed and that seems better than producing the wrong output. */
+ abort();
+ }
+ va_start(args, format);
+ out_len = vsnprintf(out, requested_len + 1, format, args);
+ va_end(args);
+ assert(out_len == requested_len);
+ } else {
+ out = buf;
+ }
+
+ ret = BIO_write(bio, out, out_len);
+ if (out_malloced) {
+ OPENSSL_free(out);
+ }
+
+ return ret;
+}
diff --git a/src/crypto/bio/socket.c b/src/crypto/bio/socket.c
new file mode 100644
index 0000000..590447f
--- /dev/null
+++ b/src/crypto/bio/socket.c
@@ -0,0 +1,191 @@
+/* crypto/bio/bss_sock.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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 acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/bio.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <unistd.h>
+#else
+#pragma warning(push, 3)
+#include <WinSock2.h>
+#pragma warning(pop)
+#endif
+
+#include "internal.h"
+
+
+#if !defined(OPENSSL_WINDOWS)
+static int closesocket(int sock) {
+ return close(sock);
+}
+#endif
+
+static int sock_new(BIO *bio) {
+ bio->init = 0;
+ bio->num = 0;
+ bio->ptr = NULL;
+ bio->flags = 0;
+ return 1;
+}
+
+static int sock_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->shutdown) {
+ if (bio->init) {
+ closesocket(bio->num);
+ }
+ bio->init = 0;
+ bio->flags = 0;
+ }
+ return 1;
+}
+
+static int sock_read(BIO *b, char *out, int outl) {
+ int ret = 0;
+
+ if (out == NULL) {
+ return 0;
+ }
+
+ bio_clear_socket_error();
+ ret = recv(b->num, out, outl, 0);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_read(b);
+ }
+ }
+ return ret;
+}
+
+static int sock_write(BIO *b, const char *in, int inl) {
+ int ret;
+
+ bio_clear_socket_error();
+ ret = send(b->num, in, inl, 0);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_write(b);
+ }
+ }
+ return ret;
+}
+
+static int sock_puts(BIO *bp, const char *str) {
+ return sock_write(bp, str, strlen(str));
+}
+
+static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ long ret = 1;
+ int *ip;
+
+ switch (cmd) {
+ case BIO_C_SET_FD:
+ sock_free(b);
+ b->num = *((int *)ptr);
+ b->shutdown = (int)num;
+ b->init = 1;
+ break;
+ case BIO_C_GET_FD:
+ if (b->init) {
+ ip = (int *)ptr;
+ if (ip != NULL)
+ *ip = b->num;
+ ret = b->num;
+ } else
+ ret = -1;
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown = (int)num;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static const BIO_METHOD methods_sockp = {
+ BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts,
+ NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL,
+};
+
+const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; }
+
+BIO *BIO_new_socket(int fd, int close_flag) {
+ BIO *ret;
+
+ ret = BIO_new(BIO_s_socket());
+ if (ret == NULL) {
+ return NULL;
+ }
+ BIO_set_fd(ret, fd, close_flag);
+ return ret;
+}
diff --git a/src/crypto/bio/socket_helper.c b/src/crypto/bio/socket_helper.c
new file mode 100644
index 0000000..52e1606
--- /dev/null
+++ b/src/crypto/bio/socket_helper.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#define _POSIX_SOURCE
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <netdb.h>
+#include <unistd.h>
+#else
+#pragma warning(push, 3)
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+#pragma warning(pop)
+#endif
+
+#include "internal.h"
+
+
+int bio_ip_and_port_to_socket_and_addr(int *out_sock,
+ struct sockaddr_storage *out_addr,
+ socklen_t *out_addr_length,
+ const char *hostname,
+ const char *port_str) {
+ struct addrinfo hint, *result, *cur;
+ int ret;
+
+ *out_sock = -1;
+
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+
+ ret = getaddrinfo(hostname, port_str, &hint, &result);
+ if (ret != 0) {
+ OPENSSL_PUT_ERROR(SYS, getaddrinfo, 0);
+ ERR_add_error_data(2, gai_strerror(ret));
+ return 0;
+ }
+
+ ret = 0;
+
+ for (cur = result; cur; cur = cur->ai_next) {
+ if (cur->ai_addrlen > sizeof(struct sockaddr_storage)) {
+ continue;
+ }
+ memset(out_addr, 0, sizeof(struct sockaddr_storage));
+ memcpy(out_addr, cur->ai_addr, cur->ai_addrlen);
+ *out_addr_length = cur->ai_addrlen;
+
+ *out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
+ if (*out_sock < 0) {
+ OPENSSL_PUT_SYSTEM_ERROR(socket);
+ goto out;
+ }
+
+ ret = 1;
+ break;
+ }
+
+out:
+ freeaddrinfo(result);
+ return ret;
+}
+
+int bio_socket_nbio(int sock, int on) {
+#if defined(OPENSSL_WINDOWS)
+ u_long arg = on;
+
+ return 0 == ioctlsocket(sock, FIONBIO, &arg);
+#else
+ int flags = fcntl(sock, F_GETFL, 0);
+ if (flags < 0) {
+ return 0;
+ }
+ if (!on) {
+ flags &= ~O_NONBLOCK;
+ } else {
+ flags |= O_NONBLOCK;
+ }
+ return fcntl(sock, F_SETFL, flags) == 0;
+#endif
+}
+
+void bio_clear_socket_error(void) {}
+
+int bio_sock_error(int sock) {
+ int error;
+ socklen_t error_size = sizeof(error);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &error_size) < 0) {
+ return 1;
+ }
+ return error;
+}