1 /* Copyright (c) 2014, Google Inc. 2 * 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. 6 * 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. */ 14 15 #include "packeted_bio.h" 16 17 #include <assert.h> 18 #include <errno.h> 19 #include <openssl/mem.h> 20 21 namespace { 22 23 extern const BIO_METHOD packeted_bio_method; 24 25 static int packeted_write(BIO *bio, const char *in, int inl) { 26 if (bio->next_bio == NULL) { 27 return 0; 28 } 29 30 BIO_clear_retry_flags(bio); 31 32 // Write the length prefix. 33 uint8_t len_bytes[4]; 34 len_bytes[0] = (inl >> 24) & 0xff; 35 len_bytes[1] = (inl >> 16) & 0xff; 36 len_bytes[2] = (inl >> 8) & 0xff; 37 len_bytes[3] = inl & 0xff; 38 int ret = BIO_write(bio->next_bio, len_bytes, sizeof(len_bytes)); 39 if (ret <= 0) { 40 BIO_copy_next_retry(bio); 41 return ret; 42 } 43 44 // Write the buffer. BIOs for which this operation fails are not supported. 45 ret = BIO_write(bio->next_bio, in, inl); 46 assert(ret == inl); 47 return ret; 48 } 49 50 static int packeted_read(BIO *bio, char *out, int outl) { 51 if (bio->next_bio == NULL) { 52 return 0; 53 } 54 55 BIO_clear_retry_flags(bio); 56 57 // Read the length prefix. 58 uint8_t len_bytes[4]; 59 int ret = BIO_read(bio->next_bio, &len_bytes, sizeof(len_bytes)); 60 if (ret <= 0) { 61 BIO_copy_next_retry(bio); 62 return ret; 63 } 64 // BIOs for which a partial length comes back are not supported. 65 assert(ret == 4); 66 67 uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) | 68 (len_bytes[2] << 8) | len_bytes[3]; 69 char *buf = (char *)OPENSSL_malloc(len); 70 assert(buf != NULL); 71 ret = BIO_read(bio->next_bio, buf, len); 72 assert(ret == (int)len); 73 74 if (outl > (int)len) { 75 outl = len; 76 } 77 memcpy(out, buf, outl); 78 OPENSSL_free(buf); 79 return outl; 80 } 81 82 static long packeted_ctrl(BIO *bio, int cmd, long num, void *ptr) { 83 if (bio->next_bio == NULL) { 84 return 0; 85 } 86 BIO_clear_retry_flags(bio); 87 int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); 88 BIO_copy_next_retry(bio); 89 return ret; 90 } 91 92 static int packeted_new(BIO *bio) { 93 bio->init = 1; 94 return 1; 95 } 96 97 static int packeted_free(BIO *bio) { 98 if (bio == NULL) { 99 return 0; 100 } 101 102 bio->init = 0; 103 return 1; 104 } 105 106 static long packeted_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { 107 if (bio->next_bio == NULL) { 108 return 0; 109 } 110 return BIO_callback_ctrl(bio->next_bio, cmd, fp); 111 } 112 113 const BIO_METHOD packeted_bio_method = { 114 BIO_TYPE_FILTER, 115 "packeted bio", 116 packeted_write, 117 packeted_read, 118 NULL /* puts */, 119 NULL /* gets */, 120 packeted_ctrl, 121 packeted_new, 122 packeted_free, 123 packeted_callback_ctrl, 124 }; 125 126 } // namespace 127 128 BIO *packeted_bio_create() { 129 return BIO_new(&packeted_bio_method); 130 } 131