xref: /minix3/external/bsd/libevent/dist/bufferevent_openssl.c (revision e985b929927b5932e3b68f4b50587d458900107a)
1*e985b929SDavid van Moolenbroek /*	$NetBSD: bufferevent_openssl.c,v 1.1.1.1 2013/04/11 16:43:25 christos Exp $	*/
2*e985b929SDavid van Moolenbroek /*
3*e985b929SDavid van Moolenbroek  * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
4*e985b929SDavid van Moolenbroek  *
5*e985b929SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
6*e985b929SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
7*e985b929SDavid van Moolenbroek  * are met:
8*e985b929SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
9*e985b929SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
10*e985b929SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
11*e985b929SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
12*e985b929SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
13*e985b929SDavid van Moolenbroek  * 3. The name of the author may not be used to endorse or promote products
14*e985b929SDavid van Moolenbroek  *    derived from this software without specific prior written permission.
15*e985b929SDavid van Moolenbroek  *
16*e985b929SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*e985b929SDavid van Moolenbroek  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*e985b929SDavid van Moolenbroek  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*e985b929SDavid van Moolenbroek  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*e985b929SDavid van Moolenbroek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*e985b929SDavid van Moolenbroek  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*e985b929SDavid van Moolenbroek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*e985b929SDavid van Moolenbroek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*e985b929SDavid van Moolenbroek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*e985b929SDavid van Moolenbroek  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*e985b929SDavid van Moolenbroek  */
27*e985b929SDavid van Moolenbroek 
28*e985b929SDavid van Moolenbroek #include <sys/types.h>
29*e985b929SDavid van Moolenbroek 
30*e985b929SDavid van Moolenbroek #include "event2/event-config.h"
31*e985b929SDavid van Moolenbroek #include <sys/cdefs.h>
32*e985b929SDavid van Moolenbroek __RCSID("$NetBSD: bufferevent_openssl.c,v 1.1.1.1 2013/04/11 16:43:25 christos Exp $");
33*e985b929SDavid van Moolenbroek 
34*e985b929SDavid van Moolenbroek #ifdef _EVENT_HAVE_SYS_TIME_H
35*e985b929SDavid van Moolenbroek #include <sys/time.h>
36*e985b929SDavid van Moolenbroek #endif
37*e985b929SDavid van Moolenbroek 
38*e985b929SDavid van Moolenbroek #include <errno.h>
39*e985b929SDavid van Moolenbroek #include <stdio.h>
40*e985b929SDavid van Moolenbroek #include <stdlib.h>
41*e985b929SDavid van Moolenbroek #include <string.h>
42*e985b929SDavid van Moolenbroek #ifdef _EVENT_HAVE_STDARG_H
43*e985b929SDavid van Moolenbroek #include <stdarg.h>
44*e985b929SDavid van Moolenbroek #endif
45*e985b929SDavid van Moolenbroek #ifdef _EVENT_HAVE_UNISTD_H
46*e985b929SDavid van Moolenbroek #include <unistd.h>
47*e985b929SDavid van Moolenbroek #endif
48*e985b929SDavid van Moolenbroek 
49*e985b929SDavid van Moolenbroek #ifdef WIN32
50*e985b929SDavid van Moolenbroek #include <winsock2.h>
51*e985b929SDavid van Moolenbroek #endif
52*e985b929SDavid van Moolenbroek 
53*e985b929SDavid van Moolenbroek #include "event2/bufferevent.h"
54*e985b929SDavid van Moolenbroek #include "event2/bufferevent_struct.h"
55*e985b929SDavid van Moolenbroek #include "event2/bufferevent_ssl.h"
56*e985b929SDavid van Moolenbroek #include "event2/buffer.h"
57*e985b929SDavid van Moolenbroek #include "event2/event.h"
58*e985b929SDavid van Moolenbroek 
59*e985b929SDavid van Moolenbroek #include "mm-internal.h"
60*e985b929SDavid van Moolenbroek #include "bufferevent-internal.h"
61*e985b929SDavid van Moolenbroek #include "log-internal.h"
62*e985b929SDavid van Moolenbroek 
63*e985b929SDavid van Moolenbroek #include <openssl/bio.h>
64*e985b929SDavid van Moolenbroek #include <openssl/ssl.h>
65*e985b929SDavid van Moolenbroek #include <openssl/err.h>
66*e985b929SDavid van Moolenbroek 
67*e985b929SDavid van Moolenbroek /*
68*e985b929SDavid van Moolenbroek  * Define an OpenSSL bio that targets a bufferevent.
69*e985b929SDavid van Moolenbroek  */
70*e985b929SDavid van Moolenbroek 
71*e985b929SDavid van Moolenbroek /* --------------------
72*e985b929SDavid van Moolenbroek    A BIO is an OpenSSL abstraction that handles reading and writing data.  The
73*e985b929SDavid van Moolenbroek    library will happily speak SSL over anything that implements a BIO
74*e985b929SDavid van Moolenbroek    interface.
75*e985b929SDavid van Moolenbroek 
76*e985b929SDavid van Moolenbroek    Here we define a BIO implementation that directs its output to a
77*e985b929SDavid van Moolenbroek    bufferevent.  We'll want to use this only when none of OpenSSL's built-in
78*e985b929SDavid van Moolenbroek    IO mechanisms work for us.
79*e985b929SDavid van Moolenbroek    -------------------- */
80*e985b929SDavid van Moolenbroek 
81*e985b929SDavid van Moolenbroek /* every BIO type needs its own integer type value. */
82*e985b929SDavid van Moolenbroek #define BIO_TYPE_LIBEVENT 57
83*e985b929SDavid van Moolenbroek /* ???? Arguably, we should set BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK on
84*e985b929SDavid van Moolenbroek  * this. */
85*e985b929SDavid van Moolenbroek 
86*e985b929SDavid van Moolenbroek #if 0
87*e985b929SDavid van Moolenbroek static void
88*e985b929SDavid van Moolenbroek print_err(int val)
89*e985b929SDavid van Moolenbroek {
90*e985b929SDavid van Moolenbroek 	int err;
91*e985b929SDavid van Moolenbroek 	printf("Error was %d\n", val);
92*e985b929SDavid van Moolenbroek 
93*e985b929SDavid van Moolenbroek 	while ((err = ERR_get_error())) {
94*e985b929SDavid van Moolenbroek 		const char *msg = (const char*)ERR_reason_error_string(err);
95*e985b929SDavid van Moolenbroek 		const char *lib = (const char*)ERR_lib_error_string(err);
96*e985b929SDavid van Moolenbroek 		const char *func = (const char*)ERR_func_error_string(err);
97*e985b929SDavid van Moolenbroek 
98*e985b929SDavid van Moolenbroek 		printf("%s in %s %s\n", msg, lib, func);
99*e985b929SDavid van Moolenbroek 	}
100*e985b929SDavid van Moolenbroek }
101*e985b929SDavid van Moolenbroek #else
102*e985b929SDavid van Moolenbroek #define print_err(v) ((void)0)
103*e985b929SDavid van Moolenbroek #endif
104*e985b929SDavid van Moolenbroek 
105*e985b929SDavid van Moolenbroek /* Called to initialize a new BIO */
106*e985b929SDavid van Moolenbroek static int
bio_bufferevent_new(BIO * b)107*e985b929SDavid van Moolenbroek bio_bufferevent_new(BIO *b)
108*e985b929SDavid van Moolenbroek {
109*e985b929SDavid van Moolenbroek 	b->init = 0;
110*e985b929SDavid van Moolenbroek 	b->num = -1;
111*e985b929SDavid van Moolenbroek 	b->ptr = NULL; /* We'll be putting the bufferevent in this field.*/
112*e985b929SDavid van Moolenbroek 	b->flags = 0;
113*e985b929SDavid van Moolenbroek 	return 1;
114*e985b929SDavid van Moolenbroek }
115*e985b929SDavid van Moolenbroek 
116*e985b929SDavid van Moolenbroek /* Called to uninitialize the BIO. */
117*e985b929SDavid van Moolenbroek static int
bio_bufferevent_free(BIO * b)118*e985b929SDavid van Moolenbroek bio_bufferevent_free(BIO *b)
119*e985b929SDavid van Moolenbroek {
120*e985b929SDavid van Moolenbroek 	if (!b)
121*e985b929SDavid van Moolenbroek 		return 0;
122*e985b929SDavid van Moolenbroek 	if (b->shutdown) {
123*e985b929SDavid van Moolenbroek 		if (b->init && b->ptr)
124*e985b929SDavid van Moolenbroek 			bufferevent_free(b->ptr);
125*e985b929SDavid van Moolenbroek 		b->init = 0;
126*e985b929SDavid van Moolenbroek 		b->flags = 0;
127*e985b929SDavid van Moolenbroek 		b->ptr = NULL;
128*e985b929SDavid van Moolenbroek 	}
129*e985b929SDavid van Moolenbroek 	return 1;
130*e985b929SDavid van Moolenbroek }
131*e985b929SDavid van Moolenbroek 
132*e985b929SDavid van Moolenbroek /* Called to extract data from the BIO. */
133*e985b929SDavid van Moolenbroek static int
bio_bufferevent_read(BIO * b,char * out,int outlen)134*e985b929SDavid van Moolenbroek bio_bufferevent_read(BIO *b, char *out, int outlen)
135*e985b929SDavid van Moolenbroek {
136*e985b929SDavid van Moolenbroek 	int r = 0;
137*e985b929SDavid van Moolenbroek 	struct evbuffer *input;
138*e985b929SDavid van Moolenbroek 
139*e985b929SDavid van Moolenbroek 	BIO_clear_retry_flags(b);
140*e985b929SDavid van Moolenbroek 
141*e985b929SDavid van Moolenbroek 	if (!out)
142*e985b929SDavid van Moolenbroek 		return 0;
143*e985b929SDavid van Moolenbroek 	if (!b->ptr)
144*e985b929SDavid van Moolenbroek 		return -1;
145*e985b929SDavid van Moolenbroek 
146*e985b929SDavid van Moolenbroek 	input = bufferevent_get_input(b->ptr);
147*e985b929SDavid van Moolenbroek 	if (evbuffer_get_length(input) == 0) {
148*e985b929SDavid van Moolenbroek 		/* If there's no data to read, say so. */
149*e985b929SDavid van Moolenbroek 		BIO_set_retry_read(b);
150*e985b929SDavid van Moolenbroek 		return -1;
151*e985b929SDavid van Moolenbroek 	} else {
152*e985b929SDavid van Moolenbroek 		r = evbuffer_remove(input, out, outlen);
153*e985b929SDavid van Moolenbroek 	}
154*e985b929SDavid van Moolenbroek 
155*e985b929SDavid van Moolenbroek 	return r;
156*e985b929SDavid van Moolenbroek }
157*e985b929SDavid van Moolenbroek 
158*e985b929SDavid van Moolenbroek /* Called to write data info the BIO */
159*e985b929SDavid van Moolenbroek static int
bio_bufferevent_write(BIO * b,const char * in,int inlen)160*e985b929SDavid van Moolenbroek bio_bufferevent_write(BIO *b, const char *in, int inlen)
161*e985b929SDavid van Moolenbroek {
162*e985b929SDavid van Moolenbroek 	struct bufferevent *bufev = b->ptr;
163*e985b929SDavid van Moolenbroek 	struct evbuffer *output;
164*e985b929SDavid van Moolenbroek 	size_t outlen;
165*e985b929SDavid van Moolenbroek 
166*e985b929SDavid van Moolenbroek 	BIO_clear_retry_flags(b);
167*e985b929SDavid van Moolenbroek 
168*e985b929SDavid van Moolenbroek 	if (!b->ptr)
169*e985b929SDavid van Moolenbroek 		return -1;
170*e985b929SDavid van Moolenbroek 
171*e985b929SDavid van Moolenbroek 	output = bufferevent_get_output(bufev);
172*e985b929SDavid van Moolenbroek 	outlen = evbuffer_get_length(output);
173*e985b929SDavid van Moolenbroek 
174*e985b929SDavid van Moolenbroek 	/* Copy only as much data onto the output buffer as can fit under the
175*e985b929SDavid van Moolenbroek 	 * high-water mark. */
176*e985b929SDavid van Moolenbroek 	if (bufev->wm_write.high && bufev->wm_write.high <= (outlen+inlen)) {
177*e985b929SDavid van Moolenbroek 		if (bufev->wm_write.high <= outlen) {
178*e985b929SDavid van Moolenbroek 			/* If no data can fit, we'll need to retry later. */
179*e985b929SDavid van Moolenbroek 			BIO_set_retry_write(b);
180*e985b929SDavid van Moolenbroek 			return -1;
181*e985b929SDavid van Moolenbroek 		}
182*e985b929SDavid van Moolenbroek 		inlen = bufev->wm_write.high - outlen;
183*e985b929SDavid van Moolenbroek 	}
184*e985b929SDavid van Moolenbroek 
185*e985b929SDavid van Moolenbroek 	EVUTIL_ASSERT(inlen > 0);
186*e985b929SDavid van Moolenbroek 	evbuffer_add(output, in, inlen);
187*e985b929SDavid van Moolenbroek 	return inlen;
188*e985b929SDavid van Moolenbroek }
189*e985b929SDavid van Moolenbroek 
190*e985b929SDavid van Moolenbroek /* Called to handle various requests */
191*e985b929SDavid van Moolenbroek static long
bio_bufferevent_ctrl(BIO * b,int cmd,long num,void * ptr)192*e985b929SDavid van Moolenbroek bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
193*e985b929SDavid van Moolenbroek {
194*e985b929SDavid van Moolenbroek 	struct bufferevent *bufev = b->ptr;
195*e985b929SDavid van Moolenbroek 	long ret = 1;
196*e985b929SDavid van Moolenbroek 
197*e985b929SDavid van Moolenbroek 	switch (cmd) {
198*e985b929SDavid van Moolenbroek 	case BIO_CTRL_GET_CLOSE:
199*e985b929SDavid van Moolenbroek 		ret = b->shutdown;
200*e985b929SDavid van Moolenbroek 		break;
201*e985b929SDavid van Moolenbroek 	case BIO_CTRL_SET_CLOSE:
202*e985b929SDavid van Moolenbroek 		b->shutdown = (int)num;
203*e985b929SDavid van Moolenbroek 		break;
204*e985b929SDavid van Moolenbroek 	case BIO_CTRL_PENDING:
205*e985b929SDavid van Moolenbroek 		ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
206*e985b929SDavid van Moolenbroek 		break;
207*e985b929SDavid van Moolenbroek 	case BIO_CTRL_WPENDING:
208*e985b929SDavid van Moolenbroek 		ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0;
209*e985b929SDavid van Moolenbroek 		break;
210*e985b929SDavid van Moolenbroek 	/* XXXX These two are given a special-case treatment because
211*e985b929SDavid van Moolenbroek 	 * of cargo-cultism.  I should come up with a better reason. */
212*e985b929SDavid van Moolenbroek 	case BIO_CTRL_DUP:
213*e985b929SDavid van Moolenbroek 	case BIO_CTRL_FLUSH:
214*e985b929SDavid van Moolenbroek 		ret = 1;
215*e985b929SDavid van Moolenbroek 		break;
216*e985b929SDavid van Moolenbroek 	default:
217*e985b929SDavid van Moolenbroek 		ret = 0;
218*e985b929SDavid van Moolenbroek 		break;
219*e985b929SDavid van Moolenbroek 	}
220*e985b929SDavid van Moolenbroek 	return ret;
221*e985b929SDavid van Moolenbroek }
222*e985b929SDavid van Moolenbroek 
223*e985b929SDavid van Moolenbroek /* Called to write a string to the BIO */
224*e985b929SDavid van Moolenbroek static int
bio_bufferevent_puts(BIO * b,const char * s)225*e985b929SDavid van Moolenbroek bio_bufferevent_puts(BIO *b, const char *s)
226*e985b929SDavid van Moolenbroek {
227*e985b929SDavid van Moolenbroek 	return bio_bufferevent_write(b, s, strlen(s));
228*e985b929SDavid van Moolenbroek }
229*e985b929SDavid van Moolenbroek 
230*e985b929SDavid van Moolenbroek /* Method table for the bufferevent BIO */
231*e985b929SDavid van Moolenbroek static BIO_METHOD methods_bufferevent = {
232*e985b929SDavid van Moolenbroek 	BIO_TYPE_LIBEVENT, "bufferevent",
233*e985b929SDavid van Moolenbroek 	bio_bufferevent_write,
234*e985b929SDavid van Moolenbroek 	bio_bufferevent_read,
235*e985b929SDavid van Moolenbroek 	bio_bufferevent_puts,
236*e985b929SDavid van Moolenbroek 	NULL /* bio_bufferevent_gets */,
237*e985b929SDavid van Moolenbroek 	bio_bufferevent_ctrl,
238*e985b929SDavid van Moolenbroek 	bio_bufferevent_new,
239*e985b929SDavid van Moolenbroek 	bio_bufferevent_free,
240*e985b929SDavid van Moolenbroek 	NULL /* callback_ctrl */,
241*e985b929SDavid van Moolenbroek };
242*e985b929SDavid van Moolenbroek 
243*e985b929SDavid van Moolenbroek /* Return the method table for the bufferevents BIO */
244*e985b929SDavid van Moolenbroek static BIO_METHOD *
BIO_s_bufferevent(void)245*e985b929SDavid van Moolenbroek BIO_s_bufferevent(void)
246*e985b929SDavid van Moolenbroek {
247*e985b929SDavid van Moolenbroek 	return &methods_bufferevent;
248*e985b929SDavid van Moolenbroek }
249*e985b929SDavid van Moolenbroek 
250*e985b929SDavid van Moolenbroek /* Create a new BIO to wrap communication around a bufferevent.  If close_flag
251*e985b929SDavid van Moolenbroek  * is true, the bufferevent will be freed when the BIO is closed. */
252*e985b929SDavid van Moolenbroek static BIO *
BIO_new_bufferevent(struct bufferevent * bufferevent,int close_flag)253*e985b929SDavid van Moolenbroek BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
254*e985b929SDavid van Moolenbroek {
255*e985b929SDavid van Moolenbroek 	BIO *result;
256*e985b929SDavid van Moolenbroek 	if (!bufferevent)
257*e985b929SDavid van Moolenbroek 		return NULL;
258*e985b929SDavid van Moolenbroek 	if (!(result = BIO_new(BIO_s_bufferevent())))
259*e985b929SDavid van Moolenbroek 		return NULL;
260*e985b929SDavid van Moolenbroek 	result->init = 1;
261*e985b929SDavid van Moolenbroek 	result->ptr = bufferevent;
262*e985b929SDavid van Moolenbroek 	result->shutdown = close_flag ? 1 : 0;
263*e985b929SDavid van Moolenbroek 	return result;
264*e985b929SDavid van Moolenbroek }
265*e985b929SDavid van Moolenbroek 
266*e985b929SDavid van Moolenbroek /* --------------------
267*e985b929SDavid van Moolenbroek    Now, here's the OpenSSL-based implementation of bufferevent.
268*e985b929SDavid van Moolenbroek 
269*e985b929SDavid van Moolenbroek    The implementation comes in two flavors: one that connects its SSL object
270*e985b929SDavid van Moolenbroek    to an underlying bufferevent using a BIO_bufferevent, and one that has the
271*e985b929SDavid van Moolenbroek    SSL object connect to a socket directly.  The latter should generally be
272*e985b929SDavid van Moolenbroek    faster, except on Windows, where your best bet is using a
273*e985b929SDavid van Moolenbroek    bufferevent_async.
274*e985b929SDavid van Moolenbroek 
275*e985b929SDavid van Moolenbroek    (OpenSSL supports many other BIO types, too.  But we can't use any unless
276*e985b929SDavid van Moolenbroek    we have a good way to get notified when they become readable/writable.)
277*e985b929SDavid van Moolenbroek    -------------------- */
278*e985b929SDavid van Moolenbroek 
279*e985b929SDavid van Moolenbroek struct bio_data_counts {
280*e985b929SDavid van Moolenbroek 	unsigned long n_written;
281*e985b929SDavid van Moolenbroek 	unsigned long n_read;
282*e985b929SDavid van Moolenbroek };
283*e985b929SDavid van Moolenbroek 
284*e985b929SDavid van Moolenbroek struct bufferevent_openssl {
285*e985b929SDavid van Moolenbroek 	/* Shared fields with common bufferevent implementation code.
286*e985b929SDavid van Moolenbroek 	   If we were set up with an underlying bufferevent, we use the
287*e985b929SDavid van Moolenbroek 	   events here as timers only.  If we have an SSL, then we use
288*e985b929SDavid van Moolenbroek 	   the events as socket events.
289*e985b929SDavid van Moolenbroek 	 */
290*e985b929SDavid van Moolenbroek 	struct bufferevent_private bev;
291*e985b929SDavid van Moolenbroek 	/* An underlying bufferevent that we're directing our output to.
292*e985b929SDavid van Moolenbroek 	   If it's NULL, then we're connected to an fd, not an evbuffer. */
293*e985b929SDavid van Moolenbroek 	struct bufferevent *underlying;
294*e985b929SDavid van Moolenbroek 	/* The SSL object doing our encryption. */
295*e985b929SDavid van Moolenbroek 	SSL *ssl;
296*e985b929SDavid van Moolenbroek 
297*e985b929SDavid van Moolenbroek 	/* A callback that's invoked when data arrives on our outbuf so we
298*e985b929SDavid van Moolenbroek 	   know to write data to the SSL. */
299*e985b929SDavid van Moolenbroek 	struct evbuffer_cb_entry *outbuf_cb;
300*e985b929SDavid van Moolenbroek 
301*e985b929SDavid van Moolenbroek 	/* A count of how much data the bios have read/written total.  Used
302*e985b929SDavid van Moolenbroek 	   for rate-limiting. */
303*e985b929SDavid van Moolenbroek 	struct bio_data_counts counts;
304*e985b929SDavid van Moolenbroek 
305*e985b929SDavid van Moolenbroek 	/* If this value is greater than 0, then the last SSL_write blocked,
306*e985b929SDavid van Moolenbroek 	 * and we need to try it again with this many bytes. */
307*e985b929SDavid van Moolenbroek 	ev_ssize_t last_write;
308*e985b929SDavid van Moolenbroek 
309*e985b929SDavid van Moolenbroek #define NUM_ERRORS 3
310*e985b929SDavid van Moolenbroek 	ev_uint32_t errors[NUM_ERRORS];
311*e985b929SDavid van Moolenbroek 
312*e985b929SDavid van Moolenbroek 	/* When we next get available space, we should say "read" instead of
313*e985b929SDavid van Moolenbroek 	   "write". This can happen if there's a renegotiation during a read
314*e985b929SDavid van Moolenbroek 	   operation. */
315*e985b929SDavid van Moolenbroek 	unsigned read_blocked_on_write : 1;
316*e985b929SDavid van Moolenbroek 	/* When we next get data, we should say "write" instead of "read". */
317*e985b929SDavid van Moolenbroek 	unsigned write_blocked_on_read : 1;
318*e985b929SDavid van Moolenbroek 	/* XXX */
319*e985b929SDavid van Moolenbroek 	unsigned allow_dirty_shutdown : 1;
320*e985b929SDavid van Moolenbroek 	/* XXXX */
321*e985b929SDavid van Moolenbroek 	unsigned fd_is_set : 1;
322*e985b929SDavid van Moolenbroek 	/* XXX */
323*e985b929SDavid van Moolenbroek 	unsigned n_errors : 2;
324*e985b929SDavid van Moolenbroek 
325*e985b929SDavid van Moolenbroek 	/* Are we currently connecting, accepting, or doing IO? */
326*e985b929SDavid van Moolenbroek 	unsigned state : 2;
327*e985b929SDavid van Moolenbroek };
328*e985b929SDavid van Moolenbroek 
329*e985b929SDavid van Moolenbroek static int be_openssl_enable(struct bufferevent *, short);
330*e985b929SDavid van Moolenbroek static int be_openssl_disable(struct bufferevent *, short);
331*e985b929SDavid van Moolenbroek static void be_openssl_destruct(struct bufferevent *);
332*e985b929SDavid van Moolenbroek static int be_openssl_adj_timeouts(struct bufferevent *);
333*e985b929SDavid van Moolenbroek static int be_openssl_flush(struct bufferevent *bufev,
334*e985b929SDavid van Moolenbroek     short iotype, enum bufferevent_flush_mode mode);
335*e985b929SDavid van Moolenbroek static int be_openssl_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
336*e985b929SDavid van Moolenbroek 
337*e985b929SDavid van Moolenbroek const struct bufferevent_ops bufferevent_ops_openssl = {
338*e985b929SDavid van Moolenbroek 	"ssl",
339*e985b929SDavid van Moolenbroek 	evutil_offsetof(struct bufferevent_openssl, bev.bev),
340*e985b929SDavid van Moolenbroek 	be_openssl_enable,
341*e985b929SDavid van Moolenbroek 	be_openssl_disable,
342*e985b929SDavid van Moolenbroek 	be_openssl_destruct,
343*e985b929SDavid van Moolenbroek 	be_openssl_adj_timeouts,
344*e985b929SDavid van Moolenbroek 	be_openssl_flush,
345*e985b929SDavid van Moolenbroek 	be_openssl_ctrl,
346*e985b929SDavid van Moolenbroek };
347*e985b929SDavid van Moolenbroek 
348*e985b929SDavid van Moolenbroek /* Given a bufferevent, return a pointer to the bufferevent_openssl that
349*e985b929SDavid van Moolenbroek  * contains it, if any. */
350*e985b929SDavid van Moolenbroek static inline struct bufferevent_openssl *
upcast(struct bufferevent * bev)351*e985b929SDavid van Moolenbroek upcast(struct bufferevent *bev)
352*e985b929SDavid van Moolenbroek {
353*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_o;
354*e985b929SDavid van Moolenbroek 	if (bev->be_ops != &bufferevent_ops_openssl)
355*e985b929SDavid van Moolenbroek 		return NULL;
356*e985b929SDavid van Moolenbroek 	bev_o = (void*)( ((char*)bev) -
357*e985b929SDavid van Moolenbroek 			 evutil_offsetof(struct bufferevent_openssl, bev.bev));
358*e985b929SDavid van Moolenbroek 	EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
359*e985b929SDavid van Moolenbroek 	return bev_o;
360*e985b929SDavid van Moolenbroek }
361*e985b929SDavid van Moolenbroek 
362*e985b929SDavid van Moolenbroek static inline void
put_error(struct bufferevent_openssl * bev_ssl,unsigned long err)363*e985b929SDavid van Moolenbroek put_error(struct bufferevent_openssl *bev_ssl, unsigned long err)
364*e985b929SDavid van Moolenbroek {
365*e985b929SDavid van Moolenbroek 	if (bev_ssl->n_errors == NUM_ERRORS)
366*e985b929SDavid van Moolenbroek 		return;
367*e985b929SDavid van Moolenbroek 	/* The error type according to openssl is "unsigned long", but
368*e985b929SDavid van Moolenbroek 	   openssl never uses more than 32 bits of it.  It _can't_ use more
369*e985b929SDavid van Moolenbroek 	   than 32 bits of it, since it needs to report errors on systems
370*e985b929SDavid van Moolenbroek 	   where long is only 32 bits.
371*e985b929SDavid van Moolenbroek 	 */
372*e985b929SDavid van Moolenbroek 	bev_ssl->errors[bev_ssl->n_errors++] = (ev_uint32_t) err;
373*e985b929SDavid van Moolenbroek }
374*e985b929SDavid van Moolenbroek 
375*e985b929SDavid van Moolenbroek /* Have the base communications channel (either the underlying bufferevent or
376*e985b929SDavid van Moolenbroek  * ev_read and ev_write) start reading.  Take the read-blocked-on-write flag
377*e985b929SDavid van Moolenbroek  * into account. */
378*e985b929SDavid van Moolenbroek static int
start_reading(struct bufferevent_openssl * bev_ssl)379*e985b929SDavid van Moolenbroek start_reading(struct bufferevent_openssl *bev_ssl)
380*e985b929SDavid van Moolenbroek {
381*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
382*e985b929SDavid van Moolenbroek 		bufferevent_unsuspend_read(bev_ssl->underlying,
383*e985b929SDavid van Moolenbroek 		    BEV_SUSPEND_FILT_READ);
384*e985b929SDavid van Moolenbroek 		return 0;
385*e985b929SDavid van Moolenbroek 	} else {
386*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
387*e985b929SDavid van Moolenbroek 		int r;
388*e985b929SDavid van Moolenbroek 		r = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
389*e985b929SDavid van Moolenbroek 		if (r == 0 && bev_ssl->read_blocked_on_write)
390*e985b929SDavid van Moolenbroek 			r = _bufferevent_add_event(&bev->ev_write,
391*e985b929SDavid van Moolenbroek 			    &bev->timeout_write);
392*e985b929SDavid van Moolenbroek 		return r;
393*e985b929SDavid van Moolenbroek 	}
394*e985b929SDavid van Moolenbroek }
395*e985b929SDavid van Moolenbroek 
396*e985b929SDavid van Moolenbroek /* Have the base communications channel (either the underlying bufferevent or
397*e985b929SDavid van Moolenbroek  * ev_read and ev_write) start writing.  Take the write-blocked-on-read flag
398*e985b929SDavid van Moolenbroek  * into account. */
399*e985b929SDavid van Moolenbroek static int
start_writing(struct bufferevent_openssl * bev_ssl)400*e985b929SDavid van Moolenbroek start_writing(struct bufferevent_openssl *bev_ssl)
401*e985b929SDavid van Moolenbroek {
402*e985b929SDavid van Moolenbroek 	int r = 0;
403*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
404*e985b929SDavid van Moolenbroek 		;
405*e985b929SDavid van Moolenbroek 	} else {
406*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
407*e985b929SDavid van Moolenbroek 		r = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
408*e985b929SDavid van Moolenbroek 		if (!r && bev_ssl->write_blocked_on_read)
409*e985b929SDavid van Moolenbroek 			r = _bufferevent_add_event(&bev->ev_read,
410*e985b929SDavid van Moolenbroek 			    &bev->timeout_read);
411*e985b929SDavid van Moolenbroek 	}
412*e985b929SDavid van Moolenbroek 	return r;
413*e985b929SDavid van Moolenbroek }
414*e985b929SDavid van Moolenbroek 
415*e985b929SDavid van Moolenbroek static void
stop_reading(struct bufferevent_openssl * bev_ssl)416*e985b929SDavid van Moolenbroek stop_reading(struct bufferevent_openssl *bev_ssl)
417*e985b929SDavid van Moolenbroek {
418*e985b929SDavid van Moolenbroek 	if (bev_ssl->write_blocked_on_read)
419*e985b929SDavid van Moolenbroek 		return;
420*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
421*e985b929SDavid van Moolenbroek 		bufferevent_suspend_read(bev_ssl->underlying,
422*e985b929SDavid van Moolenbroek 		    BEV_SUSPEND_FILT_READ);
423*e985b929SDavid van Moolenbroek 	} else {
424*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
425*e985b929SDavid van Moolenbroek 		event_del(&bev->ev_read);
426*e985b929SDavid van Moolenbroek 	}
427*e985b929SDavid van Moolenbroek }
428*e985b929SDavid van Moolenbroek 
429*e985b929SDavid van Moolenbroek static void
stop_writing(struct bufferevent_openssl * bev_ssl)430*e985b929SDavid van Moolenbroek stop_writing(struct bufferevent_openssl *bev_ssl)
431*e985b929SDavid van Moolenbroek {
432*e985b929SDavid van Moolenbroek 	if (bev_ssl->read_blocked_on_write)
433*e985b929SDavid van Moolenbroek 		return;
434*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
435*e985b929SDavid van Moolenbroek 		;
436*e985b929SDavid van Moolenbroek 	} else {
437*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
438*e985b929SDavid van Moolenbroek 		event_del(&bev->ev_write);
439*e985b929SDavid van Moolenbroek 	}
440*e985b929SDavid van Moolenbroek }
441*e985b929SDavid van Moolenbroek 
442*e985b929SDavid van Moolenbroek static int
set_rbow(struct bufferevent_openssl * bev_ssl)443*e985b929SDavid van Moolenbroek set_rbow(struct bufferevent_openssl *bev_ssl)
444*e985b929SDavid van Moolenbroek {
445*e985b929SDavid van Moolenbroek 	if (!bev_ssl->underlying)
446*e985b929SDavid van Moolenbroek 		stop_reading(bev_ssl);
447*e985b929SDavid van Moolenbroek 	bev_ssl->read_blocked_on_write = 1;
448*e985b929SDavid van Moolenbroek 	return start_writing(bev_ssl);
449*e985b929SDavid van Moolenbroek }
450*e985b929SDavid van Moolenbroek 
451*e985b929SDavid van Moolenbroek static int
set_wbor(struct bufferevent_openssl * bev_ssl)452*e985b929SDavid van Moolenbroek set_wbor(struct bufferevent_openssl *bev_ssl)
453*e985b929SDavid van Moolenbroek {
454*e985b929SDavid van Moolenbroek 	if (!bev_ssl->underlying)
455*e985b929SDavid van Moolenbroek 		stop_writing(bev_ssl);
456*e985b929SDavid van Moolenbroek 	bev_ssl->write_blocked_on_read = 1;
457*e985b929SDavid van Moolenbroek 	return start_reading(bev_ssl);
458*e985b929SDavid van Moolenbroek }
459*e985b929SDavid van Moolenbroek 
460*e985b929SDavid van Moolenbroek static int
clear_rbow(struct bufferevent_openssl * bev_ssl)461*e985b929SDavid van Moolenbroek clear_rbow(struct bufferevent_openssl *bev_ssl)
462*e985b929SDavid van Moolenbroek {
463*e985b929SDavid van Moolenbroek 	struct bufferevent *bev = &bev_ssl->bev.bev;
464*e985b929SDavid van Moolenbroek 	int r = 0;
465*e985b929SDavid van Moolenbroek 	bev_ssl->read_blocked_on_write = 0;
466*e985b929SDavid van Moolenbroek 	if (!(bev->enabled & EV_WRITE))
467*e985b929SDavid van Moolenbroek 		stop_writing(bev_ssl);
468*e985b929SDavid van Moolenbroek 	if (bev->enabled & EV_READ)
469*e985b929SDavid van Moolenbroek 		r = start_reading(bev_ssl);
470*e985b929SDavid van Moolenbroek 	return r;
471*e985b929SDavid van Moolenbroek }
472*e985b929SDavid van Moolenbroek 
473*e985b929SDavid van Moolenbroek 
474*e985b929SDavid van Moolenbroek static int
clear_wbor(struct bufferevent_openssl * bev_ssl)475*e985b929SDavid van Moolenbroek clear_wbor(struct bufferevent_openssl *bev_ssl)
476*e985b929SDavid van Moolenbroek {
477*e985b929SDavid van Moolenbroek 	struct bufferevent *bev = &bev_ssl->bev.bev;
478*e985b929SDavid van Moolenbroek 	int r = 0;
479*e985b929SDavid van Moolenbroek 	bev_ssl->write_blocked_on_read = 0;
480*e985b929SDavid van Moolenbroek 	if (!(bev->enabled & EV_READ))
481*e985b929SDavid van Moolenbroek 		stop_reading(bev_ssl);
482*e985b929SDavid van Moolenbroek 	if (bev->enabled & EV_WRITE)
483*e985b929SDavid van Moolenbroek 		r = start_writing(bev_ssl);
484*e985b929SDavid van Moolenbroek 	return r;
485*e985b929SDavid van Moolenbroek }
486*e985b929SDavid van Moolenbroek 
487*e985b929SDavid van Moolenbroek static void
conn_closed(struct bufferevent_openssl * bev_ssl,int errcode,int ret)488*e985b929SDavid van Moolenbroek conn_closed(struct bufferevent_openssl *bev_ssl, int errcode, int ret)
489*e985b929SDavid van Moolenbroek {
490*e985b929SDavid van Moolenbroek 	int event = BEV_EVENT_ERROR;
491*e985b929SDavid van Moolenbroek 	int dirty_shutdown = 0;
492*e985b929SDavid van Moolenbroek 	unsigned long err;
493*e985b929SDavid van Moolenbroek 
494*e985b929SDavid van Moolenbroek 	switch (errcode) {
495*e985b929SDavid van Moolenbroek 	case SSL_ERROR_ZERO_RETURN:
496*e985b929SDavid van Moolenbroek 		/* Possibly a clean shutdown. */
497*e985b929SDavid van Moolenbroek 		if (SSL_get_shutdown(bev_ssl->ssl) & SSL_RECEIVED_SHUTDOWN)
498*e985b929SDavid van Moolenbroek 			event = BEV_EVENT_EOF;
499*e985b929SDavid van Moolenbroek 		else
500*e985b929SDavid van Moolenbroek 			dirty_shutdown = 1;
501*e985b929SDavid van Moolenbroek 		break;
502*e985b929SDavid van Moolenbroek 	case SSL_ERROR_SYSCALL:
503*e985b929SDavid van Moolenbroek 		/* IO error; possibly a dirty shutdown. */
504*e985b929SDavid van Moolenbroek 		if (ret == 0 && ERR_peek_error() == 0)
505*e985b929SDavid van Moolenbroek 			dirty_shutdown = 1;
506*e985b929SDavid van Moolenbroek 		break;
507*e985b929SDavid van Moolenbroek 	case SSL_ERROR_SSL:
508*e985b929SDavid van Moolenbroek 		/* Protocol error. */
509*e985b929SDavid van Moolenbroek 		break;
510*e985b929SDavid van Moolenbroek 	case SSL_ERROR_WANT_X509_LOOKUP:
511*e985b929SDavid van Moolenbroek 		/* XXXX handle this. */
512*e985b929SDavid van Moolenbroek 		break;
513*e985b929SDavid van Moolenbroek 	case SSL_ERROR_NONE:
514*e985b929SDavid van Moolenbroek 	case SSL_ERROR_WANT_READ:
515*e985b929SDavid van Moolenbroek 	case SSL_ERROR_WANT_WRITE:
516*e985b929SDavid van Moolenbroek 	case SSL_ERROR_WANT_CONNECT:
517*e985b929SDavid van Moolenbroek 	case SSL_ERROR_WANT_ACCEPT:
518*e985b929SDavid van Moolenbroek 	default:
519*e985b929SDavid van Moolenbroek 		/* should be impossible; treat as normal error. */
520*e985b929SDavid van Moolenbroek 		event_warnx("BUG: Unexpected OpenSSL error code %d", errcode);
521*e985b929SDavid van Moolenbroek 		break;
522*e985b929SDavid van Moolenbroek 	}
523*e985b929SDavid van Moolenbroek 
524*e985b929SDavid van Moolenbroek 	while ((err = ERR_get_error())) {
525*e985b929SDavid van Moolenbroek 		put_error(bev_ssl, err);
526*e985b929SDavid van Moolenbroek 	}
527*e985b929SDavid van Moolenbroek 
528*e985b929SDavid van Moolenbroek 	if (dirty_shutdown && bev_ssl->allow_dirty_shutdown)
529*e985b929SDavid van Moolenbroek 		event = BEV_EVENT_EOF;
530*e985b929SDavid van Moolenbroek 
531*e985b929SDavid van Moolenbroek 	stop_reading(bev_ssl);
532*e985b929SDavid van Moolenbroek 	stop_writing(bev_ssl);
533*e985b929SDavid van Moolenbroek 
534*e985b929SDavid van Moolenbroek 	_bufferevent_run_eventcb(&bev_ssl->bev.bev, event);
535*e985b929SDavid van Moolenbroek }
536*e985b929SDavid van Moolenbroek 
537*e985b929SDavid van Moolenbroek static void
init_bio_counts(struct bufferevent_openssl * bev_ssl)538*e985b929SDavid van Moolenbroek init_bio_counts(struct bufferevent_openssl *bev_ssl)
539*e985b929SDavid van Moolenbroek {
540*e985b929SDavid van Moolenbroek 	bev_ssl->counts.n_written =
541*e985b929SDavid van Moolenbroek 	    BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
542*e985b929SDavid van Moolenbroek 	bev_ssl->counts.n_read =
543*e985b929SDavid van Moolenbroek 	    BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
544*e985b929SDavid van Moolenbroek }
545*e985b929SDavid van Moolenbroek 
546*e985b929SDavid van Moolenbroek static inline void
decrement_buckets(struct bufferevent_openssl * bev_ssl)547*e985b929SDavid van Moolenbroek decrement_buckets(struct bufferevent_openssl *bev_ssl)
548*e985b929SDavid van Moolenbroek {
549*e985b929SDavid van Moolenbroek 	unsigned long num_w = BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
550*e985b929SDavid van Moolenbroek 	unsigned long num_r = BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
551*e985b929SDavid van Moolenbroek 	/* These next two subtractions can wrap around. That's okay. */
552*e985b929SDavid van Moolenbroek 	unsigned long w = num_w - bev_ssl->counts.n_written;
553*e985b929SDavid van Moolenbroek 	unsigned long r = num_r - bev_ssl->counts.n_read;
554*e985b929SDavid van Moolenbroek 	if (w)
555*e985b929SDavid van Moolenbroek 		_bufferevent_decrement_write_buckets(&bev_ssl->bev, w);
556*e985b929SDavid van Moolenbroek 	if (r)
557*e985b929SDavid van Moolenbroek 		_bufferevent_decrement_read_buckets(&bev_ssl->bev, r);
558*e985b929SDavid van Moolenbroek 	bev_ssl->counts.n_written = num_w;
559*e985b929SDavid van Moolenbroek 	bev_ssl->counts.n_read = num_r;
560*e985b929SDavid van Moolenbroek }
561*e985b929SDavid van Moolenbroek 
562*e985b929SDavid van Moolenbroek #define OP_MADE_PROGRESS 1
563*e985b929SDavid van Moolenbroek #define OP_BLOCKED 2
564*e985b929SDavid van Moolenbroek #define OP_ERR 4
565*e985b929SDavid van Moolenbroek 
566*e985b929SDavid van Moolenbroek /* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
567*e985b929SDavid van Moolenbroek    we're now blocked); and OP_ERR (if an error occurred). */
568*e985b929SDavid van Moolenbroek static int
do_read(struct bufferevent_openssl * bev_ssl,int n_to_read)569*e985b929SDavid van Moolenbroek do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
570*e985b929SDavid van Moolenbroek 	/* Requires lock */
571*e985b929SDavid van Moolenbroek 	struct bufferevent *bev = &bev_ssl->bev.bev;
572*e985b929SDavid van Moolenbroek 	struct evbuffer *input = bev->input;
573*e985b929SDavid van Moolenbroek 	int r, n, i, n_used = 0, atmost;
574*e985b929SDavid van Moolenbroek 	struct evbuffer_iovec space[2];
575*e985b929SDavid van Moolenbroek 	int result = 0;
576*e985b929SDavid van Moolenbroek 
577*e985b929SDavid van Moolenbroek 	if (bev_ssl->bev.read_suspended)
578*e985b929SDavid van Moolenbroek 		return 0;
579*e985b929SDavid van Moolenbroek 
580*e985b929SDavid van Moolenbroek 	atmost = _bufferevent_get_read_max(&bev_ssl->bev);
581*e985b929SDavid van Moolenbroek 	if (n_to_read > atmost)
582*e985b929SDavid van Moolenbroek 		n_to_read = atmost;
583*e985b929SDavid van Moolenbroek 
584*e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(input, n_to_read, space, 2);
585*e985b929SDavid van Moolenbroek 	if (n < 0)
586*e985b929SDavid van Moolenbroek 		return OP_ERR;
587*e985b929SDavid van Moolenbroek 
588*e985b929SDavid van Moolenbroek 	for (i=0; i<n; ++i) {
589*e985b929SDavid van Moolenbroek 		if (bev_ssl->bev.read_suspended)
590*e985b929SDavid van Moolenbroek 			break;
591*e985b929SDavid van Moolenbroek 		r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
592*e985b929SDavid van Moolenbroek 		if (r>0) {
593*e985b929SDavid van Moolenbroek 			result |= OP_MADE_PROGRESS;
594*e985b929SDavid van Moolenbroek 			if (bev_ssl->read_blocked_on_write)
595*e985b929SDavid van Moolenbroek 				if (clear_rbow(bev_ssl) < 0)
596*e985b929SDavid van Moolenbroek 					return OP_ERR | result;
597*e985b929SDavid van Moolenbroek 			++n_used;
598*e985b929SDavid van Moolenbroek 			space[i].iov_len = r;
599*e985b929SDavid van Moolenbroek 			decrement_buckets(bev_ssl);
600*e985b929SDavid van Moolenbroek 		} else {
601*e985b929SDavid van Moolenbroek 			int err = SSL_get_error(bev_ssl->ssl, r);
602*e985b929SDavid van Moolenbroek 			print_err(err);
603*e985b929SDavid van Moolenbroek 			switch (err) {
604*e985b929SDavid van Moolenbroek 			case SSL_ERROR_WANT_READ:
605*e985b929SDavid van Moolenbroek 				/* Can't read until underlying has more data. */
606*e985b929SDavid van Moolenbroek 				if (bev_ssl->read_blocked_on_write)
607*e985b929SDavid van Moolenbroek 					if (clear_rbow(bev_ssl) < 0)
608*e985b929SDavid van Moolenbroek 						return OP_ERR | result;
609*e985b929SDavid van Moolenbroek 				break;
610*e985b929SDavid van Moolenbroek 			case SSL_ERROR_WANT_WRITE:
611*e985b929SDavid van Moolenbroek 				/* This read operation requires a write, and the
612*e985b929SDavid van Moolenbroek 				 * underlying is full */
613*e985b929SDavid van Moolenbroek 				if (!bev_ssl->read_blocked_on_write)
614*e985b929SDavid van Moolenbroek 					if (set_rbow(bev_ssl) < 0)
615*e985b929SDavid van Moolenbroek 						return OP_ERR | result;
616*e985b929SDavid van Moolenbroek 				break;
617*e985b929SDavid van Moolenbroek 			default:
618*e985b929SDavid van Moolenbroek 				conn_closed(bev_ssl, err, r);
619*e985b929SDavid van Moolenbroek 				break;
620*e985b929SDavid van Moolenbroek 			}
621*e985b929SDavid van Moolenbroek 			result |= OP_BLOCKED;
622*e985b929SDavid van Moolenbroek 			break; /* out of the loop */
623*e985b929SDavid van Moolenbroek 		}
624*e985b929SDavid van Moolenbroek 	}
625*e985b929SDavid van Moolenbroek 
626*e985b929SDavid van Moolenbroek 	if (n_used) {
627*e985b929SDavid van Moolenbroek 		evbuffer_commit_space(input, space, n_used);
628*e985b929SDavid van Moolenbroek 		if (bev_ssl->underlying)
629*e985b929SDavid van Moolenbroek 			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
630*e985b929SDavid van Moolenbroek 	}
631*e985b929SDavid van Moolenbroek 
632*e985b929SDavid van Moolenbroek 	return result;
633*e985b929SDavid van Moolenbroek }
634*e985b929SDavid van Moolenbroek 
635*e985b929SDavid van Moolenbroek /* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
636*e985b929SDavid van Moolenbroek    we're now blocked); and OP_ERR (if an error occurred). */
637*e985b929SDavid van Moolenbroek static int
do_write(struct bufferevent_openssl * bev_ssl,int atmost)638*e985b929SDavid van Moolenbroek do_write(struct bufferevent_openssl *bev_ssl, int atmost)
639*e985b929SDavid van Moolenbroek {
640*e985b929SDavid van Moolenbroek 	int i, r, n, n_written = 0;
641*e985b929SDavid van Moolenbroek 	struct bufferevent *bev = &bev_ssl->bev.bev;
642*e985b929SDavid van Moolenbroek 	struct evbuffer *output = bev->output;
643*e985b929SDavid van Moolenbroek 	struct evbuffer_iovec space[8];
644*e985b929SDavid van Moolenbroek 	int result = 0;
645*e985b929SDavid van Moolenbroek 
646*e985b929SDavid van Moolenbroek 	if (bev_ssl->last_write > 0)
647*e985b929SDavid van Moolenbroek 		atmost = bev_ssl->last_write;
648*e985b929SDavid van Moolenbroek 	else
649*e985b929SDavid van Moolenbroek 		atmost = _bufferevent_get_write_max(&bev_ssl->bev);
650*e985b929SDavid van Moolenbroek 
651*e985b929SDavid van Moolenbroek 	n = evbuffer_peek(output, atmost, NULL, space, 8);
652*e985b929SDavid van Moolenbroek 	if (n < 0)
653*e985b929SDavid van Moolenbroek 		return OP_ERR | result;
654*e985b929SDavid van Moolenbroek 
655*e985b929SDavid van Moolenbroek 	if (n > 8)
656*e985b929SDavid van Moolenbroek 		n = 8;
657*e985b929SDavid van Moolenbroek 	for (i=0; i < n; ++i) {
658*e985b929SDavid van Moolenbroek 		if (bev_ssl->bev.write_suspended)
659*e985b929SDavid van Moolenbroek 			break;
660*e985b929SDavid van Moolenbroek 
661*e985b929SDavid van Moolenbroek 		/* SSL_write will (reasonably) return 0 if we tell it to
662*e985b929SDavid van Moolenbroek 		   send 0 data.  Skip this case so we don't interpret the
663*e985b929SDavid van Moolenbroek 		   result as an error */
664*e985b929SDavid van Moolenbroek 		if (space[i].iov_len == 0)
665*e985b929SDavid van Moolenbroek 			continue;
666*e985b929SDavid van Moolenbroek 
667*e985b929SDavid van Moolenbroek 		r = SSL_write(bev_ssl->ssl, space[i].iov_base,
668*e985b929SDavid van Moolenbroek 		    space[i].iov_len);
669*e985b929SDavid van Moolenbroek 		if (r > 0) {
670*e985b929SDavid van Moolenbroek 			result |= OP_MADE_PROGRESS;
671*e985b929SDavid van Moolenbroek 			if (bev_ssl->write_blocked_on_read)
672*e985b929SDavid van Moolenbroek 				if (clear_wbor(bev_ssl) < 0)
673*e985b929SDavid van Moolenbroek 					return OP_ERR | result;
674*e985b929SDavid van Moolenbroek 			n_written += r;
675*e985b929SDavid van Moolenbroek 			bev_ssl->last_write = -1;
676*e985b929SDavid van Moolenbroek 			decrement_buckets(bev_ssl);
677*e985b929SDavid van Moolenbroek 		} else {
678*e985b929SDavid van Moolenbroek 			int err = SSL_get_error(bev_ssl->ssl, r);
679*e985b929SDavid van Moolenbroek 			print_err(err);
680*e985b929SDavid van Moolenbroek 			switch (err) {
681*e985b929SDavid van Moolenbroek 			case SSL_ERROR_WANT_WRITE:
682*e985b929SDavid van Moolenbroek 				/* Can't read until underlying has more data. */
683*e985b929SDavid van Moolenbroek 				if (bev_ssl->write_blocked_on_read)
684*e985b929SDavid van Moolenbroek 					if (clear_wbor(bev_ssl) < 0)
685*e985b929SDavid van Moolenbroek 						return OP_ERR | result;
686*e985b929SDavid van Moolenbroek 				bev_ssl->last_write = space[i].iov_len;
687*e985b929SDavid van Moolenbroek 				break;
688*e985b929SDavid van Moolenbroek 			case SSL_ERROR_WANT_READ:
689*e985b929SDavid van Moolenbroek 				/* This read operation requires a write, and the
690*e985b929SDavid van Moolenbroek 				 * underlying is full */
691*e985b929SDavid van Moolenbroek 				if (!bev_ssl->write_blocked_on_read)
692*e985b929SDavid van Moolenbroek 					if (set_wbor(bev_ssl) < 0)
693*e985b929SDavid van Moolenbroek 						return OP_ERR | result;
694*e985b929SDavid van Moolenbroek 				bev_ssl->last_write = space[i].iov_len;
695*e985b929SDavid van Moolenbroek 				break;
696*e985b929SDavid van Moolenbroek 			default:
697*e985b929SDavid van Moolenbroek 				conn_closed(bev_ssl, err, r);
698*e985b929SDavid van Moolenbroek 				bev_ssl->last_write = -1;
699*e985b929SDavid van Moolenbroek 				break;
700*e985b929SDavid van Moolenbroek 			}
701*e985b929SDavid van Moolenbroek 			result |= OP_BLOCKED;
702*e985b929SDavid van Moolenbroek 			break;
703*e985b929SDavid van Moolenbroek 		}
704*e985b929SDavid van Moolenbroek 	}
705*e985b929SDavid van Moolenbroek 	if (n_written) {
706*e985b929SDavid van Moolenbroek 		evbuffer_drain(output, n_written);
707*e985b929SDavid van Moolenbroek 		if (bev_ssl->underlying)
708*e985b929SDavid van Moolenbroek 			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
709*e985b929SDavid van Moolenbroek 
710*e985b929SDavid van Moolenbroek 		if (evbuffer_get_length(output) <= bev->wm_write.low)
711*e985b929SDavid van Moolenbroek 			_bufferevent_run_writecb(bev);
712*e985b929SDavid van Moolenbroek 	}
713*e985b929SDavid van Moolenbroek 	return result;
714*e985b929SDavid van Moolenbroek }
715*e985b929SDavid van Moolenbroek 
716*e985b929SDavid van Moolenbroek #define WRITE_FRAME 15000
717*e985b929SDavid van Moolenbroek 
718*e985b929SDavid van Moolenbroek #define READ_DEFAULT 4096
719*e985b929SDavid van Moolenbroek 
720*e985b929SDavid van Moolenbroek /* Try to figure out how many bytes to read; return 0 if we shouldn't be
721*e985b929SDavid van Moolenbroek  * reading. */
722*e985b929SDavid van Moolenbroek static int
bytes_to_read(struct bufferevent_openssl * bev)723*e985b929SDavid van Moolenbroek bytes_to_read(struct bufferevent_openssl *bev)
724*e985b929SDavid van Moolenbroek {
725*e985b929SDavid van Moolenbroek 	struct evbuffer *input = bev->bev.bev.input;
726*e985b929SDavid van Moolenbroek 	struct event_watermark *wm = &bev->bev.bev.wm_read;
727*e985b929SDavid van Moolenbroek 	int result = READ_DEFAULT;
728*e985b929SDavid van Moolenbroek 	ev_ssize_t limit;
729*e985b929SDavid van Moolenbroek 	/* XXX 99% of this is generic code that nearly all bufferevents will
730*e985b929SDavid van Moolenbroek 	 * want. */
731*e985b929SDavid van Moolenbroek 
732*e985b929SDavid van Moolenbroek 	if (bev->write_blocked_on_read) {
733*e985b929SDavid van Moolenbroek 		return 0;
734*e985b929SDavid van Moolenbroek 	}
735*e985b929SDavid van Moolenbroek 
736*e985b929SDavid van Moolenbroek 	if (! (bev->bev.bev.enabled & EV_READ)) {
737*e985b929SDavid van Moolenbroek 		return 0;
738*e985b929SDavid van Moolenbroek 	}
739*e985b929SDavid van Moolenbroek 
740*e985b929SDavid van Moolenbroek 	if (bev->bev.read_suspended) {
741*e985b929SDavid van Moolenbroek 		return 0;
742*e985b929SDavid van Moolenbroek 	}
743*e985b929SDavid van Moolenbroek 
744*e985b929SDavid van Moolenbroek 	if (wm->high) {
745*e985b929SDavid van Moolenbroek 		if (evbuffer_get_length(input) >= wm->high) {
746*e985b929SDavid van Moolenbroek 			return 0;
747*e985b929SDavid van Moolenbroek 		}
748*e985b929SDavid van Moolenbroek 
749*e985b929SDavid van Moolenbroek 		result = wm->high - evbuffer_get_length(input);
750*e985b929SDavid van Moolenbroek 	} else {
751*e985b929SDavid van Moolenbroek 		result = READ_DEFAULT;
752*e985b929SDavid van Moolenbroek 	}
753*e985b929SDavid van Moolenbroek 
754*e985b929SDavid van Moolenbroek 	/* Respect the rate limit */
755*e985b929SDavid van Moolenbroek 	limit = _bufferevent_get_read_max(&bev->bev);
756*e985b929SDavid van Moolenbroek 	if (result > limit) {
757*e985b929SDavid van Moolenbroek 		result = limit;
758*e985b929SDavid van Moolenbroek 	}
759*e985b929SDavid van Moolenbroek 
760*e985b929SDavid van Moolenbroek 	return result;
761*e985b929SDavid van Moolenbroek }
762*e985b929SDavid van Moolenbroek 
763*e985b929SDavid van Moolenbroek 
764*e985b929SDavid van Moolenbroek /* Things look readable.  If write is blocked on read, write till it isn't.
765*e985b929SDavid van Moolenbroek  * Read from the underlying buffer until we block or we hit our high-water
766*e985b929SDavid van Moolenbroek  * mark.
767*e985b929SDavid van Moolenbroek  */
768*e985b929SDavid van Moolenbroek static void
consider_reading(struct bufferevent_openssl * bev_ssl)769*e985b929SDavid van Moolenbroek consider_reading(struct bufferevent_openssl *bev_ssl)
770*e985b929SDavid van Moolenbroek {
771*e985b929SDavid van Moolenbroek 	int r;
772*e985b929SDavid van Moolenbroek 	int n_to_read;
773*e985b929SDavid van Moolenbroek 	int all_result_flags = 0;
774*e985b929SDavid van Moolenbroek 
775*e985b929SDavid van Moolenbroek 	while (bev_ssl->write_blocked_on_read) {
776*e985b929SDavid van Moolenbroek 		r = do_write(bev_ssl, WRITE_FRAME);
777*e985b929SDavid van Moolenbroek 		if (r & (OP_BLOCKED|OP_ERR))
778*e985b929SDavid van Moolenbroek 			break;
779*e985b929SDavid van Moolenbroek 	}
780*e985b929SDavid van Moolenbroek 	if (bev_ssl->write_blocked_on_read)
781*e985b929SDavid van Moolenbroek 		return;
782*e985b929SDavid van Moolenbroek 
783*e985b929SDavid van Moolenbroek 	n_to_read = bytes_to_read(bev_ssl);
784*e985b929SDavid van Moolenbroek 
785*e985b929SDavid van Moolenbroek 	while (n_to_read) {
786*e985b929SDavid van Moolenbroek 		r = do_read(bev_ssl, n_to_read);
787*e985b929SDavid van Moolenbroek 		all_result_flags |= r;
788*e985b929SDavid van Moolenbroek 
789*e985b929SDavid van Moolenbroek 		if (r & (OP_BLOCKED|OP_ERR))
790*e985b929SDavid van Moolenbroek 			break;
791*e985b929SDavid van Moolenbroek 
792*e985b929SDavid van Moolenbroek 		if (bev_ssl->bev.read_suspended)
793*e985b929SDavid van Moolenbroek 			break;
794*e985b929SDavid van Moolenbroek 
795*e985b929SDavid van Moolenbroek 		/* Read all pending data.  This won't hit the network
796*e985b929SDavid van Moolenbroek 		 * again, and will (most importantly) put us in a state
797*e985b929SDavid van Moolenbroek 		 * where we don't need to read anything else until the
798*e985b929SDavid van Moolenbroek 		 * socket is readable again.  It'll potentially make us
799*e985b929SDavid van Moolenbroek 		 * overrun our read high-watermark (somewhat
800*e985b929SDavid van Moolenbroek 		 * regrettable).  The damage to the rate-limit has
801*e985b929SDavid van Moolenbroek 		 * already been done, since OpenSSL went and read a
802*e985b929SDavid van Moolenbroek 		 * whole SSL record anyway. */
803*e985b929SDavid van Moolenbroek 		n_to_read = SSL_pending(bev_ssl->ssl);
804*e985b929SDavid van Moolenbroek 
805*e985b929SDavid van Moolenbroek 		/* XXX This if statement is actually a bad bug, added to avoid
806*e985b929SDavid van Moolenbroek 		 * XXX a worse bug.
807*e985b929SDavid van Moolenbroek 		 *
808*e985b929SDavid van Moolenbroek 		 * The bad bug: It can potentially cause resource unfairness
809*e985b929SDavid van Moolenbroek 		 * by reading too much data from the underlying bufferevent;
810*e985b929SDavid van Moolenbroek 		 * it can potentially cause read looping if the underlying
811*e985b929SDavid van Moolenbroek 		 * bufferevent is a bufferevent_pair and deferred callbacks
812*e985b929SDavid van Moolenbroek 		 * aren't used.
813*e985b929SDavid van Moolenbroek 		 *
814*e985b929SDavid van Moolenbroek 		 * The worse bug: If we didn't do this, then we would
815*e985b929SDavid van Moolenbroek 		 * potentially not read any more from bev_ssl->underlying
816*e985b929SDavid van Moolenbroek 		 * until more data arrived there, which could lead to us
817*e985b929SDavid van Moolenbroek 		 * waiting forever.
818*e985b929SDavid van Moolenbroek 		 */
819*e985b929SDavid van Moolenbroek 		if (!n_to_read && bev_ssl->underlying)
820*e985b929SDavid van Moolenbroek 			n_to_read = bytes_to_read(bev_ssl);
821*e985b929SDavid van Moolenbroek 	}
822*e985b929SDavid van Moolenbroek 
823*e985b929SDavid van Moolenbroek 	if (all_result_flags & OP_MADE_PROGRESS) {
824*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
825*e985b929SDavid van Moolenbroek 		struct evbuffer *input = bev->input;
826*e985b929SDavid van Moolenbroek 
827*e985b929SDavid van Moolenbroek 		if (evbuffer_get_length(input) >= bev->wm_read.low) {
828*e985b929SDavid van Moolenbroek 			_bufferevent_run_readcb(bev);
829*e985b929SDavid van Moolenbroek 		}
830*e985b929SDavid van Moolenbroek 	}
831*e985b929SDavid van Moolenbroek 
832*e985b929SDavid van Moolenbroek 	if (!bev_ssl->underlying) {
833*e985b929SDavid van Moolenbroek 		/* Should be redundant, but let's avoid busy-looping */
834*e985b929SDavid van Moolenbroek 		if (bev_ssl->bev.read_suspended ||
835*e985b929SDavid van Moolenbroek 		    !(bev_ssl->bev.bev.enabled & EV_READ)) {
836*e985b929SDavid van Moolenbroek 			event_del(&bev_ssl->bev.bev.ev_read);
837*e985b929SDavid van Moolenbroek 		}
838*e985b929SDavid van Moolenbroek 	}
839*e985b929SDavid van Moolenbroek }
840*e985b929SDavid van Moolenbroek 
841*e985b929SDavid van Moolenbroek static void
consider_writing(struct bufferevent_openssl * bev_ssl)842*e985b929SDavid van Moolenbroek consider_writing(struct bufferevent_openssl *bev_ssl)
843*e985b929SDavid van Moolenbroek {
844*e985b929SDavid van Moolenbroek 	int r;
845*e985b929SDavid van Moolenbroek 	struct evbuffer *output = bev_ssl->bev.bev.output;
846*e985b929SDavid van Moolenbroek 	struct evbuffer *target = NULL;
847*e985b929SDavid van Moolenbroek 	struct event_watermark *wm = NULL;
848*e985b929SDavid van Moolenbroek 
849*e985b929SDavid van Moolenbroek 	while (bev_ssl->read_blocked_on_write) {
850*e985b929SDavid van Moolenbroek 		r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
851*e985b929SDavid van Moolenbroek 		if (r & OP_MADE_PROGRESS) {
852*e985b929SDavid van Moolenbroek 			struct bufferevent *bev = &bev_ssl->bev.bev;
853*e985b929SDavid van Moolenbroek 			struct evbuffer *input = bev->input;
854*e985b929SDavid van Moolenbroek 
855*e985b929SDavid van Moolenbroek 			if (evbuffer_get_length(input) >= bev->wm_read.low) {
856*e985b929SDavid van Moolenbroek 				_bufferevent_run_readcb(bev);
857*e985b929SDavid van Moolenbroek 			}
858*e985b929SDavid van Moolenbroek 		}
859*e985b929SDavid van Moolenbroek 		if (r & (OP_ERR|OP_BLOCKED))
860*e985b929SDavid van Moolenbroek 			break;
861*e985b929SDavid van Moolenbroek 	}
862*e985b929SDavid van Moolenbroek 	if (bev_ssl->read_blocked_on_write)
863*e985b929SDavid van Moolenbroek 		return;
864*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
865*e985b929SDavid van Moolenbroek 		target = bev_ssl->underlying->output;
866*e985b929SDavid van Moolenbroek 		wm = &bev_ssl->underlying->wm_write;
867*e985b929SDavid van Moolenbroek 	}
868*e985b929SDavid van Moolenbroek 	while ((bev_ssl->bev.bev.enabled & EV_WRITE) &&
869*e985b929SDavid van Moolenbroek 	    (! bev_ssl->bev.write_suspended) &&
870*e985b929SDavid van Moolenbroek 	    evbuffer_get_length(output) &&
871*e985b929SDavid van Moolenbroek 	    (!target || (! wm->high || evbuffer_get_length(target) < wm->high))) {
872*e985b929SDavid van Moolenbroek 		int n_to_write;
873*e985b929SDavid van Moolenbroek 		if (wm && wm->high)
874*e985b929SDavid van Moolenbroek 			n_to_write = wm->high - evbuffer_get_length(target);
875*e985b929SDavid van Moolenbroek 		else
876*e985b929SDavid van Moolenbroek 			n_to_write = WRITE_FRAME;
877*e985b929SDavid van Moolenbroek 		r = do_write(bev_ssl, n_to_write);
878*e985b929SDavid van Moolenbroek 		if (r & (OP_BLOCKED|OP_ERR))
879*e985b929SDavid van Moolenbroek 			break;
880*e985b929SDavid van Moolenbroek 	}
881*e985b929SDavid van Moolenbroek 
882*e985b929SDavid van Moolenbroek 	if (!bev_ssl->underlying) {
883*e985b929SDavid van Moolenbroek 		if (evbuffer_get_length(output) == 0) {
884*e985b929SDavid van Moolenbroek 			event_del(&bev_ssl->bev.bev.ev_write);
885*e985b929SDavid van Moolenbroek 		} else if (bev_ssl->bev.write_suspended ||
886*e985b929SDavid van Moolenbroek 		    !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
887*e985b929SDavid van Moolenbroek 			/* Should be redundant, but let's avoid busy-looping */
888*e985b929SDavid van Moolenbroek 			event_del(&bev_ssl->bev.bev.ev_write);
889*e985b929SDavid van Moolenbroek 		}
890*e985b929SDavid van Moolenbroek 	}
891*e985b929SDavid van Moolenbroek }
892*e985b929SDavid van Moolenbroek 
893*e985b929SDavid van Moolenbroek static void
be_openssl_readcb(struct bufferevent * bev_base,void * ctx)894*e985b929SDavid van Moolenbroek be_openssl_readcb(struct bufferevent *bev_base, void *ctx)
895*e985b929SDavid van Moolenbroek {
896*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ctx;
897*e985b929SDavid van Moolenbroek 	consider_reading(bev_ssl);
898*e985b929SDavid van Moolenbroek }
899*e985b929SDavid van Moolenbroek 
900*e985b929SDavid van Moolenbroek static void
be_openssl_writecb(struct bufferevent * bev_base,void * ctx)901*e985b929SDavid van Moolenbroek be_openssl_writecb(struct bufferevent *bev_base, void *ctx)
902*e985b929SDavid van Moolenbroek {
903*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ctx;
904*e985b929SDavid van Moolenbroek 	consider_writing(bev_ssl);
905*e985b929SDavid van Moolenbroek }
906*e985b929SDavid van Moolenbroek 
907*e985b929SDavid van Moolenbroek static void
be_openssl_eventcb(struct bufferevent * bev_base,short what,void * ctx)908*e985b929SDavid van Moolenbroek be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
909*e985b929SDavid van Moolenbroek {
910*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ctx;
911*e985b929SDavid van Moolenbroek 	int event = 0;
912*e985b929SDavid van Moolenbroek 
913*e985b929SDavid van Moolenbroek 	if (what & BEV_EVENT_EOF) {
914*e985b929SDavid van Moolenbroek 		if (bev_ssl->allow_dirty_shutdown)
915*e985b929SDavid van Moolenbroek 			event = BEV_EVENT_EOF;
916*e985b929SDavid van Moolenbroek 		else
917*e985b929SDavid van Moolenbroek 			event = BEV_EVENT_ERROR;
918*e985b929SDavid van Moolenbroek 	} else if (what & BEV_EVENT_TIMEOUT) {
919*e985b929SDavid van Moolenbroek 		/* We sure didn't set this.  Propagate it to the user. */
920*e985b929SDavid van Moolenbroek 		event = what;
921*e985b929SDavid van Moolenbroek 	} else if (what & BEV_EVENT_ERROR) {
922*e985b929SDavid van Moolenbroek 		/* An error occurred on the connection.  Propagate it to the user. */
923*e985b929SDavid van Moolenbroek 		event = what;
924*e985b929SDavid van Moolenbroek 	} else if (what & BEV_EVENT_CONNECTED) {
925*e985b929SDavid van Moolenbroek 		/* Ignore it.  We're saying SSL_connect() already, which will
926*e985b929SDavid van Moolenbroek 		   eat it. */
927*e985b929SDavid van Moolenbroek 	}
928*e985b929SDavid van Moolenbroek 	if (event)
929*e985b929SDavid van Moolenbroek 		_bufferevent_run_eventcb(&bev_ssl->bev.bev, event);
930*e985b929SDavid van Moolenbroek }
931*e985b929SDavid van Moolenbroek 
932*e985b929SDavid van Moolenbroek static void
be_openssl_readeventcb(evutil_socket_t fd,short what,void * ptr)933*e985b929SDavid van Moolenbroek be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
934*e985b929SDavid van Moolenbroek {
935*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ptr;
936*e985b929SDavid van Moolenbroek 	_bufferevent_incref_and_lock(&bev_ssl->bev.bev);
937*e985b929SDavid van Moolenbroek 	if (what == EV_TIMEOUT) {
938*e985b929SDavid van Moolenbroek 		_bufferevent_run_eventcb(&bev_ssl->bev.bev,
939*e985b929SDavid van Moolenbroek 		    BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
940*e985b929SDavid van Moolenbroek 	} else {
941*e985b929SDavid van Moolenbroek 		consider_reading(bev_ssl);
942*e985b929SDavid van Moolenbroek 	}
943*e985b929SDavid van Moolenbroek 	_bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
944*e985b929SDavid van Moolenbroek }
945*e985b929SDavid van Moolenbroek 
946*e985b929SDavid van Moolenbroek static void
be_openssl_writeeventcb(evutil_socket_t fd,short what,void * ptr)947*e985b929SDavid van Moolenbroek be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
948*e985b929SDavid van Moolenbroek {
949*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ptr;
950*e985b929SDavid van Moolenbroek 	_bufferevent_incref_and_lock(&bev_ssl->bev.bev);
951*e985b929SDavid van Moolenbroek 	if (what == EV_TIMEOUT) {
952*e985b929SDavid van Moolenbroek 		_bufferevent_run_eventcb(&bev_ssl->bev.bev,
953*e985b929SDavid van Moolenbroek 		    BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
954*e985b929SDavid van Moolenbroek 	} else {
955*e985b929SDavid van Moolenbroek 		consider_writing(bev_ssl);
956*e985b929SDavid van Moolenbroek 	}
957*e985b929SDavid van Moolenbroek 	_bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
958*e985b929SDavid van Moolenbroek }
959*e985b929SDavid van Moolenbroek 
960*e985b929SDavid van Moolenbroek static int
set_open_callbacks(struct bufferevent_openssl * bev_ssl,evutil_socket_t fd)961*e985b929SDavid van Moolenbroek set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
962*e985b929SDavid van Moolenbroek {
963*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
964*e985b929SDavid van Moolenbroek 		bufferevent_setcb(bev_ssl->underlying,
965*e985b929SDavid van Moolenbroek 		    be_openssl_readcb, be_openssl_writecb, be_openssl_eventcb,
966*e985b929SDavid van Moolenbroek 		    bev_ssl);
967*e985b929SDavid van Moolenbroek 		return 0;
968*e985b929SDavid van Moolenbroek 	} else {
969*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
970*e985b929SDavid van Moolenbroek 		int rpending=0, wpending=0, r1=0, r2=0;
971*e985b929SDavid van Moolenbroek 		if (fd < 0 && bev_ssl->fd_is_set)
972*e985b929SDavid van Moolenbroek 			fd = event_get_fd(&bev->ev_read);
973*e985b929SDavid van Moolenbroek 		if (bev_ssl->fd_is_set) {
974*e985b929SDavid van Moolenbroek 			rpending = event_pending(&bev->ev_read, EV_READ, NULL);
975*e985b929SDavid van Moolenbroek 			wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
976*e985b929SDavid van Moolenbroek 			event_del(&bev->ev_read);
977*e985b929SDavid van Moolenbroek 			event_del(&bev->ev_write);
978*e985b929SDavid van Moolenbroek 		}
979*e985b929SDavid van Moolenbroek 		event_assign(&bev->ev_read, bev->ev_base, fd,
980*e985b929SDavid van Moolenbroek 		    EV_READ|EV_PERSIST, be_openssl_readeventcb, bev_ssl);
981*e985b929SDavid van Moolenbroek 		event_assign(&bev->ev_write, bev->ev_base, fd,
982*e985b929SDavid van Moolenbroek 		    EV_WRITE|EV_PERSIST, be_openssl_writeeventcb, bev_ssl);
983*e985b929SDavid van Moolenbroek 		if (rpending)
984*e985b929SDavid van Moolenbroek 			r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
985*e985b929SDavid van Moolenbroek 		if (wpending)
986*e985b929SDavid van Moolenbroek 			r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
987*e985b929SDavid van Moolenbroek 		if (fd >= 0) {
988*e985b929SDavid van Moolenbroek 			bev_ssl->fd_is_set = 1;
989*e985b929SDavid van Moolenbroek 		}
990*e985b929SDavid van Moolenbroek 		return (r1<0 || r2<0) ? -1 : 0;
991*e985b929SDavid van Moolenbroek 	}
992*e985b929SDavid van Moolenbroek }
993*e985b929SDavid van Moolenbroek 
994*e985b929SDavid van Moolenbroek static int
do_handshake(struct bufferevent_openssl * bev_ssl)995*e985b929SDavid van Moolenbroek do_handshake(struct bufferevent_openssl *bev_ssl)
996*e985b929SDavid van Moolenbroek {
997*e985b929SDavid van Moolenbroek 	int r;
998*e985b929SDavid van Moolenbroek 
999*e985b929SDavid van Moolenbroek 	switch (bev_ssl->state) {
1000*e985b929SDavid van Moolenbroek 	default:
1001*e985b929SDavid van Moolenbroek 	case BUFFEREVENT_SSL_OPEN:
1002*e985b929SDavid van Moolenbroek 		EVUTIL_ASSERT(0);
1003*e985b929SDavid van Moolenbroek 		return -1;
1004*e985b929SDavid van Moolenbroek 	case BUFFEREVENT_SSL_CONNECTING:
1005*e985b929SDavid van Moolenbroek 	case BUFFEREVENT_SSL_ACCEPTING:
1006*e985b929SDavid van Moolenbroek 		r = SSL_do_handshake(bev_ssl->ssl);
1007*e985b929SDavid van Moolenbroek 		break;
1008*e985b929SDavid van Moolenbroek 	}
1009*e985b929SDavid van Moolenbroek 	decrement_buckets(bev_ssl);
1010*e985b929SDavid van Moolenbroek 
1011*e985b929SDavid van Moolenbroek 	if (r==1) {
1012*e985b929SDavid van Moolenbroek 		/* We're done! */
1013*e985b929SDavid van Moolenbroek 		bev_ssl->state = BUFFEREVENT_SSL_OPEN;
1014*e985b929SDavid van Moolenbroek 		set_open_callbacks(bev_ssl, -1); /* XXXX handle failure */
1015*e985b929SDavid van Moolenbroek 		/* Call do_read and do_write as needed */
1016*e985b929SDavid van Moolenbroek 		bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
1017*e985b929SDavid van Moolenbroek 		_bufferevent_run_eventcb(&bev_ssl->bev.bev,
1018*e985b929SDavid van Moolenbroek 		    BEV_EVENT_CONNECTED);
1019*e985b929SDavid van Moolenbroek 		return 1;
1020*e985b929SDavid van Moolenbroek 	} else {
1021*e985b929SDavid van Moolenbroek 		int err = SSL_get_error(bev_ssl->ssl, r);
1022*e985b929SDavid van Moolenbroek 		print_err(err);
1023*e985b929SDavid van Moolenbroek 		switch (err) {
1024*e985b929SDavid van Moolenbroek 		case SSL_ERROR_WANT_WRITE:
1025*e985b929SDavid van Moolenbroek 			if (!bev_ssl->underlying) {
1026*e985b929SDavid van Moolenbroek 				stop_reading(bev_ssl);
1027*e985b929SDavid van Moolenbroek 				return start_writing(bev_ssl);
1028*e985b929SDavid van Moolenbroek 			}
1029*e985b929SDavid van Moolenbroek 			return 0;
1030*e985b929SDavid van Moolenbroek 		case SSL_ERROR_WANT_READ:
1031*e985b929SDavid van Moolenbroek 			if (!bev_ssl->underlying) {
1032*e985b929SDavid van Moolenbroek 				stop_writing(bev_ssl);
1033*e985b929SDavid van Moolenbroek 				return start_reading(bev_ssl);
1034*e985b929SDavid van Moolenbroek 			}
1035*e985b929SDavid van Moolenbroek 			return 0;
1036*e985b929SDavid van Moolenbroek 		default:
1037*e985b929SDavid van Moolenbroek 			conn_closed(bev_ssl, err, r);
1038*e985b929SDavid van Moolenbroek 			return -1;
1039*e985b929SDavid van Moolenbroek 		}
1040*e985b929SDavid van Moolenbroek 	}
1041*e985b929SDavid van Moolenbroek }
1042*e985b929SDavid van Moolenbroek 
1043*e985b929SDavid van Moolenbroek static void
be_openssl_handshakecb(struct bufferevent * bev_base,void * ctx)1044*e985b929SDavid van Moolenbroek be_openssl_handshakecb(struct bufferevent *bev_base, void *ctx)
1045*e985b929SDavid van Moolenbroek {
1046*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ctx;
1047*e985b929SDavid van Moolenbroek 	do_handshake(bev_ssl);/* XXX handle failure */
1048*e985b929SDavid van Moolenbroek }
1049*e985b929SDavid van Moolenbroek 
1050*e985b929SDavid van Moolenbroek static void
be_openssl_handshakeeventcb(evutil_socket_t fd,short what,void * ptr)1051*e985b929SDavid van Moolenbroek be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
1052*e985b929SDavid van Moolenbroek {
1053*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = ptr;
1054*e985b929SDavid van Moolenbroek 
1055*e985b929SDavid van Moolenbroek 	_bufferevent_incref_and_lock(&bev_ssl->bev.bev);
1056*e985b929SDavid van Moolenbroek 	if (what & EV_TIMEOUT) {
1057*e985b929SDavid van Moolenbroek 		_bufferevent_run_eventcb(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT);
1058*e985b929SDavid van Moolenbroek 	} else
1059*e985b929SDavid van Moolenbroek 		do_handshake(bev_ssl);/* XXX handle failure */
1060*e985b929SDavid van Moolenbroek 	_bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
1061*e985b929SDavid van Moolenbroek }
1062*e985b929SDavid van Moolenbroek 
1063*e985b929SDavid van Moolenbroek static int
set_handshake_callbacks(struct bufferevent_openssl * bev_ssl,evutil_socket_t fd)1064*e985b929SDavid van Moolenbroek set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
1065*e985b929SDavid van Moolenbroek {
1066*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
1067*e985b929SDavid van Moolenbroek 		bufferevent_setcb(bev_ssl->underlying,
1068*e985b929SDavid van Moolenbroek 		    be_openssl_handshakecb, be_openssl_handshakecb,
1069*e985b929SDavid van Moolenbroek 		    be_openssl_eventcb,
1070*e985b929SDavid van Moolenbroek 		    bev_ssl);
1071*e985b929SDavid van Moolenbroek 		return do_handshake(bev_ssl);
1072*e985b929SDavid van Moolenbroek 	} else {
1073*e985b929SDavid van Moolenbroek 		struct bufferevent *bev = &bev_ssl->bev.bev;
1074*e985b929SDavid van Moolenbroek 		int r1=0, r2=0;
1075*e985b929SDavid van Moolenbroek 		if (fd < 0 && bev_ssl->fd_is_set)
1076*e985b929SDavid van Moolenbroek 			fd = event_get_fd(&bev->ev_read);
1077*e985b929SDavid van Moolenbroek 		if (bev_ssl->fd_is_set) {
1078*e985b929SDavid van Moolenbroek 			event_del(&bev->ev_read);
1079*e985b929SDavid van Moolenbroek 			event_del(&bev->ev_write);
1080*e985b929SDavid van Moolenbroek 		}
1081*e985b929SDavid van Moolenbroek 		event_assign(&bev->ev_read, bev->ev_base, fd,
1082*e985b929SDavid van Moolenbroek 		    EV_READ|EV_PERSIST, be_openssl_handshakeeventcb, bev_ssl);
1083*e985b929SDavid van Moolenbroek 		event_assign(&bev->ev_write, bev->ev_base, fd,
1084*e985b929SDavid van Moolenbroek 		    EV_WRITE|EV_PERSIST, be_openssl_handshakeeventcb, bev_ssl);
1085*e985b929SDavid van Moolenbroek 		if (fd >= 0) {
1086*e985b929SDavid van Moolenbroek 			r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
1087*e985b929SDavid van Moolenbroek 			r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
1088*e985b929SDavid van Moolenbroek 			bev_ssl->fd_is_set = 1;
1089*e985b929SDavid van Moolenbroek 		}
1090*e985b929SDavid van Moolenbroek 		return (r1<0 || r2<0) ? -1 : 0;
1091*e985b929SDavid van Moolenbroek 	}
1092*e985b929SDavid van Moolenbroek }
1093*e985b929SDavid van Moolenbroek 
1094*e985b929SDavid van Moolenbroek int
bufferevent_ssl_renegotiate(struct bufferevent * bev)1095*e985b929SDavid van Moolenbroek bufferevent_ssl_renegotiate(struct bufferevent *bev)
1096*e985b929SDavid van Moolenbroek {
1097*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bev);
1098*e985b929SDavid van Moolenbroek 	if (!bev_ssl)
1099*e985b929SDavid van Moolenbroek 		return -1;
1100*e985b929SDavid van Moolenbroek 	if (SSL_renegotiate(bev_ssl->ssl) < 0)
1101*e985b929SDavid van Moolenbroek 		return -1;
1102*e985b929SDavid van Moolenbroek 	bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
1103*e985b929SDavid van Moolenbroek 	if (set_handshake_callbacks(bev_ssl, -1) < 0)
1104*e985b929SDavid van Moolenbroek 		return -1;
1105*e985b929SDavid van Moolenbroek 	if (!bev_ssl->underlying)
1106*e985b929SDavid van Moolenbroek 		return do_handshake(bev_ssl);
1107*e985b929SDavid van Moolenbroek 	return 0;
1108*e985b929SDavid van Moolenbroek }
1109*e985b929SDavid van Moolenbroek 
1110*e985b929SDavid van Moolenbroek static void
be_openssl_outbuf_cb(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)1111*e985b929SDavid van Moolenbroek be_openssl_outbuf_cb(struct evbuffer *buf,
1112*e985b929SDavid van Moolenbroek     const struct evbuffer_cb_info *cbinfo, void *arg)
1113*e985b929SDavid van Moolenbroek {
1114*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = arg;
1115*e985b929SDavid van Moolenbroek 	int r = 0;
1116*e985b929SDavid van Moolenbroek 	/* XXX need to hold a reference here. */
1117*e985b929SDavid van Moolenbroek 
1118*e985b929SDavid van Moolenbroek 	if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
1119*e985b929SDavid van Moolenbroek 		if (cbinfo->orig_size == 0)
1120*e985b929SDavid van Moolenbroek 			r = _bufferevent_add_event(&bev_ssl->bev.bev.ev_write,
1121*e985b929SDavid van Moolenbroek 			    &bev_ssl->bev.bev.timeout_write);
1122*e985b929SDavid van Moolenbroek 		consider_writing(bev_ssl);
1123*e985b929SDavid van Moolenbroek 	}
1124*e985b929SDavid van Moolenbroek 	/* XXX Handle r < 0 */
1125*e985b929SDavid van Moolenbroek         (void)r;
1126*e985b929SDavid van Moolenbroek }
1127*e985b929SDavid van Moolenbroek 
1128*e985b929SDavid van Moolenbroek 
1129*e985b929SDavid van Moolenbroek static int
be_openssl_enable(struct bufferevent * bev,short events)1130*e985b929SDavid van Moolenbroek be_openssl_enable(struct bufferevent *bev, short events)
1131*e985b929SDavid van Moolenbroek {
1132*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bev);
1133*e985b929SDavid van Moolenbroek 	int r1 = 0, r2 = 0;
1134*e985b929SDavid van Moolenbroek 
1135*e985b929SDavid van Moolenbroek 	if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
1136*e985b929SDavid van Moolenbroek 		return 0;
1137*e985b929SDavid van Moolenbroek 
1138*e985b929SDavid van Moolenbroek 	if (events & EV_READ)
1139*e985b929SDavid van Moolenbroek 		r1 = start_reading(bev_ssl);
1140*e985b929SDavid van Moolenbroek 	if (events & EV_WRITE)
1141*e985b929SDavid van Moolenbroek 		r2 = start_writing(bev_ssl);
1142*e985b929SDavid van Moolenbroek 
1143*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
1144*e985b929SDavid van Moolenbroek 		if (events & EV_READ)
1145*e985b929SDavid van Moolenbroek 			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
1146*e985b929SDavid van Moolenbroek 		if (events & EV_WRITE)
1147*e985b929SDavid van Moolenbroek 			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
1148*e985b929SDavid van Moolenbroek 
1149*e985b929SDavid van Moolenbroek 		if (events & EV_READ)
1150*e985b929SDavid van Moolenbroek 			consider_reading(bev_ssl);
1151*e985b929SDavid van Moolenbroek 		if (events & EV_WRITE)
1152*e985b929SDavid van Moolenbroek 			consider_writing(bev_ssl);
1153*e985b929SDavid van Moolenbroek 	}
1154*e985b929SDavid van Moolenbroek 	return (r1 < 0 || r2 < 0) ? -1 : 0;
1155*e985b929SDavid van Moolenbroek }
1156*e985b929SDavid van Moolenbroek 
1157*e985b929SDavid van Moolenbroek static int
be_openssl_disable(struct bufferevent * bev,short events)1158*e985b929SDavid van Moolenbroek be_openssl_disable(struct bufferevent *bev, short events)
1159*e985b929SDavid van Moolenbroek {
1160*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bev);
1161*e985b929SDavid van Moolenbroek 	if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
1162*e985b929SDavid van Moolenbroek 		return 0;
1163*e985b929SDavid van Moolenbroek 
1164*e985b929SDavid van Moolenbroek 	if (events & EV_READ)
1165*e985b929SDavid van Moolenbroek 		stop_reading(bev_ssl);
1166*e985b929SDavid van Moolenbroek 	if (events & EV_WRITE)
1167*e985b929SDavid van Moolenbroek 		stop_writing(bev_ssl);
1168*e985b929SDavid van Moolenbroek 
1169*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
1170*e985b929SDavid van Moolenbroek 		if (events & EV_READ)
1171*e985b929SDavid van Moolenbroek 			BEV_DEL_GENERIC_READ_TIMEOUT(bev);
1172*e985b929SDavid van Moolenbroek 		if (events & EV_WRITE)
1173*e985b929SDavid van Moolenbroek 			BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
1174*e985b929SDavid van Moolenbroek 	}
1175*e985b929SDavid van Moolenbroek 	return 0;
1176*e985b929SDavid van Moolenbroek }
1177*e985b929SDavid van Moolenbroek 
1178*e985b929SDavid van Moolenbroek static void
be_openssl_destruct(struct bufferevent * bev)1179*e985b929SDavid van Moolenbroek be_openssl_destruct(struct bufferevent *bev)
1180*e985b929SDavid van Moolenbroek {
1181*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bev);
1182*e985b929SDavid van Moolenbroek 
1183*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying) {
1184*e985b929SDavid van Moolenbroek 		_bufferevent_del_generic_timeout_cbs(bev);
1185*e985b929SDavid van Moolenbroek 	} else {
1186*e985b929SDavid van Moolenbroek 		event_del(&bev->ev_read);
1187*e985b929SDavid van Moolenbroek 		event_del(&bev->ev_write);
1188*e985b929SDavid van Moolenbroek 	}
1189*e985b929SDavid van Moolenbroek 
1190*e985b929SDavid van Moolenbroek 	if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
1191*e985b929SDavid van Moolenbroek 		if (bev_ssl->underlying) {
1192*e985b929SDavid van Moolenbroek 			if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
1193*e985b929SDavid van Moolenbroek 				event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
1194*e985b929SDavid van Moolenbroek 				    "bufferevent with too few references");
1195*e985b929SDavid van Moolenbroek 			} else {
1196*e985b929SDavid van Moolenbroek 				bufferevent_free(bev_ssl->underlying);
1197*e985b929SDavid van Moolenbroek 				bev_ssl->underlying = NULL;
1198*e985b929SDavid van Moolenbroek 			}
1199*e985b929SDavid van Moolenbroek 		} else {
1200*e985b929SDavid van Moolenbroek 			evutil_socket_t fd = -1;
1201*e985b929SDavid van Moolenbroek 			BIO *bio = SSL_get_wbio(bev_ssl->ssl);
1202*e985b929SDavid van Moolenbroek 			if (bio)
1203*e985b929SDavid van Moolenbroek 				fd = BIO_get_fd(bio, NULL);
1204*e985b929SDavid van Moolenbroek 			if (fd >= 0)
1205*e985b929SDavid van Moolenbroek 				evutil_closesocket(fd);
1206*e985b929SDavid van Moolenbroek 		}
1207*e985b929SDavid van Moolenbroek 		SSL_free(bev_ssl->ssl);
1208*e985b929SDavid van Moolenbroek 	} else {
1209*e985b929SDavid van Moolenbroek 		if (bev_ssl->underlying) {
1210*e985b929SDavid van Moolenbroek 			if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
1211*e985b929SDavid van Moolenbroek 				bufferevent_setcb(bev_ssl->underlying,
1212*e985b929SDavid van Moolenbroek 				    NULL,NULL,NULL,NULL);
1213*e985b929SDavid van Moolenbroek 			bufferevent_unsuspend_read(bev_ssl->underlying,
1214*e985b929SDavid van Moolenbroek 			    BEV_SUSPEND_FILT_READ);
1215*e985b929SDavid van Moolenbroek 		}
1216*e985b929SDavid van Moolenbroek 	}
1217*e985b929SDavid van Moolenbroek }
1218*e985b929SDavid van Moolenbroek 
1219*e985b929SDavid van Moolenbroek static int
be_openssl_adj_timeouts(struct bufferevent * bev)1220*e985b929SDavid van Moolenbroek be_openssl_adj_timeouts(struct bufferevent *bev)
1221*e985b929SDavid van Moolenbroek {
1222*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bev);
1223*e985b929SDavid van Moolenbroek 
1224*e985b929SDavid van Moolenbroek 	if (bev_ssl->underlying)
1225*e985b929SDavid van Moolenbroek 		return _bufferevent_generic_adj_timeouts(bev);
1226*e985b929SDavid van Moolenbroek 	else {
1227*e985b929SDavid van Moolenbroek 		int r1=0, r2=0;
1228*e985b929SDavid van Moolenbroek 		if (event_pending(&bev->ev_read, EV_READ, NULL))
1229*e985b929SDavid van Moolenbroek 			r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
1230*e985b929SDavid van Moolenbroek 		if (event_pending(&bev->ev_write, EV_WRITE, NULL))
1231*e985b929SDavid van Moolenbroek 			r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
1232*e985b929SDavid van Moolenbroek 		return (r1<0 || r2<0) ? -1 : 0;
1233*e985b929SDavid van Moolenbroek 	}
1234*e985b929SDavid van Moolenbroek }
1235*e985b929SDavid van Moolenbroek 
1236*e985b929SDavid van Moolenbroek static int
be_openssl_flush(struct bufferevent * bufev,short iotype,enum bufferevent_flush_mode mode)1237*e985b929SDavid van Moolenbroek be_openssl_flush(struct bufferevent *bufev,
1238*e985b929SDavid van Moolenbroek     short iotype, enum bufferevent_flush_mode mode)
1239*e985b929SDavid van Moolenbroek {
1240*e985b929SDavid van Moolenbroek 	/* XXXX Implement this. */
1241*e985b929SDavid van Moolenbroek 	return 0;
1242*e985b929SDavid van Moolenbroek }
1243*e985b929SDavid van Moolenbroek 
1244*e985b929SDavid van Moolenbroek static int
be_openssl_ctrl(struct bufferevent * bev,enum bufferevent_ctrl_op op,union bufferevent_ctrl_data * data)1245*e985b929SDavid van Moolenbroek be_openssl_ctrl(struct bufferevent *bev,
1246*e985b929SDavid van Moolenbroek     enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
1247*e985b929SDavid van Moolenbroek {
1248*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bev);
1249*e985b929SDavid van Moolenbroek 	switch (op) {
1250*e985b929SDavid van Moolenbroek 	case BEV_CTRL_SET_FD:
1251*e985b929SDavid van Moolenbroek 		if (bev_ssl->underlying)
1252*e985b929SDavid van Moolenbroek 			return -1;
1253*e985b929SDavid van Moolenbroek 		{
1254*e985b929SDavid van Moolenbroek 			BIO *bio;
1255*e985b929SDavid van Moolenbroek 			bio = BIO_new_socket(data->fd, 0);
1256*e985b929SDavid van Moolenbroek 			SSL_set_bio(bev_ssl->ssl, bio, bio);
1257*e985b929SDavid van Moolenbroek 			bev_ssl->fd_is_set = 1;
1258*e985b929SDavid van Moolenbroek 		}
1259*e985b929SDavid van Moolenbroek 		if (bev_ssl->state == BUFFEREVENT_SSL_OPEN)
1260*e985b929SDavid van Moolenbroek 			return set_open_callbacks(bev_ssl, data->fd);
1261*e985b929SDavid van Moolenbroek 		else {
1262*e985b929SDavid van Moolenbroek 			return set_handshake_callbacks(bev_ssl, data->fd);
1263*e985b929SDavid van Moolenbroek 		}
1264*e985b929SDavid van Moolenbroek 	case BEV_CTRL_GET_FD:
1265*e985b929SDavid van Moolenbroek 		if (bev_ssl->underlying)
1266*e985b929SDavid van Moolenbroek 			return -1;
1267*e985b929SDavid van Moolenbroek 		if (!bev_ssl->fd_is_set)
1268*e985b929SDavid van Moolenbroek 			return -1;
1269*e985b929SDavid van Moolenbroek 		data->fd = event_get_fd(&bev->ev_read);
1270*e985b929SDavid van Moolenbroek 		return 0;
1271*e985b929SDavid van Moolenbroek 	case BEV_CTRL_GET_UNDERLYING:
1272*e985b929SDavid van Moolenbroek 		if (!bev_ssl->underlying)
1273*e985b929SDavid van Moolenbroek 			return -1;
1274*e985b929SDavid van Moolenbroek 		data->ptr = bev_ssl->underlying;
1275*e985b929SDavid van Moolenbroek 		return 0;
1276*e985b929SDavid van Moolenbroek 	case BEV_CTRL_CANCEL_ALL:
1277*e985b929SDavid van Moolenbroek 	default:
1278*e985b929SDavid van Moolenbroek 		return -1;
1279*e985b929SDavid van Moolenbroek 	}
1280*e985b929SDavid van Moolenbroek }
1281*e985b929SDavid van Moolenbroek 
1282*e985b929SDavid van Moolenbroek SSL *
bufferevent_openssl_get_ssl(struct bufferevent * bufev)1283*e985b929SDavid van Moolenbroek bufferevent_openssl_get_ssl(struct bufferevent *bufev)
1284*e985b929SDavid van Moolenbroek {
1285*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = upcast(bufev);
1286*e985b929SDavid van Moolenbroek 	if (!bev_ssl)
1287*e985b929SDavid van Moolenbroek 		return NULL;
1288*e985b929SDavid van Moolenbroek 	return bev_ssl->ssl;
1289*e985b929SDavid van Moolenbroek }
1290*e985b929SDavid van Moolenbroek 
1291*e985b929SDavid van Moolenbroek 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)1292*e985b929SDavid van Moolenbroek bufferevent_openssl_new_impl(struct event_base *base,
1293*e985b929SDavid van Moolenbroek     struct bufferevent *underlying,
1294*e985b929SDavid van Moolenbroek     evutil_socket_t fd,
1295*e985b929SDavid van Moolenbroek     SSL *ssl,
1296*e985b929SDavid van Moolenbroek     enum bufferevent_ssl_state state,
1297*e985b929SDavid van Moolenbroek     int options)
1298*e985b929SDavid van Moolenbroek {
1299*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl = NULL;
1300*e985b929SDavid van Moolenbroek 	struct bufferevent_private *bev_p = NULL;
1301*e985b929SDavid van Moolenbroek 	int tmp_options = options & ~BEV_OPT_THREADSAFE;
1302*e985b929SDavid van Moolenbroek 
1303*e985b929SDavid van Moolenbroek 	if (underlying != NULL && fd >= 0)
1304*e985b929SDavid van Moolenbroek 		return NULL; /* Only one can be set. */
1305*e985b929SDavid van Moolenbroek 
1306*e985b929SDavid van Moolenbroek 	if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
1307*e985b929SDavid van Moolenbroek 		goto err;
1308*e985b929SDavid van Moolenbroek 
1309*e985b929SDavid van Moolenbroek 	bev_p = &bev_ssl->bev;
1310*e985b929SDavid van Moolenbroek 
1311*e985b929SDavid van Moolenbroek 	if (bufferevent_init_common(bev_p, base,
1312*e985b929SDavid van Moolenbroek 		&bufferevent_ops_openssl, tmp_options) < 0)
1313*e985b929SDavid van Moolenbroek 		goto err;
1314*e985b929SDavid van Moolenbroek 
1315*e985b929SDavid van Moolenbroek 	/* Don't explode if we decide to realloc a chunk we're writing from in
1316*e985b929SDavid van Moolenbroek 	 * the output buffer. */
1317*e985b929SDavid van Moolenbroek 	SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
1318*e985b929SDavid van Moolenbroek 
1319*e985b929SDavid van Moolenbroek 	bev_ssl->underlying = underlying;
1320*e985b929SDavid van Moolenbroek 	bev_ssl->ssl = ssl;
1321*e985b929SDavid van Moolenbroek 
1322*e985b929SDavid van Moolenbroek 	bev_ssl->outbuf_cb = evbuffer_add_cb(bev_p->bev.output,
1323*e985b929SDavid van Moolenbroek 	    be_openssl_outbuf_cb, bev_ssl);
1324*e985b929SDavid van Moolenbroek 
1325*e985b929SDavid van Moolenbroek 	if (options & BEV_OPT_THREADSAFE)
1326*e985b929SDavid van Moolenbroek 		bufferevent_enable_locking(&bev_ssl->bev.bev, NULL);
1327*e985b929SDavid van Moolenbroek 
1328*e985b929SDavid van Moolenbroek 	if (underlying) {
1329*e985b929SDavid van Moolenbroek 		_bufferevent_init_generic_timeout_cbs(&bev_ssl->bev.bev);
1330*e985b929SDavid van Moolenbroek 		bufferevent_incref(underlying);
1331*e985b929SDavid van Moolenbroek 	}
1332*e985b929SDavid van Moolenbroek 
1333*e985b929SDavid van Moolenbroek 	bev_ssl->state = state;
1334*e985b929SDavid van Moolenbroek 	bev_ssl->last_write = -1;
1335*e985b929SDavid van Moolenbroek 
1336*e985b929SDavid van Moolenbroek 	init_bio_counts(bev_ssl);
1337*e985b929SDavid van Moolenbroek 
1338*e985b929SDavid van Moolenbroek 	switch (state) {
1339*e985b929SDavid van Moolenbroek 	case BUFFEREVENT_SSL_ACCEPTING:
1340*e985b929SDavid van Moolenbroek 		SSL_set_accept_state(bev_ssl->ssl);
1341*e985b929SDavid van Moolenbroek 		if (set_handshake_callbacks(bev_ssl, fd) < 0)
1342*e985b929SDavid van Moolenbroek 			goto err;
1343*e985b929SDavid van Moolenbroek 		break;
1344*e985b929SDavid van Moolenbroek 	case BUFFEREVENT_SSL_CONNECTING:
1345*e985b929SDavid van Moolenbroek 		SSL_set_connect_state(bev_ssl->ssl);
1346*e985b929SDavid van Moolenbroek 		if (set_handshake_callbacks(bev_ssl, fd) < 0)
1347*e985b929SDavid van Moolenbroek 			goto err;
1348*e985b929SDavid van Moolenbroek 		break;
1349*e985b929SDavid van Moolenbroek 	case BUFFEREVENT_SSL_OPEN:
1350*e985b929SDavid van Moolenbroek 		if (set_open_callbacks(bev_ssl, fd) < 0)
1351*e985b929SDavid van Moolenbroek 			goto err;
1352*e985b929SDavid van Moolenbroek 		break;
1353*e985b929SDavid van Moolenbroek 	default:
1354*e985b929SDavid van Moolenbroek 		goto err;
1355*e985b929SDavid van Moolenbroek 	}
1356*e985b929SDavid van Moolenbroek 
1357*e985b929SDavid van Moolenbroek 	if (underlying) {
1358*e985b929SDavid van Moolenbroek 		bufferevent_setwatermark(underlying, EV_READ, 0, 0);
1359*e985b929SDavid van Moolenbroek 		bufferevent_enable(underlying, EV_READ|EV_WRITE);
1360*e985b929SDavid van Moolenbroek 		if (state == BUFFEREVENT_SSL_OPEN)
1361*e985b929SDavid van Moolenbroek 			bufferevent_suspend_read(underlying,
1362*e985b929SDavid van Moolenbroek 			    BEV_SUSPEND_FILT_READ);
1363*e985b929SDavid van Moolenbroek 	} else {
1364*e985b929SDavid van Moolenbroek 		bev_ssl->bev.bev.enabled = EV_READ|EV_WRITE;
1365*e985b929SDavid van Moolenbroek 		if (bev_ssl->fd_is_set) {
1366*e985b929SDavid van Moolenbroek 			if (state != BUFFEREVENT_SSL_OPEN)
1367*e985b929SDavid van Moolenbroek 				if (event_add(&bev_ssl->bev.bev.ev_read, NULL) < 0)
1368*e985b929SDavid van Moolenbroek 					goto err;
1369*e985b929SDavid van Moolenbroek 			if (event_add(&bev_ssl->bev.bev.ev_write, NULL) < 0)
1370*e985b929SDavid van Moolenbroek 				goto err;
1371*e985b929SDavid van Moolenbroek 		}
1372*e985b929SDavid van Moolenbroek 	}
1373*e985b929SDavid van Moolenbroek 
1374*e985b929SDavid van Moolenbroek 	return &bev_ssl->bev.bev;
1375*e985b929SDavid van Moolenbroek err:
1376*e985b929SDavid van Moolenbroek 	if (bev_ssl)
1377*e985b929SDavid van Moolenbroek 		bufferevent_free(&bev_ssl->bev.bev);
1378*e985b929SDavid van Moolenbroek 	return NULL;
1379*e985b929SDavid van Moolenbroek }
1380*e985b929SDavid van Moolenbroek 
1381*e985b929SDavid van Moolenbroek struct bufferevent *
bufferevent_openssl_filter_new(struct event_base * base,struct bufferevent * underlying,SSL * ssl,enum bufferevent_ssl_state state,int options)1382*e985b929SDavid van Moolenbroek bufferevent_openssl_filter_new(struct event_base *base,
1383*e985b929SDavid van Moolenbroek     struct bufferevent *underlying,
1384*e985b929SDavid van Moolenbroek     SSL *ssl,
1385*e985b929SDavid van Moolenbroek     enum bufferevent_ssl_state state,
1386*e985b929SDavid van Moolenbroek     int options)
1387*e985b929SDavid van Moolenbroek {
1388*e985b929SDavid van Moolenbroek 	/* We don't tell the BIO to close the bufferevent; we do it ourselves
1389*e985b929SDavid van Moolenbroek 	 * on be_openssl_destruct */
1390*e985b929SDavid van Moolenbroek 	int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
1391*e985b929SDavid van Moolenbroek 	BIO *bio;
1392*e985b929SDavid van Moolenbroek 	if (!underlying)
1393*e985b929SDavid van Moolenbroek 		return NULL;
1394*e985b929SDavid van Moolenbroek 	if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
1395*e985b929SDavid van Moolenbroek 		return NULL;
1396*e985b929SDavid van Moolenbroek 
1397*e985b929SDavid van Moolenbroek 	SSL_set_bio(ssl, bio, bio);
1398*e985b929SDavid van Moolenbroek 
1399*e985b929SDavid van Moolenbroek 	return bufferevent_openssl_new_impl(
1400*e985b929SDavid van Moolenbroek 		base, underlying, -1, ssl, state, options);
1401*e985b929SDavid van Moolenbroek }
1402*e985b929SDavid van Moolenbroek 
1403*e985b929SDavid van Moolenbroek struct bufferevent *
bufferevent_openssl_socket_new(struct event_base * base,evutil_socket_t fd,SSL * ssl,enum bufferevent_ssl_state state,int options)1404*e985b929SDavid van Moolenbroek bufferevent_openssl_socket_new(struct event_base *base,
1405*e985b929SDavid van Moolenbroek     evutil_socket_t fd,
1406*e985b929SDavid van Moolenbroek     SSL *ssl,
1407*e985b929SDavid van Moolenbroek     enum bufferevent_ssl_state state,
1408*e985b929SDavid van Moolenbroek     int options)
1409*e985b929SDavid van Moolenbroek {
1410*e985b929SDavid van Moolenbroek 	/* Does the SSL already have an fd? */
1411*e985b929SDavid van Moolenbroek 	BIO *bio = SSL_get_wbio(ssl);
1412*e985b929SDavid van Moolenbroek 	long have_fd = -1;
1413*e985b929SDavid van Moolenbroek 
1414*e985b929SDavid van Moolenbroek 	if (bio)
1415*e985b929SDavid van Moolenbroek 		have_fd = BIO_get_fd(bio, NULL);
1416*e985b929SDavid van Moolenbroek 
1417*e985b929SDavid van Moolenbroek 	if (have_fd >= 0) {
1418*e985b929SDavid van Moolenbroek 		/* The SSL is already configured with an fd. */
1419*e985b929SDavid van Moolenbroek 		if (fd < 0) {
1420*e985b929SDavid van Moolenbroek 			/* We should learn the fd from the SSL. */
1421*e985b929SDavid van Moolenbroek 			fd = (evutil_socket_t) have_fd;
1422*e985b929SDavid van Moolenbroek 		} else if (have_fd == (long)fd) {
1423*e985b929SDavid van Moolenbroek 			/* We already know the fd from the SSL; do nothing */
1424*e985b929SDavid van Moolenbroek 		} else {
1425*e985b929SDavid van Moolenbroek 			/* We specified an fd different from that of the SSL.
1426*e985b929SDavid van Moolenbroek 			   This is probably an error on our part.  Fail. */
1427*e985b929SDavid van Moolenbroek 			return NULL;
1428*e985b929SDavid van Moolenbroek 		}
1429*e985b929SDavid van Moolenbroek 		(void) BIO_set_close(bio, 0);
1430*e985b929SDavid van Moolenbroek 	} else {
1431*e985b929SDavid van Moolenbroek 		/* The SSL isn't configured with a BIO with an fd. */
1432*e985b929SDavid van Moolenbroek 		if (fd >= 0) {
1433*e985b929SDavid van Moolenbroek 			/* ... and we have an fd we want to use. */
1434*e985b929SDavid van Moolenbroek 			bio = BIO_new_socket(fd, 0);
1435*e985b929SDavid van Moolenbroek 			SSL_set_bio(ssl, bio, bio);
1436*e985b929SDavid van Moolenbroek 		} else {
1437*e985b929SDavid van Moolenbroek 			/* Leave the fd unset. */
1438*e985b929SDavid van Moolenbroek 		}
1439*e985b929SDavid van Moolenbroek 	}
1440*e985b929SDavid van Moolenbroek 
1441*e985b929SDavid van Moolenbroek 	return bufferevent_openssl_new_impl(
1442*e985b929SDavid van Moolenbroek 		base, NULL, fd, ssl, state, options);
1443*e985b929SDavid van Moolenbroek }
1444*e985b929SDavid van Moolenbroek 
1445*e985b929SDavid van Moolenbroek unsigned long
bufferevent_get_openssl_error(struct bufferevent * bev)1446*e985b929SDavid van Moolenbroek bufferevent_get_openssl_error(struct bufferevent *bev)
1447*e985b929SDavid van Moolenbroek {
1448*e985b929SDavid van Moolenbroek 	unsigned long err = 0;
1449*e985b929SDavid van Moolenbroek 	struct bufferevent_openssl *bev_ssl;
1450*e985b929SDavid van Moolenbroek 	BEV_LOCK(bev);
1451*e985b929SDavid van Moolenbroek 	bev_ssl = upcast(bev);
1452*e985b929SDavid van Moolenbroek 	if (bev_ssl && bev_ssl->n_errors) {
1453*e985b929SDavid van Moolenbroek 		err = bev_ssl->errors[--bev_ssl->n_errors];
1454*e985b929SDavid van Moolenbroek 	}
1455*e985b929SDavid van Moolenbroek 	BEV_UNLOCK(bev);
1456*e985b929SDavid van Moolenbroek 	return err;
1457*e985b929SDavid van Moolenbroek }
1458