1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Copyright (c) 2014, Google Inc. 2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Permission to use, copy, modify, and/or distribute this software for any 4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * purpose with or without fee is hereby granted, provided that the above 5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * copyright notice and this permission notice appear in all copies. 6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "async_bio.h" 16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <errno.h> 18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <string.h> 19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/mem.h> 21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 23d9e397b599b13d642138480a28c14db7a136bf0Adam Langleynamespace { 24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 25e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyextern const BIO_METHOD g_async_bio_method; 26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 27e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystruct AsyncBio { 28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley bool datagram; 29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley size_t read_quota; 30d9e397b599b13d642138480a28c14db7a136bf0Adam Langley size_t write_quota; 31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}; 32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 33e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam LangleyAsyncBio *GetData(BIO *bio) { 34e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (bio->method != &g_async_bio_method) { 35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return NULL; 36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 37e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return (AsyncBio *)bio->ptr; 38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 39d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 40e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic int AsyncWrite(BIO *bio, const char *in, int inl) { 41e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncBio *a = GetData(bio); 42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a == NULL || bio->next_bio == NULL) { 43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 46d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a->datagram) { 47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley // Perform writes synchronously; the DTLS implementation drops any packets 48d9e397b599b13d642138480a28c14db7a136bf0Adam Langley // that failed to send. 49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return BIO_write(bio->next_bio, in, inl); 50d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_clear_retry_flags(bio); 53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 54d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a->write_quota == 0) { 55d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_set_retry_write(bio); 56d9e397b599b13d642138480a28c14db7a136bf0Adam Langley errno = EAGAIN; 57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return -1; 58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 59d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 60d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!a->datagram && (size_t)inl > a->write_quota) { 61d9e397b599b13d642138480a28c14db7a136bf0Adam Langley inl = a->write_quota; 62d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int ret = BIO_write(bio->next_bio, in, inl); 64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (ret <= 0) { 65d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_copy_next_retry(bio); 66d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 67d9e397b599b13d642138480a28c14db7a136bf0Adam Langley a->write_quota -= (a->datagram ? 1 : ret); 68d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 69d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return ret; 70d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 71d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 72e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic int AsyncRead(BIO *bio, char *out, int outl) { 73e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncBio *a = GetData(bio); 74d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a == NULL || bio->next_bio == NULL) { 75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 76d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 77d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 78d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_clear_retry_flags(bio); 79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 80d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a->read_quota == 0) { 81d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_set_retry_read(bio); 82d9e397b599b13d642138480a28c14db7a136bf0Adam Langley errno = EAGAIN; 83d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return -1; 84d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 85d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 86d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!a->datagram && (size_t)outl > a->read_quota) { 87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley outl = a->read_quota; 88d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 89d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int ret = BIO_read(bio->next_bio, out, outl); 90d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (ret <= 0) { 91d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_copy_next_retry(bio); 92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 93d9e397b599b13d642138480a28c14db7a136bf0Adam Langley a->read_quota -= (a->datagram ? 1 : ret); 94d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return ret; 96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 98e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic long AsyncCtrl(BIO *bio, int cmd, long num, void *ptr) { 99d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (bio->next_bio == NULL) { 100d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 101d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 102d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_clear_retry_flags(bio); 103d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); 104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_copy_next_retry(bio); 105d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return ret; 106d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 107d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 108e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic int AsyncNew(BIO *bio) { 109e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncBio *a = (AsyncBio *)OPENSSL_malloc(sizeof(*a)); 110d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a == NULL) { 111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 112d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley memset(a, 0, sizeof(*a)); 114d9e397b599b13d642138480a28c14db7a136bf0Adam Langley bio->init = 1; 115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley bio->ptr = (char *)a; 116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 119e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic int AsyncFree(BIO *bio) { 120d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (bio == NULL) { 121d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 122d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 123d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 124d9e397b599b13d642138480a28c14db7a136bf0Adam Langley OPENSSL_free(bio->ptr); 125d9e397b599b13d642138480a28c14db7a136bf0Adam Langley bio->ptr = NULL; 126d9e397b599b13d642138480a28c14db7a136bf0Adam Langley bio->init = 0; 127d9e397b599b13d642138480a28c14db7a136bf0Adam Langley bio->flags = 0; 128d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 129d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 131e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic long AsyncCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) { 132d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (bio->next_bio == NULL) { 133d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 134d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 135d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return BIO_callback_ctrl(bio->next_bio, cmd, fp); 136d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 137d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 138e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyconst BIO_METHOD g_async_bio_method = { 139d9e397b599b13d642138480a28c14db7a136bf0Adam Langley BIO_TYPE_FILTER, 140d9e397b599b13d642138480a28c14db7a136bf0Adam Langley "async bio", 141e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncWrite, 142e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncRead, 143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley NULL /* puts */, 144d9e397b599b13d642138480a28c14db7a136bf0Adam Langley NULL /* gets */, 145e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncCtrl, 146e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncNew, 147e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncFree, 148e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncCallbackCtrl, 149d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}; 150d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 151d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} // namespace 152d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 153e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam LangleyScopedBIO AsyncBioCreate() { 154e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return ScopedBIO(BIO_new(&g_async_bio_method)); 155d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 156d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 157e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam LangleyScopedBIO AsyncBioCreateDatagram() { 158e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley ScopedBIO ret(BIO_new(&g_async_bio_method)); 159d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!ret) { 160e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return nullptr; 161d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 162e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley GetData(ret.get())->datagram = true; 163d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return ret; 164d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 165d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 166e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid AsyncBioAllowRead(BIO *bio, size_t count) { 167e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncBio *a = GetData(bio); 168d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a == NULL) { 169d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return; 170d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 171d9e397b599b13d642138480a28c14db7a136bf0Adam Langley a->read_quota += count; 172d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 173d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 174e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid AsyncBioAllowWrite(BIO *bio, size_t count) { 175e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley AsyncBio *a = GetData(bio); 176d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (a == NULL) { 177d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return; 178d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 179d9e397b599b13d642138480a28c14db7a136bf0Adam Langley a->write_quota += count; 180d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 181