143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin/* Copyright (c) 2014, Google Inc. 243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * 343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * Permission to use, copy, modify, and/or distribute this software for any 443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * purpose with or without fee is hereby granted, provided that the above 543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * copyright notice and this permission notice appear in all copies. 643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * 743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 1043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 1243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 1343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 1443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 1543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin#include "async_bio.h" 1643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 1743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin#include <errno.h> 1843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin#include <openssl/mem.h> 1943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 2043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminnamespace { 2143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 2243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminextern const BIO_METHOD async_bio_method; 2343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 2443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstruct async_bio { 256fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin bool datagram; 2643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin size_t read_quota; 2743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin size_t write_quota; 2843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin}; 2943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 3043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminasync_bio *get_data(BIO *bio) { 3143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (bio->method != &async_bio_method) { 3243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return NULL; 3343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 3443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return (async_bio *)bio->ptr; 3543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 3643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 3743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstatic int async_write(BIO *bio, const char *in, int inl) { 3843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_bio *a = get_data(bio); 3943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a == NULL || bio->next_bio == NULL) { 4043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 0; 4143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 4243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 436fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin if (a->datagram) { 446fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin // Perform writes synchronously; the DTLS implementation drops any packets 456fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin // that failed to send. 466fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin return BIO_write(bio->next_bio, in, inl); 476fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin } 486fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin 4943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_clear_retry_flags(bio); 5043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 5143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a->write_quota == 0) { 5243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_set_retry_write(bio); 5343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin errno = EAGAIN; 5443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return -1; 5543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 5643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 576fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin if (!a->datagram && (size_t)inl > a->write_quota) { 5843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin inl = a->write_quota; 5943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 6043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin int ret = BIO_write(bio->next_bio, in, inl); 6143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (ret <= 0) { 6243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_copy_next_retry(bio); 6343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } else { 6443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin a->write_quota -= ret; 6543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 6643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return ret; 6743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 6843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 6943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstatic int async_read(BIO *bio, char *out, int outl) { 7043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_bio *a = get_data(bio); 7143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a == NULL || bio->next_bio == NULL) { 7243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 0; 7343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 7443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 7543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_clear_retry_flags(bio); 7643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 7743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a->read_quota == 0) { 7843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_set_retry_read(bio); 7943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin errno = EAGAIN; 8043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return -1; 8143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 8243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 836fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin if (!a->datagram && (size_t)outl > a->read_quota) { 8443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin outl = a->read_quota; 8543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 8643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin int ret = BIO_read(bio->next_bio, out, outl); 8743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (ret <= 0) { 8843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_copy_next_retry(bio); 8943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } else { 906fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin a->read_quota -= (a->datagram ? 1 : ret); 9143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 9243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return ret; 9343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 9443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 9543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstatic long async_ctrl(BIO *bio, int cmd, long num, void *ptr) { 9643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (bio->next_bio == NULL) { 9743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 0; 9843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 9943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_clear_retry_flags(bio); 10043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); 10143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_copy_next_retry(bio); 10243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return ret; 10343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 10443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 10543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstatic int async_new(BIO *bio) { 10643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_bio *a = (async_bio *)OPENSSL_malloc(sizeof(*a)); 10743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a == NULL) { 10843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 0; 10943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 11043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin memset(a, 0, sizeof(*a)); 11143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin bio->init = 1; 11243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin bio->ptr = (char *)a; 11343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 1; 11443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 11543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 11643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstatic int async_free(BIO *bio) { 11743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (bio == NULL) { 11843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 0; 11943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 12043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 12143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin OPENSSL_free(bio->ptr); 12243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin bio->ptr = NULL; 12343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin bio->init = 0; 12443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin bio->flags = 0; 12543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 1; 12643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 12743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 12843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminstatic long async_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { 12943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (bio->next_bio == NULL) { 13043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return 0; 13143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 13243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return BIO_callback_ctrl(bio->next_bio, cmd, fp); 13343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 13443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 13543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjaminconst BIO_METHOD async_bio_method = { 13643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin BIO_TYPE_FILTER, 13743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin "async bio", 13843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_write, 13943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_read, 14043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin NULL /* puts */, 14143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin NULL /* gets */, 14243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_ctrl, 14343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_new, 14443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_free, 14543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_callback_ctrl, 14643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin}; 14743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 14843ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} // namespace 14943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 15043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid BenjaminBIO *async_bio_create() { 15143ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return BIO_new(&async_bio_method); 15243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 15343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 1546fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid BenjaminBIO *async_bio_create_datagram() { 1556fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin BIO *ret = BIO_new(&async_bio_method); 1566fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin if (!ret) { 1576fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin return NULL; 1586fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin } 1596fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin get_data(ret)->datagram = true; 1606fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin return ret; 1616fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin} 1626fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin 1636fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjaminvoid async_bio_allow_read(BIO *bio, size_t count) { 16443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_bio *a = get_data(bio); 16543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a == NULL) { 16643ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return; 16743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 1686fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin a->read_quota += count; 16943ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 17043ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin 1716fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjaminvoid async_bio_allow_write(BIO *bio, size_t count) { 17243ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin async_bio *a = get_data(bio); 17343ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin if (a == NULL) { 17443ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin return; 17543ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin } 1766fd297bb62c7097a7d3e36da2e9dbb0d7e589acbDavid Benjamin a->write_quota += count; 17743ec06f705a1a3bc84ae4430b1a62a93f7f0242aDavid Benjamin} 178