Ruslan Osmanov avatar Ruslan Osmanov committed ae24707

Fix: misc segfaults, missing list refcount increments etc.
Add: bufferevent_socket_connect_hostname, bufferevent_get_input, bufferevent_get_output, evbuffer_new, evbuffer_free, evbuffer_freeze, evbuffer_get_length, evbuffer_lock, evbuffer_unlock, evbuffer_enable_locking, evbuffer_add, evbuffer_remove
Change: renamed event_dns_* to evdns_*
Add: some examples(dir)
Change: release/api versions marked devel

Comments (0)

Files changed (9)

 static int le_event_config;
 /* Represents bufferevent returned by ex. bufferevent_socket_new() */
 static int le_event_bevent;
+/* Represents php_event_buffer_t(struct evbuffer)*/
+static int le_event_buffer;
 
 #if HAVE_EVENT_EXTRA_LIB
 static int le_event_dns_base;
 #define PHP_EVENT_FETCH_BEVENT(b, zb) \
 	ZEND_FETCH_RESOURCE((b), php_event_bevent_t *, &(zb), -1, PHP_EVENT_BEVENT_RES_NAME, le_event_bevent)
 
+#define PHP_EVENT_FETCH_BUFFER(b, zb) \
+	ZEND_FETCH_RESOURCE((b), php_event_buffer_t *, &(zb), -1, PHP_EVENT_BUFFER_RES_NAME, le_event_buffer)
+
 #define PHP_EVENT_FETCH_DNS_BASE(b, zb) \
 	ZEND_FETCH_RESOURCE((b), php_event_dns_base_t *, &(zb), -1, PHP_EVENT_DNS_BASE_RES_NAME, le_event_dns_base)
 
 
 /* {{{ bevent_rw_cb
  * Is called from the bufferevent read and write callbacks */
-static zend_always_inline void bevent_rw_cb(struct bufferevent *bevent, void *ptr, zend_fcall_info *pfci, zend_fcall_info_cache *pfcc)
+static zend_always_inline void bevent_rw_cb(struct bufferevent *bevent, php_event_bevent_t *bev, zend_fcall_info *pfci, zend_fcall_info_cache *pfcc)
 {
-	php_event_bevent_t *bev = (php_event_bevent_t *) ptr;
-
+	PHP_EVENT_ASSERT(bev);
 	PHP_EVENT_ASSERT(pfci && pfcc);
 
 	zval  *arg_data   = bev->data;
 		/* Setup callback args */
 		MAKE_STD_ZVAL(arg_bevent);
 
-		PHP_EVENT_ASSERT(bev->stream_id >= 0);
+		PHP_EVENT_ASSERT(bev->rsrc_id > 0);
 
-		if (bev->stream_id >= 0) {
-			ZVAL_RESOURCE(arg_bevent, bev->stream_id);
-			zend_list_addref(bev->stream_id);
+		if (bev->rsrc_id > 0) {
+			ZVAL_RESOURCE(arg_bevent, bev->rsrc_id);
+			zend_list_addref(bev->rsrc_id);
 		} else {
 			ZVAL_NULL(arg_bevent);
 		}
 {
 	php_event_bevent_t *bev = (php_event_bevent_t *) ptr;
 
-	bevent_rw_cb(bevent, ptr, bev->fci_read, bev->fcc_read);
+	bevent_rw_cb(bevent, bev, bev->fci_read, bev->fcc_read);
 }
 /* }}} */
 
 {
 	php_event_bevent_t *bev = (php_event_bevent_t *) ptr;
 
-	bevent_rw_cb(bevent, ptr, bev->fci_write, bev->fcc_write);
+	bevent_rw_cb(bevent, bev, bev->fci_write, bev->fcc_write);
 }
 /* }}} */
 
 		/* Setup callback args */
 		MAKE_STD_ZVAL(arg_bevent);
 
-		PHP_EVENT_ASSERT(bev->stream_id >= 0);
+		PHP_EVENT_ASSERT(bev->rsrc_id > 0);
 
-		if (bev->stream_id >= 0) {
-			ZVAL_RESOURCE(arg_bevent, bev->stream_id);
-			zend_list_addref(bev->stream_id);
+		if (bev->rsrc_id >= 0) {
+			ZVAL_RESOURCE(arg_bevent, bev->rsrc_id);
+			zend_list_addref(bev->rsrc_id);
 		} else {
 			ZVAL_NULL(arg_bevent);
 		}
 }
 /* }}} */
 
+/* {{{ php_event_buffer_dtor*/
+static void php_event_buffer_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+	php_event_buffer_t *b = (php_event_buffer_t *) rsrc->ptr;
+
+	if (b) {
+		evbuffer_free(b->buf);
+		efree(b);
+	}
+}
+/* }}} */
+
 /* {{{ php_event_dns_base_dtor */
 static void php_event_dns_base_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 {
 	le_event_base     = zend_register_list_destructors_ex(php_event_base_dtor,     NULL, PHP_EVENT_BASE_RES_NAME,     module_number);
 	le_event_config   = zend_register_list_destructors_ex(php_event_config_dtor,   NULL, PHP_EVENT_CONFIG_RES_NAME,   module_number);
 	le_event_bevent   = zend_register_list_destructors_ex(php_event_bevent_dtor,   NULL, PHP_EVENT_BEVENT_RES_NAME,   module_number);
+	le_event_buffer   = zend_register_list_destructors_ex(php_event_buffer_dtor,   NULL, PHP_EVENT_BUFFER_RES_NAME,   module_number);
 	le_event_dns_base = zend_register_list_destructors_ex(php_event_dns_base_dtor, NULL, PHP_EVENT_DNS_BASE_RES_NAME, module_number);
 
 	/* Loop flags */
 }
 /* }}} */
 
-/* {{{ proto bool bufferevent_socket_connect(resource bevent, resource dns_base, string hostname, int port[, int family = EVENT_AF_UNSPEC]);
+/* {{{ proto bool bufferevent_socket_connect_hostname(resource bevent, resource dns_base, string hostname, int port[, int family = EVENT_AF_UNSPEC]);
  *
  * Resolves the DNS name hostname, looking for addresses of type
  * family(EVENT_AF_* constants). If the name resolution fails, it invokes the
  * event_dns_base_new()(requires --with-event-extra configure option).
  * For asyncronous hostname resolving pass a valid event dns base resource.
  * Otherwise the hostname resolving will block.
+ * Recognized hostname formats are:
+ * www.example.com (hostname) 1.2.3.4 (ipv4address) ::1 (ipv6address) [::1] ([ipv6address])
  */
 PHP_FUNCTION(bufferevent_socket_connect_hostname)
 {
 #else
 	php_event_bevent_t   *bev;
 	zval                 *zbevent;
-	php_event_dns_base_t *dnsb;
 	zval                 *zdns_base;
 	char                 *hostname;
 	int                   hostname_len;
 
 	PHP_EVENT_FETCH_BEVENT(bev, zbevent);
 
+	/* bufferevent_socket_connect() allocates a socket stream internally, if we
+	 * didn't provide the file descriptor to the bufferevent before, e.g. with
+	 * bufferevent_socket_new() */
+
+#if HAVE_EVENT_EXTRA_LIB
+	php_event_dns_base_t *dnsb;
+
 	if (zdns_base) {
 		PHP_EVENT_FETCH_DNS_BASE(dnsb, zdns_base);
+		PHP_EVENT_ASSERT(dnsb->rsrc_id);
 	}
 
-	/* bufferevent_socket_connect() allocates a socket stream internally, if we
-	 * didn't provide the file descriptor to the bufferevent before, e.g. with
-	 * bufferevent_socket_new() */
 	if (bufferevent_socket_connect_hostname(bev->bevent,
 				(zdns_base ? dnsb->dns_base : NULL),
 				family, hostname, port)) {
+# ifdef PHP_EVENT_DEBUG
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s",
+				evutil_gai_strerror(bufferevent_socket_get_dns_error(bev->bevent)));
+# endif
 		RETURN_FALSE;
 	}
+	/*zend_list_addref(dnsb->rsrc_id);*/
+#else /* don't HAVE_EVENT_EXTRA_LIB */
+	if (bufferevent_socket_connect_hostname(bev->bevent,
+				NULL,
+				family, hostname, port)) {
+# ifdef PHP_EVENT_DEBUG
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s",
+				evutil_gai_strerror(bufferevent_socket_get_dns_error(bev->bevent)));
+# endif
+		RETURN_FALSE;
+	}
+#endif
 
 	bev->stream_id = bufferevent_getfd(bev->bevent);
 
-	PHP_EVENT_ASSERT(bev->stream_id >= 0);
+	/*
+	It may not work with evdns
+	if (bev->stream_id < 0) {
+		RETURN_FALSE;
+	}
+	 PHP_EVENT_ASSERT(bev->stream_id >= 0);
+	*/
 
 	RETVAL_TRUE;
 #endif
 }
 /* }}} */
 
-/* {{{ proto mixed bufferevent_socket_get_dns_error(resource bevent);
- *
- * Finds out what the most recent error was.
- *
- * If there was a DNS error encountered on the buffer event, returns
- * descriptive string.  Otherwise returns NULL. */
+/* {{{ proto resource bufferevent_socket_get_dns_error_string(resource bevent);
+ * Returns string describing the last failed DNS lookup attempt made by
+ * bufferevent_socket_connect_hostname(), or an empty string, if no DNS error
+ * detected. */
 PHP_FUNCTION(bufferevent_socket_get_dns_error)
 {
 	php_event_bevent_t *bev;
 	PHP_EVENT_FETCH_BEVENT(bev, zbevent);
 
 	err = bufferevent_socket_get_dns_error(bev->bevent);
-	if (err) {
-		RETVAL_STRING(evutil_gai_strerror(err), 1);
-	} else {
-		RETVAL_NULL();
+
+	if (err == 0) {
+		RETURN_EMPTY_STRING();
 	}
+	RETVAL_STRING(evutil_gai_strerror(err), 1);
 }
 /* }}} */
 
 }
 /* }}} */
 
+/* {{{ proto resource bufferevent_get_input(resource bevent);
+ * Returns the input event buffer resource */
+PHP_FUNCTION(bufferevent_get_input)
+{
+	php_event_bevent_t *bev;
+	zval               *zbevent;
+	php_event_buffer_t *b;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbevent) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BEVENT(bev, zbevent);
+
+	b = emalloc(sizeof(php_event_buffer_t));
+	memset(b, 0, sizeof(php_event_buffer_t));
+
+	b->buf       = bufferevent_get_input(bev->bevent);
+	b->rsrc_id   = ZEND_REGISTER_RESOURCE(return_value, b, le_event_buffer);
+
+	zend_list_addref(b->rsrc_id);
+}
+/* }}} */
+
+/* {{{ proto resource bufferevent_get_output(resource bevent);
+ * Returns the output event buffer resource */
+PHP_FUNCTION(bufferevent_get_output)
+{
+	php_event_bevent_t *bev;
+	zval               *zbevent;
+	php_event_buffer_t *b;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbevent) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BEVENT(bev, zbevent);
+
+	b = emalloc(sizeof(php_event_buffer_t));
+	memset(b, 0, sizeof(php_event_buffer_t));
+
+	b->buf       = bufferevent_get_output(bev->bevent);
+	b->rsrc_id   = ZEND_REGISTER_RESOURCE(return_value, b, le_event_buffer);
+
+	zend_list_addref(b->rsrc_id);
+}
+/* }}} */
+
 /* {{{ proto void bufferevent_set_watermark(resource bevent, int events, int lowmark, int highmark);
  * Adjusts the read watermarks, the write watermarks, or both, of a single bufferevent. */
 PHP_FUNCTION(bufferevent_set_watermark)
 }
 /* }}} */
 
+/* {{{ proto resource evbuffer_new(void);
+ * Allocates storage for new event buffer and returns it's resource. */
+PHP_FUNCTION(evbuffer_new)
+{
+	php_event_buffer_t *b;
+
+	if (zend_parse_parameters_none() == FAILURE) {
+		return;
+	}
+
+	b = emalloc(sizeof(php_event_buffer_t));
+	memset(b, 0, sizeof(php_event_buffer_t));
+
+	b->buf       = evbuffer_new();
+	b->rsrc_id   = ZEND_REGISTER_RESOURCE(return_value, b, le_event_buffer);
+}
+/* }}} */
+
+/* {{{ proto void evbuffer_free(resource buf);
+ * Free storage allocated for the event buffer */
+PHP_FUNCTION(evbuffer_free)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbuf) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	zend_list_delete(b->rsrc_id);
+}
+/* }}} */
+
+/* {{{ proto bool evbuffer_freeze(resource buf, bool at_front);
+ * Prevent calls that modify an event buffer from succeeding. */
+PHP_FUNCTION(evbuffer_freeze)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+	zend_bool           at_front;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb",
+				&zbuf, &at_front) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	if (evbuffer_freeze(b->buf, at_front)) {
+		RETURN_FALSE;
+	}
+	RETVAL_TRUE;
+}
+/* }}} */
+
+/* {{{ proto long evbuffer_get_length(resource buf);
+ * Returns the total number of bytes stored in the event buffer. */
+PHP_FUNCTION(evbuffer_get_length)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbuf) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	RETVAL_LONG(evbuffer_get_length(b->buf));
+}
+/* }}} */
+
+/* {{{ proto void evbuffer_lock(resource buf);
+ * Acquire the lock on an evbuffer. 
+ * Has no effect if locking was not enabled with evbuffer_enable_locking.
+ */
+PHP_FUNCTION(evbuffer_lock)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbuf) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	evbuffer_lock(b->buf);
+}
+/* }}} */
+
+/* {{{ proto void evbuffer_unlock(resource buf);
+ * Release the lock on an evbuffer.
+ * Has no effect if locking was not enabled with evbuffer_enable_locking.
+ */
+PHP_FUNCTION(evbuffer_unlock)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbuf) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	evbuffer_unlock(b->buf);
+}
+/* }}} */
+
+/* {{{ proto void evbuffer_enable_locking(resource buf);
+ *
+ * Enable locking on an evbuffer so that it can safely be used by multiple threads at the same time.
+ * When locking is enabled, the lock will be held when callbacks are invoked.
+ * This could result in deadlock if you aren't careful. Plan accordingly!
+ */
+PHP_FUNCTION(evbuffer_enable_locking)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
+				&zbuf) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	evbuffer_enable_locking(b->buf, NULL);
+}
+/* }}} */
+
+/* {{{ proto bool evbuffer_add(resource buf, ...);
+ *
+ * Append data to the end of an event buffer. The function accepts variable set
+ * of arguments. Each argument is converted to string.
+ */
+PHP_FUNCTION(evbuffer_add)
+{
+	php_event_buffer_t   *b;
+	zval                 *zbuf;
+	int                   i;
+	int                   num_varargs;
+	zval               ***varargs     = NULL;
+	zval                **ppz;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r+",
+				&zbuf, &varargs, &num_varargs) == FAILURE) {
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	for (i = 0; i < num_varargs; i++) {
+		ppz = varargs[i];
+		convert_to_string_ex(ppz);
+
+		if (evbuffer_add(b->buf, (void *) Z_STRVAL_PP(ppz), Z_STRLEN_PP(ppz))) {
+			RETVAL_FALSE;
+			break;
+		}
+	}
+
+	if (varargs) {
+		efree(varargs);
+	}
+
+	RETVAL_TRUE;
+}
+/* }}} */
+
+/* {{{ proto long evbuffer_remove(resource buf, string &data, long max_bytes);
+ * Read data from an evbuffer and drain the bytes read.  If more bytes are
+ * requested than are available in the evbuffer, we only extract as many bytes
+ * as were available.
+ *
+ * Returns the number of bytes read, or -1 if we can't drain the buffer.
+ */
+PHP_FUNCTION(evbuffer_remove)
+{
+	php_event_buffer_t *b;
+	zval               *zbuf;
+	zval               *zdata;
+	long                max_bytes;
+	long                ret;
+	char               *data;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzl",
+				&zbuf, &zdata, &max_bytes) == FAILURE) {
+		return;
+	}
+
+	if (!Z_ISREF_P(zdata)) {
+		/* Was not passed by reference */
+		return;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	data = emalloc(sizeof(char) * max_bytes + 1);
+
+	ret = evbuffer_remove(b->buf, data, max_bytes);
+
+	if (ret > 0) {
+		convert_to_string(zdata);
+		zval_dtor(zdata);
+		Z_STRVAL_P(zdata) = estrndup(data, ret);
+		Z_STRLEN_P(zdata) = ret;
+	}
+
+	efree(data);
+
+	RETVAL_LONG(ret);
+}
+/* }}} */
+
 
 /* API functions END }}} */
 
 #if HAVE_EVENT_EXTRA_LIB
 /* {{{ Extra API functions */
 
-/* {{{ proto resource event_dns_base_new(resource base, bool initialize);
+/* {{{ proto resource evdns_base_new(resource base, bool initialize);
  *
  * Returns resource representing event dns base.
  *
  * evdns_base empty, with no nameservers or options configured. In the latter
  * case you should configure dns base yourself, e.g. with
  * event_dns_base_resolv_conf_parse() */
-PHP_FUNCTION(event_dns_base_new)
+PHP_FUNCTION(evdns_base_new)
 {
 	php_event_base_t     *base;
 	zval                 *zbase;
 	dnsb->dns_base = evdns_base_new(base, initialize);
 
 	if (dnsb->dns_base) {
-		dnsb->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, dnsb->dns_base, le_event_dns_base);
+		dnsb->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, dnsb, le_event_dns_base);
+		PHP_EVENT_ASSERT(dnsb->rsrc_id);
 	} else {
 		RETVAL_FALSE;
 	}
 }
 /* }}} */
 
-/* {{{ proto void event_dns_base_free(void);
- * Free an event dns base */
-PHP_FUNCTION(event_dns_base_free)
+/* {{{ proto void evdns_base_free(void);
+ * Free an evdns base */
+PHP_FUNCTION(evdns_base_free)
 {
 	php_event_dns_base_t *dnsb;
 	zval                 *zdns_base;
 }
 /* }}} */
 
-/* {{{ proto bool event_dns_base_resolv_conf_parse(resource dns_base, int flags, string filename);
+/* {{{ proto bool evdns_base_resolv_conf_parse(resource dns_base, int flags, string filename);
  * Scans the resolv.conf formatted file stored in filename, and read in all the
  * options from it that are listed in flags */
-PHP_FUNCTION(event_dns_base_resolv_conf_parse)
+PHP_FUNCTION(evdns_base_resolv_conf_parse)
 {
 	php_event_dns_base_t *dnsb;
 	zval                 *zdns_base;

examples/httpv0client.php

+<?php
+function readcb($bev, $base) {
+	$input = bufferevent_get_input($bev);
+
+	while (($n = evbuffer_remove($input, $buf, 1024)) > 0) {
+		echo $buf;
+	}
+}
+
+function eventcb($bev, $events, $base) {
+	if ($events & EVENT_BEV_EVENT_CONNECTED) {
+		echo "Connected.\n";
+	} elseif ($events & (EVENT_BEV_EVENT_ERROR | EVENT_BEV_EVENT_EOF)) {
+		if ($events & EVENT_BEV_EVENT_ERROR) {
+			echo "DNS error: ", bufferevent_socket_get_dns_error($bev), PHP_EOL;
+		}
+
+		echo "Closing\n";
+		bufferevent_free($bev);
+		event_base_loopexit($base);
+		exit("exit\n");
+	}
+}
+
+if ($argc != 3) {
+	echo <<<EOS
+Trivial HTTP 0.x client
+Syntax: php {$argv[0]} [hostname] [resource]
+Example: php {$argv[0]} www.google.com /
+EOS;
+	exit();
+}
+
+$base = event_base_new();
+$dns_base = evdns_base_new($base, TRUE);
+echo "rsrc type of \$dns_base= ", get_resource_type($dns_base), PHP_EOL;
+if (!$dns_base) {
+	exit("Failed to init DNS Base\n");
+}
+
+$bev = bufferevent_socket_new($base, NULL, EVENT_BEV_OPT_CLOSE_ON_FREE /*| EVENT_BEV_OPT_DEFER_CALLBACKS*/);
+
+bufferevent_setcb($bev, "readcb", NULL, "eventcb", $base);
+bufferevent_enable($bev, EVENT_READ | EVENT_WRITE);
+
+$output = bufferevent_get_output($bev);
+
+if (!evbuffer_add($output,
+	"GET {$argv[2]} HTTP/1.1\r\n".
+	"Host: {$argv[1]}\r\n".
+	"Connection: Close\r\n\r\n"
+)) {
+	exit("Failed adding request to output buffer\n");
+}
+
+if (!bufferevent_socket_connect_hostname($bev, $dns_base, $argv[1], 80, EVENT_AF_UNSPEC)) {
+	exit("Can't connect to host {$argv[1]}\n");
+}
+
+event_base_dispatch($base);

examples/misc.php

+<?php
+/* {{{ Config & supported stuff */
+echo "Supported methods:\n";
+foreach (event_get_supported_methods() as $m) {
+	echo $m, PHP_EOL;
+}
+
+// Avoiding "select" method
+$cfg = event_config_new();
+if (event_config_avoid_method($cfg, "select")) {
+	echo "`select' method avoided\n";
+}
+
+// Create event_base associated with the config
+$base = event_base_new_with_config($cfg);
+echo "Event method used: ", event_base_get_method($base), PHP_EOL;
+
+echo "Features:\n";
+$features = event_base_get_features($base);
+($features & EVENT_FEATURE_ET) and print("ET - edge-triggered IO\n");
+($features & EVENT_FEATURE_O1) and print("O1 - O(1) operation for adding/deletting events\n");
+($features & EVENT_FEATURE_FDS) and print("FDS - arbitrary file descriptor types, and not just sockets\n");
+
+// Require FDS feature
+if (event_config_require_features($cfg, EVENT_FEATURE_FDS)) {
+	echo "FDS feature is now requried\n";
+
+	$base = event_base_new_with_config($cfg);
+	(event_base_get_features($base) & EVENT_FEATURE_FDS)
+		and print("FDS - arbitrary file descriptor types, and not just sockets\n");
+}
+/* }}} */
+
+/* {{{ Base */
+$base = event_base_new();
+$event = event_new($base, STDIN, EVENT_READ | EVENT_PERSIST, function ($fd, $events, $arg) {
+	static $max_iterations = 0;
+
+    if (++$max_iterations >= 5) {
+		/* exit after 5 iterations with timeout of 2.33 seconds */
+		echo "Stopping...\n";
+        event_base_loopexit($arg[0], 2.33);
+    }
+
+    echo fgets($fd);
+}, array (&$base));
+
+event_add($event);
+event_base_loop($base);
+/* Base }}} */
+?>
+
 	ZEND_ARG_INFO(0, addr)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_bufferevent_socket_connect_hostname, 0, 0, 4)
+	ZEND_ARG_INFO(0, bevent)
+	ZEND_ARG_INFO(0, dns_base)
+	ZEND_ARG_INFO(0, hostname)
+	ZEND_ARG_INFO(0, port)
+	ZEND_ARG_INFO(0, family)
+ZEND_END_ARG_INFO();
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_bufferevent_set_callbacks, 0, 0, 4)
 	ZEND_ARG_INFO(0, bevent)
 	ZEND_ARG_INFO(0, readcb)
 	ZEND_ARG_INFO(0, highmark)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_1, 0, 0, 1)
+	ZEND_ARG_INFO(0, buf)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_freeze, 0, 0, 2)
+	ZEND_ARG_INFO(0, buf)
+	ZEND_ARG_INFO(0, at_front)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_add, 0, 0, 2)
+	ZEND_ARG_INFO(0, buf)
+	ZEND_ARG_INFO(0, ...)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_remove, 0, 0, 3)
+	ZEND_ARG_INFO(0, buf)
+	ZEND_ARG_INFO(1, data)
+	ZEND_ARG_INFO(0, max_bytes)
+ZEND_END_ARG_INFO();
+
 /* ARGINFO END }}} */
 
 
 #if HAVE_EVENT_EXTRA_LIB
 /* {{{ ARGINFO for extra API */
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_event_dns_base_1, 0, 0, 1)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evdns_base_1, 0, 0, 1)
 	ZEND_ARG_INFO(0, dns_base)
 ZEND_END_ARG_INFO();
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_event_dns_base_new, 0, 0, 2)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evdns_base_new, 0, 0, 2)
 	ZEND_ARG_INFO(0, base)
 	ZEND_ARG_INFO(0, initialize)
 ZEND_END_ARG_INFO();
 	PHP_FE(event_config_set_max_dispatch_interval, arginfo_event_config_set_max_dispatch_interval)
 #endif
 
-	PHP_FE(bufferevent_socket_new,           arginfo_bufferevent_socket_new)
-	PHP_FE(bufferevent_free,                 arginfo_bufferevent_1)
-	PHP_FE(bufferevent_socket_connect,       arginfo_bufferevent_socket_connect)
-	PHP_FE(bufferevent_socket_get_dns_error, arginfo_bufferevent_1)
-	PHP_FE(bufferevent_setcb,                arginfo_bufferevent_set_callbacks)
-	PHP_FE(bufferevent_enable,               arginfo_bufferevent__events)
-	PHP_FE(bufferevent_disable,              arginfo_bufferevent__events)
-	PHP_FE(bufferevent_get_enabled,          arginfo_bufferevent_1)
-	PHP_FE(bufferevent_set_watermark,        arginfo_bufferevent_set_watermark)
-	
+	PHP_FE(bufferevent_socket_new,              arginfo_bufferevent_socket_new)
+	PHP_FE(bufferevent_free,                    arginfo_bufferevent_1)
+	PHP_FE(bufferevent_socket_connect,          arginfo_bufferevent_socket_connect)
+	PHP_FE(bufferevent_socket_connect_hostname, arginfo_bufferevent_socket_connect_hostname)
+	PHP_FE(bufferevent_socket_get_dns_error,    arginfo_bufferevent_1)
+	PHP_FE(bufferevent_setcb,                   arginfo_bufferevent_set_callbacks)
+	PHP_FE(bufferevent_enable,                  arginfo_bufferevent__events)
+	PHP_FE(bufferevent_disable,                 arginfo_bufferevent__events)
+	PHP_FE(bufferevent_get_enabled,             arginfo_bufferevent_1)
+	PHP_FE(bufferevent_get_input,               arginfo_bufferevent_1)
+	PHP_FE(bufferevent_get_output,              arginfo_bufferevent_1)
+	PHP_FE(bufferevent_set_watermark,           arginfo_bufferevent_set_watermark)
+
+	PHP_FE(evbuffer_new,            arginfo_event__void)
+	PHP_FE(evbuffer_free,           arginfo_evbuffer_1)
+	PHP_FE(evbuffer_freeze,         arginfo_evbuffer_freeze)
+	PHP_FE(evbuffer_get_length,     arginfo_evbuffer_1)
+	PHP_FE(evbuffer_lock,           arginfo_evbuffer_1)
+	PHP_FE(evbuffer_unlock,         arginfo_evbuffer_1)
+	PHP_FE(evbuffer_enable_locking, arginfo_evbuffer_1)
+	PHP_FE(evbuffer_add,            arginfo_evbuffer_add)
+	PHP_FE(evbuffer_remove,         arginfo_evbuffer_remove)
+
 	/* These aliases are for compatibility with libevent extension */
 
 	PHP_FALIAS(event_timer_new,            evtimer_new,               arginfo_evtimer_new)
 #if HAVE_EVENT_EXTRA_LIB
 /* {{{ Extra API */
 
-	PHP_FE(event_dns_base_new, arginfo_event_dns_base_new)
-	PHP_FE(event_dns_base_free, arginfo_event_dns_base_1)
+	PHP_FE(evdns_base_new, arginfo_evdns_base_new)
+	PHP_FE(evdns_base_free, arginfo_evdns_base_1)
 	
 /* Extra API END}}} */
 #endif
 PHP_FUNCTION(bufferevent_socket_new);
 PHP_FUNCTION(bufferevent_free);
 PHP_FUNCTION(bufferevent_socket_connect);
+PHP_FUNCTION(bufferevent_socket_connect_hostname);
 PHP_FUNCTION(bufferevent_setcb);
 PHP_FUNCTION(bufferevent_enable);
 PHP_FUNCTION(bufferevent_disable);
 PHP_FUNCTION(bufferevent_get_enabled);
+PHP_FUNCTION(bufferevent_get_input);
+PHP_FUNCTION(bufferevent_get_output);
 PHP_FUNCTION(bufferevent_set_watermark);
 PHP_FUNCTION(bufferevent_socket_get_dns_error);
 
+PHP_FUNCTION(evbuffer_new);
+PHP_FUNCTION(evbuffer_free);
+PHP_FUNCTION(evbuffer_freeze);
+PHP_FUNCTION(evbuffer_get_length);
+PHP_FUNCTION(evbuffer_lock);
+PHP_FUNCTION(evbuffer_unlock);
+PHP_FUNCTION(evbuffer_enable_locking);
+PHP_FUNCTION(evbuffer_add);
+PHP_FUNCTION(evbuffer_remove);
+
 
 #if HAVE_EVENT_EXTRA_LIB
 /* {{{ Extra API */
 
-PHP_FUNCTION(event_dns_base_new);
-PHP_FUNCTION(event_dns_base_free);
+PHP_FUNCTION(evdns_base_new);
+PHP_FUNCTION(evdns_base_free);
 
 /* Extra API END }}} */
 #endif
   <date>2013-01-06</date>
   <!--{{{ Current version -->
   <version>
-    <release>0.1.0</release>
-    <api>0.1.0</api>
+    <release>0.1.0-devel</release>
+    <api>0.1.0-devel</api>
   </version>
   <stability>
-    <release>stable</release>
-    <api>stable</api>
+    <release>devel</release>
+    <api>devel</api>
   </stability>
   <license uri="http://www.php.net/license">PHP</license>
   <notes><![CDATA[
   </extsrcrelease>
   <!--{{{ changelog-->
   <changelog>
-    <!--{{{ Current version -->
+    <!--{{{ 0.1.0-devel -->
     <version>
-      <release>0.1.0</release>
-      <api>0.1.0</api>
+      <release>0.1.0-devel</release>
+      <api>0.1.0-devel</api>
     </version>
     <stability>
-      <release>stable</release>
-      <api>stable</api>
+      <release>devel</release>
+      <api>devel</api>
     </stability>
     <license uri="http://www.php.net/license">PHP</license>
     <notes><![CDATA[
 #ifndef PHP_EVENT_H
 #define PHP_EVENT_H
 
-#define PHP_EVENT_VERSION "0.1.0"
+#define PHP_EVENT_VERSION "0.1.0-devel"
 
 
 extern zend_module_entry event_module_entry;
 #define PHP_EVENT_BUFFER_RES_NAME "Event Buffer"
 
 #if HAVE_EVENT_EXTRA_LIB
-# define PHP_EVENT_DNS_BASE_RES_NAME "DNS Event Base"
+# define PHP_EVENT_DNS_BASE_RES_NAME "Event DNS Base"
 #endif
 
 PHP_MINIT_FUNCTION(event);
 	PHP_EVENT_COMMON_THREAD_CTX;
 } php_event_bevent_t;
 
+typedef struct {
+	struct evbuffer *buf;
+	int              rsrc_id;   /* Resource ID of the event buffer */
+} php_event_buffer_t;
+
 #ifdef HAVE_EVENT_EXTRA_LIB/* {{{ */
 
 typedef struct {

test.php

-<?php
-/* {{{ Config & supported stuff */
-echo "Supported methods:\n";
-foreach (event_get_supported_methods() as $m) {
-	echo $m, PHP_EOL;
-}
-
-// Avoiding "select" method
-$cfg = event_config_new();
-if (event_config_avoid_method($cfg, "select")) {
-	echo "`select' method avoided\n";
-}
-
-// Create event_base associated with the config
-$base = event_base_new_with_config($cfg);
-echo "Event method used: ", event_base_get_method($base), PHP_EOL;
-
-echo "Features:\n";
-$features = event_base_get_features($base);
-($features & EVENT_FEATURE_ET) and print("ET - edge-triggered IO\n");
-($features & EVENT_FEATURE_O1) and print("O1 - O(1) operation for adding/deletting events\n");
-($features & EVENT_FEATURE_FDS) and print("FDS - arbitrary file descriptor types, and not just sockets\n");
-
-// Require FDS feature
-if (event_config_require_features($cfg, EVENT_FEATURE_FDS)) {
-	echo "FDS feature is now requried\n";
-
-	$base = event_base_new_with_config($cfg);
-	(event_base_get_features($base) & EVENT_FEATURE_FDS)
-		and print("FDS - arbitrary file descriptor types, and not just sockets\n");
-}
-/* }}} */
-
-/* {{{ Base */
-$base = event_base_new();
-$event = event_new($base, STDIN, EVENT_READ | EVENT_PERSIST, function ($fd, $events, $arg) {
-	static $max_iterations = 0;
-
-    if (++$max_iterations >= 5) {
-		/* exit after 5 iterations with timeout of 2.33 seconds */
-		echo "Stopping...\n";
-        event_base_loopexit($arg[0], 2.33);
-    }
-
-    echo fgets($fd);
-}, array (&$base));
-
-event_add($event);
-event_base_loop($base);
-/* Base }}} */
-?>
-
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.