Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / ssl / test / async_bio.cc
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 <openssl/mem.h>
19
20 namespace {
21
22 extern const BIO_METHOD async_bio_method;
23
24 struct async_bio {
25   bool datagram;
26   size_t read_quota;
27   size_t write_quota;
28 };
29
30 async_bio *get_data(BIO *bio) {
31   if (bio->method != &async_bio_method) {
32     return NULL;
33   }
34   return (async_bio *)bio->ptr;
35 }
36
37 static int async_write(BIO *bio, const char *in, int inl) {
38   async_bio *a = get_data(bio);
39   if (a == NULL || bio->next_bio == NULL) {
40     return 0;
41   }
42
43   if (a->datagram) {
44     // Perform writes synchronously; the DTLS implementation drops any packets
45     // that failed to send.
46     return BIO_write(bio->next_bio, in, inl);
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 && (size_t)inl > a->write_quota) {
58     inl = 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 -= ret;
65   }
66   return ret;
67 }
68
69 static int async_read(BIO *bio, char *out, int outl) {
70   async_bio *a = get_data(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 && (size_t)outl > a->read_quota) {
84     outl = 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
95 static long async_ctrl(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   int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
101   BIO_copy_next_retry(bio);
102   return ret;
103 }
104
105 static int async_new(BIO *bio) {
106   async_bio *a = (async_bio *)OPENSSL_malloc(sizeof(*a));
107   if (a == NULL) {
108     return 0;
109   }
110   memset(a, 0, sizeof(*a));
111   bio->init = 1;
112   bio->ptr = (char *)a;
113   return 1;
114 }
115
116 static int async_free(BIO *bio) {
117   if (bio == NULL) {
118     return 0;
119   }
120
121   OPENSSL_free(bio->ptr);
122   bio->ptr = NULL;
123   bio->init = 0;
124   bio->flags = 0;
125   return 1;
126 }
127
128 static long async_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
129   if (bio->next_bio == NULL) {
130     return 0;
131   }
132   return BIO_callback_ctrl(bio->next_bio, cmd, fp);
133 }
134
135 const BIO_METHOD async_bio_method = {
136   BIO_TYPE_FILTER,
137   "async bio",
138   async_write,
139   async_read,
140   NULL /* puts */,
141   NULL /* gets */,
142   async_ctrl,
143   async_new,
144   async_free,
145   async_callback_ctrl,
146 };
147
148 }  // namespace
149
150 BIO *async_bio_create() {
151   return BIO_new(&async_bio_method);
152 }
153
154 BIO *async_bio_create_datagram() {
155   BIO *ret = BIO_new(&async_bio_method);
156   if (!ret) {
157     return NULL;
158   }
159   get_data(ret)->datagram = true;
160   return ret;
161 }
162
163 void async_bio_allow_read(BIO *bio, size_t count) {
164   async_bio *a = get_data(bio);
165   if (a == NULL) {
166     return;
167   }
168   a->read_quota += count;
169 }
170
171 void async_bio_allow_write(BIO *bio, size_t count) {
172   async_bio *a = get_data(bio);
173   if (a == NULL) {
174     return;
175   }
176   a->write_quota += count;
177 }