• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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