1 /*
2 +-----------------------------------------------------------------------------------+
3 |  ZMQ extension for PHP                                                            |
4 |  Copyright (c) 2010-2013, Mikko Koppanen <mkoppanen@php.net>                      |
5 |  All rights reserved.                                                             |
6 +-----------------------------------------------------------------------------------+
7 |  Redistribution and use in source and binary forms, with or without               |
8 |  modification, are permitted provided that the following conditions are met:      |
9 |     * Redistributions of source code must retain the above copyright              |
10 |       notice, this list of conditions and the following disclaimer.               |
11 |     * Redistributions in binary form must reproduce the above copyright           |
12 |       notice, this list of conditions and the following disclaimer in the         |
13 |       documentation and/or other materials provided with the distribution.        |
14 |     * Neither the name of the copyright holder nor the                            |
15 |       names of its contributors may be used to endorse or promote products        |
16 |       derived from this software without specific prior written permission.       |
17 +-----------------------------------------------------------------------------------+
18 |  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND  |
19 |  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED    |
20 |  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           |
21 |  DISCLAIMED. IN NO EVENT SHALL MIKKO KOPPANEN BE LIABLE FOR ANY                   |
22 |  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES       |
23 |  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;     |
24 |  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND      |
25 |  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       |
26 |  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS    |
27 |  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                     |
28 +-----------------------------------------------------------------------------------+
29 */
30 
31 #include "php_zmq.h"
32 #include "php_zmq_private.h"
33 #include "php_zmq_pollset.h"
34 
35 ZEND_DECLARE_MODULE_GLOBALS(php_zmq);
36 
37 static zend_class_entry *php_zmq_sc_entry;
38 static zend_class_entry *php_zmq_context_sc_entry;
39 static zend_class_entry *php_zmq_socket_sc_entry;
40 static zend_class_entry *php_zmq_poll_sc_entry;
41 static zend_class_entry *php_zmq_device_sc_entry;
42 
43 static zend_class_entry *php_zmq_exception_sc_entry;
44 static zend_class_entry *php_zmq_context_exception_sc_entry;
45 static zend_class_entry *php_zmq_socket_exception_sc_entry;
46 static zend_class_entry *php_zmq_poll_exception_sc_entry;
47 static zend_class_entry *php_zmq_device_exception_sc_entry;
48 
49 static zend_object_handlers zmq_object_handlers;
50 static zend_object_handlers zmq_socket_object_handlers;
51 static zend_object_handlers zmq_context_object_handlers;
52 static zend_object_handlers zmq_poll_object_handlers;
53 static zend_object_handlers zmq_device_object_handlers;
54 
55 #ifdef HAVE_CZMQ_2
56 static zend_class_entry *php_zmq_cert_sc_entry;
57 static zend_class_entry *php_zmq_auth_sc_entry;
58 
59 static zend_class_entry *php_zmq_cert_exception_sc_entry;
60 static zend_class_entry *php_zmq_auth_exception_sc_entry;
61 
62 static zend_object_handlers zmq_cert_object_handlers;
63 static zend_object_handlers zmq_auth_object_handlers;
64 #endif
65 
66 
67 #include "zmq_object_access.c"
68 
php_zmq_context_exception_sc_entry_get()69 zend_class_entry *php_zmq_context_exception_sc_entry_get ()
70 {
71 	return php_zmq_context_exception_sc_entry;
72 }
73 
php_zmq_socket_exception_sc_entry_get()74 zend_class_entry *php_zmq_socket_exception_sc_entry_get ()
75 {
76 	return php_zmq_socket_exception_sc_entry;
77 }
78 
php_zmq_device_exception_sc_entry_get()79 zend_class_entry *php_zmq_device_exception_sc_entry_get ()
80 {
81 	return php_zmq_device_exception_sc_entry;
82 }
83 
84 static
php_zmq_context_socket_count_get(php_zmq_context * context)85 zend_long php_zmq_context_socket_count_get(php_zmq_context *context)
86 {
87 	zend_long value = 0;
88 
89 	if (context->use_shared_ctx) {
90 		value = php_zmq_shared_ctx_socket_count();
91 	}
92 	else {
93 		value = context->socket_count;
94 	}
95 	return value;
96 }
97 
98 static
php_zmq_context_socket_count_incr(php_zmq_context * context)99 void php_zmq_context_socket_count_incr(php_zmq_context *context)
100 {
101 	if (context->use_shared_ctx) {
102 		php_zmq_shared_ctx_socket_count_incr();
103 	}
104 	else {
105 		context->socket_count++;
106 	}
107 }
108 
109 static
php_zmq_context_socket_count_decr(php_zmq_context * context)110 void php_zmq_context_socket_count_decr(php_zmq_context *context)
111 {
112 	if (context->use_shared_ctx) {
113 		php_zmq_shared_ctx_socket_count_decr();
114 	}
115 	else {
116 		context->socket_count--;
117 	}
118 }
119 
120 /* list entries */
121 static int le_zmq_socket, le_zmq_context;
122 
123 /** {{{ static int php_zmq_socket_list_entry(void)
124 */
php_zmq_socket_list_entry(void)125 static int php_zmq_socket_list_entry(void)
126 {
127 	return le_zmq_socket;
128 }
129 /* }}} */
130 
131 /* {{{ static int php_zmq_context_list_entry(void)
132 */
php_zmq_context_list_entry(void)133 static int php_zmq_context_list_entry(void)
134 {
135 	return le_zmq_context;
136 }
137 /* }}} */
138 
139 /* {{{ static void php_zmq_context_destroy(php_zmq_context *context)
140 	Destroy the context
141 */
php_zmq_context_destroy(php_zmq_context * context)142 static void php_zmq_context_destroy(php_zmq_context *context)
143 {
144 	if (context->pid == getpid()) {
145 		(void) zmq_term(context->z_ctx);
146 	}
147 	pefree(context, context->is_persistent);
148 }
149 /* }}} */
150 
151 /* {{{ static void php_zmq_socket_destroy(php_zmq_socket *zmq_sock)
152 	Destroy the socket (note: does not touch context)
153 */
php_zmq_socket_destroy(php_zmq_socket * zmq_sock)154 static void php_zmq_socket_destroy(php_zmq_socket *zmq_sock)
155 {
156 	zend_hash_destroy(&(zmq_sock->connect));
157 	zend_hash_destroy(&(zmq_sock->bind));
158 
159 	/* Decrement socket count */
160 	php_zmq_context_socket_count_decr(zmq_sock->ctx);
161 
162 	if (zmq_sock->pid == getpid ()) {
163 		(void) zmq_close(zmq_sock->z_socket);
164 	}
165 	pefree(zmq_sock, zmq_sock->is_persistent);
166 }
167 /* }}} */
168 
169 /* --- START ZMQContext --- */
170 
171 /* {{{ static php_zmq_context *php_zmq_context_new(zend_long io_threads, zend_bool is_persistent, zend_bool use_shared_ctx)
172 	Create a new zmq context
173 */
174 static
php_zmq_context_new(zend_long io_threads,zend_bool is_persistent,zend_bool use_shared_ctx)175 php_zmq_context *php_zmq_context_new(zend_long io_threads, zend_bool is_persistent, zend_bool use_shared_ctx)
176 {
177 	php_zmq_context *context = pecalloc(1, sizeof(php_zmq_context), is_persistent);
178 
179 	if (use_shared_ctx) {
180 		php_zmq_shared_ctx_assign_to(context);
181 	}
182 	else {
183 		context->z_ctx = zmq_init(io_threads);
184 	}
185 
186 	if (!context->z_ctx) {
187 		pefree(context, is_persistent);
188 		return NULL;
189 	}
190 
191 	context->io_threads     = io_threads;
192 	context->is_persistent  = is_persistent;
193 	context->pid            = getpid();
194 	context->socket_count   = 0;
195 	context->use_shared_ctx = use_shared_ctx;
196 	return context;
197 }
198 /* }}} */
199 
200 /* {{{ static php_zmq_context *php_zmq_context_get(zend_long io_threads, zend_bool is_persistent)
201 */
202 static
php_zmq_context_get(zend_long io_threads,zend_bool is_persistent)203 php_zmq_context *php_zmq_context_get(zend_long io_threads, zend_bool is_persistent)
204 {
205 	php_zmq_context *context;
206 	zend_string *plist_key = NULL;
207 
208 	if (is_persistent) {
209 		zend_resource *le_p = NULL;
210 		plist_key = strpprintf(0, "zmq_context=[%ld]", io_threads);
211 
212 		if ((le_p = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) {
213 			if (le_p->type == php_zmq_context_list_entry()) {
214 
215 				if (plist_key) {
216 					zend_string_release(plist_key);
217 				}
218 				return (php_zmq_context *) le_p->ptr;
219 			}
220 		}
221 	}
222 
223 	context = php_zmq_context_new(io_threads, is_persistent, 0);
224 
225 	if (!context) {
226 		if (plist_key) {
227 			zend_string_release(plist_key);
228 		}
229 		return NULL;
230 	}
231 
232 	if (is_persistent) {
233 
234 		zend_resource le;
235 		le.type = php_zmq_context_list_entry();
236 		le.ptr  = context;
237 
238 #if PHP_VERSION_ID < 70300
239 		GC_REFCOUNT(&le) = 1;
240 #else
241 		GC_SET_REFCOUNT(&le, 1);
242 #endif
243 
244 		/* plist_key is not a persistent allocated key, thus we use str_update here */
245 		if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) {
246 			if (plist_key) {
247 				zend_string_release(plist_key);
248 			}
249 			php_error_docref(NULL, E_ERROR, "Could not register persistent entry for the context");
250 			/* not reached */
251 		}
252 	}
253 	if (plist_key) {
254 		zend_string_release(plist_key);
255 	}
256 	return context;
257 }
258 /* }}} */
259 
260 /* {{{ proto ZMQ ZMQ::__construct()
261 	Private constructor
262 */
PHP_METHOD(zmq,__construct)263 PHP_METHOD(zmq, __construct) {}
264 /* }}} */
265 
266 /* {{{ proto integer ZMQ::clock()
267 	A monotonic clock
268 */
PHP_METHOD(zmq,clock)269 PHP_METHOD(zmq, clock)
270 {
271 	if (zend_parse_parameters_none() == FAILURE) {
272 		return;
273 	}
274 	RETURN_LONG((long) php_zmq_clock (ZMQ_G (clock_ctx)));
275 }
276 /* }}} */
277 
278 #ifdef PHP_ZMQ_HAVE_Z85
279 
280 /* {{{ proto string ZMQ::z85Encode(string $data)
281 
282 */
PHP_METHOD(zmq,z85encode)283 PHP_METHOD(zmq, z85encode)
284 {
285 	zend_string *data;
286 	char *buffer;
287 	size_t buffer_size;
288 
289 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
290 		return;
291 	}
292 
293 	if (!data->len) {
294 		RETURN_NULL();
295 	}
296 
297 	buffer_size = 5 * data->len / 4 + 1;
298 	buffer = emalloc(buffer_size);
299 
300 	if (!zmq_z85_encode (buffer, (const uint8_t *) data->val, data->len)) {
301 		efree(buffer);
302 		RETURN_NULL();
303 	}
304 
305 	RETVAL_STRINGL(buffer, buffer_size - 1);
306 	efree(buffer);
307 	return;
308 }
309 /* }}} */
310 
311 /* {{{ proto string ZMQ::z85Decode(string $z85_encoded_data)
312 
313 */
PHP_METHOD(zmq,z85decode)314 PHP_METHOD(zmq, z85decode)
315 {
316 	zend_string *data;
317 	uint8_t *buffer;
318 	size_t buffer_size;
319 
320 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
321 		return;
322 	}
323 
324 	if (!data->len) {
325 		RETURN_NULL();
326 	}
327 
328 	buffer_size = 4 * data->len / 5;
329 	buffer = emalloc(buffer_size);
330 
331 	if (!zmq_z85_decode (buffer, data->val)) {
332 		efree(buffer);
333 		RETURN_NULL();
334 	}
335 
336 	RETVAL_STRINGL((char *) buffer, buffer_size);
337 	efree(buffer);
338 	return;
339 }
340 /* }}} */
341 #endif
342 
343 #ifdef PHP_ZMQ_HAVE_CURVE_KEYPAIR
344 
345 #define PHP_ZMQ_KEY_SIZE 41
346 
347 /* {{{ proto array ZMQ::curveKeypair()
348 
349 */
PHP_METHOD(zmq,curvekeypair)350 PHP_METHOD(zmq, curvekeypair)
351 {
352 	char public_key[PHP_ZMQ_KEY_SIZE], secret_key[PHP_ZMQ_KEY_SIZE];
353 
354 	if (zend_parse_parameters_none() == FAILURE) {
355 		return;
356 	}
357 
358 	if (zmq_curve_keypair(public_key, secret_key) == 0) {
359 		array_init(return_value);
360 
361 		add_assoc_stringl(return_value, "public_key", public_key, PHP_ZMQ_KEY_SIZE - 1);
362 		add_assoc_stringl(return_value, "secret_key", secret_key, PHP_ZMQ_KEY_SIZE - 1);
363 	}
364 }
365 /* }}} */
366 
367 #endif
368 
369 
370 /* {{{ proto ZMQContext ZMQContext::__construct(integer $io_threads[, boolean $is_persistent = true])
371 	Build a new ZMQContext object
372 */
PHP_METHOD(zmqcontext,__construct)373 PHP_METHOD(zmqcontext, __construct)
374 {
375 	php_zmq_context_object *intern;
376 	long io_threads = 1;
377 	zend_bool is_persistent = 1;
378 
379 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lb", &io_threads, &is_persistent) == FAILURE) {
380 		return;
381 	}
382 	intern          = php_zmq_context_fetch_object(Z_OBJ_P(getThis()));
383 	intern->context = php_zmq_context_get(io_threads, is_persistent);
384 
385 	if (!intern->context) {
386 		zend_throw_exception_ex(php_zmq_context_exception_sc_entry, errno, "Error creating context: %s", zmq_strerror(errno));
387 		return;
388 	}
389 	return;
390 }
391 /* }}} */
392 
393 /* {{{ proto ZMQContext ZMQContext::acquire()
394 	Acquires a handle to the process global context
395 */
PHP_METHOD(zmqcontext,acquire)396 PHP_METHOD(zmqcontext, acquire)
397 {
398 	php_zmq_context *context;
399 	php_zmq_context_object *intern;
400 
401 	if (zend_parse_parameters_none() == FAILURE) {
402 		return;
403 	}
404 
405 	context = php_zmq_context_new(1, 1, 1);
406 
407 	// Create a global context
408 	object_init_ex(return_value, php_zmq_context_sc_entry);
409 	intern          = php_zmq_context_fetch_object(Z_OBJ_P(return_value));
410 	intern->context = context;
411 	return;
412 }
413 /* }}} */
414 
415 /* {{{ proto integer ZMQContext::getSocketCount()
416 	Number of active sockets in this context
417 */
PHP_METHOD(zmqcontext,getsocketcount)418 PHP_METHOD(zmqcontext, getsocketcount)
419 {
420 	php_zmq_context_object *intern;
421 
422 	if (zend_parse_parameters_none() == FAILURE) {
423 		return;
424 	}
425 	intern = PHP_ZMQ_CONTEXT_OBJECT;
426 	RETURN_LONG(php_zmq_context_socket_count_get(intern->context));
427 }
428 /* }}} */
429 
430 #ifdef PHP_ZMQ_HAVE_CTX_OPTIONS
431 /* {{{ proto ZMQContext ZMQContext::setOpt(int option, int value)
432 	Set a context option
433 */
PHP_METHOD(zmqcontext,setOpt)434 PHP_METHOD(zmqcontext, setOpt)
435 {
436 	php_zmq_context_object *intern;
437 	zend_long option, value;
438 
439 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &option, &value) == FAILURE) {
440 		return;
441 	}
442 	intern = PHP_ZMQ_CONTEXT_OBJECT;
443 
444 	switch (option) {
445 		case ZMQ_MAX_SOCKETS:
446 		{
447 			if (zmq_ctx_set(intern->context->z_ctx, option, value) != 0) {
448 				zend_throw_exception_ex(php_zmq_context_exception_sc_entry_get (), errno, "Failed to set the option ZMQ::CTXOPT_MAX_SOCKETS value: %s", zmq_strerror(errno));
449 				return;
450 			}
451 		}
452 		break;
453 
454 		default:
455 		{
456 			zend_throw_exception(php_zmq_context_exception_sc_entry_get (), "Unknown option key", PHP_ZMQ_INTERNAL_ERROR);
457 			return;
458 		}
459 	}
460 	return;
461 }
462 /* }}} */
463 
464 /* {{{ proto ZMQContext ZMQContext::getOpt(int option)
465 	Set a context option
466 */
PHP_METHOD(zmqcontext,getOpt)467 PHP_METHOD(zmqcontext, getOpt)
468 {
469 	php_zmq_context_object *intern;
470 	zend_long option;
471 
472 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &option) == FAILURE) {
473 		return;
474 	}
475 	intern = PHP_ZMQ_CONTEXT_OBJECT;
476 
477 	switch (option) {
478 
479 		case ZMQ_MAX_SOCKETS:
480 		{
481 			int value = zmq_ctx_get(intern->context->z_ctx, option);
482 			RETURN_LONG(value);
483 		}
484 		break;
485 
486 		default:
487 		{
488 			zend_throw_exception(php_zmq_context_exception_sc_entry_get (), "Unknown option key", PHP_ZMQ_INTERNAL_ERROR);
489 			return;
490 		}
491 	}
492 	return;
493 }
494 /* }}} */
495 #endif
496 
497 
498 /* {{{ static php_zmq_socket *php_zmq_socket_new(php_zmq_context *context, int type, zend_bool is_persistent)
499 	Create a new zmq socket
500 */
501 static
php_zmq_socket_new(php_zmq_context * context,int type,zend_bool is_persistent)502 php_zmq_socket *php_zmq_socket_new(php_zmq_context *context, int type, zend_bool is_persistent)
503 {
504 	php_zmq_socket *zmq_sock;
505 
506 	zmq_sock              = pecalloc(1, sizeof(php_zmq_socket), is_persistent);
507 	zmq_sock->z_socket    = zmq_socket(context->z_ctx, type);
508 	zmq_sock->pid         = getpid();
509 	zmq_sock->ctx         = context;
510     zmq_sock->socket_type = type;
511 
512 	if (!zmq_sock->z_socket) {
513 		pefree(zmq_sock, is_persistent);
514 		return NULL;
515 	}
516 
517 	/* Increment socket count */
518 	php_zmq_context_socket_count_incr(context);
519 	zmq_sock->is_persistent = is_persistent;
520 
521 	zend_hash_init(&(zmq_sock->connect), 0, NULL, NULL, is_persistent);
522 	zend_hash_init(&(zmq_sock->bind),    0, NULL, NULL, is_persistent);
523 	return zmq_sock;
524 }
525 /* }}} */
526 
527 static
php_zmq_socket_plist_key(zend_long type,zend_string * persistent_id,zend_bool use_shared_ctx)528 zend_string *php_zmq_socket_plist_key(zend_long type, zend_string *persistent_id, zend_bool use_shared_ctx)
529 {
530 	return strpprintf(0, "zmq_socket:[%ld]-[%s]-[%d]", type, persistent_id->val, use_shared_ctx);
531 }
532 
533 static
php_zmq_socket_store(php_zmq_socket * zmq_sock_p,zend_long type,zend_string * persistent_id,zend_bool use_shared_ctx)534 void php_zmq_socket_store(php_zmq_socket *zmq_sock_p, zend_long type, zend_string *persistent_id, zend_bool use_shared_ctx)
535 {
536 	zend_string *plist_key = NULL;
537 
538 	zend_resource le;
539 	le.type = php_zmq_socket_list_entry();
540 	le.ptr  = zmq_sock_p;
541 
542 #if PHP_VERSION_ID < 70300
543 	GC_REFCOUNT(&le) = 1;
544 #else
545 	GC_SET_REFCOUNT(&le, 1);
546 #endif
547 
548 	plist_key = php_zmq_socket_plist_key(type, persistent_id, use_shared_ctx);
549 
550 	/* plist_key is not a persistent allocated key, thus we use str_update here */
551 	if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) {
552 		if (plist_key) {
553 			zend_string_release(plist_key);
554 		}
555 		php_error_docref(NULL, E_ERROR, "Could not register persistent entry for the socket");
556 		/* not reached */
557 	}
558 
559 	if (plist_key) {
560 		zend_string_release(plist_key);
561 	}
562 }
563 
564 /* {{{ static php_zmq_socket *php_zmq_socket_get(php_zmq_context *context, zend_long type, zend_string *persistent_id, zend_bool *is_new)
565 	Tries to get context from plist and allocates a new context if context does not exist
566 */
php_zmq_socket_get(php_zmq_context * context,zend_long type,zend_string * persistent_id,zend_bool * is_new)567 static php_zmq_socket *php_zmq_socket_get(php_zmq_context *context, zend_long type, zend_string *persistent_id, zend_bool *is_new)
568 {
569 	php_zmq_socket *zmq_sock_p;
570 	zend_string *plist_key = NULL;
571 	zend_bool is_persistent = 0;
572 
573 	is_persistent = (context->is_persistent && persistent_id && persistent_id->len) ? 1 : 0;
574 	*is_new        = 0;
575 
576 	if (is_persistent) {
577 		zend_resource *le_p = NULL;
578 
579 		plist_key = php_zmq_socket_plist_key(type, persistent_id, context->use_shared_ctx);
580 
581 		if ((le_p = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) {
582 			if (le_p->type == php_zmq_socket_list_entry()) {
583 				if (plist_key) {
584 					zend_string_release(plist_key);
585 				}
586 				return (php_zmq_socket *) le_p->ptr;
587 			}
588 		}
589 	}
590 	zmq_sock_p = php_zmq_socket_new(context, type, is_persistent);
591 
592 	if (plist_key) {
593 		zend_string_release(plist_key);
594 	}
595 
596 	if (!zmq_sock_p) {
597 		return NULL;
598 	}
599 
600 	*is_new = 1;
601 	return zmq_sock_p;
602 }
603 /* }}} */
604 
605 static
php_zmq_connect_callback(zval * socket,zend_fcall_info * fci,zend_fcall_info_cache * fci_cache,zend_string * persistent_id)606 zend_bool php_zmq_connect_callback(zval *socket, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id)
607 {
608 	zval retval;
609 	zval params[2];
610 	zend_bool rv = 1;
611 
612 	/* Call the cb */
613 	params[0] = *socket;
614 
615 	if (persistent_id && persistent_id->len) {
616 		ZVAL_STR(&params[1], zend_string_copy(persistent_id));
617 	} else {
618 		ZVAL_NULL(&params[1]);
619 	}
620 
621 	fci->params         = params;
622 	fci->param_count    = 2;
623 	fci->retval         = &retval;
624 	fci->no_separation  = 1;
625 
626 	if (zend_call_function(fci, fci_cache) == FAILURE) {
627 		if (!EG(exception)) {
628 			char *func_name = php_zmq_printable_func(fci, fci_cache);
629 			zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, 0, "Failed to invoke 'on_new_socket' callback %s()", func_name);
630 			efree(func_name);
631 		}
632 		rv = 0;
633 	}
634 
635 	zval_ptr_dtor(&params[1]);
636 
637 	if (Z_TYPE(retval) != IS_UNDEF) {
638 		zval_ptr_dtor(&retval);
639 	}
640 
641 	if (EG(exception)) {
642 		rv = 0;
643 	}
644 	return rv;
645 }
646 
647 /* {{{ proto ZMQContext ZMQContext::getSocket(integer $type[, string $persistent_id = null[, callback $on_new_socket = null]])
648 	Build a new ZMQContext object
649 */
PHP_METHOD(zmqcontext,getsocket)650 PHP_METHOD(zmqcontext, getsocket)
651 {
652 	php_zmq_socket *socket;
653 	php_zmq_socket_object *interns;
654 	php_zmq_context_object *intern;
655 	zend_long type;
656 	zend_string *persistent_id = NULL;
657 	int rc;
658 	zend_bool is_new;
659 
660 	zend_fcall_info fci;
661 	zend_fcall_info_cache fci_cache;
662 
663 	PHP_ZMQ_ERROR_HANDLING_INIT()
664 	PHP_ZMQ_ERROR_HANDLING_THROW()
665 
666 	fci.size = 0;
667 	rc = zend_parse_parameters(ZEND_NUM_ARGS(), "l|S!f!", &type, &persistent_id, &fci, &fci_cache);
668 
669 	PHP_ZMQ_ERROR_HANDLING_RESTORE()
670 
671 	if (rc == FAILURE) {
672 		return;
673 	}
674 
675 	intern = php_zmq_context_fetch_object(Z_OBJ_P(getThis()));
676 	socket = php_zmq_socket_get(intern->context, type, persistent_id, &is_new);
677 
678 	if (!socket) {
679 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Error creating socket: %s", zmq_strerror(errno));
680 		return;
681 	}
682 
683 	object_init_ex(return_value, php_zmq_socket_sc_entry);
684 	interns         = php_zmq_socket_fetch_object(Z_OBJ_P(return_value));
685 	interns->socket = socket;
686 
687 	/* Need to add refcount if context is not persistent */
688 	if (!intern->context->is_persistent) {
689 		ZVAL_OBJ(&interns->context_obj, &intern->zo);
690 		Z_ADDREF(interns->context_obj);
691 	}
692 
693 	if (is_new) {
694 		if (fci.size) {
695 			if (!php_zmq_connect_callback(return_value, &fci, &fci_cache, persistent_id)) {
696 				php_zmq_socket_destroy(socket);
697 				interns->socket = NULL;
698 				zval_dtor(return_value);
699 				return;
700 			}
701 		}
702 		if (socket->is_persistent) {
703 			php_zmq_socket_store(socket, type, persistent_id, intern->context->use_shared_ctx);
704 		}
705 	}
706 	if (socket->is_persistent) {
707 		interns->persistent_id = estrdup(persistent_id->val);
708 	}
709 	return;
710 }
711 /* }}} */
712 
713 /* {{{ proto ZMQContext ZMQContext::isPersistent()
714 	Whether the context is persistent
715 */
PHP_METHOD(zmqcontext,ispersistent)716 PHP_METHOD(zmqcontext, ispersistent)
717 {
718 	php_zmq_context_object *intern;
719 
720 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
721 		return;
722 	}
723 
724 	intern = PHP_ZMQ_CONTEXT_OBJECT;
725 	RETURN_BOOL(intern->context->is_persistent);
726 }
727 /* }}} */
728 
729 /* {{{ proto ZMQContext ZMQContext::__clone()
730 	Clones the instance of the ZMQContext class
731 */
PHP_METHOD(zmqcontext,__clone)732 PHP_METHOD(zmqcontext, __clone) { }
733 /* }}} */
734 
735 /* --- END ZMQContext --- */
736 
737 /* --- START ZMQSocket --- */
738 
739 /* {{{ proto ZMQSocket ZMQSocket::__construct(ZMQContext $context, integer $type[, string $persistent_id = null[, callback $on_new_socket = null]])
740 	Build a new ZMQSocket object
741 */
PHP_METHOD(zmqsocket,__construct)742 PHP_METHOD(zmqsocket, __construct)
743 {
744 	php_zmq_socket *socket;
745 	php_zmq_socket_object *intern;
746 	php_zmq_context_object *internc;
747 	zend_long type;
748 	zend_string *persistent_id = NULL;
749 	int rc;
750 	zval *obj;
751 	zend_bool is_new;
752 
753 	zend_fcall_info fci;
754 	zend_fcall_info_cache fci_cache;
755 
756 	PHP_ZMQ_ERROR_HANDLING_INIT()
757 	PHP_ZMQ_ERROR_HANDLING_THROW()
758 
759 	fci.size = 0;
760 	rc = zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|S!f!", &obj, php_zmq_context_sc_entry, &type, &persistent_id, &fci, &fci_cache);
761 
762 	PHP_ZMQ_ERROR_HANDLING_RESTORE()
763 
764 	if (rc == FAILURE) {
765 		return;
766 	}
767 
768 	internc = php_zmq_context_fetch_object(Z_OBJ_P(obj));
769 	socket  = php_zmq_socket_get(internc->context, type, persistent_id, &is_new);
770 
771 	if (!socket) {
772 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Error creating socket: %s", zmq_strerror(errno));
773 		return;
774 	}
775 
776 	intern         = PHP_ZMQ_SOCKET_OBJECT;
777 	intern->socket = socket;
778 
779 	/* Need to add refcount if context is not persistent */
780 	if (!internc->context->is_persistent) {
781 		ZVAL_OBJ(&intern->context_obj, &internc->zo);
782 		Z_ADDREF(intern->context_obj);
783 	}
784 
785 	if (is_new) {
786 		if (fci.size) {
787 			if (!php_zmq_connect_callback(getThis(), &fci, &fci_cache, persistent_id)) {
788 				php_zmq_socket_destroy(socket);
789 				intern->socket = NULL;
790 				return;
791 			}
792 		}
793 		if (socket->is_persistent) {
794 			php_zmq_socket_store(socket, type, persistent_id, internc->context->use_shared_ctx);
795 		}
796 	}
797 	if (socket->is_persistent) {
798 		intern->persistent_id = estrdup(persistent_id->val);
799 	}
800 
801 	return;
802 }
803 /* }}} */
804 
805 /* {{{ static zend_bool php_zmq_send(php_zmq_socket_object *intern, char *message_param, long flags)
806 */
php_zmq_send(php_zmq_socket_object * intern,zend_string * message_param,long flags)807 static zend_bool php_zmq_send(php_zmq_socket_object *intern, zend_string *message_param, long flags)
808 {
809 	int rc, errno_;
810 	zmq_msg_t message;
811 
812 	if (zmq_msg_init_size(&message, message_param->len) != 0) {
813 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to initialize message structure: %s", zmq_strerror(errno));
814 		return 0;
815 	}
816 	memcpy(zmq_msg_data(&message), message_param->val, message_param->len);
817 
818 	rc = zmq_sendmsg(intern->socket->z_socket, &message, flags);
819 	errno_ = errno;
820 
821 	zmq_msg_close(&message);
822 
823 	if (rc == -1) {
824 	    if (errno_ == EAGAIN) {
825 			return 0;
826 	    }
827 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno_, "Failed to send message: %s", zmq_strerror(errno_));
828 		return 0;
829 	}
830 
831 	return 1;
832 }
833 /* }}} */
834 
php_zmq_sendmsg_impl(INTERNAL_FUNCTION_PARAMETERS)835 static void php_zmq_sendmsg_impl(INTERNAL_FUNCTION_PARAMETERS)
836 {
837 	php_zmq_socket_object *intern;
838 	zend_string *message_param;
839 	long flags = 0;
840 	zend_bool ret;
841 
842 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &message_param, &flags) == FAILURE) {
843 		return;
844 	}
845 	intern = PHP_ZMQ_SOCKET_OBJECT;
846 	ret = php_zmq_send(intern, message_param, flags);
847 
848 	if (ret) {
849 		ZMQ_RETURN_THIS;
850 	} else {
851 		RETURN_FALSE;
852 	}
853 }
854 
855 /* {{{ proto ZMQSocket ZMQSocket::send(string $message[, integer $flags = 0])
856 	Send a message. Return true if message was sent and false on EAGAIN
857 */
PHP_METHOD(zmqsocket,send)858 PHP_METHOD(zmqsocket, send)
859 {
860 	php_zmq_sendmsg_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
861 }
862 /* }}} */
863 
864 
865 static
php_zmq_send_cb(zval * zv,int num_args,va_list args,zend_hash_key * hash_key)866 int php_zmq_send_cb(zval *zv, int num_args, va_list args, zend_hash_key *hash_key)
867 {
868 	php_zmq_socket_object *intern;
869 	int flags, *rc, *to_send;
870 
871 	intern  = va_arg(args, php_zmq_socket_object *);
872 	flags   = va_arg(args, int);
873 	to_send = va_arg(args, int *);
874 	rc      = va_arg(args, int *);
875 
876 	if (--(*to_send)) {
877 		flags = flags | ZMQ_SNDMORE;
878 	} else {
879 		flags = flags & ~ZMQ_SNDMORE;
880 	}
881 
882 	zend_string *str = zval_get_string(zv);
883 	*rc = php_zmq_send(intern, str, flags);
884 
885 	zend_string_release(str);
886 
887 	if (!*rc) {
888 		return ZEND_HASH_APPLY_STOP;
889 	}
890 	return ZEND_HASH_APPLY_KEEP;
891 }
892 
893 /* {{{ proto ZMQSocket ZMQSocket::sendmulti(arrays $messages[, integer $flags = 0])
894 	Send a multipart message. Return true if message was sent and false on EAGAIN
895 */
PHP_METHOD(zmqsocket,sendmulti)896 PHP_METHOD(zmqsocket, sendmulti)
897 {
898 	zval *messages;
899 	php_zmq_socket_object *intern;
900 	int to_send, ret = 0;
901 	long flags = 0;
902 
903 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &messages, &flags) == FAILURE) {
904 		return;
905 	}
906 
907 	intern = PHP_ZMQ_SOCKET_OBJECT;
908 	to_send = zend_hash_num_elements(Z_ARRVAL_P(messages));
909 	zend_hash_apply_with_arguments(Z_ARRVAL_P(messages), (apply_func_args_t) php_zmq_send_cb, 4, intern, flags, &to_send, &ret);
910 
911 	if (ret) {
912 		ZMQ_RETURN_THIS;
913 	} else {
914 		RETURN_FALSE;
915 	}
916 }
917 
918 /* {{{ static zend_bool php_zmq_recv(php_zmq_socket_object *intern, long flags, zval *return_value)
919 */
920 static
php_zmq_recv(php_zmq_socket_object * intern,long flags)921 zend_string *php_zmq_recv(php_zmq_socket_object *intern, long flags)
922 {
923 	int rc, errno_;
924 	zmq_msg_t message;
925 	zend_string *str = NULL;
926 
927 	if (zmq_msg_init(&message) != 0) {
928 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to initialize message structure: %s", zmq_strerror(errno));
929 		return NULL;
930 	}
931 
932 	rc = zmq_recvmsg(intern->socket->z_socket, &message, flags);
933 	errno_ = errno;
934 
935 	if (rc == -1) {
936 		zmq_msg_close(&message);
937 		if (errno == EAGAIN) {
938 			return NULL;
939 		}
940 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno_, "Failed to receive message: %s", zmq_strerror(errno_));
941 		return NULL;
942 	}
943 
944 	str = zend_string_init(zmq_msg_data(&message), zmq_msg_size(&message), 1);
945 	zmq_msg_close(&message);
946 	return str;
947 }
948 /* }}} */
949 
php_zmq_recvmsg_impl(INTERNAL_FUNCTION_PARAMETERS)950 static void php_zmq_recvmsg_impl(INTERNAL_FUNCTION_PARAMETERS)
951 {
952 	zend_string *str = NULL;
953 	php_zmq_socket_object *intern;
954 	long flags = 0;
955 
956 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
957 		return;
958 	}
959 
960 	intern = PHP_ZMQ_SOCKET_OBJECT;
961 	str = php_zmq_recv(intern, flags);
962 
963 	if (!str) {
964 		RETURN_FALSE;
965 	}
966 	RETURN_STR(str);
967 }
968 
969 /* {{{ proto string ZMQ::recv([integer $flags = 0])
970 	Receive a message
971 */
PHP_METHOD(zmqsocket,recv)972 PHP_METHOD(zmqsocket, recv)
973 {
974 	php_zmq_recvmsg_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
975 }
976 /* }}} */
977 
978 /* {{{ proto array ZMQ::recvmulti([integer $flags = 0])
979 	Receive an array of message parts
980 */
PHP_METHOD(zmqsocket,recvmulti)981 PHP_METHOD(zmqsocket, recvmulti)
982 {
983 	php_zmq_socket_object *intern;
984 	size_t value_len;
985 	long flags = 0;
986 #if ZMQ_VERSION_MAJOR < 3
987 	int64_t value;
988 #else
989 	int value;
990 #endif
991 
992 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
993 		return;
994 	}
995 
996 	intern = PHP_ZMQ_SOCKET_OBJECT;
997 	array_init(return_value);
998 	value_len = sizeof (value);
999 
1000 	do {
1001 		zend_string *part = php_zmq_recv(intern, flags);
1002 		if (!part) {
1003 			zval_dtor(return_value);
1004 			RETURN_FALSE;
1005 		}
1006 		add_next_index_str(return_value, part);
1007 		zmq_getsockopt(intern->socket->z_socket, ZMQ_RCVMORE, &value, &value_len);
1008 	} while (value > 0);
1009 
1010 	return;
1011 }
1012 /* }}} */
1013 
1014 #if PHP_ZMQ_HAVE_SOCKET_MONITOR
1015 
1016 /* {{{ proto array ZMQ::recvevent([integer $flags = 0])
1017 	Receive an event from monitor endpoint
1018 */
PHP_METHOD(zmqsocket,recvevent)1019 PHP_METHOD(zmqsocket, recvevent)
1020 {
1021 	php_zmq_socket_object *intern;
1022 	zend_long flags = 0;
1023 	int value;
1024 	uint8_t *data;
1025 	uint16_t event;
1026 	zend_string *metadata, *address;
1027 
1028 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
1029 		return;
1030 	}
1031 
1032 	intern = PHP_ZMQ_SOCKET_OBJECT;
1033 
1034 	metadata = php_zmq_recv(intern, flags);
1035 	if (!metadata || metadata->len != sizeof (uint16_t) + sizeof (uint32_t)) {
1036 		if (metadata) {
1037 			zend_string_release(metadata);
1038 		}
1039 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Invalid monitor message received: %s", zmq_strerror(errno));
1040 		return;
1041 	}
1042 	address = php_zmq_recv(intern, flags);
1043 	if (!address) {
1044 		zend_string_release(metadata);
1045 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Invalid monitor message received: %s", zmq_strerror(errno));
1046 		return;
1047 	}
1048 
1049 	data  = (uint8_t *) metadata->val;
1050 	event = *(uint16_t *) (data);
1051 	value = *(uint32_t *) (data + sizeof(uint16_t));
1052 
1053 	array_init(return_value);
1054 
1055 	add_assoc_long(return_value, "event", event);
1056 	add_assoc_long(return_value, "value", value);
1057 	add_assoc_str(return_value, "address", address);
1058 
1059 	zend_string_release(metadata);
1060 	return;
1061 }
1062 /* }}} */
1063 
1064 /* {{{ proto ZMQSocket ZMQ::monitor(string $dsn[, integer $events = ZMQ::EVENTS_ALL])
1065 	Add a monitor
1066 */
PHP_METHOD(zmqsocket,monitor)1067 PHP_METHOD(zmqsocket, monitor)
1068 {
1069 	php_zmq_socket_object *intern;
1070 
1071 	zend_string *dsn;
1072 	zend_long events = ZMQ_EVENT_ALL;
1073 
1074 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &dsn, &events) == FAILURE) {
1075 		return;
1076 	}
1077 
1078 	intern = PHP_ZMQ_SOCKET_OBJECT;
1079 
1080 	if (zmq_socket_monitor(intern->socket->z_socket, dsn->val, events) != 0) {
1081 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to add socket monitor: %s", zmq_strerror(errno));
1082 		return;
1083 	}
1084 	ZMQ_RETURN_THIS;
1085 }
1086 /* }}} */
1087 
1088 #endif
1089 
1090 /** {{{ string ZMQ::getPersistentId()
1091 	Returns the persistent id of the object
1092 */
PHP_METHOD(zmqsocket,getpersistentid)1093 PHP_METHOD(zmqsocket, getpersistentid)
1094 {
1095 	php_zmq_socket_object *intern;
1096 
1097 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1098 		return;
1099 	}
1100 
1101 	intern = PHP_ZMQ_SOCKET_OBJECT;
1102 
1103 	if (intern->socket->is_persistent && intern->persistent_id) {
1104 		RETURN_STRING(intern->persistent_id);
1105 	}
1106 	RETURN_NULL();
1107 }
1108 /* }}} */
1109 
1110 /* {{{ proto ZMQSocket ZMQSocket::bind(string $dsn[, boolean $force = false])
1111 	Bind the socket to an endpoint
1112 */
PHP_METHOD(zmqsocket,bind)1113 PHP_METHOD(zmqsocket, bind)
1114 {
1115 	php_zmq_socket_object *intern;
1116 	zend_string *dsn;
1117 	zend_bool force = 0;
1118 
1119 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &dsn, &force) == FAILURE) {
1120 		return;
1121 	}
1122 
1123 	intern = php_zmq_socket_fetch_object(Z_OBJ_P(getThis()));
1124 
1125 	/* already connected ? */
1126 	if (!force && zend_hash_exists(&(intern->socket->bind), dsn)) {
1127 		ZMQ_RETURN_THIS;
1128 	}
1129 
1130 	if (zmq_bind(intern->socket->z_socket, dsn->val) != 0) {
1131 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to bind the ZMQ: %s", zmq_strerror(errno));
1132 		return;
1133 	}
1134 
1135 	zend_hash_str_add_empty_element(&(intern->socket->bind), dsn->val, dsn->len);
1136 	ZMQ_RETURN_THIS;
1137 }
1138 /* }}} */
1139 
1140 /* {{{ proto ZMQSocket ZMQSocket::connect(string $dsn[, boolean $force = false])
1141 	Connect the socket to an endpoint
1142 */
PHP_METHOD(zmqsocket,connect)1143 PHP_METHOD(zmqsocket, connect)
1144 {
1145 	php_zmq_socket_object *intern;
1146 	zend_string *dsn;
1147 	zend_bool force = 0;
1148 
1149 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &dsn, &force) == FAILURE) {
1150 		return;
1151 	}
1152 
1153 	intern = PHP_ZMQ_SOCKET_OBJECT;
1154 
1155 	/* already connected ? */
1156 	if (!force && zend_hash_exists(&(intern->socket->connect), dsn)) {
1157 		ZMQ_RETURN_THIS;
1158 	}
1159 
1160 	if (zmq_connect(intern->socket->z_socket, dsn->val) != 0) {
1161 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to connect the ZMQ: %s", zmq_strerror(errno));
1162 		return;
1163 	}
1164 
1165 	zend_hash_str_add_empty_element(&(intern->socket->connect), dsn->val, dsn->len);
1166 	ZMQ_RETURN_THIS;
1167 }
1168 /* }}} */
1169 
1170 #ifdef PHP_ZMQ_HAVE_UNBIND
1171 /* {{{ proto ZMQSocket ZMQSocket::unbind(string $dsn)
1172 	Unbind the socket from an endpoint
1173 */
PHP_METHOD(zmqsocket,unbind)1174 PHP_METHOD(zmqsocket, unbind)
1175 {
1176 	php_zmq_socket_object *intern;
1177 	zend_string *dsn;
1178 
1179 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &dsn) == FAILURE) {
1180 		return;
1181 	}
1182 
1183 	intern = PHP_ZMQ_SOCKET_OBJECT;
1184 
1185 	if (zmq_unbind(intern->socket->z_socket, dsn->val) != 0) {
1186 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to unbind the ZMQ socket: %s", zmq_strerror(errno));
1187 		return;
1188 	}
1189 
1190 	zend_hash_del(&(intern->socket->bind), dsn);
1191 	ZMQ_RETURN_THIS;
1192 }
1193 /* }}} */
1194 #endif
1195 
1196 #ifdef PHP_ZMQ_HAVE_DISCONNECT
1197 /* {{{ proto ZMQSocket ZMQSocket::disconnect(string $dsn)
1198 	Disconnect the socket from an endpoint
1199 */
PHP_METHOD(zmqsocket,disconnect)1200 PHP_METHOD(zmqsocket, disconnect)
1201 {
1202 	php_zmq_socket_object *intern;
1203 	zend_string *dsn;
1204 
1205 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &dsn) == FAILURE) {
1206 		return;
1207 	}
1208 
1209 	intern = PHP_ZMQ_SOCKET_OBJECT;
1210 
1211 	if (zmq_disconnect(intern->socket->z_socket, dsn->val) != 0) {
1212 		zend_throw_exception_ex(php_zmq_socket_exception_sc_entry, errno, "Failed to disconnect the ZMQ socket: %s", zmq_strerror(errno));
1213 		return;
1214 	}
1215 
1216 	zend_hash_del(&(intern->socket->connect), dsn);
1217 	ZMQ_RETURN_THIS;
1218 }
1219 /* }}} */
1220 #endif
1221 
1222 
1223 static
php_zmq_get_keys(zval * ppzval,int num_args,va_list args,zend_hash_key * hash_key)1224 int php_zmq_get_keys(zval *ppzval, int num_args, va_list args, zend_hash_key *hash_key)
1225 {
1226 	zval *retval = va_arg(args, zval *);
1227 	add_next_index_string(retval, hash_key->key->val);
1228 	return ZEND_HASH_APPLY_KEEP;
1229 }
1230 /* }}} */
1231 
1232 /* {{{ proto array ZMQ::getEndpoints()
1233 	Returns endpoints where this socket is connected/bound to. Contains two keys ('bind', 'connect')
1234 */
PHP_METHOD(zmqsocket,getendpoints)1235 PHP_METHOD(zmqsocket, getendpoints)
1236 {
1237 	php_zmq_socket_object *intern;
1238 	zval connect, bind;
1239 
1240 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1241 		return;
1242 	}
1243 
1244 	intern = PHP_ZMQ_SOCKET_OBJECT;
1245 	array_init(return_value);
1246 
1247 	array_init(&connect);
1248 	array_init(&bind);
1249 
1250 	zend_hash_apply_with_arguments(&(intern->socket->connect), (apply_func_args_t) php_zmq_get_keys, 1, &connect);
1251 	zend_hash_apply_with_arguments(&(intern->socket->bind), (apply_func_args_t) php_zmq_get_keys, 1, &bind);
1252 
1253 	add_assoc_zval(return_value, "connect", &connect);
1254 	add_assoc_zval(return_value, "bind", &bind);
1255 	return;
1256 }
1257 /* }}} */
1258 
1259 /* {{{ proto integer ZMQSocket::getSocketType()
1260 	Returns the socket type
1261 */
PHP_METHOD(zmqsocket,getsockettype)1262 PHP_METHOD(zmqsocket, getsockettype)
1263 {
1264 	int type;
1265 	size_t type_siz;
1266 	php_zmq_socket_object *intern;
1267 
1268 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1269 		return;
1270 	}
1271 	intern = PHP_ZMQ_SOCKET_OBJECT;
1272 	type_siz = sizeof (int);
1273 
1274 	if (zmq_getsockopt(intern->socket->z_socket, ZMQ_TYPE, &type, &type_siz) != -1) {
1275 		RETURN_LONG(type);
1276 	}
1277 	RETURN_LONG(-1);
1278 }
1279 /* }}} */
1280 
1281 /* {{{ proto boolean ZMQSocket::isPersistent()
1282 	Whether the socket is persistent
1283 */
PHP_METHOD(zmqsocket,ispersistent)1284 PHP_METHOD(zmqsocket, ispersistent)
1285 {
1286 	php_zmq_socket_object *intern;
1287 
1288 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1289 		return;
1290 	}
1291 
1292 	intern = PHP_ZMQ_SOCKET_OBJECT;
1293 	RETURN_BOOL(intern->socket->is_persistent);
1294 }
1295 /* }}} */
1296 
1297 /* {{{ proto ZMQSocket ZMQSocket::__clone()
1298 	Clones the instance of the ZMQSocket class
1299 */
PHP_METHOD(zmqsocket,__clone)1300 PHP_METHOD(zmqsocket, __clone) { }
1301 /* }}} */
1302 
1303 /* -- END ZMQSocket--- */
1304 
1305 /* -- START ZMQPoll --- */
1306 
1307 /* {{{ proto integer ZMQPoll::add(ZMQSocket $object, integer $events)
1308 	Add a ZMQSocket object into the pollset
1309 */
PHP_METHOD(zmqpoll,add)1310 PHP_METHOD(zmqpoll, add)
1311 {
1312 	php_zmq_poll_object *intern;
1313 	zval *object;
1314 	long events;
1315 	int error;
1316 	zend_string *key;
1317 
1318 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &object, &events) == FAILURE) {
1319 		return;
1320 	}
1321 
1322 	intern = PHP_ZMQ_POLL_OBJECT;
1323 
1324 	switch (Z_TYPE_P(object)) {
1325 		case IS_OBJECT:
1326 			if (!instanceof_function(Z_OBJCE_P(object), php_zmq_socket_sc_entry)) {
1327 				zend_throw_exception(php_zmq_poll_exception_sc_entry, "The first argument must be an instance of ZMQSocket or a resource", PHP_ZMQ_INTERNAL_ERROR);
1328 				return;
1329 			}
1330 		break;
1331 
1332 		case IS_RESOURCE:
1333 			/* noop */
1334 		break;
1335 
1336 		default:
1337 			zend_throw_exception(php_zmq_poll_exception_sc_entry, "The first argument must be an instance of ZMQSocket or a resource", PHP_ZMQ_INTERNAL_ERROR);
1338 			return;
1339 		break;
1340 	}
1341 
1342 	key = php_zmq_pollset_add(intern->set, object, events, &error);
1343 
1344 	if (!key) {
1345 		const char *message = NULL;
1346 
1347 		switch (error) {
1348 			case PHP_ZMQ_POLLSET_ERR_NO_STREAM:
1349 				message = "The supplied resource is not a valid stream resource";
1350 			break;
1351 
1352 			case PHP_ZMQ_POLLSET_ERR_CANNOT_CAST:
1353 				message = "The supplied resource is not castable";
1354 			break;
1355 
1356 			case PHP_ZMQ_POLLSET_ERR_CAST_FAILED:
1357 				message = "Failed to cast the supplied stream resource";
1358 			break;
1359 
1360 			case PHP_ZMQ_POLLSET_ERR_NO_INIT:
1361 				message = "The ZMQSocket object has not been initialized properly";
1362 			break;
1363 
1364 			case PHP_ZMQ_POLLSET_ERR_NO_POLL:
1365 				message = "The ZMQSocket object has not been initialized with polling";
1366 			break;
1367 
1368 			default:
1369 				message = "Unknown error";
1370 			break;
1371 		}
1372 
1373 		zend_throw_exception(php_zmq_poll_exception_sc_entry, message, PHP_ZMQ_INTERNAL_ERROR);
1374 		return;
1375 	}
1376 	RETURN_STR(key);
1377 }
1378 /* }}} */
1379 
1380 /* {{{ proto boolean ZMQPoll::remove(mixed $item)
1381 	Remove item from poll set
1382 */
PHP_METHOD(zmqpoll,remove)1383 PHP_METHOD(zmqpoll, remove)
1384 {
1385 	php_zmq_poll_object *intern;
1386 	zval *item;
1387 
1388 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &item) == FAILURE) {
1389 		return;
1390 	}
1391 
1392 	intern = PHP_ZMQ_POLL_OBJECT;
1393 
1394 	if (php_zmq_pollset_num_items(intern->set) == 0) {
1395 		zend_throw_exception(php_zmq_poll_exception_sc_entry, "No sockets assigned to the ZMQPoll", PHP_ZMQ_INTERNAL_ERROR);
1396 		return;
1397 	}
1398 
1399 	switch (Z_TYPE_P(item)) {
1400 
1401 		case IS_OBJECT:
1402 			if (!instanceof_function(Z_OBJCE_P(item), php_zmq_socket_sc_entry)) {
1403 				zend_throw_exception(php_zmq_poll_exception_sc_entry, "The object must be an instanceof ZMQSocket", PHP_ZMQ_INTERNAL_ERROR);
1404 				return;
1405 			}
1406 			/* break intentionally missing */
1407 		case IS_RESOURCE:
1408 			RETVAL_BOOL(php_zmq_pollset_delete(intern->set, item));
1409 		break;
1410 
1411 		default: {
1412 			zend_string *str = zval_get_string(item);
1413 			zend_bool retval;
1414 
1415 			retval = php_zmq_pollset_delete_by_key(intern->set, str);
1416 			zend_string_release(str);
1417 
1418 			RETVAL_BOOL(retval);
1419 		} break;
1420 	}
1421 
1422 	return;
1423 }
1424 /* }}} */
1425 
1426 /* {{{ proto integer ZMQPoll::poll(array &$readable, array &$writable[, integer $timeout = -1])
1427 	Poll the sockets
1428 */
PHP_METHOD(zmqpoll,poll)1429 PHP_METHOD(zmqpoll, poll)
1430 {
1431 	php_zmq_poll_object *intern;
1432 	zval *r_array, *w_array;
1433 
1434 	long timeout = -1;
1435 	int rc;
1436 
1437 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a!a!|l", &r_array, &w_array, &timeout) == FAILURE) {
1438 		return;
1439 	}
1440 
1441 	intern = PHP_ZMQ_POLL_OBJECT;
1442 
1443 	if (php_zmq_pollset_num_items(intern->set) == 0) {
1444 		zend_throw_exception(php_zmq_poll_exception_sc_entry, "No sockets assigned to the ZMQPoll", PHP_ZMQ_INTERNAL_ERROR);
1445 		return;
1446 	}
1447 
1448 	rc = php_zmq_pollset_poll(intern->set, timeout * PHP_ZMQ_TIMEOUT, r_array, w_array);
1449 
1450 	if (rc == -1) {
1451 		zend_throw_exception_ex(php_zmq_poll_exception_sc_entry, errno, "Poll failed: %s", zmq_strerror(errno));
1452 		return;
1453 	}
1454 	RETURN_LONG(rc);
1455 }
1456 /* }}} */
1457 
1458 /* {{{ proto integer ZMQPoll::count()
1459 	Returns the number of items in the set
1460 */
PHP_METHOD(zmqpoll,count)1461 PHP_METHOD(zmqpoll, count)
1462 {
1463 	php_zmq_poll_object *intern;
1464 
1465 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1466 		return;
1467 	}
1468 
1469 	intern = PHP_ZMQ_POLL_OBJECT;
1470 	RETURN_LONG(php_zmq_pollset_num_items(intern->set));
1471 }
1472 /* }}} */
1473 
1474 /* {{{ proto ZMQPoll ZMQPoll::clear()
1475 	Clear the pollset
1476 */
PHP_METHOD(zmqpoll,clear)1477 PHP_METHOD(zmqpoll, clear)
1478 {
1479 	php_zmq_poll_object *intern;
1480 
1481 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1482 		return;
1483 	}
1484 
1485 	intern = PHP_ZMQ_POLL_OBJECT;
1486 
1487 	php_zmq_pollset_clear(intern->set);
1488 	ZMQ_RETURN_THIS;
1489 }
1490 /* }}} */
1491 
1492 /* {{{ proto array ZMQPoll::items()
1493 	Clear the pollset
1494 */
PHP_METHOD(zmqpoll,items)1495 PHP_METHOD(zmqpoll, items)
1496 {
1497 	php_zmq_poll_object *intern;
1498 
1499 	if (zend_parse_parameters_none() == FAILURE) {
1500 		return;
1501 	}
1502 
1503 	intern = PHP_ZMQ_POLL_OBJECT;
1504 
1505 	array_init(return_value);
1506 	php_zmq_pollset_items(intern->set, return_value);
1507 }
1508 /* }}} */
1509 
1510 /* {{{ proto array ZMQPoll::getLastErrors()
1511 	Returns last errors
1512 */
PHP_METHOD(zmqpoll,getlasterrors)1513 PHP_METHOD(zmqpoll, getlasterrors)
1514 {
1515 	php_zmq_poll_object *intern;
1516 
1517 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1518 		return;
1519 	}
1520 
1521 	intern = PHP_ZMQ_POLL_OBJECT;
1522 	RETVAL_ZVAL(php_zmq_pollset_errors(intern->set), 1, 0);
1523 	return;
1524 }
1525 /* }}} */
1526 
1527 /* {{{ proto ZMQPoll ZMQPoll::__clone()
1528 	Clones the instance of the ZMQPoll class
1529 */
PHP_METHOD(zmqpoll,__clone)1530 PHP_METHOD(zmqpoll, __clone) { }
1531 /* }}} */
1532 
1533 /* -- END ZMQPoll */
1534 
1535 /* {{{ proto void ZMQDevice::__construct(ZMQSocket frontend, ZMQSocket backend)
1536 	Construct a device
1537 */
PHP_METHOD(zmqdevice,__construct)1538 PHP_METHOD(zmqdevice, __construct)
1539 {
1540 	php_zmq_device_object *intern;
1541 	zval *f, *b, *c = NULL;
1542 
1543 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO|O!", &f, php_zmq_socket_sc_entry, &b, php_zmq_socket_sc_entry, &c, php_zmq_socket_sc_entry) == FAILURE) {
1544 		return;
1545 	}
1546 
1547 	intern = PHP_ZMQ_DEVICE_OBJECT;
1548 
1549 	ZVAL_OBJ(&intern->front, Z_OBJ_P(f));
1550 	Z_ADDREF(intern->front);
1551 
1552 	ZVAL_OBJ(&intern->back, Z_OBJ_P(b));
1553 	Z_ADDREF(intern->back);
1554 
1555 	if (c) {
1556 		ZVAL_OBJ(&intern->capture, Z_OBJ_P(c));
1557 		Z_ADDREF(intern->capture);
1558 	} else {
1559 		ZVAL_UNDEF(&intern->capture);
1560 	}
1561 }
1562 /* }}} */
1563 
1564 /* {{{ proto void ZMQDevice::run()
1565 	Start a device
1566 */
PHP_METHOD(zmqdevice,run)1567 PHP_METHOD(zmqdevice, run)
1568 {
1569 	php_zmq_device_object *intern;
1570 	zend_bool rc;
1571 
1572 	if (zend_parse_parameters_none() == FAILURE) {
1573 		return;
1574 	}
1575 
1576 	intern = PHP_ZMQ_DEVICE_OBJECT;
1577 	rc = php_zmq_device (intern);
1578 
1579 	if (!rc && !EG (exception)) {
1580 		zend_throw_exception_ex(php_zmq_device_exception_sc_entry, errno, "Failed to start the device: %s", zmq_strerror (errno));
1581 		return;
1582 	}
1583 	return;
1584 }
1585 /* }}} */
1586 
1587 static
s_clear_device_callback(php_zmq_device_cb_t * cb)1588 void s_clear_device_callback (php_zmq_device_cb_t *cb)
1589 {
1590 	if (cb->initialized) {
1591 		zval_ptr_dtor(&cb->fci.function_name);
1592 		cb->fci.size = 0;
1593 
1594 		if (!Z_ISUNDEF(cb->user_data)) {
1595 			zval_ptr_dtor(&cb->user_data);
1596 		}
1597 		memset (cb, 0, sizeof (php_zmq_device_cb_t));
1598 		cb->initialized = 0;
1599 	}
1600 }
1601 
1602 static
s_init_device_callback(php_zmq_device_cb_t * cb,zend_fcall_info * fci,zend_fcall_info_cache * fci_cache,long timeout,zval * user_data)1603 void s_init_device_callback (php_zmq_device_cb_t *cb, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, long timeout, zval *user_data)
1604 {
1605 	memcpy (&cb->fci, fci, sizeof (zend_fcall_info));
1606 	memcpy (&cb->fci_cache, fci_cache, sizeof (zend_fcall_info_cache));
1607 
1608 	Z_TRY_ADDREF (fci->function_name);
1609 	cb->initialized  = 1;
1610 	cb->scheduled_at = php_zmq_clock (ZMQ_G (clock_ctx)) + timeout;
1611 	cb->timeout      = timeout;
1612 
1613 	if (user_data) {
1614 		ZVAL_COPY(&cb->user_data, user_data);
1615 	} else {
1616 		ZVAL_NULL(&cb->user_data);
1617 	}
1618 }
1619 
1620 /* {{{ proto void ZMQDevice::setIdleTimeout (int $milliseconds)
1621 	Set the idle timeout value
1622 */
PHP_METHOD(zmqdevice,setidletimeout)1623 PHP_METHOD(zmqdevice, setidletimeout)
1624 {
1625 	php_zmq_device_object *intern;
1626 	long timeout;
1627 
1628 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &timeout) == FAILURE) {
1629 		return;
1630 	}
1631 
1632 	intern = PHP_ZMQ_DEVICE_OBJECT;
1633 	intern->idle_cb.timeout = timeout;
1634 	ZMQ_RETURN_THIS;
1635 
1636 }
1637 /* }}} */
1638 
PHP_METHOD(zmqdevice,getidletimeout)1639 PHP_METHOD(zmqdevice, getidletimeout)
1640 {
1641 	php_zmq_device_object *intern;
1642 
1643 	if (zend_parse_parameters_none() == FAILURE) {
1644 		return;
1645 	}
1646 
1647 	intern = PHP_ZMQ_DEVICE_OBJECT;
1648 	RETURN_LONG(intern->idle_cb.timeout);
1649 }
1650 
1651 
PHP_METHOD(zmqdevice,settimertimeout)1652 PHP_METHOD(zmqdevice, settimertimeout)
1653 {
1654 	php_zmq_device_object *intern;
1655 	long timeout;
1656 
1657 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &timeout) == FAILURE) {
1658 		return;
1659 	}
1660 
1661 	intern = PHP_ZMQ_DEVICE_OBJECT;
1662 	intern->timer_cb.timeout = timeout;
1663 	ZMQ_RETURN_THIS;
1664 }
1665 
PHP_METHOD(zmqdevice,gettimertimeout)1666 PHP_METHOD(zmqdevice, gettimertimeout)
1667 {
1668 	php_zmq_device_object *intern;
1669 
1670 	if (zend_parse_parameters_none() == FAILURE) {
1671 		return;
1672 	}
1673 
1674 	intern = PHP_ZMQ_DEVICE_OBJECT;
1675 	RETURN_LONG(intern->timer_cb.timeout);
1676 }
1677 
1678 /* {{{ proto void ZMQDevice::setIdleCallback (callable $function, integer timeout [, mixed $userdata])
1679 	Set the idle timeout value
1680 */
PHP_METHOD(zmqdevice,setidlecallback)1681 PHP_METHOD(zmqdevice, setidlecallback)
1682 {
1683 	php_zmq_device_object *intern;
1684 	zval *user_data = NULL;
1685 	zend_fcall_info fci;
1686 	zend_fcall_info_cache fci_cache;
1687 	long timeout = 0;
1688 
1689 	if (ZEND_NUM_ARGS() == 2) {
1690 		php_error_docref(NULL, E_DEPRECATED, "The signature for setIdleCallback has changed, please update your code");
1691 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "f|z!", &fci, &fci_cache, &user_data) == FAILURE) {
1692 			return;
1693 		}
1694 	}
1695 	else {
1696 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "fl|z!", &fci, &fci_cache, &timeout, &user_data) == FAILURE) {
1697 			return;
1698 		}
1699 	}
1700 
1701 	intern = PHP_ZMQ_DEVICE_OBJECT;
1702 
1703 	/* Hack for backwards compatible behaviour */
1704 	if (!timeout) {
1705 		if (intern->idle_cb.timeout) {
1706 			timeout = intern->idle_cb.timeout;
1707 		}
1708 	}
1709 
1710 	s_clear_device_callback (&intern->idle_cb);
1711 
1712 	if (fci.size > 0) {
1713 		s_init_device_callback (&intern->idle_cb, &fci, &fci_cache, timeout, user_data);
1714 	}
1715 	ZMQ_RETURN_THIS;
1716 
1717 }
1718 /* }}} */
1719 
1720 /* {{{ proto void ZMQDevice::setTimerCallback (callable $function, integer timeout [, mixed $userdata])
1721 	Set the timer function
1722 */
PHP_METHOD(zmqdevice,settimercallback)1723 PHP_METHOD(zmqdevice, settimercallback)
1724 {
1725 	php_zmq_device_object *intern;
1726 	zval *user_data = NULL;
1727 	zend_fcall_info fci;
1728 	zend_fcall_info_cache fci_cache;
1729 	long timeout;
1730 
1731 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "fl|z!", &fci, &fci_cache, &timeout, &user_data) == FAILURE) {
1732 		return;
1733 	}
1734 
1735 	intern = PHP_ZMQ_DEVICE_OBJECT;
1736 
1737 	s_clear_device_callback (&intern->timer_cb);
1738 	if (fci.size > 0) {
1739 		s_init_device_callback (&intern->timer_cb, &fci, &fci_cache, timeout, user_data);
1740 	}
1741 	ZMQ_RETURN_THIS;
1742 }
1743 /* }}} */
1744 
1745 /* {{{ proto ZMQDevice ZMQDevice::__clone()
1746 	Clones the instance of the ZMQDevice class
1747 */
PHP_METHOD(zmqdevice,__clone)1748 PHP_METHOD(zmqdevice, __clone) { }
1749 /* }}} */
1750 
1751 /* -- END ZMQPoll */
1752 
1753 #ifdef HAVE_CZMQ_2
1754 
1755 /* --- START q --- */
1756 
1757 static
php_zmq_cert_object_free_storage(zend_object * object)1758 void php_zmq_cert_object_free_storage(zend_object *object)
1759 {
1760 	php_zmq_cert_object *intern = php_zmq_cert_fetch_object(object);
1761 
1762 	if (!intern) {
1763 		return;
1764 	}
1765 
1766 	if (intern->zcert) {
1767 		zcert_destroy(&intern->zcert);
1768 	}
1769 	zend_object_std_dtor(&intern->zo);
1770 }
1771 
1772 static
php_zmq_cert_new(zend_class_entry * class_type)1773 zend_object *php_zmq_cert_new(zend_class_entry *class_type)
1774 {
1775 	php_zmq_cert_object *intern = ecalloc(1, sizeof(php_zmq_cert_object) + zend_object_properties_size(class_type));
1776 
1777 	/* zcert is initialised in ZMQCert#__construct. */
1778 	intern->zcert = NULL;
1779 
1780 	zend_object_std_init(&intern->zo, class_type);
1781 	object_properties_init(&intern->zo, class_type);
1782 
1783 	intern->zo.handlers = &zmq_cert_object_handlers;
1784 	return &intern->zo;
1785 }
1786 
PHP_METHOD(zmqcert,__construct)1787 PHP_METHOD(zmqcert, __construct)
1788 {
1789 	zend_string *filename = NULL;
1790 	zend_error_handling error_handling;
1791 	int parse_parameters_result;
1792 	php_zmq_cert_object *intern;
1793 
1794 	zend_replace_error_handling(EH_THROW, php_zmq_cert_exception_sc_entry, &error_handling);
1795 	parse_parameters_result = zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &filename);
1796 	zend_restore_error_handling(&error_handling);
1797 
1798 	if (parse_parameters_result != SUCCESS) {
1799 		return;
1800 	}
1801 
1802 	intern = PHP_ZMQ_CERT_OBJECT;
1803 
1804 	if (!filename) {
1805 		intern->zcert = zcert_new();
1806 
1807 		if (!intern->zcert) {
1808 			zend_throw_exception_ex(php_zmq_cert_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to create the underlying zcert object. Is libsodium installed?", filename);
1809 		}
1810 		return;
1811 	}
1812 
1813 	intern->zcert = zcert_load(filename->val);
1814 
1815 	if (!intern->zcert) {
1816 		zend_throw_exception_ex(php_zmq_cert_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to load the certificate from %s", filename->val);
1817 	}
1818 
1819 	return;
1820 }
1821 
1822 ZEND_BEGIN_ARG_INFO_EX(zmqcert___construct_args, 0, 0, 0)
1823 	ZEND_ARG_INFO(0, filename)
1824 ZEND_END_ARG_INFO();
1825 
PHP_METHOD(zmqcert,getPublicKey)1826 PHP_METHOD(zmqcert, getPublicKey)
1827 {
1828 	php_zmq_cert_object *intern;
1829 	byte *public_key;
1830 
1831 	if (zend_parse_parameters_none() != SUCCESS) {
1832 		return;
1833 	}
1834 
1835 	intern = PHP_ZMQ_CERT_OBJECT;
1836 	public_key = zcert_public_key(intern->zcert);
1837 
1838 	if (!public_key) {
1839 		RETURN_NULL();
1840 	}
1841 	RETURN_STRINGL((char *) public_key, 32);
1842 }
1843 
1844 ZEND_BEGIN_ARG_INFO_EX(zmqcert_getPublicKey_args, 0, 0, 0)
ZEND_END_ARG_INFO()1845 ZEND_END_ARG_INFO()
1846 
1847 PHP_METHOD(zmqcert, getSecretKey)
1848 {
1849 	php_zmq_cert_object *intern;
1850 	byte *secret_key;
1851 
1852 	if (zend_parse_parameters_none() != SUCCESS) {
1853 		return;
1854 	}
1855 
1856 	intern = PHP_ZMQ_CERT_OBJECT;
1857 	secret_key = zcert_secret_key(intern->zcert);
1858 
1859 	if (!secret_key) {
1860 		RETURN_NULL();
1861 	}
1862 	RETURN_STRINGL((char *) secret_key, 32);
1863 }
1864 
1865 ZEND_BEGIN_ARG_INFO_EX(zmqcert_getSecretKey_args, 0, 0, 0)
ZEND_END_ARG_INFO()1866 ZEND_END_ARG_INFO()
1867 
1868 PHP_METHOD(zmqcert, getPublicTxt)
1869 {
1870 	php_zmq_cert_object *intern;
1871 	char *public_txt;
1872 
1873 	if (zend_parse_parameters_none() != SUCCESS) {
1874 		return;
1875 	}
1876 
1877 	intern = PHP_ZMQ_CERT_OBJECT;
1878 	public_txt = zcert_public_txt(intern->zcert);
1879 
1880 	if (!public_txt) {
1881 		RETURN_NULL();
1882 	}
1883 	RETURN_STRING(public_txt);
1884 }
1885 
1886 ZEND_BEGIN_ARG_INFO_EX(zmqcert_getPublicTxt_args, 0, 0, 0)
ZEND_END_ARG_INFO()1887 ZEND_END_ARG_INFO()
1888 
1889 PHP_METHOD(zmqcert, getSecretTxt)
1890 {
1891 	php_zmq_cert_object *intern;
1892 	char *secret_txt;
1893 
1894 	if (zend_parse_parameters_none() != SUCCESS) {
1895 		return;
1896 	}
1897 
1898 	intern = PHP_ZMQ_CERT_OBJECT;
1899 	secret_txt = zcert_secret_txt(intern->zcert);
1900 
1901 	if (!secret_txt) {
1902 		RETURN_NULL();
1903 	}
1904 	RETURN_STRING(secret_txt);
1905 }
1906 
1907 ZEND_BEGIN_ARG_INFO_EX(zmqcert_getSecretTxt_args, 0, 0, 0)
ZEND_END_ARG_INFO()1908 ZEND_END_ARG_INFO()
1909 
1910 PHP_METHOD(zmqcert, setMeta)
1911 {
1912 	php_zmq_cert_object *intern;
1913 	zend_string *name;
1914 	zend_string *format;
1915 
1916 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &name, &format) != SUCCESS) {
1917 		return;
1918 	}
1919 
1920 	intern = PHP_ZMQ_CERT_OBJECT;
1921 	zcert_set_meta(intern->zcert, name->val, format->val);
1922 
1923 	return;
1924 }
1925 
1926 ZEND_BEGIN_ARG_INFO_EX(zmqcert_setMeta_args, 0, 0, 2)
1927 	ZEND_ARG_INFO(0, name)
1928 	ZEND_ARG_INFO(0, format)
ZEND_END_ARG_INFO()1929 ZEND_END_ARG_INFO()
1930 
1931 PHP_METHOD(zmqcert, getMeta)
1932 {
1933 	zend_string *name;
1934 	php_zmq_cert_object *intern;
1935 	char *result;
1936 
1937 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) != SUCCESS) {
1938 		return;
1939 	}
1940 
1941 	intern = PHP_ZMQ_CERT_OBJECT;
1942 	result = zcert_meta(intern->zcert, name->val);
1943 
1944 	if (!result) {
1945 		RETURN_NULL();
1946 	}
1947 	RETURN_STRING(result);
1948 }
1949 
1950 ZEND_BEGIN_ARG_INFO_EX(zmqcert_getMeta_args, 0, 0, 1)
1951 	ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()1952 ZEND_END_ARG_INFO()
1953 
1954 PHP_METHOD(zmqcert, getMetaKeys)
1955 {
1956 	php_zmq_cert_object *intern;
1957 	zlist_t *meta_keys;
1958 	char *meta_key;
1959 
1960 	if (zend_parse_parameters_none() != SUCCESS) {
1961 		return;
1962 	}
1963 
1964 	intern = PHP_ZMQ_CERT_OBJECT;
1965 
1966 	meta_keys = zcert_meta_keys(intern->zcert);
1967 	meta_key = (char *) zlist_first(meta_keys);
1968 
1969 	array_init(return_value);
1970 	while (meta_key) {
1971 		add_next_index_string(return_value, meta_key);
1972 		meta_key = zlist_next(meta_keys);
1973 	}
1974 
1975 	return;
1976 }
1977 
1978 ZEND_BEGIN_ARG_INFO_EX(zmqcert_getMetaKeys_args, 0, 0, 0)
ZEND_END_ARG_INFO()1979 ZEND_END_ARG_INFO()
1980 
1981 PHP_METHOD(zmqcert, save)
1982 {
1983 	php_zmq_cert_object *intern;
1984 	zend_string *filename;
1985 
1986 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &filename) != SUCCESS) {
1987 		return;
1988 	}
1989 
1990 	intern = PHP_ZMQ_CERT_OBJECT;
1991 
1992 	if (zcert_save(intern->zcert, filename->val) == -1) {
1993 		zend_throw_exception_ex(php_zmq_cert_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to save the certificate to %s", filename->val);
1994 	}
1995 
1996 	return;
1997 }
1998 
1999 ZEND_BEGIN_ARG_INFO_EX(zmqcert_save_args, 0, 0, 1)
2000 	ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()2001 ZEND_END_ARG_INFO()
2002 
2003 PHP_METHOD(zmqcert, savePublic)
2004 {
2005 	zend_string *filename;
2006 	php_zmq_cert_object *intern;
2007 
2008 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &filename) != SUCCESS) {
2009 		return;
2010 	}
2011 
2012 	intern = PHP_ZMQ_CERT_OBJECT;
2013 
2014 	if (zcert_save_public(intern->zcert, filename->val) == -1) {
2015 		zend_throw_exception_ex(php_zmq_cert_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to save the public certificate to %s", filename->val);
2016 	}
2017 
2018 	return;
2019 }
2020 
2021 ZEND_BEGIN_ARG_INFO_EX(zmqcert_savePublic_args, 0, 0, 1)
2022 	ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()2023 ZEND_END_ARG_INFO()
2024 
2025 PHP_METHOD(zmqcert, saveSecret)
2026 {
2027 	zend_string *filename;
2028 	php_zmq_cert_object *intern;
2029 
2030 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &filename) != SUCCESS) {
2031 		return;
2032 	}
2033 
2034 	intern = PHP_ZMQ_CERT_OBJECT;
2035 
2036 	if (zcert_save_secret(intern->zcert, filename->val) == -1) {
2037 		zend_throw_exception_ex(php_zmq_cert_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to save the secret certificate to %s", filename->val);
2038 	}
2039 
2040 	return;
2041 }
2042 
2043 ZEND_BEGIN_ARG_INFO_EX(zmqcert_saveSecret_args, 0, 0, 1)
2044 	ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()2045 ZEND_END_ARG_INFO()
2046 
2047 PHP_METHOD(zmqcert, apply)
2048 {
2049 	php_zmq_cert_object *intern;
2050 	zval *object;
2051 
2052 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &object, php_zmq_socket_sc_entry) != SUCCESS) {
2053 		return;
2054 	}
2055 
2056 	intern = PHP_ZMQ_CERT_OBJECT;
2057 	zcert_apply(intern->zcert, php_zmq_socket_fetch_object(Z_OBJ_P(object))->socket->z_socket);
2058 }
2059 
2060 ZEND_BEGIN_ARG_INFO_EX(zmqcert_apply_args, 0, 0, 1)
2061 	ZEND_ARG_OBJ_INFO(0, ZMQSocket, ZMQSocket, 0)
ZEND_END_ARG_INFO()2062 ZEND_END_ARG_INFO()
2063 
2064 static
2065 zend_object *php_zmq_cert_clone(zval *object)
2066 {
2067 	zend_object *result;
2068 	php_zmq_cert_object *intern;
2069 	php_zmq_cert_object *that;
2070 
2071 	intern = php_zmq_cert_fetch_object(Z_OBJ_P(object));
2072 	result = php_zmq_cert_new(php_zmq_cert_sc_entry);
2073 
2074 	that = php_zmq_cert_fetch_object(result);
2075 	that->zcert = zcert_dup(intern->zcert);
2076 	return result;
2077 }
2078 
PHP_METHOD(zmqcert,equals)2079 PHP_METHOD(zmqcert, equals)
2080 {
2081 	php_zmq_cert_object *intern;
2082 	zval *object;
2083 	php_zmq_cert_object *that;
2084 
2085 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &object, php_zmq_cert_sc_entry) != SUCCESS) {
2086 		return;
2087 	}
2088 
2089 	intern = PHP_ZMQ_CERT_OBJECT;
2090 	that = php_zmq_cert_fetch_object(Z_OBJ_P(object));
2091 
2092 	RETURN_BOOL(zcert_eq(intern->zcert, that->zcert) == 1);
2093 }
2094 
2095 ZEND_BEGIN_ARG_INFO_EX(zmqcert_equals_args, 0, 0, 1)
2096 	ZEND_ARG_OBJ_INFO(0, ZMQCert, ZMQCert, 0)
2097 ZEND_END_ARG_INFO()
2098 
2099 static zend_function_entry php_zmq_cert_class_methods[] = {
2100 	PHP_ME(zmqcert, __construct,	zmqcert___construct_args,	ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
2101 	PHP_ME(zmqcert, getPublicKey,	zmqcert_getPublicKey_args,	ZEND_ACC_PUBLIC)
2102 	PHP_ME(zmqcert, getSecretKey,	zmqcert_getSecretKey_args,	ZEND_ACC_PUBLIC)
2103 	PHP_ME(zmqcert, getPublicTxt,	zmqcert_getPublicTxt_args,	ZEND_ACC_PUBLIC)
2104 	PHP_ME(zmqcert, getSecretTxt,	zmqcert_getSecretTxt_args,	ZEND_ACC_PUBLIC)
2105 	PHP_ME(zmqcert, setMeta,		zmqcert_setMeta_args,		ZEND_ACC_PUBLIC)
2106 	PHP_ME(zmqcert, getMeta,		zmqcert_getMeta_args,		ZEND_ACC_PUBLIC)
2107 	PHP_ME(zmqcert, getMetaKeys,	zmqcert_getMetaKeys_args,	ZEND_ACC_PUBLIC)
2108 	PHP_ME(zmqcert, save,			zmqcert_save_args,			ZEND_ACC_PUBLIC)
2109 	PHP_ME(zmqcert, savePublic,		zmqcert_savePublic_args,	ZEND_ACC_PUBLIC)
2110 	PHP_ME(zmqcert, saveSecret,		zmqcert_saveSecret_args,	ZEND_ACC_PUBLIC)
2111 	PHP_ME(zmqcert, apply,			zmqcert_apply_args,			ZEND_ACC_PUBLIC)
2112 	/* PHP_ME(zmqcert, __clone, zmqcert___clone_args, ZEND_ACC_PUBLIC) */
2113 	PHP_ME(zmqcert, equals,			zmqcert_equals_args,		ZEND_ACC_PUBLIC)
2114 	{NULL, NULL, NULL}
2115 };
2116 
2117 /* --- END ZMQCert --- */
2118 
2119 /* --- START ZMQAuth --- */
2120 
2121 static
php_zmq_auth_object_free_storage(zend_object * object)2122 void php_zmq_auth_object_free_storage(zend_object *object)
2123 {
2124 	php_zmq_auth_object *intern = php_zmq_auth_fetch_object(object);
2125 
2126 	if (!intern) {
2127 		return;
2128 	}
2129 
2130 	if (intern->zauth) {
2131 		zauth_destroy(&intern->zauth);
2132 	}
2133 	if (intern->shadow_context) {
2134 		zctx_destroy(&intern->shadow_context);
2135 	}
2136 	zend_object_std_dtor(&intern->zo);
2137 }
2138 
2139 static
php_zmq_auth_new(zend_class_entry * class_type)2140 zend_object *php_zmq_auth_new(zend_class_entry *class_type)
2141 {
2142 	php_zmq_auth_object *intern = ecalloc(1, sizeof(php_zmq_auth_object) + zend_object_properties_size(class_type));
2143 
2144 	/* zcert is initialised in ZMQCert#__construct. */
2145 	intern->zauth = NULL;
2146 
2147 	zend_object_std_init(&intern->zo, class_type);
2148 	object_properties_init(&intern->zo, class_type);
2149 
2150 	intern->zo.handlers = &zmq_auth_object_handlers;
2151 	return &intern->zo;
2152 }
2153 
PHP_METHOD(zmqauth,__construct)2154 PHP_METHOD(zmqauth, __construct)
2155 {
2156 	php_zmq_auth_object *intern;
2157 	zval *object;
2158 	zend_error_handling error_handling;
2159 	int parse_parameters_result;
2160 	php_zmq_context_object *context_object;
2161 
2162 	zend_replace_error_handling(EH_THROW, php_zmq_cert_exception_sc_entry, &error_handling);
2163 	parse_parameters_result = zend_parse_parameters(ZEND_NUM_ARGS(), "O", &object, php_zmq_context_sc_entry);
2164 	zend_restore_error_handling(&error_handling);
2165 
2166 	if (parse_parameters_result != SUCCESS) {
2167 		return;
2168 	}
2169 
2170 	intern = PHP_ZMQ_AUTH_OBJECT;
2171 
2172 	context_object = php_zmq_context_fetch_object(Z_OBJ_P(object));
2173 
2174 	// NOTE (phuedx, 2014-05-14): A zauth object needs a context so that it
2175 	// can take over authentication for all incoming connections in that
2176 	// context. Creating a shadow context from the specified context allows
2177 	// us to continue working with CZMQ.
2178 	intern->shadow_context = zctx_shadow_zmq_ctx(context_object->context->z_ctx);
2179 
2180 	if (!intern->shadow_context) {
2181 		zend_throw_exception_ex(php_zmq_auth_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to create the underlying shadow context object.");
2182 		return;
2183 	}
2184 
2185 	intern->zauth = zauth_new(intern->shadow_context);
2186 
2187 	if (!intern->zauth) {
2188 		zctx_destroy(&intern->shadow_context);
2189 		zend_throw_exception_ex(php_zmq_auth_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Failed to create the underlying zauth object.");
2190 	}
2191 	return;
2192 }
2193 
2194 ZEND_BEGIN_ARG_INFO_EX(zmqauth___construct_args, 0, 0, 1)
2195 	ZEND_ARG_OBJ_INFO(0, ZMQContext, ZMQContext, 0)
2196 ZEND_END_ARG_INFO();
2197 
PHP_METHOD(zmqauth,allow)2198 PHP_METHOD(zmqauth, allow)
2199 {
2200 	zend_string *address;
2201 	php_zmq_auth_object *intern;
2202 
2203 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &address) != SUCCESS) {
2204 		return;
2205 	}
2206 
2207 	intern = PHP_ZMQ_AUTH_OBJECT;
2208 	zauth_allow(intern->zauth, address->val);
2209 	RETURN_ZVAL(getThis(), 1, 0);
2210 }
2211 
2212 ZEND_BEGIN_ARG_INFO_EX(zmqauth_allow_args, 0, 0, 1)
2213 	ZEND_ARG_INFO(0, address)
2214 ZEND_END_ARG_INFO();
2215 
PHP_METHOD(zmqauth,deny)2216 PHP_METHOD(zmqauth, deny)
2217 {
2218 	zend_string *address;
2219 	php_zmq_auth_object *intern;
2220 
2221 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &address) != SUCCESS) {
2222 		return;
2223 	}
2224 
2225 	intern = PHP_ZMQ_AUTH_OBJECT;
2226 	zauth_deny(intern->zauth, address->val);
2227 	RETURN_ZVAL(getThis(), 1, 0);
2228 }
2229 
2230 ZEND_BEGIN_ARG_INFO_EX(zmqauth_deny_args, 0, 0, 1)
2231 	ZEND_ARG_INFO(0, address)
2232 ZEND_END_ARG_INFO();
2233 
PHP_METHOD(zmqauth,configure)2234 PHP_METHOD(zmqauth, configure)
2235 {
2236 	php_zmq_auth_object *intern;
2237 	zend_long type;
2238 	zend_string *domain;
2239 	zend_string *filename;
2240 
2241 	intern = PHP_ZMQ_AUTH_OBJECT
2242 
2243 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lSS", &type, &domain, &filename) != SUCCESS) {
2244 		return;
2245 	}
2246 
2247 	intern = PHP_ZMQ_AUTH_OBJECT;
2248 
2249 	switch (type) {
2250 		case PHP_ZMQ_AUTH_TYPE_PLAIN:
2251 			zauth_configure_plain(intern->zauth, domain->val, filename->val);
2252 		break;
2253 
2254 		case PHP_ZMQ_AUTH_TYPE_CURVE:
2255 			zauth_configure_curve(intern->zauth, domain->val, filename->val);
2256 		break;
2257 
2258 		// TODO (phuedx, 2014-05-16): CZMQ now supports GSSAPI (see
2259 		// zauth_configure_gssapi).
2260 
2261 		default:
2262 			zend_throw_exception_ex(php_zmq_auth_exception_sc_entry, PHP_ZMQ_INTERNAL_ERROR, "Unknown auth type. Are you using one of the ZMQAuth constants?");
2263 		break;
2264 	}
2265 
2266 	RETURN_ZVAL(getThis(), 1, 0);
2267 }
2268 
2269 ZEND_BEGIN_ARG_INFO_EX(zmqauth_configure_args, 0, 0, 3)
2270 	ZEND_ARG_INFO(0, type)
2271 	ZEND_ARG_INFO(0, domain)
2272 	ZEND_ARG_INFO(0, filename)
2273 ZEND_END_ARG_INFO();
2274 
2275 static zend_function_entry php_zmq_auth_class_methods[] = {
2276 	PHP_ME(zmqauth, __construct,	zmqauth___construct_args,	ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
2277 	PHP_ME(zmqauth, allow,			zmqauth_allow_args,			ZEND_ACC_PUBLIC)
2278 	PHP_ME(zmqauth, deny,			zmqauth_deny_args,			ZEND_ACC_PUBLIC)
2279 	PHP_ME(zmqauth, configure,		zmqauth_configure_args,		ZEND_ACC_PUBLIC)
2280 	{NULL, NULL, NULL}
2281 };
2282 
2283 /* --- END ZMQAuth --- */
2284 
2285 #endif // HAVE_CZMQ_2
2286 
2287 ZEND_BEGIN_ARG_INFO_EX(zmq_construct_args, 0, 0, 0)
2288 ZEND_END_ARG_INFO()
2289 
2290 ZEND_BEGIN_ARG_INFO_EX(zmq_clock_args, 0, 0, 0)
2291 ZEND_END_ARG_INFO()
2292 
2293 #ifdef PHP_ZMQ_HAVE_Z85
2294 
2295 ZEND_BEGIN_ARG_INFO_EX(zmq_z85encode_args, 0, 0, 1)
2296 	ZEND_ARG_INFO(0, data)
2297 ZEND_END_ARG_INFO()
2298 
2299 ZEND_BEGIN_ARG_INFO_EX(zmq_z85decode_args, 0, 0, 1)
2300 	ZEND_ARG_INFO(0, data)
2301 ZEND_END_ARG_INFO()
2302 
2303 #endif
2304 
2305 #ifdef PHP_ZMQ_HAVE_CURVE_KEYPAIR
2306 ZEND_BEGIN_ARG_INFO_EX(zmq_curvekeypair_args, 0, 0, 0)
2307 ZEND_END_ARG_INFO()
2308 #endif
2309 
2310 static zend_function_entry php_zmq_class_methods[] = {
2311 	PHP_ME(zmq, __construct,    zmq_construct_args,  ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
2312 	PHP_ME(zmq, clock,          zmq_clock_args,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
2313 #ifdef PHP_ZMQ_HAVE_Z85
2314 	PHP_ME(zmq, z85encode,      zmq_z85encode_args,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
2315 	PHP_ME(zmq, z85decode,      zmq_z85decode_args,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
2316 #endif
2317 #ifdef PHP_ZMQ_HAVE_CURVE_KEYPAIR
2318 	PHP_ME(zmq, curvekeypair,   zmq_curvekeypair_args,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
2319 #endif
2320 	{NULL, NULL, NULL}
2321 };
2322 
2323 ZEND_BEGIN_ARG_INFO_EX(zmq_context_construct_args, 0, 0, 0)
2324 	ZEND_ARG_INFO(0, io_threads)
2325 	ZEND_ARG_INFO(0, persistent)
2326 ZEND_END_ARG_INFO()
2327 
2328 ZEND_BEGIN_ARG_INFO_EX(zmq_context_acquire_args, 0, 0, 0)
2329 ZEND_END_ARG_INFO()
2330 
2331 ZEND_BEGIN_ARG_INFO_EX(zmq_context_getsocketcount_args, 0, 0, 0)
2332 ZEND_END_ARG_INFO()
2333 
2334 ZEND_BEGIN_ARG_INFO_EX(zmq_context_getsocket_args, 0, 0, 2)
2335 	ZEND_ARG_INFO(0, type)
2336 	ZEND_ARG_INFO(0, dsn)
2337 	ZEND_ARG_INFO(0, on_new_socket)
2338 ZEND_END_ARG_INFO()
2339 
2340 ZEND_BEGIN_ARG_INFO_EX(zmq_context_ispersistent_args, 0, 0, 2)
2341 ZEND_END_ARG_INFO()
2342 
2343 ZEND_BEGIN_ARG_INFO_EX(zmq_context_clone_args, 0, 0, 0)
2344 ZEND_END_ARG_INFO()
2345 
2346 #ifdef PHP_ZMQ_HAVE_CTX_OPTIONS
2347 ZEND_BEGIN_ARG_INFO_EX(zmq_context_setopt_args, 0, 0, 2)
2348 	ZEND_ARG_INFO(0, option)
2349 	ZEND_ARG_INFO(0, value)
2350 ZEND_END_ARG_INFO()
2351 
2352 ZEND_BEGIN_ARG_INFO_EX(zmq_context_getopt_args, 0, 0, 2)
2353 	ZEND_ARG_INFO(0, option)
2354 ZEND_END_ARG_INFO()
2355 #endif
2356 
2357 static zend_function_entry php_zmq_context_class_methods[] = {
2358 	PHP_ME(zmqcontext, __construct,		zmq_context_construct_args,		ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
2359 	PHP_ME(zmqcontext, acquire,			zmq_context_acquire_args,		ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
2360 	PHP_ME(zmqcontext, getsocketcount,	zmq_context_getsocketcount_args,ZEND_ACC_PUBLIC)
2361 	PHP_ME(zmqcontext, getsocket,		zmq_context_getsocket_args,		ZEND_ACC_PUBLIC)
2362 	PHP_ME(zmqcontext, ispersistent,	zmq_context_ispersistent_args,	ZEND_ACC_PUBLIC)
2363 	PHP_ME(zmqcontext, __clone,			zmq_context_clone_args,			ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
2364 #ifdef PHP_ZMQ_HAVE_CTX_OPTIONS
2365 	PHP_ME(zmqcontext, setOpt,			zmq_context_setopt_args,		ZEND_ACC_PUBLIC)
2366 	PHP_ME(zmqcontext, getOpt,			zmq_context_getopt_args,		ZEND_ACC_PUBLIC)
2367 #endif
2368 	{NULL, NULL, NULL}
2369 };
2370 
2371 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_construct_args, 0, 0, 2)
2372 	ZEND_ARG_OBJ_INFO(0, ZMQContext, ZMQContext, 0)
2373 	ZEND_ARG_INFO(0, type)
2374 	ZEND_ARG_INFO(0, persistent_id)
2375 	ZEND_ARG_INFO(0, on_new_socket)
2376 ZEND_END_ARG_INFO()
2377 
2378 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_bind_args, 0, 0, 1)
2379 	ZEND_ARG_INFO(0, dsn)
2380 	ZEND_ARG_INFO(0, force)
2381 ZEND_END_ARG_INFO()
2382 
2383 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_connect_args, 0, 0, 1)
2384 	ZEND_ARG_INFO(0, dsn)
2385 	ZEND_ARG_INFO(0, force)
2386 ZEND_END_ARG_INFO()
2387 
2388 #ifdef PHP_ZMQ_HAVE_SOCKET_MONITOR
2389 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_monitor_args, 0, 0, 1)
2390 	ZEND_ARG_INFO(0, dsn)
2391 	ZEND_ARG_INFO(0, events)
2392 ZEND_END_ARG_INFO()
2393 
2394 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_recvevent_args, 0, 0, 0)
2395 	ZEND_ARG_INFO(0, flags)
2396 ZEND_END_ARG_INFO()
2397 #endif
2398 
2399 #ifdef PHP_ZMQ_HAVE_UNBIND
2400 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_unbind_args, 0, 0, 1)
2401 	ZEND_ARG_INFO(0, dsn)
2402 ZEND_END_ARG_INFO()
2403 #endif
2404 
2405 #ifdef PHP_ZMQ_HAVE_DISCONNECT
2406 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_disconnect_args, 0, 0, 1)
2407 	ZEND_ARG_INFO(0, dsn)
2408 ZEND_END_ARG_INFO()
2409 #endif
2410 
2411 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_setsockopt_args, 0, 0, 2)
2412 	ZEND_ARG_INFO(0, key)
2413 	ZEND_ARG_INFO(0, value)
2414 ZEND_END_ARG_INFO()
2415 
2416 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_getendpoints_args, 0, 0, 0)
2417 ZEND_END_ARG_INFO()
2418 
2419 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_getsockettype_args, 0, 0, 0)
2420 ZEND_END_ARG_INFO()
2421 
2422 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_send_args, 0, 0, 1)
2423 	ZEND_ARG_INFO(0, message)
2424 	ZEND_ARG_INFO(0, mode)
2425 ZEND_END_ARG_INFO()
2426 
2427 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_recv_args, 0, 0, 0)
2428 	ZEND_ARG_INFO(0, mode)
2429 ZEND_END_ARG_INFO()
2430 
2431 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_getpersistentid_args, 0, 0, 0)
2432 ZEND_END_ARG_INFO()
2433 
2434 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_getsockopt_args, 0, 0, 1)
2435 	ZEND_ARG_INFO(0, key)
2436 ZEND_END_ARG_INFO()
2437 
2438 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_ispersistent_args, 0, 0, 0)
2439 ZEND_END_ARG_INFO()
2440 
2441 ZEND_BEGIN_ARG_INFO_EX(zmq_socket_clone_args, 0, 0, 0)
2442 ZEND_END_ARG_INFO()
2443 
2444 static zend_function_entry php_zmq_socket_class_methods[] = {
2445 	PHP_ME(zmqsocket, __construct,			zmq_socket_construct_args,			ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
2446 	PHP_ME(zmqsocket, send,					zmq_socket_send_args,				ZEND_ACC_PUBLIC)
2447 	PHP_ME(zmqsocket, recv,					zmq_socket_recv_args,				ZEND_ACC_PUBLIC)
2448 	PHP_ME(zmqsocket, sendmulti,			zmq_socket_send_args,				ZEND_ACC_PUBLIC)
2449 	PHP_ME(zmqsocket, recvmulti,			zmq_socket_recv_args,				ZEND_ACC_PUBLIC)
2450 	PHP_ME(zmqsocket, bind,					zmq_socket_bind_args,				ZEND_ACC_PUBLIC)
2451 	PHP_ME(zmqsocket, connect,				zmq_socket_connect_args,			ZEND_ACC_PUBLIC)
2452 #ifdef PHP_ZMQ_HAVE_SOCKET_MONITOR
2453 	PHP_ME(zmqsocket, monitor,				zmq_socket_monitor_args,			ZEND_ACC_PUBLIC)
2454 	PHP_ME(zmqsocket, recvevent,			zmq_socket_recvevent_args,			ZEND_ACC_PUBLIC)
2455 #endif
2456 #ifdef PHP_ZMQ_HAVE_UNBIND
2457 	PHP_ME(zmqsocket, unbind,				zmq_socket_unbind_args,				ZEND_ACC_PUBLIC)
2458 #endif
2459 #ifdef PHP_ZMQ_HAVE_DISCONNECT
2460 	PHP_ME(zmqsocket, disconnect,			zmq_socket_disconnect_args,			ZEND_ACC_PUBLIC)
2461 #endif
2462 	PHP_ME(zmqsocket, setsockopt,			zmq_socket_setsockopt_args,			ZEND_ACC_PUBLIC)
2463 	PHP_ME(zmqsocket, getendpoints,			zmq_socket_getendpoints_args,		ZEND_ACC_PUBLIC)
2464 	PHP_ME(zmqsocket, getsockettype,		zmq_socket_getsockettype_args,		ZEND_ACC_PUBLIC)
2465 	PHP_ME(zmqsocket, ispersistent,			zmq_socket_ispersistent_args,		ZEND_ACC_PUBLIC)
2466 	PHP_ME(zmqsocket, getpersistentid,		zmq_socket_getpersistentid_args,	ZEND_ACC_PUBLIC)
2467 	PHP_ME(zmqsocket, getsockopt,			zmq_socket_getsockopt_args,			ZEND_ACC_PUBLIC)
2468 	PHP_ME(zmqsocket, __clone,				zmq_socket_clone_args,				ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
2469 	PHP_MALIAS(zmqsocket,	sendmsg, send,	zmq_socket_send_args, 				ZEND_ACC_PUBLIC)
2470 	PHP_MALIAS(zmqsocket,	recvmsg, recv, 	zmq_socket_recv_args, 				ZEND_ACC_PUBLIC)
2471 	{NULL, NULL, NULL}
2472 };
2473 
2474 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_add_args, 0, 0, 2)
2475 	ZEND_ARG_INFO(0, entry)
2476 	ZEND_ARG_INFO(0, type)
2477 ZEND_END_ARG_INFO()
2478 
2479 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_poll_args, 0, 0, 2)
2480 	ZEND_ARG_INFO(1, readable)
2481 	ZEND_ARG_INFO(1, writable)
2482 	ZEND_ARG_INFO(0, timeout)
2483 ZEND_END_ARG_INFO()
2484 
2485 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_getlasterrors_args, 0, 0, 0)
2486 ZEND_END_ARG_INFO()
2487 
2488 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_remove_args, 0, 0, 2)
2489 	ZEND_ARG_INFO(0, remove)
2490 ZEND_END_ARG_INFO()
2491 
2492 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_count_args, 0, 0, 0)
2493 ZEND_END_ARG_INFO()
2494 
2495 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_clear_args, 0, 0, 0)
2496 ZEND_END_ARG_INFO()
2497 
2498 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_items_args, 0, 0, 0)
2499 ZEND_END_ARG_INFO()
2500 
2501 ZEND_BEGIN_ARG_INFO_EX(zmq_poll_clone_args, 0, 0, 0)
2502 ZEND_END_ARG_INFO()
2503 
2504 static zend_function_entry php_zmq_poll_class_methods[] = {
2505 	PHP_ME(zmqpoll, add,			zmq_poll_add_args,				ZEND_ACC_PUBLIC)
2506 	PHP_ME(zmqpoll, poll,			zmq_poll_poll_args,				ZEND_ACC_PUBLIC)
2507 	PHP_ME(zmqpoll, getlasterrors,	zmq_poll_getlasterrors_args,	ZEND_ACC_PUBLIC)
2508 	PHP_ME(zmqpoll, remove,			zmq_poll_remove_args,			ZEND_ACC_PUBLIC)
2509 	PHP_ME(zmqpoll, count,			zmq_poll_count_args,			ZEND_ACC_PUBLIC)
2510 	PHP_ME(zmqpoll, clear,			zmq_poll_clear_args,			ZEND_ACC_PUBLIC)
2511 	PHP_ME(zmqpoll, items,			zmq_poll_items_args,			ZEND_ACC_PUBLIC)
2512 	PHP_ME(zmqpoll, __clone,		zmq_poll_clone_args,			ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
2513 	{NULL, NULL, NULL}
2514 };
2515 
2516 ZEND_BEGIN_ARG_INFO_EX(zmq_device_construct_args, 0, 0, 2)
2517 	ZEND_ARG_OBJ_INFO(0, frontend, ZMQSocket, 0)
2518 	ZEND_ARG_OBJ_INFO(0, backend, ZMQSocket, 0)
2519 	ZEND_ARG_OBJ_INFO(0, capture, ZMQSocket, 0)
2520 ZEND_END_ARG_INFO()
2521 
2522 ZEND_BEGIN_ARG_INFO_EX(zmq_device_run_args, 0, 0, 0)
2523 ZEND_END_ARG_INFO()
2524 
2525 ZEND_BEGIN_ARG_INFO_EX(zmq_device_setidlecallback_args, 0, 0, 2)
2526 	ZEND_ARG_INFO(0, idle_callback)
2527 	ZEND_ARG_INFO(0, timeout)
2528 	ZEND_ARG_INFO(0, user_data)
2529 ZEND_END_ARG_INFO()
2530 
2531 ZEND_BEGIN_ARG_INFO_EX(zmq_device_settimercallback_args, 0, 0, 2)
2532 	ZEND_ARG_INFO(0, idle_callback)
2533 	ZEND_ARG_INFO(0, timeout)
2534 	ZEND_ARG_INFO(0, user_data)
2535 ZEND_END_ARG_INFO()
2536 
2537 ZEND_BEGIN_ARG_INFO_EX(zmq_device_setidletimeout_args, 0, 0, 1)
2538 	ZEND_ARG_INFO(0, timeout)
2539 ZEND_END_ARG_INFO()
2540 
2541 ZEND_BEGIN_ARG_INFO_EX(zmq_device_settimertimeout_args, 0, 0, 1)
2542 	ZEND_ARG_INFO(0, timeout)
2543 ZEND_END_ARG_INFO()
2544 
2545 ZEND_BEGIN_ARG_INFO_EX(zmq_device_getidletimeout_args, 0, 0, 0)
2546 ZEND_END_ARG_INFO()
2547 
2548 ZEND_BEGIN_ARG_INFO_EX(zmq_device_gettimertimeout_args, 0, 0, 0)
2549 ZEND_END_ARG_INFO()
2550 
2551 ZEND_BEGIN_ARG_INFO_EX(zmq_device_clone_args, 0, 0, 0)
2552 ZEND_END_ARG_INFO()
2553 
2554 static zend_function_entry php_zmq_device_class_methods[] = {
2555 	PHP_ME(zmqdevice, __construct,      zmq_device_construct_args,         ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
2556 	PHP_ME(zmqdevice, run,              zmq_device_run_args,               ZEND_ACC_PUBLIC)
2557 	PHP_ME(zmqdevice, setidlecallback,  zmq_device_setidlecallback_args,   ZEND_ACC_PUBLIC)
2558 	PHP_ME(zmqdevice, setidletimeout,   zmq_device_setidletimeout_args,    ZEND_ACC_PUBLIC)
2559 	PHP_ME(zmqdevice, getidletimeout,   zmq_device_getidletimeout_args,    ZEND_ACC_PUBLIC)
2560 	PHP_ME(zmqdevice, settimercallback, zmq_device_settimercallback_args,  ZEND_ACC_PUBLIC)
2561 	PHP_ME(zmqdevice, settimertimeout,  zmq_device_settimertimeout_args,   ZEND_ACC_PUBLIC)
2562 	PHP_ME(zmqdevice, gettimertimeout,  zmq_device_gettimertimeout_args,   ZEND_ACC_PUBLIC)
2563 	PHP_ME(zmqdevice, __clone,          zmq_device_clone_args,             ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
2564 	{NULL, NULL, NULL}
2565 };
2566 
2567 
2568 zend_function_entry zmq_functions[] = {
2569 	{NULL, NULL, NULL}
2570 };
2571 
2572 static
php_zmq_context_object_free_storage(zend_object * object)2573 void php_zmq_context_object_free_storage(zend_object *object)
2574 {
2575 	php_zmq_context_object *intern = php_zmq_context_fetch_object(object);
2576 
2577 	if (!intern) {
2578 		return;
2579 	}
2580 
2581 	if (intern->context) {
2582 		if (!intern->context->is_persistent) {
2583 			php_zmq_context_destroy(intern->context);
2584 		}
2585 	}
2586 	zend_object_std_dtor(&intern->zo);
2587 }
2588 
2589 static
php_zmq_socket_object_free_storage(zend_object * object)2590 void php_zmq_socket_object_free_storage(zend_object *object)
2591 {
2592 	php_zmq_socket_object *intern = php_zmq_socket_fetch_object(object);
2593 
2594 	if (!intern) {
2595 		return;
2596 	}
2597 
2598 	if (intern->socket) {
2599 		if (intern->socket->is_persistent && intern->persistent_id) {
2600 			efree(intern->persistent_id);
2601 		}
2602 		if (!intern->socket->is_persistent) {
2603 			php_zmq_socket_destroy(intern->socket);
2604 		}
2605 	}
2606 
2607 	if (!Z_ISUNDEF(intern->context_obj)) {
2608 		zval_ptr_dtor(&intern->context_obj);
2609 	}
2610 	zend_object_std_dtor(&intern->zo);
2611 }
2612 
2613 static
php_zmq_poll_object_free_storage(zend_object * object)2614 void php_zmq_poll_object_free_storage(zend_object *object)
2615 {
2616 	php_zmq_poll_object *intern = php_zmq_poll_fetch_object(object);
2617 
2618 	if (!intern) {
2619 		return;
2620 	}
2621 	php_zmq_pollset_destroy(&intern->set);
2622 	zend_object_std_dtor(&intern->zo);
2623 }
2624 
php_zmq_device_object_free_storage(zend_object * object)2625 static void php_zmq_device_object_free_storage(zend_object *object)
2626 {
2627 	php_zmq_device_object *intern = php_zmq_device_fetch_object(object);
2628 
2629 	if (!intern) {
2630 		return;
2631 	}
2632 
2633 	s_clear_device_callback (&intern->idle_cb);
2634 	s_clear_device_callback (&intern->timer_cb);
2635 
2636 	if (!Z_ISUNDEF(intern->front)) {
2637 		zval_ptr_dtor(&intern->front);
2638 	}
2639 
2640 	if (!Z_ISUNDEF(intern->back)) {
2641 		zval_ptr_dtor(&intern->back);
2642 	}
2643 
2644 	if (!Z_ISUNDEF(intern->capture)) {
2645 		zval_ptr_dtor(&intern->capture);
2646 	}
2647 	zend_object_std_dtor(&intern->zo);
2648 }
2649 
2650 static
php_zmq_context_object_new_ex(zend_class_entry * class_type,php_zmq_context_object ** ptr)2651 zend_object *php_zmq_context_object_new_ex(zend_class_entry *class_type, php_zmq_context_object **ptr)
2652 {
2653 	php_zmq_context_object *intern = ecalloc(1, sizeof(php_zmq_context_object) + zend_object_properties_size(class_type));
2654 
2655 	/* Context is initialized in the constructor */
2656 	intern->context = NULL;
2657 
2658 	if (ptr) {
2659 		*ptr = intern;
2660 	}
2661 
2662 	zend_object_std_init(&intern->zo, class_type);
2663 	object_properties_init(&intern->zo, class_type);
2664 
2665 	intern->zo.handlers = &zmq_context_object_handlers;
2666 	return &intern->zo;
2667 }
2668 
2669 static
php_zmq_socket_object_new_ex(zend_class_entry * class_type,php_zmq_socket_object ** ptr)2670 zend_object *php_zmq_socket_object_new_ex(zend_class_entry *class_type, php_zmq_socket_object **ptr)
2671 {
2672 	php_zmq_socket_object *intern;
2673 
2674 	/* Allocate memory for it */
2675 	intern = ecalloc(1, sizeof(php_zmq_socket_object) + zend_object_properties_size(class_type));
2676 
2677 	intern->socket        = NULL;
2678 	intern->persistent_id = NULL;
2679 	ZVAL_UNDEF(&intern->context_obj);
2680 
2681 	if (ptr) {
2682 		*ptr = intern;
2683 	}
2684 
2685 	zend_object_std_init(&intern->zo, class_type);
2686 	object_properties_init(&intern->zo, class_type);
2687 
2688 	intern->zo.handlers = &zmq_socket_object_handlers;
2689 	return &intern->zo;
2690 }
2691 
2692 static
php_zmq_poll_object_new_ex(zend_class_entry * class_type,php_zmq_poll_object ** ptr)2693 zend_object *php_zmq_poll_object_new_ex(zend_class_entry *class_type, php_zmq_poll_object **ptr)
2694 {
2695 	php_zmq_poll_object *intern = ecalloc(1, sizeof(php_zmq_poll_object) + zend_object_properties_size(class_type));
2696 	intern->set = php_zmq_pollset_init();
2697 
2698 	if (ptr) {
2699 		*ptr = intern;
2700 	}
2701 
2702 	zend_object_std_init(&intern->zo, class_type);
2703 	object_properties_init(&intern->zo, class_type);
2704 
2705 	intern->zo.handlers = &zmq_poll_object_handlers;
2706 	return &intern->zo;
2707 }
2708 
2709 static
php_zmq_device_object_new_ex(zend_class_entry * class_type,php_zmq_device_object ** ptr)2710 zend_object *php_zmq_device_object_new_ex(zend_class_entry *class_type, php_zmq_device_object **ptr)
2711 {
2712 	php_zmq_device_object *intern = ecalloc(1, sizeof(php_zmq_device_object) + zend_object_properties_size(class_type));
2713 
2714 	memset (&intern->idle_cb, 0, sizeof (php_zmq_device_cb_t));
2715 	memset (&intern->timer_cb, 0, sizeof (php_zmq_device_cb_t));
2716 
2717 	ZVAL_UNDEF(&intern->front);
2718 	ZVAL_UNDEF(&intern->back);
2719 	ZVAL_UNDEF(&intern->capture);
2720 
2721 	if (ptr) {
2722 		*ptr = intern;
2723 	}
2724 
2725 	zend_object_std_init(&intern->zo, class_type);
2726 	object_properties_init(&intern->zo, class_type);
2727 
2728 	intern->zo.handlers = &zmq_device_object_handlers;
2729 	return &intern->zo;
2730 }
2731 
2732 static
php_zmq_context_object_new(zend_class_entry * class_type)2733 zend_object *php_zmq_context_object_new(zend_class_entry *class_type)
2734 {
2735 	return php_zmq_context_object_new_ex(class_type, NULL);
2736 }
2737 
2738 static
php_zmq_socket_object_new(zend_class_entry * class_type)2739 zend_object *php_zmq_socket_object_new(zend_class_entry *class_type)
2740 {
2741 	return php_zmq_socket_object_new_ex(class_type, NULL);
2742 }
2743 
2744 static
php_zmq_poll_object_new(zend_class_entry * class_type)2745 zend_object *php_zmq_poll_object_new(zend_class_entry *class_type)
2746 {
2747 	return php_zmq_poll_object_new_ex(class_type, NULL);
2748 }
2749 
2750 static
php_zmq_device_object_new(zend_class_entry * class_type)2751 zend_object *php_zmq_device_object_new(zend_class_entry *class_type)
2752 {
2753 	return php_zmq_device_object_new_ex(class_type, NULL);
2754 }
2755 
ZEND_RSRC_DTOR_FUNC(php_zmq_context_dtor)2756 ZEND_RSRC_DTOR_FUNC(php_zmq_context_dtor)
2757 {
2758 	if (res->ptr) {
2759 		php_zmq_context *ctx = (php_zmq_context *)res->ptr;
2760 		php_zmq_context_destroy(ctx);
2761 		res->ptr = NULL;
2762 	}
2763 }
2764 
ZEND_RSRC_DTOR_FUNC(php_zmq_socket_dtor)2765 ZEND_RSRC_DTOR_FUNC(php_zmq_socket_dtor)
2766 {
2767 	if (res->ptr) {
2768 		php_zmq_socket *zms = (php_zmq_socket *)res->ptr;
2769 		php_zmq_socket_destroy(zms);
2770 		res->ptr = NULL;
2771 	}
2772 }
2773 
2774 static
php_zmq_init_globals(zend_php_zmq_globals * zmq_globals)2775 void php_zmq_init_globals (zend_php_zmq_globals *zmq_globals)
2776 {
2777 	zmq_globals->clock_ctx = NULL;
2778 }
2779 
PHP_MINIT_FUNCTION(zmq)2780 PHP_MINIT_FUNCTION(zmq)
2781 {
2782 	char *version;
2783 	zend_class_entry ce, ce_context, ce_socket, ce_poll, ce_device;
2784 	zend_class_entry ce_exception, ce_context_exception, ce_socket_exception, ce_poll_exception, ce_device_exception;
2785 
2786 #ifdef HAVE_CZMQ_2
2787 	zend_class_entry ce_cert, ce_cert_exception, ce_auth, ce_auth_exception;
2788 #endif
2789 
2790 	le_zmq_context = zend_register_list_destructors_ex(NULL, php_zmq_context_dtor, "ZMQ persistent context", module_number);
2791 	le_zmq_socket  = zend_register_list_destructors_ex(NULL, php_zmq_socket_dtor, "ZMQ persistent socket", module_number);
2792 
2793 	memcpy(&zmq_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2794 	memcpy(&zmq_context_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2795 	memcpy(&zmq_socket_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2796 	memcpy(&zmq_poll_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2797 	memcpy(&zmq_device_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2798 
2799 #ifdef HAVE_CZMQ_2
2800 	memcpy(&zmq_cert_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2801 	memcpy(&zmq_auth_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2802 #endif
2803 
2804 	INIT_CLASS_ENTRY(ce, "ZMQ", php_zmq_class_methods);
2805 	ce.create_object = NULL;
2806 	zmq_object_handlers.clone_obj = NULL;
2807 	php_zmq_sc_entry = zend_register_internal_class(&ce);
2808 
2809 	INIT_CLASS_ENTRY(ce_context, "ZMQContext", php_zmq_context_class_methods);
2810 	ce_context.create_object = php_zmq_context_object_new;
2811 
2812 	zmq_context_object_handlers.offset    = XtOffsetOf(php_zmq_context_object, zo);
2813 	zmq_context_object_handlers.clone_obj = NULL;
2814 	zmq_context_object_handlers.free_obj  = php_zmq_context_object_free_storage;
2815 
2816 	php_zmq_context_sc_entry = zend_register_internal_class(&ce_context);
2817 
2818 	INIT_CLASS_ENTRY(ce_socket, "ZMQSocket", php_zmq_socket_class_methods);
2819 	ce_socket.create_object = php_zmq_socket_object_new;
2820 
2821 	zmq_socket_object_handlers.offset    = XtOffsetOf(php_zmq_socket_object, zo);
2822 	zmq_socket_object_handlers.clone_obj = NULL;
2823 	zmq_socket_object_handlers.free_obj  = php_zmq_socket_object_free_storage;
2824 
2825 	php_zmq_socket_sc_entry = zend_register_internal_class(&ce_socket);
2826 
2827 	INIT_CLASS_ENTRY(ce_poll, "ZMQPoll", php_zmq_poll_class_methods);
2828 	ce_poll.create_object = php_zmq_poll_object_new;
2829 
2830 	zmq_poll_object_handlers.offset    = XtOffsetOf(php_zmq_poll_object, zo);
2831 	zmq_poll_object_handlers.clone_obj = NULL;
2832 	zmq_poll_object_handlers.free_obj  = php_zmq_poll_object_free_storage;
2833 
2834 	php_zmq_poll_sc_entry = zend_register_internal_class(&ce_poll);
2835 
2836 	INIT_CLASS_ENTRY(ce_device, "ZMQDevice", php_zmq_device_class_methods);
2837 	ce_device.create_object = php_zmq_device_object_new;
2838 
2839 	zmq_device_object_handlers.offset    = XtOffsetOf(php_zmq_device_object, zo);
2840 	zmq_device_object_handlers.clone_obj = NULL;
2841 	zmq_device_object_handlers.free_obj  = php_zmq_device_object_free_storage;
2842 
2843 	php_zmq_device_sc_entry = zend_register_internal_class(&ce_device);
2844 
2845 #ifdef HAVE_CZMQ_2
2846 	INIT_CLASS_ENTRY(ce_cert, "ZMQCert", php_zmq_cert_class_methods);
2847 	ce_cert.create_object = php_zmq_cert_new;
2848 
2849 	zmq_cert_object_handlers.offset    = XtOffsetOf(php_zmq_cert_object, zo);
2850 	zmq_cert_object_handlers.clone_obj = php_zmq_cert_clone;
2851 	zmq_cert_object_handlers.free_obj  = php_zmq_cert_object_free_storage;
2852 
2853 	php_zmq_cert_sc_entry = zend_register_internal_class(&ce_cert);
2854 
2855 	INIT_CLASS_ENTRY(ce_auth, "ZMQAuth", php_zmq_auth_class_methods);
2856 	ce_auth.create_object = php_zmq_auth_new;
2857 
2858 	zmq_auth_object_handlers.offset    = XtOffsetOf(php_zmq_auth_object, zo);
2859 	zmq_auth_object_handlers.clone_obj = NULL;
2860 	zmq_auth_object_handlers.free_obj  = php_zmq_auth_object_free_storage;
2861 
2862 	php_zmq_auth_sc_entry = zend_register_internal_class(&ce_auth);
2863 #endif
2864 
2865 	INIT_CLASS_ENTRY(ce_exception, "ZMQException", NULL);
2866 	php_zmq_exception_sc_entry = zend_register_internal_class_ex(&ce_exception, zend_exception_get_default());
2867 	php_zmq_exception_sc_entry->ce_flags &= ~ZEND_ACC_FINAL;
2868 
2869 	INIT_CLASS_ENTRY(ce_context_exception, "ZMQContextException", NULL);
2870 	php_zmq_context_exception_sc_entry = zend_register_internal_class_ex(&ce_context_exception, php_zmq_exception_sc_entry);
2871 	php_zmq_context_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL;
2872 
2873 	INIT_CLASS_ENTRY(ce_socket_exception, "ZMQSocketException", NULL);
2874 	php_zmq_socket_exception_sc_entry = zend_register_internal_class_ex(&ce_socket_exception, php_zmq_exception_sc_entry);
2875 	php_zmq_socket_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL;
2876 
2877 	INIT_CLASS_ENTRY(ce_poll_exception, "ZMQPollException", NULL);
2878 	php_zmq_poll_exception_sc_entry = zend_register_internal_class_ex(&ce_poll_exception, php_zmq_exception_sc_entry);
2879 	php_zmq_poll_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL;
2880 
2881 	INIT_CLASS_ENTRY(ce_device_exception, "ZMQDeviceException", NULL);
2882 	php_zmq_device_exception_sc_entry = zend_register_internal_class_ex(&ce_device_exception, php_zmq_exception_sc_entry);
2883 	php_zmq_device_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL;
2884 
2885 #ifdef HAVE_CZMQ_2
2886 	INIT_CLASS_ENTRY(ce_cert_exception, "ZMQCertException", NULL);
2887 	php_zmq_cert_exception_sc_entry = zend_register_internal_class_ex(&ce_cert_exception, php_zmq_exception_sc_entry);
2888 	php_zmq_cert_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL;
2889 
2890 	INIT_CLASS_ENTRY(ce_auth_exception, "ZMQAuthException", NULL);
2891 	php_zmq_auth_exception_sc_entry = zend_register_internal_class_ex(&ce_auth_exception, php_zmq_exception_sc_entry);
2892 	php_zmq_auth_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL;
2893 #endif
2894 
2895 	ZEND_INIT_MODULE_GLOBALS(php_zmq, php_zmq_init_globals, NULL);
2896 
2897 	ZMQ_G(clock_ctx) = php_zmq_clock_init ();
2898 
2899 	if (!ZMQ_G(clock_ctx)) {
2900 		php_error_docref(NULL, E_WARNING, "Failed to initialise clock");
2901 		return FAILURE;
2902 	}
2903 
2904 #define PHP_ZMQ_REGISTER_CONST_LONG(const_name, value) \
2905 	zend_declare_class_constant_long(php_zmq_sc_entry, const_name, sizeof(const_name)-1, (long)value);
2906 #define PHP_ZMQ_REGISTER_CONST_STRING(const_name, value) \
2907 	zend_declare_class_constant_string (php_zmq_sc_entry, const_name, sizeof(const_name)-1, value);
2908 #define PHP_ZMQ_REGISTER_CONST_BOOL(const_name, value) \
2909 	zend_declare_class_constant_bool (php_zmq_sc_entry, const_name, sizeof(const_name)-1, value);
2910 
2911 	/* Socket constants */
2912 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_PAIR", ZMQ_PAIR);
2913 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_PUB", ZMQ_PUB);
2914 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_SUB", ZMQ_SUB);
2915 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_REQ", ZMQ_REQ);
2916 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_REP", ZMQ_REP);
2917 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_XREQ", ZMQ_XREQ);
2918 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_XREP", ZMQ_XREP);
2919 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_PUSH", ZMQ_PUSH);
2920 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_PULL", ZMQ_PULL);
2921 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_DEALER", ZMQ_DEALER);
2922 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_ROUTER", ZMQ_ROUTER);
2923 #ifdef ZMQ_XSUB
2924 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_XSUB", ZMQ_XSUB);
2925 #endif
2926 #ifdef ZMQ_XPUB
2927 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_XPUB", ZMQ_XPUB);
2928 #endif
2929 #ifdef ZMQ_STREAM
2930 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_STREAM", ZMQ_STREAM);
2931 #endif
2932 
2933 	/* 2.0? */
2934 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_UPSTREAM", ZMQ_PULL);
2935 	PHP_ZMQ_REGISTER_CONST_LONG("SOCKET_DOWNSTREAM", ZMQ_PUSH);
2936 
2937 #ifdef ZMQ_SNDLABEL
2938 	PHP_ZMQ_REGISTER_CONST_LONG("MODE_SNDLABEL", ZMQ_SNDLABEL);
2939 #endif
2940 
2941 	PHP_ZMQ_REGISTER_CONST_LONG("POLL_IN", ZMQ_POLLIN);
2942 	PHP_ZMQ_REGISTER_CONST_LONG("POLL_OUT", ZMQ_POLLOUT);
2943 
2944 	PHP_ZMQ_REGISTER_CONST_LONG("MODE_SNDMORE", ZMQ_SNDMORE);
2945 	PHP_ZMQ_REGISTER_CONST_LONG("MODE_NOBLOCK", ZMQ_DONTWAIT);
2946 	PHP_ZMQ_REGISTER_CONST_LONG("MODE_DONTWAIT", ZMQ_DONTWAIT);
2947 
2948 	PHP_ZMQ_REGISTER_CONST_LONG("ERR_INTERNAL", PHP_ZMQ_INTERNAL_ERROR);
2949 	PHP_ZMQ_REGISTER_CONST_LONG("ERR_EAGAIN", EAGAIN);
2950 	PHP_ZMQ_REGISTER_CONST_LONG("ERR_ENOTSUP", ENOTSUP);
2951 	PHP_ZMQ_REGISTER_CONST_LONG("ERR_EFSM", EFSM);
2952 	PHP_ZMQ_REGISTER_CONST_LONG("ERR_ETERM", ETERM);
2953 
2954 	version = php_zmq_get_libzmq_version();
2955 
2956 	PHP_ZMQ_REGISTER_CONST_STRING("LIBZMQ_VER",     version);
2957 	PHP_ZMQ_REGISTER_CONST_STRING("LIBZMQ_VERSION", version);
2958 	PHP_ZMQ_REGISTER_CONST_LONG("LIBZMQ_VERSION_ID", php_zmq_get_libzmq_version_id());
2959 
2960 	PHP_ZMQ_REGISTER_CONST_LONG("LIBZMQ_VERSION_MAJOR", ZMQ_VERSION_MAJOR);
2961 	PHP_ZMQ_REGISTER_CONST_LONG("LIBZMQ_VERSION_MINOR", ZMQ_VERSION_MINOR);
2962 	PHP_ZMQ_REGISTER_CONST_LONG("LIBZMQ_VERSION_PATCH", ZMQ_VERSION_PATCH);
2963 
2964 	efree(version);
2965 
2966 	php_zmq_register_sockopt_constants (php_zmq_sc_entry);
2967 
2968 #ifdef ZMQ_MAX_SOCKETS
2969 	PHP_ZMQ_REGISTER_CONST_LONG("CTXOPT_MAX_SOCKETS", ZMQ_MAX_SOCKETS);
2970 #endif
2971 
2972 #ifdef ZMQ_MAX_SOCKETS_DFLT
2973 	PHP_ZMQ_REGISTER_CONST_LONG("CTXOPT_MAX_SOCKETS_DEFAULT", ZMQ_MAX_SOCKETS_DFLT);
2974 #endif
2975 
2976 #ifdef HAVE_CZMQ_2
2977 	PHP_ZMQ_REGISTER_CONST_STRING("CURVE_ALLOW_ANY", CURVE_ALLOW_ANY);
2978 
2979 	zend_declare_class_constant_long(php_zmq_auth_sc_entry, "AUTH_TYPE_PLAIN", 15, (long)PHP_ZMQ_AUTH_TYPE_PLAIN);
2980 	zend_declare_class_constant_long(php_zmq_auth_sc_entry, "AUTH_TYPE_CURVE", 15, (long)PHP_ZMQ_AUTH_TYPE_CURVE);
2981 #endif
2982 
2983 #ifdef PHP_ZMQ_HAVE_SOCKET_MONITOR
2984 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_CONNECTED",       ZMQ_EVENT_CONNECTED);
2985 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_CONNECT_DELAYED", ZMQ_EVENT_CONNECT_DELAYED);
2986 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_CONNECT_RETRIED", ZMQ_EVENT_CONNECT_RETRIED);
2987 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_LISTENING",       ZMQ_EVENT_LISTENING);
2988 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_BIND_FAILED",     ZMQ_EVENT_BIND_FAILED);
2989 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_ACCEPTED",        ZMQ_EVENT_ACCEPTED);
2990 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_ACCEPT_FAILED",   ZMQ_EVENT_ACCEPT_FAILED);
2991 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_CLOSED",          ZMQ_EVENT_CLOSED);
2992 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_CLOSE_FAILED",    ZMQ_EVENT_CLOSE_FAILED);
2993 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_DISCONNECTED",    ZMQ_EVENT_DISCONNECTED);
2994 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_MONITOR_STOPPED", ZMQ_EVENT_MONITOR_STOPPED);
2995 	PHP_ZMQ_REGISTER_CONST_LONG("EVENT_ALL",             ZMQ_EVENT_ALL);
2996 #endif
2997 
2998 #undef PHP_ZMQ_REGISTER_CONST_LONG
2999 #undef PHP_ZMQ_REGISTER_CONST_STRING
3000 
3001 	if (!php_zmq_shared_ctx_init()) {
3002 		return FAILURE;
3003 	}
3004 	return SUCCESS;
3005 }
3006 
PHP_MSHUTDOWN_FUNCTION(zmq)3007 PHP_MSHUTDOWN_FUNCTION(zmq)
3008 {
3009 	php_zmq_shared_ctx_destroy();
3010 	php_zmq_clock_destroy (&ZMQ_G (clock_ctx));
3011 	return SUCCESS;
3012 }
3013 
PHP_MINFO_FUNCTION(zmq)3014 PHP_MINFO_FUNCTION(zmq)
3015 {
3016 	char *version = php_zmq_get_libzmq_version();
3017 
3018 	php_info_print_table_start();
3019 
3020 		php_info_print_table_header(2, "ZMQ extension", "enabled");
3021 		php_info_print_table_row(2, "ZMQ extension version", PHP_ZMQ_VERSION);
3022 		php_info_print_table_row(2, "libzmq version", version);
3023 
3024 	php_info_print_table_end();
3025 	DISPLAY_INI_ENTRIES();
3026 
3027 	efree(version);
3028 }
3029 
3030 zend_module_entry zmq_module_entry =
3031 {
3032 	STANDARD_MODULE_HEADER,
3033 	PHP_ZMQ_EXTNAME,
3034 	zmq_functions,			/* Functions */
3035 	PHP_MINIT(zmq),			/* MINIT */
3036 	PHP_MSHUTDOWN(zmq),		/* MSHUTDOWN */
3037 	NULL,					/* RINIT */
3038 	NULL,					/* RSHUTDOWN */
3039 	PHP_MINFO(zmq),			/* MINFO */
3040 	PHP_ZMQ_VERSION,		/* version */
3041 	STANDARD_MODULE_PROPERTIES
3042 };
3043 
3044 #ifdef COMPILE_DL_ZMQ
3045 ZEND_GET_MODULE(zmq)
3046 #endif /* COMPILE_DL_ZMQ */
3047