1 /* Copyright (c) 2014, Google Inc.
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
15 #include "packeted_bio.h"
22 #include <openssl/crypto.h>
27 const uint8_t kOpcodePacket = 'P';
28 const uint8_t kOpcodeTimeout = 'T';
30 // ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and
32 static int ReadAll(BIO *bio, uint8_t *out, size_t len) {
34 int chunk_len = INT_MAX;
38 int ret = BIO_read(bio, out, chunk_len);
48 static int PacketedWrite(BIO *bio, const char *in, int inl) {
49 if (BIO_next(bio) == NULL) {
53 BIO_clear_retry_flags(bio);
57 header[0] = kOpcodePacket;
58 header[1] = (inl >> 24) & 0xff;
59 header[2] = (inl >> 16) & 0xff;
60 header[3] = (inl >> 8) & 0xff;
61 header[4] = inl & 0xff;
62 int ret = BIO_write(BIO_next(bio), header, sizeof(header));
64 BIO_copy_next_retry(bio);
69 ret = BIO_write(BIO_next(bio), in, inl);
70 if (ret < 0 || (inl > 0 && ret == 0)) {
71 BIO_copy_next_retry(bio);
78 static int PacketedRead(BIO *bio, char *out, int outl) {
79 if (BIO_next(bio) == NULL) {
83 BIO_clear_retry_flags(bio);
87 int ret = ReadAll(BIO_next(bio), &opcode, sizeof(opcode));
89 BIO_copy_next_retry(bio);
93 if (opcode == kOpcodeTimeout) {
94 fprintf(stderr, "Timeout simulation not supported.\n");
98 if (opcode != kOpcodePacket) {
99 fprintf(stderr, "Unknown opcode, %u\n", opcode);
103 // Read the length prefix.
104 uint8_t len_bytes[4];
105 ret = ReadAll(BIO_next(bio), len_bytes, sizeof(len_bytes));
107 BIO_copy_next_retry(bio);
111 uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
112 (len_bytes[2] << 8) | len_bytes[3];
113 uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
117 ret = ReadAll(BIO_next(bio), buf, len);
119 fprintf(stderr, "Packeted BIO was truncated\n");
123 if (outl > (int)len) {
126 memcpy(out, buf, outl);
131 static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
132 if (BIO_next(bio) == NULL) {
135 BIO_clear_retry_flags(bio);
136 int ret = BIO_ctrl(BIO_next(bio), cmd, num, ptr);
137 BIO_copy_next_retry(bio);
141 static int PacketedNew(BIO *bio) {
142 BIO_set_init(bio, 1);
146 static int PacketedFree(BIO *bio) {
151 BIO_set_init(bio, 0);
155 static long PacketedCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) {
156 if (BIO_next(bio) == NULL) {
159 return BIO_callback_ctrl(BIO_next(bio), cmd, fp);
162 static BIO_METHOD *g_packeted_bio_method = NULL;
164 static const BIO_METHOD *PacketedMethod(void)
166 if (g_packeted_bio_method == NULL) {
167 g_packeted_bio_method = BIO_meth_new(BIO_TYPE_FILTER, "packeted bio");
168 if ( g_packeted_bio_method == NULL
169 || !BIO_meth_set_write(g_packeted_bio_method, PacketedWrite)
170 || !BIO_meth_set_read(g_packeted_bio_method, PacketedRead)
171 || !BIO_meth_set_ctrl(g_packeted_bio_method, PacketedCtrl)
172 || !BIO_meth_set_create(g_packeted_bio_method, PacketedNew)
173 || !BIO_meth_set_destroy(g_packeted_bio_method, PacketedFree)
174 || !BIO_meth_set_callback_ctrl(g_packeted_bio_method,
175 PacketedCallbackCtrl))
178 return g_packeted_bio_method;
182 ScopedBIO PacketedBioCreate(timeval *out_timeout) {
183 ScopedBIO bio(BIO_new(PacketedMethod()));
187 BIO_set_data(bio.get(), out_timeout);