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