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 "async_bio.h" 16 17 #include <errno.h> 18 #include <string.h> 19 20 #include <openssl/bio.h> 21 #include <openssl/mem.h> 22 23 #include "../../crypto/internal.h" 24 25 26 namespace { 27 28 extern const BIO_METHOD g_async_bio_method; 29 30 struct AsyncBio { 31 bool datagram; 32 bool enforce_write_quota; 33 size_t read_quota; 34 size_t write_quota; 35 }; 36 37 AsyncBio *GetData(BIO *bio) { 38 if (bio->method != &g_async_bio_method) { 39 return NULL; 40 } 41 return (AsyncBio *)bio->ptr; 42 } 43 44 static int AsyncWrite(BIO *bio, const char *in, int inl) { 45 AsyncBio *a = GetData(bio); 46 if (a == NULL || bio->next_bio == NULL) { 47 return 0; 48 } 49 50 if (!a->enforce_write_quota) { 51 return BIO_write(bio->next_bio, in, inl); 52 } 53 54 BIO_clear_retry_flags(bio); 55 56 if (a->write_quota == 0) { 57 BIO_set_retry_write(bio); 58 errno = EAGAIN; 59 return -1; 60 } 61 62 if (!a->datagram && (size_t)inl > a->write_quota) { 63 inl = a->write_quota; 64 } 65 int ret = BIO_write(bio->next_bio, in, inl); 66 if (ret <= 0) { 67 BIO_copy_next_retry(bio); 68 } else { 69 a->write_quota -= (a->datagram ? 1 : ret); 70 } 71 return ret; 72 } 73 74 static int AsyncRead(BIO *bio, char *out, int outl) { 75 AsyncBio *a = GetData(bio); 76 if (a == NULL || bio->next_bio == NULL) { 77 return 0; 78 } 79 80 BIO_clear_retry_flags(bio); 81 82 if (a->read_quota == 0) { 83 BIO_set_retry_read(bio); 84 errno = EAGAIN; 85 return -1; 86 } 87 88 if (!a->datagram && (size_t)outl > a->read_quota) { 89 outl = a->read_quota; 90 } 91 int ret = BIO_read(bio->next_bio, out, outl); 92 if (ret <= 0) { 93 BIO_copy_next_retry(bio); 94 } else { 95 a->read_quota -= (a->datagram ? 1 : ret); 96 } 97 return ret; 98 } 99 100 static long AsyncCtrl(BIO *bio, int cmd, long num, void *ptr) { 101 if (bio->next_bio == NULL) { 102 return 0; 103 } 104 BIO_clear_retry_flags(bio); 105 int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); 106 BIO_copy_next_retry(bio); 107 return ret; 108 } 109 110 static int AsyncNew(BIO *bio) { 111 AsyncBio *a = (AsyncBio *)OPENSSL_malloc(sizeof(*a)); 112 if (a == NULL) { 113 return 0; 114 } 115 OPENSSL_memset(a, 0, sizeof(*a)); 116 a->enforce_write_quota = true; 117 bio->init = 1; 118 bio->ptr = (char *)a; 119 return 1; 120 } 121 122 static int AsyncFree(BIO *bio) { 123 if (bio == NULL) { 124 return 0; 125 } 126 127 OPENSSL_free(bio->ptr); 128 bio->ptr = NULL; 129 bio->init = 0; 130 bio->flags = 0; 131 return 1; 132 } 133 134 static long AsyncCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) { 135 if (bio->next_bio == NULL) { 136 return 0; 137 } 138 return BIO_callback_ctrl(bio->next_bio, cmd, fp); 139 } 140 141 const BIO_METHOD g_async_bio_method = { 142 BIO_TYPE_FILTER, 143 "async bio", 144 AsyncWrite, 145 AsyncRead, 146 NULL /* puts */, 147 NULL /* gets */, 148 AsyncCtrl, 149 AsyncNew, 150 AsyncFree, 151 AsyncCallbackCtrl, 152 }; 153 154 } // namespace 155 156 bssl::UniquePtr<BIO> AsyncBioCreate() { 157 return bssl::UniquePtr<BIO>(BIO_new(&g_async_bio_method)); 158 } 159 160 bssl::UniquePtr<BIO> AsyncBioCreateDatagram() { 161 bssl::UniquePtr<BIO> ret(BIO_new(&g_async_bio_method)); 162 if (!ret) { 163 return nullptr; 164 } 165 GetData(ret.get())->datagram = true; 166 return ret; 167 } 168 169 void AsyncBioAllowRead(BIO *bio, size_t count) { 170 AsyncBio *a = GetData(bio); 171 if (a == NULL) { 172 return; 173 } 174 a->read_quota += count; 175 } 176 177 void AsyncBioAllowWrite(BIO *bio, size_t count) { 178 AsyncBio *a = GetData(bio); 179 if (a == NULL) { 180 return; 181 } 182 a->write_quota += count; 183 } 184 185 void AsyncBioEnforceWriteQuota(BIO *bio, bool enforce) { 186 AsyncBio *a = GetData(bio); 187 if (a == NULL) { 188 return; 189 } 190 a->enforce_write_quota = enforce; 191 } 192