Commits

Ruslan Osmanov committed a54d9a9 Merge

Merge branch 'ssl'

  • Participants
  • Parent commits dca6f13, 3c3bc2d

Comments (0)

Files changed (17)

 }
 /* }}} */
 
+/* {{{ proto string EventBuffer::pullup(int size);
+ *
+ * "Linearizes" the first size bytes of the buffer, copying or moving them as needed to
+ * ensure that they are all contiguous and occupying the same chunk of memory. If size is
+ * negative, the function linearizes the entire buffer. If size is greater than the number
+ * of bytes in the buffer, the function returns NULL. Otherwise, EventBuffer::pullup()
+ * returns string.
+ *
+ * Calling EventBuffer::pullup() with a large size can be quite slow, since it potentially
+ * needs to copy the entire buffer's contents.
+ */
+PHP_METHOD(EventBuffer, pullup)
+{
+	zval               *zbuf = getThis();
+	php_event_buffer_t *b;
+	long                size;
+	unsigned char      *mem;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
+				&size) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	mem = evbuffer_pullup(b->buf, size);
+
+	if (mem == NULL) {
+		RETURN_NULL();
+	}
+
+	RETVAL_STRING((const char *)mem, 1);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4

classes/buffer_event.c

 }
 /* }}} */
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+/* {{{ is_valid_ssl_state */
+static zend_always_inline zend_bool is_valid_ssl_state(long state)
+{
+	return (zend_bool) (state == BUFFEREVENT_SSL_OPEN
+			|| state == BUFFEREVENT_SSL_CONNECTING
+			|| state == BUFFEREVENT_SSL_ACCEPTING);
+}
+/* }}} */
+#endif
+
 /* Private }}} */
 
 
 	}
 
 	if (ppzfd) {
-#ifdef PHP_EVENT_SOCKETS_SUPPORT 
 		/* php_event_zval_to_fd reports error
 	 	 * in case if it is not a valid socket resource */
 		/*fd = (evutil_socket_t) php_event_zval_to_fd(ppzfd TSRMLS_CC);*/
 		}
 		/* Make sure that the socket is in non-blocking mode(libevent's tip) */
 		evutil_make_socket_nonblocking(fd);
-#else
-		fd = -1;
-#endif
 	} else {
  		/* User decided to assign fd later,
  		 * e.g. by means of bufferevent_socket_connect()
 	}
 
 	bev->self = zself;
+	/* Ensure the object won't be destroyed in case if we are in a callback */
 	Z_ADDREF_P(zself);
 }
 /* }}} */
 }
 /* }}} */
 
+#ifdef HAVE_EVENT_OPENSSL_LIB /* {{{ */
+/* {{{ proto EventBufferEvent EventBufferEvent::sslFilter(EventBase base, EventBufferEvent underlying, EventSslContext ctx, int state[, int options = 0]);
+ */
+PHP_METHOD(EventBufferEvent, sslFilter)
+{
+	zval                    *zbase;
+	php_event_base_t        *base;
+	zval                    *zunderlying;
+	php_event_bevent_t      *bev_underlying;
+	zval                    *zctx;
+	php_event_ssl_context_t *ectx;
+	long                     state;
+	long                     options        = 0;
+	php_event_bevent_t      *bev;
+	struct bufferevent      *bevent;
+	SSL                     *ssl;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OOOl|l",
+				&zbase, php_event_base_ce,
+				&zunderlying, php_event_bevent_ce,
+				&zctx, php_event_ssl_context_ce,
+				&state, &options) == FAILURE) {
+		return;
+	}
+
+	if (!is_valid_ssl_state(state)) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Invalid state specified");
+		RETURN_FALSE;
+	}
+
+	PHP_EVENT_FETCH_BASE(base, zbase);
+	PHP_EVENT_FETCH_BEVENT(bev_underlying, zunderlying);
+	PHP_EVENT_FETCH_SSL_CONTEXT(ectx, zctx);
+
+	PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_bevent_ce);
+	PHP_EVENT_FETCH_BEVENT(bev, return_value);
+
+	PHP_EVENT_ASSERT(ectx->ctx);
+	ssl = SSL_new(ectx->ctx);
+	if (!ssl) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Event: Failed creating SSL handle");
+		RETURN_FALSE;
+	}
+
+	bevent = bufferevent_openssl_filter_new(base->base,
+    		bev_underlying->bevent,
+    		ssl, state, options);
+	if (bevent == NULL) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Failed to allocate bufferevent filter");
+		RETURN_FALSE;
+	}
+	bev->bevent = bevent;
+
+	bev->stream_id = -1;
+
+	bev->self = return_value;
+	/* Ensure the object won't be destroyed in case if we are in a callback */
+	Z_ADDREF_P(return_value);
+}
+/* }}} */
+
+/* {{{ proto EventBufferEvent EventBufferEvent::sslSocket(EventBase base, resource socket, EventSslContext ctx, int state[, int options = 0]);
+ * */
+PHP_METHOD(EventBufferEvent, sslSocket)
+{
+	zval                     *zbase;
+	php_event_base_t         *base;
+	zval                     *zctx;
+	php_event_ssl_context_t  *ectx;
+	zval                    **ppzfd;
+	evutil_socket_t           fd;
+	long                      state;
+	long                      options = 0;
+	php_event_bevent_t       *bev;
+	struct bufferevent       *bevent;
+	SSL                      *ssl;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OZOl|l",
+				&zbase, php_event_base_ce,
+				&ppzfd, 
+				&zctx, php_event_ssl_context_ce,
+				&state, &options) == FAILURE) {
+		return;
+	}
+
+	if (!is_valid_ssl_state(state)) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Invalid state specified");
+		RETURN_FALSE;
+	}
+
+	PHP_EVENT_FETCH_BASE(base, zbase);
+	PHP_EVENT_FETCH_SSL_CONTEXT(ectx, zctx);
+
+	PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_bevent_ce);
+	PHP_EVENT_FETCH_BEVENT(bev, return_value);
+
+	fd = php_event_zval_to_fd(ppzfd TSRMLS_CC);
+	if (fd < 0) {
+		RETURN_FALSE;
+	}
+	/* Make sure that the socket is in non-blocking mode(libevent's tip) */
+	/*evutil_make_socket_nonblocking(fd);*/
+
+	PHP_EVENT_ASSERT(ectx->ctx);
+	ssl = SSL_new(ectx->ctx);
+	if (!ssl) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Event: Failed creating SSL handle");
+		RETURN_FALSE;
+	}
+
+	bevent = bufferevent_openssl_socket_new(base->base, fd, ssl, state, options);
+	if (bevent == NULL) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR,
+				"Failed to allocate bufferevent filter");
+		RETURN_FALSE;
+	}
+	bev->bevent = bevent;
+
+	/* lval of ppzfd is the resource ID */
+	bev->stream_id = Z_LVAL_PP(ppzfd);
+	zend_list_addref(Z_LVAL_PP(ppzfd));
+
+	bev->self = return_value;
+	/* Ensure the object won't be destroyed in case if we are in a callback */
+	Z_ADDREF_P(return_value);
+}
+/* }}} */
+#endif /* HAVE_EVENT_OPENSSL_LIB }}} */
+
 /*
  * Local variables:
  * tab-width: 4

classes/event_util.c

 }
 /* }}} */
 
+#ifdef HAVE_EVENT_OPENSSL_LIB/* {{{ */
+/* {{{ proto bool EventUtil::sslRandPoll(void);
+ * 
+ * Generates entropy by means of OpenSSL's RAND_poll()
+ */
+PHP_METHOD(EventUtil, sslRandPoll)
+{
+	RETVAL_BOOL((zend_bool) RAND_poll());
+}
+/* }}} */
+#endif/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4

classes/ssl_context.c

+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2013 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+#include "src/common.h"
+#include "src/util.h"
+#include "src/priv.h"
+
+#ifndef HAVE_EVENT_OPENSSL_LIB
+# error "HAVE_EVENT_OPENSSL_LIB undefined"
+#endif
+
+/* {{{ Private */
+
+/* {{{ passwd_callback */
+static int passwd_callback(char *buf, int num, int verify, void *data)
+{
+    HashTable  *ht  = (HashTable *) data;
+    zval      **val = NULL;
+
+	if (zend_hash_find(ht, "passphrase", sizeof("passphrase"),
+				(void **) &val) == SUCCESS) {
+        if (Z_STRLEN_PP(val) < num - 1) {
+            memcpy(buf, Z_STRVAL_PP(val), Z_STRLEN_PP(val) + 1);
+            return Z_STRLEN_PP(val);
+        }
+    }
+
+    return 0;
+}
+/* }}} */
+
+/* {{{ set_ca */
+static zend_always_inline void set_ca(SSL_CTX *ctx, const char *cafile, const char *capath TSRMLS_DC) {
+    if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
+        php_error_docref(NULL TSRMLS_CC, E_WARNING,
+        		"Unable to set verify locations `%s' `%s'",
+        		cafile, capath);
+    }
+}
+/* }}} */
+
+/* {{{ set_ciphers */
+static zend_always_inline void set_ciphers(SSL_CTX *ctx, const char *cipher_list TSRMLS_DC)
+{
+	if (SSL_CTX_set_cipher_list(ctx, cipher_list) != 1) {
+        php_error_docref(NULL TSRMLS_CC, E_WARNING,
+            	"Failed setting cipher list: `%s'", cipher_list);
+	}
+}
+/* }}} */
+
+/* {{{ set_local_cert */
+static int set_local_cert(SSL_CTX *ctx, const char *certfile, const char *private_key TSRMLS_DC)
+{
+	char resolved_path_buff[MAXPATHLEN];
+
+    if (VCWD_REALPATH(certfile, resolved_path_buff)) {
+        if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) {
+            php_error_docref(NULL TSRMLS_CC, E_WARNING,
+            		"SSL_CTX_use_certificate_chain_file failed, file: `%s'", certfile);
+            return -1;
+        }
+
+        if (private_key) {
+            char resolved_path_buff_pk[MAXPATHLEN];
+
+            if (VCWD_REALPATH(private_key, resolved_path_buff_pk)) {
+                if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff_pk, SSL_FILETYPE_PEM) != 1) {
+                    php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                    		"Unable to set private key file `%s'",
+                    		resolved_path_buff_pk);
+                    return -1;
+                }
+            }
+        } else {
+            if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
+                php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                		"Unable to set private key file `%s'",
+                		resolved_path_buff);
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+/* }}} */
+
+/* {{{ set_ssl_ctx_options */
+static inline void set_ssl_ctx_options(SSL_CTX *ctx, HashTable *ht TSRMLS_DC)
+{
+	HashPosition  pos         = 0;
+	zend_bool     got_ciphers = 0;
+	char         *cafile      = NULL;
+	char         *capath      = NULL;
+
+	for (zend_hash_internal_pointer_reset_ex(ht, &pos);
+			zend_hash_has_more_elements_ex(ht, &pos) == SUCCESS;
+			zend_hash_move_forward_ex(ht, &pos)) {
+		char   *key;
+		uint    keylen;
+		ulong   idx;
+		int     type;
+		zval  **ppzval;
+
+		type = zend_hash_get_current_key_ex(ht, &key, &keylen,
+				&idx, 0, &pos);
+		if (type != HASH_KEY_IS_LONG) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING,
+					"Invalid option `%s'", key);
+			continue;
+		}
+
+		if (zend_hash_get_current_data_ex(ht, (void **) &ppzval, &pos) == FAILURE) {
+			continue;
+		}
+
+		switch (idx) {
+			case PHP_EVENT_OPT_LOCAL_CERT:
+				convert_to_string_ex(ppzval);
+				zval **ppz_private_key;
+
+				if (zend_hash_index_find(ht, PHP_EVENT_OPT_LOCAL_PK,
+						(void **) &ppz_private_key) == SUCCESS) {
+					set_local_cert(ctx, Z_STRVAL_PP(ppzval), Z_STRVAL_PP(ppz_private_key));
+				} else {
+					set_local_cert(ctx, Z_STRVAL_PP(ppzval), NULL);
+				}
+				break;
+			case PHP_EVENT_OPT_LOCAL_PK:
+				/* Skip. SSL_CTX_use_PrivateKey_file is applied in "local_cert". */
+				break;
+			case PHP_EVENT_OPT_PASSPHRASE:
+				convert_to_string_ex(ppzval);
+        		SSL_CTX_set_default_passwd_cb_userdata(ctx, ht);
+        		SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+				break;
+			case PHP_EVENT_OPT_CA_FILE:
+				convert_to_string_ex(ppzval);
+				cafile = Z_STRVAL_PP(ppzval);
+				break;
+			case PHP_EVENT_OPT_CA_PATH:
+				convert_to_string_ex(ppzval);
+				capath = Z_STRVAL_PP(ppzval);
+				break;
+			case PHP_EVENT_OPT_ALLOW_SELF_SIGNED:
+				/* Skip */
+				break;
+			case PHP_EVENT_OPT_VERIFY_PEER:
+				/* Skip */
+				break;
+			case PHP_EVENT_OPT_VERIFY_DEPTH:
+				convert_to_long_ex(ppzval);
+				SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(ppzval));
+				break;
+			case PHP_EVENT_OPT_CIPHERS:
+				got_ciphers = 1;
+				convert_to_string_ex(ppzval);
+				set_ciphers(ctx, Z_STRVAL_PP(ppzval));
+				break;
+			default:
+				php_error_docref(NULL TSRMLS_CC, E_WARNING,
+						"Unknown option %ld", idx);
+		}
+	}
+
+	if (got_ciphers == 0) {
+		set_ciphers(ctx, "DEFAULT");
+	}
+
+	if (cafile || capath) {
+		set_ca(ctx, cafile, capath);
+	}
+}
+/* }}} */
+
+/* {{{ get_ssl_method */
+static zend_always_inline SSL_METHOD *get_ssl_method(long in_method)
+{
+	SSL_METHOD *method;
+
+	switch (in_method) {
+    	case PHP_EVENT_SSLv2_CLIENT_METHOD:
+    		method = (SSL_METHOD *) SSLv2_method();
+			break;
+    	case PHP_EVENT_SSLv3_CLIENT_METHOD:
+    		method = (SSL_METHOD *) SSLv3_method();
+			break;
+    	case PHP_EVENT_SSLv23_CLIENT_METHOD:
+    		method = (SSL_METHOD *) SSLv23_method();
+			break;
+    	case PHP_EVENT_TLS_CLIENT_METHOD:
+    		method = (SSL_METHOD *) TLSv1_method();
+			break;
+    	case PHP_EVENT_SSLv2_SERVER_METHOD:
+    		method = (SSL_METHOD *) SSLv2_server_method();
+			break;
+    	case PHP_EVENT_SSLv3_SERVER_METHOD:
+    		method = (SSL_METHOD *) SSLv3_server_method();
+			break;
+    	case PHP_EVENT_SSLv23_SERVER_METHOD:
+    		method = (SSL_METHOD *) SSLv23_server_method();
+			break;
+    	case PHP_EVENT_TLS_SERVER_METHOD:
+    		method = (SSL_METHOD *) TLSv1_server_method();
+    		break;
+    	default:
+    		return NULL;
+	}
+
+	return method;
+}
+/* }}} */
+
+/* Private }}} */
+
+
+/* {{{ proto EventSslContext EventSslContext::__construct(int method, array options);
+ *
+ * Creates SSL context holding pointer to SSL_CTX.
+ * method parameter is one of EventSslContext::*_METHOD constants.
+ * options parameter is an associative array of SSL context options */
+PHP_METHOD(EventSslContext, __construct)
+{
+	php_event_ssl_context_t *ectx;
+	HashTable               *ht_options;
+	long                     in_method;
+	SSL_METHOD              *method;
+	SSL_CTX                 *ctx;
+	long                     options    = SSL_OP_ALL;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lh",
+				&in_method, &ht_options) == FAILURE) {
+		return;
+	}
+
+	method = get_ssl_method(in_method);
+	if (method == NULL) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+			"Invalid method passed: %ld", in_method);
+		return;
+	}
+
+	ctx = SSL_CTX_new(method);
+	if (ctx == NULL) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Creation of a new SSL_CTX object failed");
+		return;
+	}
+
+	PHP_EVENT_FETCH_SSL_CONTEXT(ectx, getThis());
+	ectx->ctx = ctx;
+
+	ALLOC_HASHTABLE(ectx->ht);
+	zend_hash_init_ex(ectx->ht, zend_hash_num_elements(ht_options), NULL, NULL, 0, 1);
+	zend_hash_copy(ectx->ht, ht_options, (copy_ctor_func_t) zval_add_ref,
+			(void *) NULL, sizeof(zval *));
+
+	SSL_CTX_set_options(ectx->ctx, options);
+	set_ssl_ctx_options(ectx->ctx, ectx->ht TSRMLS_CC);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4 sts=4
+ */
 PHP_ARG_WITH(event-extra, for event extra functionality support,
 [  --with-event-extra       Include libevent protocol-specific functionality support including HTTP, DNS, and RPC], yes, no)
 
+PHP_ARG_WITH(event-openssl, for OpenSSL support in event,
+[  --with-event-extra       Include libevent OpenSSL support], yes, no)
+
+PHP_ARG_WITH(openssl-dir, OpenSSL dir for FTP,
+[  --with-openssl-dir[=DIR]  Event: openssl install prefix], yes, no)
+
 PHP_ARG_ENABLE(event-debug, for ev debug support,
 [  --enable-event-debug     Enable event debug support], no, no)
 
     PHP_CHECK_LIBRARY(event_extra, evhttp_new,
     [
       PHP_ADD_LIBRARY_WITH_PATH(event_extra, $EVENT_LIB_DIR, EVENT_SHARED_LIBADD)
-      AC_DEFINE(HAVE_EVENT_EXTRA_LIB,1,[ ])
+      AC_DEFINE(HAVE_EVENT_EXTRA_LIB, 1, [ ])
     ],[
       AC_MSG_ERROR([libevent_extra >= 2.0 not found])
     ],[
       classes/http_connection.c"
   fi
   dnl }}}
+  
+  dnl {{{ --with-event-openssl
+  if test "$PHP_EVENT_OPENSSL" != "no"; then
+    test -z "$PHP_OPENSSL" && PHP_OPENSSL=no
+
+    if test -z "$PHP_OPENSSL_DIR" || test $PHP_OPENSSL_DIR == "no"; then
+      PHP_OPENSSL_DIR=yes
+    fi
+
+    PHP_SETUP_OPENSSL(EVENT_SHARED_LIBADD)
+
+    PHP_CHECK_LIBRARY(event_openssl, bufferevent_openssl_filter_new,
+    [
+      PHP_ADD_LIBRARY_WITH_PATH(event_openssl, $EVENT_LIB_DIR, EVENT_SHARED_LIBADD)
+      AC_DEFINE(HAVE_EVENT_OPENSSL_LIB, 1, [ ])
+    ], [
+        AC_MSG_ERROR([libevent_openssl >= 2.0 not found])
+    ], [
+      -L$EVENT_LIB_DIR -levent_core
+    ])
+
+    event_src="$event_src classes/ssl_context.c"
+  fi
+  dnl }}}
  
   PHP_NEW_EXTENSION(event, $event_src, $ext_shared,,$CFLAGS)
   PHP_ADD_BUILD_DIR($ext_builddir/src)
   PHP_ADD_BUILD_DIR($ext_builddir/classes)
   PHP_ADD_INCLUDE($ext_builddir/src)
   PHP_ADD_EXTENSION_DEP(event, sockets, true)
+  dnl We have this dep only because of the need of ssl transports defined in
+  dnl openssl ext.
+  PHP_ADD_EXTENSION_DEP(event, openssl, true)
   PHP_SUBST(EVENT_SHARED_LIBADD)
   PHP_SUBST(CFLAGS)
 fi

examples/ssl_echo_server.php

+<?php
+//
+// To test: socat - SSL:devbox:9999,verify=0
+//
+
+// Creates self-signed certificate in PEM format
+function create_cert($pem_file, $pem_passphrase, $pem_dn) {
+ 	$privkey = openssl_pkey_new();
+ 	$cert    = openssl_csr_new($pem_dn, $privkey);
+ 	$cert    = openssl_csr_sign($cert, null, $privkey, 365);
+
+ 	$pem = array();
+ 	openssl_x509_export($cert, $pem[0]);
+ 	openssl_pkey_export($privkey, $pem[1], $pem_passphrase);
+ 	$pem = implode($pem);
+
+ 	file_put_contents($pem_file, $pem);
+ 	chmod($pem_file, 0600);
+}
+
+// This callback is invoked when there is data to read on $bev.
+function ssl_read_cb($bev, $ctx) {
+	$in = $bev->getInput();
+
+	printf("Received %zu bytes\n", $in->length);
+    printf("----- data ----\n");
+    printf("%ld:\t%s\n", (int) $in->length, $in->pullup(-1));
+
+	$bev->writeBuffer($in);
+}
+
+function ssl_event_cb($bev, $events, $ctx) {
+	if ($events & EventBufferEvent::ERROR)
+		echo "Error from bufferevent\n";
+
+	if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) {
+		$bev->free();
+	}
+}
+
+function ssl_accept_cb($listener, $fd, $address, $ctx) {
+	// We got a new connection! Set up a bufferevent for it.
+	$base = $listener->getBase();
+
+	$bev = EventBufferEvent::sslSocket($base, $fd, $ctx,
+		EventBufferEvent::SSL_ACCEPTING, EventBufferEvent::OPT_CLOSE_ON_FREE);
+
+	if (!$bev) {
+		echo "Failed creating ssl buffer\n";
+		$base->exit(NULL);
+		exit(1);
+	}
+
+	$bev->enable(Event::READ);
+	$bev->setCallbacks("ssl_read_cb", NULL, "ssl_event_cb", NULL);
+}
+
+function accept_error_cb($listener, $ctx) {
+	$base = $listener->getBase();
+
+	fprintf(STDERR, "Got an error %d (%s) on the listener. "
+		."Shutting down.\n",
+		EventUtil::getLastSocketErrno(),
+		EventUtil::getLastSocketError());
+
+	$base->exit(NULL);
+}
+
+function init_ssl() {
+	// We *must* have entropy. Otherwise there's no point to crypto.
+	if (!EventUtil::sslRandPoll()) {
+		exit("EventUtil::sslRandPoll failed\n");
+	}
+
+	$pem_passphrase = "echo server";
+	$pem_file       = "cert.pem";
+
+	$pem_dn = array (
+ 		"countryName"            => "RU",
+ 		"stateOrProvinceName"    => "Moscow",
+ 		"localityName"           => "Moscow",
+ 		"organizationName"       => "Fancy Company",
+ 		"organizationalUnitName" => "Fancy Department",
+ 		"commonName"             => "devbox",
+ 		"emailAddress"           => "rrosmanov@gmail.com"
+	);
+	create_cert($pem_file, $pem_passphrase, $pem_dn);
+
+	$ctx = new EventSslContext(EventSslContext::SSLv23_SERVER_METHOD, array (
+ 		EventSslContext::OPT_LOCAL_CERT        => $pem_file,
+ 		EventSslContext::OPT_PASSPHRASE        => $pem_passphrase,
+ 		EventSslContext::OPT_ALLOW_SELF_SIGNED => true,
+ 		EventSslContext::OPT_VERIFY_PEER       => false,
+	));
+	return $ctx;
+}
+
+$port = 9999;
+if ($argc > 1) {
+	$port = (int) $argv[1];
+}
+if ($port <= 0 || $port > 65535) {
+	exit("Invalid port\n");
+}
+
+$host = "127.0.0.1";
+
+$ctx = init_ssl();
+if (!$ctx) {
+	exit("Failed creating SSL context\n");
+}
+
+$base = new EventBase();
+if (!$base) {
+	exit("Couldn't open event base\n");
+}
+
+$listener = new EventListener($base, "ssl_accept_cb", $ctx,
+	EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE,
+	-1, "$host:$port");
+if (!$listener) {
+	exit("Couldn't create listener\n");
+}
+$listener->setErrorCallback("accept_error_cb");
+
+$base->dispatch();
     <email>osmanov@php.net</email>
     <active>yes</active>
   </lead>
-  <date>2013-02-06</date>
+  <date>2013-02-12</date>
   <!--{{{ Current version -->
   <version>
-    <release>1.1.2</release>
-    <api>1.1.0</api>
+    <release>1.2.0</release>
+    <api>1.2.0</api>
   </version>
   <stability>
-    <release>beta</release>
-    <api>beta</api>
+    <release>alpha</release>
+    <api>alpha</api>
   </stability>
   <license uri="http://www.php.net/license">PHP</license>
   <notes><![CDATA[
   setPosition methods
   Add: EventBufferPosition class
   Fix: configure error in FreeBSD
+  Add: OpenSSL support: EventBufferEvent methods: sslFilter, sslSocket, EventSslContext class
+  Add: EventBuffer::pullup
   ]]></notes>
   <!--}}}-->
   <!--{{{ Contents -->
         <file role="src" name="base.c"/>
         <file role="src" name="buffer.c"/>
         <file role="src" name="buffer_event.c"/>
+        <file role="src" name="buffer_pos.c"/>
         <file role="src" name="dns.c"/>
         <file role="src" name="event.c"/>
         <file role="src" name="event_config.c"/>
         <file role="src" name="http.c"/>
         <file role="src" name="http_connection.c"/>
         <file role="src" name="listener.c"/>
+        <file role="src" name="ssl_context.c"/>
       </dir>
       <dir name="examples">
         <file role="doc" name="buffer_proxy.php"/>
+        <file role="doc" name="ssl_echo_server.php"/>
         <file role="doc" name="eio.php"/>
         <file role="doc" name="fibonacci_buffer.php"/>
         <file role="doc" name="httpv0client.php"/>
   <extsrcrelease>
     <configureoption default="no" name="enable-event-debug" prompt="Enable internal debugging in event"/>
     <configureoption default="yes" name="with-event-extra" prompt="Include libevent protocol-specific functionality support including HTTP, DNS, and RPC"/>
+    <configureoption default="yes" name="with-event-openssl" prompt="Include libevent OpenSSL support"/>
+    <configureoption default="yes" name="with-openssl-dir" prompt="Event: openssl install prefix"/>
   </extsrcrelease>
   <!--{{{ changelog-->
   <changelog>
-  <!--{{{ 1.1.1-beta-->
+  <!--{{{ 1.2.0-alpha-->
   <release>
   <version>
-    <release>1.1.2</release>
-    <api>1.1.0</api>
+    <release>1.2.0</release>
+    <api>1.2.0</api>
   </version>
   <stability>
-    <release>beta</release>
-    <api>beta</api>
+    <release>alpha</release>
+    <api>alpha</api>
   </stability>
   <license uri="http://www.php.net/license">PHP</license>
   <notes><![CDATA[
   setPosition methods
   Add: EventBufferPosition class
   Fix: configure error in FreeBSD
+  Add: OpenSSL support: EventBufferEvent methods: sslFilter, sslSocket, EventSslContext class
+  Add: EventBuffer::pullup
   ]]></notes>
   </release>
   <!--}}}-->
 #include "src/util.h"
 #include "src/priv.h"
 
-/*
+#if 0
 ZEND_DECLARE_MODULE_GLOBALS(event)
-*/
+static PHP_GINIT_FUNCTION(event);
+#endif
 
 zend_class_entry *php_event_ce;
 zend_class_entry *php_event_base_ce;
 zend_class_entry *php_event_buffer_ce;
 zend_class_entry *php_event_util_ce;
 zend_class_entry *php_event_buffer_pos_ce;
+#ifdef HAVE_EVENT_OPENSSL_LIB
+zend_class_entry *php_event_ssl_context_ce;
+#endif
 
-#if HAVE_EVENT_EXTRA_LIB
+#ifdef HAVE_EVENT_EXTRA_LIB
 zend_class_entry *php_event_dns_base_ce;
 zend_class_entry *php_event_listener_ce;
 zend_class_entry *php_event_http_conn_ce;
 
 static const zend_module_dep event_deps[] = {
 	ZEND_MOD_OPTIONAL("sockets")
+	ZEND_MOD_OPTIONAL("openssl")
 	{NULL, NULL, NULL}
 };
 
 #if ZEND_MODULE_API_NO >= 20010901
 	PHP_EVENT_VERSION,
 #endif
-	STANDARD_MODULE_PROPERTIES
+#if 0
+    PHP_MODULE_GLOBALS(event),
+    PHP_GINIT(event),
+    NULL,
+    NULL,
+    STANDARD_MODULE_PROPERTIES_EX
+#endif
+    STANDARD_MODULE_PROPERTIES
 };
 /* }}} */
 
 }
 /* }}} */
 
+/* {{{ event_ssl_context_object_free_storage */
+static void event_ssl_context_object_free_storage(void *ptr TSRMLS_DC)
+{
+	php_event_ssl_context_t *ectx = (php_event_ssl_context_t *) ptr;
+
+	if (ectx->ctx) {
+		SSL_CTX_free(ectx->ctx);
+		ectx->ctx = NULL;
+	}
+
+	if (ectx->ht) {
+		/*zend_hash_destroy(ectx->ht);*/
+		FREE_HASHTABLE(ectx->ht);
+		ectx->ht = NULL;
+	}
+
+	event_generic_object_free_storage(ptr TSRMLS_CC);
+}
+/* }}} */
+
 
 /* {{{ register_object */
 static zend_always_inline zend_object_value register_object(zend_class_entry *ce, void *obj, zend_objects_store_dtor_t func_dtor, zend_objects_free_object_storage_t func_free_storage TSRMLS_DC)
 }
 /* }}} */
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+/* {{{ event_ssl_context_object_create
+ * EventBufferPosition object ctor */
+static zend_object_value event_ssl_context_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+	php_event_abstract_object_t *obj = (php_event_abstract_object_t *)
+		object_new(ce, sizeof(php_event_ssl_context_t) TSRMLS_CC);
+
+	return register_object(ce, (void *) obj,
+			(zend_objects_store_dtor_t) zend_objects_destroy_object,
+			event_ssl_context_object_free_storage TSRMLS_CC);
+}
+/* }}} */
+#endif
+
 #if HAVE_EVENT_EXTRA_LIB
 
 /* {{{ event_dns_base_object_create
 	zend_hash_init(&event_properties, 0, NULL, NULL, 1);
 	PHP_EVENT_ADD_CLASS_PROPERTIES(&event_properties, event_property_entries);
 	PHP_EVENT_DECL_CLASS_PROPERTIES(ce, event_property_entry_info);
-	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_properties, sizeof(event_properties), NULL);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_properties,
+			sizeof(event_properties), NULL);
 
 	PHP_EVENT_REGISTER_CLASS("EventBase", event_base_object_create, php_event_base_ce,
 			php_event_base_ce_functions);
 	zend_hash_init(&event_base_properties, 0, NULL, NULL, 1);
 	PHP_EVENT_ADD_CLASS_PROPERTIES(&event_base_properties, event_base_property_entries);
 	PHP_EVENT_DECL_CLASS_PROPERTIES(ce, event_base_property_entry_info);
-	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_base_properties, sizeof(event_base_properties), NULL);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_base_properties,
+			sizeof(event_base_properties), NULL);
 
 	PHP_EVENT_REGISTER_CLASS("EventConfig", event_config_object_create, php_event_config_ce,
 			php_event_config_ce_functions);
 	zend_hash_init(&event_config_properties, 0, NULL, NULL, 1);
 	PHP_EVENT_ADD_CLASS_PROPERTIES(&event_config_properties, event_config_property_entries);
 	PHP_EVENT_DECL_CLASS_PROPERTIES(ce, event_config_property_entry_info);
-	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_config_properties, sizeof(event_config_properties), NULL);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_config_properties,
+			sizeof(event_config_properties), NULL);
 
 	PHP_EVENT_REGISTER_CLASS("EventBufferEvent", event_bevent_object_create, php_event_bevent_ce,
 			php_event_bevent_ce_functions);
 	zend_hash_init(&event_bevent_properties, 0, NULL, NULL, 1);
 	PHP_EVENT_ADD_CLASS_PROPERTIES(&event_bevent_properties, event_bevent_property_entries);
 	PHP_EVENT_DECL_CLASS_PROPERTIES(ce, event_bevent_property_entry_info);
-	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_bevent_properties, sizeof(event_bevent_properties), NULL);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_bevent_properties,
+			sizeof(event_bevent_properties), NULL);
 
 	PHP_EVENT_REGISTER_CLASS("EventBuffer", event_buffer_object_create, php_event_buffer_ce,
 			php_event_buffer_ce_functions);
 	ce = php_event_buffer_ce;
 	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
-	zend_hash_init(&event_buffer_properties, 0, NULL, NULL, 1);
+	zend_hash_init(&event_buffer_properties, 2, NULL, NULL, 1);
 	PHP_EVENT_ADD_CLASS_PROPERTIES(&event_buffer_properties, event_buffer_property_entries);
 	PHP_EVENT_DECL_CLASS_PROPERTIES(ce, event_buffer_property_entry_info);
-	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_buffer_properties, sizeof(event_buffer_properties), NULL);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_buffer_properties,
+			sizeof(event_buffer_properties), NULL);
 
-	PHP_EVENT_REGISTER_CLASS("EventBufferPosition", event_buffer_pos_object_create, php_event_buffer_pos_ce,
+	PHP_EVENT_REGISTER_CLASS("EventBufferPosition", event_buffer_pos_object_create,
+			php_event_buffer_pos_ce,
 			php_event_buffer_pos_ce_functions);
 	ce = php_event_buffer_pos_ce;
 	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
 	zend_hash_init(&event_buffer_pos_properties, 0, NULL, NULL, 1);
 	PHP_EVENT_ADD_CLASS_PROPERTIES(&event_buffer_pos_properties, event_buffer_pos_property_entries);
 	PHP_EVENT_DECL_CLASS_PROPERTIES(ce, event_buffer_pos_property_entry_info);
-	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_buffer_pos_properties, sizeof(event_buffer_pos_properties), NULL);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &event_buffer_pos_properties,
+			sizeof(event_buffer_pos_properties), NULL);
 
 #if HAVE_EVENT_EXTRA_LIB
-
 	PHP_EVENT_REGISTER_CLASS("EventDnsBase", event_dns_base_object_create, php_event_dns_base_ce,
 			php_event_dns_base_ce_functions);
 	ce = php_event_dns_base_ce;
 	ce = php_event_listener_ce;
 	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
 
-	PHP_EVENT_REGISTER_CLASS("EventHttpConnection", event_http_conn_object_create, php_event_http_conn_ce,
+	PHP_EVENT_REGISTER_CLASS("EventHttpConnection", event_http_conn_object_create,
+			php_event_http_conn_ce,
 			php_event_http_conn_ce_functions);
 	ce = php_event_http_conn_ce;
 	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
 			php_event_http_ce_functions);
 	ce = php_event_http_ce;
 	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
-
 #endif /* HAVE_EVENT_EXTRA_LIB */
 
 	PHP_EVENT_REGISTER_CLASS("EventUtil", event_util_object_create, php_event_util_ce,
 	ce = php_event_util_ce;
 	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+	PHP_EVENT_REGISTER_CLASS("EventSslContext", event_ssl_context_object_create,
+			php_event_ssl_context_ce,
+			php_event_ssl_context_ce_functions);
+	ce = php_event_ssl_context_ce;
+	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
+#endif /* HAVE_EVENT_OPENSSL_LIB */
+
 }
 /* }}} */
 
 /* Private functions }}} */
 
+#if 0
+/* {{{ PHP_GINIT_FUNCTION */ 
+static PHP_GINIT_FUNCTION(event)
+{
+	event_globals->ssl_dummy_stream = NULL;
+}
+/* }}} */
+#endif
 
 #define REGISTER_EVENT_CLASS_CONST_LONG(pce, const_name, value) \
     zend_declare_class_constant_long((pce), #const_name,        \
 	object_handlers.get_debug_info       = object_get_debug_info;
 #endif
 
-	zend_hash_init(&classes, 0, NULL, NULL, 1);
+	zend_hash_init(&classes, 8, NULL, NULL, 1);
 	register_classes(TSRMLS_C);
 
 	/* Loop flags */
 #if LIBEVENT_VERSION_NUMBER >= 0x02000500
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_bevent_ce, OPT_UNLOCK_CALLBACKS, BEV_OPT_UNLOCK_CALLBACKS);
 #endif
+#ifdef HAVE_EVENT_OPENSSL_LIB
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_bevent_ce, SSL_OPEN,       BUFFEREVENT_SSL_OPEN);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_bevent_ce, SSL_CONNECTING, BUFFEREVENT_SSL_CONNECTING);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_bevent_ce, SSL_ACCEPTING,  BUFFEREVENT_SSL_ACCEPTING);
+#endif
 
 	/* Address families */
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, AF_INET,   AF_INET);
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_buffer_ce, PTR_SET,         EVBUFFER_PTR_SET);
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_buffer_ce, PTR_ADD,         EVBUFFER_PTR_ADD);
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, SSLv2_CLIENT_METHOD,  PHP_EVENT_SSLv2_CLIENT_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, SSLv3_CLIENT_METHOD,  PHP_EVENT_SSLv3_CLIENT_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, SSLv23_CLIENT_METHOD, PHP_EVENT_SSLv23_CLIENT_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, TLS_CLIENT_METHOD,    PHP_EVENT_TLS_CLIENT_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, SSLv2_SERVER_METHOD,  PHP_EVENT_SSLv2_SERVER_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, SSLv3_SERVER_METHOD,  PHP_EVENT_SSLv3_SERVER_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, SSLv23_SERVER_METHOD, PHP_EVENT_SSLv23_SERVER_METHOD);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, TLS_SERVER_METHOD,    PHP_EVENT_TLS_SERVER_METHOD);
+
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_LOCAL_CERT,        PHP_EVENT_OPT_LOCAL_CERT);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_LOCAL_PK,          PHP_EVENT_OPT_LOCAL_PK);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_PASSPHRASE,        PHP_EVENT_OPT_PASSPHRASE);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_CA_FILE,           PHP_EVENT_OPT_CA_FILE);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_CA_PATH,           PHP_EVENT_OPT_CA_PATH);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_ALLOW_SELF_SIGNED, PHP_EVENT_OPT_ALLOW_SELF_SIGNED);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_VERIFY_PEER,       PHP_EVENT_OPT_VERIFY_PEER);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_VERIFY_DEPTH,      PHP_EVENT_OPT_VERIFY_DEPTH);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_ssl_context_ce, OPT_CIPHERS,           PHP_EVENT_OPT_CIPHERS);
+#endif
+
 	/* Handle libevent's error logging more gracefully than it's default
 	 * logging to stderr, or calling abort()/exit() */
 	event_set_fatal_callback(fatal_error_cb);
 #else
 	php_info_print_table_row(2, "Debug support", "disabled");
 #endif
+#ifdef HAVE_EVENT_EXTRA_LIB
+	php_info_print_table_row(2, "Extra functionality support including HTTP, DNS, and RPC", "enabled");
+#else
+	php_info_print_table_row(2, "Extra functionality support including HTTP, DNS, and RPC", "disabled");
+#endif
+#ifdef HAVE_EVENT_OPENSSL_LIB
+	php_info_print_table_row(2, "OpenSSL support", "enabled");
+#else
+	php_info_print_table_row(2, "OpenSSL support", "disabled");
+#endif
+
 	php_info_print_table_row(2, "Version", PHP_EVENT_VERSION);
 	php_info_print_table_end();
 }
 #ifndef PHP_EVENT_H
 #define PHP_EVENT_H
 
-#define PHP_EVENT_VERSION "1.1.2-beta"
+#define PHP_EVENT_VERSION "1.2.0-beta"
 
 
 extern zend_module_entry event_module_entry;
 
 #if 0
 ZEND_BEGIN_MODULE_GLOBALS(event)
+	php_stream *ssl_dummy_stream;
 ZEND_END_MODULE_GLOBALS(event)
+ZEND_EXTERN_MODULE_GLOBALS(event)
 #endif
 
 #ifdef ZTS
 # include <event2/tag.h>
 #endif
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+# include <event2/bufferevent_ssl.h>
+#endif
+
 #if !defined(_WIN32) && !defined(_MINIX)
 # include <pthread.h>
 #endif
 # error "This version of Libevent is not supported; get 2.0.2-alpha or later."
 #endif
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+# include <openssl/evp.h>
+# include <openssl/x509.h>
+# include <openssl/x509v3.h>
+# include <openssl/crypto.h>
+# include <openssl/pem.h>
+# include <openssl/err.h>
+# include <openssl/conf.h>
+# include <openssl/rand.h>
+# include <openssl/ssl.h>
+# include <openssl/pkcs12.h>
+#endif
+
 #include "php_event.h"
 #include "structs.h"
 
 	ZEND_ARG_INFO(0, timeout_write)
 ZEND_END_ARG_INFO();
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+ZEND_BEGIN_ARG_INFO_EX(arginfo_bufferevent_ssl_filter, 0, 0, 4)
+	ZEND_ARG_INFO(0, base)
+	ZEND_ARG_INFO(0, underlying)
+	ZEND_ARG_INFO(0, ctx)
+	ZEND_ARG_INFO(0, state)
+	ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_bufferevent_ssl_socket, 0, 0, 4)
+	ZEND_ARG_INFO(0, base)
+	ZEND_ARG_INFO(0, socket)
+	ZEND_ARG_INFO(0, ctx)
+	ZEND_ARG_INFO(0, state)
+	ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO();
+#endif
 
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_freeze, 0, 0, 1)
 	ZEND_ARG_INFO(0, how)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_pullup, 0, 0, 1)
+	ZEND_ARG_INFO(0, size)
+ZEND_END_ARG_INFO();
+
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_event_socket_1, 0, 0, 0)
 	ZEND_ARG_INFO(0, socket)
 	ZEND_ARG_INFO(0, port)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_event_ssl_context__construct, 0, 0, 2)
+	ZEND_ARG_INFO(0, method)
+	ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO();
 
 /* ARGINFO END }}} */
 
 	PHP_ME(EventBufferEvent, createPair,        arginfo_bufferevent_pair_new,                ZEND_ACC_PUBLIC)
 	PHP_ME(EventBufferEvent, setPriority,       arginfo_bufferevent_priority_set,            ZEND_ACC_PUBLIC)
 	PHP_ME(EventBufferEvent, setTimeouts,       arginfo_bufferevent_set_timeouts,            ZEND_ACC_PUBLIC)
+#ifdef HAVE_EVENT_OPENSSL_LIB
+	PHP_ME(EventBufferEvent, sslFilter,         arginfo_bufferevent_ssl_filter,              ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventBufferEvent, sslSocket,         arginfo_bufferevent_ssl_socket,              ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#endif
 
 	PHP_FE_END
 };
 	PHP_ME(EventBuffer, readLine,      arginfo_evbuffer_read_line,     ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, search,        arginfo_evbuffer_search,        ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, setPosition,   arginfo_evbuffer_set_position,  ZEND_ACC_PUBLIC)
+	PHP_ME(EventBuffer, pullup,        arginfo_evbuffer_pullup,        ZEND_ACC_PUBLIC)
 
 	PHP_FE_END
 };
 
 	PHP_ME(EventUtil, getLastSocketErrno, arginfo_event_socket_1, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 	PHP_ME(EventUtil, getLastSocketError, arginfo_event_socket_1, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventUtil, sslRandPoll,        arginfo_event__void,    ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 
 	PHP_FE_END
 };
 /* Extra API END}}} */
 #endif
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+const zend_function_entry php_event_ssl_context_ce_functions[] = {/* {{{ */
+	PHP_ME(EventSslContext, __construct, arginfo_event_ssl_context__construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+
+	PHP_FE_END
+};
+/* }}} */
+#endif
+
 /*
  * Local variables:
  * tab-width: 4
 PHP_METHOD(EventBufferEvent, readBuffer);
 PHP_METHOD(EventBufferEvent, setPriority);
 PHP_METHOD(EventBufferEvent, setTimeouts);
+#ifdef HAVE_EVENT_OPENSSL_LIB
+PHP_METHOD(EventBufferEvent, sslFilter);
+PHP_METHOD(EventBufferEvent, sslSocket);
+#endif
 
 PHP_METHOD(EventBuffer, __construct);
 PHP_METHOD(EventBuffer, freeze);
 PHP_METHOD(EventBuffer, readLine);
 PHP_METHOD(EventBuffer, search);
 PHP_METHOD(EventBuffer, setPosition);
+PHP_METHOD(EventBuffer, pullup);
 
 PHP_METHOD(EventUtil, getLastSocketErrno);
 PHP_METHOD(EventUtil, getLastSocketError);
+PHP_METHOD(EventUtil, sslRandPoll);
 
 PHP_METHOD(EventBufferPosition, __construct);
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+PHP_METHOD(EventSslContext, __construct);
+#endif
+
 #if HAVE_EVENT_EXTRA_LIB
 /* {{{ Extra API */
 
 }
 /* }}} */
 
-/* {{{ event_bevent_priority_write */
-static int event_bevent_priority_write(php_event_abstract_object_t *obj, zval *value TSRMLS_DC)
+/* {{{ event_bevent_priority_prop_write*/
+static int event_bevent_priority_prop_write(php_event_abstract_object_t *obj, zval *value TSRMLS_DC)
 {
 	php_event_bevent_t *bev = (php_event_bevent_t *) obj;
 	long priority           = Z_LVAL_P(value);
 }
 /* }}} */
 
+/* {{{ event_bevent_priority_prop_read */
+static int event_bevent_priority_prop_read(php_event_abstract_object_t *obj, zval **retval TSRMLS_DC)
+{
+	ALLOC_INIT_ZVAL(*retval);
+	return SUCCESS;
+}
+/* }}} */
 
 const php_event_property_entry_t event_property_entries[] = {
 	{"timer_pending",           sizeof("timer_pending") - 1, event_timer_pending_prop_read, NULL, NULL},
     {NULL, 0, NULL, NULL, NULL}
 };
 const php_event_property_entry_t event_bevent_property_entries[] = {
-	{"priority", sizeof("priority") - 1, NULL, event_bevent_priority_write, NULL},
+	{"priority", sizeof("priority") - 1, event_bevent_priority_prop_read, event_bevent_priority_prop_write, NULL },
     {NULL, 0, NULL, NULL, NULL}
 };
 const php_event_property_entry_t event_buffer_property_entries[] = {
 extern const zend_function_entry php_event_buffer_ce_functions[];
 extern const zend_function_entry php_event_util_ce_functions[];
 extern const zend_function_entry php_event_buffer_pos_ce_functions[];
+extern const zend_function_entry php_event_ssl_context_ce_functions[];
 
 extern zend_class_entry *php_event_ce;
 extern zend_class_entry *php_event_base_ce;
 extern zend_class_entry *php_event_buffer_ce;
 extern zend_class_entry *php_event_buffer_pos_ce;
 extern zend_class_entry *php_event_util_ce;
+#ifdef HAVE_EVENT_OPENSSL_LIB
+extern zend_class_entry *php_event_ssl_context_ce;
+#endif
 
 extern const php_event_property_entry_t event_property_entries[];
 extern const php_event_property_entry_t event_base_property_entries[];
 extern const zend_property_info event_buffer_pos_property_entry_info[];
 
 #if HAVE_EVENT_EXTRA_LIB
-
 extern const zend_function_entry php_event_dns_base_ce_functions[];
 extern const zend_function_entry php_event_http_conn_ce_functions[];
 extern const zend_function_entry php_event_http_ce_functions[];
 extern const zend_property_info event_listener_property_entry_info[];
 extern const zend_property_info event_http_conn_property_entry_info[];
 extern const zend_property_info event_http_property_entry_info[];
-
-#endif
+#endif /* HAVE_EVENT_EXTRA_LIB */
 
 
 #endif /* PHP_EVENT_PRIV_H */
 
 /* php_event_abstract_object_t is for type casting only. However, all the
  * class objects must have the same fields at the head of their structs */
-typedef struct {
+typedef struct _php_event_abstract_object_t {
 	PHP_EVENT_OBJECT_HEAD;
-} php_event_abstract_object_t; 
+} php_event_abstract_object_t;
 
 /* Represents Event object */
-typedef struct {
+typedef struct _php_event_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct event          *event;       /* Pointer returned by event_new                        */
 } php_event_t;
 
 /* Represents EventBase object */
-typedef struct {
+typedef struct _php_event_base_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct event_base *base;
 } php_event_base_t;
 
 /* Represents EventConfig object */
-typedef struct {
+typedef struct _php_event_config_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct event_config *ptr;
 } php_event_config_t;
 
 /* Represents EventBufferEvent object */
-typedef struct {
+typedef struct _php_event_bevent_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct bufferevent    *bevent;
 } php_event_bevent_t;
 
 /* Represents EventBuffer object */
-typedef struct {
+typedef struct _php_event_buffer_t {
 	PHP_EVENT_OBJECT_HEAD;
 	zend_bool internal; /* Whether is an internal buffer of a bufferevent */
 
 #ifdef HAVE_EVENT_EXTRA_LIB/* {{{ */
 
 /* Represents EventDnsBase object */
-typedef struct {
+typedef struct _php_event_dns_base_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct evdns_base *dns_base;
 } php_event_dns_base_t;
 
 /* Represents EventListener object */
-typedef struct {
+typedef struct _php_event_listener_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct evconnlistener *listener;
 } php_event_listener_t;
 
 /* Represents EventHttpConnection object */
-typedef struct {
+typedef struct _php_event_http_conn_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct evhttp_connection *conn;
 
 #endif/* HAVE_EVENT_EXTRA_LIB }}} */
 
-typedef struct {
+typedef struct _php_event_buffer_pos_t {
 	PHP_EVENT_OBJECT_HEAD;
 
 	struct evbuffer_ptr p;
 } php_event_buffer_pos_t;
 
+#ifdef HAVE_EVENT_OPENSSL_LIB
+
+enum {
+	PHP_EVENT_OPT_LOCAL_CERT        = 1,
+	PHP_EVENT_OPT_LOCAL_PK          = 2,
+	PHP_EVENT_OPT_PASSPHRASE        = 3,
+	PHP_EVENT_OPT_CA_FILE           = 4,
+	PHP_EVENT_OPT_CA_PATH           = 5,
+	PHP_EVENT_OPT_ALLOW_SELF_SIGNED = 6,
+	PHP_EVENT_OPT_VERIFY_PEER       = 7,
+	PHP_EVENT_OPT_VERIFY_DEPTH      = 8,
+	PHP_EVENT_OPT_CIPHERS           = 9
+};
+
+enum {
+    PHP_EVENT_SSLv2_CLIENT_METHOD  = 1,
+    PHP_EVENT_SSLv3_CLIENT_METHOD  = 2,
+    PHP_EVENT_SSLv23_CLIENT_METHOD = 3,
+    PHP_EVENT_TLS_CLIENT_METHOD    = 4,
+    PHP_EVENT_SSLv2_SERVER_METHOD  = 5,
+    PHP_EVENT_SSLv3_SERVER_METHOD  = 6,
+    PHP_EVENT_SSLv23_SERVER_METHOD = 7,
+    PHP_EVENT_TLS_SERVER_METHOD    = 8
+};
+
+typedef struct _php_event_ssl_context_t {
+	PHP_EVENT_OBJECT_HEAD;
+
+	SSL_CTX *ctx;
+	HashTable *ht;
+} php_event_ssl_context_t;
+#endif
+
 typedef double php_event_timestamp_t;
 
 typedef int (*php_event_prop_read_t)(php_event_abstract_object_t *obj, zval **retval TSRMLS_DC);
 typedef int (*php_event_prop_write_t)(php_event_abstract_object_t *obj, zval *newval  TSRMLS_DC);
 typedef zval **(*php_event_prop_get_prop_ptr_ptr_t)(php_event_abstract_object_t *obj TSRMLS_DC);
 
-typedef struct {
+typedef struct _php_event_property_entry_t {
 	const char                        *name;
 	size_t                             name_length;
 	php_event_prop_read_t              read_func;
 	php_event_prop_get_prop_ptr_ptr_t  get_ptr_ptr_func;
 } php_event_property_entry_t;
 
-typedef struct {
+typedef struct _php_event_prop_handler_t {
 	char                              *name;
 	size_t                             name_len;
 	php_event_prop_read_t              read_func;
 }
 /* }}} */
 
+/* {{{ php_event_ssl_dummy_stream
+ * Creates a dummy ssl stream which may be used to detect whether a stream is an ssl stream */
+php_stream *php_event_ssl_dummy_stream(void)
+{
+	char *errstr = NULL;
+	int errcode  = 0;
+
+	php_stream *ssl_stream = php_stream_xport_create("ssl://127.0.0.1:445",
+			sizeof("ssl://127.0.0.1:445") - 1, 0,
+			STREAM_XPORT_CLIENT, NULL, NULL, NULL, &errstr, &errcode);
+
+	return ssl_stream;
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
 #define PHP_EVENT_UTIL_H
 
 php_socket_t php_event_zval_to_fd(zval **ppfd TSRMLS_DC);
+php_stream *php_event_ssl_dummy_stream(void);
 
 #define php_event_is_pending(e) \
 	event_pending((e), EV_READ | EV_WRITE | EV_SIGNAL | EV_TIMEOUT, NULL)
 #define PHP_EVENT_FETCH_BUFFER_POS(p, zp) \
 	p = (php_event_buffer_pos_t *) zend_object_store_get_object(zp TSRMLS_CC)
 
+#define PHP_EVENT_FETCH_SSL_CONTEXT(p, zp) \
+	p = (php_event_ssl_context_t *) zend_object_store_get_object(zp TSRMLS_CC)
+
 #define PHP_EVENT_TIMEVAL_SET(tv, t)                     \
         do {                                             \
             tv.tv_sec  = (long) t;                       \