blob: 605b33aaaf15def735cf97578cf1c8189124b9b2 [file] [log] [blame]
Adam Langleyd9e397b2015-01-22 14:27:53 -08001/* 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
David Benjaminf0c4a6c2016-08-11 13:26:41 -040020#include <openssl/bio.h>
Adam Langleyd9e397b2015-01-22 14:27:53 -080021#include <openssl/mem.h>
22
23
24namespace {
25
Adam Langleye9ada862015-05-11 17:20:37 -070026extern const BIO_METHOD g_async_bio_method;
Adam Langleyd9e397b2015-01-22 14:27:53 -080027
Adam Langleye9ada862015-05-11 17:20:37 -070028struct AsyncBio {
Adam Langleyd9e397b2015-01-22 14:27:53 -080029 bool datagram;
Adam Langleyfad63272015-11-12 12:15:39 -080030 bool enforce_write_quota;
Adam Langleyd9e397b2015-01-22 14:27:53 -080031 size_t read_quota;
32 size_t write_quota;
33};
34
Adam Langleye9ada862015-05-11 17:20:37 -070035AsyncBio *GetData(BIO *bio) {
36 if (bio->method != &g_async_bio_method) {
Adam Langleyd9e397b2015-01-22 14:27:53 -080037 return NULL;
38 }
Adam Langleye9ada862015-05-11 17:20:37 -070039 return (AsyncBio *)bio->ptr;
Adam Langleyd9e397b2015-01-22 14:27:53 -080040}
41
Adam Langleye9ada862015-05-11 17:20:37 -070042static int AsyncWrite(BIO *bio, const char *in, int inl) {
43 AsyncBio *a = GetData(bio);
Adam Langleyd9e397b2015-01-22 14:27:53 -080044 if (a == NULL || bio->next_bio == NULL) {
45 return 0;
46 }
47
Adam Langleyfad63272015-11-12 12:15:39 -080048 if (!a->enforce_write_quota) {
Adam Langleyd9e397b2015-01-22 14:27:53 -080049 return BIO_write(bio->next_bio, in, inl);
50 }
51
52 BIO_clear_retry_flags(bio);
53
54 if (a->write_quota == 0) {
55 BIO_set_retry_write(bio);
56 errno = EAGAIN;
57 return -1;
58 }
59
60 if (!a->datagram && (size_t)inl > a->write_quota) {
61 inl = a->write_quota;
62 }
63 int ret = BIO_write(bio->next_bio, in, inl);
64 if (ret <= 0) {
65 BIO_copy_next_retry(bio);
66 } else {
67 a->write_quota -= (a->datagram ? 1 : ret);
68 }
69 return ret;
70}
71
Adam Langleye9ada862015-05-11 17:20:37 -070072static int AsyncRead(BIO *bio, char *out, int outl) {
73 AsyncBio *a = GetData(bio);
Adam Langleyd9e397b2015-01-22 14:27:53 -080074 if (a == NULL || bio->next_bio == NULL) {
75 return 0;
76 }
77
78 BIO_clear_retry_flags(bio);
79
80 if (a->read_quota == 0) {
81 BIO_set_retry_read(bio);
82 errno = EAGAIN;
83 return -1;
84 }
85
86 if (!a->datagram && (size_t)outl > a->read_quota) {
87 outl = a->read_quota;
88 }
89 int ret = BIO_read(bio->next_bio, out, outl);
90 if (ret <= 0) {
91 BIO_copy_next_retry(bio);
92 } else {
93 a->read_quota -= (a->datagram ? 1 : ret);
94 }
95 return ret;
96}
97
Adam Langleye9ada862015-05-11 17:20:37 -070098static long AsyncCtrl(BIO *bio, int cmd, long num, void *ptr) {
Adam Langleyd9e397b2015-01-22 14:27:53 -080099 if (bio->next_bio == NULL) {
100 return 0;
101 }
102 BIO_clear_retry_flags(bio);
103 int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
104 BIO_copy_next_retry(bio);
105 return ret;
106}
107
Adam Langleye9ada862015-05-11 17:20:37 -0700108static int AsyncNew(BIO *bio) {
109 AsyncBio *a = (AsyncBio *)OPENSSL_malloc(sizeof(*a));
Adam Langleyd9e397b2015-01-22 14:27:53 -0800110 if (a == NULL) {
111 return 0;
112 }
113 memset(a, 0, sizeof(*a));
Adam Langleyfad63272015-11-12 12:15:39 -0800114 a->enforce_write_quota = true;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800115 bio->init = 1;
116 bio->ptr = (char *)a;
117 return 1;
118}
119
Adam Langleye9ada862015-05-11 17:20:37 -0700120static int AsyncFree(BIO *bio) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800121 if (bio == NULL) {
122 return 0;
123 }
124
125 OPENSSL_free(bio->ptr);
126 bio->ptr = NULL;
127 bio->init = 0;
128 bio->flags = 0;
129 return 1;
130}
131
Adam Langleye9ada862015-05-11 17:20:37 -0700132static long AsyncCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800133 if (bio->next_bio == NULL) {
134 return 0;
135 }
136 return BIO_callback_ctrl(bio->next_bio, cmd, fp);
137}
138
Adam Langleye9ada862015-05-11 17:20:37 -0700139const BIO_METHOD g_async_bio_method = {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800140 BIO_TYPE_FILTER,
141 "async bio",
Adam Langleye9ada862015-05-11 17:20:37 -0700142 AsyncWrite,
143 AsyncRead,
Adam Langleyd9e397b2015-01-22 14:27:53 -0800144 NULL /* puts */,
145 NULL /* gets */,
Adam Langleye9ada862015-05-11 17:20:37 -0700146 AsyncCtrl,
147 AsyncNew,
148 AsyncFree,
149 AsyncCallbackCtrl,
Adam Langleyd9e397b2015-01-22 14:27:53 -0800150};
151
152} // namespace
153
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400154bssl::UniquePtr<BIO> AsyncBioCreate() {
155 return bssl::UniquePtr<BIO>(BIO_new(&g_async_bio_method));
Adam Langleyd9e397b2015-01-22 14:27:53 -0800156}
157
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400158bssl::UniquePtr<BIO> AsyncBioCreateDatagram() {
159 bssl::UniquePtr<BIO> ret(BIO_new(&g_async_bio_method));
Adam Langleyd9e397b2015-01-22 14:27:53 -0800160 if (!ret) {
Adam Langleye9ada862015-05-11 17:20:37 -0700161 return nullptr;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800162 }
Adam Langleye9ada862015-05-11 17:20:37 -0700163 GetData(ret.get())->datagram = true;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800164 return ret;
165}
166
Adam Langleye9ada862015-05-11 17:20:37 -0700167void AsyncBioAllowRead(BIO *bio, size_t count) {
168 AsyncBio *a = GetData(bio);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800169 if (a == NULL) {
170 return;
171 }
172 a->read_quota += count;
173}
174
Adam Langleye9ada862015-05-11 17:20:37 -0700175void AsyncBioAllowWrite(BIO *bio, size_t count) {
176 AsyncBio *a = GetData(bio);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800177 if (a == NULL) {
178 return;
179 }
180 a->write_quota += count;
181}
Adam Langleyfad63272015-11-12 12:15:39 -0800182
183void AsyncBioEnforceWriteQuota(BIO *bio, bool enforce) {
184 AsyncBio *a = GetData(bio);
185 if (a == NULL) {
186 return;
187 }
188 a->enforce_write_quota = enforce;
189}