mirror of
https://github.com/php/pecl-event-libevent.git
synced 2026-03-23 23:22:05 +01:00
1699 lines
41 KiB
C
1699 lines
41 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 5 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2008 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: Antony Dovgal <tony@daylessday.org> |
|
|
| Arnaud Le Blanc <lbarnaud@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "php_ini.h"
|
|
#include "ext/standard/info.h"
|
|
#include "php_streams.h"
|
|
#include "php_network.h"
|
|
#include "php_libevent.h"
|
|
|
|
#include <signal.h>
|
|
|
|
#if PHP_VERSION_ID >= 50301 && (HAVE_SOCKETS || defined(COMPILE_DL_SOCKETS))
|
|
# include "ext/sockets/php_sockets.h"
|
|
# define LIBEVENT_SOCKETS_SUPPORT
|
|
#endif
|
|
|
|
#ifndef ZEND_FETCH_RESOURCE_NO_RETURN
|
|
# define ZEND_FETCH_RESOURCE_NO_RETURN(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type) \
|
|
(rsrc = (rsrc_type) zend_fetch_resource(passed_id TSRMLS_CC, default_id, resource_type_name, NULL, 1, resource_type))
|
|
#endif
|
|
|
|
#ifdef PHP_WIN32
|
|
/* XXX compiling with 2.x on Windows. Luckily the ext code works thanks to the
|
|
compat exports from the libevent. However it might need to be adapted to the
|
|
never version, so this ifdefs would go away. */
|
|
# include <event2/event.h>
|
|
# include <event2/event_compat.h>
|
|
# include <event2/event_struct.h>
|
|
# include <event2/bufferevent.h>
|
|
# include <event2/bufferevent_compat.h>
|
|
#else
|
|
# include <event.h>
|
|
#endif
|
|
|
|
#if PHP_MAJOR_VERSION < 5
|
|
# ifdef PHP_WIN32
|
|
typedef SOCKET php_socket_t;
|
|
# else
|
|
typedef int php_socket_t;
|
|
# endif
|
|
|
|
# ifdef ZTS
|
|
# define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx
|
|
# define TSRMLS_SET_CTX(ctx) ctx = (void ***) tsrm_ls
|
|
# else
|
|
# define TSRMLS_FETCH_FROM_CTX(ctx)
|
|
# define TSRMLS_SET_CTX(ctx)
|
|
# endif
|
|
|
|
# ifndef Z_ADDREF_P
|
|
# define Z_ADDREF_P(x) (x)->refcount++
|
|
# endif
|
|
#endif
|
|
|
|
static int le_event_base;
|
|
static int le_event;
|
|
static int le_bufferevent;
|
|
|
|
#ifdef COMPILE_DL_LIBEVENT
|
|
ZEND_GET_MODULE(libevent)
|
|
#endif
|
|
|
|
typedef struct _php_event_base_t { /* {{{ */
|
|
struct event_base *base;
|
|
int rsrc_id;
|
|
zend_uint events;
|
|
} php_event_base_t;
|
|
/* }}} */
|
|
|
|
typedef struct _php_event_callback_t { /* {{{ */
|
|
zval *func;
|
|
zval *arg;
|
|
} php_event_callback_t;
|
|
/* }}} */
|
|
|
|
typedef struct _php_event_t { /* {{{ */
|
|
struct event *event;
|
|
int rsrc_id;
|
|
int stream_id;
|
|
php_event_base_t *base;
|
|
php_event_callback_t *callback;
|
|
#ifdef ZTS
|
|
void ***thread_ctx;
|
|
#endif
|
|
int in_free;
|
|
} php_event_t;
|
|
/* }}} */
|
|
|
|
typedef struct _php_bufferevent_t { /* {{{ */
|
|
struct bufferevent *bevent;
|
|
int rsrc_id;
|
|
php_event_base_t *base;
|
|
zval *readcb;
|
|
zval *writecb;
|
|
zval *errorcb;
|
|
zval *arg;
|
|
#ifdef ZTS
|
|
void ***thread_ctx;
|
|
#endif
|
|
} php_bufferevent_t;
|
|
/* }}} */
|
|
|
|
#define ZVAL_TO_BASE(zval, base) \
|
|
ZEND_FETCH_RESOURCE(base, php_event_base_t *, &zval, -1, "event base", le_event_base)
|
|
|
|
#define ZVAL_TO_EVENT(zval, event) \
|
|
ZEND_FETCH_RESOURCE(event, php_event_t *, &zval, -1, "event", le_event)
|
|
|
|
#define ZVAL_TO_BEVENT(zval, bevent) \
|
|
ZEND_FETCH_RESOURCE(bevent, php_bufferevent_t *, &zval, -1, "buffer event", le_bufferevent)
|
|
|
|
/* {{{ internal funcs */
|
|
|
|
static inline void _php_event_callback_free(php_event_callback_t *callback) /* {{{ */
|
|
{
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
|
|
zval_ptr_dtor(&callback->func);
|
|
if (callback->arg) {
|
|
zval_ptr_dtor(&callback->arg);
|
|
}
|
|
efree(callback);
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_event_base_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
|
|
{
|
|
php_event_base_t *base = (php_event_base_t*)rsrc->ptr;
|
|
|
|
event_base_free(base->base);
|
|
efree(base);
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_event_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
|
|
{
|
|
php_event_t *event = (php_event_t*)rsrc->ptr;
|
|
int base_id = -1;
|
|
|
|
if (event->in_free) {
|
|
return;
|
|
}
|
|
|
|
event->in_free = 1;
|
|
|
|
if (event->base) {
|
|
base_id = event->base->rsrc_id;
|
|
--event->base->events;
|
|
}
|
|
if (event->stream_id >= 0) {
|
|
zend_list_delete(event->stream_id);
|
|
}
|
|
event_del(event->event);
|
|
|
|
_php_event_callback_free(event->callback);
|
|
efree(event->event);
|
|
efree(event);
|
|
|
|
if (base_id >= 0) {
|
|
zend_list_delete(base_id);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_bufferevent_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
|
|
{
|
|
php_bufferevent_t *bevent = (php_bufferevent_t*)rsrc->ptr;
|
|
int base_id = -1;
|
|
|
|
if (bevent->base) {
|
|
base_id = bevent->base->rsrc_id;
|
|
--bevent->base->events;
|
|
}
|
|
if (bevent->readcb) {
|
|
zval_ptr_dtor(&(bevent->readcb));
|
|
}
|
|
if (bevent->writecb) {
|
|
zval_ptr_dtor(&(bevent->writecb));
|
|
}
|
|
if (bevent->errorcb) {
|
|
zval_ptr_dtor(&(bevent->errorcb));
|
|
}
|
|
if (bevent->arg) {
|
|
zval_ptr_dtor(&(bevent->arg));
|
|
}
|
|
|
|
bufferevent_free(bevent->bevent);
|
|
efree(bevent);
|
|
|
|
if (base_id >= 0) {
|
|
zend_list_delete(base_id);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_event_callback(int fd, short events, void *arg) /* {{{ */
|
|
{
|
|
zval *args[3];
|
|
php_event_t *event = (php_event_t *)arg;
|
|
php_event_callback_t *callback;
|
|
zval retval;
|
|
TSRMLS_FETCH_FROM_CTX(event ? event->thread_ctx : NULL);
|
|
|
|
if (!event || !event->callback || !event->base) {
|
|
return;
|
|
}
|
|
|
|
callback = event->callback;
|
|
|
|
MAKE_STD_ZVAL(args[0]);
|
|
if (event->stream_id >= 0) {
|
|
ZVAL_RESOURCE(args[0], event->stream_id);
|
|
zend_list_addref(event->stream_id);
|
|
} else if (events & EV_SIGNAL) {
|
|
ZVAL_LONG(args[0], fd);
|
|
} else {
|
|
ZVAL_NULL(args[0]);
|
|
}
|
|
|
|
MAKE_STD_ZVAL(args[1]);
|
|
ZVAL_LONG(args[1], events);
|
|
|
|
args[2] = callback->arg;
|
|
Z_ADDREF_P(callback->arg);
|
|
|
|
if (call_user_function(EG(function_table), NULL, callback->func, &retval, 3, args TSRMLS_CC) == SUCCESS) {
|
|
zval_dtor(&retval);
|
|
}
|
|
|
|
zval_ptr_dtor(&(args[0]));
|
|
zval_ptr_dtor(&(args[1]));
|
|
zval_ptr_dtor(&(args[2]));
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_bufferevent_readcb(struct bufferevent *be, void *arg) /* {{{ */
|
|
{
|
|
zval *args[2];
|
|
zval retval;
|
|
php_bufferevent_t *bevent = (php_bufferevent_t *)arg;
|
|
TSRMLS_FETCH_FROM_CTX(bevent ? bevent->thread_ctx : NULL);
|
|
|
|
if (!bevent || !bevent->base || !bevent->readcb) {
|
|
return;
|
|
}
|
|
|
|
MAKE_STD_ZVAL(args[0]);
|
|
ZVAL_RESOURCE(args[0], bevent->rsrc_id);
|
|
zend_list_addref(bevent->rsrc_id); /* we do refcount-- later in zval_ptr_dtor */
|
|
|
|
args[1] = bevent->arg;
|
|
Z_ADDREF_P(args[1]);
|
|
|
|
if (call_user_function(EG(function_table), NULL, bevent->readcb, &retval, 2, args TSRMLS_CC) == SUCCESS) {
|
|
zval_dtor(&retval);
|
|
}
|
|
|
|
zval_ptr_dtor(&(args[0]));
|
|
zval_ptr_dtor(&(args[1]));
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_bufferevent_writecb(struct bufferevent *be, void *arg) /* {{{ */
|
|
{
|
|
zval *args[2];
|
|
zval retval;
|
|
php_bufferevent_t *bevent = (php_bufferevent_t *)arg;
|
|
TSRMLS_FETCH_FROM_CTX(bevent ? bevent->thread_ctx : NULL);
|
|
|
|
if (!bevent || !bevent->base || !bevent->writecb) {
|
|
return;
|
|
}
|
|
|
|
MAKE_STD_ZVAL(args[0]);
|
|
ZVAL_RESOURCE(args[0], bevent->rsrc_id);
|
|
zend_list_addref(bevent->rsrc_id); /* we do refcount-- later in zval_ptr_dtor */
|
|
|
|
args[1] = bevent->arg;
|
|
Z_ADDREF_P(args[1]);
|
|
|
|
if (call_user_function(EG(function_table), NULL, bevent->writecb, &retval, 2, args TSRMLS_CC) == SUCCESS) {
|
|
zval_dtor(&retval);
|
|
}
|
|
|
|
zval_ptr_dtor(&(args[0]));
|
|
zval_ptr_dtor(&(args[1]));
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
static void _php_bufferevent_errorcb(struct bufferevent *be, short what, void *arg) /* {{{ */
|
|
{
|
|
zval *args[3];
|
|
zval retval;
|
|
php_bufferevent_t *bevent = (php_bufferevent_t *)arg;
|
|
TSRMLS_FETCH_FROM_CTX(bevent ? bevent->thread_ctx : NULL);
|
|
|
|
if (!bevent || !bevent->base || !bevent->errorcb) {
|
|
return;
|
|
}
|
|
|
|
MAKE_STD_ZVAL(args[0]);
|
|
ZVAL_RESOURCE(args[0], bevent->rsrc_id);
|
|
zend_list_addref(bevent->rsrc_id); /* we do refcount-- later in zval_ptr_dtor */
|
|
|
|
MAKE_STD_ZVAL(args[1]);
|
|
ZVAL_LONG(args[1], what);
|
|
|
|
args[2] = bevent->arg;
|
|
Z_ADDREF_P(args[2]);
|
|
|
|
if (call_user_function(EG(function_table), NULL, bevent->errorcb, &retval, 3, args TSRMLS_CC) == SUCCESS) {
|
|
zval_dtor(&retval);
|
|
}
|
|
|
|
zval_ptr_dtor(&(args[0]));
|
|
zval_ptr_dtor(&(args[1]));
|
|
zval_ptr_dtor(&(args[2]));
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ proto resource event_base_new()
|
|
*/
|
|
static PHP_FUNCTION(event_base_new)
|
|
{
|
|
php_event_base_t *base;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
base = emalloc(sizeof(php_event_base_t));
|
|
base->base = event_base_new();
|
|
if (!base->base) {
|
|
efree(base);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
base->events = 0;
|
|
|
|
#if PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 4
|
|
base->rsrc_id = zend_list_insert(base, le_event_base TSRMLS_CC);
|
|
#else
|
|
base->rsrc_id = zend_list_insert(base, le_event_base);
|
|
#endif
|
|
RETURN_RESOURCE(base->rsrc_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_base_reinit()
|
|
*/
|
|
static PHP_FUNCTION(event_base_reinit) {
|
|
zval *zbase;
|
|
php_event_base_t *base;
|
|
int r = 0;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zbase) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
r = event_reinit(base->base);
|
|
if (r == -1) {
|
|
RETURN_FALSE
|
|
} else {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto void event_base_free(resource base)
|
|
*/
|
|
static PHP_FUNCTION(event_base_free)
|
|
{
|
|
zval *zbase;
|
|
php_event_base_t *base;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zbase) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
|
|
if (base->events > 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "base has events attached to it and cannot be freed");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
zend_list_delete(base->rsrc_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int event_base_loop(resource base[, int flags])
|
|
*/
|
|
static PHP_FUNCTION(event_base_loop)
|
|
{
|
|
zval *zbase;
|
|
php_event_base_t *base;
|
|
long flags = 0;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zbase, &flags) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
zend_list_addref(base->rsrc_id); /* make sure the base cannot be destroyed during the loop */
|
|
ret = event_base_loop(base->base, flags);
|
|
zend_list_delete(base->rsrc_id);
|
|
|
|
RETURN_LONG(ret);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_base_loopbreak(resource base)
|
|
*/
|
|
static PHP_FUNCTION(event_base_loopbreak)
|
|
{
|
|
zval *zbase;
|
|
php_event_base_t *base;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zbase) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
ret = event_base_loopbreak(base->base);
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_base_loopexit(resource base[, int timeout])
|
|
*/
|
|
static PHP_FUNCTION(event_base_loopexit)
|
|
{
|
|
zval *zbase;
|
|
php_event_base_t *base;
|
|
int ret;
|
|
long timeout = -1;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zbase, &timeout) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
|
|
if (timeout < 0) {
|
|
ret = event_base_loopexit(base->base, NULL);
|
|
} else {
|
|
struct timeval time;
|
|
|
|
time.tv_usec = timeout % 1000000;
|
|
time.tv_sec = timeout / 1000000;
|
|
ret = event_base_loopexit(base->base, &time);
|
|
}
|
|
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_base_set(resource event, resource base)
|
|
*/
|
|
static PHP_FUNCTION(event_base_set)
|
|
{
|
|
zval *zbase, *zevent;
|
|
php_event_base_t *base, *old_base;
|
|
php_event_t *event;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &zevent, &zbase) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
old_base = event->base;
|
|
ret = event_base_set(base->base, event->event);
|
|
|
|
if (ret == 0) {
|
|
if (base != old_base) {
|
|
/* make sure the base is destroyed after the event */
|
|
zend_list_addref(base->rsrc_id);
|
|
++base->events;
|
|
}
|
|
|
|
if (old_base && base != old_base) {
|
|
--old_base->events;
|
|
zend_list_delete(old_base->rsrc_id);
|
|
}
|
|
|
|
event->base = base;
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_base_priority_init(resource base, int npriorities)
|
|
*/
|
|
static PHP_FUNCTION(event_base_priority_init)
|
|
{
|
|
zval *zbase;
|
|
php_event_base_t *base;
|
|
long npriorities;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zbase, &npriorities) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
|
|
if (npriorities < 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "npriorities cannot be less than zero");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ret = event_base_priority_init(base->base, npriorities);
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ proto resource event_new()
|
|
*/
|
|
static PHP_FUNCTION(event_new)
|
|
{
|
|
php_event_t *event;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
event = emalloc(sizeof(php_event_t));
|
|
event->event = ecalloc(1, sizeof(struct event));
|
|
|
|
event->stream_id = -1;
|
|
event->callback = NULL;
|
|
event->base = NULL;
|
|
event->in_free = 0;
|
|
TSRMLS_SET_CTX(event->thread_ctx);
|
|
|
|
#if PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 4
|
|
event->rsrc_id = zend_list_insert(event, le_event TSRMLS_CC);
|
|
#else
|
|
event->rsrc_id = zend_list_insert(event, le_event);
|
|
#endif
|
|
RETURN_RESOURCE(event->rsrc_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto void event_free(resource event)
|
|
*/
|
|
static PHP_FUNCTION(event_free)
|
|
{
|
|
zval *zevent;
|
|
php_event_t *event;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zevent) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
zend_list_delete(event->rsrc_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_add(resource event[, int timeout])
|
|
*/
|
|
static PHP_FUNCTION(event_add)
|
|
{
|
|
zval *zevent;
|
|
php_event_t *event;
|
|
int ret;
|
|
long timeout = -1;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zevent, &timeout) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
if (!event->base) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add event without an event base");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (timeout < 0) {
|
|
ret = event_add(event->event, NULL);
|
|
} else {
|
|
struct timeval time;
|
|
|
|
time.tv_usec = timeout % 1000000;
|
|
time.tv_sec = timeout / 1000000;
|
|
ret = event_add(event->event, &time);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_set(resource event, mixed fd, int events, mixed callback[, mixed arg])
|
|
*/
|
|
static PHP_FUNCTION(event_set)
|
|
{
|
|
zval *zevent, **fd, *zcallback, *zarg = NULL;
|
|
php_event_t *event;
|
|
long events;
|
|
php_event_callback_t *callback, *old_callback;
|
|
char *func_name;
|
|
php_stream *stream;
|
|
php_socket_t file_desc;
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
php_socket *php_sock;
|
|
#endif
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZlz|z", &zevent, &fd, &events, &zcallback, &zarg) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
if (events & EV_SIGNAL) {
|
|
/* signal support */
|
|
convert_to_long_ex(fd);
|
|
file_desc = Z_LVAL_PP(fd);
|
|
if (file_desc < 0 || file_desc >= NSIG) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid signal passed");
|
|
RETURN_FALSE;
|
|
}
|
|
} else {
|
|
if (Z_TYPE_PP(fd) == IS_RESOURCE) {
|
|
if (ZEND_FETCH_RESOURCE2_NO_RETURN(stream, php_stream *, fd, -1, NULL, php_file_le_stream(), php_file_le_pstream())) {
|
|
if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&file_desc, 1) != SUCCESS || file_desc < 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
} else {
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
if (ZEND_FETCH_RESOURCE_NO_RETURN(php_sock, php_socket *, fd, -1, NULL, php_sockets_le_socket())) {
|
|
file_desc = php_sock->bsd_socket;
|
|
} else {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be either valid PHP stream or valid PHP socket resource");
|
|
RETURN_FALSE;
|
|
}
|
|
#else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream resource");
|
|
RETURN_FALSE;
|
|
#endif
|
|
}
|
|
} else if (Z_TYPE_PP(fd) == IS_LONG) {
|
|
file_desc = Z_LVAL_PP(fd);
|
|
if (file_desc < 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid file descriptor passed");
|
|
RETURN_FALSE;
|
|
}
|
|
} else {
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream or socket resource or a file descriptor of type long");
|
|
#else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream resource or a file descriptor of type long");
|
|
#endif
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
if (!zend_is_callable(zcallback, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
|
|
zval_add_ref(&zcallback);
|
|
if (zarg) {
|
|
zval_add_ref(&zarg);
|
|
} else {
|
|
ALLOC_INIT_ZVAL(zarg);
|
|
}
|
|
|
|
callback = emalloc(sizeof(php_event_callback_t));
|
|
callback->func = zcallback;
|
|
callback->arg = zarg;
|
|
|
|
old_callback = event->callback;
|
|
event->callback = callback;
|
|
if (events & EV_SIGNAL) {
|
|
event->stream_id = -1;
|
|
} else {
|
|
zend_list_addref(Z_LVAL_PP(fd));
|
|
event->stream_id = Z_LVAL_PP(fd);
|
|
}
|
|
|
|
event_set(event->event, (int)file_desc, (short)events, _php_event_callback, event);
|
|
|
|
if (old_callback) {
|
|
_php_event_callback_free(old_callback);
|
|
}
|
|
|
|
if (event->base) {
|
|
ret = event_base_set(event->base->base, event->event);
|
|
if (ret != 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_del(resource event)
|
|
*/
|
|
static PHP_FUNCTION(event_del)
|
|
{
|
|
zval *zevent;
|
|
php_event_t *event;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zevent) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
if (!event->base) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to delete event without an event base");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (event_del(event->event) == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_priority_set(resource event, int priority)
|
|
*/
|
|
static PHP_FUNCTION(event_priority_set)
|
|
{
|
|
zval *zevent;
|
|
php_event_t *event;
|
|
long priority;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zevent, &priority) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
if (!event->base) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set event priority without an event base");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ret = event_priority_set(event->event, priority);
|
|
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_timer_set(resource event, mixed callback[, mixed arg])
|
|
*/
|
|
static PHP_FUNCTION(event_timer_set)
|
|
{
|
|
zval *zevent, *zcallback, *zarg = NULL;
|
|
php_event_t *event;
|
|
php_event_callback_t *callback, *old_callback;
|
|
char *func_name;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &zevent, &zcallback, &zarg) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
if (!zend_is_callable(zcallback, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
|
|
zval_add_ref(&zcallback);
|
|
if (zarg) {
|
|
zval_add_ref(&zarg);
|
|
} else {
|
|
ALLOC_INIT_ZVAL(zarg);
|
|
}
|
|
|
|
callback = emalloc(sizeof(php_event_callback_t));
|
|
callback->func = zcallback;
|
|
callback->arg = zarg;
|
|
|
|
old_callback = event->callback;
|
|
event->callback = callback;
|
|
if (event->stream_id >= 0) {
|
|
zend_list_delete(event->stream_id);
|
|
}
|
|
event->stream_id = -1;
|
|
|
|
event_set(event->event, -1, 0, _php_event_callback, event);
|
|
|
|
if (old_callback) {
|
|
_php_event_callback_free(old_callback);
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_timer_pending(resource event[, int timeout])
|
|
*/
|
|
static PHP_FUNCTION(event_timer_pending)
|
|
{
|
|
zval *zevent;
|
|
php_event_t *event;
|
|
int ret;
|
|
long timeout = -1;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zevent, &timeout) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_EVENT(zevent, event);
|
|
|
|
if (timeout < 0) {
|
|
ret = event_pending(event->event, EV_TIMEOUT, NULL);
|
|
} else {
|
|
struct timeval time;
|
|
|
|
time.tv_usec = timeout % 1000000;
|
|
time.tv_sec = timeout / 1000000;
|
|
ret = event_pending(event->event, EV_TIMEOUT, &time);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource event_buffer_new(mixed fd, mixed readcb, mixed writecb, mixed errorcb[, mixed arg])
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_new)
|
|
{
|
|
php_bufferevent_t *bevent;
|
|
php_stream *stream;
|
|
zval *zfd, *zreadcb, *zwritecb, *zerrorcb, *zarg = NULL;
|
|
php_socket_t fd;
|
|
char *func_name;
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
php_socket *php_sock;
|
|
#endif
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzzz|z", &zfd, &zreadcb, &zwritecb, &zerrorcb, &zarg) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
if (Z_TYPE_P(zfd) == IS_RESOURCE) {
|
|
if (ZEND_FETCH_RESOURCE2_NO_RETURN(stream, php_stream *, &zfd, -1, NULL, php_file_le_stream(), php_file_le_pstream())) {
|
|
if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 1) != SUCCESS || fd < 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
} else {
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
if (ZEND_FETCH_RESOURCE_NO_RETURN(php_sock, php_socket *, &zfd, -1, NULL, php_sockets_le_socket())) {
|
|
fd = php_sock->bsd_socket;
|
|
} else {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream or socket resource or a file descriptor of type long");
|
|
RETURN_FALSE;
|
|
}
|
|
#else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream resource or a file descriptor of type long");
|
|
RETURN_FALSE;
|
|
#endif
|
|
}
|
|
} else if (Z_TYPE_P(zfd) == IS_LONG) {
|
|
fd = Z_LVAL_P(zfd);
|
|
} else {
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream or socket resource or a file descriptor of type long");
|
|
#else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream resource or a file descriptor of type long");
|
|
#endif
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (Z_TYPE_P(zreadcb) != IS_NULL) {
|
|
if (!zend_is_callable(zreadcb, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid read callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
} else {
|
|
zreadcb = NULL;
|
|
}
|
|
|
|
if (Z_TYPE_P(zwritecb) != IS_NULL) {
|
|
if (!zend_is_callable(zwritecb, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid write callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
} else {
|
|
zwritecb = NULL;
|
|
}
|
|
|
|
if (!zend_is_callable(zerrorcb, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid error callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
|
|
bevent = emalloc(sizeof(php_bufferevent_t));
|
|
bevent->bevent = bufferevent_new(fd, _php_bufferevent_readcb, _php_bufferevent_writecb, _php_bufferevent_errorcb, bevent);
|
|
|
|
bevent->base = NULL;
|
|
|
|
if (zreadcb) {
|
|
zval_add_ref(&zreadcb);
|
|
}
|
|
bevent->readcb = zreadcb;
|
|
|
|
if (zwritecb) {
|
|
zval_add_ref(&zwritecb);
|
|
}
|
|
bevent->writecb = zwritecb;
|
|
|
|
zval_add_ref(&zerrorcb);
|
|
bevent->errorcb = zerrorcb;
|
|
|
|
if (zarg) {
|
|
zval_add_ref(&zarg);
|
|
bevent->arg = zarg;
|
|
} else {
|
|
ALLOC_INIT_ZVAL(bevent->arg);
|
|
}
|
|
|
|
TSRMLS_SET_CTX(bevent->thread_ctx);
|
|
|
|
#if PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 4
|
|
bevent->rsrc_id = zend_list_insert(bevent, le_bufferevent TSRMLS_CC);
|
|
#else
|
|
bevent->rsrc_id = zend_list_insert(bevent, le_bufferevent);
|
|
#endif
|
|
RETURN_RESOURCE(bevent->rsrc_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto void event_buffer_free(resource bevent)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_free)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zbevent) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
zend_list_delete(bevent->rsrc_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_buffer_base_set(resource bevent, resource base)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_base_set)
|
|
{
|
|
zval *zbase, *zbevent;
|
|
php_event_base_t *base, *old_base;
|
|
php_bufferevent_t *bevent;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &zbevent, &zbase) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BASE(zbase, base);
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
old_base = bevent->base;
|
|
ret = bufferevent_base_set(base->base, bevent->bevent);
|
|
|
|
if (ret == 0) {
|
|
if (base != old_base) {
|
|
/* make sure the base is destroyed after the event */
|
|
zend_list_addref(base->rsrc_id);
|
|
++base->events;
|
|
}
|
|
|
|
if (old_base) {
|
|
--old_base->events;
|
|
zend_list_delete(old_base->rsrc_id);
|
|
}
|
|
|
|
bevent->base = base;
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_buffer_priority_set(resource bevent, int priority)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_priority_set)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
long priority;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zbevent, &priority) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
if (!bevent->base) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set event priority without an event base");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ret = bufferevent_priority_set(bevent->bevent, priority);
|
|
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_buffer_write(resource bevent, string data[, int data_size])
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_write)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
char *data;
|
|
int data_len;
|
|
long data_size = -1;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &zbevent, &data, &data_len, &data_size) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
if (ZEND_NUM_ARGS() < 3 || data_size < 0) {
|
|
data_size = data_len;
|
|
} else if (data_size > data_len) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_size out of range");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ret = bufferevent_write(bevent->bevent, (const void *)data, data_size);
|
|
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string event_buffer_read(resource bevent, int data_size)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_read)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
char *data;
|
|
long data_size;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zbevent, &data_size) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
if (data_size == 0) {
|
|
RETURN_EMPTY_STRING();
|
|
} else if (data_size < 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_size cannot be less than zero");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
data = safe_emalloc((int)data_size, sizeof(char), 1);
|
|
|
|
ret = bufferevent_read(bevent->bevent, data, data_size);
|
|
if (ret > 0) {
|
|
if (ret > data_size) { /* paranoia */
|
|
ret = data_size;
|
|
}
|
|
data[ret] = '\0';
|
|
RETURN_STRINGL(data, ret, 0);
|
|
}
|
|
efree(data);
|
|
RETURN_EMPTY_STRING();
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_buffer_enable(resource bevent, int events)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_enable)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
long events;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zbevent, &events) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
ret = bufferevent_enable(bevent->bevent, events);
|
|
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool event_buffer_disable(resource bevent, int events)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_disable)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
long events;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zbevent, &events) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
ret = bufferevent_disable(bevent->bevent, events);
|
|
|
|
if (ret == 0) {
|
|
RETURN_TRUE;
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto void event_buffer_timeout_set(resource bevent, int read_timeout, int write_timeout)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_timeout_set)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
long read_timeout, write_timeout;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &zbevent, &read_timeout, &write_timeout) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
bufferevent_settimeout(bevent->bevent, read_timeout, write_timeout);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto void event_buffer_watermark_set(resource bevent, int events, int lowmark, int highmark)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_watermark_set)
|
|
{
|
|
zval *zbevent;
|
|
php_bufferevent_t *bevent;
|
|
long events, lowmark, highmark;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlll", &zbevent, &events, &lowmark, &highmark) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
bufferevent_setwatermark(bevent->bevent, events, lowmark, highmark);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto void event_buffer_fd_set(resource bevent, resource fd)
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_fd_set)
|
|
{
|
|
zval *zbevent, *zfd;
|
|
php_stream *stream;
|
|
php_bufferevent_t *bevent;
|
|
php_socket_t fd;
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
php_socket *php_sock;
|
|
#endif
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &zbevent, &zfd) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
if (Z_TYPE_P(zfd) == IS_RESOURCE) {
|
|
if (ZEND_FETCH_RESOURCE2_NO_RETURN(stream, php_stream *, &zfd, -1, NULL, php_file_le_stream(), php_file_le_pstream())) {
|
|
if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 1) != SUCCESS || fd < 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
} else {
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
if (ZEND_FETCH_RESOURCE_NO_RETURN(php_sock, php_socket *, &zfd, -1, NULL, php_sockets_le_socket())) {
|
|
fd = php_sock->bsd_socket;
|
|
} else {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream or socket resource or a file descriptor of type long");
|
|
RETURN_FALSE;
|
|
}
|
|
#else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream resource or a file descriptor of type long");
|
|
RETURN_FALSE;
|
|
#endif
|
|
}
|
|
} else if (Z_TYPE_P(zfd) == IS_LONG) {
|
|
fd = Z_LVAL_P(zfd);
|
|
} else {
|
|
#ifdef LIBEVENT_SOCKETS_SUPPORT
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream or socket resource or a file descriptor of type long");
|
|
#else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "fd argument must be valid PHP stream resource or a file descriptor of type long");
|
|
#endif
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
bufferevent_setfd(bevent->bevent, fd);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource event_buffer_set_callback(resource bevent, mixed readcb, mixed writecb, mixed errorcb[, mixed arg])
|
|
*/
|
|
static PHP_FUNCTION(event_buffer_set_callback)
|
|
{
|
|
php_bufferevent_t *bevent;
|
|
zval *zbevent, *zreadcb, *zwritecb, *zerrorcb, *zarg = NULL;
|
|
char *func_name;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzzz|z", &zbevent, &zreadcb, &zwritecb, &zerrorcb, &zarg) != SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
ZVAL_TO_BEVENT(zbevent, bevent);
|
|
|
|
if (Z_TYPE_P(zreadcb) != IS_NULL) {
|
|
if (!zend_is_callable(zreadcb, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid read callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
} else {
|
|
zreadcb = NULL;
|
|
}
|
|
|
|
if (Z_TYPE_P(zwritecb) != IS_NULL) {
|
|
if (!zend_is_callable(zwritecb, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid write callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
} else {
|
|
zwritecb = NULL;
|
|
}
|
|
|
|
if (Z_TYPE_P(zerrorcb) != IS_NULL) {
|
|
if (!zend_is_callable(zerrorcb, 0, &func_name TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid error callback", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
} else {
|
|
zerrorcb = NULL;
|
|
}
|
|
|
|
if (zreadcb) {
|
|
zval_add_ref(&zreadcb);
|
|
|
|
if (bevent->readcb) {
|
|
zval_ptr_dtor(&bevent->readcb);
|
|
}
|
|
bevent->readcb = zreadcb;
|
|
} else {
|
|
if (bevent->readcb) {
|
|
zval_ptr_dtor(&bevent->readcb);
|
|
}
|
|
bevent->readcb = NULL;
|
|
}
|
|
|
|
if (zwritecb) {
|
|
zval_add_ref(&zwritecb);
|
|
|
|
if (bevent->writecb) {
|
|
zval_ptr_dtor(&bevent->writecb);
|
|
}
|
|
bevent->writecb = zwritecb;
|
|
} else {
|
|
if (bevent->writecb) {
|
|
zval_ptr_dtor(&bevent->writecb);
|
|
}
|
|
bevent->writecb = NULL;
|
|
}
|
|
|
|
if (zerrorcb) {
|
|
zval_add_ref(&zerrorcb);
|
|
|
|
if (bevent->errorcb) {
|
|
zval_ptr_dtor(&bevent->errorcb);
|
|
}
|
|
bevent->errorcb = zerrorcb;
|
|
}
|
|
|
|
if (zarg) {
|
|
zval_add_ref(&zarg);
|
|
if (bevent->arg) {
|
|
zval_ptr_dtor(&bevent->arg);
|
|
}
|
|
bevent->arg = zarg;
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ PHP_MINIT_FUNCTION
|
|
*/
|
|
static PHP_MINIT_FUNCTION(libevent)
|
|
{
|
|
le_event_base = zend_register_list_destructors_ex(_php_event_base_dtor, NULL, "event base", module_number);
|
|
le_event = zend_register_list_destructors_ex(_php_event_dtor, NULL, "event", module_number);
|
|
le_bufferevent = zend_register_list_destructors_ex(_php_bufferevent_dtor, NULL, "buffer event", module_number);
|
|
|
|
REGISTER_LONG_CONSTANT("EV_TIMEOUT", EV_TIMEOUT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EV_READ", EV_READ, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EV_WRITE", EV_WRITE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EV_SIGNAL", EV_SIGNAL, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EV_PERSIST", EV_PERSIST, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EVLOOP_NONBLOCK", EVLOOP_NONBLOCK, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EVLOOP_ONCE", EVLOOP_ONCE, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("EVBUFFER_READ", EVBUFFER_READ, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EVBUFFER_WRITE", EVBUFFER_WRITE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EVBUFFER_EOF", EVBUFFER_EOF, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EVBUFFER_ERROR", EVBUFFER_ERROR, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("EVBUFFER_TIMEOUT", EVBUFFER_TIMEOUT, CONST_CS | CONST_PERSISTENT);
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MINFO_FUNCTION
|
|
*/
|
|
static PHP_MINFO_FUNCTION(libevent)
|
|
{
|
|
char buf[64];
|
|
|
|
|
|
php_info_print_table_start();
|
|
php_info_print_table_header(2, "libevent support", "enabled");
|
|
php_info_print_table_row(2, "extension version", PHP_LIBEVENT_VERSION);
|
|
php_info_print_table_row(2, "Revision", "$Revision$");
|
|
|
|
snprintf(buf, sizeof(buf) - 1, "%s", event_get_version());
|
|
php_info_print_table_row(2, "libevent version", buf);
|
|
|
|
php_info_print_table_end();
|
|
}
|
|
/* }}} */
|
|
|
|
#if PHP_MAJOR_VERSION >= 5
|
|
/* {{{ arginfo */
|
|
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3) || PHP_MAJOR_VERSION > 5
|
|
# define EVENT_ARGINFO
|
|
#else
|
|
# define EVENT_ARGINFO static
|
|
#endif
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_base_loop, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, base)
|
|
ZEND_ARG_INFO(0, flags)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_base_loopbreak, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, base)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_base_loopexit, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, base)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_base_set, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_ARG_INFO(0, base)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_base_priority_init, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, base)
|
|
ZEND_ARG_INFO(0, npriorities)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO(arginfo_event_new, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_add, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_set, 0, 0, 4)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_ARG_INFO(0, fd)
|
|
ZEND_ARG_INFO(0, events)
|
|
ZEND_ARG_INFO(0, callback)
|
|
ZEND_ARG_INFO(0, arg)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_del, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_priority_set, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_ARG_INFO(0, priority)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_new, 0, 0, 4)
|
|
ZEND_ARG_INFO(0, stream)
|
|
ZEND_ARG_INFO(0, readcb)
|
|
ZEND_ARG_INFO(0, writecb)
|
|
ZEND_ARG_INFO(0, errorcb)
|
|
ZEND_ARG_INFO(0, arg)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_free, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_base_set, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, base)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_priority_set, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, priority)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_write, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, data)
|
|
ZEND_ARG_INFO(0, data_size)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_read, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, data_size)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_disable, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, events)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_timeout_set, 0, 0, 3)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, read_timeout)
|
|
ZEND_ARG_INFO(0, write_timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_watermark_set, 0, 0, 4)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, events)
|
|
ZEND_ARG_INFO(0, lowmark)
|
|
ZEND_ARG_INFO(0, highmark)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_fd_set, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, fd)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_buffer_set_callback, 0, 0, 4)
|
|
ZEND_ARG_INFO(0, bevent)
|
|
ZEND_ARG_INFO(0, readcb)
|
|
ZEND_ARG_INFO(0, writecb)
|
|
ZEND_ARG_INFO(0, errorcb)
|
|
ZEND_ARG_INFO(0, arg)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_timer_set, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_ARG_INFO(0, callback)
|
|
ZEND_ARG_INFO(0, arg)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
EVENT_ARGINFO
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_event_timer_pending, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, event)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
/* }}} */
|
|
|
|
/* {{{ libevent_functions[]
|
|
*/
|
|
#if ZEND_MODULE_API_NO >= 20071006
|
|
const
|
|
#endif
|
|
zend_function_entry libevent_functions[] = {
|
|
PHP_FE(event_base_new, arginfo_event_new)
|
|
PHP_FE(event_base_reinit, arginfo_event_base_loopbreak)
|
|
PHP_FE(event_base_free, arginfo_event_base_loopbreak)
|
|
PHP_FE(event_base_loop, arginfo_event_base_loop)
|
|
PHP_FE(event_base_loopbreak, arginfo_event_base_loopbreak)
|
|
PHP_FE(event_base_loopexit, arginfo_event_base_loopexit)
|
|
PHP_FE(event_base_set, arginfo_event_base_set)
|
|
PHP_FE(event_base_priority_init, arginfo_event_base_priority_init)
|
|
PHP_FE(event_new, arginfo_event_new)
|
|
PHP_FE(event_free, arginfo_event_del)
|
|
PHP_FE(event_add, arginfo_event_add)
|
|
PHP_FE(event_set, arginfo_event_set)
|
|
PHP_FE(event_del, arginfo_event_del)
|
|
PHP_FE(event_priority_set, arginfo_event_priority_set)
|
|
PHP_FE(event_buffer_new, arginfo_event_buffer_new)
|
|
PHP_FE(event_buffer_free, arginfo_event_buffer_free)
|
|
PHP_FE(event_buffer_base_set, arginfo_event_buffer_base_set)
|
|
PHP_FE(event_buffer_priority_set, arginfo_event_buffer_priority_set)
|
|
PHP_FE(event_buffer_write, arginfo_event_buffer_write)
|
|
PHP_FE(event_buffer_read, arginfo_event_buffer_read)
|
|
PHP_FE(event_buffer_enable, arginfo_event_buffer_disable)
|
|
PHP_FE(event_buffer_disable, arginfo_event_buffer_disable)
|
|
PHP_FE(event_buffer_timeout_set, arginfo_event_buffer_timeout_set)
|
|
PHP_FE(event_buffer_watermark_set, arginfo_event_buffer_watermark_set)
|
|
PHP_FE(event_buffer_fd_set, arginfo_event_buffer_fd_set)
|
|
PHP_FE(event_buffer_set_callback, arginfo_event_buffer_set_callback)
|
|
PHP_FALIAS(event_timer_new, event_new, arginfo_event_new)
|
|
PHP_FE(event_timer_set, arginfo_event_timer_set)
|
|
PHP_FE(event_timer_pending, arginfo_event_timer_pending)
|
|
PHP_FALIAS(event_timer_add, event_add, arginfo_event_add)
|
|
PHP_FALIAS(event_timer_del, event_del, arginfo_event_del)
|
|
{NULL, NULL, NULL}
|
|
};
|
|
/* }}} */
|
|
#else
|
|
/* {{{ libevent_functions[]
|
|
*/
|
|
zend_function_entry libevent_functions[] = {
|
|
PHP_FE(event_base_new, NULL)
|
|
PHP_FE(event_base_reinit, NULL)
|
|
PHP_FE(event_base_free, NULL)
|
|
PHP_FE(event_base_loop, NULL)
|
|
PHP_FE(event_base_loopbreak, NULL)
|
|
PHP_FE(event_base_loopexit, NULL)
|
|
PHP_FE(event_base_set, NULL)
|
|
PHP_FE(event_base_priority_init, NULL)
|
|
PHP_FE(event_new, NULL)
|
|
PHP_FE(event_free, NULL)
|
|
PHP_FE(event_add, NULL)
|
|
PHP_FE(event_set, NULL)
|
|
PHP_FE(event_del, NULL)
|
|
PHP_FE(event_priority_set, NULL)
|
|
PHP_FE(event_buffer_new, NULL)
|
|
PHP_FE(event_buffer_free, NULL)
|
|
PHP_FE(event_buffer_base_set, NULL)
|
|
PHP_FE(event_buffer_priority_set, NULL)
|
|
PHP_FE(event_buffer_write, NULL)
|
|
PHP_FE(event_buffer_read, NULL)
|
|
PHP_FE(event_buffer_enable, NULL)
|
|
PHP_FE(event_buffer_disable, NULL)
|
|
PHP_FE(event_buffer_timeout_set, NULL)
|
|
PHP_FE(event_buffer_watermark_set, NULL)
|
|
PHP_FE(event_buffer_fd_set, NULL)
|
|
PHP_FALIAS(event_timer_new, event_new, NULL)
|
|
PHP_FE(event_timer_set, NULL)
|
|
PHP_FE(event_timer_pending, NULL)
|
|
PHP_FALIAS(event_timer_add, event_add, NULL)
|
|
PHP_FALIAS(event_timer_del, event_del, NULL)
|
|
{NULL, NULL, NULL}
|
|
};
|
|
/* }}} */
|
|
#endif
|
|
|
|
static const zend_module_dep libevent_deps[] = { /* {{{ */
|
|
ZEND_MOD_OPTIONAL("sockets")
|
|
{NULL, NULL, NULL}
|
|
};
|
|
/* }}} */
|
|
|
|
/* {{{ libevent_module_entry
|
|
*/
|
|
zend_module_entry libevent_module_entry = {
|
|
STANDARD_MODULE_HEADER_EX,
|
|
NULL,
|
|
libevent_deps,
|
|
"libevent",
|
|
libevent_functions,
|
|
PHP_MINIT(libevent),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
PHP_MINFO(libevent),
|
|
PHP_LIBEVENT_VERSION,
|
|
STANDARD_MODULE_PROPERTIES
|
|
};
|
|
/* }}} */
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|