1709c21c4SNick Mathewson /*
2e49e2891SNick Mathewson * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
3709c21c4SNick Mathewson *
4709c21c4SNick Mathewson * Redistribution and use in source and binary forms, with or without
5709c21c4SNick Mathewson * modification, are permitted provided that the following conditions
6709c21c4SNick Mathewson * are met:
7709c21c4SNick Mathewson * 1. Redistributions of source code must retain the above copyright
8709c21c4SNick Mathewson * notice, this list of conditions and the following disclaimer.
9709c21c4SNick Mathewson * 2. Redistributions in binary form must reproduce the above copyright
10709c21c4SNick Mathewson * notice, this list of conditions and the following disclaimer in the
11709c21c4SNick Mathewson * documentation and/or other materials provided with the distribution.
12709c21c4SNick Mathewson * 3. The name of the author may not be used to endorse or promote products
13709c21c4SNick Mathewson * derived from this software without specific prior written permission.
14709c21c4SNick Mathewson *
15709c21c4SNick Mathewson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16709c21c4SNick Mathewson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17709c21c4SNick Mathewson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18709c21c4SNick Mathewson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19709c21c4SNick Mathewson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20709c21c4SNick Mathewson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21709c21c4SNick Mathewson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22709c21c4SNick Mathewson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23709c21c4SNick Mathewson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24709c21c4SNick Mathewson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25709c21c4SNick Mathewson */
26709c21c4SNick Mathewson
2769c3516bSJoakim Söderberg // Get rid of OSX 10.7 and greater deprecation warnings.
28e212c548SJoakim Soderberg #if defined(__APPLE__) && defined(__clang__)
2969c3516bSJoakim Söderberg #pragma clang diagnostic ignored "-Wdeprecated-declarations"
300ef1d04eSJoakim Soderberg #endif
3169c3516bSJoakim Söderberg
32ec347b92SNick Mathewson #include "event2/event-config.h"
330915ca0aSKevin Bowling #include "evconfig-private.h"
340915ca0aSKevin Bowling
350915ca0aSKevin Bowling #include <sys/types.h>
36709c21c4SNick Mathewson
3768120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
38709c21c4SNick Mathewson #include <sys/time.h>
39709c21c4SNick Mathewson #endif
40709c21c4SNick Mathewson
41709c21c4SNick Mathewson #include <errno.h>
42709c21c4SNick Mathewson #include <stdio.h>
43709c21c4SNick Mathewson #include <stdlib.h>
44709c21c4SNick Mathewson #include <string.h>
4568120d9bSNick Mathewson #ifdef EVENT__HAVE_STDARG_H
46709c21c4SNick Mathewson #include <stdarg.h>
47709c21c4SNick Mathewson #endif
4868120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
49709c21c4SNick Mathewson #include <unistd.h>
50709c21c4SNick Mathewson #endif
51709c21c4SNick Mathewson
529f560bfaSNick Mathewson #ifdef _WIN32
53709c21c4SNick Mathewson #include <winsock2.h>
54709c21c4SNick Mathewson #endif
55709c21c4SNick Mathewson
56709c21c4SNick Mathewson #include "event2/bufferevent.h"
57709c21c4SNick Mathewson #include "event2/bufferevent_struct.h"
58709c21c4SNick Mathewson #include "event2/bufferevent_ssl.h"
59709c21c4SNick Mathewson #include "event2/buffer.h"
60709c21c4SNick Mathewson #include "event2/event.h"
61709c21c4SNick Mathewson
62709c21c4SNick Mathewson #include "mm-internal.h"
63709c21c4SNick Mathewson #include "bufferevent-internal.h"
64709c21c4SNick Mathewson #include "log-internal.h"
65709c21c4SNick Mathewson
66709c21c4SNick Mathewson #include <openssl/ssl.h>
67709c21c4SNick Mathewson #include <openssl/err.h>
683e9e0a0dSKurt Roeckx #include "openssl-compat.h"
69709c21c4SNick Mathewson
70709c21c4SNick Mathewson /*
71709c21c4SNick Mathewson * Define an OpenSSL bio that targets a bufferevent.
72709c21c4SNick Mathewson */
73709c21c4SNick Mathewson
74709c21c4SNick Mathewson /* --------------------
75709c21c4SNick Mathewson A BIO is an OpenSSL abstraction that handles reading and writing data. The
76709c21c4SNick Mathewson library will happily speak SSL over anything that implements a BIO
77709c21c4SNick Mathewson interface.
78709c21c4SNick Mathewson
79709c21c4SNick Mathewson Here we define a BIO implementation that directs its output to a
80709c21c4SNick Mathewson bufferevent. We'll want to use this only when none of OpenSSL's built-in
81e3fd294aSNick Mathewson IO mechanisms work for us.
82709c21c4SNick Mathewson -------------------- */
83709c21c4SNick Mathewson
84709c21c4SNick Mathewson /* every BIO type needs its own integer type value. */
85709c21c4SNick Mathewson #define BIO_TYPE_LIBEVENT 57
86709c21c4SNick Mathewson /* ???? Arguably, we should set BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK on
87709c21c4SNick Mathewson * this. */
88709c21c4SNick Mathewson
89709c21c4SNick Mathewson #if 0
90709c21c4SNick Mathewson static void
91709c21c4SNick Mathewson print_err(int val)
92709c21c4SNick Mathewson {
93709c21c4SNick Mathewson int err;
94709c21c4SNick Mathewson printf("Error was %d\n", val);
95709c21c4SNick Mathewson
96ac356502SPatrick Pelletier while ((err = ERR_get_error())) {
97709c21c4SNick Mathewson const char *msg = (const char*)ERR_reason_error_string(err);
98709c21c4SNick Mathewson const char *lib = (const char*)ERR_lib_error_string(err);
99709c21c4SNick Mathewson const char *func = (const char*)ERR_func_error_string(err);
100709c21c4SNick Mathewson
101709c21c4SNick Mathewson printf("%s in %s %s\n", msg, lib, func);
102709c21c4SNick Mathewson }
103709c21c4SNick Mathewson }
104709c21c4SNick Mathewson #else
105709c21c4SNick Mathewson #define print_err(v) ((void)0)
106709c21c4SNick Mathewson #endif
107709c21c4SNick Mathewson
108709c21c4SNick Mathewson /* Called to initialize a new BIO */
109709c21c4SNick Mathewson static int
bio_bufferevent_new(BIO * b)110709c21c4SNick Mathewson bio_bufferevent_new(BIO *b)
111709c21c4SNick Mathewson {
1123e9e0a0dSKurt Roeckx BIO_set_init(b, 0);
1133e9e0a0dSKurt Roeckx BIO_set_data(b, NULL); /* We'll be putting the bufferevent in this field.*/
114709c21c4SNick Mathewson return 1;
115709c21c4SNick Mathewson }
116709c21c4SNick Mathewson
117709c21c4SNick Mathewson /* Called to uninitialize the BIO. */
118709c21c4SNick Mathewson static int
bio_bufferevent_free(BIO * b)119709c21c4SNick Mathewson bio_bufferevent_free(BIO *b)
120709c21c4SNick Mathewson {
121709c21c4SNick Mathewson if (!b)
122709c21c4SNick Mathewson return 0;
1233e9e0a0dSKurt Roeckx if (BIO_get_shutdown(b)) {
1243e9e0a0dSKurt Roeckx if (BIO_get_init(b) && BIO_get_data(b))
1253e9e0a0dSKurt Roeckx bufferevent_free(BIO_get_data(b));
1263e9e0a0dSKurt Roeckx BIO_free(b);
127709c21c4SNick Mathewson }
128709c21c4SNick Mathewson return 1;
129709c21c4SNick Mathewson }
130709c21c4SNick Mathewson
131709c21c4SNick Mathewson /* Called to extract data from the BIO. */
132709c21c4SNick Mathewson static int
bio_bufferevent_read(BIO * b,char * out,int outlen)133709c21c4SNick Mathewson bio_bufferevent_read(BIO *b, char *out, int outlen)
134709c21c4SNick Mathewson {
135709c21c4SNick Mathewson int r = 0;
136709c21c4SNick Mathewson struct evbuffer *input;
137709c21c4SNick Mathewson
138709c21c4SNick Mathewson BIO_clear_retry_flags(b);
139709c21c4SNick Mathewson
140709c21c4SNick Mathewson if (!out)
141709c21c4SNick Mathewson return 0;
1423e9e0a0dSKurt Roeckx if (!BIO_get_data(b))
143709c21c4SNick Mathewson return -1;
144709c21c4SNick Mathewson
1453e9e0a0dSKurt Roeckx input = bufferevent_get_input(BIO_get_data(b));
146709c21c4SNick Mathewson if (evbuffer_get_length(input) == 0) {
147709c21c4SNick Mathewson /* If there's no data to read, say so. */
148709c21c4SNick Mathewson BIO_set_retry_read(b);
149709c21c4SNick Mathewson return -1;
150709c21c4SNick Mathewson } else {
151709c21c4SNick Mathewson r = evbuffer_remove(input, out, outlen);
152709c21c4SNick Mathewson }
153709c21c4SNick Mathewson
154709c21c4SNick Mathewson return r;
155709c21c4SNick Mathewson }
156709c21c4SNick Mathewson
15700761b43San-tao /* Called to write data into the BIO */
158709c21c4SNick Mathewson static int
bio_bufferevent_write(BIO * b,const char * in,int inlen)159709c21c4SNick Mathewson bio_bufferevent_write(BIO *b, const char *in, int inlen)
160709c21c4SNick Mathewson {
1613e9e0a0dSKurt Roeckx struct bufferevent *bufev = BIO_get_data(b);
162709c21c4SNick Mathewson struct evbuffer *output;
163709c21c4SNick Mathewson size_t outlen;
164709c21c4SNick Mathewson
165709c21c4SNick Mathewson BIO_clear_retry_flags(b);
166709c21c4SNick Mathewson
1673e9e0a0dSKurt Roeckx if (!BIO_get_data(b))
168709c21c4SNick Mathewson return -1;
169709c21c4SNick Mathewson
170709c21c4SNick Mathewson output = bufferevent_get_output(bufev);
171709c21c4SNick Mathewson outlen = evbuffer_get_length(output);
172709c21c4SNick Mathewson
173709c21c4SNick Mathewson /* Copy only as much data onto the output buffer as can fit under the
174709c21c4SNick Mathewson * high-water mark. */
175e050703dSJoachim Bauch if (bufev->wm_write.high && bufev->wm_write.high <= (outlen+inlen)) {
176e050703dSJoachim Bauch if (bufev->wm_write.high <= outlen) {
177709c21c4SNick Mathewson /* If no data can fit, we'll need to retry later. */
178709c21c4SNick Mathewson BIO_set_retry_write(b);
179709c21c4SNick Mathewson return -1;
180709c21c4SNick Mathewson }
181709c21c4SNick Mathewson inlen = bufev->wm_write.high - outlen;
182709c21c4SNick Mathewson }
183709c21c4SNick Mathewson
1842e36dbe1SNick Mathewson EVUTIL_ASSERT(inlen > 0);
185709c21c4SNick Mathewson evbuffer_add(output, in, inlen);
186709c21c4SNick Mathewson return inlen;
187709c21c4SNick Mathewson }
188709c21c4SNick Mathewson
189709c21c4SNick Mathewson /* Called to handle various requests */
190709c21c4SNick Mathewson static long
bio_bufferevent_ctrl(BIO * b,int cmd,long num,void * ptr)191709c21c4SNick Mathewson bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
192709c21c4SNick Mathewson {
1933e9e0a0dSKurt Roeckx struct bufferevent *bufev = BIO_get_data(b);
194709c21c4SNick Mathewson long ret = 1;
195709c21c4SNick Mathewson
196709c21c4SNick Mathewson switch (cmd) {
197709c21c4SNick Mathewson case BIO_CTRL_GET_CLOSE:
1983e9e0a0dSKurt Roeckx ret = BIO_get_shutdown(b);
199709c21c4SNick Mathewson break;
200709c21c4SNick Mathewson case BIO_CTRL_SET_CLOSE:
2013e9e0a0dSKurt Roeckx BIO_set_shutdown(b, (int)num);
202709c21c4SNick Mathewson break;
203709c21c4SNick Mathewson case BIO_CTRL_PENDING:
204709c21c4SNick Mathewson ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
205709c21c4SNick Mathewson break;
206709c21c4SNick Mathewson case BIO_CTRL_WPENDING:
207709c21c4SNick Mathewson ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0;
208709c21c4SNick Mathewson break;
209709c21c4SNick Mathewson /* XXXX These two are given a special-case treatment because
210709c21c4SNick Mathewson * of cargo-cultism. I should come up with a better reason. */
211709c21c4SNick Mathewson case BIO_CTRL_DUP:
212709c21c4SNick Mathewson case BIO_CTRL_FLUSH:
213709c21c4SNick Mathewson ret = 1;
214709c21c4SNick Mathewson break;
215709c21c4SNick Mathewson default:
216709c21c4SNick Mathewson ret = 0;
217709c21c4SNick Mathewson break;
218709c21c4SNick Mathewson }
219709c21c4SNick Mathewson return ret;
220709c21c4SNick Mathewson }
221709c21c4SNick Mathewson
222709c21c4SNick Mathewson /* Called to write a string to the BIO */
223709c21c4SNick Mathewson static int
bio_bufferevent_puts(BIO * b,const char * s)224709c21c4SNick Mathewson bio_bufferevent_puts(BIO *b, const char *s)
225709c21c4SNick Mathewson {
226709c21c4SNick Mathewson return bio_bufferevent_write(b, s, strlen(s));
227709c21c4SNick Mathewson }
228709c21c4SNick Mathewson
229709c21c4SNick Mathewson /* Method table for the bufferevent BIO */
2303e9e0a0dSKurt Roeckx static BIO_METHOD *methods_bufferevent;
231709c21c4SNick Mathewson
232709c21c4SNick Mathewson /* Return the method table for the bufferevents BIO */
233709c21c4SNick Mathewson static BIO_METHOD *
BIO_s_bufferevent(void)234709c21c4SNick Mathewson BIO_s_bufferevent(void)
235709c21c4SNick Mathewson {
2363e9e0a0dSKurt Roeckx if (methods_bufferevent == NULL) {
2373e9e0a0dSKurt Roeckx methods_bufferevent = BIO_meth_new(BIO_TYPE_LIBEVENT, "bufferevent");
2383e9e0a0dSKurt Roeckx if (methods_bufferevent == NULL)
2393e9e0a0dSKurt Roeckx return NULL;
2403e9e0a0dSKurt Roeckx BIO_meth_set_write(methods_bufferevent, bio_bufferevent_write);
2413e9e0a0dSKurt Roeckx BIO_meth_set_read(methods_bufferevent, bio_bufferevent_read);
2423e9e0a0dSKurt Roeckx BIO_meth_set_puts(methods_bufferevent, bio_bufferevent_puts);
2433e9e0a0dSKurt Roeckx BIO_meth_set_ctrl(methods_bufferevent, bio_bufferevent_ctrl);
2443e9e0a0dSKurt Roeckx BIO_meth_set_create(methods_bufferevent, bio_bufferevent_new);
2453e9e0a0dSKurt Roeckx BIO_meth_set_destroy(methods_bufferevent, bio_bufferevent_free);
2463e9e0a0dSKurt Roeckx }
2473e9e0a0dSKurt Roeckx return methods_bufferevent;
248709c21c4SNick Mathewson }
249709c21c4SNick Mathewson
250709c21c4SNick Mathewson /* Create a new BIO to wrap communication around a bufferevent. If close_flag
251709c21c4SNick Mathewson * is true, the bufferevent will be freed when the BIO is closed. */
252709c21c4SNick Mathewson static BIO *
BIO_new_bufferevent(struct bufferevent * bufferevent)25383275459SAzat Khuzhin BIO_new_bufferevent(struct bufferevent *bufferevent)
254709c21c4SNick Mathewson {
255709c21c4SNick Mathewson BIO *result;
256709c21c4SNick Mathewson if (!bufferevent)
257709c21c4SNick Mathewson return NULL;
258709c21c4SNick Mathewson if (!(result = BIO_new(BIO_s_bufferevent())))
259709c21c4SNick Mathewson return NULL;
2603e9e0a0dSKurt Roeckx BIO_set_init(result, 1);
2613e9e0a0dSKurt Roeckx BIO_set_data(result, bufferevent);
26283275459SAzat Khuzhin /* We don't tell the BIO to close the bufferevent; we do it ourselves on
26383275459SAzat Khuzhin * be_openssl_destruct() */
26483275459SAzat Khuzhin BIO_set_shutdown(result, 0);
265709c21c4SNick Mathewson return result;
266709c21c4SNick Mathewson }
267709c21c4SNick Mathewson
268709c21c4SNick Mathewson /* --------------------
269e3fd294aSNick Mathewson Now, here's the OpenSSL-based implementation of bufferevent.
270709c21c4SNick Mathewson
271709c21c4SNick Mathewson The implementation comes in two flavors: one that connects its SSL object
272709c21c4SNick Mathewson to an underlying bufferevent using a BIO_bufferevent, and one that has the
273709c21c4SNick Mathewson SSL object connect to a socket directly. The latter should generally be
274709c21c4SNick Mathewson faster, except on Windows, where your best bet is using a
275709c21c4SNick Mathewson bufferevent_async.
276709c21c4SNick Mathewson
277709c21c4SNick Mathewson (OpenSSL supports many other BIO types, too. But we can't use any unless
278709c21c4SNick Mathewson we have a good way to get notified when they become readable/writable.)
279709c21c4SNick Mathewson -------------------- */
280709c21c4SNick Mathewson
281009f3005SNick Mathewson struct bio_data_counts {
282009f3005SNick Mathewson unsigned long n_written;
283009f3005SNick Mathewson unsigned long n_read;
284009f3005SNick Mathewson };
285009f3005SNick Mathewson
286709c21c4SNick Mathewson struct bufferevent_openssl {
287e3fd294aSNick Mathewson /* Shared fields with common bufferevent implementation code.
288709c21c4SNick Mathewson If we were set up with an underlying bufferevent, we use the
289709c21c4SNick Mathewson events here as timers only. If we have an SSL, then we use
290709c21c4SNick Mathewson the events as socket events.
291709c21c4SNick Mathewson */
292709c21c4SNick Mathewson struct bufferevent_private bev;
293709c21c4SNick Mathewson /* An underlying bufferevent that we're directing our output to.
294709c21c4SNick Mathewson If it's NULL, then we're connected to an fd, not an evbuffer. */
295709c21c4SNick Mathewson struct bufferevent *underlying;
296709c21c4SNick Mathewson /* The SSL object doing our encryption. */
297709c21c4SNick Mathewson SSL *ssl;
298709c21c4SNick Mathewson
299709c21c4SNick Mathewson /* A callback that's invoked when data arrives on our outbuf so we
300709c21c4SNick Mathewson know to write data to the SSL. */
301709c21c4SNick Mathewson struct evbuffer_cb_entry *outbuf_cb;
302709c21c4SNick Mathewson
303009f3005SNick Mathewson /* A count of how much data the bios have read/written total. Used
304009f3005SNick Mathewson for rate-limiting. */
305009f3005SNick Mathewson struct bio_data_counts counts;
306009f3005SNick Mathewson
307595f7e38SNick Mathewson /* If this value is greater than 0, then the last SSL_write blocked,
308595f7e38SNick Mathewson * and we need to try it again with this many bytes. */
309595f7e38SNick Mathewson ev_ssize_t last_write;
310595f7e38SNick Mathewson
311516452b7SNick Mathewson #define NUM_ERRORS 3
312516452b7SNick Mathewson ev_uint32_t errors[NUM_ERRORS];
313516452b7SNick Mathewson
314709c21c4SNick Mathewson /* When we next get available space, we should say "read" instead of
315709c21c4SNick Mathewson "write". This can happen if there's a renegotiation during a read
316709c21c4SNick Mathewson operation. */
317709c21c4SNick Mathewson unsigned read_blocked_on_write : 1;
318709c21c4SNick Mathewson /* When we next get data, we should say "write" instead of "read". */
319709c21c4SNick Mathewson unsigned write_blocked_on_read : 1;
320099d27dfSCatalin Patulea /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
321709c21c4SNick Mathewson unsigned allow_dirty_shutdown : 1;
322516452b7SNick Mathewson /* XXX */
323516452b7SNick Mathewson unsigned n_errors : 2;
324709c21c4SNick Mathewson
325709c21c4SNick Mathewson /* Are we currently connecting, accepting, or doing IO? */
326709c21c4SNick Mathewson unsigned state : 2;
3275ab9518fSAzat Khuzhin /* If we reset fd, we sould reset state too */
3285ab9518fSAzat Khuzhin unsigned old_state : 2;
329709c21c4SNick Mathewson };
330709c21c4SNick Mathewson
331709c21c4SNick Mathewson static int be_openssl_enable(struct bufferevent *, short);
332709c21c4SNick Mathewson static int be_openssl_disable(struct bufferevent *, short);
33302fbf687SNick Mathewson static void be_openssl_unlink(struct bufferevent *);
334709c21c4SNick Mathewson static void be_openssl_destruct(struct bufferevent *);
335ff3f6cd4SNick Mathewson static int be_openssl_adj_timeouts(struct bufferevent *);
336709c21c4SNick Mathewson static int be_openssl_flush(struct bufferevent *bufev,
337709c21c4SNick Mathewson short iotype, enum bufferevent_flush_mode mode);
338709c21c4SNick Mathewson static int be_openssl_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
339709c21c4SNick Mathewson
340709c21c4SNick Mathewson const struct bufferevent_ops bufferevent_ops_openssl = {
341709c21c4SNick Mathewson "ssl",
342657d1b6dSNick Mathewson evutil_offsetof(struct bufferevent_openssl, bev.bev),
343709c21c4SNick Mathewson be_openssl_enable,
344709c21c4SNick Mathewson be_openssl_disable,
34502fbf687SNick Mathewson be_openssl_unlink,
346709c21c4SNick Mathewson be_openssl_destruct,
347709c21c4SNick Mathewson be_openssl_adj_timeouts,
348709c21c4SNick Mathewson be_openssl_flush,
349709c21c4SNick Mathewson be_openssl_ctrl,
350709c21c4SNick Mathewson };
351709c21c4SNick Mathewson
352709c21c4SNick Mathewson /* Given a bufferevent, return a pointer to the bufferevent_openssl that
353e3fd294aSNick Mathewson * contains it, if any. */
354709c21c4SNick Mathewson static inline struct bufferevent_openssl *
upcast(struct bufferevent * bev)355709c21c4SNick Mathewson upcast(struct bufferevent *bev)
356709c21c4SNick Mathewson {
357709c21c4SNick Mathewson struct bufferevent_openssl *bev_o;
35856faf02bSDominic Chen if (!BEV_IS_OPENSSL(bev))
359709c21c4SNick Mathewson return NULL;
360709c21c4SNick Mathewson bev_o = (void*)( ((char*)bev) -
361709c21c4SNick Mathewson evutil_offsetof(struct bufferevent_openssl, bev.bev));
36256faf02bSDominic Chen EVUTIL_ASSERT(BEV_IS_OPENSSL(&bev_o->bev.bev));
363709c21c4SNick Mathewson return bev_o;
364709c21c4SNick Mathewson }
365709c21c4SNick Mathewson
366516452b7SNick Mathewson static inline void
put_error(struct bufferevent_openssl * bev_ssl,unsigned long err)367516452b7SNick Mathewson put_error(struct bufferevent_openssl *bev_ssl, unsigned long err)
368516452b7SNick Mathewson {
369516452b7SNick Mathewson if (bev_ssl->n_errors == NUM_ERRORS)
370516452b7SNick Mathewson return;
371516452b7SNick Mathewson /* The error type according to openssl is "unsigned long", but
372516452b7SNick Mathewson openssl never uses more than 32 bits of it. It _can't_ use more
373516452b7SNick Mathewson than 32 bits of it, since it needs to report errors on systems
374516452b7SNick Mathewson where long is only 32 bits.
375516452b7SNick Mathewson */
37634f28e08SNick Mathewson bev_ssl->errors[bev_ssl->n_errors++] = (ev_uint32_t) err;
377516452b7SNick Mathewson }
378516452b7SNick Mathewson
379709c21c4SNick Mathewson /* Have the base communications channel (either the underlying bufferevent or
380709c21c4SNick Mathewson * ev_read and ev_write) start reading. Take the read-blocked-on-write flag
381709c21c4SNick Mathewson * into account. */
382ff3f6cd4SNick Mathewson static int
start_reading(struct bufferevent_openssl * bev_ssl)383709c21c4SNick Mathewson start_reading(struct bufferevent_openssl *bev_ssl)
384709c21c4SNick Mathewson {
385709c21c4SNick Mathewson if (bev_ssl->underlying) {
3868ac3c4c2SNick Mathewson bufferevent_unsuspend_read_(bev_ssl->underlying,
387ac27eb82SNick Mathewson BEV_SUSPEND_FILT_READ);
388ac27eb82SNick Mathewson return 0;
389709c21c4SNick Mathewson } else {
390709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
391ff3f6cd4SNick Mathewson int r;
392cb9da0bfSNick Mathewson r = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
393ff3f6cd4SNick Mathewson if (r == 0 && bev_ssl->read_blocked_on_write)
394cb9da0bfSNick Mathewson r = bufferevent_add_event_(&bev->ev_write,
395709c21c4SNick Mathewson &bev->timeout_write);
396ff3f6cd4SNick Mathewson return r;
397709c21c4SNick Mathewson }
398709c21c4SNick Mathewson }
399709c21c4SNick Mathewson
400709c21c4SNick Mathewson /* Have the base communications channel (either the underlying bufferevent or
401709c21c4SNick Mathewson * ev_read and ev_write) start writing. Take the write-blocked-on-read flag
402709c21c4SNick Mathewson * into account. */
403ff3f6cd4SNick Mathewson static int
start_writing(struct bufferevent_openssl * bev_ssl)404709c21c4SNick Mathewson start_writing(struct bufferevent_openssl *bev_ssl)
405709c21c4SNick Mathewson {
406ac27eb82SNick Mathewson int r = 0;
407709c21c4SNick Mathewson if (bev_ssl->underlying) {
40889396767SAzat Khuzhin if (bev_ssl->write_blocked_on_read) {
40989396767SAzat Khuzhin bufferevent_unsuspend_read_(bev_ssl->underlying,
41089396767SAzat Khuzhin BEV_SUSPEND_FILT_READ);
41189396767SAzat Khuzhin }
412709c21c4SNick Mathewson } else {
413709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
414cb9da0bfSNick Mathewson r = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
415ff3f6cd4SNick Mathewson if (!r && bev_ssl->write_blocked_on_read)
416cb9da0bfSNick Mathewson r = bufferevent_add_event_(&bev->ev_read,
417709c21c4SNick Mathewson &bev->timeout_read);
418709c21c4SNick Mathewson }
419ff3f6cd4SNick Mathewson return r;
420709c21c4SNick Mathewson }
421709c21c4SNick Mathewson
422709c21c4SNick Mathewson static void
stop_reading(struct bufferevent_openssl * bev_ssl)423709c21c4SNick Mathewson stop_reading(struct bufferevent_openssl *bev_ssl)
424709c21c4SNick Mathewson {
425709c21c4SNick Mathewson if (bev_ssl->write_blocked_on_read)
426709c21c4SNick Mathewson return;
427ac27eb82SNick Mathewson if (bev_ssl->underlying) {
4288ac3c4c2SNick Mathewson bufferevent_suspend_read_(bev_ssl->underlying,
429ac27eb82SNick Mathewson BEV_SUSPEND_FILT_READ);
430ac27eb82SNick Mathewson } else {
431709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
432709c21c4SNick Mathewson event_del(&bev->ev_read);
433709c21c4SNick Mathewson }
434709c21c4SNick Mathewson }
435709c21c4SNick Mathewson
436709c21c4SNick Mathewson static void
stop_writing(struct bufferevent_openssl * bev_ssl)437709c21c4SNick Mathewson stop_writing(struct bufferevent_openssl *bev_ssl)
438709c21c4SNick Mathewson {
439709c21c4SNick Mathewson if (bev_ssl->read_blocked_on_write)
440709c21c4SNick Mathewson return;
441ac27eb82SNick Mathewson if (bev_ssl->underlying) {
44289396767SAzat Khuzhin bufferevent_unsuspend_read_(bev_ssl->underlying,
44389396767SAzat Khuzhin BEV_SUSPEND_FILT_READ);
444ac27eb82SNick Mathewson } else {
445709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
446709c21c4SNick Mathewson event_del(&bev->ev_write);
447709c21c4SNick Mathewson }
448709c21c4SNick Mathewson }
449709c21c4SNick Mathewson
450ff3f6cd4SNick Mathewson static int
set_rbow(struct bufferevent_openssl * bev_ssl)451709c21c4SNick Mathewson set_rbow(struct bufferevent_openssl *bev_ssl)
452709c21c4SNick Mathewson {
4537a2a51a3SNick Mathewson if (!bev_ssl->underlying)
454709c21c4SNick Mathewson stop_reading(bev_ssl);
455709c21c4SNick Mathewson bev_ssl->read_blocked_on_write = 1;
456ff3f6cd4SNick Mathewson return start_writing(bev_ssl);
457709c21c4SNick Mathewson }
458709c21c4SNick Mathewson
459ff3f6cd4SNick Mathewson static int
set_wbor(struct bufferevent_openssl * bev_ssl)460709c21c4SNick Mathewson set_wbor(struct bufferevent_openssl *bev_ssl)
461709c21c4SNick Mathewson {
4627a2a51a3SNick Mathewson if (!bev_ssl->underlying)
463709c21c4SNick Mathewson stop_writing(bev_ssl);
464709c21c4SNick Mathewson bev_ssl->write_blocked_on_read = 1;
465ff3f6cd4SNick Mathewson return start_reading(bev_ssl);
466709c21c4SNick Mathewson }
467709c21c4SNick Mathewson
468ff3f6cd4SNick Mathewson static int
clear_rbow(struct bufferevent_openssl * bev_ssl)469709c21c4SNick Mathewson clear_rbow(struct bufferevent_openssl *bev_ssl)
470709c21c4SNick Mathewson {
471709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
472ff3f6cd4SNick Mathewson int r = 0;
473709c21c4SNick Mathewson bev_ssl->read_blocked_on_write = 0;
474709c21c4SNick Mathewson if (!(bev->enabled & EV_WRITE))
475709c21c4SNick Mathewson stop_writing(bev_ssl);
476709c21c4SNick Mathewson if (bev->enabled & EV_READ)
477ff3f6cd4SNick Mathewson r = start_reading(bev_ssl);
478ff3f6cd4SNick Mathewson return r;
479709c21c4SNick Mathewson }
480709c21c4SNick Mathewson
481709c21c4SNick Mathewson
482ff3f6cd4SNick Mathewson static int
clear_wbor(struct bufferevent_openssl * bev_ssl)483709c21c4SNick Mathewson clear_wbor(struct bufferevent_openssl *bev_ssl)
484709c21c4SNick Mathewson {
485709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
486ff3f6cd4SNick Mathewson int r = 0;
487709c21c4SNick Mathewson bev_ssl->write_blocked_on_read = 0;
488709c21c4SNick Mathewson if (!(bev->enabled & EV_READ))
489709c21c4SNick Mathewson stop_reading(bev_ssl);
490709c21c4SNick Mathewson if (bev->enabled & EV_WRITE)
491ff3f6cd4SNick Mathewson r = start_writing(bev_ssl);
492ff3f6cd4SNick Mathewson return r;
493709c21c4SNick Mathewson }
494709c21c4SNick Mathewson
495709c21c4SNick Mathewson static void
conn_closed(struct bufferevent_openssl * bev_ssl,int when,int errcode,int ret)496f7eb69acSCatalin Patulea conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
497709c21c4SNick Mathewson {
498709c21c4SNick Mathewson int event = BEV_EVENT_ERROR;
499709c21c4SNick Mathewson int dirty_shutdown = 0;
500516452b7SNick Mathewson unsigned long err;
501709c21c4SNick Mathewson
502709c21c4SNick Mathewson switch (errcode) {
503709c21c4SNick Mathewson case SSL_ERROR_ZERO_RETURN:
504709c21c4SNick Mathewson /* Possibly a clean shutdown. */
505709c21c4SNick Mathewson if (SSL_get_shutdown(bev_ssl->ssl) & SSL_RECEIVED_SHUTDOWN)
506709c21c4SNick Mathewson event = BEV_EVENT_EOF;
507709c21c4SNick Mathewson else
508709c21c4SNick Mathewson dirty_shutdown = 1;
509709c21c4SNick Mathewson break;
510709c21c4SNick Mathewson case SSL_ERROR_SYSCALL:
511709c21c4SNick Mathewson /* IO error; possibly a dirty shutdown. */
512d94b1762SAzat Khuzhin if ((ret == 0 || ret == -1) && ERR_peek_error() == 0)
513709c21c4SNick Mathewson dirty_shutdown = 1;
514*3d1a7a1dSYury Korzhetsky put_error(bev_ssl, errcode);
515709c21c4SNick Mathewson break;
516709c21c4SNick Mathewson case SSL_ERROR_SSL:
517709c21c4SNick Mathewson /* Protocol error. */
518*3d1a7a1dSYury Korzhetsky put_error(bev_ssl, errcode);
519709c21c4SNick Mathewson break;
520709c21c4SNick Mathewson case SSL_ERROR_WANT_X509_LOOKUP:
521709c21c4SNick Mathewson /* XXXX handle this. */
522*3d1a7a1dSYury Korzhetsky put_error(bev_ssl, errcode);
523709c21c4SNick Mathewson break;
524709c21c4SNick Mathewson case SSL_ERROR_NONE:
525709c21c4SNick Mathewson case SSL_ERROR_WANT_READ:
526709c21c4SNick Mathewson case SSL_ERROR_WANT_WRITE:
527709c21c4SNick Mathewson case SSL_ERROR_WANT_CONNECT:
528709c21c4SNick Mathewson case SSL_ERROR_WANT_ACCEPT:
529709c21c4SNick Mathewson default:
53026573d3dSNick Mathewson /* should be impossible; treat as normal error. */
53126573d3dSNick Mathewson event_warnx("BUG: Unexpected OpenSSL error code %d", errcode);
53226573d3dSNick Mathewson break;
533709c21c4SNick Mathewson }
534709c21c4SNick Mathewson
535516452b7SNick Mathewson while ((err = ERR_get_error())) {
536516452b7SNick Mathewson put_error(bev_ssl, err);
537516452b7SNick Mathewson }
538516452b7SNick Mathewson
539709c21c4SNick Mathewson if (dirty_shutdown && bev_ssl->allow_dirty_shutdown)
540709c21c4SNick Mathewson event = BEV_EVENT_EOF;
541709c21c4SNick Mathewson
542709c21c4SNick Mathewson stop_reading(bev_ssl);
543709c21c4SNick Mathewson stop_writing(bev_ssl);
54429f7623cSNick Mathewson
545f7eb69acSCatalin Patulea /* when is BEV_EVENT_{READING|WRITING} */
546f7eb69acSCatalin Patulea event = when | event;
547a7384c78SOndřej Kuzník bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
548709c21c4SNick Mathewson }
549709c21c4SNick Mathewson
550009f3005SNick Mathewson static void
init_bio_counts(struct bufferevent_openssl * bev_ssl)551009f3005SNick Mathewson init_bio_counts(struct bufferevent_openssl *bev_ssl)
552009f3005SNick Mathewson {
5536bf2061cSPhilip Prindeville BIO *rbio, *wbio;
5546bf2061cSPhilip Prindeville
5556bf2061cSPhilip Prindeville wbio = SSL_get_wbio(bev_ssl->ssl);
5566702da1aSAdam Langley bev_ssl->counts.n_written = wbio ? BIO_number_written(wbio) : 0;
5576bf2061cSPhilip Prindeville rbio = SSL_get_rbio(bev_ssl->ssl);
5586702da1aSAdam Langley bev_ssl->counts.n_read = rbio ? BIO_number_read(rbio) : 0;
559009f3005SNick Mathewson }
560009f3005SNick Mathewson
561009f3005SNick Mathewson static inline void
decrement_buckets(struct bufferevent_openssl * bev_ssl)562009f3005SNick Mathewson decrement_buckets(struct bufferevent_openssl *bev_ssl)
563009f3005SNick Mathewson {
564009f3005SNick Mathewson unsigned long num_w = BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
565819b1715SNick Mathewson unsigned long num_r = BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
566009f3005SNick Mathewson /* These next two subtractions can wrap around. That's okay. */
567009f3005SNick Mathewson unsigned long w = num_w - bev_ssl->counts.n_written;
568009f3005SNick Mathewson unsigned long r = num_r - bev_ssl->counts.n_read;
569009f3005SNick Mathewson if (w)
570cb9da0bfSNick Mathewson bufferevent_decrement_write_buckets_(&bev_ssl->bev, w);
571009f3005SNick Mathewson if (r)
572cb9da0bfSNick Mathewson bufferevent_decrement_read_buckets_(&bev_ssl->bev, r);
573009f3005SNick Mathewson bev_ssl->counts.n_written = num_w;
574009f3005SNick Mathewson bev_ssl->counts.n_read = num_r;
575009f3005SNick Mathewson }
576009f3005SNick Mathewson
577606ac43bSNick Mathewson #define OP_MADE_PROGRESS 1
578606ac43bSNick Mathewson #define OP_BLOCKED 2
579606ac43bSNick Mathewson #define OP_ERR 4
580606ac43bSNick Mathewson
581606ac43bSNick Mathewson /* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
582606ac43bSNick Mathewson we're now blocked); and OP_ERR (if an error occurred). */
583709c21c4SNick Mathewson static int
do_read(struct bufferevent_openssl * bev_ssl,int n_to_read)584606ac43bSNick Mathewson do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
585709c21c4SNick Mathewson /* Requires lock */
586709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
587709c21c4SNick Mathewson struct evbuffer *input = bev->input;
588606ac43bSNick Mathewson int r, n, i, n_used = 0, atmost;
589709c21c4SNick Mathewson struct evbuffer_iovec space[2];
590606ac43bSNick Mathewson int result = 0;
591709c21c4SNick Mathewson
5921acf2ebcSJoachim Bauch if (bev_ssl->bev.read_suspended)
5931acf2ebcSJoachim Bauch return 0;
594709c21c4SNick Mathewson
595cb9da0bfSNick Mathewson atmost = bufferevent_get_read_max_(&bev_ssl->bev);
596737c9cd8SNick Mathewson if (n_to_read > atmost)
597737c9cd8SNick Mathewson n_to_read = atmost;
598737c9cd8SNick Mathewson
599709c21c4SNick Mathewson n = evbuffer_reserve_space(input, n_to_read, space, 2);
600709c21c4SNick Mathewson if (n < 0)
601606ac43bSNick Mathewson return OP_ERR;
602709c21c4SNick Mathewson
603709c21c4SNick Mathewson for (i=0; i<n; ++i) {
604737c9cd8SNick Mathewson if (bev_ssl->bev.read_suspended)
605737c9cd8SNick Mathewson break;
60638e0f4a5SAzat Khuzhin ERR_clear_error();
607709c21c4SNick Mathewson r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
608709c21c4SNick Mathewson if (r>0) {
609606ac43bSNick Mathewson result |= OP_MADE_PROGRESS;
610709c21c4SNick Mathewson if (bev_ssl->read_blocked_on_write)
611ff3f6cd4SNick Mathewson if (clear_rbow(bev_ssl) < 0)
612606ac43bSNick Mathewson return OP_ERR | result;
613709c21c4SNick Mathewson ++n_used;
614709c21c4SNick Mathewson space[i].iov_len = r;
615009f3005SNick Mathewson decrement_buckets(bev_ssl);
616709c21c4SNick Mathewson } else {
617709c21c4SNick Mathewson int err = SSL_get_error(bev_ssl->ssl, r);
618709c21c4SNick Mathewson print_err(err);
619709c21c4SNick Mathewson switch (err) {
620709c21c4SNick Mathewson case SSL_ERROR_WANT_READ:
621709c21c4SNick Mathewson /* Can't read until underlying has more data. */
622709c21c4SNick Mathewson if (bev_ssl->read_blocked_on_write)
623ff3f6cd4SNick Mathewson if (clear_rbow(bev_ssl) < 0)
624606ac43bSNick Mathewson return OP_ERR | result;
625709c21c4SNick Mathewson break;
626709c21c4SNick Mathewson case SSL_ERROR_WANT_WRITE:
627709c21c4SNick Mathewson /* This read operation requires a write, and the
628709c21c4SNick Mathewson * underlying is full */
629709c21c4SNick Mathewson if (!bev_ssl->read_blocked_on_write)
630ff3f6cd4SNick Mathewson if (set_rbow(bev_ssl) < 0)
631606ac43bSNick Mathewson return OP_ERR | result;
632709c21c4SNick Mathewson break;
633709c21c4SNick Mathewson default:
634f7eb69acSCatalin Patulea conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
635709c21c4SNick Mathewson break;
636709c21c4SNick Mathewson }
637606ac43bSNick Mathewson result |= OP_BLOCKED;
638709c21c4SNick Mathewson break; /* out of the loop */
639709c21c4SNick Mathewson }
640709c21c4SNick Mathewson }
641709c21c4SNick Mathewson
642709c21c4SNick Mathewson if (n_used) {
643709c21c4SNick Mathewson evbuffer_commit_space(input, space, n_used);
644709c21c4SNick Mathewson if (bev_ssl->underlying)
645709c21c4SNick Mathewson BEV_RESET_GENERIC_READ_TIMEOUT(bev);
646709c21c4SNick Mathewson }
647709c21c4SNick Mathewson
648606ac43bSNick Mathewson return result;
649709c21c4SNick Mathewson }
650709c21c4SNick Mathewson
651606ac43bSNick Mathewson /* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
652606ac43bSNick Mathewson we're now blocked); and OP_ERR (if an error occurred). */
653709c21c4SNick Mathewson static int
do_write(struct bufferevent_openssl * bev_ssl,int atmost)654709c21c4SNick Mathewson do_write(struct bufferevent_openssl *bev_ssl, int atmost)
655709c21c4SNick Mathewson {
656606ac43bSNick Mathewson int i, r, n, n_written = 0;
657709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
658709c21c4SNick Mathewson struct evbuffer *output = bev->output;
659709c21c4SNick Mathewson struct evbuffer_iovec space[8];
660606ac43bSNick Mathewson int result = 0;
661709c21c4SNick Mathewson
662595f7e38SNick Mathewson if (bev_ssl->last_write > 0)
663595f7e38SNick Mathewson atmost = bev_ssl->last_write;
664737c9cd8SNick Mathewson else
665cb9da0bfSNick Mathewson atmost = bufferevent_get_write_max_(&bev_ssl->bev);
666595f7e38SNick Mathewson
667709c21c4SNick Mathewson n = evbuffer_peek(output, atmost, NULL, space, 8);
668709c21c4SNick Mathewson if (n < 0)
669606ac43bSNick Mathewson return OP_ERR | result;
670709c21c4SNick Mathewson
671a6adeca7SJoachim Bauch if (n > 8)
672a6adeca7SJoachim Bauch n = 8;
673709c21c4SNick Mathewson for (i=0; i < n; ++i) {
674737c9cd8SNick Mathewson if (bev_ssl->bev.write_suspended)
675737c9cd8SNick Mathewson break;
676737c9cd8SNick Mathewson
677c9913174SMike Smellie /* SSL_write will (reasonably) return 0 if we tell it to
678c9913174SMike Smellie send 0 data. Skip this case so we don't interpret the
679c9913174SMike Smellie result as an error */
680c9913174SMike Smellie if (space[i].iov_len == 0)
681c9913174SMike Smellie continue;
682c9913174SMike Smellie
68338e0f4a5SAzat Khuzhin ERR_clear_error();
684709c21c4SNick Mathewson r = SSL_write(bev_ssl->ssl, space[i].iov_base,
685709c21c4SNick Mathewson space[i].iov_len);
686709c21c4SNick Mathewson if (r > 0) {
687606ac43bSNick Mathewson result |= OP_MADE_PROGRESS;
688709c21c4SNick Mathewson if (bev_ssl->write_blocked_on_read)
689ff3f6cd4SNick Mathewson if (clear_wbor(bev_ssl) < 0)
690606ac43bSNick Mathewson return OP_ERR | result;
691709c21c4SNick Mathewson n_written += r;
692595f7e38SNick Mathewson bev_ssl->last_write = -1;
693009f3005SNick Mathewson decrement_buckets(bev_ssl);
694709c21c4SNick Mathewson } else {
695709c21c4SNick Mathewson int err = SSL_get_error(bev_ssl->ssl, r);
696709c21c4SNick Mathewson print_err(err);
697709c21c4SNick Mathewson switch (err) {
698709c21c4SNick Mathewson case SSL_ERROR_WANT_WRITE:
699709c21c4SNick Mathewson /* Can't read until underlying has more data. */
700709c21c4SNick Mathewson if (bev_ssl->write_blocked_on_read)
701ff3f6cd4SNick Mathewson if (clear_wbor(bev_ssl) < 0)
702606ac43bSNick Mathewson return OP_ERR | result;
703595f7e38SNick Mathewson bev_ssl->last_write = space[i].iov_len;
704709c21c4SNick Mathewson break;
705709c21c4SNick Mathewson case SSL_ERROR_WANT_READ:
706709c21c4SNick Mathewson /* This read operation requires a write, and the
707709c21c4SNick Mathewson * underlying is full */
708709c21c4SNick Mathewson if (!bev_ssl->write_blocked_on_read)
709ff3f6cd4SNick Mathewson if (set_wbor(bev_ssl) < 0)
710606ac43bSNick Mathewson return OP_ERR | result;
711595f7e38SNick Mathewson bev_ssl->last_write = space[i].iov_len;
712709c21c4SNick Mathewson break;
713709c21c4SNick Mathewson default:
714f7eb69acSCatalin Patulea conn_closed(bev_ssl, BEV_EVENT_WRITING, err, r);
715595f7e38SNick Mathewson bev_ssl->last_write = -1;
716709c21c4SNick Mathewson break;
717709c21c4SNick Mathewson }
718606ac43bSNick Mathewson result |= OP_BLOCKED;
719709c21c4SNick Mathewson break;
720709c21c4SNick Mathewson }
721709c21c4SNick Mathewson }
722709c21c4SNick Mathewson if (n_written) {
723709c21c4SNick Mathewson evbuffer_drain(output, n_written);
724709c21c4SNick Mathewson if (bev_ssl->underlying)
725709c21c4SNick Mathewson BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
726709c21c4SNick Mathewson
72789396767SAzat Khuzhin bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
728709c21c4SNick Mathewson }
729606ac43bSNick Mathewson return result;
730709c21c4SNick Mathewson }
731709c21c4SNick Mathewson
732709c21c4SNick Mathewson #define WRITE_FRAME 15000
733709c21c4SNick Mathewson
734709c21c4SNick Mathewson #define READ_DEFAULT 4096
735709c21c4SNick Mathewson
736a186e732SMark Ellzey /* Try to figure out how many bytes to read; return 0 if we shouldn't be
737a186e732SMark Ellzey * reading. */
738a186e732SMark Ellzey static int
bytes_to_read(struct bufferevent_openssl * bev)739a186e732SMark Ellzey bytes_to_read(struct bufferevent_openssl *bev)
740a186e732SMark Ellzey {
741a186e732SMark Ellzey struct evbuffer *input = bev->bev.bev.input;
742a186e732SMark Ellzey struct event_watermark *wm = &bev->bev.bev.wm_read;
74396c562faSNick Mathewson int result = READ_DEFAULT;
74496c562faSNick Mathewson ev_ssize_t limit;
74596c562faSNick Mathewson /* XXX 99% of this is generic code that nearly all bufferevents will
74696c562faSNick Mathewson * want. */
747a186e732SMark Ellzey
748a186e732SMark Ellzey if (bev->write_blocked_on_read) {
749a186e732SMark Ellzey return 0;
750a186e732SMark Ellzey }
751a186e732SMark Ellzey
752a186e732SMark Ellzey if (! (bev->bev.bev.enabled & EV_READ)) {
753a186e732SMark Ellzey return 0;
754a186e732SMark Ellzey }
755a186e732SMark Ellzey
756a186e732SMark Ellzey if (bev->bev.read_suspended) {
757a186e732SMark Ellzey return 0;
758a186e732SMark Ellzey }
759a186e732SMark Ellzey
760a186e732SMark Ellzey if (wm->high) {
761a186e732SMark Ellzey if (evbuffer_get_length(input) >= wm->high) {
762a186e732SMark Ellzey return 0;
763a186e732SMark Ellzey }
764a186e732SMark Ellzey
76596c562faSNick Mathewson result = wm->high - evbuffer_get_length(input);
76696c562faSNick Mathewson } else {
76796c562faSNick Mathewson result = READ_DEFAULT;
768a186e732SMark Ellzey }
769a186e732SMark Ellzey
77096c562faSNick Mathewson /* Respect the rate limit */
771cb9da0bfSNick Mathewson limit = bufferevent_get_read_max_(&bev->bev);
77296c562faSNick Mathewson if (result > limit) {
77396c562faSNick Mathewson result = limit;
77496c562faSNick Mathewson }
77596c562faSNick Mathewson
77696c562faSNick Mathewson return result;
777a186e732SMark Ellzey }
778a186e732SMark Ellzey
779a186e732SMark Ellzey
780709c21c4SNick Mathewson /* Things look readable. If write is blocked on read, write till it isn't.
781709c21c4SNick Mathewson * Read from the underlying buffer until we block or we hit our high-water
782709c21c4SNick Mathewson * mark.
783709c21c4SNick Mathewson */
784709c21c4SNick Mathewson static void
consider_reading(struct bufferevent_openssl * bev_ssl)785709c21c4SNick Mathewson consider_reading(struct bufferevent_openssl *bev_ssl)
786709c21c4SNick Mathewson {
787709c21c4SNick Mathewson int r;
788a186e732SMark Ellzey int n_to_read;
789606ac43bSNick Mathewson int all_result_flags = 0;
790709c21c4SNick Mathewson
791709c21c4SNick Mathewson while (bev_ssl->write_blocked_on_read) {
792709c21c4SNick Mathewson r = do_write(bev_ssl, WRITE_FRAME);
793606ac43bSNick Mathewson if (r & (OP_BLOCKED|OP_ERR))
794709c21c4SNick Mathewson break;
795709c21c4SNick Mathewson }
796709c21c4SNick Mathewson if (bev_ssl->write_blocked_on_read)
797709c21c4SNick Mathewson return;
798a186e732SMark Ellzey
7992aa036faSMark Ellzey n_to_read = bytes_to_read(bev_ssl);
8002aa036faSMark Ellzey
8012aa036faSMark Ellzey while (n_to_read) {
802606ac43bSNick Mathewson r = do_read(bev_ssl, n_to_read);
803606ac43bSNick Mathewson all_result_flags |= r;
8042aa036faSMark Ellzey
805606ac43bSNick Mathewson if (r & (OP_BLOCKED|OP_ERR))
806606ac43bSNick Mathewson break;
8074e62cd16SMark Ellzey
808f719b8a9SJoachim Bauch if (bev_ssl->bev.read_suspended)
809f719b8a9SJoachim Bauch break;
810f719b8a9SJoachim Bauch
811ebf82199SNick Mathewson /* Read all pending data. This won't hit the network
812ebf82199SNick Mathewson * again, and will (most importantly) put us in a state
813ebf82199SNick Mathewson * where we don't need to read anything else until the
814ebf82199SNick Mathewson * socket is readable again. It'll potentially make us
815ebf82199SNick Mathewson * overrun our read high-watermark (somewhat
816ebf82199SNick Mathewson * regrettable). The damage to the rate-limit has
817ebf82199SNick Mathewson * already been done, since OpenSSL went and read a
818ebf82199SNick Mathewson * whole SSL record anyway. */
8192aa036faSMark Ellzey n_to_read = SSL_pending(bev_ssl->ssl);
8205b4b8126SNick Mathewson
8215b4b8126SNick Mathewson /* XXX This if statement is actually a bad bug, added to avoid
8225b4b8126SNick Mathewson * XXX a worse bug.
8235b4b8126SNick Mathewson *
8245b4b8126SNick Mathewson * The bad bug: It can potentially cause resource unfairness
8255b4b8126SNick Mathewson * by reading too much data from the underlying bufferevent;
8265b4b8126SNick Mathewson * it can potentially cause read looping if the underlying
8275b4b8126SNick Mathewson * bufferevent is a bufferevent_pair and deferred callbacks
8285b4b8126SNick Mathewson * aren't used.
8295b4b8126SNick Mathewson *
8305b4b8126SNick Mathewson * The worse bug: If we didn't do this, then we would
8315b4b8126SNick Mathewson * potentially not read any more from bev_ssl->underlying
8325b4b8126SNick Mathewson * until more data arrived there, which could lead to us
8335b4b8126SNick Mathewson * waiting forever.
8345b4b8126SNick Mathewson */
8355b4b8126SNick Mathewson if (!n_to_read && bev_ssl->underlying)
8365b4b8126SNick Mathewson n_to_read = bytes_to_read(bev_ssl);
837709c21c4SNick Mathewson }
8381213d3ddSNick Mathewson
839606ac43bSNick Mathewson if (all_result_flags & OP_MADE_PROGRESS) {
8404e62cd16SMark Ellzey struct bufferevent *bev = &bev_ssl->bev.bev;
8414e62cd16SMark Ellzey
84261ee18b8SOndřej Kuzník bufferevent_trigger_nolock_(bev, EV_READ, 0);
8434e62cd16SMark Ellzey }
8444e62cd16SMark Ellzey
8451213d3ddSNick Mathewson if (!bev_ssl->underlying) {
8461213d3ddSNick Mathewson /* Should be redundant, but let's avoid busy-looping */
8471213d3ddSNick Mathewson if (bev_ssl->bev.read_suspended ||
8481213d3ddSNick Mathewson !(bev_ssl->bev.bev.enabled & EV_READ)) {
8491213d3ddSNick Mathewson event_del(&bev_ssl->bev.bev.ev_read);
8501213d3ddSNick Mathewson }
8511213d3ddSNick Mathewson }
852709c21c4SNick Mathewson }
853709c21c4SNick Mathewson
854709c21c4SNick Mathewson static void
consider_writing(struct bufferevent_openssl * bev_ssl)855709c21c4SNick Mathewson consider_writing(struct bufferevent_openssl *bev_ssl)
856709c21c4SNick Mathewson {
857709c21c4SNick Mathewson int r;
858709c21c4SNick Mathewson struct evbuffer *output = bev_ssl->bev.bev.output;
859709c21c4SNick Mathewson struct evbuffer *target = NULL;
860709c21c4SNick Mathewson struct event_watermark *wm = NULL;
861709c21c4SNick Mathewson
862709c21c4SNick Mathewson while (bev_ssl->read_blocked_on_write) {
863709c21c4SNick Mathewson r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
864606ac43bSNick Mathewson if (r & OP_MADE_PROGRESS) {
8654e62cd16SMark Ellzey struct bufferevent *bev = &bev_ssl->bev.bev;
8664e62cd16SMark Ellzey
86761ee18b8SOndřej Kuzník bufferevent_trigger_nolock_(bev, EV_READ, 0);
8684e62cd16SMark Ellzey }
869606ac43bSNick Mathewson if (r & (OP_ERR|OP_BLOCKED))
870606ac43bSNick Mathewson break;
871709c21c4SNick Mathewson }
872709c21c4SNick Mathewson if (bev_ssl->read_blocked_on_write)
873709c21c4SNick Mathewson return;
874709c21c4SNick Mathewson if (bev_ssl->underlying) {
875709c21c4SNick Mathewson target = bev_ssl->underlying->output;
876709c21c4SNick Mathewson wm = &bev_ssl->underlying->wm_write;
877709c21c4SNick Mathewson }
878a62346deSNick Mathewson while ((bev_ssl->bev.bev.enabled & EV_WRITE) &&
87982743794SNick Mathewson (! bev_ssl->bev.write_suspended) &&
880709c21c4SNick Mathewson evbuffer_get_length(output) &&
881709c21c4SNick Mathewson (!target || (! wm->high || evbuffer_get_length(target) < wm->high))) {
882709c21c4SNick Mathewson int n_to_write;
883709c21c4SNick Mathewson if (wm && wm->high)
884709c21c4SNick Mathewson n_to_write = wm->high - evbuffer_get_length(target);
885709c21c4SNick Mathewson else
886709c21c4SNick Mathewson n_to_write = WRITE_FRAME;
887709c21c4SNick Mathewson r = do_write(bev_ssl, n_to_write);
888606ac43bSNick Mathewson if (r & (OP_BLOCKED|OP_ERR))
889a62346deSNick Mathewson break;
890709c21c4SNick Mathewson }
891709c21c4SNick Mathewson
8921213d3ddSNick Mathewson if (!bev_ssl->underlying) {
8931213d3ddSNick Mathewson if (evbuffer_get_length(output) == 0) {
894709c21c4SNick Mathewson event_del(&bev_ssl->bev.bev.ev_write);
8951213d3ddSNick Mathewson } else if (bev_ssl->bev.write_suspended ||
8961213d3ddSNick Mathewson !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
8971213d3ddSNick Mathewson /* Should be redundant, but let's avoid busy-looping */
8981213d3ddSNick Mathewson event_del(&bev_ssl->bev.bev.ev_write);
8991213d3ddSNick Mathewson }
9001213d3ddSNick Mathewson }
901709c21c4SNick Mathewson }
902709c21c4SNick Mathewson
903709c21c4SNick Mathewson static void
be_openssl_readcb(struct bufferevent * bev_base,void * ctx)904709c21c4SNick Mathewson be_openssl_readcb(struct bufferevent *bev_base, void *ctx)
905709c21c4SNick Mathewson {
906709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ctx;
907709c21c4SNick Mathewson consider_reading(bev_ssl);
908709c21c4SNick Mathewson }
909709c21c4SNick Mathewson
910709c21c4SNick Mathewson static void
be_openssl_writecb(struct bufferevent * bev_base,void * ctx)911709c21c4SNick Mathewson be_openssl_writecb(struct bufferevent *bev_base, void *ctx)
912709c21c4SNick Mathewson {
913709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ctx;
914709c21c4SNick Mathewson consider_writing(bev_ssl);
915709c21c4SNick Mathewson }
916709c21c4SNick Mathewson
917709c21c4SNick Mathewson static void
be_openssl_eventcb(struct bufferevent * bev_base,short what,void * ctx)918709c21c4SNick Mathewson be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
919709c21c4SNick Mathewson {
920709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ctx;
921709c21c4SNick Mathewson int event = 0;
922709c21c4SNick Mathewson
923709c21c4SNick Mathewson if (what & BEV_EVENT_EOF) {
924709c21c4SNick Mathewson if (bev_ssl->allow_dirty_shutdown)
925709c21c4SNick Mathewson event = BEV_EVENT_EOF;
926709c21c4SNick Mathewson else
927709c21c4SNick Mathewson event = BEV_EVENT_ERROR;
928709c21c4SNick Mathewson } else if (what & BEV_EVENT_TIMEOUT) {
929709c21c4SNick Mathewson /* We sure didn't set this. Propagate it to the user. */
930709c21c4SNick Mathewson event = what;
9314a343943SJoachim Bauch } else if (what & BEV_EVENT_ERROR) {
9324a343943SJoachim Bauch /* An error occurred on the connection. Propagate it to the user. */
9334a343943SJoachim Bauch event = what;
934709c21c4SNick Mathewson } else if (what & BEV_EVENT_CONNECTED) {
935709c21c4SNick Mathewson /* Ignore it. We're saying SSL_connect() already, which will
936709c21c4SNick Mathewson eat it. */
937709c21c4SNick Mathewson }
938709c21c4SNick Mathewson if (event)
939a7384c78SOndřej Kuzník bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
940709c21c4SNick Mathewson }
941709c21c4SNick Mathewson
942709c21c4SNick Mathewson static void
be_openssl_readeventcb(evutil_socket_t fd,short what,void * ptr)943709c21c4SNick Mathewson be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
944709c21c4SNick Mathewson {
945709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ptr;
946cb9da0bfSNick Mathewson bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
947576b29f2SNick Mathewson if (what == EV_TIMEOUT) {
948cb9da0bfSNick Mathewson bufferevent_run_eventcb_(&bev_ssl->bev.bev,
949a7384c78SOndřej Kuzník BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
950576b29f2SNick Mathewson } else {
951709c21c4SNick Mathewson consider_reading(bev_ssl);
952576b29f2SNick Mathewson }
953cb9da0bfSNick Mathewson bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
954709c21c4SNick Mathewson }
955709c21c4SNick Mathewson
956709c21c4SNick Mathewson static void
be_openssl_writeeventcb(evutil_socket_t fd,short what,void * ptr)957709c21c4SNick Mathewson be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
958709c21c4SNick Mathewson {
959709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ptr;
960cb9da0bfSNick Mathewson bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
961576b29f2SNick Mathewson if (what == EV_TIMEOUT) {
962cb9da0bfSNick Mathewson bufferevent_run_eventcb_(&bev_ssl->bev.bev,
963a7384c78SOndřej Kuzník BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
964576b29f2SNick Mathewson } else {
965709c21c4SNick Mathewson consider_writing(bev_ssl);
966576b29f2SNick Mathewson }
967cb9da0bfSNick Mathewson bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
968709c21c4SNick Mathewson }
969709c21c4SNick Mathewson
970e66078a0SAzat Khuzhin static evutil_socket_t
be_openssl_auto_fd(struct bufferevent_openssl * bev_ssl,evutil_socket_t fd)971e66078a0SAzat Khuzhin be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
9722a8a7112SAzat Khuzhin {
9732a8a7112SAzat Khuzhin if (!bev_ssl->underlying) {
9742a8a7112SAzat Khuzhin struct bufferevent *bev = &bev_ssl->bev.bev;
9752a8a7112SAzat Khuzhin if (event_initialized(&bev->ev_read) && fd < 0) {
9762a8a7112SAzat Khuzhin fd = event_get_fd(&bev->ev_read);
9772a8a7112SAzat Khuzhin }
9782a8a7112SAzat Khuzhin }
9792a8a7112SAzat Khuzhin return fd;
9802a8a7112SAzat Khuzhin }
9812a8a7112SAzat Khuzhin
9822a8a7112SAzat Khuzhin static int
set_open_callbacks(struct bufferevent_openssl * bev_ssl,evutil_socket_t fd)983709c21c4SNick Mathewson set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
984709c21c4SNick Mathewson {
985709c21c4SNick Mathewson if (bev_ssl->underlying) {
986709c21c4SNick Mathewson bufferevent_setcb(bev_ssl->underlying,
987709c21c4SNick Mathewson be_openssl_readcb, be_openssl_writecb, be_openssl_eventcb,
988709c21c4SNick Mathewson bev_ssl);
989ff3f6cd4SNick Mathewson return 0;
990709c21c4SNick Mathewson } else {
991709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
992ff3f6cd4SNick Mathewson int rpending=0, wpending=0, r1=0, r2=0;
99340b03798SAzat Khuzhin
994510da71fSAzat Khuzhin if (event_initialized(&bev->ev_read)) {
995709c21c4SNick Mathewson rpending = event_pending(&bev->ev_read, EV_READ, NULL);
996709c21c4SNick Mathewson wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
997e8a2da96SAzat Khuzhin
998709c21c4SNick Mathewson event_del(&bev->ev_read);
999709c21c4SNick Mathewson event_del(&bev->ev_write);
1000709c21c4SNick Mathewson }
100140b03798SAzat Khuzhin
1002510da71fSAzat Khuzhin event_assign(&bev->ev_read, bev->ev_base, fd,
100302fbf687SNick Mathewson EV_READ|EV_PERSIST|EV_FINALIZE,
100402fbf687SNick Mathewson be_openssl_readeventcb, bev_ssl);
1005510da71fSAzat Khuzhin event_assign(&bev->ev_write, bev->ev_base, fd,
100602fbf687SNick Mathewson EV_WRITE|EV_PERSIST|EV_FINALIZE,
100702fbf687SNick Mathewson be_openssl_writeeventcb, bev_ssl);
100840b03798SAzat Khuzhin
1009709c21c4SNick Mathewson if (rpending)
1010cb9da0bfSNick Mathewson r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
1011709c21c4SNick Mathewson if (wpending)
1012cb9da0bfSNick Mathewson r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
101340b03798SAzat Khuzhin
1014ff3f6cd4SNick Mathewson return (r1<0 || r2<0) ? -1 : 0;
1015709c21c4SNick Mathewson }
1016709c21c4SNick Mathewson }
1017709c21c4SNick Mathewson
1018709c21c4SNick Mathewson static int
do_handshake(struct bufferevent_openssl * bev_ssl)1019709c21c4SNick Mathewson do_handshake(struct bufferevent_openssl *bev_ssl)
1020709c21c4SNick Mathewson {
1021709c21c4SNick Mathewson int r;
1022709c21c4SNick Mathewson
1023709c21c4SNick Mathewson switch (bev_ssl->state) {
1024709c21c4SNick Mathewson default:
1025709c21c4SNick Mathewson case BUFFEREVENT_SSL_OPEN:
10262e36dbe1SNick Mathewson EVUTIL_ASSERT(0);
1027743f8665SNick Mathewson return -1;
1028709c21c4SNick Mathewson case BUFFEREVENT_SSL_CONNECTING:
1029709c21c4SNick Mathewson case BUFFEREVENT_SSL_ACCEPTING:
103038e0f4a5SAzat Khuzhin ERR_clear_error();
103144715517SNick Mathewson r = SSL_do_handshake(bev_ssl->ssl);
1032709c21c4SNick Mathewson break;
1033709c21c4SNick Mathewson }
1034009f3005SNick Mathewson decrement_buckets(bev_ssl);
1035709c21c4SNick Mathewson
1036709c21c4SNick Mathewson if (r==1) {
1037e66078a0SAzat Khuzhin evutil_socket_t fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
1038709c21c4SNick Mathewson /* We're done! */
1039709c21c4SNick Mathewson bev_ssl->state = BUFFEREVENT_SSL_OPEN;
1040877280dbSAzat Khuzhin set_open_callbacks(bev_ssl, fd); /* XXXX handle failure */
1041709c21c4SNick Mathewson /* Call do_read and do_write as needed */
1042709c21c4SNick Mathewson bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
1043cb9da0bfSNick Mathewson bufferevent_run_eventcb_(&bev_ssl->bev.bev,
1044a7384c78SOndřej Kuzník BEV_EVENT_CONNECTED, 0);
1045709c21c4SNick Mathewson return 1;
1046709c21c4SNick Mathewson } else {
1047709c21c4SNick Mathewson int err = SSL_get_error(bev_ssl->ssl, r);
1048709c21c4SNick Mathewson print_err(err);
1049709c21c4SNick Mathewson switch (err) {
1050709c21c4SNick Mathewson case SSL_ERROR_WANT_WRITE:
1051709c21c4SNick Mathewson stop_reading(bev_ssl);
1052ff3f6cd4SNick Mathewson return start_writing(bev_ssl);
1053709c21c4SNick Mathewson case SSL_ERROR_WANT_READ:
105446a61869SNick Mathewson stop_writing(bev_ssl);
1055ff3f6cd4SNick Mathewson return start_reading(bev_ssl);
1056709c21c4SNick Mathewson default:
1057f7eb69acSCatalin Patulea conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
1058709c21c4SNick Mathewson return -1;
1059709c21c4SNick Mathewson }
1060709c21c4SNick Mathewson }
1061709c21c4SNick Mathewson }
1062709c21c4SNick Mathewson
1063709c21c4SNick Mathewson static void
be_openssl_handshakecb(struct bufferevent * bev_base,void * ctx)1064709c21c4SNick Mathewson be_openssl_handshakecb(struct bufferevent *bev_base, void *ctx)
1065709c21c4SNick Mathewson {
1066709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ctx;
1067ff3f6cd4SNick Mathewson do_handshake(bev_ssl);/* XXX handle failure */
1068709c21c4SNick Mathewson }
1069d5a3f1f1SNick Mathewson
1070709c21c4SNick Mathewson static void
be_openssl_handshakeeventcb(evutil_socket_t fd,short what,void * ptr)1071709c21c4SNick Mathewson be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
1072709c21c4SNick Mathewson {
1073709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = ptr;
1074709c21c4SNick Mathewson
1075cb9da0bfSNick Mathewson bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
1076709c21c4SNick Mathewson if (what & EV_TIMEOUT) {
1077a7384c78SOndřej Kuzník bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT, 0);
1078709c21c4SNick Mathewson } else
1079ff3f6cd4SNick Mathewson do_handshake(bev_ssl);/* XXX handle failure */
1080cb9da0bfSNick Mathewson bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
1081709c21c4SNick Mathewson }
1082709c21c4SNick Mathewson
1083ff3f6cd4SNick Mathewson static int
set_handshake_callbacks(struct bufferevent_openssl * bev_ssl,evutil_socket_t fd)1084709c21c4SNick Mathewson set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
1085709c21c4SNick Mathewson {
1086709c21c4SNick Mathewson if (bev_ssl->underlying) {
1087709c21c4SNick Mathewson bufferevent_setcb(bev_ssl->underlying,
1088709c21c4SNick Mathewson be_openssl_handshakecb, be_openssl_handshakecb,
1089709c21c4SNick Mathewson be_openssl_eventcb,
1090709c21c4SNick Mathewson bev_ssl);
109189396767SAzat Khuzhin
109289396767SAzat Khuzhin if (fd < 0)
109389396767SAzat Khuzhin return 0;
109489396767SAzat Khuzhin
109589396767SAzat Khuzhin if (bufferevent_setfd(bev_ssl->underlying, fd))
109689396767SAzat Khuzhin return 1;
109789396767SAzat Khuzhin
1098ff3f6cd4SNick Mathewson return do_handshake(bev_ssl);
1099709c21c4SNick Mathewson } else {
1100709c21c4SNick Mathewson struct bufferevent *bev = &bev_ssl->bev.bev;
110140b03798SAzat Khuzhin
110240b03798SAzat Khuzhin if (event_initialized(&bev->ev_read)) {
1103709c21c4SNick Mathewson event_del(&bev->ev_read);
1104709c21c4SNick Mathewson event_del(&bev->ev_write);
1105709c21c4SNick Mathewson }
110640b03798SAzat Khuzhin
1107709c21c4SNick Mathewson event_assign(&bev->ev_read, bev->ev_base, fd,
110802fbf687SNick Mathewson EV_READ|EV_PERSIST|EV_FINALIZE,
110902fbf687SNick Mathewson be_openssl_handshakeeventcb, bev_ssl);
1110709c21c4SNick Mathewson event_assign(&bev->ev_write, bev->ev_base, fd,
111102fbf687SNick Mathewson EV_WRITE|EV_PERSIST|EV_FINALIZE,
111202fbf687SNick Mathewson be_openssl_handshakeeventcb, bev_ssl);
11130c66d321SAzat Khuzhin if (fd >= 0)
11140c66d321SAzat Khuzhin bufferevent_enable(bev, bev->enabled);
11150c66d321SAzat Khuzhin return 0;
1116709c21c4SNick Mathewson }
1117709c21c4SNick Mathewson }
1118709c21c4SNick Mathewson
1119f2282398SNick Mathewson int
bufferevent_ssl_renegotiate(struct bufferevent * bev)1120f2282398SNick Mathewson bufferevent_ssl_renegotiate(struct bufferevent *bev)
1121f2282398SNick Mathewson {
1122f2282398SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
1123f2282398SNick Mathewson if (!bev_ssl)
1124f2282398SNick Mathewson return -1;
1125f2282398SNick Mathewson if (SSL_renegotiate(bev_ssl->ssl) < 0)
1126f2282398SNick Mathewson return -1;
1127f2282398SNick Mathewson bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
11285ab9518fSAzat Khuzhin if (set_handshake_callbacks(bev_ssl, be_openssl_auto_fd(bev_ssl, -1)) < 0)
1129ff3f6cd4SNick Mathewson return -1;
1130f2282398SNick Mathewson if (!bev_ssl->underlying)
1131ff3f6cd4SNick Mathewson return do_handshake(bev_ssl);
1132f2282398SNick Mathewson return 0;
1133f2282398SNick Mathewson }
1134709c21c4SNick Mathewson
1135709c21c4SNick Mathewson static void
be_openssl_outbuf_cb(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)1136709c21c4SNick Mathewson be_openssl_outbuf_cb(struct evbuffer *buf,
1137709c21c4SNick Mathewson const struct evbuffer_cb_info *cbinfo, void *arg)
1138709c21c4SNick Mathewson {
1139709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = arg;
1140ff3f6cd4SNick Mathewson int r = 0;
1141709c21c4SNick Mathewson /* XXX need to hold a reference here. */
1142709c21c4SNick Mathewson
114389396767SAzat Khuzhin if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
114489396767SAzat Khuzhin if (cbinfo->orig_size == 0)
1145cb9da0bfSNick Mathewson r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
1146709c21c4SNick Mathewson &bev_ssl->bev.bev.timeout_write);
114789396767SAzat Khuzhin
114889396767SAzat Khuzhin if (bev_ssl->underlying)
114989396767SAzat Khuzhin consider_writing(bev_ssl);
1150709c21c4SNick Mathewson }
1151ff3f6cd4SNick Mathewson /* XXX Handle r < 0 */
115265707d7cSSebastian Hahn (void)r;
1153709c21c4SNick Mathewson }
1154709c21c4SNick Mathewson
1155709c21c4SNick Mathewson
1156709c21c4SNick Mathewson static int
be_openssl_enable(struct bufferevent * bev,short events)1157709c21c4SNick Mathewson be_openssl_enable(struct bufferevent *bev, short events)
1158709c21c4SNick Mathewson {
1159709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
1160ff3f6cd4SNick Mathewson int r1 = 0, r2 = 0;
1161709c21c4SNick Mathewson
1162709c21c4SNick Mathewson if (events & EV_READ)
1163ff3f6cd4SNick Mathewson r1 = start_reading(bev_ssl);
1164709c21c4SNick Mathewson if (events & EV_WRITE)
1165ff3f6cd4SNick Mathewson r2 = start_writing(bev_ssl);
1166709c21c4SNick Mathewson
1167709c21c4SNick Mathewson if (bev_ssl->underlying) {
1168d3288293SNick Mathewson if (events & EV_READ)
1169d3288293SNick Mathewson BEV_RESET_GENERIC_READ_TIMEOUT(bev);
1170d3288293SNick Mathewson if (events & EV_WRITE)
1171d3288293SNick Mathewson BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
1172709c21c4SNick Mathewson
1173709c21c4SNick Mathewson if (events & EV_READ)
1174709c21c4SNick Mathewson consider_reading(bev_ssl);
1175709c21c4SNick Mathewson if (events & EV_WRITE)
1176709c21c4SNick Mathewson consider_writing(bev_ssl);
1177709c21c4SNick Mathewson }
1178ff3f6cd4SNick Mathewson return (r1 < 0 || r2 < 0) ? -1 : 0;
1179709c21c4SNick Mathewson }
1180709c21c4SNick Mathewson
1181709c21c4SNick Mathewson static int
be_openssl_disable(struct bufferevent * bev,short events)1182709c21c4SNick Mathewson be_openssl_disable(struct bufferevent *bev, short events)
1183709c21c4SNick Mathewson {
1184709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
1185709c21c4SNick Mathewson
1186709c21c4SNick Mathewson if (events & EV_READ)
1187709c21c4SNick Mathewson stop_reading(bev_ssl);
1188709c21c4SNick Mathewson if (events & EV_WRITE)
1189709c21c4SNick Mathewson stop_writing(bev_ssl);
1190709c21c4SNick Mathewson
1191d3288293SNick Mathewson if (bev_ssl->underlying) {
1192d3288293SNick Mathewson if (events & EV_READ)
1193d3288293SNick Mathewson BEV_DEL_GENERIC_READ_TIMEOUT(bev);
1194d3288293SNick Mathewson if (events & EV_WRITE)
1195d3288293SNick Mathewson BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
1196d3288293SNick Mathewson }
1197709c21c4SNick Mathewson return 0;
1198709c21c4SNick Mathewson }
1199709c21c4SNick Mathewson
1200709c21c4SNick Mathewson static void
be_openssl_unlink(struct bufferevent * bev)120102fbf687SNick Mathewson be_openssl_unlink(struct bufferevent *bev)
1202709c21c4SNick Mathewson {
1203709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
1204709c21c4SNick Mathewson
1205709c21c4SNick Mathewson if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
1206709c21c4SNick Mathewson if (bev_ssl->underlying) {
1207f1bc125eSNick Mathewson if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
1208f1bc125eSNick Mathewson event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
1209f1bc125eSNick Mathewson "bufferevent with too few references");
1210f1bc125eSNick Mathewson } else {
1211709c21c4SNick Mathewson bufferevent_free(bev_ssl->underlying);
1212a800b913SNick Mathewson /* We still have a reference to it, via our
1213a800b913SNick Mathewson * BIO. So we don't drop this. */
121402fbf687SNick Mathewson // bev_ssl->underlying = NULL;
1215709c21c4SNick Mathewson }
1216f1bc125eSNick Mathewson }
1217fc7b1b00SNick Mathewson } else {
1218fc7b1b00SNick Mathewson if (bev_ssl->underlying) {
12191ac5b230SNick Mathewson if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
1220fc7b1b00SNick Mathewson bufferevent_setcb(bev_ssl->underlying,
1221fc7b1b00SNick Mathewson NULL,NULL,NULL,NULL);
12228ac3c4c2SNick Mathewson bufferevent_unsuspend_read_(bev_ssl->underlying,
1223fc7b1b00SNick Mathewson BEV_SUSPEND_FILT_READ);
1224fc7b1b00SNick Mathewson }
1225709c21c4SNick Mathewson }
1226709c21c4SNick Mathewson }
1227709c21c4SNick Mathewson
122802fbf687SNick Mathewson static void
be_openssl_destruct(struct bufferevent * bev)122902fbf687SNick Mathewson be_openssl_destruct(struct bufferevent *bev)
123002fbf687SNick Mathewson {
123102fbf687SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
123202fbf687SNick Mathewson
123302fbf687SNick Mathewson if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
123402fbf687SNick Mathewson if (! bev_ssl->underlying) {
1235e66078a0SAzat Khuzhin evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
123602fbf687SNick Mathewson BIO *bio = SSL_get_wbio(bev_ssl->ssl);
123702fbf687SNick Mathewson if (bio)
123802fbf687SNick Mathewson fd = BIO_get_fd(bio, NULL);
123902fbf687SNick Mathewson if (fd >= 0)
124002fbf687SNick Mathewson evutil_closesocket(fd);
124102fbf687SNick Mathewson }
124202fbf687SNick Mathewson SSL_free(bev_ssl->ssl);
124302fbf687SNick Mathewson }
124402fbf687SNick Mathewson }
124502fbf687SNick Mathewson
1246ff3f6cd4SNick Mathewson static int
be_openssl_adj_timeouts(struct bufferevent * bev)1247709c21c4SNick Mathewson be_openssl_adj_timeouts(struct bufferevent *bev)
1248709c21c4SNick Mathewson {
1249709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
1250709c21c4SNick Mathewson
12519dee36bcSNick Mathewson if (bev_ssl->underlying) {
1252cb9da0bfSNick Mathewson return bufferevent_generic_adj_timeouts_(bev);
12539dee36bcSNick Mathewson } else {
12543c1f58f5SAzat Khuzhin return bufferevent_generic_adj_existing_timeouts_(bev);
1255709c21c4SNick Mathewson }
1256709c21c4SNick Mathewson }
1257709c21c4SNick Mathewson
1258709c21c4SNick Mathewson static int
be_openssl_flush(struct bufferevent * bufev,short iotype,enum bufferevent_flush_mode mode)1259709c21c4SNick Mathewson be_openssl_flush(struct bufferevent *bufev,
1260709c21c4SNick Mathewson short iotype, enum bufferevent_flush_mode mode)
1261709c21c4SNick Mathewson {
1262709c21c4SNick Mathewson /* XXXX Implement this. */
1263709c21c4SNick Mathewson return 0;
1264709c21c4SNick Mathewson }
1265709c21c4SNick Mathewson
126632adf434SAzat Khuzhin static int
be_openssl_set_fd(struct bufferevent_openssl * bev_ssl,enum bufferevent_ssl_state state,evutil_socket_t fd)12675ab9518fSAzat Khuzhin be_openssl_set_fd(struct bufferevent_openssl *bev_ssl,
1268e66078a0SAzat Khuzhin enum bufferevent_ssl_state state, evutil_socket_t fd)
12695ab9518fSAzat Khuzhin {
12705ab9518fSAzat Khuzhin bev_ssl->state = state;
12715ab9518fSAzat Khuzhin
12725ab9518fSAzat Khuzhin switch (state) {
12735ab9518fSAzat Khuzhin case BUFFEREVENT_SSL_ACCEPTING:
127429b7a516SDavid Benjamin if (!SSL_clear(bev_ssl->ssl))
127529b7a516SDavid Benjamin return -1;
12765ab9518fSAzat Khuzhin SSL_set_accept_state(bev_ssl->ssl);
12775ab9518fSAzat Khuzhin if (set_handshake_callbacks(bev_ssl, fd) < 0)
12785ab9518fSAzat Khuzhin return -1;
12795ab9518fSAzat Khuzhin break;
12805ab9518fSAzat Khuzhin case BUFFEREVENT_SSL_CONNECTING:
128129b7a516SDavid Benjamin if (!SSL_clear(bev_ssl->ssl))
128229b7a516SDavid Benjamin return -1;
12835ab9518fSAzat Khuzhin SSL_set_connect_state(bev_ssl->ssl);
12845ab9518fSAzat Khuzhin if (set_handshake_callbacks(bev_ssl, fd) < 0)
12855ab9518fSAzat Khuzhin return -1;
12865ab9518fSAzat Khuzhin break;
12875ab9518fSAzat Khuzhin case BUFFEREVENT_SSL_OPEN:
12885ab9518fSAzat Khuzhin if (set_open_callbacks(bev_ssl, fd) < 0)
12895ab9518fSAzat Khuzhin return -1;
12905ab9518fSAzat Khuzhin break;
12915ab9518fSAzat Khuzhin default:
12925ab9518fSAzat Khuzhin return -1;
12935ab9518fSAzat Khuzhin }
12945ab9518fSAzat Khuzhin
12955ab9518fSAzat Khuzhin return 0;
12965ab9518fSAzat Khuzhin }
12975ab9518fSAzat Khuzhin
1298709c21c4SNick Mathewson static int
be_openssl_ctrl(struct bufferevent * bev,enum bufferevent_ctrl_op op,union bufferevent_ctrl_data * data)1299709c21c4SNick Mathewson be_openssl_ctrl(struct bufferevent *bev,
1300709c21c4SNick Mathewson enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
1301709c21c4SNick Mathewson {
1302709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bev);
1303709c21c4SNick Mathewson switch (op) {
1304709c21c4SNick Mathewson case BEV_CTRL_SET_FD:
130589396767SAzat Khuzhin if (!bev_ssl->underlying) {
1306709c21c4SNick Mathewson BIO *bio;
1307e66078a0SAzat Khuzhin bio = BIO_new_socket((int)data->fd, 0);
1308709c21c4SNick Mathewson SSL_set_bio(bev_ssl->ssl, bio, bio);
130989396767SAzat Khuzhin } else {
131089396767SAzat Khuzhin BIO *bio;
131183275459SAzat Khuzhin if (!(bio = BIO_new_bufferevent(bev_ssl->underlying)))
131289396767SAzat Khuzhin return -1;
131389396767SAzat Khuzhin SSL_set_bio(bev_ssl->ssl, bio, bio);
1314709c21c4SNick Mathewson }
13155ab9518fSAzat Khuzhin
13165ab9518fSAzat Khuzhin return be_openssl_set_fd(bev_ssl, bev_ssl->old_state, data->fd);
1317709c21c4SNick Mathewson case BEV_CTRL_GET_FD:
131889396767SAzat Khuzhin if (bev_ssl->underlying) {
131989396767SAzat Khuzhin data->fd = event_get_fd(&bev_ssl->underlying->ev_read);
132089396767SAzat Khuzhin } else {
1321709c21c4SNick Mathewson data->fd = event_get_fd(&bev->ev_read);
132289396767SAzat Khuzhin }
1323709c21c4SNick Mathewson return 0;
1324709c21c4SNick Mathewson case BEV_CTRL_GET_UNDERLYING:
1325709c21c4SNick Mathewson data->ptr = bev_ssl->underlying;
1326709c21c4SNick Mathewson return 0;
1327e6af35d7SNick Mathewson case BEV_CTRL_CANCEL_ALL:
1328709c21c4SNick Mathewson default:
1329709c21c4SNick Mathewson return -1;
1330709c21c4SNick Mathewson }
1331709c21c4SNick Mathewson }
1332709c21c4SNick Mathewson
1333eecefc50SNick Mathewson SSL *
bufferevent_openssl_get_ssl(struct bufferevent * bufev)1334eecefc50SNick Mathewson bufferevent_openssl_get_ssl(struct bufferevent *bufev)
1335eecefc50SNick Mathewson {
1336eecefc50SNick Mathewson struct bufferevent_openssl *bev_ssl = upcast(bufev);
1337eecefc50SNick Mathewson if (!bev_ssl)
1338eecefc50SNick Mathewson return NULL;
1339eecefc50SNick Mathewson return bev_ssl->ssl;
1340eecefc50SNick Mathewson }
1341eecefc50SNick Mathewson
1342709c21c4SNick Mathewson static struct bufferevent *
bufferevent_openssl_new_impl(struct event_base * base,struct bufferevent * underlying,evutil_socket_t fd,SSL * ssl,enum bufferevent_ssl_state state,int options)1343709c21c4SNick Mathewson bufferevent_openssl_new_impl(struct event_base *base,
1344709c21c4SNick Mathewson struct bufferevent *underlying,
1345709c21c4SNick Mathewson evutil_socket_t fd,
1346709c21c4SNick Mathewson SSL *ssl,
1347709c21c4SNick Mathewson enum bufferevent_ssl_state state,
1348b73ad7bcSNick Mathewson int options)
1349709c21c4SNick Mathewson {
1350709c21c4SNick Mathewson struct bufferevent_openssl *bev_ssl = NULL;
1351709c21c4SNick Mathewson struct bufferevent_private *bev_p = NULL;
1352b73ad7bcSNick Mathewson int tmp_options = options & ~BEV_OPT_THREADSAFE;
1353709c21c4SNick Mathewson
1354e86ccfe5SAzat Khuzhin /* Only one can be set. */
1355709c21c4SNick Mathewson if (underlying != NULL && fd >= 0)
1356e86ccfe5SAzat Khuzhin goto err;
1357709c21c4SNick Mathewson
1358709c21c4SNick Mathewson if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
1359709c21c4SNick Mathewson goto err;
1360709c21c4SNick Mathewson
1361709c21c4SNick Mathewson bev_p = &bev_ssl->bev;
1362709c21c4SNick Mathewson
13638ac3c4c2SNick Mathewson if (bufferevent_init_common_(bev_p, base,
1364709c21c4SNick Mathewson &bufferevent_ops_openssl, tmp_options) < 0)
1365709c21c4SNick Mathewson goto err;
1366709c21c4SNick Mathewson
1367d5a3f1f1SNick Mathewson /* Don't explode if we decide to realloc a chunk we're writing from in
1368d5a3f1f1SNick Mathewson * the output buffer. */
1369d5a3f1f1SNick Mathewson SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
1370d5a3f1f1SNick Mathewson
1371709c21c4SNick Mathewson bev_ssl->underlying = underlying;
1372709c21c4SNick Mathewson bev_ssl->ssl = ssl;
1373709c21c4SNick Mathewson
1374709c21c4SNick Mathewson bev_ssl->outbuf_cb = evbuffer_add_cb(bev_p->bev.output,
1375709c21c4SNick Mathewson be_openssl_outbuf_cb, bev_ssl);
1376709c21c4SNick Mathewson
1377709c21c4SNick Mathewson if (options & BEV_OPT_THREADSAFE)
13788ac3c4c2SNick Mathewson bufferevent_enable_locking_(&bev_ssl->bev.bev, NULL);
1379709c21c4SNick Mathewson
1380a773df54SJoachim Bauch if (underlying) {
1381cb9da0bfSNick Mathewson bufferevent_init_generic_timeout_cbs_(&bev_ssl->bev.bev);
13828ac3c4c2SNick Mathewson bufferevent_incref_(underlying);
1383a773df54SJoachim Bauch }
1384709c21c4SNick Mathewson
13855ab9518fSAzat Khuzhin bev_ssl->old_state = state;
1386595f7e38SNick Mathewson bev_ssl->last_write = -1;
1387709c21c4SNick Mathewson
1388009f3005SNick Mathewson init_bio_counts(bev_ssl);
1389009f3005SNick Mathewson
13905ab9518fSAzat Khuzhin fd = be_openssl_auto_fd(bev_ssl, fd);
13915ab9518fSAzat Khuzhin if (be_openssl_set_fd(bev_ssl, state, fd))
1392ff3f6cd4SNick Mathewson goto err;
1393709c21c4SNick Mathewson
1394ac27eb82SNick Mathewson if (underlying) {
139554f7e61bSJoachim Bauch bufferevent_setwatermark(underlying, EV_READ, 0, 0);
1396709c21c4SNick Mathewson bufferevent_enable(underlying, EV_READ|EV_WRITE);
1397223ee40fSNick Mathewson if (state == BUFFEREVENT_SSL_OPEN)
13988ac3c4c2SNick Mathewson bufferevent_suspend_read_(underlying,
1399223ee40fSNick Mathewson BEV_SUSPEND_FILT_READ);
1400709c21c4SNick Mathewson }
1401709c21c4SNick Mathewson
1402709c21c4SNick Mathewson return &bev_ssl->bev.bev;
1403709c21c4SNick Mathewson err:
1404e86ccfe5SAzat Khuzhin if (options & BEV_OPT_CLOSE_ON_FREE)
1405e86ccfe5SAzat Khuzhin SSL_free(ssl);
1406e86ccfe5SAzat Khuzhin if (bev_ssl) {
1407e86ccfe5SAzat Khuzhin bev_ssl->ssl = NULL;
1408709c21c4SNick Mathewson bufferevent_free(&bev_ssl->bev.bev);
1409e86ccfe5SAzat Khuzhin }
1410709c21c4SNick Mathewson return NULL;
1411709c21c4SNick Mathewson }
1412709c21c4SNick Mathewson
1413709c21c4SNick Mathewson struct bufferevent *
bufferevent_openssl_filter_new(struct event_base * base,struct bufferevent * underlying,SSL * ssl,enum bufferevent_ssl_state state,int options)1414709c21c4SNick Mathewson bufferevent_openssl_filter_new(struct event_base *base,
1415709c21c4SNick Mathewson struct bufferevent *underlying,
1416709c21c4SNick Mathewson SSL *ssl,
1417709c21c4SNick Mathewson enum bufferevent_ssl_state state,
1418b73ad7bcSNick Mathewson int options)
1419709c21c4SNick Mathewson {
1420709c21c4SNick Mathewson BIO *bio;
1421e86ccfe5SAzat Khuzhin struct bufferevent *bev;
1422e86ccfe5SAzat Khuzhin
1423709c21c4SNick Mathewson if (!underlying)
1424e86ccfe5SAzat Khuzhin goto err;
142583275459SAzat Khuzhin if (!(bio = BIO_new_bufferevent(underlying)))
1426e86ccfe5SAzat Khuzhin goto err;
1427709c21c4SNick Mathewson
1428709c21c4SNick Mathewson SSL_set_bio(ssl, bio, bio);
1429709c21c4SNick Mathewson
1430e86ccfe5SAzat Khuzhin bev = bufferevent_openssl_new_impl(
1431709c21c4SNick Mathewson base, underlying, -1, ssl, state, options);
1432e86ccfe5SAzat Khuzhin return bev;
1433e86ccfe5SAzat Khuzhin
1434e86ccfe5SAzat Khuzhin err:
1435e86ccfe5SAzat Khuzhin if (options & BEV_OPT_CLOSE_ON_FREE)
1436e86ccfe5SAzat Khuzhin SSL_free(ssl);
1437e86ccfe5SAzat Khuzhin return NULL;
1438709c21c4SNick Mathewson }
1439709c21c4SNick Mathewson
1440709c21c4SNick Mathewson struct bufferevent *
bufferevent_openssl_socket_new(struct event_base * base,evutil_socket_t fd,SSL * ssl,enum bufferevent_ssl_state state,int options)1441709c21c4SNick Mathewson bufferevent_openssl_socket_new(struct event_base *base,
1442709c21c4SNick Mathewson evutil_socket_t fd,
1443709c21c4SNick Mathewson SSL *ssl,
1444709c21c4SNick Mathewson enum bufferevent_ssl_state state,
1445b73ad7bcSNick Mathewson int options)
1446709c21c4SNick Mathewson {
1447709c21c4SNick Mathewson /* Does the SSL already have an fd? */
1448709c21c4SNick Mathewson BIO *bio = SSL_get_wbio(ssl);
1449709c21c4SNick Mathewson long have_fd = -1;
145093bb7d8eSNick Mathewson
1451709c21c4SNick Mathewson if (bio)
1452709c21c4SNick Mathewson have_fd = BIO_get_fd(bio, NULL);
1453709c21c4SNick Mathewson
1454709c21c4SNick Mathewson if (have_fd >= 0) {
1455709c21c4SNick Mathewson /* The SSL is already configured with an fd. */
1456709c21c4SNick Mathewson if (fd < 0) {
1457709c21c4SNick Mathewson /* We should learn the fd from the SSL. */
1458709c21c4SNick Mathewson fd = (evutil_socket_t) have_fd;
1459709c21c4SNick Mathewson } else if (have_fd == (long)fd) {
1460709c21c4SNick Mathewson /* We already know the fd from the SSL; do nothing */
1461709c21c4SNick Mathewson } else {
1462709c21c4SNick Mathewson /* We specified an fd different from that of the SSL.
1463709c21c4SNick Mathewson This is probably an error on our part. Fail. */
1464e86ccfe5SAzat Khuzhin goto err;
1465709c21c4SNick Mathewson }
1466e86ccfe5SAzat Khuzhin BIO_set_close(bio, 0);
1467709c21c4SNick Mathewson } else {
1468709c21c4SNick Mathewson /* The SSL isn't configured with a BIO with an fd. */
1469709c21c4SNick Mathewson if (fd >= 0) {
1470709c21c4SNick Mathewson /* ... and we have an fd we want to use. */
1471e66078a0SAzat Khuzhin bio = BIO_new_socket((int)fd, 0);
1472709c21c4SNick Mathewson SSL_set_bio(ssl, bio, bio);
1473709c21c4SNick Mathewson } else {
1474709c21c4SNick Mathewson /* Leave the fd unset. */
1475709c21c4SNick Mathewson }
1476709c21c4SNick Mathewson }
1477709c21c4SNick Mathewson
1478709c21c4SNick Mathewson return bufferevent_openssl_new_impl(
1479709c21c4SNick Mathewson base, NULL, fd, ssl, state, options);
1480e86ccfe5SAzat Khuzhin
1481e86ccfe5SAzat Khuzhin err:
1482e86ccfe5SAzat Khuzhin if (options & BEV_OPT_CLOSE_ON_FREE)
1483e86ccfe5SAzat Khuzhin SSL_free(ssl);
1484e86ccfe5SAzat Khuzhin return NULL;
1485709c21c4SNick Mathewson }
1486516452b7SNick Mathewson
1487f3b89decSNick Mathewson int
bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent * bev)1488f3b89decSNick Mathewson bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev)
1489099d27dfSCatalin Patulea {
1490f3b89decSNick Mathewson int allow_dirty_shutdown = -1;
1491099d27dfSCatalin Patulea struct bufferevent_openssl *bev_ssl;
1492099d27dfSCatalin Patulea BEV_LOCK(bev);
1493099d27dfSCatalin Patulea bev_ssl = upcast(bev);
1494f3b89decSNick Mathewson if (bev_ssl)
1495099d27dfSCatalin Patulea allow_dirty_shutdown = bev_ssl->allow_dirty_shutdown;
1496099d27dfSCatalin Patulea BEV_UNLOCK(bev);
1497099d27dfSCatalin Patulea return allow_dirty_shutdown;
1498099d27dfSCatalin Patulea }
1499099d27dfSCatalin Patulea
1500f3b89decSNick Mathewson void
bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent * bev,int allow_dirty_shutdown)1501f3b89decSNick Mathewson bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
1502099d27dfSCatalin Patulea int allow_dirty_shutdown)
1503099d27dfSCatalin Patulea {
1504099d27dfSCatalin Patulea struct bufferevent_openssl *bev_ssl;
1505099d27dfSCatalin Patulea BEV_LOCK(bev);
1506099d27dfSCatalin Patulea bev_ssl = upcast(bev);
1507f3b89decSNick Mathewson if (bev_ssl)
1508f3b89decSNick Mathewson bev_ssl->allow_dirty_shutdown = !!allow_dirty_shutdown;
1509099d27dfSCatalin Patulea BEV_UNLOCK(bev);
1510099d27dfSCatalin Patulea }
1511099d27dfSCatalin Patulea
1512516452b7SNick Mathewson unsigned long
bufferevent_get_openssl_error(struct bufferevent * bev)1513516452b7SNick Mathewson bufferevent_get_openssl_error(struct bufferevent *bev)
1514516452b7SNick Mathewson {
1515516452b7SNick Mathewson unsigned long err = 0;
1516516452b7SNick Mathewson struct bufferevent_openssl *bev_ssl;
1517516452b7SNick Mathewson BEV_LOCK(bev);
1518516452b7SNick Mathewson bev_ssl = upcast(bev);
1519516452b7SNick Mathewson if (bev_ssl && bev_ssl->n_errors) {
1520516452b7SNick Mathewson err = bev_ssl->errors[--bev_ssl->n_errors];
1521516452b7SNick Mathewson }
1522516452b7SNick Mathewson BEV_UNLOCK(bev);
1523516452b7SNick Mathewson return err;
1524516452b7SNick Mathewson }
1525