1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2020 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Ruslan Osmanov <osmanov@php.net>                             |
16    +----------------------------------------------------------------------+
17 */
18 #include "../src/common.h"
19 #include "../src/util.h"
20 #include "../src/priv.h"
21 #include "zend_exceptions.h"
22 
23 /* {{{ proto EventBase EventBase::__construct([EventConfig cfg = null]); */
PHP_METHOD(EventBase,__construct)24 PHP_METHOD(EventBase, __construct)
25 {
26 	php_event_base_t   *b;
27 	php_event_config_t *cfg;
28 	zval               *zcfg = NULL;
29 
30 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!",
31 				&zcfg, php_event_config_ce) == FAILURE) {
32 		return;
33 	}
34 
35 	PHP_EVENT_FETCH_BASE(b, getThis());
36 
37 	if (zcfg == NULL) {
38 		b->base = event_base_new();
39 	} else {
40 		PHP_EVENT_FETCH_CONFIG(cfg, zcfg);
41 
42 		b->base = event_base_new_with_config(cfg->ptr);
43 		if (!b->base) {
44 			zend_throw_exception_ex(php_event_get_exception(), 0 TSRMLS_CC,
45 					"EventBase cannot be constructed with the provided configuration. "
46 					"Make sure that the specified features are supported on the current platform.");
47 		}
48 	}
49 }
50 /* }}} */
51 
52 /* {{{ proto int EventBase::__wakeup()
53    Prevents use of a EventBase instance that has been unserialized */
PHP_METHOD(EventBase,__wakeup)54 PHP_METHOD(EventBase, __wakeup)
55 {
56 	zend_throw_exception_ex(php_event_get_exception(), 0 TSRMLS_CC, "EventBase instances are not serializable");
57 }
58 /* }}} */
59 
60 /* {{{ proto int EventBase::__sleep()
61    Prevents serialization of a EventBase instance */
PHP_METHOD(EventBase,__sleep)62 PHP_METHOD(EventBase, __sleep)
63 {
64 	zend_throw_exception_ex(php_event_get_exception(), 0 TSRMLS_CC, "EventBase instances are not serializable");
65 }
66 /* }}} */
67 
68 /* {{{ proto void EventBase::free(void); */
PHP_METHOD(EventBase,free)69 PHP_METHOD(EventBase, free)
70 {
71 	zval *zbase = getThis();
72 	php_event_base_t *b;
73 
74 	if (zend_parse_parameters_none() == FAILURE) {
75 		return;
76 	}
77 
78 	PHP_EVENT_FETCH_BASE(b, zbase);
79 
80 	if (b->base) {
81 		event_base_free(b->base);
82 		b->base=NULL;
83 	}
84 }
85 /* }}} */
86 
87 /* {{{ proto string EventBase::getMethod(void);
88  * Returns event method in use. */
PHP_METHOD(EventBase,getMethod)89 PHP_METHOD(EventBase, getMethod)
90 {
91 	zval             *zbase = getThis();
92 	php_event_base_t *b;
93 
94 	if (zend_parse_parameters_none() == FAILURE) {
95 		return;
96 	}
97 
98 	PHP_EVENT_FETCH_BASE(b, zbase);
99 
100 	RETURN_STRING((char *)event_base_get_method(b->base), 1);
101 }
102 /* }}} */
103 
104 /* {{{ proto int EventBase::getFeatures(void);
105  * Returns bitmask of features supported. See EVENT_FEATURE_* constants. */
PHP_METHOD(EventBase,getFeatures)106 PHP_METHOD(EventBase, getFeatures)
107 {
108 	zval             *zbase = getThis();
109 	php_event_base_t *b;
110 
111 	if (zend_parse_parameters_none() == FAILURE) {
112 		return;
113 	}
114 
115 	PHP_EVENT_FETCH_BASE(b, zbase);
116 
117 	RETVAL_LONG(event_base_get_features(b->base));
118 }
119 /* }}} */
120 
121 /* {{{ proto bool EventBase::priorityInit(int n_priorities);
122  * Sets number of priorities per event base. Returns &true; on success, otherwise &false; */
PHP_METHOD(EventBase,priorityInit)123 PHP_METHOD(EventBase, priorityInit)
124 {
125 	zval             *zbase = getThis();
126 	long              n_priorities;
127 	php_event_base_t *b;
128 
129 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
130 				&n_priorities) == FAILURE) {
131 		return;
132 	}
133 
134 	PHP_EVENT_FETCH_BASE(b, zbase);
135 
136 	if (event_base_priority_init(b->base, n_priorities)) {
137 		RETURN_FALSE;
138 	}
139 	RETVAL_TRUE;
140 }
141 /* }}} */
142 
143 /* {{{ proto bool EventBase::loop([int flags]);
144  * Wait for events to become active, and run their callbacks. */
PHP_METHOD(EventBase,loop)145 PHP_METHOD(EventBase, loop)
146 {
147 	zval             *zbase = getThis();
148 	long              flags = -1;
149 	php_event_base_t *b;
150 
151 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l",
152 				&flags) == FAILURE) {
153 		return;
154 	}
155 
156 	PHP_EVENT_FETCH_BASE(b, zbase);
157 
158 	/* Call event_base_dispatch when flags omitted. */
159 	if (flags == -1) {
160 		if (event_base_dispatch(b->base) == -1) {
161 			RETURN_FALSE;
162 		}
163 	} else if (event_base_loop(b->base, flags) == -1) {
164 		RETURN_FALSE;
165 	}
166 
167 	if (EG(exception)) {
168 		zend_throw_exception_object(EG(exception) TSRMLS_CC);
169 	}
170 	/* Since 2.1.2-alpha we can call event_base_loopcontinue(b->base);*/
171 
172 	RETVAL_TRUE;
173 }
174 /* }}} */
175 
176 /* {{{ proto bool EventBase::dispatch(void);
177  * Wait for events to become active, and run their callbacks.
178  * The same as EventBase::loop() with no flags set*/
PHP_METHOD(EventBase,dispatch)179 PHP_METHOD(EventBase, dispatch)
180 {
181 	zval             *zbase = getThis();
182 	php_event_base_t *b;
183 
184 	if (zend_parse_parameters_none() == FAILURE) {
185 		return;
186 	}
187 
188 	PHP_EVENT_FETCH_BASE(b, zbase);
189 
190 	if (event_base_dispatch(b->base) == -1) {
191 		RETURN_FALSE;
192 	}
193 
194 	if (EG(exception)) {
195 		zend_throw_exception_object(EG(exception) TSRMLS_CC);
196 	}
197 
198 	RETVAL_TRUE;
199 }
200 /* }}} */
201 
202 /* {{{ proto bool EventBase::exit([double timeout = 0.0]);
203  * Tells event_base to stop optionally after given number of seconds. */
PHP_METHOD(EventBase,exit)204 PHP_METHOD(EventBase, exit)
205 {
206 	zval             *zbase = getThis();
207 	php_event_base_t *b;
208 	double            timeout = -1;
209 	int               res;
210 
211 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d",
212 				&timeout) == FAILURE) {
213 		return;
214 	}
215 
216 	PHP_EVENT_FETCH_BASE(b, zbase);
217 
218 	if (timeout == -1) {
219 		res = event_base_loopexit(b->base, NULL);
220 	} else {
221 		struct timeval tv;
222 		PHP_EVENT_TIMEVAL_SET(tv, timeout);
223 
224 		res = event_base_loopexit(b->base, &tv);
225 	}
226 
227 	if (res) {
228 		RETURN_FALSE;
229 	}
230 	RETVAL_TRUE;
231 }
232 /* }}} */
233 
234 /* {{{ proto bool EventBase::stop(void);
235  * Tells event_base to stop. */
PHP_METHOD(EventBase,stop)236 PHP_METHOD(EventBase, stop)
237 {
238 	zval             *zbase = getThis();
239 	php_event_base_t *b;
240 
241 	if (zend_parse_parameters_none() == FAILURE) {
242 		return;
243 	}
244 
245 	PHP_EVENT_FETCH_BASE(b, zbase);
246 
247 	if (event_base_loopbreak(b->base)) {
248 		RETURN_FALSE;
249 	}
250 	RETVAL_TRUE;
251 }
252 /* }}} */
253 
254 /* {{{ proto bool EventBase::set(Event event);
255  * Associate event base with an event. */
PHP_METHOD(EventBase,set)256 PHP_METHOD(EventBase, set)
257 {
258 	zval             *zbase = getThis();
259 	php_event_base_t *b;
260 	zval             *zevent;
261 	php_event_t      *e;
262 
263 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O",
264 				&zevent, php_event_ce) == FAILURE) {
265 		return;
266 	}
267 
268 	PHP_EVENT_FETCH_EVENT(e, zevent);
269 
270 	if (php_event_is_pending(e->event)) {
271 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't modify pending event");
272 		RETURN_FALSE;
273 	}
274 
275 	PHP_EVENT_FETCH_BASE(b, zbase);
276 
277 	if (event_base_set(b->base, e->event)) {
278 		RETURN_FALSE;
279 	}
280 	RETVAL_TRUE;
281 }
282 /* }}} */
283 
284 /* {{{ proto bool EventBase::gotStop(void);
285  *
286  * Checks if the event loop was told to abort immediately by EventBase::stop() */
PHP_METHOD(EventBase,gotStop)287 PHP_METHOD(EventBase, gotStop)
288 {
289 	zval             *zbase = getThis();
290 	php_event_base_t *b;
291 
292 	if (zend_parse_parameters_none() == FAILURE) {
293 		return;
294 	}
295 
296 	PHP_EVENT_FETCH_BASE(b, zbase);
297 
298 	if (event_base_got_break(b->base)) {
299 		RETURN_TRUE;
300 	}
301 	RETVAL_FALSE;
302 }
303 /* }}} */
304 
305 /* {{{ proto bool EventBase::gotExit(void);
306  * Checks if the event loop was told to exit by EventBase::exit */
PHP_METHOD(EventBase,gotExit)307 PHP_METHOD(EventBase, gotExit)
308 {
309 	zval             *zbase = getThis();
310 	php_event_base_t *b;
311 
312 	if (zend_parse_parameters_none() == FAILURE) {
313 		return;
314 	}
315 
316 	PHP_EVENT_FETCH_BASE(b, zbase);
317 
318 	if (event_base_got_exit(b->base)) {
319 		RETURN_TRUE;
320 	}
321 	RETVAL_FALSE;
322 }
323 /* }}} */
324 
325 /* {{{ proto double EventBase::getTimeOfDayCached(void);
326  *
327  * On success returns the current time(as returned by gettimeofday()), looking
328  * at the cached value in 'base' if possible, and calling gettimeofday() or
329  * clock_gettime() as appropriate if there is no cached time. On failure
330  * returns NULL. */
PHP_METHOD(EventBase,getTimeOfDayCached)331 PHP_METHOD(EventBase, getTimeOfDayCached)
332 {
333 	zval             *zbase = getThis();
334 	php_event_base_t *b;
335 	struct timeval    tv;
336 
337 	if (zend_parse_parameters_none() == FAILURE) {
338 		return;
339 	}
340 
341 	PHP_EVENT_FETCH_BASE(b, zbase);
342 
343 	if (event_base_gettimeofday_cached(b->base, &tv)) {
344 		RETURN_NULL();
345 	}
346 
347 	RETVAL_DOUBLE(PHP_EVENT_TIMEVAL_TO_DOUBLE(tv));
348 }
349 /* }}} */
350 
351 #if LIBEVENT_VERSION_NUMBER >= 0x02010100
352 /* {{{ proto bool EventBase::updateCacheTime(void);
353  * Updates cache time. Available since libevent 2.1.1-alpha */
PHP_METHOD(EventBase,updateCacheTime)354 PHP_METHOD(EventBase, updateCacheTime)
355 {
356 	zval             *zbase = getThis();
357 	php_event_base_t *b;
358 
359 	if (zend_parse_parameters_none() == FAILURE) {
360 		return;
361 	}
362 
363 	PHP_EVENT_FETCH_BASE(b, zbase);
364 
365 	if (event_base_update_cache_time(b->base)) {
366 		RETURN_FALSE;
367 	}
368 	RETVAL_TRUE;
369 }
370 /* }}} */
371 #endif
372 
373 /* {{{ proto bool EventBase::reInit(void);
374  * Re-initialize event base. Should be called after a fork.
375  * XXX pthread_atfork() in MINIT */
PHP_METHOD(EventBase,reInit)376 PHP_METHOD(EventBase, reInit)
377 {
378 	zval             *zbase = getThis();
379 	php_event_base_t *b;
380 
381 	if (zend_parse_parameters_none() == FAILURE) {
382 		return;
383 	}
384 
385 	PHP_EVENT_FETCH_BASE(b, zbase);
386 
387 	if (event_reinit(b->base)) {
388 		RETURN_FALSE;
389 	}
390 
391 	RETVAL_TRUE;
392 }
393 /* }}} */
394 
395 #if LIBEVENT_VERSION_NUMBER >= 0x02010200
396 /* {{{ proto bool EventBase::resume(void);
397  * Tells event_base to resume previously stopped event.
398  * Available since libevent version 2.1.2-alpha. */
PHP_METHOD(EventBase,resume)399 PHP_METHOD(EventBase, resume)
400 {
401 	zval             *zbase = getThis();
402 	php_event_base_t *b;
403 
404 	if (zend_parse_parameters_none() == FAILURE) {
405 		return;
406 	}
407 
408 	PHP_EVENT_FETCH_BASE(b, zbase);
409 
410 	if (event_base_loopcontinue(b->base)) {
411 		RETURN_FALSE;
412 	}
413 	RETVAL_TRUE;
414 }
415 /* }}} */
416 #endif
417 
418 /*
419  * Local variables:
420  * tab-width: 4
421  * c-basic-offset: 4
422  * End:
423  * vim600: noet sw=4 ts=4 sts=4 fdm=marker
424  * vim<600: noet sw=4 ts=4 sts=4
425  */
426