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