1290001Sglebius/*
2290001Sglebius * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
3290001Sglebius *
4290001Sglebius * Redistribution and use in source and binary forms, with or without
5290001Sglebius * modification, are permitted provided that the following conditions
6290001Sglebius * are met:
7290001Sglebius * 1. Redistributions of source code must retain the above copyright
8290001Sglebius *    notice, this list of conditions and the following disclaimer.
9290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
10290001Sglebius *    notice, this list of conditions and the following disclaimer in the
11290001Sglebius *    documentation and/or other materials provided with the distribution.
12290001Sglebius * 3. The name of the author may not be used to endorse or promote products
13290001Sglebius *    derived from this software without specific prior written permission.
14290001Sglebius *
15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25290001Sglebius */
26290001Sglebius
27290001Sglebius// Get rid of OSX 10.7 and greater deprecation warnings.
28290001Sglebius#if defined(__APPLE__) && defined(__clang__)
29290001Sglebius#pragma clang diagnostic ignored "-Wdeprecated-declarations"
30290001Sglebius#endif
31290001Sglebius
32290001Sglebius#include "event2/event-config.h"
33290001Sglebius#include "evconfig-private.h"
34290001Sglebius
35290001Sglebius#include <sys/types.h>
36290001Sglebius
37290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H
38290001Sglebius#include <sys/time.h>
39290001Sglebius#endif
40290001Sglebius
41290001Sglebius#include <errno.h>
42290001Sglebius#include <stdio.h>
43290001Sglebius#include <stdlib.h>
44290001Sglebius#include <string.h>
45290001Sglebius#ifdef EVENT__HAVE_STDARG_H
46290001Sglebius#include <stdarg.h>
47290001Sglebius#endif
48290001Sglebius#ifdef EVENT__HAVE_UNISTD_H
49290001Sglebius#include <unistd.h>
50290001Sglebius#endif
51290001Sglebius
52290001Sglebius#ifdef _WIN32
53290001Sglebius#include <winsock2.h>
54290001Sglebius#endif
55290001Sglebius
56290001Sglebius#include "event2/bufferevent.h"
57290001Sglebius#include "event2/bufferevent_struct.h"
58290001Sglebius#include "event2/bufferevent_ssl.h"
59290001Sglebius#include "event2/buffer.h"
60290001Sglebius#include "event2/event.h"
61290001Sglebius
62290001Sglebius#include "mm-internal.h"
63290001Sglebius#include "bufferevent-internal.h"
64290001Sglebius#include "log-internal.h"
65290001Sglebius
66290001Sglebius#include <openssl/bio.h>
67290001Sglebius#include <openssl/ssl.h>
68290001Sglebius#include <openssl/err.h>
69290001Sglebius
70290001Sglebius/*
71290001Sglebius * Define an OpenSSL bio that targets a bufferevent.
72290001Sglebius */
73290001Sglebius
74290001Sglebius/* --------------------
75290001Sglebius   A BIO is an OpenSSL abstraction that handles reading and writing data.  The
76290001Sglebius   library will happily speak SSL over anything that implements a BIO
77290001Sglebius   interface.
78290001Sglebius
79290001Sglebius   Here we define a BIO implementation that directs its output to a
80290001Sglebius   bufferevent.  We'll want to use this only when none of OpenSSL's built-in
81290001Sglebius   IO mechanisms work for us.
82290001Sglebius   -------------------- */
83290001Sglebius
84290001Sglebius/* every BIO type needs its own integer type value. */
85290001Sglebius#define BIO_TYPE_LIBEVENT 57
86290001Sglebius/* ???? Arguably, we should set BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK on
87290001Sglebius * this. */
88290001Sglebius
89290001Sglebius#if 0
90290001Sglebiusstatic void
91290001Sglebiusprint_err(int val)
92290001Sglebius{
93290001Sglebius	int err;
94290001Sglebius	printf("Error was %d\n", val);
95290001Sglebius
96290001Sglebius	while ((err = ERR_get_error())) {
97290001Sglebius		const char *msg = (const char*)ERR_reason_error_string(err);
98290001Sglebius		const char *lib = (const char*)ERR_lib_error_string(err);
99290001Sglebius		const char *func = (const char*)ERR_func_error_string(err);
100290001Sglebius
101290001Sglebius		printf("%s in %s %s\n", msg, lib, func);
102290001Sglebius	}
103290001Sglebius}
104290001Sglebius#else
105290001Sglebius#define print_err(v) ((void)0)
106290001Sglebius#endif
107290001Sglebius
108290001Sglebius/* Called to initialize a new BIO */
109290001Sglebiusstatic int
110290001Sglebiusbio_bufferevent_new(BIO *b)
111290001Sglebius{
112290001Sglebius	b->init = 0;
113290001Sglebius	b->num = -1;
114290001Sglebius	b->ptr = NULL; /* We'll be putting the bufferevent in this field.*/
115290001Sglebius	b->flags = 0;
116290001Sglebius	return 1;
117290001Sglebius}
118290001Sglebius
119290001Sglebius/* Called to uninitialize the BIO. */
120290001Sglebiusstatic int
121290001Sglebiusbio_bufferevent_free(BIO *b)
122290001Sglebius{
123290001Sglebius	if (!b)
124290001Sglebius		return 0;
125290001Sglebius	if (b->shutdown) {
126290001Sglebius		if (b->init && b->ptr)
127290001Sglebius			bufferevent_free(b->ptr);
128290001Sglebius		b->init = 0;
129290001Sglebius		b->flags = 0;
130290001Sglebius		b->ptr = NULL;
131290001Sglebius	}
132290001Sglebius	return 1;
133290001Sglebius}
134290001Sglebius
135290001Sglebius/* Called to extract data from the BIO. */
136290001Sglebiusstatic int
137290001Sglebiusbio_bufferevent_read(BIO *b, char *out, int outlen)
138290001Sglebius{
139290001Sglebius	int r = 0;
140290001Sglebius	struct evbuffer *input;
141290001Sglebius
142290001Sglebius	BIO_clear_retry_flags(b);
143290001Sglebius
144290001Sglebius	if (!out)
145290001Sglebius		return 0;
146290001Sglebius	if (!b->ptr)
147290001Sglebius		return -1;
148290001Sglebius
149290001Sglebius	input = bufferevent_get_input(b->ptr);
150290001Sglebius	if (evbuffer_get_length(input) == 0) {
151290001Sglebius		/* If there's no data to read, say so. */
152290001Sglebius		BIO_set_retry_read(b);
153290001Sglebius		return -1;
154290001Sglebius	} else {
155290001Sglebius		r = evbuffer_remove(input, out, outlen);
156290001Sglebius	}
157290001Sglebius
158290001Sglebius	return r;
159290001Sglebius}
160290001Sglebius
161290001Sglebius/* Called to write data info the BIO */
162290001Sglebiusstatic int
163290001Sglebiusbio_bufferevent_write(BIO *b, const char *in, int inlen)
164290001Sglebius{
165290001Sglebius	struct bufferevent *bufev = b->ptr;
166290001Sglebius	struct evbuffer *output;
167290001Sglebius	size_t outlen;
168290001Sglebius
169290001Sglebius	BIO_clear_retry_flags(b);
170290001Sglebius
171290001Sglebius	if (!b->ptr)
172290001Sglebius		return -1;
173290001Sglebius
174290001Sglebius	output = bufferevent_get_output(bufev);
175290001Sglebius	outlen = evbuffer_get_length(output);
176290001Sglebius
177290001Sglebius	/* Copy only as much data onto the output buffer as can fit under the
178290001Sglebius	 * high-water mark. */
179290001Sglebius	if (bufev->wm_write.high && bufev->wm_write.high <= (outlen+inlen)) {
180290001Sglebius		if (bufev->wm_write.high <= outlen) {
181290001Sglebius			/* If no data can fit, we'll need to retry later. */
182290001Sglebius			BIO_set_retry_write(b);
183290001Sglebius			return -1;
184290001Sglebius		}
185290001Sglebius		inlen = bufev->wm_write.high - outlen;
186290001Sglebius	}
187290001Sglebius
188290001Sglebius	EVUTIL_ASSERT(inlen > 0);
189290001Sglebius	evbuffer_add(output, in, inlen);
190290001Sglebius	return inlen;
191290001Sglebius}
192290001Sglebius
193290001Sglebius/* Called to handle various requests */
194290001Sglebiusstatic long
195290001Sglebiusbio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
196290001Sglebius{
197290001Sglebius	struct bufferevent *bufev = b->ptr;
198290001Sglebius	long ret = 1;
199290001Sglebius
200290001Sglebius	switch (cmd) {
201290001Sglebius	case BIO_CTRL_GET_CLOSE:
202290001Sglebius		ret = b->shutdown;
203290001Sglebius		break;
204290001Sglebius	case BIO_CTRL_SET_CLOSE:
205290001Sglebius		b->shutdown = (int)num;
206290001Sglebius		break;
207290001Sglebius	case BIO_CTRL_PENDING:
208290001Sglebius		ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
209290001Sglebius		break;
210290001Sglebius	case BIO_CTRL_WPENDING:
211290001Sglebius		ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0;
212290001Sglebius		break;
213290001Sglebius	/* XXXX These two are given a special-case treatment because
214290001Sglebius	 * of cargo-cultism.  I should come up with a better reason. */
215290001Sglebius	case BIO_CTRL_DUP:
216290001Sglebius	case BIO_CTRL_FLUSH:
217290001Sglebius		ret = 1;
218290001Sglebius		break;
219290001Sglebius	default:
220290001Sglebius		ret = 0;
221290001Sglebius		break;
222290001Sglebius	}
223290001Sglebius	return ret;
224290001Sglebius}
225290001Sglebius
226290001Sglebius/* Called to write a string to the BIO */
227290001Sglebiusstatic int
228290001Sglebiusbio_bufferevent_puts(BIO *b, const char *s)
229290001Sglebius{
230290001Sglebius	return bio_bufferevent_write(b, s, strlen(s));
231290001Sglebius}
232290001Sglebius
233290001Sglebius/* Method table for the bufferevent BIO */
234290001Sglebiusstatic BIO_METHOD methods_bufferevent = {
235290001Sglebius	BIO_TYPE_LIBEVENT, "bufferevent",
236290001Sglebius	bio_bufferevent_write,
237290001Sglebius	bio_bufferevent_read,
238290001Sglebius	bio_bufferevent_puts,
239290001Sglebius	NULL /* bio_bufferevent_gets */,
240290001Sglebius	bio_bufferevent_ctrl,
241290001Sglebius	bio_bufferevent_new,
242290001Sglebius	bio_bufferevent_free,
243290001Sglebius	NULL /* callback_ctrl */,
244290001Sglebius};
245290001Sglebius
246290001Sglebius/* Return the method table for the bufferevents BIO */
247290001Sglebiusstatic BIO_METHOD *
248290001SglebiusBIO_s_bufferevent(void)
249290001Sglebius{
250290001Sglebius	return &methods_bufferevent;
251290001Sglebius}
252290001Sglebius
253290001Sglebius/* Create a new BIO to wrap communication around a bufferevent.  If close_flag
254290001Sglebius * is true, the bufferevent will be freed when the BIO is closed. */
255290001Sglebiusstatic BIO *
256290001SglebiusBIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
257290001Sglebius{
258290001Sglebius	BIO *result;
259290001Sglebius	if (!bufferevent)
260290001Sglebius		return NULL;
261290001Sglebius	if (!(result = BIO_new(BIO_s_bufferevent())))
262290001Sglebius		return NULL;
263290001Sglebius	result->init = 1;
264290001Sglebius	result->ptr = bufferevent;
265290001Sglebius	result->shutdown = close_flag ? 1 : 0;
266290001Sglebius	return result;
267290001Sglebius}
268290001Sglebius
269290001Sglebius/* --------------------
270290001Sglebius   Now, here's the OpenSSL-based implementation of bufferevent.
271290001Sglebius
272290001Sglebius   The implementation comes in two flavors: one that connects its SSL object
273290001Sglebius   to an underlying bufferevent using a BIO_bufferevent, and one that has the
274290001Sglebius   SSL object connect to a socket directly.  The latter should generally be
275290001Sglebius   faster, except on Windows, where your best bet is using a
276290001Sglebius   bufferevent_async.
277290001Sglebius
278290001Sglebius   (OpenSSL supports many other BIO types, too.  But we can't use any unless
279290001Sglebius   we have a good way to get notified when they become readable/writable.)
280290001Sglebius   -------------------- */
281290001Sglebius
282290001Sglebiusstruct bio_data_counts {
283290001Sglebius	unsigned long n_written;
284290001Sglebius	unsigned long n_read;
285290001Sglebius};
286290001Sglebius
287290001Sglebiusstruct bufferevent_openssl {
288290001Sglebius	/* Shared fields with common bufferevent implementation code.
289290001Sglebius	   If we were set up with an underlying bufferevent, we use the
290290001Sglebius	   events here as timers only.  If we have an SSL, then we use
291290001Sglebius	   the events as socket events.
292290001Sglebius	 */
293290001Sglebius	struct bufferevent_private bev;
294290001Sglebius	/* An underlying bufferevent that we're directing our output to.
295290001Sglebius	   If it's NULL, then we're connected to an fd, not an evbuffer. */
296290001Sglebius	struct bufferevent *underlying;
297290001Sglebius	/* The SSL object doing our encryption. */
298290001Sglebius	SSL *ssl;
299290001Sglebius
300290001Sglebius	/* A callback that's invoked when data arrives on our outbuf so we
301290001Sglebius	   know to write data to the SSL. */
302290001Sglebius	struct evbuffer_cb_entry *outbuf_cb;
303290001Sglebius
304290001Sglebius	/* A count of how much data the bios have read/written total.  Used
305290001Sglebius	   for rate-limiting. */
306290001Sglebius	struct bio_data_counts counts;
307290001Sglebius
308290001Sglebius	/* If this value is greater than 0, then the last SSL_write blocked,
309290001Sglebius	 * and we need to try it again with this many bytes. */
310290001Sglebius	ev_ssize_t last_write;
311290001Sglebius
312290001Sglebius#define NUM_ERRORS 3
313290001Sglebius	ev_uint32_t errors[NUM_ERRORS];
314290001Sglebius
315290001Sglebius	/* When we next get available space, we should say "read" instead of
316290001Sglebius	   "write". This can happen if there's a renegotiation during a read
317290001Sglebius	   operation. */
318290001Sglebius	unsigned read_blocked_on_write : 1;
319290001Sglebius	/* When we next get data, we should say "write" instead of "read". */
320290001Sglebius	unsigned write_blocked_on_read : 1;
321290001Sglebius	/* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
322290001Sglebius	unsigned allow_dirty_shutdown : 1;
323290001Sglebius	/* XXXX */
324290001Sglebius	unsigned fd_is_set : 1;
325290001Sglebius	/* XXX */
326290001Sglebius	unsigned n_errors : 2;
327290001Sglebius
328290001Sglebius	/* Are we currently connecting, accepting, or doing IO? */
329290001Sglebius	unsigned state : 2;
330290001Sglebius};
331290001Sglebius
332290001Sglebiusstatic int be_openssl_enable(struct bufferevent *, short);
333290001Sglebiusstatic int be_openssl_disable(struct bufferevent *, short);
334290001Sglebiusstatic void be_openssl_unlink(struct bufferevent *);
335290001Sglebiusstatic void be_openssl_destruct(struct bufferevent *);
336290001Sglebiusstatic int be_openssl_adj_timeouts(struct bufferevent *);
337290001Sglebiusstatic int be_openssl_flush(struct bufferevent *bufev,
338290001Sglebius    short iotype, enum bufferevent_flush_mode mode);
339290001Sglebiusstatic int be_openssl_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
340290001Sglebius
341290001Sglebiusconst struct bufferevent_ops bufferevent_ops_openssl = {
342290001Sglebius	"ssl",
343290001Sglebius	evutil_offsetof(struct bufferevent_openssl, bev.bev),
344290001Sglebius	be_openssl_enable,
345290001Sglebius	be_openssl_disable,
346290001Sglebius	be_openssl_unlink,
347290001Sglebius	be_openssl_destruct,
348290001Sglebius	be_openssl_adj_timeouts,
349290001Sglebius	be_openssl_flush,
350290001Sglebius	be_openssl_ctrl,
351290001Sglebius};
352290001Sglebius
353290001Sglebius/* Given a bufferevent, return a pointer to the bufferevent_openssl that
354290001Sglebius * contains it, if any. */
355290001Sglebiusstatic inline struct bufferevent_openssl *
356290001Sglebiusupcast(struct bufferevent *bev)
357290001Sglebius{
358290001Sglebius	struct bufferevent_openssl *bev_o;
359290001Sglebius	if (bev->be_ops != &bufferevent_ops_openssl)
360290001Sglebius		return NULL;
361290001Sglebius	bev_o = (void*)( ((char*)bev) -
362290001Sglebius			 evutil_offsetof(struct bufferevent_openssl, bev.bev));
363290001Sglebius	EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
364290001Sglebius	return bev_o;
365290001Sglebius}
366290001Sglebius
367290001Sglebiusstatic inline void
368290001Sglebiusput_error(struct bufferevent_openssl *bev_ssl, unsigned long err)
369290001Sglebius{
370290001Sglebius	if (bev_ssl->n_errors == NUM_ERRORS)
371290001Sglebius		return;
372290001Sglebius	/* The error type according to openssl is "unsigned long", but
373290001Sglebius	   openssl never uses more than 32 bits of it.  It _can't_ use more
374290001Sglebius	   than 32 bits of it, since it needs to report errors on systems
375290001Sglebius	   where long is only 32 bits.
376290001Sglebius	 */
377290001Sglebius	bev_ssl->errors[bev_ssl->n_errors++] = (ev_uint32_t) err;
378290001Sglebius}
379290001Sglebius
380290001Sglebius/* Have the base communications channel (either the underlying bufferevent or
381290001Sglebius * ev_read and ev_write) start reading.  Take the read-blocked-on-write flag
382290001Sglebius * into account. */
383290001Sglebiusstatic int
384290001Sglebiusstart_reading(struct bufferevent_openssl *bev_ssl)
385290001Sglebius{
386290001Sglebius	if (bev_ssl->underlying) {
387290001Sglebius		bufferevent_unsuspend_read_(bev_ssl->underlying,
388290001Sglebius		    BEV_SUSPEND_FILT_READ);
389290001Sglebius		return 0;
390290001Sglebius	} else {
391290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
392290001Sglebius		int r;
393290001Sglebius		r = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
394290001Sglebius		if (r == 0 && bev_ssl->read_blocked_on_write)
395290001Sglebius			r = bufferevent_add_event_(&bev->ev_write,
396290001Sglebius			    &bev->timeout_write);
397290001Sglebius		return r;
398290001Sglebius	}
399290001Sglebius}
400290001Sglebius
401290001Sglebius/* Have the base communications channel (either the underlying bufferevent or
402290001Sglebius * ev_read and ev_write) start writing.  Take the write-blocked-on-read flag
403290001Sglebius * into account. */
404290001Sglebiusstatic int
405290001Sglebiusstart_writing(struct bufferevent_openssl *bev_ssl)
406290001Sglebius{
407290001Sglebius	int r = 0;
408290001Sglebius	if (bev_ssl->underlying) {
409290001Sglebius		;
410290001Sglebius	} else {
411290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
412290001Sglebius		r = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
413290001Sglebius		if (!r && bev_ssl->write_blocked_on_read)
414290001Sglebius			r = bufferevent_add_event_(&bev->ev_read,
415290001Sglebius			    &bev->timeout_read);
416290001Sglebius	}
417290001Sglebius	return r;
418290001Sglebius}
419290001Sglebius
420290001Sglebiusstatic void
421290001Sglebiusstop_reading(struct bufferevent_openssl *bev_ssl)
422290001Sglebius{
423290001Sglebius	if (bev_ssl->write_blocked_on_read)
424290001Sglebius		return;
425290001Sglebius	if (bev_ssl->underlying) {
426290001Sglebius		bufferevent_suspend_read_(bev_ssl->underlying,
427290001Sglebius		    BEV_SUSPEND_FILT_READ);
428290001Sglebius	} else {
429290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
430290001Sglebius		event_del(&bev->ev_read);
431290001Sglebius	}
432290001Sglebius}
433290001Sglebius
434290001Sglebiusstatic void
435290001Sglebiusstop_writing(struct bufferevent_openssl *bev_ssl)
436290001Sglebius{
437290001Sglebius	if (bev_ssl->read_blocked_on_write)
438290001Sglebius		return;
439290001Sglebius	if (bev_ssl->underlying) {
440290001Sglebius		;
441290001Sglebius	} else {
442290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
443290001Sglebius		event_del(&bev->ev_write);
444290001Sglebius	}
445290001Sglebius}
446290001Sglebius
447290001Sglebiusstatic int
448290001Sglebiusset_rbow(struct bufferevent_openssl *bev_ssl)
449290001Sglebius{
450290001Sglebius	if (!bev_ssl->underlying)
451290001Sglebius		stop_reading(bev_ssl);
452290001Sglebius	bev_ssl->read_blocked_on_write = 1;
453290001Sglebius	return start_writing(bev_ssl);
454290001Sglebius}
455290001Sglebius
456290001Sglebiusstatic int
457290001Sglebiusset_wbor(struct bufferevent_openssl *bev_ssl)
458290001Sglebius{
459290001Sglebius	if (!bev_ssl->underlying)
460290001Sglebius		stop_writing(bev_ssl);
461290001Sglebius	bev_ssl->write_blocked_on_read = 1;
462290001Sglebius	return start_reading(bev_ssl);
463290001Sglebius}
464290001Sglebius
465290001Sglebiusstatic int
466290001Sglebiusclear_rbow(struct bufferevent_openssl *bev_ssl)
467290001Sglebius{
468290001Sglebius	struct bufferevent *bev = &bev_ssl->bev.bev;
469290001Sglebius	int r = 0;
470290001Sglebius	bev_ssl->read_blocked_on_write = 0;
471290001Sglebius	if (!(bev->enabled & EV_WRITE))
472290001Sglebius		stop_writing(bev_ssl);
473290001Sglebius	if (bev->enabled & EV_READ)
474290001Sglebius		r = start_reading(bev_ssl);
475290001Sglebius	return r;
476290001Sglebius}
477290001Sglebius
478290001Sglebius
479290001Sglebiusstatic int
480290001Sglebiusclear_wbor(struct bufferevent_openssl *bev_ssl)
481290001Sglebius{
482290001Sglebius	struct bufferevent *bev = &bev_ssl->bev.bev;
483290001Sglebius	int r = 0;
484290001Sglebius	bev_ssl->write_blocked_on_read = 0;
485290001Sglebius	if (!(bev->enabled & EV_READ))
486290001Sglebius		stop_reading(bev_ssl);
487290001Sglebius	if (bev->enabled & EV_WRITE)
488290001Sglebius		r = start_writing(bev_ssl);
489290001Sglebius	return r;
490290001Sglebius}
491290001Sglebius
492290001Sglebiusstatic void
493290001Sglebiusconn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
494290001Sglebius{
495290001Sglebius	int event = BEV_EVENT_ERROR;
496290001Sglebius	int dirty_shutdown = 0;
497290001Sglebius	unsigned long err;
498290001Sglebius
499290001Sglebius	switch (errcode) {
500290001Sglebius	case SSL_ERROR_ZERO_RETURN:
501290001Sglebius		/* Possibly a clean shutdown. */
502290001Sglebius		if (SSL_get_shutdown(bev_ssl->ssl) & SSL_RECEIVED_SHUTDOWN)
503290001Sglebius			event = BEV_EVENT_EOF;
504290001Sglebius		else
505290001Sglebius			dirty_shutdown = 1;
506290001Sglebius		break;
507290001Sglebius	case SSL_ERROR_SYSCALL:
508290001Sglebius		/* IO error; possibly a dirty shutdown. */
509290001Sglebius		if (ret == 0 && ERR_peek_error() == 0)
510290001Sglebius			dirty_shutdown = 1;
511290001Sglebius		break;
512290001Sglebius	case SSL_ERROR_SSL:
513290001Sglebius		/* Protocol error. */
514290001Sglebius		break;
515290001Sglebius	case SSL_ERROR_WANT_X509_LOOKUP:
516290001Sglebius		/* XXXX handle this. */
517290001Sglebius		break;
518290001Sglebius	case SSL_ERROR_NONE:
519290001Sglebius	case SSL_ERROR_WANT_READ:
520290001Sglebius	case SSL_ERROR_WANT_WRITE:
521290001Sglebius	case SSL_ERROR_WANT_CONNECT:
522290001Sglebius	case SSL_ERROR_WANT_ACCEPT:
523290001Sglebius	default:
524290001Sglebius		/* should be impossible; treat as normal error. */
525290001Sglebius		event_warnx("BUG: Unexpected OpenSSL error code %d", errcode);
526290001Sglebius		break;
527290001Sglebius	}
528290001Sglebius
529290001Sglebius	while ((err = ERR_get_error())) {
530290001Sglebius		put_error(bev_ssl, err);
531290001Sglebius	}
532290001Sglebius
533290001Sglebius	if (dirty_shutdown && bev_ssl->allow_dirty_shutdown)
534290001Sglebius		event = BEV_EVENT_EOF;
535290001Sglebius
536290001Sglebius	stop_reading(bev_ssl);
537290001Sglebius	stop_writing(bev_ssl);
538290001Sglebius
539290001Sglebius	/* when is BEV_EVENT_{READING|WRITING} */
540290001Sglebius	event = when | event;
541290001Sglebius	bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
542290001Sglebius}
543290001Sglebius
544290001Sglebiusstatic void
545290001Sglebiusinit_bio_counts(struct bufferevent_openssl *bev_ssl)
546290001Sglebius{
547290001Sglebius	bev_ssl->counts.n_written =
548290001Sglebius	    BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
549290001Sglebius	bev_ssl->counts.n_read =
550290001Sglebius	    BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
551290001Sglebius}
552290001Sglebius
553290001Sglebiusstatic inline void
554290001Sglebiusdecrement_buckets(struct bufferevent_openssl *bev_ssl)
555290001Sglebius{
556290001Sglebius	unsigned long num_w = BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
557290001Sglebius	unsigned long num_r = BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
558290001Sglebius	/* These next two subtractions can wrap around. That's okay. */
559290001Sglebius	unsigned long w = num_w - bev_ssl->counts.n_written;
560290001Sglebius	unsigned long r = num_r - bev_ssl->counts.n_read;
561290001Sglebius	if (w)
562290001Sglebius		bufferevent_decrement_write_buckets_(&bev_ssl->bev, w);
563290001Sglebius	if (r)
564290001Sglebius		bufferevent_decrement_read_buckets_(&bev_ssl->bev, r);
565290001Sglebius	bev_ssl->counts.n_written = num_w;
566290001Sglebius	bev_ssl->counts.n_read = num_r;
567290001Sglebius}
568290001Sglebius
569290001Sglebius#define OP_MADE_PROGRESS 1
570290001Sglebius#define OP_BLOCKED 2
571290001Sglebius#define OP_ERR 4
572290001Sglebius
573290001Sglebius/* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
574290001Sglebius   we're now blocked); and OP_ERR (if an error occurred). */
575290001Sglebiusstatic int
576290001Sglebiusdo_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
577290001Sglebius	/* Requires lock */
578290001Sglebius	struct bufferevent *bev = &bev_ssl->bev.bev;
579290001Sglebius	struct evbuffer *input = bev->input;
580290001Sglebius	int r, n, i, n_used = 0, atmost;
581290001Sglebius	struct evbuffer_iovec space[2];
582290001Sglebius	int result = 0;
583290001Sglebius
584290001Sglebius	if (bev_ssl->bev.read_suspended)
585290001Sglebius		return 0;
586290001Sglebius
587290001Sglebius	atmost = bufferevent_get_read_max_(&bev_ssl->bev);
588290001Sglebius	if (n_to_read > atmost)
589290001Sglebius		n_to_read = atmost;
590290001Sglebius
591290001Sglebius	n = evbuffer_reserve_space(input, n_to_read, space, 2);
592290001Sglebius	if (n < 0)
593290001Sglebius		return OP_ERR;
594290001Sglebius
595290001Sglebius	for (i=0; i<n; ++i) {
596290001Sglebius		if (bev_ssl->bev.read_suspended)
597290001Sglebius			break;
598290001Sglebius		r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
599290001Sglebius		if (r>0) {
600290001Sglebius			result |= OP_MADE_PROGRESS;
601290001Sglebius			if (bev_ssl->read_blocked_on_write)
602290001Sglebius				if (clear_rbow(bev_ssl) < 0)
603290001Sglebius					return OP_ERR | result;
604290001Sglebius			++n_used;
605290001Sglebius			space[i].iov_len = r;
606290001Sglebius			decrement_buckets(bev_ssl);
607290001Sglebius		} else {
608290001Sglebius			int err = SSL_get_error(bev_ssl->ssl, r);
609290001Sglebius			print_err(err);
610290001Sglebius			switch (err) {
611290001Sglebius			case SSL_ERROR_WANT_READ:
612290001Sglebius				/* Can't read until underlying has more data. */
613290001Sglebius				if (bev_ssl->read_blocked_on_write)
614290001Sglebius					if (clear_rbow(bev_ssl) < 0)
615290001Sglebius						return OP_ERR | result;
616290001Sglebius				break;
617290001Sglebius			case SSL_ERROR_WANT_WRITE:
618290001Sglebius				/* This read operation requires a write, and the
619290001Sglebius				 * underlying is full */
620290001Sglebius				if (!bev_ssl->read_blocked_on_write)
621290001Sglebius					if (set_rbow(bev_ssl) < 0)
622290001Sglebius						return OP_ERR | result;
623290001Sglebius				break;
624290001Sglebius			default:
625290001Sglebius				conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
626290001Sglebius				break;
627290001Sglebius			}
628290001Sglebius			result |= OP_BLOCKED;
629290001Sglebius			break; /* out of the loop */
630290001Sglebius		}
631290001Sglebius	}
632290001Sglebius
633290001Sglebius	if (n_used) {
634290001Sglebius		evbuffer_commit_space(input, space, n_used);
635290001Sglebius		if (bev_ssl->underlying)
636290001Sglebius			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
637290001Sglebius	}
638290001Sglebius
639290001Sglebius	return result;
640290001Sglebius}
641290001Sglebius
642290001Sglebius/* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
643290001Sglebius   we're now blocked); and OP_ERR (if an error occurred). */
644290001Sglebiusstatic int
645290001Sglebiusdo_write(struct bufferevent_openssl *bev_ssl, int atmost)
646290001Sglebius{
647290001Sglebius	int i, r, n, n_written = 0;
648290001Sglebius	struct bufferevent *bev = &bev_ssl->bev.bev;
649290001Sglebius	struct evbuffer *output = bev->output;
650290001Sglebius	struct evbuffer_iovec space[8];
651290001Sglebius	int result = 0;
652290001Sglebius
653290001Sglebius	if (bev_ssl->last_write > 0)
654290001Sglebius		atmost = bev_ssl->last_write;
655290001Sglebius	else
656290001Sglebius		atmost = bufferevent_get_write_max_(&bev_ssl->bev);
657290001Sglebius
658290001Sglebius	n = evbuffer_peek(output, atmost, NULL, space, 8);
659290001Sglebius	if (n < 0)
660290001Sglebius		return OP_ERR | result;
661290001Sglebius
662290001Sglebius	if (n > 8)
663290001Sglebius		n = 8;
664290001Sglebius	for (i=0; i < n; ++i) {
665290001Sglebius		if (bev_ssl->bev.write_suspended)
666290001Sglebius			break;
667290001Sglebius
668290001Sglebius		/* SSL_write will (reasonably) return 0 if we tell it to
669290001Sglebius		   send 0 data.  Skip this case so we don't interpret the
670290001Sglebius		   result as an error */
671290001Sglebius		if (space[i].iov_len == 0)
672290001Sglebius			continue;
673290001Sglebius
674290001Sglebius		r = SSL_write(bev_ssl->ssl, space[i].iov_base,
675290001Sglebius		    space[i].iov_len);
676290001Sglebius		if (r > 0) {
677290001Sglebius			result |= OP_MADE_PROGRESS;
678290001Sglebius			if (bev_ssl->write_blocked_on_read)
679290001Sglebius				if (clear_wbor(bev_ssl) < 0)
680290001Sglebius					return OP_ERR | result;
681290001Sglebius			n_written += r;
682290001Sglebius			bev_ssl->last_write = -1;
683290001Sglebius			decrement_buckets(bev_ssl);
684290001Sglebius		} else {
685290001Sglebius			int err = SSL_get_error(bev_ssl->ssl, r);
686290001Sglebius			print_err(err);
687290001Sglebius			switch (err) {
688290001Sglebius			case SSL_ERROR_WANT_WRITE:
689290001Sglebius				/* Can't read until underlying has more data. */
690290001Sglebius				if (bev_ssl->write_blocked_on_read)
691290001Sglebius					if (clear_wbor(bev_ssl) < 0)
692290001Sglebius						return OP_ERR | result;
693290001Sglebius				bev_ssl->last_write = space[i].iov_len;
694290001Sglebius				break;
695290001Sglebius			case SSL_ERROR_WANT_READ:
696290001Sglebius				/* This read operation requires a write, and the
697290001Sglebius				 * underlying is full */
698290001Sglebius				if (!bev_ssl->write_blocked_on_read)
699290001Sglebius					if (set_wbor(bev_ssl) < 0)
700290001Sglebius						return OP_ERR | result;
701290001Sglebius				bev_ssl->last_write = space[i].iov_len;
702290001Sglebius				break;
703290001Sglebius			default:
704290001Sglebius				conn_closed(bev_ssl, BEV_EVENT_WRITING, err, r);
705290001Sglebius				bev_ssl->last_write = -1;
706290001Sglebius				break;
707290001Sglebius			}
708290001Sglebius			result |= OP_BLOCKED;
709290001Sglebius			break;
710290001Sglebius		}
711290001Sglebius	}
712290001Sglebius	if (n_written) {
713290001Sglebius		evbuffer_drain(output, n_written);
714290001Sglebius		if (bev_ssl->underlying)
715290001Sglebius			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
716290001Sglebius
717290001Sglebius		bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
718290001Sglebius	}
719290001Sglebius	return result;
720290001Sglebius}
721290001Sglebius
722290001Sglebius#define WRITE_FRAME 15000
723290001Sglebius
724290001Sglebius#define READ_DEFAULT 4096
725290001Sglebius
726290001Sglebius/* Try to figure out how many bytes to read; return 0 if we shouldn't be
727290001Sglebius * reading. */
728290001Sglebiusstatic int
729290001Sglebiusbytes_to_read(struct bufferevent_openssl *bev)
730290001Sglebius{
731290001Sglebius	struct evbuffer *input = bev->bev.bev.input;
732290001Sglebius	struct event_watermark *wm = &bev->bev.bev.wm_read;
733290001Sglebius	int result = READ_DEFAULT;
734290001Sglebius	ev_ssize_t limit;
735290001Sglebius	/* XXX 99% of this is generic code that nearly all bufferevents will
736290001Sglebius	 * want. */
737290001Sglebius
738290001Sglebius	if (bev->write_blocked_on_read) {
739290001Sglebius		return 0;
740290001Sglebius	}
741290001Sglebius
742290001Sglebius	if (! (bev->bev.bev.enabled & EV_READ)) {
743290001Sglebius		return 0;
744290001Sglebius	}
745290001Sglebius
746290001Sglebius	if (bev->bev.read_suspended) {
747290001Sglebius		return 0;
748290001Sglebius	}
749290001Sglebius
750290001Sglebius	if (wm->high) {
751290001Sglebius		if (evbuffer_get_length(input) >= wm->high) {
752290001Sglebius			return 0;
753290001Sglebius		}
754290001Sglebius
755290001Sglebius		result = wm->high - evbuffer_get_length(input);
756290001Sglebius	} else {
757290001Sglebius		result = READ_DEFAULT;
758290001Sglebius	}
759290001Sglebius
760290001Sglebius	/* Respect the rate limit */
761290001Sglebius	limit = bufferevent_get_read_max_(&bev->bev);
762290001Sglebius	if (result > limit) {
763290001Sglebius		result = limit;
764290001Sglebius	}
765290001Sglebius
766290001Sglebius	return result;
767290001Sglebius}
768290001Sglebius
769290001Sglebius
770290001Sglebius/* Things look readable.  If write is blocked on read, write till it isn't.
771290001Sglebius * Read from the underlying buffer until we block or we hit our high-water
772290001Sglebius * mark.
773290001Sglebius */
774290001Sglebiusstatic void
775290001Sglebiusconsider_reading(struct bufferevent_openssl *bev_ssl)
776290001Sglebius{
777290001Sglebius	int r;
778290001Sglebius	int n_to_read;
779290001Sglebius	int all_result_flags = 0;
780290001Sglebius
781290001Sglebius	while (bev_ssl->write_blocked_on_read) {
782290001Sglebius		r = do_write(bev_ssl, WRITE_FRAME);
783290001Sglebius		if (r & (OP_BLOCKED|OP_ERR))
784290001Sglebius			break;
785290001Sglebius	}
786290001Sglebius	if (bev_ssl->write_blocked_on_read)
787290001Sglebius		return;
788290001Sglebius
789290001Sglebius	n_to_read = bytes_to_read(bev_ssl);
790290001Sglebius
791290001Sglebius	while (n_to_read) {
792290001Sglebius		r = do_read(bev_ssl, n_to_read);
793290001Sglebius		all_result_flags |= r;
794290001Sglebius
795290001Sglebius		if (r & (OP_BLOCKED|OP_ERR))
796290001Sglebius			break;
797290001Sglebius
798290001Sglebius		if (bev_ssl->bev.read_suspended)
799290001Sglebius			break;
800290001Sglebius
801290001Sglebius		/* Read all pending data.  This won't hit the network
802290001Sglebius		 * again, and will (most importantly) put us in a state
803290001Sglebius		 * where we don't need to read anything else until the
804290001Sglebius		 * socket is readable again.  It'll potentially make us
805290001Sglebius		 * overrun our read high-watermark (somewhat
806290001Sglebius		 * regrettable).  The damage to the rate-limit has
807290001Sglebius		 * already been done, since OpenSSL went and read a
808290001Sglebius		 * whole SSL record anyway. */
809290001Sglebius		n_to_read = SSL_pending(bev_ssl->ssl);
810290001Sglebius
811290001Sglebius		/* XXX This if statement is actually a bad bug, added to avoid
812290001Sglebius		 * XXX a worse bug.
813290001Sglebius		 *
814290001Sglebius		 * The bad bug: It can potentially cause resource unfairness
815290001Sglebius		 * by reading too much data from the underlying bufferevent;
816290001Sglebius		 * it can potentially cause read looping if the underlying
817290001Sglebius		 * bufferevent is a bufferevent_pair and deferred callbacks
818290001Sglebius		 * aren't used.
819290001Sglebius		 *
820290001Sglebius		 * The worse bug: If we didn't do this, then we would
821290001Sglebius		 * potentially not read any more from bev_ssl->underlying
822290001Sglebius		 * until more data arrived there, which could lead to us
823290001Sglebius		 * waiting forever.
824290001Sglebius		 */
825290001Sglebius		if (!n_to_read && bev_ssl->underlying)
826290001Sglebius			n_to_read = bytes_to_read(bev_ssl);
827290001Sglebius	}
828290001Sglebius
829290001Sglebius	if (all_result_flags & OP_MADE_PROGRESS) {
830290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
831290001Sglebius
832290001Sglebius		bufferevent_trigger_nolock_(bev, EV_READ, 0);
833290001Sglebius	}
834290001Sglebius
835290001Sglebius	if (!bev_ssl->underlying) {
836290001Sglebius		/* Should be redundant, but let's avoid busy-looping */
837290001Sglebius		if (bev_ssl->bev.read_suspended ||
838290001Sglebius		    !(bev_ssl->bev.bev.enabled & EV_READ)) {
839290001Sglebius			event_del(&bev_ssl->bev.bev.ev_read);
840290001Sglebius		}
841290001Sglebius	}
842290001Sglebius}
843290001Sglebius
844290001Sglebiusstatic void
845290001Sglebiusconsider_writing(struct bufferevent_openssl *bev_ssl)
846290001Sglebius{
847290001Sglebius	int r;
848290001Sglebius	struct evbuffer *output = bev_ssl->bev.bev.output;
849290001Sglebius	struct evbuffer *target = NULL;
850290001Sglebius	struct event_watermark *wm = NULL;
851290001Sglebius
852290001Sglebius	while (bev_ssl->read_blocked_on_write) {
853290001Sglebius		r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
854290001Sglebius		if (r & OP_MADE_PROGRESS) {
855290001Sglebius			struct bufferevent *bev = &bev_ssl->bev.bev;
856290001Sglebius
857290001Sglebius			bufferevent_trigger_nolock_(bev, EV_READ, 0);
858290001Sglebius		}
859290001Sglebius		if (r & (OP_ERR|OP_BLOCKED))
860290001Sglebius			break;
861290001Sglebius	}
862290001Sglebius	if (bev_ssl->read_blocked_on_write)
863290001Sglebius		return;
864290001Sglebius	if (bev_ssl->underlying) {
865290001Sglebius		target = bev_ssl->underlying->output;
866290001Sglebius		wm = &bev_ssl->underlying->wm_write;
867290001Sglebius	}
868290001Sglebius	while ((bev_ssl->bev.bev.enabled & EV_WRITE) &&
869290001Sglebius	    (! bev_ssl->bev.write_suspended) &&
870290001Sglebius	    evbuffer_get_length(output) &&
871290001Sglebius	    (!target || (! wm->high || evbuffer_get_length(target) < wm->high))) {
872290001Sglebius		int n_to_write;
873290001Sglebius		if (wm && wm->high)
874290001Sglebius			n_to_write = wm->high - evbuffer_get_length(target);
875290001Sglebius		else
876290001Sglebius			n_to_write = WRITE_FRAME;
877290001Sglebius		r = do_write(bev_ssl, n_to_write);
878290001Sglebius		if (r & (OP_BLOCKED|OP_ERR))
879290001Sglebius			break;
880290001Sglebius	}
881290001Sglebius
882290001Sglebius	if (!bev_ssl->underlying) {
883290001Sglebius		if (evbuffer_get_length(output) == 0) {
884290001Sglebius			event_del(&bev_ssl->bev.bev.ev_write);
885290001Sglebius		} else if (bev_ssl->bev.write_suspended ||
886290001Sglebius		    !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
887290001Sglebius			/* Should be redundant, but let's avoid busy-looping */
888290001Sglebius			event_del(&bev_ssl->bev.bev.ev_write);
889290001Sglebius		}
890290001Sglebius	}
891290001Sglebius}
892290001Sglebius
893290001Sglebiusstatic void
894290001Sglebiusbe_openssl_readcb(struct bufferevent *bev_base, void *ctx)
895290001Sglebius{
896290001Sglebius	struct bufferevent_openssl *bev_ssl = ctx;
897290001Sglebius	consider_reading(bev_ssl);
898290001Sglebius}
899290001Sglebius
900290001Sglebiusstatic void
901290001Sglebiusbe_openssl_writecb(struct bufferevent *bev_base, void *ctx)
902290001Sglebius{
903290001Sglebius	struct bufferevent_openssl *bev_ssl = ctx;
904290001Sglebius	consider_writing(bev_ssl);
905290001Sglebius}
906290001Sglebius
907290001Sglebiusstatic void
908290001Sglebiusbe_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
909290001Sglebius{
910290001Sglebius	struct bufferevent_openssl *bev_ssl = ctx;
911290001Sglebius	int event = 0;
912290001Sglebius
913290001Sglebius	if (what & BEV_EVENT_EOF) {
914290001Sglebius		if (bev_ssl->allow_dirty_shutdown)
915290001Sglebius			event = BEV_EVENT_EOF;
916290001Sglebius		else
917290001Sglebius			event = BEV_EVENT_ERROR;
918290001Sglebius	} else if (what & BEV_EVENT_TIMEOUT) {
919290001Sglebius		/* We sure didn't set this.  Propagate it to the user. */
920290001Sglebius		event = what;
921290001Sglebius	} else if (what & BEV_EVENT_ERROR) {
922290001Sglebius		/* An error occurred on the connection.  Propagate it to the user. */
923290001Sglebius		event = what;
924290001Sglebius	} else if (what & BEV_EVENT_CONNECTED) {
925290001Sglebius		/* Ignore it.  We're saying SSL_connect() already, which will
926290001Sglebius		   eat it. */
927290001Sglebius	}
928290001Sglebius	if (event)
929290001Sglebius		bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
930290001Sglebius}
931290001Sglebius
932290001Sglebiusstatic void
933290001Sglebiusbe_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
934290001Sglebius{
935290001Sglebius	struct bufferevent_openssl *bev_ssl = ptr;
936290001Sglebius	bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
937290001Sglebius	if (what == EV_TIMEOUT) {
938290001Sglebius		bufferevent_run_eventcb_(&bev_ssl->bev.bev,
939290001Sglebius		    BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
940290001Sglebius	} else {
941290001Sglebius		consider_reading(bev_ssl);
942290001Sglebius	}
943290001Sglebius	bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
944290001Sglebius}
945290001Sglebius
946290001Sglebiusstatic void
947290001Sglebiusbe_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
948290001Sglebius{
949290001Sglebius	struct bufferevent_openssl *bev_ssl = ptr;
950290001Sglebius	bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
951290001Sglebius	if (what == EV_TIMEOUT) {
952290001Sglebius		bufferevent_run_eventcb_(&bev_ssl->bev.bev,
953290001Sglebius		    BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
954290001Sglebius	} else {
955290001Sglebius		consider_writing(bev_ssl);
956290001Sglebius	}
957290001Sglebius	bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
958290001Sglebius}
959290001Sglebius
960290001Sglebiusstatic int
961290001Sglebiusset_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
962290001Sglebius{
963290001Sglebius	if (bev_ssl->underlying) {
964290001Sglebius		bufferevent_setcb(bev_ssl->underlying,
965290001Sglebius		    be_openssl_readcb, be_openssl_writecb, be_openssl_eventcb,
966290001Sglebius		    bev_ssl);
967290001Sglebius		return 0;
968290001Sglebius	} else {
969290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
970290001Sglebius		int rpending=0, wpending=0, r1=0, r2=0;
971290001Sglebius		if (fd < 0 && bev_ssl->fd_is_set)
972290001Sglebius			fd = event_get_fd(&bev->ev_read);
973290001Sglebius		if (bev_ssl->fd_is_set) {
974290001Sglebius			rpending = event_pending(&bev->ev_read, EV_READ, NULL);
975290001Sglebius			wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
976290001Sglebius			event_del(&bev->ev_read);
977290001Sglebius			event_del(&bev->ev_write);
978290001Sglebius		}
979290001Sglebius		event_assign(&bev->ev_read, bev->ev_base, fd,
980290001Sglebius		    EV_READ|EV_PERSIST|EV_FINALIZE,
981290001Sglebius		    be_openssl_readeventcb, bev_ssl);
982290001Sglebius		event_assign(&bev->ev_write, bev->ev_base, fd,
983290001Sglebius		    EV_WRITE|EV_PERSIST|EV_FINALIZE,
984290001Sglebius		    be_openssl_writeeventcb, bev_ssl);
985290001Sglebius		if (rpending)
986290001Sglebius			r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
987290001Sglebius		if (wpending)
988290001Sglebius			r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
989290001Sglebius		if (fd >= 0) {
990290001Sglebius			bev_ssl->fd_is_set = 1;
991290001Sglebius		}
992290001Sglebius		return (r1<0 || r2<0) ? -1 : 0;
993290001Sglebius	}
994290001Sglebius}
995290001Sglebius
996290001Sglebiusstatic int
997290001Sglebiusdo_handshake(struct bufferevent_openssl *bev_ssl)
998290001Sglebius{
999290001Sglebius	int r;
1000290001Sglebius
1001290001Sglebius	switch (bev_ssl->state) {
1002290001Sglebius	default:
1003290001Sglebius	case BUFFEREVENT_SSL_OPEN:
1004290001Sglebius		EVUTIL_ASSERT(0);
1005290001Sglebius		return -1;
1006290001Sglebius	case BUFFEREVENT_SSL_CONNECTING:
1007290001Sglebius	case BUFFEREVENT_SSL_ACCEPTING:
1008290001Sglebius		r = SSL_do_handshake(bev_ssl->ssl);
1009290001Sglebius		break;
1010290001Sglebius	}
1011290001Sglebius	decrement_buckets(bev_ssl);
1012290001Sglebius
1013290001Sglebius	if (r==1) {
1014290001Sglebius		/* We're done! */
1015290001Sglebius		bev_ssl->state = BUFFEREVENT_SSL_OPEN;
1016290001Sglebius		set_open_callbacks(bev_ssl, -1); /* XXXX handle failure */
1017290001Sglebius		/* Call do_read and do_write as needed */
1018290001Sglebius		bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
1019290001Sglebius		bufferevent_run_eventcb_(&bev_ssl->bev.bev,
1020290001Sglebius		    BEV_EVENT_CONNECTED, 0);
1021290001Sglebius		return 1;
1022290001Sglebius	} else {
1023290001Sglebius		int err = SSL_get_error(bev_ssl->ssl, r);
1024290001Sglebius		print_err(err);
1025290001Sglebius		switch (err) {
1026290001Sglebius		case SSL_ERROR_WANT_WRITE:
1027290001Sglebius			if (!bev_ssl->underlying) {
1028290001Sglebius				stop_reading(bev_ssl);
1029290001Sglebius				return start_writing(bev_ssl);
1030290001Sglebius			}
1031290001Sglebius			return 0;
1032290001Sglebius		case SSL_ERROR_WANT_READ:
1033290001Sglebius			if (!bev_ssl->underlying) {
1034290001Sglebius				stop_writing(bev_ssl);
1035290001Sglebius				return start_reading(bev_ssl);
1036290001Sglebius			}
1037290001Sglebius			return 0;
1038290001Sglebius		default:
1039290001Sglebius			conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
1040290001Sglebius			return -1;
1041290001Sglebius		}
1042290001Sglebius	}
1043290001Sglebius}
1044290001Sglebius
1045290001Sglebiusstatic void
1046290001Sglebiusbe_openssl_handshakecb(struct bufferevent *bev_base, void *ctx)
1047290001Sglebius{
1048290001Sglebius	struct bufferevent_openssl *bev_ssl = ctx;
1049290001Sglebius	do_handshake(bev_ssl);/* XXX handle failure */
1050290001Sglebius}
1051290001Sglebius
1052290001Sglebiusstatic void
1053290001Sglebiusbe_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
1054290001Sglebius{
1055290001Sglebius	struct bufferevent_openssl *bev_ssl = ptr;
1056290001Sglebius
1057290001Sglebius	bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
1058290001Sglebius	if (what & EV_TIMEOUT) {
1059290001Sglebius		bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT, 0);
1060290001Sglebius	} else
1061290001Sglebius		do_handshake(bev_ssl);/* XXX handle failure */
1062290001Sglebius	bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
1063290001Sglebius}
1064290001Sglebius
1065290001Sglebiusstatic int
1066290001Sglebiusset_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
1067290001Sglebius{
1068290001Sglebius	if (bev_ssl->underlying) {
1069290001Sglebius		bufferevent_setcb(bev_ssl->underlying,
1070290001Sglebius		    be_openssl_handshakecb, be_openssl_handshakecb,
1071290001Sglebius		    be_openssl_eventcb,
1072290001Sglebius		    bev_ssl);
1073290001Sglebius		return do_handshake(bev_ssl);
1074290001Sglebius	} else {
1075290001Sglebius		struct bufferevent *bev = &bev_ssl->bev.bev;
1076290001Sglebius		int r1=0, r2=0;
1077290001Sglebius		if (fd < 0 && bev_ssl->fd_is_set)
1078290001Sglebius			fd = event_get_fd(&bev->ev_read);
1079290001Sglebius		if (bev_ssl->fd_is_set) {
1080290001Sglebius			event_del(&bev->ev_read);
1081290001Sglebius			event_del(&bev->ev_write);
1082290001Sglebius		}
1083290001Sglebius		event_assign(&bev->ev_read, bev->ev_base, fd,
1084290001Sglebius		    EV_READ|EV_PERSIST|EV_FINALIZE,
1085290001Sglebius		    be_openssl_handshakeeventcb, bev_ssl);
1086290001Sglebius		event_assign(&bev->ev_write, bev->ev_base, fd,
1087290001Sglebius		    EV_WRITE|EV_PERSIST|EV_FINALIZE,
1088290001Sglebius		    be_openssl_handshakeeventcb, bev_ssl);
1089290001Sglebius		if (fd >= 0) {
1090290001Sglebius			r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
1091290001Sglebius			r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
1092290001Sglebius			bev_ssl->fd_is_set = 1;
1093290001Sglebius		}
1094290001Sglebius		return (r1<0 || r2<0) ? -1 : 0;
1095290001Sglebius	}
1096290001Sglebius}
1097290001Sglebius
1098290001Sglebiusint
1099290001Sglebiusbufferevent_ssl_renegotiate(struct bufferevent *bev)
1100290001Sglebius{
1101290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1102290001Sglebius	if (!bev_ssl)
1103290001Sglebius		return -1;
1104290001Sglebius	if (SSL_renegotiate(bev_ssl->ssl) < 0)
1105290001Sglebius		return -1;
1106290001Sglebius	bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
1107290001Sglebius	if (set_handshake_callbacks(bev_ssl, -1) < 0)
1108290001Sglebius		return -1;
1109290001Sglebius	if (!bev_ssl->underlying)
1110290001Sglebius		return do_handshake(bev_ssl);
1111290001Sglebius	return 0;
1112290001Sglebius}
1113290001Sglebius
1114290001Sglebiusstatic void
1115290001Sglebiusbe_openssl_outbuf_cb(struct evbuffer *buf,
1116290001Sglebius    const struct evbuffer_cb_info *cbinfo, void *arg)
1117290001Sglebius{
1118290001Sglebius	struct bufferevent_openssl *bev_ssl = arg;
1119290001Sglebius	int r = 0;
1120290001Sglebius	/* XXX need to hold a reference here. */
1121290001Sglebius
1122290001Sglebius	if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
1123290001Sglebius		if (cbinfo->orig_size == 0)
1124290001Sglebius			r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
1125290001Sglebius			    &bev_ssl->bev.bev.timeout_write);
1126290001Sglebius		consider_writing(bev_ssl);
1127290001Sglebius	}
1128290001Sglebius	/* XXX Handle r < 0 */
1129290001Sglebius        (void)r;
1130290001Sglebius}
1131290001Sglebius
1132290001Sglebius
1133290001Sglebiusstatic int
1134290001Sglebiusbe_openssl_enable(struct bufferevent *bev, short events)
1135290001Sglebius{
1136290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1137290001Sglebius	int r1 = 0, r2 = 0;
1138290001Sglebius
1139290001Sglebius	if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
1140290001Sglebius		return 0;
1141290001Sglebius
1142290001Sglebius	if (events & EV_READ)
1143290001Sglebius		r1 = start_reading(bev_ssl);
1144290001Sglebius	if (events & EV_WRITE)
1145290001Sglebius		r2 = start_writing(bev_ssl);
1146290001Sglebius
1147290001Sglebius	if (bev_ssl->underlying) {
1148290001Sglebius		if (events & EV_READ)
1149290001Sglebius			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
1150290001Sglebius		if (events & EV_WRITE)
1151290001Sglebius			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
1152290001Sglebius
1153290001Sglebius		if (events & EV_READ)
1154290001Sglebius			consider_reading(bev_ssl);
1155290001Sglebius		if (events & EV_WRITE)
1156290001Sglebius			consider_writing(bev_ssl);
1157290001Sglebius	}
1158290001Sglebius	return (r1 < 0 || r2 < 0) ? -1 : 0;
1159290001Sglebius}
1160290001Sglebius
1161290001Sglebiusstatic int
1162290001Sglebiusbe_openssl_disable(struct bufferevent *bev, short events)
1163290001Sglebius{
1164290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1165290001Sglebius	if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
1166290001Sglebius		return 0;
1167290001Sglebius
1168290001Sglebius	if (events & EV_READ)
1169290001Sglebius		stop_reading(bev_ssl);
1170290001Sglebius	if (events & EV_WRITE)
1171290001Sglebius		stop_writing(bev_ssl);
1172290001Sglebius
1173290001Sglebius	if (bev_ssl->underlying) {
1174290001Sglebius		if (events & EV_READ)
1175290001Sglebius			BEV_DEL_GENERIC_READ_TIMEOUT(bev);
1176290001Sglebius		if (events & EV_WRITE)
1177290001Sglebius			BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
1178290001Sglebius	}
1179290001Sglebius	return 0;
1180290001Sglebius}
1181290001Sglebius
1182290001Sglebiusstatic void
1183290001Sglebiusbe_openssl_unlink(struct bufferevent *bev)
1184290001Sglebius{
1185290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1186290001Sglebius
1187290001Sglebius	if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
1188290001Sglebius		if (bev_ssl->underlying) {
1189290001Sglebius			if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
1190290001Sglebius				event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
1191290001Sglebius				    "bufferevent with too few references");
1192290001Sglebius			} else {
1193290001Sglebius				bufferevent_free(bev_ssl->underlying);
1194290001Sglebius				/* We still have a reference to it, via our
1195290001Sglebius				 * BIO. So we don't drop this. */
1196290001Sglebius				// bev_ssl->underlying = NULL;
1197290001Sglebius			}
1198290001Sglebius		}
1199290001Sglebius	} else {
1200290001Sglebius		if (bev_ssl->underlying) {
1201290001Sglebius			if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
1202290001Sglebius				bufferevent_setcb(bev_ssl->underlying,
1203290001Sglebius				    NULL,NULL,NULL,NULL);
1204290001Sglebius			bufferevent_unsuspend_read_(bev_ssl->underlying,
1205290001Sglebius			    BEV_SUSPEND_FILT_READ);
1206290001Sglebius		}
1207290001Sglebius	}
1208290001Sglebius}
1209290001Sglebius
1210290001Sglebiusstatic void
1211290001Sglebiusbe_openssl_destruct(struct bufferevent *bev)
1212290001Sglebius{
1213290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1214290001Sglebius
1215290001Sglebius	if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
1216290001Sglebius		if (! bev_ssl->underlying) {
1217290001Sglebius			evutil_socket_t fd = -1;
1218290001Sglebius			BIO *bio = SSL_get_wbio(bev_ssl->ssl);
1219290001Sglebius			if (bio)
1220290001Sglebius				fd = BIO_get_fd(bio, NULL);
1221290001Sglebius			if (fd >= 0)
1222290001Sglebius				evutil_closesocket(fd);
1223290001Sglebius		}
1224290001Sglebius		SSL_free(bev_ssl->ssl);
1225290001Sglebius	}
1226290001Sglebius}
1227290001Sglebius
1228290001Sglebiusstatic int
1229290001Sglebiusbe_openssl_adj_timeouts(struct bufferevent *bev)
1230290001Sglebius{
1231290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1232290001Sglebius
1233290001Sglebius	if (bev_ssl->underlying) {
1234290001Sglebius		return bufferevent_generic_adj_timeouts_(bev);
1235290001Sglebius	} else {
1236290001Sglebius		int r1=0, r2=0;
1237290001Sglebius		if (event_pending(&bev->ev_read, EV_READ, NULL)) {
1238290001Sglebius			if (evutil_timerisset(&bev->timeout_read)) {
1239290001Sglebius				r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
1240290001Sglebius			} else {
1241290001Sglebius				event_remove_timer(&bev->ev_read);
1242290001Sglebius			}
1243290001Sglebius		}
1244290001Sglebius		if (event_pending(&bev->ev_write, EV_WRITE, NULL)) {
1245290001Sglebius			if (evutil_timerisset(&bev->timeout_write)) {
1246290001Sglebius				r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
1247290001Sglebius			} else {
1248290001Sglebius				event_remove_timer(&bev->ev_write);
1249290001Sglebius			}
1250290001Sglebius		}
1251290001Sglebius
1252290001Sglebius		return (r1<0 || r2<0) ? -1 : 0;
1253290001Sglebius	}
1254290001Sglebius}
1255290001Sglebius
1256290001Sglebiusstatic int
1257290001Sglebiusbe_openssl_flush(struct bufferevent *bufev,
1258290001Sglebius    short iotype, enum bufferevent_flush_mode mode)
1259290001Sglebius{
1260290001Sglebius	/* XXXX Implement this. */
1261290001Sglebius	return 0;
1262290001Sglebius}
1263290001Sglebius
1264290001Sglebiusstatic int
1265290001Sglebiusbe_openssl_ctrl(struct bufferevent *bev,
1266290001Sglebius    enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
1267290001Sglebius{
1268290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bev);
1269290001Sglebius	switch (op) {
1270290001Sglebius	case BEV_CTRL_SET_FD:
1271290001Sglebius		if (bev_ssl->underlying)
1272290001Sglebius			return -1;
1273290001Sglebius		{
1274290001Sglebius			BIO *bio;
1275290001Sglebius			bio = BIO_new_socket(data->fd, 0);
1276290001Sglebius			SSL_set_bio(bev_ssl->ssl, bio, bio);
1277290001Sglebius			bev_ssl->fd_is_set = 1;
1278290001Sglebius		}
1279290001Sglebius		if (data->fd == -1)
1280290001Sglebius			bev_ssl->fd_is_set = 0;
1281290001Sglebius		if (bev_ssl->state == BUFFEREVENT_SSL_OPEN)
1282290001Sglebius			return set_open_callbacks(bev_ssl, data->fd);
1283290001Sglebius		else {
1284290001Sglebius			return set_handshake_callbacks(bev_ssl, data->fd);
1285290001Sglebius		}
1286290001Sglebius	case BEV_CTRL_GET_FD:
1287290001Sglebius		if (bev_ssl->underlying)
1288290001Sglebius			return -1;
1289290001Sglebius		if (!bev_ssl->fd_is_set)
1290290001Sglebius			return -1;
1291290001Sglebius		data->fd = event_get_fd(&bev->ev_read);
1292290001Sglebius		return 0;
1293290001Sglebius	case BEV_CTRL_GET_UNDERLYING:
1294290001Sglebius		if (!bev_ssl->underlying)
1295290001Sglebius			return -1;
1296290001Sglebius		data->ptr = bev_ssl->underlying;
1297290001Sglebius		return 0;
1298290001Sglebius	case BEV_CTRL_CANCEL_ALL:
1299290001Sglebius	default:
1300290001Sglebius		return -1;
1301290001Sglebius	}
1302290001Sglebius}
1303290001Sglebius
1304290001SglebiusSSL *
1305290001Sglebiusbufferevent_openssl_get_ssl(struct bufferevent *bufev)
1306290001Sglebius{
1307290001Sglebius	struct bufferevent_openssl *bev_ssl = upcast(bufev);
1308290001Sglebius	if (!bev_ssl)
1309290001Sglebius		return NULL;
1310290001Sglebius	return bev_ssl->ssl;
1311290001Sglebius}
1312290001Sglebius
1313290001Sglebiusstatic struct bufferevent *
1314290001Sglebiusbufferevent_openssl_new_impl(struct event_base *base,
1315290001Sglebius    struct bufferevent *underlying,
1316290001Sglebius    evutil_socket_t fd,
1317290001Sglebius    SSL *ssl,
1318290001Sglebius    enum bufferevent_ssl_state state,
1319290001Sglebius    int options)
1320290001Sglebius{
1321290001Sglebius	struct bufferevent_openssl *bev_ssl = NULL;
1322290001Sglebius	struct bufferevent_private *bev_p = NULL;
1323290001Sglebius	int tmp_options = options & ~BEV_OPT_THREADSAFE;
1324290001Sglebius
1325290001Sglebius	if (underlying != NULL && fd >= 0)
1326290001Sglebius		return NULL; /* Only one can be set. */
1327290001Sglebius
1328290001Sglebius	if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
1329290001Sglebius		goto err;
1330290001Sglebius
1331290001Sglebius	bev_p = &bev_ssl->bev;
1332290001Sglebius
1333290001Sglebius	if (bufferevent_init_common_(bev_p, base,
1334290001Sglebius		&bufferevent_ops_openssl, tmp_options) < 0)
1335290001Sglebius		goto err;
1336290001Sglebius
1337290001Sglebius	/* Don't explode if we decide to realloc a chunk we're writing from in
1338290001Sglebius	 * the output buffer. */
1339290001Sglebius	SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
1340290001Sglebius
1341290001Sglebius	bev_ssl->underlying = underlying;
1342290001Sglebius	bev_ssl->ssl = ssl;
1343290001Sglebius
1344290001Sglebius	bev_ssl->outbuf_cb = evbuffer_add_cb(bev_p->bev.output,
1345290001Sglebius	    be_openssl_outbuf_cb, bev_ssl);
1346290001Sglebius
1347290001Sglebius	if (options & BEV_OPT_THREADSAFE)
1348290001Sglebius		bufferevent_enable_locking_(&bev_ssl->bev.bev, NULL);
1349290001Sglebius
1350290001Sglebius	if (underlying) {
1351290001Sglebius		bufferevent_init_generic_timeout_cbs_(&bev_ssl->bev.bev);
1352290001Sglebius		bufferevent_incref_(underlying);
1353290001Sglebius	}
1354290001Sglebius
1355290001Sglebius	bev_ssl->state = state;
1356290001Sglebius	bev_ssl->last_write = -1;
1357290001Sglebius
1358290001Sglebius	init_bio_counts(bev_ssl);
1359290001Sglebius
1360290001Sglebius	switch (state) {
1361290001Sglebius	case BUFFEREVENT_SSL_ACCEPTING:
1362290001Sglebius		SSL_set_accept_state(bev_ssl->ssl);
1363290001Sglebius		if (set_handshake_callbacks(bev_ssl, fd) < 0)
1364290001Sglebius			goto err;
1365290001Sglebius		break;
1366290001Sglebius	case BUFFEREVENT_SSL_CONNECTING:
1367290001Sglebius		SSL_set_connect_state(bev_ssl->ssl);
1368290001Sglebius		if (set_handshake_callbacks(bev_ssl, fd) < 0)
1369290001Sglebius			goto err;
1370290001Sglebius		break;
1371290001Sglebius	case BUFFEREVENT_SSL_OPEN:
1372290001Sglebius		if (set_open_callbacks(bev_ssl, fd) < 0)
1373290001Sglebius			goto err;
1374290001Sglebius		break;
1375290001Sglebius	default:
1376290001Sglebius		goto err;
1377290001Sglebius	}
1378290001Sglebius
1379290001Sglebius	if (underlying) {
1380290001Sglebius		bufferevent_setwatermark(underlying, EV_READ, 0, 0);
1381290001Sglebius		bufferevent_enable(underlying, EV_READ|EV_WRITE);
1382290001Sglebius		if (state == BUFFEREVENT_SSL_OPEN)
1383290001Sglebius			bufferevent_suspend_read_(underlying,
1384290001Sglebius			    BEV_SUSPEND_FILT_READ);
1385290001Sglebius	} else {
1386290001Sglebius		bev_ssl->bev.bev.enabled = EV_READ|EV_WRITE;
1387290001Sglebius		if (bev_ssl->fd_is_set) {
1388290001Sglebius			if (state != BUFFEREVENT_SSL_OPEN)
1389290001Sglebius				if (event_add(&bev_ssl->bev.bev.ev_read, NULL) < 0)
1390290001Sglebius					goto err;
1391290001Sglebius			if (event_add(&bev_ssl->bev.bev.ev_write, NULL) < 0)
1392290001Sglebius				goto err;
1393290001Sglebius		}
1394290001Sglebius	}
1395290001Sglebius
1396290001Sglebius	return &bev_ssl->bev.bev;
1397290001Sglebiuserr:
1398290001Sglebius	if (bev_ssl)
1399290001Sglebius		bufferevent_free(&bev_ssl->bev.bev);
1400290001Sglebius	return NULL;
1401290001Sglebius}
1402290001Sglebius
1403290001Sglebiusstruct bufferevent *
1404290001Sglebiusbufferevent_openssl_filter_new(struct event_base *base,
1405290001Sglebius    struct bufferevent *underlying,
1406290001Sglebius    SSL *ssl,
1407290001Sglebius    enum bufferevent_ssl_state state,
1408290001Sglebius    int options)
1409290001Sglebius{
1410290001Sglebius	/* We don't tell the BIO to close the bufferevent; we do it ourselves
1411290001Sglebius	 * on be_openssl_destruct */
1412290001Sglebius	int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
1413290001Sglebius	BIO *bio;
1414290001Sglebius	if (!underlying)
1415290001Sglebius		return NULL;
1416290001Sglebius	if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
1417290001Sglebius		return NULL;
1418290001Sglebius
1419290001Sglebius	SSL_set_bio(ssl, bio, bio);
1420290001Sglebius
1421290001Sglebius	return bufferevent_openssl_new_impl(
1422290001Sglebius		base, underlying, -1, ssl, state, options);
1423290001Sglebius}
1424290001Sglebius
1425290001Sglebiusstruct bufferevent *
1426290001Sglebiusbufferevent_openssl_socket_new(struct event_base *base,
1427290001Sglebius    evutil_socket_t fd,
1428290001Sglebius    SSL *ssl,
1429290001Sglebius    enum bufferevent_ssl_state state,
1430290001Sglebius    int options)
1431290001Sglebius{
1432290001Sglebius	/* Does the SSL already have an fd? */
1433290001Sglebius	BIO *bio = SSL_get_wbio(ssl);
1434290001Sglebius	long have_fd = -1;
1435290001Sglebius
1436290001Sglebius	if (bio)
1437290001Sglebius		have_fd = BIO_get_fd(bio, NULL);
1438290001Sglebius
1439290001Sglebius	if (have_fd >= 0) {
1440290001Sglebius		/* The SSL is already configured with an fd. */
1441290001Sglebius		if (fd < 0) {
1442290001Sglebius			/* We should learn the fd from the SSL. */
1443290001Sglebius			fd = (evutil_socket_t) have_fd;
1444290001Sglebius		} else if (have_fd == (long)fd) {
1445290001Sglebius			/* We already know the fd from the SSL; do nothing */
1446290001Sglebius		} else {
1447290001Sglebius			/* We specified an fd different from that of the SSL.
1448290001Sglebius			   This is probably an error on our part.  Fail. */
1449290001Sglebius			return NULL;
1450290001Sglebius		}
1451290001Sglebius		(void) BIO_set_close(bio, 0);
1452290001Sglebius	} else {
1453290001Sglebius		/* The SSL isn't configured with a BIO with an fd. */
1454290001Sglebius		if (fd >= 0) {
1455290001Sglebius			/* ... and we have an fd we want to use. */
1456290001Sglebius			bio = BIO_new_socket(fd, 0);
1457290001Sglebius			SSL_set_bio(ssl, bio, bio);
1458290001Sglebius		} else {
1459290001Sglebius			/* Leave the fd unset. */
1460290001Sglebius		}
1461290001Sglebius	}
1462290001Sglebius
1463290001Sglebius	return bufferevent_openssl_new_impl(
1464290001Sglebius		base, NULL, fd, ssl, state, options);
1465290001Sglebius}
1466290001Sglebius
1467290001Sglebiusint
1468290001Sglebiusbufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev)
1469290001Sglebius{
1470290001Sglebius	int allow_dirty_shutdown = -1;
1471290001Sglebius	struct bufferevent_openssl *bev_ssl;
1472290001Sglebius	BEV_LOCK(bev);
1473290001Sglebius	bev_ssl = upcast(bev);
1474290001Sglebius	if (bev_ssl)
1475290001Sglebius		allow_dirty_shutdown = bev_ssl->allow_dirty_shutdown;
1476290001Sglebius	BEV_UNLOCK(bev);
1477290001Sglebius	return allow_dirty_shutdown;
1478290001Sglebius}
1479290001Sglebius
1480290001Sglebiusvoid
1481290001Sglebiusbufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
1482290001Sglebius    int allow_dirty_shutdown)
1483290001Sglebius{
1484290001Sglebius	struct bufferevent_openssl *bev_ssl;
1485290001Sglebius	BEV_LOCK(bev);
1486290001Sglebius	bev_ssl = upcast(bev);
1487290001Sglebius	if (bev_ssl)
1488290001Sglebius		bev_ssl->allow_dirty_shutdown = !!allow_dirty_shutdown;
1489290001Sglebius	BEV_UNLOCK(bev);
1490290001Sglebius}
1491290001Sglebius
1492290001Sglebiusunsigned long
1493290001Sglebiusbufferevent_get_openssl_error(struct bufferevent *bev)
1494290001Sglebius{
1495290001Sglebius	unsigned long err = 0;
1496290001Sglebius	struct bufferevent_openssl *bev_ssl;
1497290001Sglebius	BEV_LOCK(bev);
1498290001Sglebius	bev_ssl = upcast(bev);
1499290001Sglebius	if (bev_ssl && bev_ssl->n_errors) {
1500290001Sglebius		err = bev_ssl->errors[--bev_ssl->n_errors];
1501290001Sglebius	}
1502290001Sglebius	BEV_UNLOCK(bev);
1503290001Sglebius	return err;
1504290001Sglebius}
1505