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