Home | History | Annotate | Download | only in test
      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