Blame libevent/bufferevent_openssl.c

Packit e9ba0d
/*
Packit e9ba0d
 * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
Packit e9ba0d
 *
Packit e9ba0d
 * Redistribution and use in source and binary forms, with or without
Packit e9ba0d
 * modification, are permitted provided that the following conditions
Packit e9ba0d
 * are met:
Packit e9ba0d
 * 1. Redistributions of source code must retain the above copyright
Packit e9ba0d
 *    notice, this list of conditions and the following disclaimer.
Packit e9ba0d
 * 2. Redistributions in binary form must reproduce the above copyright
Packit e9ba0d
 *    notice, this list of conditions and the following disclaimer in the
Packit e9ba0d
 *    documentation and/or other materials provided with the distribution.
Packit e9ba0d
 * 3. The name of the author may not be used to endorse or promote products
Packit e9ba0d
 *    derived from this software without specific prior written permission.
Packit e9ba0d
 *
Packit e9ba0d
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Packit e9ba0d
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit e9ba0d
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit e9ba0d
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit e9ba0d
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit e9ba0d
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit e9ba0d
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit e9ba0d
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit e9ba0d
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit e9ba0d
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
#include <sys/types.h>
Packit e9ba0d
Packit e9ba0d
#include "event2/event-config.h"
Packit e9ba0d
Packit e9ba0d
#ifdef _EVENT_HAVE_SYS_TIME_H
Packit e9ba0d
#include <sys/time.h>
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#include <errno.h>
Packit e9ba0d
#include <stdio.h>
Packit e9ba0d
#include <stdlib.h>
Packit e9ba0d
#include <string.h>
Packit e9ba0d
#ifdef _EVENT_HAVE_STDARG_H
Packit e9ba0d
#include <stdarg.h>
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_UNISTD_H
Packit e9ba0d
#include <unistd.h>
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
#include <winsock2.h>
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#include "event2/bufferevent.h"
Packit e9ba0d
#include "event2/bufferevent_struct.h"
Packit e9ba0d
#include "event2/bufferevent_ssl.h"
Packit e9ba0d
#include "event2/buffer.h"
Packit e9ba0d
#include "event2/event.h"
Packit e9ba0d
Packit e9ba0d
#include "mm-internal.h"
Packit e9ba0d
#include "bufferevent-internal.h"
Packit e9ba0d
#include "log-internal.h"
Packit e9ba0d
Packit e9ba0d
#include <openssl/bio.h>
Packit e9ba0d
#include <openssl/ssl.h>
Packit e9ba0d
#include <openssl/err.h>
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * Define an OpenSSL bio that targets a bufferevent.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
/* --------------------
Packit e9ba0d
   A BIO is an OpenSSL abstraction that handles reading and writing data.  The
Packit e9ba0d
   library will happily speak SSL over anything that implements a BIO
Packit e9ba0d
   interface.
Packit e9ba0d
Packit e9ba0d
   Here we define a BIO implementation that directs its output to a
Packit e9ba0d
   bufferevent.  We'll want to use this only when none of OpenSSL's built-in
Packit e9ba0d
   IO mechanisms work for us.
Packit e9ba0d
   -------------------- */
Packit e9ba0d
Packit e9ba0d
/* every BIO type needs its own integer type value. */
Packit e9ba0d
#define BIO_TYPE_LIBEVENT 57
Packit e9ba0d
/* ???? Arguably, we should set BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK on
Packit e9ba0d
 * this. */
Packit e9ba0d
Packit e9ba0d
#if 0
Packit e9ba0d
static void
Packit e9ba0d
print_err(int val)
Packit e9ba0d
{
Packit e9ba0d
	int err;
Packit e9ba0d
	printf("Error was %d\n", val);
Packit e9ba0d
Packit e9ba0d
	while ((err = ERR_get_error())) {
Packit e9ba0d
		const char *msg = (const char*)ERR_reason_error_string(err);
Packit e9ba0d
		const char *lib = (const char*)ERR_lib_error_string(err);
Packit e9ba0d
		const char *func = (const char*)ERR_func_error_string(err);
Packit e9ba0d
Packit e9ba0d
		printf("%s in %s %s\n", msg, lib, func);
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
#else
Packit e9ba0d
#define print_err(v) ((void)0)
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
/* Called to initialize a new BIO */
Packit e9ba0d
static int
Packit e9ba0d
bio_bufferevent_new(BIO *b)
Packit e9ba0d
{
Packit e9ba0d
	b->init = 0;
Packit e9ba0d
	b->num = -1;
Packit e9ba0d
	b->ptr = NULL; /* We'll be putting the bufferevent in this field.*/
Packit e9ba0d
	b->flags = 0;
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Called to uninitialize the BIO. */
Packit e9ba0d
static int
Packit e9ba0d
bio_bufferevent_free(BIO *b)
Packit e9ba0d
{
Packit e9ba0d
	if (!b)
Packit e9ba0d
		return 0;
Packit e9ba0d
	if (b->shutdown) {
Packit e9ba0d
		if (b->init && b->ptr)
Packit e9ba0d
			bufferevent_free(b->ptr);
Packit e9ba0d
		b->init = 0;
Packit e9ba0d
		b->flags = 0;
Packit e9ba0d
		b->ptr = NULL;
Packit e9ba0d
	}
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Called to extract data from the BIO. */
Packit e9ba0d
static int
Packit e9ba0d
bio_bufferevent_read(BIO *b, char *out, int outlen)
Packit e9ba0d
{
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	struct evbuffer *input;
Packit e9ba0d
Packit e9ba0d
	BIO_clear_retry_flags(b);
Packit e9ba0d
Packit e9ba0d
	if (!out)
Packit e9ba0d
		return 0;
Packit e9ba0d
	if (!b->ptr)
Packit e9ba0d
		return -1;
Packit e9ba0d
Packit e9ba0d
	input = bufferevent_get_input(b->ptr);
Packit e9ba0d
	if (evbuffer_get_length(input) == 0) {
Packit e9ba0d
		/* If there's no data to read, say so. */
Packit e9ba0d
		BIO_set_retry_read(b);
Packit e9ba0d
		return -1;
Packit e9ba0d
	} else {
Packit e9ba0d
		r = evbuffer_remove(input, out, outlen);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Called to write data info the BIO */
Packit e9ba0d
static int
Packit e9ba0d
bio_bufferevent_write(BIO *b, const char *in, int inlen)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent *bufev = b->ptr;
Packit e9ba0d
	struct evbuffer *output;
Packit e9ba0d
	size_t outlen;
Packit e9ba0d
Packit e9ba0d
	BIO_clear_retry_flags(b);
Packit e9ba0d
Packit e9ba0d
	if (!b->ptr)
Packit e9ba0d
		return -1;
Packit e9ba0d
Packit e9ba0d
	output = bufferevent_get_output(bufev);
Packit e9ba0d
	outlen = evbuffer_get_length(output);
Packit e9ba0d
Packit e9ba0d
	/* Copy only as much data onto the output buffer as can fit under the
Packit e9ba0d
	 * high-water mark. */
Packit e9ba0d
	if (bufev->wm_write.high && bufev->wm_write.high <= (outlen+inlen)) {
Packit e9ba0d
		if (bufev->wm_write.high <= outlen) {
Packit e9ba0d
			/* If no data can fit, we'll need to retry later. */
Packit e9ba0d
			BIO_set_retry_write(b);
Packit e9ba0d
			return -1;
Packit e9ba0d
		}
Packit e9ba0d
		inlen = bufev->wm_write.high - outlen;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(inlen > 0);
Packit e9ba0d
	evbuffer_add(output, in, inlen);
Packit e9ba0d
	return inlen;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Called to handle various requests */
Packit e9ba0d
static long
Packit e9ba0d
bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent *bufev = b->ptr;
Packit e9ba0d
	long ret = 1;
Packit e9ba0d
Packit e9ba0d
	switch (cmd) {
Packit e9ba0d
	case BIO_CTRL_GET_CLOSE:
Packit e9ba0d
		ret = b->shutdown;
Packit e9ba0d
		break;
Packit e9ba0d
	case BIO_CTRL_SET_CLOSE:
Packit e9ba0d
		b->shutdown = (int)num;
Packit e9ba0d
		break;
Packit e9ba0d
	case BIO_CTRL_PENDING:
Packit e9ba0d
		ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
Packit e9ba0d
		break;
Packit e9ba0d
	case BIO_CTRL_WPENDING:
Packit e9ba0d
		ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0;
Packit e9ba0d
		break;
Packit e9ba0d
	/* XXXX These two are given a special-case treatment because
Packit e9ba0d
	 * of cargo-cultism.  I should come up with a better reason. */
Packit e9ba0d
	case BIO_CTRL_DUP:
Packit e9ba0d
	case BIO_CTRL_FLUSH:
Packit e9ba0d
		ret = 1;
Packit e9ba0d
		break;
Packit e9ba0d
	default:
Packit e9ba0d
		ret = 0;
Packit e9ba0d
		break;
Packit e9ba0d
	}
Packit e9ba0d
	return ret;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Called to write a string to the BIO */
Packit e9ba0d
static int
Packit e9ba0d
bio_bufferevent_puts(BIO *b, const char *s)
Packit e9ba0d
{
Packit e9ba0d
	return bio_bufferevent_write(b, s, strlen(s));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Method table for the bufferevent BIO */
Packit e9ba0d
static BIO_METHOD methods_bufferevent = {
Packit e9ba0d
	BIO_TYPE_LIBEVENT, "bufferevent",
Packit e9ba0d
	bio_bufferevent_write,
Packit e9ba0d
	bio_bufferevent_read,
Packit e9ba0d
	bio_bufferevent_puts,
Packit e9ba0d
	NULL /* bio_bufferevent_gets */,
Packit e9ba0d
	bio_bufferevent_ctrl,
Packit e9ba0d
	bio_bufferevent_new,
Packit e9ba0d
	bio_bufferevent_free,
Packit e9ba0d
	NULL /* callback_ctrl */,
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
/* Return the method table for the bufferevents BIO */
Packit e9ba0d
static BIO_METHOD *
Packit e9ba0d
BIO_s_bufferevent(void)
Packit e9ba0d
{
Packit e9ba0d
	return &methods_bufferevent;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Create a new BIO to wrap communication around a bufferevent.  If close_flag
Packit e9ba0d
 * is true, the bufferevent will be freed when the BIO is closed. */
Packit e9ba0d
static BIO *
Packit e9ba0d
BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
Packit e9ba0d
{
Packit e9ba0d
	BIO *result;
Packit e9ba0d
	if (!bufferevent)
Packit e9ba0d
		return NULL;
Packit e9ba0d
	if (!(result = BIO_new(BIO_s_bufferevent())))
Packit e9ba0d
		return NULL;
Packit e9ba0d
	result->init = 1;
Packit e9ba0d
	result->ptr = bufferevent;
Packit e9ba0d
	result->shutdown = close_flag ? 1 : 0;
Packit e9ba0d
	return result;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* --------------------
Packit e9ba0d
   Now, here's the OpenSSL-based implementation of bufferevent.
Packit e9ba0d
Packit e9ba0d
   The implementation comes in two flavors: one that connects its SSL object
Packit e9ba0d
   to an underlying bufferevent using a BIO_bufferevent, and one that has the
Packit e9ba0d
   SSL object connect to a socket directly.  The latter should generally be
Packit e9ba0d
   faster, except on Windows, where your best bet is using a
Packit e9ba0d
   bufferevent_async.
Packit e9ba0d
Packit e9ba0d
   (OpenSSL supports many other BIO types, too.  But we can't use any unless
Packit e9ba0d
   we have a good way to get notified when they become readable/writable.)
Packit e9ba0d
   -------------------- */
Packit e9ba0d
Packit e9ba0d
struct bio_data_counts {
Packit e9ba0d
	unsigned long n_written;
Packit e9ba0d
	unsigned long n_read;
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
struct bufferevent_openssl {
Packit e9ba0d
	/* Shared fields with common bufferevent implementation code.
Packit e9ba0d
	   If we were set up with an underlying bufferevent, we use the
Packit e9ba0d
	   events here as timers only.  If we have an SSL, then we use
Packit e9ba0d
	   the events as socket events.
Packit e9ba0d
	 */
Packit e9ba0d
	struct bufferevent_private bev;
Packit e9ba0d
	/* An underlying bufferevent that we're directing our output to.
Packit e9ba0d
	   If it's NULL, then we're connected to an fd, not an evbuffer. */
Packit e9ba0d
	struct bufferevent *underlying;
Packit e9ba0d
	/* The SSL object doing our encryption. */
Packit e9ba0d
	SSL *ssl;
Packit e9ba0d
Packit e9ba0d
	/* A callback that's invoked when data arrives on our outbuf so we
Packit e9ba0d
	   know to write data to the SSL. */
Packit e9ba0d
	struct evbuffer_cb_entry *outbuf_cb;
Packit e9ba0d
Packit e9ba0d
	/* A count of how much data the bios have read/written total.  Used
Packit e9ba0d
	   for rate-limiting. */
Packit e9ba0d
	struct bio_data_counts counts;
Packit e9ba0d
Packit e9ba0d
	/* If this value is greater than 0, then the last SSL_write blocked,
Packit e9ba0d
	 * and we need to try it again with this many bytes. */
Packit e9ba0d
	ev_ssize_t last_write;
Packit e9ba0d
Packit e9ba0d
#define NUM_ERRORS 3
Packit e9ba0d
	ev_uint32_t errors[NUM_ERRORS];
Packit e9ba0d
Packit e9ba0d
	/* When we next get available space, we should say "read" instead of
Packit e9ba0d
	   "write". This can happen if there's a renegotiation during a read
Packit e9ba0d
	   operation. */
Packit e9ba0d
	unsigned read_blocked_on_write : 1;
Packit e9ba0d
	/* When we next get data, we should say "write" instead of "read". */
Packit e9ba0d
	unsigned write_blocked_on_read : 1;
Packit e9ba0d
	/* XXX */
Packit e9ba0d
	unsigned allow_dirty_shutdown : 1;
Packit e9ba0d
	/* XXXX */
Packit e9ba0d
	unsigned fd_is_set : 1;
Packit e9ba0d
	/* XXX */
Packit e9ba0d
	unsigned n_errors : 2;
Packit e9ba0d
Packit e9ba0d
	/* Are we currently connecting, accepting, or doing IO? */
Packit e9ba0d
	unsigned state : 2;
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
static int be_openssl_enable(struct bufferevent *, short);
Packit e9ba0d
static int be_openssl_disable(struct bufferevent *, short);
Packit e9ba0d
static void be_openssl_destruct(struct bufferevent *);
Packit e9ba0d
static int be_openssl_adj_timeouts(struct bufferevent *);
Packit e9ba0d
static int be_openssl_flush(struct bufferevent *bufev,
Packit e9ba0d
    short iotype, enum bufferevent_flush_mode mode);
Packit e9ba0d
static int be_openssl_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
Packit e9ba0d
Packit e9ba0d
const struct bufferevent_ops bufferevent_ops_openssl = {
Packit e9ba0d
	"ssl",
Packit e9ba0d
	evutil_offsetof(struct bufferevent_openssl, bev.bev),
Packit e9ba0d
	be_openssl_enable,
Packit e9ba0d
	be_openssl_disable,
Packit e9ba0d
	be_openssl_destruct,
Packit e9ba0d
	be_openssl_adj_timeouts,
Packit e9ba0d
	be_openssl_flush,
Packit e9ba0d
	be_openssl_ctrl,
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
/* Given a bufferevent, return a pointer to the bufferevent_openssl that
Packit e9ba0d
 * contains it, if any. */
Packit e9ba0d
static inline struct bufferevent_openssl *
Packit e9ba0d
upcast(struct bufferevent *bev)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_o;
Packit e9ba0d
	if (bev->be_ops != &bufferevent_ops_openssl)
Packit e9ba0d
		return NULL;
Packit e9ba0d
	bev_o = (void*)( ((char*)bev) -
Packit e9ba0d
			 evutil_offsetof(struct bufferevent_openssl, bev.bev));
Packit e9ba0d
	EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
Packit e9ba0d
	return bev_o;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static inline void
Packit e9ba0d
put_error(struct bufferevent_openssl *bev_ssl, unsigned long err)
Packit e9ba0d
{
Packit e9ba0d
	if (bev_ssl->n_errors == NUM_ERRORS)
Packit e9ba0d
		return;
Packit e9ba0d
	/* The error type according to openssl is "unsigned long", but
Packit e9ba0d
	   openssl never uses more than 32 bits of it.  It _can't_ use more
Packit e9ba0d
	   than 32 bits of it, since it needs to report errors on systems
Packit e9ba0d
	   where long is only 32 bits.
Packit e9ba0d
	 */
Packit e9ba0d
	bev_ssl->errors[bev_ssl->n_errors++] = (ev_uint32_t) err;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Have the base communications channel (either the underlying bufferevent or
Packit e9ba0d
 * ev_read and ev_write) start reading.  Take the read-blocked-on-write flag
Packit e9ba0d
 * into account. */
Packit e9ba0d
static int
Packit e9ba0d
start_reading(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		bufferevent_unsuspend_read(bev_ssl->underlying,
Packit e9ba0d
		    BEV_SUSPEND_FILT_READ);
Packit e9ba0d
		return 0;
Packit e9ba0d
	} else {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		int r;
Packit e9ba0d
		r = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
Packit e9ba0d
		if (r == 0 && bev_ssl->read_blocked_on_write)
Packit e9ba0d
			r = _bufferevent_add_event(&bev->ev_write,
Packit e9ba0d
			    &bev->timeout_write);
Packit e9ba0d
		return r;
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Have the base communications channel (either the underlying bufferevent or
Packit e9ba0d
 * ev_read and ev_write) start writing.  Take the write-blocked-on-read flag
Packit e9ba0d
 * into account. */
Packit e9ba0d
static int
Packit e9ba0d
start_writing(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		;
Packit e9ba0d
	} else {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		r = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
Packit e9ba0d
		if (!r && bev_ssl->write_blocked_on_read)
Packit e9ba0d
			r = _bufferevent_add_event(&bev->ev_read,
Packit e9ba0d
			    &bev->timeout_read);
Packit e9ba0d
	}
Packit e9ba0d
	return r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
stop_reading(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	if (bev_ssl->write_blocked_on_read)
Packit e9ba0d
		return;
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		bufferevent_suspend_read(bev_ssl->underlying,
Packit e9ba0d
		    BEV_SUSPEND_FILT_READ);
Packit e9ba0d
	} else {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		event_del(&bev->ev_read);
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
stop_writing(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	if (bev_ssl->read_blocked_on_write)
Packit e9ba0d
		return;
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		;
Packit e9ba0d
	} else {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		event_del(&bev->ev_write);
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
set_rbow(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	if (!bev_ssl->underlying)
Packit e9ba0d
		stop_reading(bev_ssl);
Packit e9ba0d
	bev_ssl->read_blocked_on_write = 1;
Packit e9ba0d
	return start_writing(bev_ssl);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
set_wbor(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	if (!bev_ssl->underlying)
Packit e9ba0d
		stop_writing(bev_ssl);
Packit e9ba0d
	bev_ssl->write_blocked_on_read = 1;
Packit e9ba0d
	return start_reading(bev_ssl);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
clear_rbow(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	bev_ssl->read_blocked_on_write = 0;
Packit e9ba0d
	if (!(bev->enabled & EV_WRITE))
Packit e9ba0d
		stop_writing(bev_ssl);
Packit e9ba0d
	if (bev->enabled & EV_READ)
Packit e9ba0d
		r = start_reading(bev_ssl);
Packit e9ba0d
	return r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
clear_wbor(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	bev_ssl->write_blocked_on_read = 0;
Packit e9ba0d
	if (!(bev->enabled & EV_READ))
Packit e9ba0d
		stop_reading(bev_ssl);
Packit e9ba0d
	if (bev->enabled & EV_WRITE)
Packit e9ba0d
		r = start_writing(bev_ssl);
Packit e9ba0d
	return r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
conn_closed(struct bufferevent_openssl *bev_ssl, int errcode, int ret)
Packit e9ba0d
{
Packit e9ba0d
	int event = BEV_EVENT_ERROR;
Packit e9ba0d
	int dirty_shutdown = 0;
Packit e9ba0d
	unsigned long err;
Packit e9ba0d
Packit e9ba0d
	switch (errcode) {
Packit e9ba0d
	case SSL_ERROR_ZERO_RETURN:
Packit e9ba0d
		/* Possibly a clean shutdown. */
Packit e9ba0d
		if (SSL_get_shutdown(bev_ssl->ssl) & SSL_RECEIVED_SHUTDOWN)
Packit e9ba0d
			event = BEV_EVENT_EOF;
Packit e9ba0d
		else
Packit e9ba0d
			dirty_shutdown = 1;
Packit e9ba0d
		break;
Packit e9ba0d
	case SSL_ERROR_SYSCALL:
Packit e9ba0d
		/* IO error; possibly a dirty shutdown. */
Packit e9ba0d
		if (ret == 0 && ERR_peek_error() == 0)
Packit e9ba0d
			dirty_shutdown = 1;
Packit e9ba0d
		break;
Packit e9ba0d
	case SSL_ERROR_SSL:
Packit e9ba0d
		/* Protocol error. */
Packit e9ba0d
		break;
Packit e9ba0d
	case SSL_ERROR_WANT_X509_LOOKUP:
Packit e9ba0d
		/* XXXX handle this. */
Packit e9ba0d
		break;
Packit e9ba0d
	case SSL_ERROR_NONE:
Packit e9ba0d
	case SSL_ERROR_WANT_READ:
Packit e9ba0d
	case SSL_ERROR_WANT_WRITE:
Packit e9ba0d
	case SSL_ERROR_WANT_CONNECT:
Packit e9ba0d
	case SSL_ERROR_WANT_ACCEPT:
Packit e9ba0d
	default:
Packit e9ba0d
		/* should be impossible; treat as normal error. */
Packit e9ba0d
		event_warnx("BUG: Unexpected OpenSSL error code %d", errcode);
Packit e9ba0d
		break;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	while ((err = ERR_get_error())) {
Packit e9ba0d
		put_error(bev_ssl, err);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (dirty_shutdown && bev_ssl->allow_dirty_shutdown)
Packit e9ba0d
		event = BEV_EVENT_EOF;
Packit e9ba0d
Packit e9ba0d
	stop_reading(bev_ssl);
Packit e9ba0d
	stop_writing(bev_ssl);
Packit e9ba0d
Packit e9ba0d
	_bufferevent_run_eventcb(&bev_ssl->bev.bev, event);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
init_bio_counts(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	bev_ssl->counts.n_written =
Packit e9ba0d
	    BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
Packit e9ba0d
	bev_ssl->counts.n_read =
Packit e9ba0d
	    BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static inline void
Packit e9ba0d
decrement_buckets(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	unsigned long num_w = BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
Packit e9ba0d
	unsigned long num_r = BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
Packit e9ba0d
	/* These next two subtractions can wrap around. That's okay. */
Packit e9ba0d
	unsigned long w = num_w - bev_ssl->counts.n_written;
Packit e9ba0d
	unsigned long r = num_r - bev_ssl->counts.n_read;
Packit e9ba0d
	if (w)
Packit e9ba0d
		_bufferevent_decrement_write_buckets(&bev_ssl->bev, w);
Packit e9ba0d
	if (r)
Packit e9ba0d
		_bufferevent_decrement_read_buckets(&bev_ssl->bev, r);
Packit e9ba0d
	bev_ssl->counts.n_written = num_w;
Packit e9ba0d
	bev_ssl->counts.n_read = num_r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#define OP_MADE_PROGRESS 1
Packit e9ba0d
#define OP_BLOCKED 2
Packit e9ba0d
#define OP_ERR 4
Packit e9ba0d
Packit e9ba0d
/* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
Packit e9ba0d
   we're now blocked); and OP_ERR (if an error occurred). */
Packit e9ba0d
static int
Packit e9ba0d
do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
Packit e9ba0d
	/* Requires lock */
Packit e9ba0d
	struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
	struct evbuffer *input = bev->input;
Packit e9ba0d
	int r, n, i, n_used = 0, atmost;
Packit e9ba0d
	struct evbuffer_iovec space[2];
Packit e9ba0d
	int result = 0;
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->bev.read_suspended)
Packit e9ba0d
		return 0;
Packit e9ba0d
Packit e9ba0d
	atmost = _bufferevent_get_read_max(&bev_ssl->bev);
Packit e9ba0d
	if (n_to_read > atmost)
Packit e9ba0d
		n_to_read = atmost;
Packit e9ba0d
Packit e9ba0d
	n = evbuffer_reserve_space(input, n_to_read, space, 2);
Packit e9ba0d
	if (n < 0)
Packit e9ba0d
		return OP_ERR;
Packit e9ba0d
Packit e9ba0d
	for (i=0; i
Packit e9ba0d
		if (bev_ssl->bev.read_suspended)
Packit e9ba0d
			break;
Packit e9ba0d
		r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
Packit e9ba0d
		if (r>0) {
Packit e9ba0d
			result |= OP_MADE_PROGRESS;
Packit e9ba0d
			if (bev_ssl->read_blocked_on_write)
Packit e9ba0d
				if (clear_rbow(bev_ssl) < 0)
Packit e9ba0d
					return OP_ERR | result;
Packit e9ba0d
			++n_used;
Packit e9ba0d
			space[i].iov_len = r;
Packit e9ba0d
			decrement_buckets(bev_ssl);
Packit e9ba0d
		} else {
Packit e9ba0d
			int err = SSL_get_error(bev_ssl->ssl, r);
Packit e9ba0d
			print_err(err);
Packit e9ba0d
			switch (err) {
Packit e9ba0d
			case SSL_ERROR_WANT_READ:
Packit e9ba0d
				/* Can't read until underlying has more data. */
Packit e9ba0d
				if (bev_ssl->read_blocked_on_write)
Packit e9ba0d
					if (clear_rbow(bev_ssl) < 0)
Packit e9ba0d
						return OP_ERR | result;
Packit e9ba0d
				break;
Packit e9ba0d
			case SSL_ERROR_WANT_WRITE:
Packit e9ba0d
				/* This read operation requires a write, and the
Packit e9ba0d
				 * underlying is full */
Packit e9ba0d
				if (!bev_ssl->read_blocked_on_write)
Packit e9ba0d
					if (set_rbow(bev_ssl) < 0)
Packit e9ba0d
						return OP_ERR | result;
Packit e9ba0d
				break;
Packit e9ba0d
			default:
Packit e9ba0d
				conn_closed(bev_ssl, err, r);
Packit e9ba0d
				break;
Packit e9ba0d
			}
Packit e9ba0d
			result |= OP_BLOCKED;
Packit e9ba0d
			break; /* out of the loop */
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (n_used) {
Packit e9ba0d
		evbuffer_commit_space(input, space, n_used);
Packit e9ba0d
		if (bev_ssl->underlying)
Packit e9ba0d
			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return result;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
Packit e9ba0d
   we're now blocked); and OP_ERR (if an error occurred). */
Packit e9ba0d
static int
Packit e9ba0d
do_write(struct bufferevent_openssl *bev_ssl, int atmost)
Packit e9ba0d
{
Packit e9ba0d
	int i, r, n, n_written = 0;
Packit e9ba0d
	struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
	struct evbuffer *output = bev->output;
Packit e9ba0d
	struct evbuffer_iovec space[8];
Packit e9ba0d
	int result = 0;
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->last_write > 0)
Packit e9ba0d
		atmost = bev_ssl->last_write;
Packit e9ba0d
	else
Packit e9ba0d
		atmost = _bufferevent_get_write_max(&bev_ssl->bev);
Packit e9ba0d
Packit e9ba0d
	n = evbuffer_peek(output, atmost, NULL, space, 8);
Packit e9ba0d
	if (n < 0)
Packit e9ba0d
		return OP_ERR | result;
Packit e9ba0d
Packit e9ba0d
	if (n > 8)
Packit e9ba0d
		n = 8;
Packit e9ba0d
	for (i=0; i < n; ++i) {
Packit e9ba0d
		if (bev_ssl->bev.write_suspended)
Packit e9ba0d
			break;
Packit e9ba0d
Packit e9ba0d
		/* SSL_write will (reasonably) return 0 if we tell it to
Packit e9ba0d
		   send 0 data.  Skip this case so we don't interpret the
Packit e9ba0d
		   result as an error */
Packit e9ba0d
		if (space[i].iov_len == 0)
Packit e9ba0d
			continue;
Packit e9ba0d
Packit e9ba0d
		r = SSL_write(bev_ssl->ssl, space[i].iov_base,
Packit e9ba0d
		    space[i].iov_len);
Packit e9ba0d
		if (r > 0) {
Packit e9ba0d
			result |= OP_MADE_PROGRESS;
Packit e9ba0d
			if (bev_ssl->write_blocked_on_read)
Packit e9ba0d
				if (clear_wbor(bev_ssl) < 0)
Packit e9ba0d
					return OP_ERR | result;
Packit e9ba0d
			n_written += r;
Packit e9ba0d
			bev_ssl->last_write = -1;
Packit e9ba0d
			decrement_buckets(bev_ssl);
Packit e9ba0d
		} else {
Packit e9ba0d
			int err = SSL_get_error(bev_ssl->ssl, r);
Packit e9ba0d
			print_err(err);
Packit e9ba0d
			switch (err) {
Packit e9ba0d
			case SSL_ERROR_WANT_WRITE:
Packit e9ba0d
				/* Can't read until underlying has more data. */
Packit e9ba0d
				if (bev_ssl->write_blocked_on_read)
Packit e9ba0d
					if (clear_wbor(bev_ssl) < 0)
Packit e9ba0d
						return OP_ERR | result;
Packit e9ba0d
				bev_ssl->last_write = space[i].iov_len;
Packit e9ba0d
				break;
Packit e9ba0d
			case SSL_ERROR_WANT_READ:
Packit e9ba0d
				/* This read operation requires a write, and the
Packit e9ba0d
				 * underlying is full */
Packit e9ba0d
				if (!bev_ssl->write_blocked_on_read)
Packit e9ba0d
					if (set_wbor(bev_ssl) < 0)
Packit e9ba0d
						return OP_ERR | result;
Packit e9ba0d
				bev_ssl->last_write = space[i].iov_len;
Packit e9ba0d
				break;
Packit e9ba0d
			default:
Packit e9ba0d
				conn_closed(bev_ssl, err, r);
Packit e9ba0d
				bev_ssl->last_write = -1;
Packit e9ba0d
				break;
Packit e9ba0d
			}
Packit e9ba0d
			result |= OP_BLOCKED;
Packit e9ba0d
			break;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
	if (n_written) {
Packit e9ba0d
		evbuffer_drain(output, n_written);
Packit e9ba0d
		if (bev_ssl->underlying)
Packit e9ba0d
			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
Packit e9ba0d
Packit e9ba0d
		if (evbuffer_get_length(output) <= bev->wm_write.low)
Packit e9ba0d
			_bufferevent_run_writecb(bev);
Packit e9ba0d
	}
Packit e9ba0d
	return result;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#define WRITE_FRAME 15000
Packit e9ba0d
Packit e9ba0d
#define READ_DEFAULT 4096
Packit e9ba0d
Packit e9ba0d
/* Try to figure out how many bytes to read; return 0 if we shouldn't be
Packit e9ba0d
 * reading. */
Packit e9ba0d
static int
Packit e9ba0d
bytes_to_read(struct bufferevent_openssl *bev)
Packit e9ba0d
{
Packit e9ba0d
	struct evbuffer *input = bev->bev.bev.input;
Packit e9ba0d
	struct event_watermark *wm = &bev->bev.bev.wm_read;
Packit e9ba0d
	int result = READ_DEFAULT;
Packit e9ba0d
	ev_ssize_t limit;
Packit e9ba0d
	/* XXX 99% of this is generic code that nearly all bufferevents will
Packit e9ba0d
	 * want. */
Packit e9ba0d
Packit e9ba0d
	if (bev->write_blocked_on_read) {
Packit e9ba0d
		return 0;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (! (bev->bev.bev.enabled & EV_READ)) {
Packit e9ba0d
		return 0;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (bev->bev.read_suspended) {
Packit e9ba0d
		return 0;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (wm->high) {
Packit e9ba0d
		if (evbuffer_get_length(input) >= wm->high) {
Packit e9ba0d
			return 0;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		result = wm->high - evbuffer_get_length(input);
Packit e9ba0d
	} else {
Packit e9ba0d
		result = READ_DEFAULT;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* Respect the rate limit */
Packit e9ba0d
	limit = _bufferevent_get_read_max(&bev->bev);
Packit e9ba0d
	if (result > limit) {
Packit e9ba0d
		result = limit;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return result;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
/* Things look readable.  If write is blocked on read, write till it isn't.
Packit e9ba0d
 * Read from the underlying buffer until we block or we hit our high-water
Packit e9ba0d
 * mark.
Packit e9ba0d
 */
Packit e9ba0d
static void
Packit e9ba0d
consider_reading(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	int r;
Packit e9ba0d
	int n_to_read;
Packit e9ba0d
	int all_result_flags = 0;
Packit e9ba0d
Packit e9ba0d
	while (bev_ssl->write_blocked_on_read) {
Packit e9ba0d
		r = do_write(bev_ssl, WRITE_FRAME);
Packit e9ba0d
		if (r & (OP_BLOCKED|OP_ERR))
Packit e9ba0d
			break;
Packit e9ba0d
	}
Packit e9ba0d
	if (bev_ssl->write_blocked_on_read)
Packit e9ba0d
		return;
Packit e9ba0d
Packit e9ba0d
	n_to_read = bytes_to_read(bev_ssl);
Packit e9ba0d
Packit e9ba0d
	while (n_to_read) {
Packit e9ba0d
		r = do_read(bev_ssl, n_to_read);
Packit e9ba0d
		all_result_flags |= r;
Packit e9ba0d
Packit e9ba0d
		if (r & (OP_BLOCKED|OP_ERR))
Packit e9ba0d
			break;
Packit e9ba0d
Packit e9ba0d
		if (bev_ssl->bev.read_suspended)
Packit e9ba0d
			break;
Packit e9ba0d
        
Packit e9ba0d
		/* Read all pending data.  This won't hit the network
Packit e9ba0d
		 * again, and will (most importantly) put us in a state
Packit e9ba0d
		 * where we don't need to read anything else until the
Packit e9ba0d
		 * socket is readable again.  It'll potentially make us
Packit e9ba0d
		 * overrun our read high-watermark (somewhat
Packit e9ba0d
		 * regrettable).  The damage to the rate-limit has
Packit e9ba0d
		 * already been done, since OpenSSL went and read a
Packit e9ba0d
		 * whole SSL record anyway. */
Packit e9ba0d
		n_to_read = SSL_pending(bev_ssl->ssl);
Packit e9ba0d
Packit e9ba0d
		/* XXX This if statement is actually a bad bug, added to avoid
Packit e9ba0d
		 * XXX a worse bug.
Packit e9ba0d
		 *
Packit e9ba0d
		 * The bad bug: It can potentially cause resource unfairness
Packit e9ba0d
		 * by reading too much data from the underlying bufferevent;
Packit e9ba0d
		 * it can potentially cause read looping if the underlying
Packit e9ba0d
		 * bufferevent is a bufferevent_pair and deferred callbacks
Packit e9ba0d
		 * aren't used.
Packit e9ba0d
		 *
Packit e9ba0d
		 * The worse bug: If we didn't do this, then we would
Packit e9ba0d
		 * potentially not read any more from bev_ssl->underlying
Packit e9ba0d
		 * until more data arrived there, which could lead to us
Packit e9ba0d
		 * waiting forever.
Packit e9ba0d
		 */
Packit e9ba0d
		if (!n_to_read && bev_ssl->underlying)
Packit e9ba0d
			n_to_read = bytes_to_read(bev_ssl);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (all_result_flags & OP_MADE_PROGRESS) {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		struct evbuffer *input = bev->input;
Packit e9ba0d
Packit e9ba0d
		if (evbuffer_get_length(input) >= bev->wm_read.low) {
Packit e9ba0d
			_bufferevent_run_readcb(bev);
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (!bev_ssl->underlying) {
Packit e9ba0d
		/* Should be redundant, but let's avoid busy-looping */
Packit e9ba0d
		if (bev_ssl->bev.read_suspended ||
Packit e9ba0d
		    !(bev_ssl->bev.bev.enabled & EV_READ)) {
Packit e9ba0d
			event_del(&bev_ssl->bev.bev.ev_read);
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
consider_writing(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	int r;
Packit e9ba0d
	struct evbuffer *output = bev_ssl->bev.bev.output;
Packit e9ba0d
	struct evbuffer *target = NULL;
Packit e9ba0d
	struct event_watermark *wm = NULL;
Packit e9ba0d
Packit e9ba0d
	while (bev_ssl->read_blocked_on_write) {
Packit e9ba0d
		r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
Packit e9ba0d
		if (r & OP_MADE_PROGRESS) {
Packit e9ba0d
			struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
			struct evbuffer *input = bev->input;
Packit e9ba0d
Packit e9ba0d
			if (evbuffer_get_length(input) >= bev->wm_read.low) {
Packit e9ba0d
				_bufferevent_run_readcb(bev);
Packit e9ba0d
			}
Packit e9ba0d
		}
Packit e9ba0d
		if (r & (OP_ERR|OP_BLOCKED))
Packit e9ba0d
			break;
Packit e9ba0d
	}
Packit e9ba0d
	if (bev_ssl->read_blocked_on_write)
Packit e9ba0d
		return;
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		target = bev_ssl->underlying->output;
Packit e9ba0d
		wm = &bev_ssl->underlying->wm_write;
Packit e9ba0d
	}
Packit e9ba0d
	while ((bev_ssl->bev.bev.enabled & EV_WRITE) &&
Packit e9ba0d
	    (! bev_ssl->bev.write_suspended) &&
Packit e9ba0d
	    evbuffer_get_length(output) &&
Packit e9ba0d
	    (!target || (! wm->high || evbuffer_get_length(target) < wm->high))) {
Packit e9ba0d
		int n_to_write;
Packit e9ba0d
		if (wm && wm->high)
Packit e9ba0d
			n_to_write = wm->high - evbuffer_get_length(target);
Packit e9ba0d
		else
Packit e9ba0d
			n_to_write = WRITE_FRAME;
Packit e9ba0d
		r = do_write(bev_ssl, n_to_write);
Packit e9ba0d
		if (r & (OP_BLOCKED|OP_ERR))
Packit e9ba0d
			break;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (!bev_ssl->underlying) {
Packit e9ba0d
		if (evbuffer_get_length(output) == 0) {
Packit e9ba0d
			event_del(&bev_ssl->bev.bev.ev_write);
Packit e9ba0d
		} else if (bev_ssl->bev.write_suspended ||
Packit e9ba0d
		    !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
Packit e9ba0d
			/* Should be redundant, but let's avoid busy-looping */
Packit e9ba0d
			event_del(&bev_ssl->bev.bev.ev_write);
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_readcb(struct bufferevent *bev_base, void *ctx)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ctx;
Packit e9ba0d
	consider_reading(bev_ssl);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_writecb(struct bufferevent *bev_base, void *ctx)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ctx;
Packit e9ba0d
	consider_writing(bev_ssl);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ctx;
Packit e9ba0d
	int event = 0;
Packit e9ba0d
Packit e9ba0d
	if (what & BEV_EVENT_EOF) {
Packit e9ba0d
		if (bev_ssl->allow_dirty_shutdown)
Packit e9ba0d
			event = BEV_EVENT_EOF;
Packit e9ba0d
		else
Packit e9ba0d
			event = BEV_EVENT_ERROR;
Packit e9ba0d
	} else if (what & BEV_EVENT_TIMEOUT) {
Packit e9ba0d
		/* We sure didn't set this.  Propagate it to the user. */
Packit e9ba0d
		event = what;
Packit e9ba0d
	} else if (what & BEV_EVENT_ERROR) {
Packit e9ba0d
		/* An error occurred on the connection.  Propagate it to the user. */
Packit e9ba0d
		event = what;
Packit e9ba0d
	} else if (what & BEV_EVENT_CONNECTED) {
Packit e9ba0d
		/* Ignore it.  We're saying SSL_connect() already, which will
Packit e9ba0d
		   eat it. */
Packit e9ba0d
	}
Packit e9ba0d
	if (event)
Packit e9ba0d
		_bufferevent_run_eventcb(&bev_ssl->bev.bev, event);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ptr;
Packit e9ba0d
	_bufferevent_incref_and_lock(&bev_ssl->bev.bev);
Packit e9ba0d
	if (what == EV_TIMEOUT) {
Packit e9ba0d
		_bufferevent_run_eventcb(&bev_ssl->bev.bev,
Packit e9ba0d
		    BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
Packit e9ba0d
	} else {
Packit e9ba0d
		consider_reading(bev_ssl);
Packit e9ba0d
	}
Packit e9ba0d
	_bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ptr;
Packit e9ba0d
	_bufferevent_incref_and_lock(&bev_ssl->bev.bev);
Packit e9ba0d
	if (what == EV_TIMEOUT) {
Packit e9ba0d
		_bufferevent_run_eventcb(&bev_ssl->bev.bev,
Packit e9ba0d
		    BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
Packit e9ba0d
	} else {
Packit e9ba0d
		consider_writing(bev_ssl);
Packit e9ba0d
	}
Packit e9ba0d
	_bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
Packit e9ba0d
{
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		bufferevent_setcb(bev_ssl->underlying,
Packit e9ba0d
		    be_openssl_readcb, be_openssl_writecb, be_openssl_eventcb,
Packit e9ba0d
		    bev_ssl);
Packit e9ba0d
		return 0;
Packit e9ba0d
	} else {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		int rpending=0, wpending=0, r1=0, r2=0;
Packit e9ba0d
		if (fd < 0 && bev_ssl->fd_is_set)
Packit e9ba0d
			fd = event_get_fd(&bev->ev_read);
Packit e9ba0d
		if (bev_ssl->fd_is_set) {
Packit e9ba0d
			rpending = event_pending(&bev->ev_read, EV_READ, NULL);
Packit e9ba0d
			wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
Packit e9ba0d
			event_del(&bev->ev_read);
Packit e9ba0d
			event_del(&bev->ev_write);
Packit e9ba0d
		}
Packit e9ba0d
		event_assign(&bev->ev_read, bev->ev_base, fd,
Packit e9ba0d
		    EV_READ|EV_PERSIST, be_openssl_readeventcb, bev_ssl);
Packit e9ba0d
		event_assign(&bev->ev_write, bev->ev_base, fd,
Packit e9ba0d
		    EV_WRITE|EV_PERSIST, be_openssl_writeeventcb, bev_ssl);
Packit e9ba0d
		if (rpending)
Packit e9ba0d
			r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
Packit e9ba0d
		if (wpending)
Packit e9ba0d
			r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
Packit e9ba0d
		if (fd >= 0) {
Packit e9ba0d
			bev_ssl->fd_is_set = 1;
Packit e9ba0d
		}
Packit e9ba0d
		return (r1<0 || r2<0) ? -1 : 0;
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
do_handshake(struct bufferevent_openssl *bev_ssl)
Packit e9ba0d
{
Packit e9ba0d
	int r;
Packit e9ba0d
Packit e9ba0d
	switch (bev_ssl->state) {
Packit e9ba0d
	default:
Packit e9ba0d
	case BUFFEREVENT_SSL_OPEN:
Packit e9ba0d
		EVUTIL_ASSERT(0);
Packit e9ba0d
		return -1;
Packit e9ba0d
	case BUFFEREVENT_SSL_CONNECTING:
Packit e9ba0d
	case BUFFEREVENT_SSL_ACCEPTING:
Packit e9ba0d
		r = SSL_do_handshake(bev_ssl->ssl);
Packit e9ba0d
		break;
Packit e9ba0d
	}
Packit e9ba0d
	decrement_buckets(bev_ssl);
Packit e9ba0d
Packit e9ba0d
	if (r==1) {
Packit e9ba0d
		/* We're done! */
Packit e9ba0d
		bev_ssl->state = BUFFEREVENT_SSL_OPEN;
Packit e9ba0d
		set_open_callbacks(bev_ssl, -1); /* XXXX handle failure */
Packit e9ba0d
		/* Call do_read and do_write as needed */
Packit e9ba0d
		bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
Packit e9ba0d
		_bufferevent_run_eventcb(&bev_ssl->bev.bev,
Packit e9ba0d
		    BEV_EVENT_CONNECTED);
Packit e9ba0d
		return 1;
Packit e9ba0d
	} else {
Packit e9ba0d
		int err = SSL_get_error(bev_ssl->ssl, r);
Packit e9ba0d
		print_err(err);
Packit e9ba0d
		switch (err) {
Packit e9ba0d
		case SSL_ERROR_WANT_WRITE:
Packit e9ba0d
			if (!bev_ssl->underlying) {
Packit e9ba0d
				stop_reading(bev_ssl);
Packit e9ba0d
				return start_writing(bev_ssl);
Packit e9ba0d
			}
Packit e9ba0d
			return 0;
Packit e9ba0d
		case SSL_ERROR_WANT_READ:
Packit e9ba0d
			if (!bev_ssl->underlying) {
Packit e9ba0d
				stop_writing(bev_ssl);
Packit e9ba0d
				return start_reading(bev_ssl);
Packit e9ba0d
			}
Packit e9ba0d
			return 0;
Packit e9ba0d
		default:
Packit e9ba0d
			conn_closed(bev_ssl, err, r);
Packit e9ba0d
			return -1;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_handshakecb(struct bufferevent *bev_base, void *ctx)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ctx;
Packit e9ba0d
	do_handshake(bev_ssl);/* XXX handle failure */
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = ptr;
Packit e9ba0d
Packit e9ba0d
	_bufferevent_incref_and_lock(&bev_ssl->bev.bev);
Packit e9ba0d
	if (what & EV_TIMEOUT) {
Packit e9ba0d
		_bufferevent_run_eventcb(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT);
Packit e9ba0d
	} else
Packit e9ba0d
		do_handshake(bev_ssl);/* XXX handle failure */
Packit e9ba0d
	_bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
Packit e9ba0d
{
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		bufferevent_setcb(bev_ssl->underlying,
Packit e9ba0d
		    be_openssl_handshakecb, be_openssl_handshakecb,
Packit e9ba0d
		    be_openssl_eventcb,
Packit e9ba0d
		    bev_ssl);
Packit e9ba0d
		return do_handshake(bev_ssl);
Packit e9ba0d
	} else {
Packit e9ba0d
		struct bufferevent *bev = &bev_ssl->bev.bev;
Packit e9ba0d
		int r1=0, r2=0;
Packit e9ba0d
		if (fd < 0 && bev_ssl->fd_is_set)
Packit e9ba0d
			fd = event_get_fd(&bev->ev_read);
Packit e9ba0d
		if (bev_ssl->fd_is_set) {
Packit e9ba0d
			event_del(&bev->ev_read);
Packit e9ba0d
			event_del(&bev->ev_write);
Packit e9ba0d
		}
Packit e9ba0d
		event_assign(&bev->ev_read, bev->ev_base, fd,
Packit e9ba0d
		    EV_READ|EV_PERSIST, be_openssl_handshakeeventcb, bev_ssl);
Packit e9ba0d
		event_assign(&bev->ev_write, bev->ev_base, fd,
Packit e9ba0d
		    EV_WRITE|EV_PERSIST, be_openssl_handshakeeventcb, bev_ssl);
Packit e9ba0d
		if (fd >= 0) {
Packit e9ba0d
			r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
Packit e9ba0d
			r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
Packit e9ba0d
			bev_ssl->fd_is_set = 1;
Packit e9ba0d
		}
Packit e9ba0d
		return (r1<0 || r2<0) ? -1 : 0;
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
bufferevent_ssl_renegotiate(struct bufferevent *bev)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bev);
Packit e9ba0d
	if (!bev_ssl)
Packit e9ba0d
		return -1;
Packit e9ba0d
	if (SSL_renegotiate(bev_ssl->ssl) < 0)
Packit e9ba0d
		return -1;
Packit e9ba0d
	bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
Packit e9ba0d
	if (set_handshake_callbacks(bev_ssl, -1) < 0)
Packit e9ba0d
		return -1;
Packit e9ba0d
	if (!bev_ssl->underlying)
Packit e9ba0d
		return do_handshake(bev_ssl);
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_outbuf_cb(struct evbuffer *buf,
Packit e9ba0d
    const struct evbuffer_cb_info *cbinfo, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = arg;
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	/* XXX need to hold a reference here. */
Packit e9ba0d
Packit e9ba0d
	if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
Packit e9ba0d
		if (cbinfo->orig_size == 0)
Packit e9ba0d
			r = _bufferevent_add_event(&bev_ssl->bev.bev.ev_write,
Packit e9ba0d
			    &bev_ssl->bev.bev.timeout_write);
Packit e9ba0d
		consider_writing(bev_ssl);
Packit e9ba0d
	}
Packit e9ba0d
	/* XXX Handle r < 0 */
Packit e9ba0d
        (void)r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
be_openssl_enable(struct bufferevent *bev, short events)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bev);
Packit e9ba0d
	int r1 = 0, r2 = 0;
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
Packit e9ba0d
		return 0;
Packit e9ba0d
Packit e9ba0d
	if (events & EV_READ)
Packit e9ba0d
		r1 = start_reading(bev_ssl);
Packit e9ba0d
	if (events & EV_WRITE)
Packit e9ba0d
		r2 = start_writing(bev_ssl);
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		if (events & EV_READ)
Packit e9ba0d
			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
Packit e9ba0d
		if (events & EV_WRITE)
Packit e9ba0d
			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
Packit e9ba0d
Packit e9ba0d
		if (events & EV_READ)
Packit e9ba0d
			consider_reading(bev_ssl);
Packit e9ba0d
		if (events & EV_WRITE)
Packit e9ba0d
			consider_writing(bev_ssl);
Packit e9ba0d
	}
Packit e9ba0d
	return (r1 < 0 || r2 < 0) ? -1 : 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
be_openssl_disable(struct bufferevent *bev, short events)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bev);
Packit e9ba0d
	if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
Packit e9ba0d
		return 0;
Packit e9ba0d
Packit e9ba0d
	if (events & EV_READ)
Packit e9ba0d
		stop_reading(bev_ssl);
Packit e9ba0d
	if (events & EV_WRITE)
Packit e9ba0d
		stop_writing(bev_ssl);
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		if (events & EV_READ)
Packit e9ba0d
			BEV_DEL_GENERIC_READ_TIMEOUT(bev);
Packit e9ba0d
		if (events & EV_WRITE)
Packit e9ba0d
			BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
Packit e9ba0d
	}
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
be_openssl_destruct(struct bufferevent *bev)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bev);
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->underlying) {
Packit e9ba0d
		_bufferevent_del_generic_timeout_cbs(bev);
Packit e9ba0d
	} else {
Packit e9ba0d
		event_del(&bev->ev_read);
Packit e9ba0d
		event_del(&bev->ev_write);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
Packit e9ba0d
		if (bev_ssl->underlying) {
Packit e9ba0d
			if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
Packit e9ba0d
				event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
Packit e9ba0d
				    "bufferevent with too few references");
Packit e9ba0d
			} else {
Packit e9ba0d
				bufferevent_free(bev_ssl->underlying);
Packit e9ba0d
				bev_ssl->underlying = NULL;
Packit e9ba0d
			}
Packit e9ba0d
		} else {
Packit e9ba0d
			evutil_socket_t fd = -1;
Packit e9ba0d
			BIO *bio = SSL_get_wbio(bev_ssl->ssl);
Packit e9ba0d
			if (bio)
Packit e9ba0d
				fd = BIO_get_fd(bio, NULL);
Packit e9ba0d
			if (fd >= 0)
Packit e9ba0d
				evutil_closesocket(fd);
Packit e9ba0d
		}
Packit e9ba0d
		SSL_free(bev_ssl->ssl);
Packit e9ba0d
	} else {
Packit e9ba0d
		if (bev_ssl->underlying) {
Packit e9ba0d
			if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
Packit e9ba0d
				bufferevent_setcb(bev_ssl->underlying,
Packit e9ba0d
				    NULL,NULL,NULL,NULL);
Packit e9ba0d
			bufferevent_unsuspend_read(bev_ssl->underlying,
Packit e9ba0d
			    BEV_SUSPEND_FILT_READ);
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
be_openssl_adj_timeouts(struct bufferevent *bev)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bev);
Packit e9ba0d
Packit e9ba0d
	if (bev_ssl->underlying)
Packit e9ba0d
		return _bufferevent_generic_adj_timeouts(bev);
Packit e9ba0d
	else {
Packit e9ba0d
		int r1=0, r2=0;
Packit e9ba0d
		if (event_pending(&bev->ev_read, EV_READ, NULL))
Packit e9ba0d
			r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
Packit e9ba0d
		if (event_pending(&bev->ev_write, EV_WRITE, NULL))
Packit e9ba0d
			r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
Packit e9ba0d
		return (r1<0 || r2<0) ? -1 : 0;
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
be_openssl_flush(struct bufferevent *bufev,
Packit e9ba0d
    short iotype, enum bufferevent_flush_mode mode)
Packit e9ba0d
{
Packit e9ba0d
	/* XXXX Implement this. */
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
be_openssl_ctrl(struct bufferevent *bev,
Packit e9ba0d
    enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bev);
Packit e9ba0d
	switch (op) {
Packit e9ba0d
	case BEV_CTRL_SET_FD:
Packit e9ba0d
		if (bev_ssl->underlying)
Packit e9ba0d
			return -1;
Packit e9ba0d
		{
Packit e9ba0d
			BIO *bio;
Packit e9ba0d
			bio = BIO_new_socket(data->fd, 0);
Packit e9ba0d
			SSL_set_bio(bev_ssl->ssl, bio, bio);
Packit e9ba0d
			bev_ssl->fd_is_set = 1;
Packit e9ba0d
		}
Packit e9ba0d
		if (bev_ssl->state == BUFFEREVENT_SSL_OPEN)
Packit e9ba0d
			return set_open_callbacks(bev_ssl, data->fd);
Packit e9ba0d
		else {
Packit e9ba0d
			return set_handshake_callbacks(bev_ssl, data->fd);
Packit e9ba0d
		}
Packit e9ba0d
	case BEV_CTRL_GET_FD:
Packit e9ba0d
		if (bev_ssl->underlying)
Packit e9ba0d
			return -1;
Packit e9ba0d
		if (!bev_ssl->fd_is_set)
Packit e9ba0d
			return -1;
Packit e9ba0d
		data->fd = event_get_fd(&bev->ev_read);
Packit e9ba0d
		return 0;
Packit e9ba0d
	case BEV_CTRL_GET_UNDERLYING:
Packit e9ba0d
		if (!bev_ssl->underlying)
Packit e9ba0d
			return -1;
Packit e9ba0d
		data->ptr = bev_ssl->underlying;
Packit e9ba0d
		return 0;
Packit e9ba0d
	case BEV_CTRL_CANCEL_ALL:
Packit e9ba0d
	default:
Packit e9ba0d
		return -1;
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
SSL *
Packit e9ba0d
bufferevent_openssl_get_ssl(struct bufferevent *bufev)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = upcast(bufev);
Packit e9ba0d
	if (!bev_ssl)
Packit e9ba0d
		return NULL;
Packit e9ba0d
	return bev_ssl->ssl;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static struct bufferevent *
Packit e9ba0d
bufferevent_openssl_new_impl(struct event_base *base,
Packit e9ba0d
    struct bufferevent *underlying,
Packit e9ba0d
    evutil_socket_t fd,
Packit e9ba0d
    SSL *ssl,
Packit e9ba0d
    enum bufferevent_ssl_state state,
Packit e9ba0d
    int options)
Packit e9ba0d
{
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl = NULL;
Packit e9ba0d
	struct bufferevent_private *bev_p = NULL;
Packit e9ba0d
	int tmp_options = options & ~BEV_OPT_THREADSAFE;
Packit e9ba0d
Packit e9ba0d
	if (underlying != NULL && fd >= 0)
Packit e9ba0d
		return NULL; /* Only one can be set. */
Packit e9ba0d
Packit e9ba0d
	if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
Packit e9ba0d
		goto err;
Packit e9ba0d
Packit e9ba0d
	bev_p = &bev_ssl->bev;
Packit e9ba0d
Packit e9ba0d
	if (bufferevent_init_common(bev_p, base,
Packit e9ba0d
		&bufferevent_ops_openssl, tmp_options) < 0)
Packit e9ba0d
		goto err;
Packit e9ba0d
Packit e9ba0d
	/* Don't explode if we decide to realloc a chunk we're writing from in
Packit e9ba0d
	 * the output buffer. */
Packit e9ba0d
	SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
Packit e9ba0d
Packit e9ba0d
	bev_ssl->underlying = underlying;
Packit e9ba0d
	bev_ssl->ssl = ssl;
Packit e9ba0d
Packit e9ba0d
	bev_ssl->outbuf_cb = evbuffer_add_cb(bev_p->bev.output,
Packit e9ba0d
	    be_openssl_outbuf_cb, bev_ssl);
Packit e9ba0d
Packit e9ba0d
	if (options & BEV_OPT_THREADSAFE)
Packit e9ba0d
		bufferevent_enable_locking(&bev_ssl->bev.bev, NULL);
Packit e9ba0d
Packit e9ba0d
	if (underlying) {
Packit e9ba0d
		_bufferevent_init_generic_timeout_cbs(&bev_ssl->bev.bev);
Packit e9ba0d
		bufferevent_incref(underlying);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	bev_ssl->state = state;
Packit e9ba0d
	bev_ssl->last_write = -1;
Packit e9ba0d
Packit e9ba0d
	init_bio_counts(bev_ssl);
Packit e9ba0d
Packit e9ba0d
	switch (state) {
Packit e9ba0d
	case BUFFEREVENT_SSL_ACCEPTING:
Packit e9ba0d
		SSL_set_accept_state(bev_ssl->ssl);
Packit e9ba0d
		if (set_handshake_callbacks(bev_ssl, fd) < 0)
Packit e9ba0d
			goto err;
Packit e9ba0d
		break;
Packit e9ba0d
	case BUFFEREVENT_SSL_CONNECTING:
Packit e9ba0d
		SSL_set_connect_state(bev_ssl->ssl);
Packit e9ba0d
		if (set_handshake_callbacks(bev_ssl, fd) < 0)
Packit e9ba0d
			goto err;
Packit e9ba0d
		break;
Packit e9ba0d
	case BUFFEREVENT_SSL_OPEN:
Packit e9ba0d
		if (set_open_callbacks(bev_ssl, fd) < 0)
Packit e9ba0d
			goto err;
Packit e9ba0d
		break;
Packit e9ba0d
	default:
Packit e9ba0d
		goto err;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (underlying) {
Packit e9ba0d
		bufferevent_setwatermark(underlying, EV_READ, 0, 0);
Packit e9ba0d
		bufferevent_enable(underlying, EV_READ|EV_WRITE);
Packit e9ba0d
		if (state == BUFFEREVENT_SSL_OPEN)
Packit e9ba0d
			bufferevent_suspend_read(underlying,
Packit e9ba0d
			    BEV_SUSPEND_FILT_READ);
Packit e9ba0d
	} else {
Packit e9ba0d
		bev_ssl->bev.bev.enabled = EV_READ|EV_WRITE;
Packit e9ba0d
		if (bev_ssl->fd_is_set) {
Packit e9ba0d
			if (state != BUFFEREVENT_SSL_OPEN)
Packit e9ba0d
				if (event_add(&bev_ssl->bev.bev.ev_read, NULL) < 0)
Packit e9ba0d
					goto err;
Packit e9ba0d
			if (event_add(&bev_ssl->bev.bev.ev_write, NULL) < 0)
Packit e9ba0d
				goto err;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return &bev_ssl->bev.bev;
Packit e9ba0d
err:
Packit e9ba0d
	if (bev_ssl)
Packit e9ba0d
		bufferevent_free(&bev_ssl->bev.bev);
Packit e9ba0d
	return NULL;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct bufferevent *
Packit e9ba0d
bufferevent_openssl_filter_new(struct event_base *base,
Packit e9ba0d
    struct bufferevent *underlying,
Packit e9ba0d
    SSL *ssl,
Packit e9ba0d
    enum bufferevent_ssl_state state,
Packit e9ba0d
    int options)
Packit e9ba0d
{
Packit e9ba0d
	/* We don't tell the BIO to close the bufferevent; we do it ourselves
Packit e9ba0d
	 * on be_openssl_destruct */
Packit e9ba0d
	int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
Packit e9ba0d
	BIO *bio;
Packit e9ba0d
	if (!underlying)
Packit e9ba0d
		return NULL;
Packit e9ba0d
	if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
Packit e9ba0d
		return NULL;
Packit e9ba0d
Packit e9ba0d
	SSL_set_bio(ssl, bio, bio);
Packit e9ba0d
Packit e9ba0d
	return bufferevent_openssl_new_impl(
Packit e9ba0d
		base, underlying, -1, ssl, state, options);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct bufferevent *
Packit e9ba0d
bufferevent_openssl_socket_new(struct event_base *base,
Packit e9ba0d
    evutil_socket_t fd,
Packit e9ba0d
    SSL *ssl,
Packit e9ba0d
    enum bufferevent_ssl_state state,
Packit e9ba0d
    int options)
Packit e9ba0d
{
Packit e9ba0d
	/* Does the SSL already have an fd? */
Packit e9ba0d
	BIO *bio = SSL_get_wbio(ssl);
Packit e9ba0d
	long have_fd = -1;
Packit e9ba0d
Packit e9ba0d
	if (bio)
Packit e9ba0d
		have_fd = BIO_get_fd(bio, NULL);
Packit e9ba0d
Packit e9ba0d
	if (have_fd >= 0) {
Packit e9ba0d
		/* The SSL is already configured with an fd. */
Packit e9ba0d
		if (fd < 0) {
Packit e9ba0d
			/* We should learn the fd from the SSL. */
Packit e9ba0d
			fd = (evutil_socket_t) have_fd;
Packit e9ba0d
		} else if (have_fd == (long)fd) {
Packit e9ba0d
			/* We already know the fd from the SSL; do nothing */
Packit e9ba0d
		} else {
Packit e9ba0d
			/* We specified an fd different from that of the SSL.
Packit e9ba0d
			   This is probably an error on our part.  Fail. */
Packit e9ba0d
			return NULL;
Packit e9ba0d
		}
Packit e9ba0d
		(void) BIO_set_close(bio, 0);
Packit e9ba0d
	} else {
Packit e9ba0d
		/* The SSL isn't configured with a BIO with an fd. */
Packit e9ba0d
		if (fd >= 0) {
Packit e9ba0d
			/* ... and we have an fd we want to use. */
Packit e9ba0d
			bio = BIO_new_socket(fd, 0);
Packit e9ba0d
			SSL_set_bio(ssl, bio, bio);
Packit e9ba0d
		} else {
Packit e9ba0d
			/* Leave the fd unset. */
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return bufferevent_openssl_new_impl(
Packit e9ba0d
		base, NULL, fd, ssl, state, options);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
unsigned long
Packit e9ba0d
bufferevent_get_openssl_error(struct bufferevent *bev)
Packit e9ba0d
{
Packit e9ba0d
	unsigned long err = 0;
Packit e9ba0d
	struct bufferevent_openssl *bev_ssl;
Packit e9ba0d
	BEV_LOCK(bev);
Packit e9ba0d
	bev_ssl = upcast(bev);
Packit e9ba0d
	if (bev_ssl && bev_ssl->n_errors) {
Packit e9ba0d
		err = bev_ssl->errors[--bev_ssl->n_errors];
Packit e9ba0d
	}
Packit e9ba0d
	BEV_UNLOCK(bev);
Packit e9ba0d
	return err;
Packit e9ba0d
}