diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1f1bf8f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,31 @@
+*~
+*.lo
+*.la
+
+build/
+.libs/
+autom4te.cache/
+modules/
+
+tests/*.diff
+tests/*.exp
+tests/*.log
+tests/*.out
+tests/*.php
+tests/*.sh
+
+Makefile*
+configure*
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+install-sh
+aclocal.m4
+acinclude.m4
+.deps
+
+config*
+!config.m4
+!config.w32
+
diff --git a/.travis.yml b/.travis.yml
index b1abe0d..2e7693d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,22 +1,17 @@
language: php
+
php:
- - 5.6
- 5.5
- - 5.4
- - 5.3
+
env:
- - ZEROMQ_VERSION=v2.2.0
- - ZEROMQ_VERSION=v3.1.0
- - ZEROMQ_VERSION=v3.2.0
- - ZEROMQ_VERSION=v3.2.1
- - ZEROMQ_VERSION=v3.2.2
- - ZEROMQ_VERSION=v3.2.3
- - ZEROMQ_VERSION=v3.2.4
- - ZEROMQ_VERSION=v4.0.0
- ZEROMQ_VERSION=v4.0.1
-
- ZEROMQ_VERSION=v4.0.1 WITH_CZMQ=true
+ - ZEROMQ_VERSION=v4.0.1 WITH_CZMQ=true WITH_ZYRE=true
+
before_install:
- sudo apt-get update
+ - sudo apt-get remove libzmq3-dev libzmq3
- sudo apt-get install uuid-dev
-script: travis/script.sh $ZEROMQ_VERSION $WITH_CZMQ
+
+script: travis/script.sh $ZEROMQ_VERSION $WITH_CZMQ $WITH_ZYRE
+
diff --git a/api.php b/api.php
index 1c4b474..72ed89d 100644
--- a/api.php
+++ b/api.php
@@ -426,6 +426,91 @@ public function count() {}
public function clear() {}
}
+class ZMQZyre {
+ const LIBZYRE_VERSION = '1.1.0';
+ /**
+ * Construct a ZMQZyre
+ *
+ * @param ZMQContext $context
+ * @return void
+ */
+ public function __construct(ZMQContext $ZMQContext) {}
+ /**
+ * Set node header; these are provided to other nodes during discovery and come in each ENTER message.
+ *
+ * @param string $name
+ * @param string $value
+ * @return void
+ */
+ public function setHeader($name, $value="") {}
+ /**
+ * Start node, after setting header values. When you start a node it begins discovery and connection.
+ There is no stop method; to stop a node, destroy it.
+ *
+ * @return void
+ */
+ public function start() {}
+ /**
+ * Stop node, this signals to other peers that this node will go away.
+ This is polite; however you can also just destroy the node without stopping it.
+ *
+ * @return void
+ */
+ public function stop() {}
+ /**
+ * Join a named group; after joining a group you can send messages
+ to the group and all Zyre nodes in that group will receive them.
+ *
+ * @param string $group
+ * @return void
+ */
+ public function join($group) {}
+ /**
+ * Leave a group.
+ *
+ * @param string $group
+ * @return void
+ */
+ public function leave($group) {}
+ /**
+ * Receive next message from network; the message may be a control
+ message (ENTER, EXIT, JOIN, LEAVE) or data (WHISPER, SHOUT).
+ Returns associative array, or NULL if interrupted
+ *
+ * @return void
+ */
+ public function recv() {}
+ /**
+ * Send a message on the network to a specific peer
+ *
+ * @param string $peer
+ * @param string $data
+ * @return void
+ */
+ public function sendPeer($peer, $data) {}
+ /**
+ * Send a message on the network for a group
+ *
+ * @param string $group
+ * @param string $data
+ * @return void
+ */
+ public function sendGroup($group, $data) {}
+ /**
+ * Get zyre ZeroMQ socket, for polling or receiving messages
+ *
+ * @return ZMQSocket
+ */
+ public function getSocket() {}
+}
+
+class ZMQException extends Exception {}
+class ZMQContextException extends ZMQException {}
+class ZMQSocketException extends ZMQException {}
+class ZMQPollException extends ZMQException {}
+class ZMQDeviceException extends ZMQException {}
+class ZMQZyreException extends ZMQException {}
+
/**
* A security certificate for the ØMQ CURVE authentication mechanism.
*/
@@ -665,5 +750,6 @@ public function deny($address) {}
*/
public function configure($type, $domain, $filename) {}
}
+
?>
diff --git a/config.m4 b/config.m4
index 53890fa..6450662 100644
--- a/config.m4
+++ b/config.m4
@@ -7,6 +7,9 @@ PHP_ARG_ENABLE(zmq_pthreads, whether to enable support for php threads extens
PHP_ARG_WITH(czmq, whether to enable CZMQ support,
[ --with-czmq[=DIR] Enable CZMQ support. DIR is the prefix to CZMQ installation directory.], no, no)
+PHP_ARG_WITH(zyre, whether to enable Zyre support,
+[ --with-zyre[=DIR] Enable Zyre support. DIR is the prefix to Zyre installation directory.], no, no)
+
if test "$PHP_ZMQ" != "no"; then
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
@@ -69,6 +72,29 @@ if test "$PHP_ZMQ" != "no"; then
fi
fi
+ if test "$PHP_ZYRE" != "no" -a "$PHP_CZMQ" != "no"; then
+ if test "x$PHP_ZYRE" != "xyes"; then
+ export PKG_CONFIG_PATH="${PHP_ZYRE}/${PHP_LIBDIR}/pkgconfig"
+ fi
+
+ AC_MSG_CHECKING(for Zyre)
+ if $PKG_CONFIG --exists libzyre; then
+ PHP_ZYRE_VERSION=`$PKG_CONFIG libzyre --modversion`
+ PHP_ZYRE_PREFIX=`$PKG_CONFIG libzyre --variable=prefix`
+ AC_MSG_RESULT([found version $PHP_ZYRE_VERSION in $PHP_ZYRE_PREFIX])
+
+ PHP_ZYRE_LIBS=`$PKG_CONFIG libzyre --libs`
+ PHP_ZYRE_INCS=`$PKG_CONFIG libzyre --cflags`
+
+ PHP_EVAL_LIBLINE($PHP_ZYRE_LIBS, ZMQ_SHARED_LIBADD)
+ PHP_EVAL_INCLINE($PHP_ZYRE_INCS)
+
+ AC_DEFINE([HAVE_ZYRE], [], [ZYRE was found])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
AC_CHECK_HEADERS([stdint.h],[php_zmq_have_stdint=yes; break;])
if test $php_zmq_have_stdint != "yes"; then
AC_MSG_ERROR(Unable to find stdint.h)
diff --git a/package.xml b/package.xml
index 212447b..b57c856 100644
--- a/package.xml
+++ b/package.xml
@@ -108,6 +108,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/php_zmq.h b/php_zmq.h
index ef50bfb..538fe7a 100644
--- a/php_zmq.h
+++ b/php_zmq.h
@@ -47,4 +47,16 @@
extern zend_module_entry zmq_module_entry;
#define phpext_zmq_ptr &zmq_module_entry
+/* PHP 5.4 */
+#if PHP_VERSION_ID < 50399
+# define object_properties_init(zo, class_type) { \
+ zval *tmp; \
+ zend_hash_copy((*zo).properties, \
+ &class_type->default_properties, \
+ (copy_ctor_func_t) zval_add_ref, \
+ (void *) &tmp, \
+ sizeof(zval *)); \
+ }
+#endif
+
#endif /* _PHP_ZMQ_H_ */
diff --git a/php_zmq_private.h b/php_zmq_private.h
index 7b5c24e..a4816cb 100644
--- a/php_zmq_private.h
+++ b/php_zmq_private.h
@@ -44,6 +44,14 @@
# endif
#endif
+#if defined(HAVE_CZMQ) && defined(HAVE_ZYRE)
+# include
+# include
+# if ZYRE_VERSION_MAJOR == 1 && CZMQ_VERSION_MAJOR >= 2
+# define HAVE_ZYRE_1
+# endif
+#endif
+
#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
@@ -275,6 +283,17 @@ ZEND_BEGIN_MODULE_GLOBALS(php_zmq)
php_zmq_clock_ctx_t *clock_ctx;
ZEND_END_MODULE_GLOBALS(php_zmq)
+
+#ifdef HAVE_ZYRE_1
+#define PHP_ZMQ_ZYRE_OBJECT php_zmq_zyre *this = (php_zmq_zyre *)zend_object_store_get_object(getThis() TSRMLS_CC)
+typedef struct _php_zmq_zyre {
+ zend_object zend_object;
+ zctx_t *shadow_context;
+ zyre_t *zyre;
+ zval *internal_socket;
+} php_zmq_zyre;
+#endif
+
#ifdef HAVE_CZMQ_2
typedef struct _php_zmq_cert {
zend_object zend_object;
diff --git a/tests/skipzyre.inc b/tests/skipzyre.inc
new file mode 100644
index 0000000..e81bd91
--- /dev/null
+++ b/tests/skipzyre.inc
@@ -0,0 +1,6 @@
+
diff --git a/tests/zyre-001.phpt b/tests/zyre-001.phpt
new file mode 100644
index 0000000..cbced3e
--- /dev/null
+++ b/tests/zyre-001.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test [Zyre] Object can be instancied multiple time
+--SKIPIF--
+
+--FILE--
+
+--FILE--
+setHeader('X-TEST', 'Z1');
+$z1->start();
+
+$z2 = new ZMQZyre($ctx);
+$z2->setHeader('X-TEST', 'Z2');
+$z2->start();
+
+usleep(100000);
+
+$obj = $z1->recv();
+var_dump($obj->command);
+var_dump($obj->headers->{'X-TEST'});
+
+$obj = $z2->recv();
+var_dump($obj->command);
+var_dump($obj->headers->{'X-TEST'});
+
+$z1->stop();
+
+usleep(100000);
+
+$obj = $z2->recv();
+var_dump($obj->command);
+
+$z2->stop();
+
+--EXPECTF--
+string(5) "ENTER"
+string(2) "Z2"
+string(5) "ENTER"
+string(2) "Z1"
+string(4) "EXIT"
diff --git a/tests/zyre-003.phpt b/tests/zyre-003.phpt
new file mode 100644
index 0000000..d2365b2
--- /dev/null
+++ b/tests/zyre-003.phpt
@@ -0,0 +1,79 @@
+--TEST--
+Test [Zyre] Zyre objects can exchange data in a group of peer
+--SKIPIF--
+
+--FILE--
+start();
+$z1->join('ZMQZyreTestGroup');
+
+
+$z2 = new ZMQZyre($ctx);
+$z2->start();
+$z2->join('ZMQZyreTestGroup');
+
+
+usleep(100000);
+
+// Enter
+$obj = $z1->recv();
+var_dump($obj->command);
+
+// Join
+$obj = $z1->recv();
+var_dump($obj->command);
+var_dump($obj->group);
+
+// Enter
+$obj = $z2->recv();
+var_dump($obj->command);
+
+// Join
+$obj = $z2->recv();
+var_dump($obj->command);
+var_dump($obj->group);
+
+$z2->sendGroup('ZMQZyreTestGroup', 'Some usefull data');
+
+usleep(100000);
+
+// SHOUT
+$obj = $z1->recv();
+var_dump($obj->group);
+var_dump($obj->data);
+
+$z1->leave('ZMQZyreTestGroup');
+
+usleep(100000);
+
+// Leave
+$obj = $z2->recv();
+var_dump($obj->command);
+var_dump($obj->group);
+
+$z1->stop();
+
+usleep(100000);
+
+// Exit
+$obj = $z2->recv();
+var_dump($obj->command);
+
+$z2->stop();
+
+--EXPECTF--
+string(5) "ENTER"
+string(4) "JOIN"
+string(16) "ZMQZyreTestGroup"
+string(5) "ENTER"
+string(4) "JOIN"
+string(16) "ZMQZyreTestGroup"
+string(16) "ZMQZyreTestGroup"
+string(17) "Some usefull data"
+string(5) "LEAVE"
+string(16) "ZMQZyreTestGroup"
+string(4) "EXIT"
diff --git a/tests/zyre-004.phpt b/tests/zyre-004.phpt
new file mode 100644
index 0000000..67fc720
--- /dev/null
+++ b/tests/zyre-004.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Test [Zyre] Zyre objects can exchange data with a peer
+--SKIPIF--
+
+--FILE--
+start();
+
+$z2 = new ZMQZyre($ctx);
+$z2->start();
+
+usleep(100000);
+
+// Enter
+$obj = $z1->recv();
+var_dump($obj->command);
+
+// Enter
+$obj = $z2->recv();
+var_dump($obj->command);
+$peer = $obj->peer;
+
+$z2->sendPeer($peer, 'Some very usefull data');
+
+usleep(100000);
+
+// SHOUT
+$obj = $z1->recv();
+var_dump($obj->data);
+
+$z1->stop();
+
+usleep(100000);
+
+// Exit
+$obj = $z2->recv();
+var_dump($obj->command);
+
+$z2->stop();
+
+--EXPECTF--
+string(5) "ENTER"
+string(5) "ENTER"
+string(22) "Some very usefull data"
+string(4) "EXIT"
diff --git a/tests/zyre-005.phpt b/tests/zyre-005.phpt
new file mode 100644
index 0000000..6ade673
--- /dev/null
+++ b/tests/zyre-005.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Test [Zyre] Test getter of internal ZMQSocket in ZMQZyre
+--SKIPIF--
+
+--FILE--
+setHeader('X-TEST', 'Z1');
+$z1->start();
+
+usleep(100000);
+
+$z2 = new ZMQZyre($ctx);
+$z2->setHeader('X-TEST', 'Z2');
+$z2->start();
+
+usleep(100000);
+
+$sock1 = $z1->getSocket();
+$sock2 = $z2->getSocket();
+
+
+var_dump($sock1->recv()); // Enter
+$sock1->recv(); // ID
+$sock1->recv(); // Headers
+$sock1->recv(); // IP:PORT
+
+var_dump($sock2->recv()); // Enter
+$sock2->recv(); // ID
+$sock2->recv(); // Headers
+$sock2->recv(); // IP:PORT
+
+unset($sock1);
+unset($sock2);
+
+--EXPECTF--
+string(5) "ENTER"
+string(5) "ENTER"
diff --git a/tests/zyre-006.phpt b/tests/zyre-006.phpt
new file mode 100644
index 0000000..55862d7
--- /dev/null
+++ b/tests/zyre-006.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Test [Zyre] Use ZMQSocket, build by ZMQZyre::getSocket, in a ZMQPoll
+--SKIPIF--
+
+--FILE--
+start();
+$z1->join('ZMQZyreTestGroup');
+
+usleep(100000);
+
+$z2 = new ZMQZyre($ctx);
+$z2->start();
+$z2->join('ZMQZyreTestGroup');
+
+usleep(100000);
+
+$z1->sendGroup('ZMQZyreTestGroup', 'A');
+$z1->sendGroup('ZMQZyreTestGroup', 'B');
+
+$poll = new ZMQPoll;
+$poll->add($z2->getSocket(), ZMQ::POLL_IN);
+
+$readable = array();
+$writable = array();
+
+for ($i=0; $i<4; $i++) {
+try {
+ $events = $poll->poll($readable, $writable, -1);
+ $errors = $poll->getLastErrors();
+
+ if (count($errors) > 0) {
+ foreach ($errors as $error) {
+ echo "Error polling object " . $error . "\n";
+ }
+ die('polling error');
+ }
+ } catch (ZMQPollException $e) {
+ echo "poll failed: " . $e->getMessage() . "\n";
+ die('polling exception');
+ }
+
+ if ($events > 0) {
+ /* Loop through readable objects and recv messages */
+ foreach ($readable as $r) {
+ // Don't read the Socket use the recv function of zyre
+ // Socket will return a multi-part zmq message, instead zyre will parse it and produce an abject
+ $obj = $z2->recv();
+ var_dump($obj->command);
+ }
+ }
+}
+--EXPECTF--
+string(5) "ENTER"
+string(4) "JOIN"
+string(5) "SHOUT"
+string(5) "SHOUT"
+
diff --git a/travis/script.sh b/travis/script.sh
index ac90a93..e07331a 100755
--- a/travis/script.sh
+++ b/travis/script.sh
@@ -65,6 +65,22 @@ install_libsodium() {
}
+# Installs Zyre
+#
+# Parameters:
+#
+# 1 - The directory to install Zyre to
+install_zyre() {
+ local zyre_dir=$1
+
+ if test ! -d "/tmp/php-zmq-travis-support"
+ then
+ git clone https://github.com/phuedx/php-zmq-travis-support /tmp/php-zmq-travis-support
+ fi
+
+ ln -s "/tmp/php-zmq-travis-support/zyre/zyre-1.0.0" $zyre_dir
+}
+
# Installs CZMQ v2.2.0.
#
# Parameters:
@@ -116,19 +132,25 @@ make_test() {
local zeromq_dir=$2
local with_czmq=$3
local with_czmq_option=""
+ local with_zyre=$4
+ local with_zyre_option=""
if test $with_czmq = "true"
then
with_czmq_option="--with-czmq=/tmp/czmq"
fi
+ if test $with_zyre = "true"
+ then
+ with_zyre_option="--with-zyre=/tmp/zyre"
+ fi
+
pushd $build_dir
phpize
- ./configure --with-zmq="$zeromq_dir" $with_czmq_option
+ ./configure --with-zmq="$zeromq_dir" $with_czmq_option $with_zyre_option
make
-
if test ! -e modules/zmq.so
then
printf "PHP extension build failed\n"
@@ -171,6 +193,7 @@ done
zeromq_version=$1
with_czmq=$2
+with_zyre=$3
# NOTE (phuedx, 2014/07/07): These must be kept in sync with the configure
# command used to build libsodium, ØMQ and CZMQ in
@@ -178,7 +201,7 @@ with_czmq=$2
libsodium_dir=/tmp/libsodium
zeromq_dir=/tmp/zeromq
czmq_dir=/tmp/czmq
-
+zyre_dir=/tmp/zyre
build_dir=/tmp/build
install_libsodium $libsodium_dir
@@ -189,6 +212,12 @@ then
install_czmq $czmq_dir
fi
+if test $with_zyre = "true"
+then
+ install_zyre $zyre_dir
+fi
+
init_build_dir $build_dir
-make_test $build_dir $zeromq_dir $with_czmq
+make_test $build_dir $zeromq_dir $with_czmq $with_zyre
+
diff --git a/zmq.c b/zmq.c
index f5a8c68..c97b354 100644
--- a/zmq.c
+++ b/zmq.c
@@ -52,17 +52,27 @@ zend_class_entry *php_zmq_socket_sc_entry;
zend_class_entry *php_zmq_poll_sc_entry;
zend_class_entry *php_zmq_device_sc_entry;
+
+#ifdef HAVE_ZYRE_1
+zend_class_entry *php_zmq_zyre_sc_entry;
+#endif
+
#ifdef HAVE_CZMQ_2
zend_class_entry *php_zmq_cert_sc_entry;
zend_class_entry *php_zmq_auth_sc_entry;
#endif
+
zend_class_entry *php_zmq_exception_sc_entry;
zend_class_entry *php_zmq_context_exception_sc_entry;
zend_class_entry *php_zmq_socket_exception_sc_entry;
zend_class_entry *php_zmq_poll_exception_sc_entry;
zend_class_entry *php_zmq_device_exception_sc_entry;
+#ifdef HAVE_ZYRE_1
+zend_class_entry *php_zmq_zyre_exception_sc_entry;
+#endif
+
#ifdef HAVE_CZMQ_2
zend_class_entry *php_zmq_cert_exception_sc_entry;
zend_class_entry *php_zmq_auth_exception_sc_entry;
@@ -74,6 +84,10 @@ static zend_object_handlers zmq_context_object_handlers;
static zend_object_handlers zmq_poll_object_handlers;
static zend_object_handlers zmq_device_object_handlers;
+#ifdef HAVE_ZYRE_1
+static zend_object_handlers zmq_zyre_object_handlers;
+#endif
+
#ifdef PHP_ZMQ_PTHREADS
#include
@@ -110,7 +124,7 @@ static int le_zmq_socket, le_zmq_context;
/** {{{ static void php_zmq_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
*/
-static void php_zmq_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
+static void php_zmq_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
{
int major = 0, minor = 0, patch = 0;
zmq_version(&major, &minor, &patch);
@@ -118,6 +132,30 @@ static void php_zmq_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
}
/* }}} */
+#ifdef HAVE_CZMQ
+/** {{{ static void php_czmq_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
+*/
+static void php_czmq_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
+{
+ int major = 0, minor = 0, patch = 0;
+ zsys_version(&major, &minor, &patch);
+ (void) snprintf(buffer, PHP_ZMQ_VERSION_LEN - 1, "%d.%d.%d", major, minor, patch);
+}
+/* }}} */
+#endif
+
+#ifdef HAVE_ZYRE
+/** {{{ static void php_zyre_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
+*/
+static void php_zyre_get_lib_version(char buffer[PHP_ZMQ_VERSION_LEN])
+{
+ // FFS: This is the zyre version read from include during build time
+ // libzyre will add a method to get the real version of the lib
+ (void) snprintf(buffer, PHP_ZMQ_VERSION_LEN - 1, "%d.%d.%d", ZYRE_VERSION_MAJOR, ZYRE_VERSION_MINOR, ZYRE_VERSION_PATCH);
+}
+/* }}} */
+#endif
+
/** {{{ static int php_zmq_socket_list_entry(void)
*/
static int php_zmq_socket_list_entry(void)
@@ -885,7 +923,7 @@ PHP_METHOD(zmqsocket, recvmulti)
long flags = 0;
zend_bool retval;
zval *msg;
-#if ZMQ_VERSION_MAJOR < 3
+#if ZMQ_VERSION_MAJOR < 3
int64_t value;
#else
int value;
@@ -915,7 +953,7 @@ PHP_METHOD(zmqsocket, recvmulti)
}
/* }}} */
-/** {{{ string ZMQ::getPersistentId()
+/** {{{ string ZMQ::getPersistentId()
Returns the persistent id of the object
*/
PHP_METHOD(zmqsocket, getpersistentid)
@@ -1605,8 +1643,496 @@ PHP_METHOD(zmqdevice, __clone) { }
/* -- END ZMQPoll */
-#ifdef HAVE_CZMQ_2
+#ifdef HAVE_ZYRE_1
+/* --- START ZMQZyre --- */
+
+static void php_zmq_zyre_free_storage(void *object TSRMLS_DC)
+{
+ php_zmq_zyre *zmq_zyre = (php_zmq_zyre *) object;
+
+ if (zmq_zyre->internal_socket != NULL) {
+ zend_objects_store_del_ref(zmq_zyre->internal_socket TSRMLS_CC);
+ zval_ptr_dtor (&zmq_zyre->internal_socket);
+ }
+
+ if (zmq_zyre->zyre != NULL) {
+ zyre_destroy(&zmq_zyre->zyre);
+ }
+
+ if (zmq_zyre->shadow_context != NULL) {
+ zctx_destroy(&zmq_zyre->shadow_context);
+ }
+
+ zend_object_std_dtor(&zmq_zyre->zend_object TSRMLS_CC);
+ efree(zmq_zyre);
+}
+
+static zend_object_value php_zmq_zyre_object_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ zend_object_value result;
+ php_zmq_zyre *zmq_zyre;
+
+ zmq_zyre = (php_zmq_zyre *) emalloc(sizeof(php_zmq_zyre));
+ memset(&zmq_zyre->zend_object, 0, sizeof(zend_object));
+
+ /* zbeacon is initialised in ZMQZyre#__construct. */
+ zmq_zyre->zyre = NULL;
+ zmq_zyre->internal_socket = NULL;
+ zend_object_std_init(&zmq_zyre->zend_object, class_type TSRMLS_CC);
+ object_properties_init(&zmq_zyre->zend_object, class_type);
+
+ result.handle = zend_objects_store_put(
+ zmq_zyre,
+ NULL,
+ (zend_objects_free_object_storage_t) php_zmq_zyre_free_storage,
+ NULL TSRMLS_CC
+ );
+ result.handlers = &zmq_zyre_object_handlers;
+ return result;
+}
+
+/* {{{ proto void ZMQZyre::__construct(ZMQContext context)
+ Construct a ZMQZyre
+*/
+PHP_METHOD(zmqzyre, __construct)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ zval *object;
+ php_zmq_context_object *context_object;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &object, php_zmq_context_sc_entry) != SUCCESS) {
+ return;
+ }
+
+ context_object = (php_zmq_context_object *) zend_object_store_get_object(object TSRMLS_CC);
+
+ this->shadow_context = zctx_shadow_zmq_ctx(context_object->context->z_ctx);
+ if (this->shadow_context == NULL) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Failed to create the underlying shadow context object.");
+ return;
+ }
+
+ this->zyre = zyre_new(this->shadow_context);
+ if (this->zyre == NULL) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Failed to create the underlying zbeacon object.");
+ return;
+ }
+
+ return;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre___construct_args, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, ZMQContext, ZMQContext, 0)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::setHeader(string name, string value)
+ Set node header; these are provided to other nodes during discovery and come in each ENTER message.
+*/
+PHP_METHOD(zmqzyre, setHeader)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ char *name, *value;
+ int name_len, value_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
+ return;
+ }
+
+ if (name_len == 0) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Header name can not be empty");
+ return;
+ }
+
+ if (value_len == 0) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Header value can not be empty");
+ return;
+ }
+
+ zyre_set_header(this->zyre, name, value);
+
+ ZMQ_RETURN_THIS;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_setHeader_args, 0, 0, 1)
+ ZEND_ARG_INFO(0, name)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::start()
+ Start node, after setting header values. When you start a node it begins discovery and connection.
+ There is no stop method; to stop a node, destroy it.
+*/
+PHP_METHOD(zmqzyre, start)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zyre_start(this->zyre);
+
+ ZMQ_RETURN_THIS;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_start_args, 0, 0, 1)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::stop()
+ Stop node, this signals to other peers that this node will go away.
+ This is polite; however you can also just destroy the node without stopping it.
+*/
+PHP_METHOD(zmqzyre, stop)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zyre_stop(this->zyre);
+
+ ZMQ_RETURN_THIS;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_stop_args, 0, 0, 1)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::join(string group)
+ Join a named group; after joining a group you can send messages
+ to the group and all Zyre nodes in that group will receive them.
+*/
+PHP_METHOD(zmqzyre, join)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ char *group;
+ int group_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &group, &group_len) == FAILURE) {
+ return;
+ }
+
+ if (group_len == 0) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Group name can not be empty");
+ return;
+ }
+
+ zyre_join(this->zyre, group);
+
+ ZMQ_RETURN_THIS;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_join_args, 0, 0, 1)
+ ZEND_ARG_INFO(0, group)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::leave(string group)
+ Leave a group.
+*/
+PHP_METHOD(zmqzyre, leave)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ char *group;
+ int group_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &group, &group_len) == FAILURE) {
+ return;
+ }
+
+ if (group_len == 0) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Group name can not be empty");
+ return;
+ }
+
+ zyre_leave(this->zyre, group);
+
+ ZMQ_RETURN_THIS;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_leave_args, 0, 0, 1)
+ ZEND_ARG_INFO(0, group)
+ZEND_END_ARG_INFO();
+
+
+// Helper function to convert zhash_t to php object
+void zhash_to_object(const char *key, void *item, void **argument)
+{
+ zval *obj = (zval *)argument[0];
+#ifdef ZTS
+ TSRMLS_D = argument[1];
+#endif
+
+ zend_update_property_string(NULL, obj, key, strlen(key), (char *)item TSRMLS_CC);
+}
+
+/* {{{ proto void ZMQZyre::recv()
+ Receive next message from network; the message may be a control
+ message (ENTER, EXIT, JOIN, LEAVE) or data (WHISPER, SHOUT).
+ Returns associative array, or NULL if interrupted
+*/
+PHP_METHOD(zmqzyre, recv)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ zmsg_t *msg = NULL;
+ char *command = NULL, *peerid = NULL;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ msg = zyre_recv(this->zyre);
+ if (msg == NULL) {
+ RETURN_NULL();
+ }
+
+ object_init(return_value);
+
+ // All frame start by a command
+ command = zmsg_popstr(msg);
+ if (command == NULL) {
+ goto cleanup;
+ }
+
+ // 2nd parameter is always the peerid of the emiter
+ peerid = zmsg_popstr(msg);
+ if (peerid == NULL) {
+ goto cleanup;
+ }
+
+ // Parse commands with additional content
+ if (strcmp(command, "ENTER") == 0) {
+
+ zframe_t *headers_packed = zmsg_pop (msg);
+ char *ipaddress = zmsg_popstr(msg);
+
+ if (headers_packed != NULL) {
+
+ zhash_t *headers = zhash_unpack (headers_packed);
+ zframe_destroy (&headers_packed);
+
+ if (headers != NULL) {
+ zval *h;
+ MAKE_STD_ZVAL(h);
+ object_init(h);
+
+ void *args[2];
+ args[0] = h;
+#ifdef ZTS
+ args[1] = TSRMLS_C;
+#endif
+ zhash_foreach(headers, zhash_to_object, args);
+ zhash_destroy(&headers);
+
+ zend_update_property(NULL, return_value, "headers", strlen("headers"), h TSRMLS_CC);
+ }
+ }
+
+ if (ipaddress != NULL) {
+ zend_update_property_string(NULL, return_value, "ipaddress", strlen("ipaddress"), ipaddress TSRMLS_CC);
+ free(ipaddress);
+ } else {
+ zend_update_property_null(NULL, return_value, "ipaddress", strlen("ipaddress") TSRMLS_CC);
+ }
+ } else
+ if (strcmp(command, "JOIN") == 0) {
+ char *group;
+
+ group = zmsg_popstr(msg);
+ if (group == NULL) {
+ zend_update_property_null(NULL, return_value, "group", strlen("group") TSRMLS_CC);
+ } else {
+ zend_update_property_string(NULL, return_value, "group", strlen("group"), group TSRMLS_CC);
+ free(group);
+ }
+ } else
+ if (strcmp(command, "LEAVE") == 0) {
+ char *group;
+
+ group = zmsg_popstr(msg);
+ if (group == NULL) {
+ zend_update_property_null(NULL, return_value, "group", strlen("group") TSRMLS_CC);
+ } else {
+ zend_update_property_string(NULL, return_value, "group", strlen("group"), group TSRMLS_CC);
+ free(group);
+ }
+ } else
+ if (strcmp(command, "SHOUT") == 0) {
+ char *group, *data;
+
+ group = zmsg_popstr(msg);
+ if (group == NULL) {
+ zend_update_property_null(NULL, return_value, "group", strlen("group") TSRMLS_CC);
+ } else {
+ zend_update_property_string(NULL, return_value, "group", strlen("group"), group TSRMLS_CC);
+ free(group);
+ }
+
+ data = zmsg_popstr(msg);
+ if (data == NULL) {
+ zend_update_property_null(NULL, return_value, "data", strlen("data") TSRMLS_CC);
+ } else {
+ zend_update_property_string(NULL, return_value, "data", strlen("data"), data TSRMLS_CC);
+ free(data);
+ }
+ } else
+ if (strcmp(command, "WHISPER") == 0) {
+ char *data;
+
+ data = zmsg_popstr(msg);
+ if (data == NULL) {
+ zend_update_property_null(NULL, return_value, "data", strlen("data") TSRMLS_CC);
+ } else {
+ zend_update_property_string(NULL, return_value, "data", strlen("data"), data TSRMLS_CC);
+ free(data);
+ }
+ }
+
+ zend_update_property_string(NULL, return_value, "command", strlen("command"), command TSRMLS_CC);
+ zend_update_property_string(NULL, return_value, "peer", strlen("peer"), peerid TSRMLS_CC);
+
+cleanup:
+ if (command != NULL)
+ free(command);
+
+ if (peerid != NULL)
+ free(peerid);
+
+ if (msg != NULL)
+ zmsg_destroy(&msg);
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_recv_args, 0, 0, 1)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::sendGroup(string group, string data)
+ Send a message on the network for a group
+*/
+PHP_METHOD(zmqzyre, sendGroup)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ char *data = NULL, *group = NULL;
+ int data_len, group_len;
+ int rc;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &group, &group_len, &data, &data_len) == FAILURE) {
+ return;
+ }
+
+ if (group_len == 0) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Group name can not be empty");
+ return;
+ }
+
+ zyre_shouts (this->zyre, group, data);
+
+ ZMQ_RETURN_THIS;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_sendGroup_args, 0, 0, 2)
+ ZEND_ARG_INFO(0, group)
+ ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto void ZMQZyre::sendPeer(string peer, string data)
+ Send a message on the network to a specific peer
+*/
+PHP_METHOD(zmqzyre, sendPeer)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ char *data = NULL, *peer = NULL;
+ int data_len, peer_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &peer, &peer_len, &data, &data_len) == FAILURE) {
+ return;
+ }
+
+ if (peer_len == 0) {
+ zend_throw_exception_ex(php_zmq_zyre_exception_sc_entry, 0 TSRMLS_CC, "Peer ID can not be empty");
+ return;
+ }
+
+ zyre_whispers(this->zyre, peer, data);
+
+ ZMQ_RETURN_THIS;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_sendPeer_args, 0, 0, 2)
+ ZEND_ARG_INFO(0, peer)
+ ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+
+/* {{{ proto ZMQSocket ZMQZyre::getSocket()
+ Get zyre ZeroMQ socket, for polling or receiving messages
+*/
+PHP_METHOD(zmqzyre, getSocket)
+{
+ PHP_ZMQ_ZYRE_OBJECT;
+ php_zmq_socket_object *zmq_sock;
+ void *zyre_sock = NULL;
+ bool is_persistent = true;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (this->internal_socket == NULL) {
+ zyre_sock = zyre_socket(this->zyre);
+ if (zyre_socket == NULL) {
+ RETURN_NULL();
+ }
+
+ // Create internal socket
+ php_zmq_socket *socket = (php_zmq_socket *) ecalloc(1, sizeof(php_zmq_socket));
+ socket->z_socket = zyre_sock;
+ socket->ctx = this->shadow_context;
+ socket->pid = getpid();
+ socket->is_persistent = is_persistent;
+ zend_hash_init(&(socket->connect), 0, NULL, NULL, is_persistent);
+ zend_hash_init(&(socket->bind), 0, NULL, NULL, is_persistent);
+
+ // Create a ZMQSocket
+ MAKE_STD_ZVAL(this->internal_socket);
+ object_init_ex(this->internal_socket, php_zmq_socket_sc_entry);
+ zmq_sock = (php_zmq_socket_object *) zend_object_store_get_object(this->internal_socket TSRMLS_CC);
+ zmq_sock->socket = socket;
+ zmq_sock->persistent_id = NULL;
+ }
+
+ *return_value = *(this->internal_socket);
+ zval_copy_ctor(return_value);
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(zmqzyre_getSocket_args, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+
+static zend_function_entry php_zmq_zyre_class_methods[] = {
+ PHP_ME(zmqzyre, __construct, zmqzyre___construct_args, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR | ZEND_ACC_FINAL)
+ PHP_ME(zmqzyre, setHeader, zmqzyre_setHeader_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, start, zmqzyre_start_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, stop, zmqzyre_stop_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, join, zmqzyre_join_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, leave, zmqzyre_leave_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, recv, zmqzyre_recv_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, sendPeer, zmqzyre_sendPeer_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, sendGroup, zmqzyre_sendGroup_args, ZEND_ACC_PUBLIC)
+ PHP_ME(zmqzyre, getSocket, zmqzyre_getSocket_args, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+
+/* --- END ZMQZyre --- */
+#endif // HAVE_ZYRE_1
+
+
+#ifdef HAVE_CZMQ_2
/* --- START ZMQCert --- */
static void php_zmq_cert_free_storage(void *object TSRMLS_DC)
@@ -1683,6 +2209,7 @@ PHP_METHOD(zmqcert, __construct)
return;
}
+/* }}} */
ZEND_BEGIN_ARG_INFO_EX(zmqcert___construct_args, 0, 0, 0)
ZEND_ARG_INFO(0, filename)
@@ -2326,7 +2853,7 @@ static zend_function_entry php_zmq_socket_class_methods[] = {
PHP_ME(zmqsocket, getsockopt, zmq_socket_getsockopt_args, ZEND_ACC_PUBLIC)
PHP_ME(zmqsocket, __clone, zmq_socket_clone_args, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
PHP_MALIAS(zmqsocket, sendmsg, send, zmq_socket_send_args, ZEND_ACC_PUBLIC)
- PHP_MALIAS(zmqsocket, recvmsg, recv, zmq_socket_recv_args, ZEND_ACC_PUBLIC)
+ PHP_MALIAS(zmqsocket, recvmsg, recv, zmq_socket_recv_args, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
@@ -2661,10 +3188,14 @@ PHP_MINIT_FUNCTION(zmq)
zend_class_entry ce, ce_context, ce_socket, ce_poll, ce_device;
zend_class_entry ce_exception, ce_context_exception, ce_socket_exception, ce_poll_exception, ce_device_exception;
+#ifdef HAVE_ZYRE_1
+ zend_class_entry ce_zyre, ce_zyre_exception;
+#endif
#ifdef HAVE_CZMQ_2
zend_class_entry ce_cert, ce_cert_exception, ce_auth, ce_auth_exception;
#endif
+
le_zmq_context = zend_register_list_destructors_ex(NULL, php_zmq_context_dtor, "ZMQ persistent context", module_number);
le_zmq_socket = zend_register_list_destructors_ex(NULL, php_zmq_socket_dtor, "ZMQ persistent socket", module_number);
@@ -2674,6 +3205,9 @@ PHP_MINIT_FUNCTION(zmq)
memcpy(&zmq_poll_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
memcpy(&zmq_device_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+#ifdef HAVE_ZYRE_1
+ memcpy(&zmq_zyre_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+#endif
#ifdef HAVE_CZMQ_2
memcpy(&zmq_cert_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
memcpy(&zmq_auth_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
@@ -2704,6 +3238,12 @@ PHP_MINIT_FUNCTION(zmq)
zmq_device_object_handlers.clone_obj = NULL;
php_zmq_device_sc_entry = zend_register_internal_class(&ce_device TSRMLS_CC);
+#ifdef HAVE_ZYRE_1
+ INIT_CLASS_ENTRY(ce_zyre, "ZMQZyre", php_zmq_zyre_class_methods);
+ ce_zyre.create_object = php_zmq_zyre_object_new;
+ zmq_zyre_object_handlers.clone_obj = NULL;
+ php_zmq_zyre_sc_entry = zend_register_internal_class(&ce_zyre TSRMLS_CC);
+#endif
#ifdef HAVE_CZMQ_2
INIT_CLASS_ENTRY(ce_cert, "ZMQCert", php_zmq_cert_class_methods);
ce_cert.create_object = php_zmq_cert_new;
@@ -2736,6 +3276,11 @@ PHP_MINIT_FUNCTION(zmq)
php_zmq_device_exception_sc_entry = zend_register_internal_class_ex(&ce_device_exception, php_zmq_exception_sc_entry, "ZMQException" TSRMLS_CC);
php_zmq_device_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL_CLASS;
+#ifdef HAVE_ZYRE_1
+ INIT_CLASS_ENTRY(ce_zyre_exception, "ZMQZyreException", NULL);
+ php_zmq_zyre_exception_sc_entry = zend_register_internal_class_ex(&ce_zyre_exception, php_zmq_exception_sc_entry, "ZMQException" TSRMLS_CC);
+ php_zmq_zyre_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL_CLASS;
+#endif
#ifdef HAVE_CZMQ_2
INIT_CLASS_ENTRY(ce_cert_exception, "ZMQCertException", NULL);
php_zmq_cert_exception_sc_entry = zend_register_internal_class_ex(&ce_cert_exception, php_zmq_exception_sc_entry, "ZMQException" TSRMLS_CC);
@@ -2825,6 +3370,15 @@ PHP_MINIT_FUNCTION(zmq)
#undef PHP_ZMQ_REGISTER_CONST_LONG
#undef PHP_ZMQ_REGISTER_CONST_STRING
+#ifdef HAVE_ZYRE_1
+#define PHP_ZYRE_REGISTER_CONST_STRING(const_name, value) \
+ zend_declare_class_constant_string (php_zmq_zyre_sc_entry, const_name, sizeof(const_name)-1, value TSRMLS_CC);
+
+ php_zyre_get_lib_version(version);
+ PHP_ZYRE_REGISTER_CONST_STRING("LIBZYRE_VERSION", version);
+
+#undef PHP_ZYRE_REGISTER_CONST_STRING
+#endif
return SUCCESS;
}
@@ -2842,14 +3396,33 @@ PHP_MSHUTDOWN_FUNCTION(zmq)
PHP_MINFO_FUNCTION(zmq)
{
- char version[PHP_ZMQ_VERSION_LEN];
- php_zmq_get_lib_version(version);
+ char zmq_version[PHP_ZMQ_VERSION_LEN];
+#ifdef HAVE_CZMQ
+ char czmq_version[PHP_ZMQ_VERSION_LEN];
+#endif
+#ifdef HAVE_ZYRE
+ char zyre_version[PHP_ZMQ_VERSION_LEN];
+#endif
+
+ php_zmq_get_lib_version(zmq_version);
+#ifdef HAVE_CZMQ
+ php_czmq_get_lib_version(czmq_version);
+#endif
+#ifdef HAVE_ZYRE
+ php_zyre_get_lib_version(zyre_version);
+#endif
php_info_print_table_start();
php_info_print_table_header(2, "ZMQ extension", "enabled");
php_info_print_table_row(2, "ZMQ extension version", PHP_ZMQ_VERSION);
- php_info_print_table_row(2, "libzmq version", version);
+ php_info_print_table_row(2, "libzmq version", zmq_version);
+#ifdef HAVE_CZMQ
+ php_info_print_table_row(2, "czmq version", czmq_version);
+#endif
+#ifdef HAVE_ZYRE
+ php_info_print_table_row(2, "libzyre version", zyre_version);
+#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();