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