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