• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 && (size_t)inl > a->write_quota) {
63     inl = 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 && (size_t)outl > a->read_quota) {
89     outl = 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   int 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_malloc(sizeof(*a));
112   if (a == NULL) {
113     return 0;
114   }
115   OPENSSL_memset(a, 0, sizeof(*a));
116   a->enforce_write_quota = true;
117   bio->init = 1;
118   bio->ptr = (char *)a;
119   return 1;
120 }
121 
AsyncFree(BIO * bio)122 static int AsyncFree(BIO *bio) {
123   if (bio == NULL) {
124     return 0;
125   }
126 
127   OPENSSL_free(bio->ptr);
128   bio->ptr = NULL;
129   bio->init = 0;
130   bio->flags = 0;
131   return 1;
132 }
133 
AsyncCallbackCtrl(BIO * bio,int cmd,bio_info_cb fp)134 static long AsyncCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) {
135   if (bio->next_bio == NULL) {
136     return 0;
137   }
138   return BIO_callback_ctrl(bio->next_bio, cmd, fp);
139 }
140 
141 const BIO_METHOD g_async_bio_method = {
142   BIO_TYPE_FILTER,
143   "async bio",
144   AsyncWrite,
145   AsyncRead,
146   NULL /* puts */,
147   NULL /* gets */,
148   AsyncCtrl,
149   AsyncNew,
150   AsyncFree,
151   AsyncCallbackCtrl,
152 };
153 
154 }  // namespace
155 
AsyncBioCreate()156 bssl::UniquePtr<BIO> AsyncBioCreate() {
157   return bssl::UniquePtr<BIO>(BIO_new(&g_async_bio_method));
158 }
159 
AsyncBioCreateDatagram()160 bssl::UniquePtr<BIO> AsyncBioCreateDatagram() {
161   bssl::UniquePtr<BIO> ret(BIO_new(&g_async_bio_method));
162   if (!ret) {
163     return nullptr;
164   }
165   GetData(ret.get())->datagram = true;
166   return ret;
167 }
168 
AsyncBioAllowRead(BIO * bio,size_t count)169 void AsyncBioAllowRead(BIO *bio, size_t count) {
170   AsyncBio *a = GetData(bio);
171   if (a == NULL) {
172     return;
173   }
174   a->read_quota += count;
175 }
176 
AsyncBioAllowWrite(BIO * bio,size_t count)177 void AsyncBioAllowWrite(BIO *bio, size_t count) {
178   AsyncBio *a = GetData(bio);
179   if (a == NULL) {
180     return;
181   }
182   a->write_quota += count;
183 }
184 
AsyncBioEnforceWriteQuota(BIO * bio,bool enforce)185 void AsyncBioEnforceWriteQuota(BIO *bio, bool enforce) {
186   AsyncBio *a = GetData(bio);
187   if (a == NULL) {
188     return;
189   }
190   a->enforce_write_quota = enforce;
191 }
192