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