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