├── .gitignore
├── .travis.yml
├── CREDITS
├── LICENSE
├── README
├── TODO
├── config.m4
├── config.w32
├── doc
├── classes.php
└── functions.php
├── examples
├── oop.php
└── procedural.php
├── package.xml
├── php_stomp.c
├── php_stomp.h
├── stomp.c
├── stomp.h
└── tests
├── 001-stomp.phpt
├── 002-version.phpt
├── 003-connect
├── 001.phpt
├── 002.phpt
└── 003.phpt
├── 004-getSessionId
└── 001.phpt
├── 005-close
├── 001.phpt
└── 002.phpt
├── 006-send
├── 001.phpt
├── 002.phpt
└── 003.phpt
├── 007-subscribe
└── 001.phpt
├── 008-unsubscribe
└── 001.phpt
├── 009-readFrame
├── 001.phpt
├── 002.phpt
├── 003.phpt
├── 004.phpt
├── 005.phpt
└── 006.phpt
├── 010-timeout
├── 001.phpt
└── 002.phpt
├── 011-commit
└── 001.phpt
├── bug_16930.phpt
├── bug_16936.phpt
├── config.inc
└── skipif.inc
/.gitignore:
--------------------------------------------------------------------------------
1 | .deps
2 | .libs/
3 | Makefile
4 | Makefile.fragments
5 | Makefile.global
6 | Makefile.objects
7 | acinclude.m4
8 | aclocal.m4
9 | autom4te.cache/
10 | build/
11 | config.guess
12 | config.h
13 | config.h.in
14 | config.log
15 | config.nice
16 | config.status
17 | config.sub
18 | configure
19 | configure.in
20 | install-sh
21 | libtool
22 | ltmain.sh
23 | missing
24 | mkinstalldirs
25 | modules/
26 | php_stomp.lo
27 | run-tests.php
28 | stomp.la
29 | stomp.lo
30 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | dist: xenial
4 | language: c
5 | os: linux
6 | addons:
7 | apt:
8 | packages:
9 | - rabbitmq-server
10 |
11 | services:
12 | - rabbitmq
13 |
14 | php:
15 | - 7.0
16 | - 7.1
17 | - 7.2
18 | - 7.3
19 | - 7.4
20 | - 8.0
21 |
22 | env:
23 | - STOMP_PROVIDER=rabbitmq
24 |
25 | before_script:
26 | - sh -c " if [ '$STOMP_PROVIDER' = 'rabbitmq' ]; then
27 | sudo service rabbitmq-server start;
28 | sudo rabbitmq-plugins enable rabbitmq_stomp;
29 | sudo rabbitmq-plugins list;
30 | fi"
31 | - phpize
32 |
33 | script: ./configure && make && NO_INTERACTION=1 REPORT_EXIT_STATUS=1 make test TEST_PHP_ARGS='--show-diff'
34 |
--------------------------------------------------------------------------------
/CREDITS:
--------------------------------------------------------------------------------
1 | stomp
2 | Pierrick Charron
3 | Xinchen Hui
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------
2 | The PHP License, version 3.01
3 | Copyright (c) 1999 - 2014 The PHP Group. All rights reserved.
4 | --------------------------------------------------------------------
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, is permitted provided that the following conditions
8 | are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | 2. Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in
15 | the documentation and/or other materials provided with the
16 | distribution.
17 |
18 | 3. The name "PHP" must not be used to endorse or promote products
19 | derived from this software without prior written permission. For
20 | written permission, please contact group@php.net.
21 |
22 | 4. Products derived from this software may not be called "PHP", nor
23 | may "PHP" appear in their name, without prior written permission
24 | from group@php.net. You may indicate that your software works in
25 | conjunction with PHP by saying "Foo for PHP" instead of calling
26 | it "PHP Foo" or "phpfoo"
27 |
28 | 5. The PHP Group may publish revised and/or new versions of the
29 | license from time to time. Each version will be given a
30 | distinguishing version number.
31 | Once covered code has been published under a particular version
32 | of the license, you may always continue to use it under the terms
33 | of that version. You may also choose to use such covered code
34 | under the terms of any subsequent version of the license
35 | published by the PHP Group. No one other than the PHP Group has
36 | the right to modify the terms applicable to covered code created
37 | under this License.
38 |
39 | 6. Redistributions of any form whatsoever must retain the following
40 | acknowledgment:
41 | "This product includes PHP software, freely available from
42 | ".
43 |
44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55 | OF THE POSSIBILITY OF SUCH DAMAGE.
56 |
57 | --------------------------------------------------------------------
58 |
59 | This software consists of voluntary contributions made by many
60 | individuals on behalf of the PHP Group.
61 |
62 | The PHP Group can be contacted via Email at group@php.net.
63 |
64 | For more information on the PHP Group and the PHP project,
65 | please see .
66 |
67 | PHP includes the Zend Engine, freely available at
68 | .
69 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | stomp
2 | =====
3 |
4 | This extension allows php applications to communicate with any Stomp compliant Message Broker(s) through easy object
5 | oriented and procedural interfaces.
6 |
7 | This extension currently implements STOMP 1.0 protocol: https://stomp.github.io/stomp-specification-1.0.html
8 |
9 | [The stomp extension at the PECL Repository website](http://pecl.php.net/package/stomp)
10 |
11 | Documentation
12 | =============
13 |
14 | For documentation of the functions that this extension provides can be found here: http://www.php.net/stomp
15 |
16 | Contribute
17 | ==========
18 |
19 | Your contributions and bugreports are highly appreciated. To contribute, fork and create a pull request. To report a
20 | bug use the [PHP Bug Tracking System](https://bugs.php.net/)
21 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | - Add the ability to connect to a network of brokers
2 | (Cf: http://activemq.apache.org/networks-of-brokers.html)
3 | - Add Stomp 1.1 full support
4 | - Verify if we need to call recv with MSG_PEEK for the newline char
5 | or if the current implementation is enough (cf bug #59217)
6 |
--------------------------------------------------------------------------------
/config.m4:
--------------------------------------------------------------------------------
1 | dnl config.m4 for extension stomp
2 |
3 | PHP_ARG_ENABLE(stomp, whether to enable stomp support,
4 | [ --enable-stomp Enable stomp support])
5 |
6 | PHP_ARG_WITH(openssl-dir,OpenSSL dir for stomp,
7 | [ --with-openssl-dir[=DIR] stomp: openssl install prefix], no, no)
8 |
9 | if test "$PHP_STOMP" != "no"; then
10 | PHP_NEW_EXTENSION(stomp, stomp.c php_stomp.c, $ext_shared)
11 |
12 | test -z "$PHP_OPENSSL" && PHP_OPENSSL=no
13 |
14 | if test "$PHP_OPENSSL" != "no" || test "$PHP_OPENSSL_DIR" != "no"; then
15 | PHP_SETUP_OPENSSL(STOMP_SHARED_LIBADD,
16 | [
17 | AC_DEFINE(HAVE_STOMP_SSL,1,[ ])
18 | ], [
19 | AC_MSG_ERROR([OpenSSL libraries not found.
20 |
21 | Check the path given to --with-openssl-dir and output in config.log)
22 | ])
23 | ])
24 |
25 | PHP_SUBST(STOMP_SHARED_LIBADD)
26 | fi
27 | fi
28 |
--------------------------------------------------------------------------------
/config.w32:
--------------------------------------------------------------------------------
1 | // vim:ft=javascript
2 |
3 | ARG_ENABLE("stomp", "enable stomp support", "no");
4 |
5 | if (PHP_STOMP != "no") {
6 | if (CHECK_LIB("ssleay32.lib", "stomp", PHP_STOMP) && CHECK_LIB("libeay32.lib", "stomp", PHP_STOMP)) {
7 | ADD_FLAG("CFLAGS_STOMP", "/DHAVE_STOMP_SSL=1");
8 | } else if (CHECK_LIB("libssl.lib", "stomp", PHP_STOMP) && CHECK_LIB("libcrypto.lib", "stomp", PHP_STOMP)) {
9 | ADD_FLAG("CFLAGS_STOMP", "/DHAVE_STOMP_SSL=1");
10 | }
11 |
12 | EXTENSION("stomp", "stomp.c php_stomp.c");
13 | }
14 |
--------------------------------------------------------------------------------
/doc/classes.php:
--------------------------------------------------------------------------------
1 | send($queue, $msg);
10 |
11 | $stomp->subscribe($queue);
12 | $frame = $stomp->readFrame();
13 | if ($frame->body === $msg) {
14 | echo "Worked\n";
15 | $stomp->ack($frame, array('receipt' => 'message-12345'));
16 | } else {
17 | echo "Failed\n";
18 | }
19 |
20 | $stomp->disconnect();
21 | } catch(StompException $e) {
22 | echo $e->getMessage();
23 | }
24 |
--------------------------------------------------------------------------------
/examples/procedural.php:
--------------------------------------------------------------------------------
1 | 't1'));
11 | stomp_commit($stomp, 't1');
12 |
13 | stomp_subscribe($stomp, $queue);
14 | $frame = stomp_read_frame($stomp);
15 | if ($frame['body'] === $msg) {
16 | echo "Worked\n";
17 | stomp_ack($stomp, $frame['headers']['message-id']);
18 | } else {
19 | echo "Failed\n";
20 | }
21 |
22 | stomp_close($stomp);
23 | }
24 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | stomp
4 | pecl.php.net
5 | Stomp client extension
6 |
7 | This extension allows php applications to communicate with any Stomp compliant Message Brokers through easy object oriented and procedural interfaces.
8 |
9 |
10 | Pierrick Charron
11 | pierrick
12 | pierrick@php.net
13 | yes
14 |
15 |
16 | Gennady Feldman
17 | gena01
18 | gena01@php.net
19 | yes
20 |
21 |
22 | Xinchen Hui
23 | laruence
24 | laruence@php.net
25 | yes
26 |
27 |
28 | Remi Collet
29 | remi
30 | remi@php.net
31 | yes
32 |
33 | 2022-05-31
34 | 2.0.4dev2.0.1
35 | stablestable
36 | PHP License
37 |
38 | -
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | 7.0.0
88 |
89 |
90 | 1.4.0
91 |
92 |
93 |
94 |
95 | openssl
96 |
97 |
98 |
99 |
100 | stomp
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | 2022-05-31
109 | 2.0.32.0.1
110 | stablestable
111 | PHP License
112 |
113 | - Fix compatibility with PHP 8
114 |
115 |
116 |
117 | 2018-06-29
118 | 2.0.22.0.1
119 | stablestable
120 | PHP License
121 |
122 | - Fix compatibility with PHP 7.3
123 | - Fix -Wformat issues
124 |
125 |
126 |
127 | 2.0.12.0.1
128 | stablestable
129 | PHP License
130 | 2017-05-04
131 |
132 | - PHP7.1 Support
133 |
134 |
135 |
136 | 2.0.02.0.0
137 | betabeta
138 | PHP License
139 | 2016-05-24
140 |
141 | - PHP7 Support
142 |
143 |
144 |
145 | 1.0.91.0.9
146 | stablestable
147 | PHP License
148 | 2016-01-04
149 |
150 | - Adding .travis.yml to enable Travis CI test runner. (Gennady)
151 | - Adding a basic README file. (Gennady)
152 | - Check stomp connection status after _stomp_recv. (Gennady)
153 | - Commenting out activemq.prefetchSize hardcoded header for SUBSCRIBE frame. (Gennady)
154 | - Make login and passcode headers optional (if no creds provided). (Gennady)
155 | - Fixing type cast warning, introduced a new int variable. (Gennady)
156 | - Fixing stomp_writable() check so we can catch when connect failed. (Gennady)
157 |
158 |
159 |
160 | 1.0.81.0.8
161 | stablestable
162 | PHP License
163 | 2015-05-18
164 |
165 | - Fix perm on source files. (Remi)
166 | - Fixing PHP_STOMP_VERSION constant, per Remi's request. (Gennady)
167 |
168 |
169 |
170 | 1.0.71.0.7
171 | stablestable
172 | PHP License
173 | 2015-05-15
174 |
175 | - add LICENSE file as documentation (Remi)
176 | - Fixed Windows compilation regression due to new TCP_NODELAY code. (Gennady Feldman)
177 | - Fixed bug where error checking was missing after stomp_send(). (Gennady Feldman)
178 |
179 |
180 |
181 | 1.0.61.0.6
182 | stablestable
183 | PHP License
184 | 2014-12-07
185 |
186 | - Add two new ini options stomp.default_username and stomp.default_passowrd (Pierrick)
187 | - General performance improvements (Pierrick)
188 | - Fix stomp_read_frame when buffered (Pierrick)
189 | - Fixed bug #59217 (Connections to RabbitMQ via CLI). (Pierrick).
190 | - Fixed bug #59970 (acking a message makes rabbitmq disconnect the server). (Pierrick)
191 | - Fixed bug #67170 (Disable Nagle's Algorithm with TCP_NODELAY, it delays sending small messages). (Yarek Tyshchenko)
192 | - Fixed bug #68497 (Stomp client doesn't parse ERROR response on CONNECT). (Lorenzo Fontana)
193 | - Fixed bug #64671 (Add stomp_nack and Stomp::nack functions). (Pierrick)
194 |
195 |
196 |
197 | 1.0.51.0.5
198 | stablestable
199 | PHP License
200 | 2012-11-18
201 |
202 | - Fix memory leak when Stomp can't write the message on the queue. (Pierrick)
203 | - Add a buffer for receipts. (Pierrick)
204 | - Fixed bug #62831 (Stomp module seems not initializing SSL library first).
205 | (Patch by lwhsu at lwhsu dot org)
206 | - Fixed bug #59972 (Message body are not binary safe). (Pierrick)
207 |
208 |
209 |
210 | 1.0.41.0.4
211 | stablestable
212 | PHP License
213 | 2012-09-17
214 |
215 | - Fix compatibility with 5.4
216 |
217 |
218 |
219 | 1.0.31.0.3
220 | stablestable
221 | PHP License
222 | 2010-10-12
223 |
224 | - Fixed bug #18772 (setTimeout usecs not honored)
225 |
226 |
227 |
228 | 1.0.21.0.2
229 | stablestable
230 | PHP License
231 | 2010-08-13
232 |
233 | - Fixed SSL connection bug introduced in 1.0.1
234 |
235 |
236 |
237 | 1.0.11.0.1
238 | stablestable
239 | PHP License
240 | 2010-08-03
241 |
242 | - Add new parameter to the constructor to allow client to send extra informations
243 | - Add zend engine runtime cache support (introduced into trunk)
244 | - Add new details property in the StompException class
245 | - Add new StompException::getDetails() method
246 | - Add the frame body content in the Stomp::Error() method
247 | - Fixed bug #17262 (Server is not responding on win32)
248 |
249 |
250 |
251 | 1.0.01.0.0
252 | stablestable
253 | PHP License
254 | 2010-02-11
255 |
256 | - Bump to stable
257 |
258 |
259 |
260 | 0.4.10.4.1
261 | betabeta
262 | PHP License
263 | 2010-01-19
264 |
265 | - Fix compilation issue on PHP5.2 branch
266 |
267 |
268 |
269 | 0.4.00.4.0
270 | betabeta
271 | PHP License
272 | 2010-01-17
273 |
274 | - Adds the ability to specify an alternative class for readFrame
275 |
276 |
277 |
278 | 0.3.20.3.2
279 | betabeta
280 | PHP License
281 | 2009-11-22
282 |
283 | - Adds alt class
284 | - Fixed bug #16936 (Module segfaults on readFrame if Frame > STOMP_BUFSIZE)
285 | - Fixed bug #16933 (readFrame does not notice when server shuts down)
286 | - Fixed bug #16930 (readFrame reports error-frames as "timeout")
287 |
288 |
289 |
290 | 0.3.10.3.1
291 | betabeta
292 | PHP License
293 | 2009-11-08
294 |
295 | - Fix memory leak in stomp_send and in stomp_ack
296 | - Reduced minimum php version to 5.2.2
297 |
298 |
299 |
300 | 0.3.00.3.0
301 | betabeta
302 | PHP License
303 | 2009-11-06
304 |
305 | - new stomp_connect_error() function (pierrick)
306 | - stomp_begin, stomp_abort and stomp_commit now accept additional headers (pierrick)
307 | - new connection timeout and read timeout ini configuration (pierrick)
308 | - Fix a memory leak in stomp_read_line (pierrick)
309 | - Better set of test (Pierrick and Anis)
310 |
311 |
312 |
313 | 0.2.00.2.0
314 | betabeta
315 | PHP License
316 | 2009-11-01
317 |
318 | - Windows build fix (kalle)
319 | - Add SSL support (pierrick)
320 |
321 |
322 |
323 | 0.1.00.1.0
324 | alphaalpha
325 | PHP License
326 | 2009-10-30
327 |
328 | - Initial PECL release. (pierrick)
329 |
330 |
331 |
332 |
333 |
--------------------------------------------------------------------------------
/php_stomp.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Copyright (c) The PHP Group |
4 | +----------------------------------------------------------------------+
5 | | This source file is subject to version 3.01 of the PHP license, |
6 | | that is bundled with this package in the file LICENSE, and is |
7 | | available through the world-wide-web at the following url: |
8 | | http://www.php.net/license/3_01.txt |
9 | | If you did not receive a copy of the PHP license and are unable to |
10 | | obtain it through the world-wide-web, please send a note to |
11 | | license@php.net so we can mail you a copy immediately. |
12 | +----------------------------------------------------------------------+
13 | | Author: Pierrick Charron |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifdef HAVE_CONFIG_H
18 | #include "config.h"
19 | #endif
20 |
21 | #include "php.h"
22 | #include "php_ini.h"
23 | #include "zend_exceptions.h"
24 | #include "ext/standard/info.h"
25 | #include "ext/standard/url.h"
26 | #include "php_stomp.h"
27 | #include "Zend/zend_smart_str.h"
28 |
29 | #define GET_STOMP_OBJECT() ((stomp_object_t*) ((char *)Z_OBJ_P(getThis()) - XtOffsetOf(stomp_object_t, std)))
30 | #define FETCH_STOMP_RSRC(result, rsrc) do { \
31 | result = zend_fetch_resource_ex(rsrc, PHP_STOMP_RES_NAME, le_stomp); \
32 | } while (0)
33 |
34 | #define FETCH_STOMP_OBJECT do { \
35 | stomp_object_t *i_obj = GET_STOMP_OBJECT(); \
36 | if (!(stomp = i_obj->stomp)) { \
37 | php_error_docref(NULL , E_WARNING, PHP_STOMP_ERR_NO_CTR); \
38 | RETURN_FALSE; \
39 | } \
40 | } while (0)
41 |
42 | #define INIT_FRAME_HEADERS \
43 | zend_hash_init(frame.headers, 0, NULL, ZVAL_PTR_DTOR, 0);
44 |
45 | #define INIT_FRAME_L(frame, cmd, l) \
46 | frame.command = cmd; \
47 | frame.command_length = l; \
48 | ALLOC_HASHTABLE(frame.headers); \
49 | INIT_FRAME_HEADERS
50 |
51 | #define INIT_FRAME(frame, cmd) INIT_FRAME_L(frame, cmd, sizeof(cmd)-1)
52 |
53 | #define FRAME_HEADER_FROM_HASHTABLE(h, p) do { \
54 | zval *value, _zv; \
55 | zend_string *key; \
56 | ZEND_HASH_FOREACH_STR_KEY_VAL((p), key, value) { \
57 | if (key == NULL) { \
58 | php_error_docref(NULL , E_WARNING, "Invalid argument or parameter array"); \
59 | break; \
60 | } else { \
61 | if (strncmp(ZSTR_VAL(key), "content-length", sizeof("content-length")) != 0) { \
62 | ZVAL_STR(&_zv, zval_get_string(value)); \
63 | zend_hash_add((h), key, &_zv); \
64 | } \
65 | } \
66 | } ZEND_HASH_FOREACH_END(); \
67 | } while (0)
68 |
69 | #define CLEAR_FRAME(frame) \
70 | zend_hash_destroy(frame.headers); \
71 | efree(frame.headers);
72 |
73 | #define THROW_STOMP_EXCEPTION(excobj, errnum, error) \
74 | ZVAL_OBJ(excobj, zend_throw_exception_ex(stomp_ce_exception, errnum, "%s", error));
75 |
76 | #define STOMP_ERROR(errno, msg) \
77 | STOMP_G(error_no) = errno; \
78 | if (STOMP_G(error_msg)) { \
79 | efree(STOMP_G(error_msg)); \
80 | } \
81 | STOMP_G(error_msg) = estrdup(msg); \
82 | if (stomp_object) { \
83 | zend_throw_exception_ex(stomp_ce_exception, errno , msg); \
84 | }
85 |
86 | #define STOMP_ERROR_DETAILS(errno, msg, details) \
87 | STOMP_G(error_no) = errno; \
88 | if (STOMP_G(error_msg)) { \
89 | efree(STOMP_G(error_msg)); \
90 | } \
91 | STOMP_G(error_msg) = estrdup(msg); \
92 | if (stomp_object) { \
93 | zval _object, *object = &_object; \
94 | THROW_STOMP_EXCEPTION(object, errno, msg) \
95 | if (details) { \
96 | zend_update_property_string(stomp_ce_exception, OBJ_FOR_PROP(object), "details", sizeof("details")-1, (char *) details ); \
97 | } \
98 | }
99 |
100 | #if PHP_VERSION_ID < 70300
101 | #define STOMP_URL_STR(a) (a)
102 | #else
103 | #define STOMP_URL_STR(a) ZSTR_VAL(a)
104 | #endif
105 |
106 | #if PHP_VERSION_ID < 80000
107 | #define OBJ_FOR_PROP(zv) (zv)
108 | #else
109 | #define OBJ_FOR_PROP(zv) Z_OBJ_P(zv)
110 | #endif
111 |
112 | static int le_stomp;
113 | static zend_object_handlers stomp_obj_handlers;
114 |
115 | ZEND_DECLARE_MODULE_GLOBALS(stomp)
116 | static PHP_GINIT_FUNCTION(stomp);
117 |
118 | /* {{{ stomp_class_entry */
119 | zend_class_entry *stomp_ce_stomp;
120 | zend_class_entry *stomp_ce_exception;
121 | zend_class_entry *stomp_ce_frame;
122 | /* }}} */
123 |
124 | /* {{{ arg_info */
125 | ZEND_BEGIN_ARG_INFO_EX(stomp_no_args, 0, 0, 0)
126 | ZEND_END_ARG_INFO()
127 |
128 | ZEND_BEGIN_ARG_INFO_EX(stomp_connect_args, 0, 0, 0)
129 | ZEND_ARG_INFO(0, broker)
130 | ZEND_ARG_INFO(0, username)
131 | ZEND_ARG_INFO(0, password)
132 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
133 | ZEND_END_ARG_INFO()
134 |
135 | ZEND_BEGIN_ARG_INFO_EX(stomp_link_only, 0, 0, 1)
136 | ZEND_ARG_INFO(0, link)
137 | ZEND_END_ARG_INFO()
138 |
139 | ZEND_BEGIN_ARG_INFO_EX(stomp_send_args, 0, 0, 3)
140 | ZEND_ARG_INFO(0, link)
141 | ZEND_ARG_INFO(0, destination)
142 | ZEND_ARG_INFO(0, msg)
143 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
144 | ZEND_END_ARG_INFO()
145 |
146 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_send_args, 0, 0, 2)
147 | ZEND_ARG_INFO(0, destination)
148 | ZEND_ARG_INFO(0, msg)
149 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
150 | ZEND_END_ARG_INFO()
151 |
152 | ZEND_BEGIN_ARG_INFO_EX(stomp_subscribe_args, 0, 0, 2)
153 | ZEND_ARG_INFO(0, link)
154 | ZEND_ARG_INFO(0, destination)
155 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
156 | ZEND_END_ARG_INFO()
157 |
158 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_subscribe_args, 0, 0, 1)
159 | ZEND_ARG_INFO(0, destination)
160 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
161 | ZEND_END_ARG_INFO()
162 |
163 | ZEND_BEGIN_ARG_INFO_EX(stomp_readframe_args, 0, 0, 1)
164 | ZEND_ARG_INFO(0, link)
165 | ZEND_ARG_INFO(0, class_name)
166 | ZEND_END_ARG_INFO()
167 |
168 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_readframe_args, 0, 0, 0)
169 | ZEND_ARG_INFO(0, class_name)
170 | ZEND_END_ARG_INFO()
171 |
172 | ZEND_BEGIN_ARG_INFO_EX(stomp_transaction_args, 0, 0, 2)
173 | ZEND_ARG_INFO(0, link)
174 | ZEND_ARG_INFO(0, transaction_id)
175 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
176 | ZEND_END_ARG_INFO()
177 |
178 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_transaction_args, 0, 0, 1)
179 | ZEND_ARG_INFO(0, transaction_id)
180 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
181 | ZEND_END_ARG_INFO()
182 |
183 | ZEND_BEGIN_ARG_INFO_EX(stomp_ack_args, 0, 0, 2)
184 | ZEND_ARG_INFO(0, link)
185 | ZEND_ARG_INFO(0, msg)
186 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
187 | ZEND_END_ARG_INFO()
188 |
189 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_ack_args, 0, 0, 1)
190 | ZEND_ARG_INFO(0, msg)
191 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
192 | ZEND_END_ARG_INFO()
193 |
194 | ZEND_BEGIN_ARG_INFO_EX(stomp_nack_args, 0, 0, 2)
195 | ZEND_ARG_INFO(0, link)
196 | ZEND_ARG_INFO(0, msg)
197 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
198 | ZEND_END_ARG_INFO()
199 |
200 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_nack_args, 0, 0, 1)
201 | ZEND_ARG_INFO(0, msg)
202 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
203 | ZEND_END_ARG_INFO()
204 |
205 | ZEND_BEGIN_ARG_INFO_EX(stomp_set_read_timeout_args, 0, 0, 2)
206 | ZEND_ARG_INFO(0, link)
207 | ZEND_ARG_INFO(0, seconds)
208 | ZEND_ARG_INFO(0, microseconds)
209 | ZEND_END_ARG_INFO()
210 |
211 | ZEND_BEGIN_ARG_INFO_EX(stomp_oop_set_read_timeout_args, 0, 0, 1)
212 | ZEND_ARG_INFO(0, seconds)
213 | ZEND_ARG_INFO(0, microseconds)
214 | ZEND_END_ARG_INFO()
215 |
216 | ZEND_BEGIN_ARG_INFO_EX(stomp_frame_construct_args, 0, 0, 0)
217 | ZEND_ARG_INFO(0, command)
218 | ZEND_ARG_ARRAY_INFO(0, headers, 1)
219 | ZEND_ARG_INFO(0, body)
220 | ZEND_END_ARG_INFO()
221 | /* }}} */
222 |
223 | /* {{{ stomp_functions */
224 | zend_function_entry stomp_functions[] = {
225 | PHP_FE(stomp_version, stomp_no_args)
226 | PHP_FE(stomp_connect, stomp_connect_args)
227 | PHP_FE(stomp_connect_error, stomp_no_args)
228 | PHP_FE(stomp_get_session_id, stomp_link_only)
229 | PHP_FE(stomp_close, stomp_link_only)
230 | PHP_FE(stomp_send, stomp_send_args)
231 | PHP_FE(stomp_subscribe, stomp_subscribe_args)
232 | PHP_FE(stomp_has_frame, stomp_link_only)
233 | PHP_FE(stomp_read_frame, stomp_readframe_args)
234 | PHP_FE(stomp_unsubscribe, stomp_subscribe_args)
235 | PHP_FE(stomp_begin, stomp_transaction_args)
236 | PHP_FE(stomp_commit, stomp_transaction_args)
237 | PHP_FE(stomp_abort, stomp_transaction_args)
238 | PHP_FE(stomp_ack, stomp_ack_args)
239 | PHP_FE(stomp_nack, stomp_nack_args)
240 | PHP_FE(stomp_error, stomp_link_only)
241 | PHP_FE(stomp_set_read_timeout, stomp_set_read_timeout_args)
242 | PHP_FE(stomp_get_read_timeout, stomp_link_only)
243 | {NULL, NULL, NULL}
244 | };
245 | /* }}} */
246 |
247 | /* {{{ stomp_methods[] */
248 | static zend_function_entry stomp_methods[] = {
249 | PHP_FALIAS(__construct, stomp_connect, stomp_connect_args)
250 | PHP_FALIAS(getSessionId, stomp_get_session_id, stomp_no_args)
251 | PHP_FALIAS(__destruct, stomp_close, stomp_no_args)
252 | PHP_FALIAS(send, stomp_send, stomp_oop_send_args)
253 | PHP_FALIAS(subscribe, stomp_subscribe, stomp_oop_subscribe_args)
254 | PHP_FALIAS(hasFrame, stomp_has_frame, stomp_no_args)
255 | PHP_FALIAS(readFrame, stomp_read_frame, stomp_oop_readframe_args)
256 | PHP_FALIAS(unsubscribe, stomp_unsubscribe, stomp_oop_subscribe_args)
257 | PHP_FALIAS(begin, stomp_begin, stomp_oop_transaction_args)
258 | PHP_FALIAS(commit, stomp_commit, stomp_oop_transaction_args)
259 | PHP_FALIAS(abort, stomp_abort, stomp_oop_transaction_args)
260 | PHP_FALIAS(ack, stomp_ack, stomp_oop_ack_args)
261 | PHP_FALIAS(nack, stomp_nack, stomp_oop_nack_args)
262 | PHP_FALIAS(error, stomp_error, stomp_no_args)
263 | PHP_FALIAS(setReadTimeout, stomp_set_read_timeout, stomp_oop_set_read_timeout_args)
264 | PHP_FALIAS(getReadTimeout, stomp_get_read_timeout, stomp_no_args)
265 | {NULL, NULL, NULL}
266 | };
267 | /* }}} */
268 |
269 | /* {{{ stomp_frame_methods[] */
270 | static zend_function_entry stomp_frame_methods[] = {
271 | PHP_ME(stompframe, __construct, stomp_frame_construct_args, ZEND_ACC_PUBLIC)
272 | {NULL, NULL, NULL}
273 | };
274 | /* }}} */
275 |
276 | /* {{{ stomp_exception_methods[] */
277 | static zend_function_entry stomp_exception_methods[] = {
278 | PHP_ME(stompexception, getDetails, stomp_no_args, ZEND_ACC_PUBLIC)
279 | {NULL, NULL, NULL}
280 | };
281 | /* }}} */
282 |
283 | /* {{{ stomp_module_entry */
284 | zend_module_entry stomp_module_entry = {
285 | STANDARD_MODULE_HEADER,
286 | PHP_STOMP_EXTNAME,
287 | stomp_functions,
288 | PHP_MINIT(stomp),
289 | PHP_MSHUTDOWN(stomp),
290 | PHP_RINIT(stomp),
291 | PHP_RSHUTDOWN(stomp),
292 | PHP_MINFO(stomp),
293 | PHP_STOMP_VERSION,
294 | PHP_MODULE_GLOBALS(stomp),
295 | PHP_GINIT(stomp),
296 | NULL,
297 | NULL,
298 | STANDARD_MODULE_PROPERTIES_EX
299 | };
300 | /* }}} */
301 |
302 | PHP_INI_BEGIN()
303 | STD_PHP_INI_ENTRY("stomp.default_broker", "tcp://localhost:61613", PHP_INI_ALL, OnUpdateString, default_broker, zend_stomp_globals, stomp_globals)
304 | STD_PHP_INI_ENTRY("stomp.default_username", "", PHP_INI_ALL, OnUpdateString, default_username, zend_stomp_globals, stomp_globals)
305 | STD_PHP_INI_ENTRY("stomp.default_password", "", PHP_INI_ALL, OnUpdateString, default_password, zend_stomp_globals, stomp_globals)
306 | STD_PHP_INI_ENTRY("stomp.default_read_timeout_sec", "2", PHP_INI_ALL, OnUpdateLong, read_timeout_sec, zend_stomp_globals, stomp_globals)
307 | STD_PHP_INI_ENTRY("stomp.default_read_timeout_usec", "0", PHP_INI_ALL, OnUpdateLong, read_timeout_usec, zend_stomp_globals, stomp_globals)
308 | STD_PHP_INI_ENTRY("stomp.default_connection_timeout_sec", "2", PHP_INI_ALL, OnUpdateLong, connection_timeout_sec, zend_stomp_globals, stomp_globals)
309 | STD_PHP_INI_ENTRY("stomp.default_connection_timeout_usec", "0", PHP_INI_ALL, OnUpdateLong, connection_timeout_usec, zend_stomp_globals, stomp_globals)
310 | PHP_INI_END()
311 |
312 | /* {{{ PHP_GINIT_FUNCTION */
313 | static PHP_GINIT_FUNCTION(stomp)
314 | {
315 | stomp_globals->default_broker = NULL;
316 | stomp_globals->default_username = NULL;
317 | stomp_globals->default_password = NULL;
318 | stomp_globals->read_timeout_sec = 2;
319 | stomp_globals->read_timeout_usec = 0;
320 | stomp_globals->connection_timeout_sec = 2;
321 | stomp_globals->connection_timeout_usec = 0;
322 | #if HAVE_STOMP_SSL
323 | SSL_library_init();
324 | #endif
325 | }
326 | /* }}} */
327 |
328 | ZEND_DECLARE_MODULE_GLOBALS(stomp)
329 |
330 | #ifdef COMPILE_DL_STOMP
331 | ZEND_GET_MODULE(stomp)
332 | #endif
333 |
334 | /* {{{ constructor/destructor */
335 | static void stomp_send_disconnect(stomp_t *stomp)
336 | {
337 | stomp_frame_t frame = {0};
338 | INIT_FRAME(frame, "DISCONNECT");
339 |
340 | stomp_send(stomp, &frame );
341 | CLEAR_FRAME(frame);
342 | }
343 |
344 | static void php_destroy_stomp_res(zend_resource *rsrc)
345 | {
346 | stomp_t *stomp = (stomp_t *) rsrc->ptr;
347 | stomp_send_disconnect(stomp );
348 | stomp_close(stomp);
349 | }
350 |
351 | static zend_object *php_stomp_new(zend_class_entry *ce)
352 | {
353 | stomp_object_t *intern;
354 |
355 | intern = (stomp_object_t *) ecalloc(1, sizeof(stomp_object_t) + zend_object_properties_size(ce));
356 | intern->stomp = NULL;
357 |
358 | zend_object_std_init(&intern->std, ce );
359 |
360 | intern->std.handlers = &stomp_obj_handlers;
361 |
362 | return &intern->std;
363 | }
364 | /* }}} */
365 |
366 | /* {{{ PHP_MINIT_FUNCTION */
367 | PHP_MINIT_FUNCTION(stomp)
368 | {
369 | zend_class_entry ce;
370 |
371 | /* Ressource */
372 | le_stomp = zend_register_list_destructors_ex(php_destroy_stomp_res, NULL, PHP_STOMP_RES_NAME, module_number);
373 |
374 | /* Register Stomp class */
375 | INIT_CLASS_ENTRY(ce, PHP_STOMP_CLASSNAME, stomp_methods);
376 | stomp_ce_stomp = zend_register_internal_class(&ce );
377 | stomp_ce_stomp->create_object = php_stomp_new;
378 | memcpy(&stomp_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
379 | stomp_obj_handlers.offset = XtOffsetOf(stomp_object_t, std);
380 |
381 | /* Register StompFrame class */
382 | INIT_CLASS_ENTRY(ce, PHP_STOMP_FRAME_CLASSNAME, stomp_frame_methods);
383 | stomp_ce_frame = zend_register_internal_class(&ce );
384 |
385 | /* Properties */
386 | zend_declare_property_null(stomp_ce_frame, "command", sizeof("command")-1, ZEND_ACC_PUBLIC );
387 | zend_declare_property_null(stomp_ce_frame, "headers", sizeof("headers")-1, ZEND_ACC_PUBLIC );
388 | zend_declare_property_null(stomp_ce_frame, "body", sizeof("body")-1, ZEND_ACC_PUBLIC );
389 |
390 | /* Register StompException class */
391 | INIT_CLASS_ENTRY(ce, PHP_STOMP_EXCEPTION_CLASSNAME, stomp_exception_methods);
392 | stomp_ce_exception = zend_register_internal_class_ex(&ce, zend_exception_get_default());
393 |
394 | /* Properties */
395 | zend_declare_property_null(stomp_ce_exception, "details", sizeof("details")-1, ZEND_ACC_PRIVATE );
396 |
397 | /** Register INI entries **/
398 | REGISTER_INI_ENTRIES();
399 |
400 | return SUCCESS;
401 | }
402 | /* }}} */
403 |
404 | /* {{{ PHP_MSHUTDOWN_FUNCTION */
405 | PHP_MSHUTDOWN_FUNCTION(stomp)
406 | {
407 | /* Unregister INI entries */
408 | UNREGISTER_INI_ENTRIES();
409 | return SUCCESS;
410 | }
411 | /* }}} */
412 |
413 | /* {{{ PHP_RINIT_FUNCTION */
414 | PHP_RINIT_FUNCTION(stomp)
415 | {
416 | STOMP_G(error_msg) = NULL;
417 | STOMP_G(error_no) = 0;
418 |
419 | return SUCCESS;
420 | }
421 | /* }}} */
422 |
423 | /* {{{ PHP_RSHUTDOWN_FUNCTION */
424 | PHP_RSHUTDOWN_FUNCTION(stomp)
425 | {
426 | if (STOMP_G(error_msg)) {
427 | efree(STOMP_G(error_msg));
428 | }
429 |
430 | return SUCCESS;
431 | }
432 | /* }}} */
433 |
434 | /* {{{ PHP_MINFO_FUNCTION */
435 | PHP_MINFO_FUNCTION(stomp)
436 | {
437 | php_info_print_table_start();
438 | php_info_print_table_header(2, PHP_STOMP_EXTNAME, "enabled");
439 | php_info_print_table_row(2, "API version", PHP_STOMP_VERSION);
440 | #if HAVE_STOMP_SSL
441 | php_info_print_table_row(2, "SSL Support", "enabled");
442 | #else
443 | php_info_print_table_row(2, "SSL Support", "disabled");
444 | #endif
445 | php_info_print_table_end();
446 | DISPLAY_INI_ENTRIES();
447 | }
448 | /* }}} */
449 |
450 | /* {{{ proto string stomp_version()
451 | Get stomp extension version */
452 | PHP_FUNCTION(stomp_version)
453 | {
454 | RETURN_STRINGL(PHP_STOMP_VERSION, sizeof(PHP_STOMP_VERSION)-1);
455 | }
456 | /* }}} */
457 |
458 | /* {{{ proto Stomp::__construct([string broker [, string username [, string password [, array headers]]]])
459 | Connect to server */
460 | PHP_FUNCTION(stomp_connect)
461 | {
462 | zval *stomp_object = getThis();
463 | zval *headers = NULL;
464 | stomp_t *stomp = NULL;
465 | zend_string *broker = NULL, *username = NULL, *password = NULL;
466 | php_url *url_parts;
467 |
468 | #ifdef HAVE_STOMP_SSL
469 | int use_ssl = 0;
470 | #endif
471 |
472 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "|SSSa!", &broker, &username, &password, &headers) == FAILURE) {
473 | return;
474 | }
475 |
476 | /* Verify that broker URI */
477 | if (!broker) {
478 | broker = STOMP_G(default_broker)?
479 | zend_string_init(STOMP_G(default_broker), strlen(STOMP_G(default_broker)), 0) : NULL;
480 | } else {
481 | zend_string_copy(broker);
482 | }
483 |
484 | url_parts = php_url_parse_ex(ZSTR_VAL(broker), ZSTR_LEN(broker));
485 |
486 | if (!url_parts || !url_parts->host) {
487 | STOMP_ERROR(0, PHP_STOMP_ERR_INVALID_BROKER_URI);
488 | zend_string_release(broker);
489 | php_url_free(url_parts);
490 | return;
491 | }
492 | zend_string_release(broker);
493 |
494 | if (url_parts->scheme) {
495 | if (strcmp(STOMP_URL_STR(url_parts->scheme), "ssl") == 0) {
496 | #if HAVE_STOMP_SSL
497 | use_ssl = 1;
498 | #else
499 | STOMP_ERROR(0, "SSL DISABLED");
500 | php_url_free(url_parts);
501 | return;
502 | #endif
503 | } else if (strcmp(STOMP_URL_STR(url_parts->scheme), "tcp") != 0) {
504 | STOMP_ERROR(0, PHP_STOMP_ERR_INVALID_BROKER_URI_SCHEME);
505 | php_url_free(url_parts);
506 | return;
507 | }
508 | }
509 |
510 | stomp = stomp_init();
511 |
512 | #if HAVE_STOMP_SSL
513 | stomp->options.use_ssl = use_ssl;
514 | #endif
515 |
516 | stomp->options.read_timeout_sec = STOMP_G(read_timeout_sec);
517 | stomp->options.read_timeout_usec = STOMP_G(read_timeout_usec);
518 | stomp->options.connect_timeout_sec = STOMP_G(connection_timeout_sec);
519 | stomp->options.connect_timeout_usec = STOMP_G(connection_timeout_usec);
520 |
521 | stomp->status = stomp_connect(stomp, STOMP_URL_STR(url_parts->host), url_parts->port ? url_parts->port : 61613 );
522 | php_url_free(url_parts);
523 |
524 | if (stomp->status) {
525 | zval rv;
526 | stomp_frame_t *res;
527 | stomp_frame_t frame = {0};
528 | int send_status;
529 |
530 | INIT_FRAME(frame, "CONNECT");
531 | if (!username) {
532 | username = zend_string_init(STOMP_G(default_username), strlen(STOMP_G(default_username)), 0);
533 | } else {
534 | zend_string_copy(username);
535 | }
536 |
537 | if (!password) {
538 | password = zend_string_init(STOMP_G(default_password), strlen(STOMP_G(default_password)), 0);
539 | } else {
540 | zend_string_copy(password);
541 | }
542 |
543 | /*
544 | * Per Stomp 1.1 "login" and "passcode" are optional. (Also this fix makes test pass against RabbitMQ)
545 | */
546 | if (ZSTR_LEN(username) > 0) {
547 | ZVAL_STR(&rv, zend_string_copy(username));
548 | zend_hash_str_add(frame.headers, "login", sizeof("login") - 1, &rv);
549 | }
550 |
551 | if (ZSTR_LEN(password)) {
552 | ZVAL_STR(&rv, zend_string_copy(password));
553 | zend_hash_str_add(frame.headers, "passcode", sizeof("passcode"), &rv);
554 | }
555 |
556 | zend_string_release(username);
557 | zend_string_release(password);
558 |
559 | if (NULL != headers) {
560 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(headers));
561 | }
562 |
563 | send_status = stomp_send(stomp, &frame );
564 | CLEAR_FRAME(frame);
565 | if (0 == send_status) {
566 | zval excobj;
567 | THROW_STOMP_EXCEPTION(&excobj, stomp->errnum, stomp->error);
568 | if (stomp->error_details) {
569 | zend_update_property_string(stomp_ce_exception, OBJ_FOR_PROP(&excobj), "details", sizeof("details")-1, stomp->error_details );
570 | }
571 | return;
572 | }
573 |
574 | /* Retreive Response */
575 | res = stomp_read_frame_ex(stomp, 0);
576 | if (NULL == res) {
577 | STOMP_ERROR(0, PHP_STOMP_ERR_SERVER_NOT_RESPONDING);
578 | } else if (0 == strncmp("ERROR", res->command, sizeof("ERROR") - 1)) {
579 | zval *error_msg, excobj;
580 | if ((error_msg = zend_hash_str_find(res->headers, ZEND_STRL("message"))) != NULL) {
581 | THROW_STOMP_EXCEPTION(&excobj, 0, ZSTR_VAL(Z_STR_P(error_msg)));
582 | if (res->body) {
583 | zend_update_property_string(stomp_ce_exception, OBJ_FOR_PROP(&excobj), "details", sizeof("details")-1, (char *) res->body );
584 | }
585 | }
586 | stomp_free_frame(res);
587 | } else if (0 != strncmp("CONNECTED", res->command, sizeof("CONNECTED")-1)) {
588 | if (stomp->error) {
589 | STOMP_ERROR_DETAILS(stomp->errnum, stomp->error, stomp->error_details);
590 | } else {
591 | STOMP_ERROR(0, PHP_STOMP_ERR_UNKNOWN);
592 | }
593 | stomp_free_frame(res);
594 | } else {
595 | zval *key;
596 | if ((key = zend_hash_str_find(res->headers, ZEND_STRL("session"))) != NULL) {
597 | if (stomp->session) {
598 | efree(stomp->session);
599 | }
600 | ZEND_ASSERT(Z_TYPE_P(key) == IS_STRING);
601 | stomp->session = estrdup(Z_STRVAL_P(key));
602 | }
603 | stomp_free_frame(res);
604 | if (!stomp_object) {
605 | RETURN_RES(zend_register_resource(stomp, le_stomp));
606 | } else {
607 | stomp_object_t *i_obj = GET_STOMP_OBJECT();
608 | if (i_obj->stomp) {
609 | stomp_close(i_obj->stomp);
610 | }
611 | i_obj->stomp = stomp;
612 | RETURN_TRUE;
613 | }
614 | }
615 | } else {
616 | STOMP_ERROR_DETAILS(0, stomp->error, stomp->error_details);
617 | }
618 |
619 | stomp_close(stomp);
620 | RETURN_FALSE;
621 | }
622 | /* }}} */
623 |
624 | /* {{{ proto string stomp_connect_error()
625 | Get the last connection error */
626 | PHP_FUNCTION(stomp_connect_error)
627 | {
628 | if (STOMP_G(error_msg)) {
629 | RETURN_STRING(STOMP_G(error_msg));
630 | } else {
631 | RETURN_NULL();
632 | }
633 | }
634 | /* }}} */
635 |
636 | /* {{{ proto string Stomp::getSessionId()
637 | Get the current stomp session ID */
638 | PHP_FUNCTION(stomp_get_session_id)
639 | {
640 | zval *stomp_object = getThis();
641 | stomp_t *stomp = NULL;
642 | if (stomp_object) {
643 | FETCH_STOMP_OBJECT;
644 | } else {
645 | zval *arg;
646 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "r", &arg) == FAILURE) {
647 | return;
648 | }
649 | FETCH_STOMP_RSRC(stomp, arg);
650 | }
651 |
652 | if (!stomp) {
653 | php_error_docref(NULL , E_WARNING, PHP_STOMP_ERR_NO_CTR);
654 | RETURN_FALSE;
655 | }
656 |
657 | if (stomp->session) {
658 | RETURN_STRING(stomp->session);
659 | } else {
660 | RETURN_FALSE;
661 | }
662 | }
663 | /* }}} */
664 |
665 | /* {{{ proto boolean Stomp::__destruct()
666 | Close stomp connection */
667 | PHP_FUNCTION(stomp_close)
668 | {
669 | zval *stomp_object = getThis();
670 | stomp_t *stomp = NULL;
671 |
672 | if (stomp_object) {
673 | stomp_object_t *i_obj = GET_STOMP_OBJECT();
674 | if (!(stomp = i_obj->stomp)) {
675 | php_error_docref(NULL , E_WARNING, PHP_STOMP_ERR_NO_CTR);
676 | RETURN_FALSE;
677 | }
678 | stomp_send_disconnect(stomp );
679 | stomp_close(stomp);
680 | i_obj->stomp = NULL;
681 | } else {
682 | zval *arg;
683 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "r", &arg) == FAILURE) {
684 | return;
685 | }
686 | FETCH_STOMP_RSRC(stomp, arg);
687 | zend_list_close(Z_RES_P(arg));
688 | }
689 |
690 | RETURN_TRUE;
691 | }
692 | /* }}} */
693 |
694 | /* {{{ proto boolean Stomp::send(string destination, mixed msg [, array headers])
695 | Sends a message to a destination in the messaging system */
696 | PHP_FUNCTION(stomp_send)
697 | {
698 | zval *stomp_object = getThis();
699 | stomp_t *stomp = NULL;
700 | zend_string *destination;
701 | zval *msg, *headers = NULL, rv;
702 | stomp_frame_t frame = {0};
703 | int success = 0;
704 |
705 | if (stomp_object) {
706 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "Sz|a!", &destination, &msg, &headers) == FAILURE) {
707 | return;
708 | }
709 | FETCH_STOMP_OBJECT;
710 | } else {
711 | zval *arg;
712 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "rSz|a!", &arg, &destination, &msg, &headers) == FAILURE) {
713 | return;
714 | }
715 | FETCH_STOMP_RSRC(stomp, arg);
716 | }
717 |
718 | /* Verify destination */
719 | if (0 == ZSTR_LEN(destination)) {
720 | php_error_docref(NULL , E_WARNING, PHP_STOMP_ERR_EMPTY_DESTINATION);
721 | RETURN_FALSE;
722 | }
723 |
724 | INIT_FRAME(frame, "SEND");
725 |
726 | /* Translate a PHP array to a stomp_header array */
727 | if (NULL != headers) {
728 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(headers));
729 | }
730 |
731 | /* Add the destination */
732 | ZVAL_STR(&rv, zend_string_copy(destination));
733 | zend_hash_str_add(frame.headers, "destination", sizeof("destination") - 1, &rv);
734 |
735 | if (Z_TYPE_P(msg) == IS_STRING) {
736 | frame.body = Z_STRVAL_P(msg);
737 | frame.body_length = Z_STRLEN_P(msg);
738 | } else if (Z_TYPE_P(msg) == IS_OBJECT && instanceof_function(Z_OBJCE_P(msg), stomp_ce_frame )) {
739 | zval *frame_obj_prop = NULL;
740 | frame_obj_prop = zend_read_property(stomp_ce_frame, OBJ_FOR_PROP(msg), "command", sizeof("command")-1, 1, &rv);
741 | if (Z_TYPE_P(frame_obj_prop) == IS_STRING) {
742 | frame.command = Z_STRVAL_P(frame_obj_prop);
743 | frame.command_length = Z_STRLEN_P(frame_obj_prop);
744 | }
745 | frame_obj_prop = zend_read_property(stomp_ce_frame, OBJ_FOR_PROP(msg), "body", sizeof("body")-1, 1, &rv);
746 | if (Z_TYPE_P(frame_obj_prop) == IS_STRING) {
747 | frame.body = Z_STRVAL_P(frame_obj_prop);
748 | frame.body_length = Z_STRLEN_P(frame_obj_prop);
749 | }
750 | frame_obj_prop = zend_read_property(stomp_ce_frame, OBJ_FOR_PROP(msg), "headers", sizeof("headers")-1, 1, &rv);
751 | if (Z_TYPE_P(frame_obj_prop) == IS_ARRAY) {
752 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(frame_obj_prop));
753 | }
754 | } else {
755 | php_error_docref(NULL , E_WARNING, "Expects parameter %d to be a string or a StompFrame object.", stomp_object?2:3);
756 | CLEAR_FRAME(frame);
757 | RETURN_FALSE;
758 | }
759 |
760 | if (stomp_send(stomp, &frame ) > 0) {
761 | success = stomp_valid_receipt(stomp, &frame);
762 | }
763 |
764 | CLEAR_FRAME(frame);
765 | RETURN_BOOL(success);
766 | }
767 | /* }}} */
768 |
769 | /* {{{ proto boolean Stomp::subscribe(string destination [, array headers])
770 | Register to listen to a given destination */
771 | PHP_FUNCTION(stomp_subscribe)
772 | {
773 | zval *stomp_object = getThis();
774 | stomp_t *stomp = NULL;
775 | zend_string *destination;
776 | zval *headers = NULL, rv;
777 | stomp_frame_t frame = {0};
778 | int success = 0;
779 |
780 | if (stomp_object) {
781 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "S|a!", &destination, &headers) == FAILURE) {
782 | return;
783 | }
784 | FETCH_STOMP_OBJECT;
785 | } else {
786 | zval *arg = NULL;
787 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "rS|a!", &arg, &destination, &headers) == FAILURE) {
788 | return;
789 | }
790 | FETCH_STOMP_RSRC(stomp, arg);
791 | }
792 |
793 | /* Verify destination */
794 | if (ZSTR_LEN(destination) == 0) {
795 | php_error_docref(NULL , E_WARNING, PHP_STOMP_ERR_EMPTY_DESTINATION);
796 | RETURN_FALSE;
797 | }
798 |
799 | INIT_FRAME(frame, "SUBSCRIBE");
800 |
801 | /* Translate a PHP array to a stomp_header array */
802 | if (NULL != headers) {
803 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(headers));
804 | }
805 |
806 | /* Add the ack if not already in the headers */
807 | if (!zend_hash_str_find(frame.headers, ZEND_STRL("ack"))) {
808 | ZVAL_STRINGL(&rv, "client", sizeof("client") - 1);
809 | zend_hash_str_update(frame.headers, "ack", sizeof("ack") - 1, &rv);
810 | }
811 |
812 | /* Add the destination */
813 | ZVAL_STR(&rv, zend_string_copy(destination));
814 | zend_hash_str_update(frame.headers, "destination", sizeof("destination") - 1, &rv);
815 | /* zend_hash_str_add_ptr(frame.headers, ZEND_STRL("activemq.prefetchSize"), estrdup("1")); */
816 |
817 | if (stomp_send(stomp, &frame ) > 0) {
818 | success = stomp_valid_receipt(stomp, &frame);
819 | }
820 |
821 | CLEAR_FRAME(frame);
822 | RETURN_BOOL(success);
823 | }
824 | /* }}} */
825 |
826 | /* {{{ proto boolean Stomp::unsubscribe(string destination [, array headers])
827 | Remove an existing subscription */
828 | PHP_FUNCTION(stomp_unsubscribe)
829 | {
830 | zval *stomp_object = getThis();
831 | stomp_t *stomp = NULL;
832 | zend_string *destination;
833 | zval *headers = NULL, rv;
834 | stomp_frame_t frame = {0};
835 | int success = 0;
836 |
837 | if (stomp_object) {
838 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "S|a!", &destination, &headers) == FAILURE) {
839 | return;
840 | }
841 | FETCH_STOMP_OBJECT;
842 | } else {
843 | zval *arg = NULL;
844 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "rS|a!", &arg, &destination, &headers) == FAILURE) {
845 | return;
846 | }
847 | FETCH_STOMP_RSRC(stomp, arg);
848 | }
849 |
850 | /* Verify destination */
851 | if (0 == ZSTR_LEN(destination)) {
852 | php_error_docref(NULL , E_WARNING, PHP_STOMP_ERR_EMPTY_DESTINATION);
853 | RETURN_FALSE;
854 | }
855 |
856 | INIT_FRAME(frame, "UNSUBSCRIBE");
857 |
858 | /* Translate a PHP array to a stomp_header array */
859 | if (NULL != headers) {
860 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(headers));
861 | }
862 |
863 | /* Add the destination */
864 | ZVAL_STR(&rv, zend_string_copy(destination));
865 | zend_hash_str_add(frame.headers, "destination", sizeof("destination") - 1, &rv);
866 |
867 | if (stomp_send(stomp, &frame ) > 0) {
868 | success = stomp_valid_receipt(stomp, &frame);
869 | }
870 |
871 | CLEAR_FRAME(frame);
872 | RETURN_BOOL(success);
873 | }
874 | /* }}} */
875 |
876 | /* {{{ proto boolean Stomp::hasFrame()
877 | Indicate whether or not there is a frame ready to read */
878 | PHP_FUNCTION(stomp_has_frame)
879 | {
880 | zval *stomp_object = getThis();
881 | stomp_t *stomp = NULL;
882 | if (stomp_object) {
883 | FETCH_STOMP_OBJECT;
884 | } else {
885 | zval *arg;
886 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "r", &arg) == FAILURE) {
887 | return;
888 | }
889 | FETCH_STOMP_RSRC(stomp, arg);
890 | }
891 |
892 | RETURN_BOOL(stomp_select(stomp) > 0);
893 | }
894 | /* }}} */
895 |
896 | /* {{{ proto StompFrame Stomp::readFrame()
897 | Read the next frame */
898 | PHP_FUNCTION(stomp_read_frame)
899 | {
900 | zval *stomp_object = getThis();
901 | stomp_t *stomp = NULL;
902 | stomp_frame_t *res = NULL;
903 | zend_string *class_name = NULL;
904 | zend_class_entry *ce = NULL;
905 |
906 | if (stomp_object) {
907 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "|S", &class_name) == FAILURE) {
908 | return;
909 | }
910 | FETCH_STOMP_OBJECT;
911 | } else {
912 | zval *arg;
913 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "r|S", &arg, &class_name) == FAILURE) {
914 | return;
915 | }
916 | FETCH_STOMP_RSRC(stomp, arg);
917 | }
918 |
919 | if (class_name && ZSTR_LEN(class_name)) {
920 | ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
921 | if (!ce) {
922 | php_error_docref(NULL , E_WARNING, "Could not find class '%s'", ZSTR_VAL(class_name));
923 | ce = stomp_ce_frame;
924 | }
925 | } else if (stomp_object) {
926 | ce = stomp_ce_frame;
927 | }
928 |
929 | if ((res = stomp_read_frame(stomp))) {
930 | zval headers;
931 |
932 | if (0 == strncmp("ERROR", res->command, sizeof("ERROR") - 1)) {
933 | zval *error_msg;
934 | if ((error_msg = zend_hash_str_find(res->headers, "message", sizeof("message") - 1)) != NULL) {
935 | zval excobj;
936 | THROW_STOMP_EXCEPTION(&excobj, 0, Z_STRVAL_P(error_msg));
937 | if (res->body) {
938 | zend_update_property_string(stomp_ce_exception, OBJ_FOR_PROP(&excobj), ZEND_STRL("details"), (char *)res->body );
939 | }
940 | stomp_free_frame(res);
941 | RETURN_FALSE;
942 | }
943 | }
944 |
945 | array_init(&headers);
946 | if (res->headers) {
947 | zend_string *key;
948 | zval *val;
949 | ZEND_HASH_FOREACH_STR_KEY_VAL(res->headers, key, val) {
950 | if (!key) {
951 | break;
952 | }
953 | Z_TRY_ADDREF_P(val);
954 | zend_hash_update(Z_ARRVAL(headers), key, val);
955 | } ZEND_HASH_FOREACH_END();
956 | }
957 |
958 | if (ce) {
959 | zend_fcall_info fci;
960 | zend_fcall_info_cache fcc;
961 | zval retval;
962 |
963 | object_init_ex(return_value, ce);
964 |
965 | if (ce->constructor) {
966 | zval cmd, body;
967 |
968 | ZVAL_STRINGL(&cmd, res->command, res->command_length);
969 |
970 | if (res->body) {
971 | ZVAL_STRINGL(&body, res->body, res->body_length);
972 | } else {
973 | ZVAL_NULL(&body);
974 | }
975 |
976 | memset(&fci, 0, sizeof(fci));
977 | memset(&fcc, 0, sizeof(fcc));
978 | fci.size = sizeof(fci);
979 | #if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
980 | fci.function_table = &ce->function_table;
981 | #endif
982 | /* PARAMS */
983 | fci.param_count = 3;
984 | fci.params = (zval*) safe_emalloc(sizeof(zval), 3, 0);
985 | ZVAL_COPY_VALUE(&fci.params[0], &cmd);
986 | ZVAL_COPY_VALUE(&fci.params[1], &headers);
987 | ZVAL_COPY_VALUE(&fci.params[2], &body);
988 |
989 | ZVAL_UNDEF(&fci.function_name);
990 | fci.object = Z_OBJ_P(return_value);
991 | fci.retval = &retval;
992 | #if PHP_VERSION_ID < 80000
993 | fci.no_separation = 1;
994 | #endif
995 | #if PHP_VERSION_ID < 70300
996 | fcc.initialized = 1;
997 | #endif
998 | fcc.function_handler = ce->constructor;
999 | #if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
1000 | fcc.calling_scope = EG(scope);
1001 | #else
1002 | fcc.calling_scope = zend_get_executed_scope();
1003 | #endif
1004 | fcc.object = Z_OBJ_P(return_value);
1005 |
1006 | if (zend_call_function(&fci, &fcc ) == FAILURE) {
1007 | zend_throw_exception_ex(zend_exception_get_default(), 0 , "Could not execute %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
1008 | } else {
1009 | zval_ptr_dtor(&retval);
1010 | }
1011 | if (fci.params) {
1012 | efree(fci.params);
1013 | }
1014 |
1015 | zval_ptr_dtor(&cmd);
1016 | zval_ptr_dtor(&body);
1017 | }
1018 |
1019 | zval_ptr_dtor(&headers);
1020 | } else {
1021 | array_init(return_value);
1022 | add_assoc_string_ex(return_value, "command", sizeof("command") - 1, res->command);
1023 | if (res->body) {
1024 | add_assoc_stringl_ex(return_value, "body", sizeof("body") - 1, res->body, res->body_length);
1025 | }
1026 | add_assoc_zval_ex(return_value, "headers", sizeof("headers") - 1, &headers);
1027 | }
1028 |
1029 | stomp_free_frame(res);
1030 | } else {
1031 | RETURN_FALSE;
1032 | }
1033 | }
1034 | /* }}} */
1035 |
1036 | /* {{{ _php_stomp_transaction */
1037 | static void _php_stomp_transaction(INTERNAL_FUNCTION_PARAMETERS, char *cmd, size_t cmd_len) {
1038 | zval *stomp_object = getThis();
1039 | stomp_t *stomp = NULL;
1040 | zend_string *transaction_id;
1041 | stomp_frame_t frame = {0};
1042 | int success = 0;
1043 | zval *headers = NULL, rv;
1044 |
1045 | if (stomp_object) {
1046 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "S!|a", &transaction_id, &headers) == FAILURE) {
1047 | return;
1048 | }
1049 | FETCH_STOMP_OBJECT;
1050 | } else {
1051 | zval *arg;
1052 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "rS!|a", &arg, &transaction_id, &headers) == FAILURE) {
1053 | return;
1054 | }
1055 | FETCH_STOMP_RSRC(stomp, arg);
1056 | }
1057 |
1058 | INIT_FRAME_L(frame, cmd, cmd_len);
1059 |
1060 | if (transaction_id && ZSTR_LEN(transaction_id)) {
1061 | ZVAL_STR(&rv, zend_string_copy(transaction_id));
1062 | zend_hash_str_add(frame.headers, "transaction", sizeof("transaction") - 1, &rv);
1063 | }
1064 |
1065 | /* Translate a PHP array to a stomp_header array */
1066 | if (NULL != headers) {
1067 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(headers));
1068 | }
1069 |
1070 | if (stomp_send(stomp, &frame ) > 0) {
1071 | success = stomp_valid_receipt(stomp, &frame);
1072 | }
1073 |
1074 | CLEAR_FRAME(frame);
1075 | RETURN_BOOL(success);
1076 | }
1077 | /* }}} */
1078 |
1079 | /* {{{ proto boolean Stomp::begin(string transactionId [, array headers ])
1080 | Start a transaction */
1081 | PHP_FUNCTION(stomp_begin)
1082 | {
1083 | _php_stomp_transaction(INTERNAL_FUNCTION_PARAM_PASSTHRU, "BEGIN", sizeof("BEGIN") - 1);
1084 | }
1085 | /* }}} */
1086 |
1087 | /* {{{ proto boolean Stomp::commit(string transactionId [, array headers ])
1088 | Commit a transaction in progress */
1089 | PHP_FUNCTION(stomp_commit)
1090 | {
1091 | _php_stomp_transaction(INTERNAL_FUNCTION_PARAM_PASSTHRU, "COMMIT", sizeof("COMMIT") - 1);
1092 | }
1093 | /* }}} */
1094 |
1095 | /* {{{ proto boolean Stomp::abort(string transactionId [, array headers ])
1096 | Rollback a transaction in progress */
1097 | PHP_FUNCTION(stomp_abort)
1098 | {
1099 | _php_stomp_transaction(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ABORT", sizeof("ABORT") - 1);
1100 | }
1101 | /* }}} */
1102 |
1103 | /* {{{ _php_stomp_acknowledgment
1104 | */
1105 | static void _php_stomp_acknowledgment(INTERNAL_FUNCTION_PARAMETERS, char *cmd) {
1106 | zval *stomp_object = getThis();
1107 | zval *msg, *headers = NULL;
1108 | stomp_t *stomp = NULL;
1109 | stomp_frame_t frame = {0};
1110 | int success = 0;
1111 |
1112 | if (stomp_object) {
1113 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "z|a!", &msg, &headers) == FAILURE) {
1114 | return;
1115 | }
1116 | FETCH_STOMP_OBJECT;
1117 | } else {
1118 | zval *arg;
1119 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "rz|a!", &arg, &msg, &headers) == FAILURE) {
1120 | return;
1121 | }
1122 | FETCH_STOMP_RSRC(stomp, arg);
1123 | }
1124 |
1125 | INIT_FRAME(frame, cmd);
1126 |
1127 | if (NULL != headers) {
1128 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(headers));
1129 | }
1130 |
1131 | if (Z_TYPE_P(msg) == IS_STRING) {
1132 | Z_TRY_ADDREF_P(msg);
1133 | zend_hash_str_add(frame.headers, "message-id", sizeof("message-id") - 1, msg);
1134 | } else if (Z_TYPE_P(msg) == IS_OBJECT && instanceof_function(Z_OBJCE_P(msg), stomp_ce_frame )) {
1135 | zval *frame_obj_prop, rv;
1136 |
1137 | frame_obj_prop = zend_read_property(stomp_ce_frame, OBJ_FOR_PROP(msg), "headers", sizeof("headers")-1, 1, &rv);
1138 | if (Z_TYPE_P(frame_obj_prop) == IS_ARRAY) {
1139 | FRAME_HEADER_FROM_HASHTABLE(frame.headers, Z_ARRVAL_P(frame_obj_prop));
1140 | }
1141 | } else {
1142 | php_error_docref(NULL, E_WARNING,
1143 | "Expects parameter %d to be a string or a StompFrame object.", stomp_object? 2 : 3);
1144 | CLEAR_FRAME(frame);
1145 | RETURN_FALSE;
1146 | }
1147 |
1148 | if (stomp_send(stomp, &frame ) > 0) {
1149 | success = stomp_valid_receipt(stomp, &frame);
1150 | }
1151 |
1152 | CLEAR_FRAME(frame);
1153 | RETURN_BOOL(success);
1154 | }
1155 | /* }}} */
1156 |
1157 | /* {{{ proto boolean Stomp::ack(mixed msg [, array headers])
1158 | Acknowledge consumption of a message from a subscription using client acknowledgment */
1159 | PHP_FUNCTION(stomp_ack)
1160 | {
1161 | _php_stomp_acknowledgment(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ACK");
1162 | }
1163 | /* }}} */
1164 |
1165 | /* {{{ proto boolean Stomp::nack(mixed msg [, array headers])
1166 | Negative Acknowledgment of a message from a subscription */
1167 | PHP_FUNCTION(stomp_nack)
1168 | {
1169 | _php_stomp_acknowledgment(INTERNAL_FUNCTION_PARAM_PASSTHRU, "NACK");
1170 | }
1171 | /* }}} */
1172 |
1173 | /* {{{ proto string Stomp::error()
1174 | Get the last error message */
1175 | PHP_FUNCTION(stomp_error)
1176 | {
1177 | zval *stomp_object = getThis();
1178 | stomp_t *stomp = NULL;
1179 | if (stomp_object) {
1180 | FETCH_STOMP_OBJECT;
1181 | } else {
1182 | zval *arg;
1183 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "r", &arg) == FAILURE) {
1184 | return;
1185 | }
1186 | FETCH_STOMP_RSRC(stomp, arg);
1187 | }
1188 |
1189 | if (stomp->error) {
1190 | if (stomp->error_details) {
1191 | char *error_msg = (char *) emalloc(strlen(stomp->error) + strlen(stomp->error_details) + 10);
1192 | strcpy(error_msg, stomp->error);
1193 | strcat(error_msg, "\n\n");
1194 | strcat(error_msg, stomp->error_details);
1195 | RETVAL_STRING(error_msg);
1196 | efree(error_msg);
1197 | } else {
1198 | RETURN_STRING(stomp->error);
1199 | }
1200 | } else {
1201 | RETURN_FALSE;
1202 | }
1203 | }
1204 | /* }}} */
1205 |
1206 | /* {{{ proto void Stomp::setTimeout(int seconds [, int microseconds])
1207 | Set the timeout */
1208 | PHP_FUNCTION(stomp_set_read_timeout)
1209 | {
1210 | zval *stomp_object = getThis();
1211 | stomp_t *stomp = NULL;
1212 | zend_long sec = 0, usec = 0;
1213 | if (stomp_object) {
1214 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "l|l", &sec, &usec) == FAILURE) {
1215 | return;
1216 | }
1217 | FETCH_STOMP_OBJECT;
1218 | } else {
1219 | zval *arg;
1220 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "rl|l", &arg, &sec, &usec) == FAILURE) {
1221 | return;
1222 | }
1223 | FETCH_STOMP_RSRC(stomp, arg);
1224 | }
1225 |
1226 | stomp->options.read_timeout_sec = sec;
1227 | stomp->options.read_timeout_usec = usec;
1228 | }
1229 | /* }}} */
1230 |
1231 | /* {{{ proto array Stomp::getTimeout()
1232 | Get the timeout */
1233 | PHP_FUNCTION(stomp_get_read_timeout)
1234 | {
1235 | zval *stomp_object = getThis();
1236 | stomp_t *stomp = NULL;
1237 | if (stomp_object) {
1238 | FETCH_STOMP_OBJECT;
1239 | } else {
1240 | zval *arg;
1241 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "r", &arg) == FAILURE) {
1242 | return;
1243 | }
1244 | FETCH_STOMP_RSRC(stomp, arg);
1245 | }
1246 |
1247 | array_init(return_value);
1248 | add_assoc_long_ex(return_value, "sec", sizeof("sec") - 1, stomp->options.read_timeout_sec);
1249 | add_assoc_long_ex(return_value, "usec", sizeof("usec") - 1, stomp->options.read_timeout_usec);
1250 | }
1251 | /* }}} */
1252 |
1253 | /* {{{ proto void StompFrame::__construct([string command [, array headers [, string body]]])
1254 | Create StompFrame object */
1255 | PHP_METHOD(stompframe, __construct)
1256 | {
1257 | zval *object = getThis();
1258 | char *command = NULL, *body = NULL;
1259 | zend_long command_length = 0, body_length = -1;
1260 | zval *headers = NULL;
1261 |
1262 | if (zend_parse_parameters(ZEND_NUM_ARGS() , "|sa!s", &command, &command_length, &headers, &body, &body_length) == FAILURE) {
1263 | return;
1264 | }
1265 |
1266 | if (command_length > 0) {
1267 | zend_update_property_stringl(stomp_ce_frame, OBJ_FOR_PROP(object), "command", sizeof("command")-1, command, command_length );
1268 | }
1269 | if (headers) {
1270 | zend_update_property(stomp_ce_frame, OBJ_FOR_PROP(object), "headers", sizeof("headers")-1, headers );
1271 | }
1272 | if (body_length > 0) {
1273 | zend_update_property_stringl(stomp_ce_frame, OBJ_FOR_PROP(object), "body", sizeof("body")-1, body, body_length );
1274 | }
1275 | }
1276 | /* }}} */
1277 |
1278 | /* {{{ proto string StompException::getDetails()
1279 | Get error details */
1280 | PHP_METHOD(stompexception, getDetails)
1281 | {
1282 | zval *object = getThis();
1283 | zval rv, *details = zend_read_property(stomp_ce_exception, OBJ_FOR_PROP(object), "details", sizeof("details")-1, 1, &rv);
1284 | RETURN_STR(zval_get_string(details));
1285 | }
1286 | /* }}} */
1287 |
1288 | /*
1289 | * Local variables:
1290 | * tab-width: 4
1291 | * c-basic-offset: 4
1292 | * End:
1293 | * vim600: noet sw=4 ts=4 fdm=marker
1294 | * vim<600: noet sw=4 ts=4
1295 | */
1296 |
--------------------------------------------------------------------------------
/php_stomp.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Copyright (c) The PHP Group |
4 | +----------------------------------------------------------------------+
5 | | This source file is subject to version 3.01 of the PHP license, |
6 | | that is bundled with this package in the file LICENSE, and is |
7 | | available through the world-wide-web at the following url: |
8 | | http://www.php.net/license/3_01.txt |
9 | | If you did not receive a copy of the PHP license and are unable to |
10 | | obtain it through the world-wide-web, please send a note to |
11 | | license@php.net so we can mail you a copy immediately. |
12 | +----------------------------------------------------------------------+
13 | | Author: Pierrick Charron |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef PHP_STOMP_H
18 | #define PHP_STOMP_H
19 |
20 | #include "stomp.h"
21 |
22 | typedef struct _stomp_object {
23 | stomp_t *stomp;
24 | zend_object std;
25 | } stomp_object_t;
26 |
27 | #define PHP_STOMP_EXTNAME "Stomp"
28 | #define PHP_STOMP_VERSION "2.0.4-dev"
29 |
30 | #define PHP_STOMP_RES_NAME "stomp connection"
31 |
32 | #define PHP_STOMP_CLASSNAME "Stomp"
33 | #define PHP_STOMP_FRAME_CLASSNAME "StompFrame"
34 | #define PHP_STOMP_EXCEPTION_CLASSNAME "StompException"
35 |
36 | #define PHP_STOMP_ERR_UNKNOWN "Stomp unknown error"
37 | #define PHP_STOMP_ERR_INVALID_BROKER_URI "Invalid Broker URI"
38 | #define PHP_STOMP_ERR_INVALID_BROKER_URI_SCHEME "Invalid Broker URI scheme"
39 | #define PHP_STOMP_ERR_SERVER_NOT_RESPONDING "Server is not responding"
40 | #define PHP_STOMP_ERR_EMPTY_DESTINATION "Destination can not be empty"
41 | #define PHP_STOMP_ERR_NO_CTR "Stomp constructor was not called"
42 |
43 | extern zend_module_entry stomp_module_entry;
44 | #define phpext_stomp_ptr &stomp_module_entry
45 |
46 | #ifdef PHP_WIN32
47 | #define PHP_STOMP_API __declspec(dllexport)
48 | #else
49 | #define PHP_STOMP_API
50 | #endif
51 |
52 | #ifdef ZTS
53 | #include "TSRM.h"
54 | #endif
55 |
56 | PHP_MINIT_FUNCTION(stomp);
57 | PHP_MSHUTDOWN_FUNCTION(stomp);
58 | PHP_RINIT_FUNCTION(stomp);
59 | PHP_RSHUTDOWN_FUNCTION(stomp);
60 | PHP_MINFO_FUNCTION(stomp);
61 |
62 | /* Methods declarations */
63 | PHP_FUNCTION(stomp_version);
64 | PHP_FUNCTION(stomp_connect);
65 | PHP_FUNCTION(stomp_connect_error);
66 | PHP_FUNCTION(stomp_get_session_id);
67 | PHP_FUNCTION(stomp_close);
68 | PHP_FUNCTION(stomp_send);
69 | PHP_FUNCTION(stomp_subscribe);
70 | PHP_FUNCTION(stomp_has_frame);
71 | PHP_FUNCTION(stomp_read_frame);
72 | PHP_FUNCTION(stomp_unsubscribe);
73 | PHP_FUNCTION(stomp_begin);
74 | PHP_FUNCTION(stomp_commit);
75 | PHP_FUNCTION(stomp_abort);
76 | PHP_FUNCTION(stomp_ack);
77 | PHP_FUNCTION(stomp_nack);
78 | PHP_FUNCTION(stomp_error);
79 | PHP_FUNCTION(stomp_set_read_timeout);
80 | PHP_FUNCTION(stomp_get_read_timeout);
81 |
82 | PHP_METHOD(stompframe, __construct);
83 |
84 | PHP_METHOD(stompexception, getDetails);
85 |
86 | ZEND_BEGIN_MODULE_GLOBALS(stomp)
87 | /* INI */
88 | char *default_broker;
89 | long read_timeout_sec;
90 | long read_timeout_usec;
91 | long connection_timeout_sec;
92 | long connection_timeout_usec;
93 | char *default_username;
94 | char *default_password;
95 |
96 | /* Others */
97 | long error_no;
98 | char *error_msg;
99 | ZEND_END_MODULE_GLOBALS(stomp)
100 |
101 | #ifdef ZTS
102 | #define STOMP_G(v) TSRMG(stomp_globals_id, zend_stomp_globals *, v)
103 | #else
104 | #define STOMP_G(v) (stomp_globals.v)
105 | #endif
106 |
107 | #endif /* PHP_STOMP_H */
108 |
109 |
110 | /*
111 | * Local variables:
112 | * tab-width: 4
113 | * c-basic-offset: 4
114 | * End:
115 | * vim600: noet sw=4 ts=4 fdm=marker
116 | * vim<600: noet sw=4 ts=4
117 | */
118 |
--------------------------------------------------------------------------------
/stomp.c:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Copyright (c) The PHP Group |
4 | +----------------------------------------------------------------------+
5 | | This source file is subject to version 3.01 of the PHP license, |
6 | | that is bundled with this package in the file LICENSE, and is |
7 | | available through the world-wide-web at the following url: |
8 | | http://www.php.net/license/3_01.txt |
9 | | If you did not receive a copy of the PHP license and are unable to |
10 | | obtain it through the world-wide-web, please send a note to |
11 | | license@php.net so we can mail you a copy immediately. |
12 | +----------------------------------------------------------------------+
13 | | Author: Pierrick Charron |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifdef HAVE_CONFIG_H
18 | #include "config.h"
19 | #endif
20 |
21 | #include "php.h"
22 | #include "Zend/zend_smart_str.h"
23 | #include "stomp.h"
24 | #include "php_stomp.h"
25 | #ifdef HAVE_NETINET_IN_H
26 | #include
27 | #endif
28 | #define RETURN_READ_FRAME_FAIL { stomp_free_frame(f); return NULL; }
29 |
30 | ZEND_EXTERN_MODULE_GLOBALS(stomp);
31 | extern zend_class_entry *stomp_ce_exception;
32 |
33 | /* {{{ DEBUG */
34 | #if PHP_DEBUG
35 | static void print_stomp_frame(stomp_frame_t *frame) {
36 | php_printf("------ START FRAME ------\n");
37 | php_printf("%s\n", frame->command);
38 | /* Headers */
39 | if (frame->headers) {
40 | zend_string *key;
41 | zval *value;
42 | ZEND_HASH_FOREACH_STR_KEY_VAL(frame->headers, key, value) {
43 | if (!key) {
44 | break;
45 | }
46 | php_printf("%s:%s\n", ZSTR_VAL(key), Z_STRVAL_P(value));
47 | } ZEND_HASH_FOREACH_END();
48 | }
49 | php_printf("\n%s\n", frame->body);
50 | php_printf("------ END FRAME ------\n");
51 | }
52 | #endif
53 | /* }}} */
54 |
55 | /* {{{ stomp_init
56 | */
57 | stomp_t *stomp_init()
58 | {
59 | /* Memory allocation */
60 | stomp_t *stomp = (stomp_t *) emalloc(sizeof(stomp_t));
61 | memset(stomp, 0, sizeof(*stomp));
62 |
63 | /* Define all values */
64 | stomp->host = NULL;
65 | stomp->port = 0;
66 | stomp->status = 0;
67 | stomp->error = NULL;
68 | stomp->error_details = NULL;
69 | stomp->errnum = 0;
70 | stomp->session = NULL;
71 | stomp->options.connect_timeout_sec = 2;
72 | stomp->options.connect_timeout_usec = 0;
73 | stomp->options.read_timeout_sec = 2;
74 | stomp->options.read_timeout_usec = 0;
75 |
76 | #if HAVE_STOMP_SSL
77 | stomp->options.use_ssl = 0;
78 | stomp->ssl_handle = NULL;
79 | #endif
80 |
81 | stomp->frame_stack = NULL;
82 | stomp->read_buffer.size = 0;
83 | return stomp;
84 | }
85 | /* }}} */
86 |
87 | /* {{{ stomp_frame_stack_push
88 | */
89 | static void stomp_frame_stack_push(stomp_frame_stack_t **stack, stomp_frame_t *frame)
90 | {
91 | stomp_frame_stack_t *cell = (stomp_frame_stack_t *) emalloc(sizeof(stomp_frame_stack_t));
92 | cell->frame = frame;
93 | cell->next = NULL;
94 |
95 | if (!*stack) {
96 | *stack = cell;
97 | } else {
98 | stomp_frame_stack_t *cursor = *stack;
99 | while (cursor->next != NULL) cursor = cursor->next;
100 | cursor->next = cell;
101 | }
102 | }
103 | /* }}} */
104 |
105 | /* {{{ stomp_frame_stack_shift
106 | */
107 | static stomp_frame_t *stomp_frame_stack_shift(stomp_frame_stack_t **stack) {
108 | stomp_frame_t *frame = NULL;
109 | if (*stack) {
110 | stomp_frame_stack_t *cell = *stack;
111 | *stack = cell->next;
112 | frame = cell->frame;
113 | efree(cell);
114 | }
115 | return frame;
116 | }
117 | /* }}} */
118 |
119 | /* {{{ stomp_frame_stack_clear
120 | */
121 | static void stomp_frame_stack_clear(stomp_frame_stack_t **stack) {
122 | stomp_frame_t *frame = NULL;
123 | while ((frame = stomp_frame_stack_shift(stack))) efree(frame);
124 | }
125 | /* }}} */
126 |
127 | /* {{{ stomp_set_error
128 | */
129 | void stomp_set_error(stomp_t *stomp, const char *error, int errnum, const char *fmt, ...)
130 | {
131 | va_list ap;
132 | int len;
133 |
134 | if (stomp->error != NULL) {
135 | efree(stomp->error);
136 | stomp->error = NULL;
137 | }
138 | if (stomp->error_details != NULL) {
139 | efree(stomp->error_details);
140 | stomp->error_details = NULL;
141 | }
142 | stomp->errnum = errnum;
143 | if (error != NULL) {
144 | stomp->error = estrdup(error);
145 | }
146 | if (fmt != NULL) {
147 | stomp->error_details = emalloc(STOMP_BUFSIZE);
148 | if (stomp->error_details == NULL) {
149 | return; /* Nothing else can be done */
150 | }
151 | va_start(ap, fmt);
152 | /*
153 | * Would've been better to call vasprintf(), but that
154 | * function is missing on some platforms...
155 | */
156 | len = vsnprintf(stomp->error_details, STOMP_BUFSIZE, fmt, ap);
157 | va_end(ap);
158 | if (len < STOMP_BUFSIZE) {
159 | stomp->error_details = erealloc(stomp->error_details, len+1);
160 | }
161 | }
162 | }
163 | /* }}} */
164 |
165 | /* {{{ stomp_writable
166 | */
167 | int stomp_writable(stomp_t *stomp)
168 | {
169 | int n;
170 |
171 | n = php_pollfd_for_ms(stomp->fd, POLLOUT, 1000);
172 | if (n != POLLOUT) {
173 | #ifndef PHP_WIN32
174 | if (n == 0) {
175 | errno = ETIMEDOUT;
176 | }
177 | #endif
178 | return 0;
179 | }
180 |
181 | return 1;
182 | }
183 | /* }}} */
184 |
185 | /* {{{ stomp_connect
186 | */
187 | int stomp_connect(stomp_t *stomp, const char *host, unsigned short port)
188 | {
189 | char error[1024];
190 | socklen_t size;
191 | struct timeval tv;
192 | int flag = 1;
193 |
194 | if (stomp->host != NULL) {
195 | efree(stomp->host);
196 | }
197 | stomp->host = (char *) emalloc(strlen(host) + 1);
198 | memcpy(stomp->host, host, strlen(host));
199 | stomp->host[strlen(host)] = '\0';
200 |
201 | stomp->port = port;
202 |
203 | tv.tv_sec = stomp->options.connect_timeout_sec;
204 | tv.tv_usec = stomp->options.connect_timeout_usec;
205 |
206 | stomp->fd = php_network_connect_socket_to_host(stomp->host, stomp->port, SOCK_STREAM, 0, &tv, NULL, NULL, NULL, 0, 0);
207 | if (stomp->fd == -1) {
208 | snprintf(error, sizeof(error), "Unable to connect to %s:%d", stomp->host, stomp->port);
209 | stomp_set_error(stomp, error, errno, "%s", strerror(errno));
210 | return 0;
211 | }
212 |
213 | #ifdef HAVE_NETINET_IN_H
214 | setsockopt(stomp->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
215 | #endif
216 |
217 | size = sizeof(stomp->localaddr);
218 | memset(&stomp->localaddr, 0, size);
219 | if (getsockname(stomp->fd, (struct sockaddr*) &stomp->localaddr, &size) == -1) {
220 | snprintf(error, sizeof(error), "getsockname failed: %s (%d)", strerror(errno), errno);
221 | stomp_set_error(stomp, error, errno, NULL);
222 | return 0;
223 | }
224 |
225 | if (stomp_writable(stomp)) {
226 | #if HAVE_STOMP_SSL
227 | if (stomp->options.use_ssl) {
228 | SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
229 | int ret;
230 |
231 | if (NULL == ctx) {
232 | stomp_set_error(stomp, "failed to create the SSL context", 0, NULL);
233 | return 0;
234 | }
235 |
236 | SSL_CTX_set_options(ctx, SSL_OP_ALL);
237 |
238 | stomp->ssl_handle = SSL_new(ctx);
239 | if (stomp->ssl_handle == NULL) {
240 | stomp_set_error(stomp, "failed to create the SSL handle", 0, NULL);
241 | SSL_CTX_free(ctx);
242 | return 0;
243 | }
244 |
245 | SSL_set_fd(stomp->ssl_handle, stomp->fd);
246 |
247 | if ((ret = SSL_connect(stomp->ssl_handle)) <= 0) {
248 | stomp_set_error(stomp, "SSL/TLS handshake failed", 0, "SSL error %d", SSL_get_error(stomp->ssl_handle, ret));
249 | SSL_shutdown(stomp->ssl_handle);
250 | return 0;
251 | }
252 | }
253 | #endif
254 | return 1;
255 | } else {
256 | snprintf(error, sizeof(error), "Unable to connect to %s:%d", stomp->host, stomp->port);
257 | stomp_set_error(stomp, error, errno, "%s", strerror(errno));
258 | return 0;
259 | }
260 | }
261 | /* }}} */
262 |
263 | /* {{{ stomp_close
264 | */
265 | void stomp_close(stomp_t *stomp)
266 | {
267 | if (NULL == stomp) {
268 | return;
269 | }
270 |
271 | if (stomp->fd != -1) {
272 | #if HAVE_STOMP_SSL
273 | if(stomp->ssl_handle) {
274 | SSL_shutdown(stomp->ssl_handle);
275 | }
276 | #endif
277 | closesocket(stomp->fd);
278 | }
279 | if (stomp->host) {
280 | efree(stomp->host);
281 | }
282 | if (stomp->session) {
283 | efree(stomp->session);
284 | }
285 | if (stomp->error) {
286 | efree(stomp->error);
287 | }
288 | if (stomp->error_details) {
289 | efree(stomp->error_details);
290 | }
291 | stomp_frame_stack_clear(&stomp->frame_stack);
292 | efree(stomp);
293 | }
294 | /* }}} */
295 |
296 | /* {{{ stomp_send
297 | */
298 | int stomp_send(stomp_t *stomp, stomp_frame_t *frame)
299 | {
300 | smart_str buf = {0};
301 |
302 | /* Command */
303 | smart_str_appends(&buf, frame->command);
304 | smart_str_appendc(&buf, '\n');
305 |
306 | /* Headers */
307 | if (frame->headers) {
308 | zend_string *key;
309 | zval *value;
310 | ZEND_HASH_FOREACH_STR_KEY_VAL(frame->headers, key, value) {
311 | smart_str_appends(&buf, ZSTR_VAL(key));
312 | smart_str_appendc(&buf, ':');
313 | smart_str_appends(&buf, Z_STRVAL_P(value));
314 | smart_str_appendc(&buf, '\n');
315 | } ZEND_HASH_FOREACH_END();
316 | }
317 |
318 | if (frame->body_length > 0) {
319 | smart_str_appendl(&buf, "content-length:", sizeof("content-length:") - 1);
320 | smart_str_append_long(&buf, frame->body_length);
321 | smart_str_appendc(&buf, '\n');
322 | }
323 |
324 | smart_str_appendc(&buf, '\n');
325 |
326 | if (frame->body > 0) {
327 | smart_str_appendl(&buf, frame->body, frame->body_length);
328 | }
329 |
330 | smart_str_appendl(&buf, "\0", sizeof("\0")-1);
331 |
332 | if (!stomp_writable(stomp)) {
333 | smart_str_free(&buf);
334 | stomp_set_error(stomp, "Unable to send data", errno, "%s", strerror(errno));
335 | return 0;
336 | }
337 |
338 | #ifdef HAVE_STOMP_SSL
339 | if (stomp->options.use_ssl) {
340 | int ret;
341 | if (-1 == (ret = SSL_write(stomp->ssl_handle, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)))) {
342 | smart_str_free(&buf);
343 | stomp_set_error(stomp, "Unable to send data", errno, "SSL error %d", SSL_get_error(stomp->ssl_handle, ret));
344 | return 0;
345 | }
346 | } else {
347 | #endif
348 | if (-1 == send(stomp->fd, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s), 0)) {
349 | smart_str_free(&buf);
350 | stomp_set_error(stomp, "Unable to send data", errno, "%s", strerror(errno));
351 | return 0;
352 | }
353 | #ifdef HAVE_STOMP_SSL
354 | }
355 | #endif
356 |
357 | smart_str_free(&buf);
358 |
359 | return 1;
360 | }
361 | /* }}} */
362 |
363 | /* {{{ stomp_recv
364 | */
365 | static int _stomp_recv(stomp_t *stomp, char *msg, const size_t length)
366 | {
367 | int len;
368 |
369 | stomp_select(stomp);
370 |
371 | #if HAVE_STOMP_SSL
372 | if(stomp->options.use_ssl) {
373 | len = SSL_read(stomp->ssl_handle, msg, length);
374 | } else {
375 | #endif
376 | len = recv(stomp->fd, msg, length, 0);
377 | #if HAVE_STOMP_SSL
378 | }
379 | #endif
380 |
381 | if (len == -1) {
382 | #if HAVE_STOMP_SSL
383 | if (stomp->options.use_ssl) {
384 | stomp_set_error(stomp, "Error reading from socket", errno, "%s. (SSL in use)", strerror(errno));
385 | } else {
386 | #endif
387 | stomp_set_error(stomp, "Error reading from socket", errno, "%s. (SSL not in use)", strerror(errno));
388 | #if HAVE_STOMP_SSL
389 | }
390 | #endif
391 | stomp->status = -1;
392 | } else if (len == 0) {
393 | stomp_set_error(stomp, "Sender closed connection unexpectedly", 0, NULL);
394 | stomp->status = -1;
395 | }
396 |
397 | return len;
398 | }
399 |
400 | int stomp_recv(stomp_t *stomp, char *msg, const size_t length)
401 | {
402 | if (stomp->read_buffer.size == 0) {
403 | if (length >= STOMP_BUFSIZE) {
404 | return _stomp_recv(stomp, msg, length);
405 | } else {
406 | size_t recv_size = _stomp_recv(stomp, stomp->read_buffer.buf, STOMP_BUFSIZE);
407 | if (recv_size <= length) {
408 | memcpy(msg, stomp->read_buffer.buf, recv_size);
409 | return recv_size;
410 | } else {
411 | memcpy(msg, stomp->read_buffer.buf, length);
412 | stomp->read_buffer.pos = stomp->read_buffer.buf + length;
413 | stomp->read_buffer.size = recv_size - length;
414 | return length;
415 | }
416 | }
417 | } else if (stomp->read_buffer.size >= length) {
418 | memcpy(msg, stomp->read_buffer.pos, length);
419 | stomp->read_buffer.pos += length;
420 | stomp->read_buffer.size -= length;
421 | return length;
422 | } else {
423 | int len = stomp->read_buffer.size;
424 | memcpy(msg, stomp->read_buffer.pos, stomp->read_buffer.size);
425 | stomp->read_buffer.size = 0;
426 | if (stomp_select_ex(stomp, 0, 0)) {
427 | return len + stomp_recv(stomp, msg + len, length - len);
428 | } else {
429 | return len;
430 | }
431 | }
432 | }
433 | /* }}} */
434 |
435 | /* {{{ _stomp_read_until
436 | */
437 | static size_t _stomp_read_until(stomp_t *stomp, char **data, const char delimiter)
438 | {
439 | size_t length = 0;
440 | size_t bufsize = STOMP_BUFSIZE;
441 | char *buffer = (char *) emalloc(STOMP_BUFSIZE);
442 |
443 | while (1) {
444 | unsigned int i, found;
445 | char *c;
446 | found = 0;
447 |
448 | // First populate the buffer
449 | if (stomp->read_buffer.size == 0) {
450 | stomp->read_buffer.size = _stomp_recv(stomp, stomp->read_buffer.buf, STOMP_BUFSIZE);
451 |
452 | if (stomp->status == -1) {
453 | length = 0;
454 | break;
455 | }
456 |
457 | stomp->read_buffer.pos = stomp->read_buffer.buf;
458 | }
459 |
460 | // Then search the delimiter
461 | c = stomp->read_buffer.pos;
462 | for (i = 1; i <= stomp->read_buffer.size ; i++) {
463 | if (*c == delimiter) {
464 | found = 1;
465 | break;
466 | } else {
467 | c++;
468 | }
469 | }
470 | if (!found) i--;
471 |
472 | // Make sure we have enough place in the buffer
473 | if ((i+length) >= bufsize) {
474 | buffer = (char *) erealloc(buffer, bufsize + STOMP_BUFSIZE);
475 | bufsize += STOMP_BUFSIZE;
476 | }
477 |
478 | // Copy and update the buffer
479 | memcpy(buffer + length, stomp->read_buffer.pos, i);
480 | length += i;
481 | stomp->read_buffer.pos += i;
482 | stomp->read_buffer.size -= i;
483 |
484 | if (found) {
485 | break;
486 | }
487 | }
488 |
489 | if (length) {
490 | *data = buffer;
491 | } else {
492 | efree(buffer);
493 | *data = NULL;
494 | }
495 |
496 | return length;
497 | }
498 | /* }}} */
499 |
500 | /* {{{ stomp_read_buffer
501 | */
502 | static size_t stomp_read_buffer(stomp_t *stomp, char **data)
503 | {
504 | size_t length = _stomp_read_until(stomp, data, 0);
505 | if (stomp_select_ex(stomp, 0, 0)) {
506 | char endline[1];
507 | if (1 != stomp_recv(stomp, endline, 1) && '\n' != endline[0]) {
508 | if (*data) {
509 | efree(*data);
510 | *data = NULL;
511 | }
512 | return 0;
513 | }
514 | }
515 | if (length > 1) {
516 | length --;
517 | } else if (length) {
518 | efree(*data);
519 | *data = NULL;
520 | length = 0;
521 | }
522 | return length;
523 | }
524 | /* }}} */
525 |
526 | /* {{{ stomp_read_line
527 | */
528 | static int stomp_read_line(stomp_t *stomp, char **data)
529 | {
530 | size_t length = _stomp_read_until(stomp, data, '\n');
531 | if (length > 1) {
532 | (*data)[length - 1] = 0;
533 | length--;
534 | } else if (length) {
535 | efree(*data);
536 | *data = NULL;
537 | length = 0;
538 | }
539 | return length;
540 | }
541 | /* }}} */
542 |
543 | /* {{{ stomp_free_frame
544 | */
545 | void stomp_free_frame(stomp_frame_t *frame)
546 | {
547 | if (frame) {
548 | if (frame->command) {
549 | efree(frame->command);
550 | }
551 | if (frame->body) {
552 | efree(frame->body);
553 | }
554 | if (frame->headers) {
555 | zend_hash_destroy(frame->headers);
556 | FREE_HASHTABLE(frame->headers);
557 | }
558 | efree(frame);
559 | }
560 | }
561 | /* }}} */
562 |
563 | /* {{{ stomp_read_frame
564 | */
565 | stomp_frame_t *stomp_read_frame_ex(stomp_t *stomp, int use_stack)
566 | {
567 | stomp_frame_t *f = NULL;
568 | char *cmd = NULL;
569 | zval *length_str = NULL;
570 | int length = 0;
571 |
572 | if (use_stack && stomp->frame_stack) {
573 | return stomp_frame_stack_shift(&stomp->frame_stack);
574 | }
575 |
576 | if (!stomp_select(stomp)) {
577 | return NULL;
578 | }
579 |
580 | INIT_STOMP_FRAME(f);
581 |
582 | if (NULL == f) {
583 | return NULL;
584 | }
585 |
586 | /* Parse the command */
587 | length = stomp_read_line(stomp, &cmd);
588 | if (length < 1) {
589 | RETURN_READ_FRAME_FAIL;
590 | }
591 |
592 | f->command = cmd;
593 | f->command_length = length;
594 |
595 | /* Parse the header */
596 | while (1) {
597 | char *p = NULL;
598 | length = stomp_read_line(stomp, &p);
599 |
600 | if (length < 0) {
601 | RETURN_READ_FRAME_FAIL;
602 | }
603 |
604 | if (0 == length) {
605 | break;
606 | } else {
607 | char *p2 = NULL;
608 | char *key;
609 | zval value;
610 |
611 | p2 = strstr(p,":");
612 |
613 | if (p2 == NULL) {
614 | efree(p);
615 | RETURN_READ_FRAME_FAIL;
616 | }
617 |
618 | /* Null terminate the key */
619 | *p2 = 0;
620 | key = p;
621 |
622 | /* The rest is the value. */
623 | ZVAL_STRING(&value, p2 + 1);
624 |
625 | /* Insert key/value into hash table. */
626 | zend_hash_str_add(f->headers, key, p2 - key, &value);
627 | efree(p);
628 | }
629 | }
630 |
631 | /* Check for the content length */
632 | if ((length_str = zend_hash_str_find(f->headers, ZEND_STRL("content-length"))) != NULL) {
633 | int recv_size = 0;
634 | char endbuffer[2];
635 |
636 | f->body_length = atoi(Z_STRVAL_P(length_str));
637 | f->body = (char *) emalloc(f->body_length);
638 |
639 | while (recv_size != f->body_length) {
640 | int l = stomp_recv(stomp, f->body + recv_size, f->body_length - recv_size);
641 | if (-1 == l) {
642 | RETURN_READ_FRAME_FAIL;
643 | } else {
644 | recv_size += l;
645 | }
646 | }
647 |
648 | length = stomp_recv(stomp, endbuffer, 2);
649 | if (endbuffer[0] != '\0' || ((2 == length) && (endbuffer[1] != '\n'))) {
650 | RETURN_READ_FRAME_FAIL;
651 | }
652 |
653 | } else {
654 | f->body_length = stomp_read_buffer(stomp, &f->body);
655 | }
656 |
657 | return f;
658 | }
659 | /* }}} */
660 |
661 | /* {{{ stomp_valid_receipt
662 | */
663 | int stomp_valid_receipt(stomp_t *stomp, stomp_frame_t *frame) {
664 | int success = 1;
665 | zval *receipt;
666 |
667 | if ((receipt = zend_hash_str_find(frame->headers, ZEND_STRL("receipt"))) != NULL) {
668 | success = 0;
669 | while (1) {
670 | stomp_frame_t *res = stomp_read_frame_ex(stomp, 0);
671 | if (res) {
672 | if (0 == strncmp("RECEIPT", res->command, sizeof("RECEIPT") - 1)) {
673 | zval *receipt_id;
674 | if ((receipt_id = zend_hash_str_find(res->headers, ZEND_STRL("receipt-id"))) != NULL
675 | && zend_string_equals(Z_STR_P(receipt), Z_STR_P(receipt_id))) {
676 | success = 1;
677 | } else {
678 | stomp_set_error(stomp, "Invalid receipt", 0, "%s", receipt_id);
679 | }
680 | stomp_free_frame(res);
681 | return success;
682 | } else if (0 == strncmp("ERROR", res->command, sizeof("ERROR") - 1)) {
683 | zval *error_msg;
684 | if ((error_msg = zend_hash_str_find(res->headers, ZEND_STRL("message"))) != NULL) {
685 | stomp_set_error(stomp, Z_STRVAL_P(error_msg), 0, "%s", res->body);
686 | }
687 | stomp_free_frame(res);
688 | return success;
689 | } else {
690 | stomp_frame_stack_push(&stomp->frame_stack, res);
691 | }
692 | } else {
693 | return success;
694 | }
695 | }
696 | }
697 | return success;
698 | }
699 | /* }}} */
700 |
701 | /* {{{ stomp_select
702 | */
703 | int stomp_select_ex(stomp_t *stomp, const long int sec, const long int usec)
704 | {
705 | int n;
706 | struct timeval tv;
707 |
708 | if (stomp->read_buffer.size || stomp->frame_stack) {
709 | return 1;
710 | }
711 | tv.tv_sec = sec;
712 | tv.tv_usec = usec;
713 |
714 | n = php_pollfd_for(stomp->fd, PHP_POLLREADABLE, &tv);
715 | if (n < 1) {
716 | #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
717 | if (n == 0) {
718 | errno = ETIMEDOUT;
719 | }
720 | #endif
721 | return 0;
722 | }
723 | return 1;
724 | }
725 | /* }}} */
726 |
727 | /*
728 | * Local variables:
729 | * tab-width: 4
730 | * c-basic-offset: 4
731 | * End:
732 | * vim600: noet sw=4 ts=4 fdm=marker
733 | * vim<600: noet sw=4 ts=4
734 | */
735 |
--------------------------------------------------------------------------------
/stomp.h:
--------------------------------------------------------------------------------
1 | /*
2 | +----------------------------------------------------------------------+
3 | | Copyright (c) The PHP Group |
4 | +----------------------------------------------------------------------+
5 | | This source file is subject to version 3.01 of the PHP license, |
6 | | that is bundled with this package in the file LICENSE, and is |
7 | | available through the world-wide-web at the following url: |
8 | | http://www.php.net/license/3_01.txt |
9 | | If you did not receive a copy of the PHP license and are unable to |
10 | | obtain it through the world-wide-web, please send a note to |
11 | | license@php.net so we can mail you a copy immediately. |
12 | +----------------------------------------------------------------------+
13 | | Author: Pierrick Charron |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef _STOMP_H_
18 | #define _STOMP_H_
19 |
20 | #include "php_network.h"
21 |
22 | #if HAVE_STOMP_SSL
23 | #include
24 | #endif
25 |
26 | #define STOMP_BUFSIZE 4096
27 |
28 | #define INIT_STOMP_FRAME(f) \
29 | f = (stomp_frame_t *) emalloc(sizeof(stomp_frame_t)); \
30 | f->command = NULL; f->body = NULL; \
31 | ALLOC_HASHTABLE(f->headers); \
32 | zend_hash_init(f->headers, 0, NULL, ZVAL_PTR_DTOR, 0);
33 |
34 | typedef struct _stomp_options {
35 | long connect_timeout_sec;
36 | long connect_timeout_usec;
37 | long read_timeout_sec;
38 | long read_timeout_usec;
39 | #if HAVE_STOMP_SSL
40 | int use_ssl;
41 | #endif
42 | } stomp_options_t;
43 |
44 | typedef struct _stomp_frame {
45 | char *command;
46 | int command_length;
47 | HashTable *headers;
48 | char *body;
49 | int body_length;
50 | } stomp_frame_t;
51 |
52 | typedef struct _stomp_frame_stack {
53 | stomp_frame_t *frame;
54 | struct _stomp_frame_stack *next;
55 | } stomp_frame_stack_t;
56 |
57 | typedef struct _stomp {
58 | php_socket_t fd;
59 | php_sockaddr_storage localaddr;
60 | stomp_options_t options;
61 | char *host;
62 | unsigned short port;
63 | int status;
64 | char *error;
65 | int errnum;
66 | char *error_details;
67 | char *session;
68 | #if HAVE_STOMP_SSL
69 | SSL *ssl_handle;
70 | #endif
71 | stomp_frame_stack_t *frame_stack;
72 | struct {
73 | size_t size;
74 | char buf[STOMP_BUFSIZE];
75 | char *pos;
76 | } read_buffer;
77 | } stomp_t;
78 |
79 | stomp_t *stomp_init();
80 | int stomp_connect(stomp_t *stomp, const char *host, unsigned short port);
81 | void stomp_close(stomp_t *stomp);
82 | int stomp_send(stomp_t *connection, stomp_frame_t *frame);
83 | stomp_frame_t *stomp_read_frame_ex(stomp_t *connection, int use_stack);
84 | int stomp_valid_receipt(stomp_t *connection, stomp_frame_t *frame);
85 | int stomp_select_ex(stomp_t *connection, const long int sec, const long int usec);
86 | void stomp_set_error(stomp_t *stomp, const char *error, int errnum, const char *fmt, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0);
87 | void stomp_free_frame(stomp_frame_t *frame);
88 |
89 | #define stomp_select(s) stomp_select_ex(s, s->options.read_timeout_sec, s->options.read_timeout_usec)
90 | #define stomp_read_frame(c) stomp_read_frame_ex(c, 1)
91 | #endif /* _STOMP_H_ */
92 |
93 | /*
94 | * Local variables:
95 | * tab-width: 4
96 | * c-basic-offset: 4
97 | * End:
98 | * vim600: noet sw=4 ts=4 fdm=marker
99 | * vim<600: noet sw=4 ts=4
100 | */
101 |
--------------------------------------------------------------------------------
/tests/001-stomp.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for stomp presence
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
9 | --EXPECT--
10 | stomp extension is available
11 |
--------------------------------------------------------------------------------
/tests/002-version.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_version()
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
9 | --EXPECTF--
10 | %d.%d.%s
11 |
--------------------------------------------------------------------------------
/tests/003-connect/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_connect() - URI validation
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
12 | --EXPECT--
13 | NULL
14 | string(18) "Invalid Broker URI"
15 | NULL
16 | string(18) "Invalid Broker URI"
17 | NULL
18 | string(18) "Invalid Broker URI"
19 | NULL
20 | string(25) "Invalid Broker URI scheme"
21 |
--------------------------------------------------------------------------------
/tests/003-connect/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_connect() - Test connection
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
14 | --EXPECTF--
15 | resource(%d) of type (stomp connection)
16 | NULL
17 |
--------------------------------------------------------------------------------
/tests/003-connect/003.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_connect() - Test error on CONNECT
3 | --SKIPIF--
4 |
7 | --FILE--
8 |
15 | --EXPECTF--
16 | string(14) "StompException"
17 |
--------------------------------------------------------------------------------
/tests/004-getSessionId/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_get_session_id()
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
14 | --EXPECTF--
15 | string(%d) "%s"
16 |
--------------------------------------------------------------------------------
/tests/005-close/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_close() - tests parameters
3 | --SKIPIF--
4 |
7 | --FILE--
8 | getMessage() . PHP_EOL;
13 | }
14 | ?>
15 | --EXPECTF--
16 | %stomp_close()%s1%s null %s
17 |
--------------------------------------------------------------------------------
/tests/005-close/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_close()
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
15 | --EXPECT--
16 | success
17 | closed
18 |
--------------------------------------------------------------------------------
/tests/006-send/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_send() - tests parameters
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
21 | --EXPECTF--
22 | Warning: stomp_send(): Destination can not be empty in %s on line %d
23 |
24 | Warning: stomp_send(): Expects parameter %d to be a string or a StompFrame object. in %s on line %d
25 | bool(true)
26 | bool(true)
27 | bool(true)
28 |
--------------------------------------------------------------------------------
/tests/006-send/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp::send() - tests parameters
3 | --SKIPIF--
4 |
8 | --FILE--
9 | send('', array());
16 | $s->send('/queue/test-06', array());
17 | var_dump($s->send('/queue/test-06', ''));
18 | var_dump($s->send('/queue/test-06', 'A realMessage'));
19 | var_dump($s->send('/queue/test-06', 'بياريك شارون'));
20 |
21 | ?>
22 | --EXPECTF--
23 | Warning: Stomp::send(): Destination can not be empty in %s on line %d
24 |
25 | Warning: Stomp::send(): Expects parameter %d to be a string or a StompFrame object. in %s on line %d
26 | bool(true)
27 | bool(true)
28 | bool(true)
29 |
--------------------------------------------------------------------------------
/tests/006-send/003.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp::send() - test send with receipt
3 | --SKIPIF--
4 |
8 | --FILE--
9 | send('/queue/test-06', 'A real message', array('receipt' => 'message-12345')));
13 | ?>
14 | --EXPECTF--
15 | bool(true)
16 |
--------------------------------------------------------------------------------
/tests/007-subscribe/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test Stomp::subscribe()
3 | --SKIPIF--
4 |
8 | --FILE--
9 | subscribe('', array());
14 | $s->subscribe('/queue/test', 'string');
15 | ?>
16 | --EXPECTF--
17 | Warning: Stomp::subscribe(): Destination can not be empty in %s007-subscribe%c001.php on line %d
18 |
19 | Fatal error: Uncaught TypeError: %s, string given in %s007-subscribe%c001.php:%d
20 | Stack trace:
21 | #0 %s001.php(%d): Stomp->subscribe('/queue/test', 'string')
22 | #1 {main}
23 | thrown in %s007-subscribe%c001.php on line %d
24 |
--------------------------------------------------------------------------------
/tests/008-unsubscribe/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test Stomp::unsubscribe()
3 | --SKIPIF--
4 |
8 | --FILE--
9 | unsubscribe('', array());
15 | $s->unsubscribe('/queue/test', 'string');
16 | ?>
17 | --EXPECTF--
18 | Warning: Stomp::unsubscribe(): Destination can not be empty in %s008-unsubscribe%c001.php on line %d
19 |
20 | Fatal error: Uncaught TypeError: %s2%s string given in %s008-unsubscribe%c001.php:%d
21 | Stack trace:
22 | #0 %s(%d): Stomp->unsubscribe('/queue/test', 'string')
23 | #1 {main}
24 | thrown in %s on line %d
25 |
--------------------------------------------------------------------------------
/tests/009-readFrame/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp::readFrame() - tests functionnality and parameters
3 | --SKIPIF--
4 |
8 | --FILE--
9 | send('/queue/test-09', 'A test Message');
15 | $s->subscribe('/queue/test-09', array('ack' => 'auto'));
16 | var_dump($s->readFrame()->body);
17 | var_dump($s->readFrame());
18 |
19 | ?>
20 | --EXPECTF--
21 | string(14) "A test Message"
22 | bool(false)
23 |
--------------------------------------------------------------------------------
/tests/009-readFrame/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_read_frame() - test functionnality and parameters
3 | --SKIPIF--
4 |
8 | --FILE--
9 | 'auto'));
15 | $result = stomp_read_frame($link);
16 | var_dump($result['body']);
17 | var_dump(stomp_read_frame($link));
18 |
19 | ?>
20 | --EXPECTF--
21 | string(14) "A test Message"
22 | bool(false)
23 |
--------------------------------------------------------------------------------
/tests/009-readFrame/003.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp::readFrame() - custom frame class
3 | --SKIPIF--
4 |
8 | --FILE--
9 | send('/queue/test-09', 'A test Message');
23 | $s->subscribe('/queue/test-09', array('ack' => 'auto'));
24 | $frame = $s->readFrame('customFrame');
25 | var_dump(get_class($frame), $frame->body);
26 | ?>
27 | --EXPECT--
28 | string(11) "customFrame"
29 | string(14) "A test Message"
30 |
--------------------------------------------------------------------------------
/tests/009-readFrame/004.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp::readFrame() - Test the body binary safety
3 | --SKIPIF--
4 |
8 | --FILE--
9 | send('/queue/test-09', "A test Message\0Foo");
15 | $s->subscribe('/queue/test-09', array('ack' => 'auto'));
16 | var_dump($s->readFrame()->body);
17 |
18 | ?>
19 | --EXPECTF--
20 | string(18) "A test Message Foo"
21 |
--------------------------------------------------------------------------------
/tests/009-readFrame/005.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_read_frame() - Test the body binary safety
3 | --SKIPIF--
4 |
8 | --FILE--
9 | 'auto'));
16 | $result = stomp_read_frame($link);
17 | var_dump($result['body']);
18 |
19 | ?>
20 | --EXPECTF--
21 | string(18) "A test Message Foo"
22 |
--------------------------------------------------------------------------------
/tests/009-readFrame/006.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp::readFrame() - test frame stack
3 | --SKIPIF--
4 |
8 | --FILE--
9 | subscribe('/queue/test-buffer', array('ack' => 'auto')));
16 | var_dump($s->send('/queue/test-buffer', "Message1", array('receipt' => 'msg-1')));
17 | var_dump($s->send('/queue/test-buffer', "Message2", array('receipt' => 'msg-2')));
18 | var_dump($s->send('/queue/test-buffer', "Message3", array('receipt' => 'msg-3')));
19 | var_dump($s->readFrame()->body);
20 | var_dump($s->readFrame()->body);
21 | var_dump($s->readFrame()->body);
22 | ?>
23 | --EXPECTF--
24 | bool(true)
25 | bool(true)
26 | bool(true)
27 | bool(true)
28 | string(8) "Message1"
29 | string(8) "Message2"
30 | string(8) "Message3"
31 |
--------------------------------------------------------------------------------
/tests/010-timeout/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test Stomp::getReadTimout() and Stomp::setReadTimeout() - tests functionnality and parameters
3 | --INI--
4 | stomp.default_read_timeout_sec=5
5 | stomp.default_read_timeout_usec=5
6 | --SKIPIF--
7 |
11 | --FILE--
12 | getReadTimeout());
17 |
18 | // Set read timout with an integer as seconds
19 | var_dump($s->setReadTimeout(10));
20 | // Second test, read supposed to return 10.0
21 | var_dump($s->getReadTimeout());
22 |
23 | // Set read timout with an integer as seconds
24 | var_dump($s->setReadTimeout(10, 5));
25 | // Third test, read supposed to return 10.5
26 | var_dump($s->getReadTimeout());
27 |
28 | try {
29 | // Set read timout with the first param as a string, supposed to trigger a warning/exception
30 | var_dump($s->setReadTimeout(''));
31 | } catch (TypeError $e) {
32 | echo $e->getMessage() . PHP_EOL;
33 | }
34 | // Fourth test, read supposed to get the last value set : 10.5
35 | var_dump($s->getReadTimeout());
36 |
37 | try {
38 | // Set read timout with the second param as a string, supposed to trigger a warning/exception
39 | var_dump($s->setReadTimeout(10, ''));
40 | } catch (TypeError $e) {
41 | echo $e->getMessage() . PHP_EOL;
42 | }
43 | // Fourth test, read supposed to get the last value set : 10.5
44 | var_dump($s->getReadTimeout());
45 |
46 | // Set read timout with the params as null
47 | var_dump($s->setReadTimeout(0, 0));
48 | // Fifth test, read supposed to get the last value set : 0.0
49 | var_dump($s->getReadTimeout());
50 |
51 |
52 | unset($s);
53 | ?>
54 | --EXPECTF--
55 | array(2) {
56 | ["sec"]=>
57 | int(5)
58 | ["usec"]=>
59 | int(5)
60 | }
61 | NULL
62 | array(2) {
63 | ["sec"]=>
64 | int(10)
65 | ["usec"]=>
66 | int(0)
67 | }
68 | NULL
69 | array(2) {
70 | ["sec"]=>
71 | int(10)
72 | ["usec"]=>
73 | int(5)
74 | }
75 | %AStomp::setReadTimeout()%s1%s string given%A
76 | array(2) {
77 | ["sec"]=>
78 | int(10)
79 | ["usec"]=>
80 | int(5)
81 | }
82 | %AStomp::setReadTimeout()%s2%s string given%A
83 | array(2) {
84 | ["sec"]=>
85 | int(10)
86 | ["usec"]=>
87 | int(5)
88 | }
89 | NULL
90 | array(2) {
91 | ["sec"]=>
92 | int(0)
93 | ["usec"]=>
94 | int(0)
95 | }
96 |
--------------------------------------------------------------------------------
/tests/010-timeout/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test stomp_get_read_timout() and stomp_set_read_timeout() - tests functionnality and parameters
3 | --INI--
4 | stomp.default_read_timeout_sec=5
5 | stomp.default_read_timeout_usec=5
6 | --SKIPIF--
7 |
11 | --FILE--
12 | getMessage() . PHP_EOL;
34 | }
35 | // Fourth test, read supposed to get the last value set : 10.5
36 | var_dump(stomp_get_read_timeout($link));
37 |
38 | try {
39 | // Set read timout with the second param as a string, supposed to trigger a warning on PHP 7
40 | // supposed to trigger an exception on PHP 8
41 | var_dump(stomp_set_read_timeout($link, 10, ''));
42 | } catch (TypeError $e) {
43 | echo $e->getMessage() . PHP_EOL;
44 | }
45 | // Fourth test, read supposed to get the last value set : 10.5
46 | var_dump(stomp_get_read_timeout($link));
47 |
48 | // Set read timout with the params as null
49 | var_dump(stomp_set_read_timeout($link, 0, 0));
50 | // Fifth test, read supposed to get the last value set : 0.0
51 | var_dump(stomp_get_read_timeout($link));
52 |
53 |
54 | unset($s);
55 | ?>
56 | --EXPECTF--
57 | array(2) {
58 | ["sec"]=>
59 | int(5)
60 | ["usec"]=>
61 | int(5)
62 | }
63 | NULL
64 | array(2) {
65 | ["sec"]=>
66 | int(10)
67 | ["usec"]=>
68 | int(0)
69 | }
70 | NULL
71 | array(2) {
72 | ["sec"]=>
73 | int(10)
74 | ["usec"]=>
75 | int(5)
76 | }
77 | %Astomp_set_read_timeout()%s2%S string given%A
78 | array(2) {
79 | ["sec"]=>
80 | int(10)
81 | ["usec"]=>
82 | int(5)
83 | }
84 | %Astomp_set_read_timeout()%s3%s string given%A
85 | array(2) {
86 | ["sec"]=>
87 | int(10)
88 | ["usec"]=>
89 | int(5)
90 | }
91 | NULL
92 | array(2) {
93 | ["sec"]=>
94 | int(0)
95 | ["usec"]=>
96 | int(0)
97 | }
98 |
--------------------------------------------------------------------------------
/tests/011-commit/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test Stomp::commit() - tests functionnality and parameters
3 | --SKIPIF--
4 |
8 | --FILE--
9 | begin('t1'));
17 |
18 | // sends a message to the queue and specifies a good transaction
19 | var_dump($s->send('/queue/test-011-commit', 'bar', array('transaction' => 't1')));
20 |
21 | // sends a message to the queue and asks for a receipt
22 | $s->send('/queue/test-011-commit', 'bar', array('transaction' => 't2', 'receipt' => 'tptp'));
23 | echo gettype($s->error()) . PHP_EOL;
24 |
25 | // commits a valid transaction
26 | var_dump($s->commit('t1'));
27 |
28 | // commits non valid transaction (null as a parameter) and asks for a receipt
29 | var_dump($s->commit(null, array('receipt' => 'commit-key')));
30 | var_dump($s->commit(null));
31 |
32 | // commits a non valid transaction (a transaction id that does not exist) and asks for a receipt
33 | $s->commit('t2', array('receipt' => 'commit-key'));
34 | echo gettype($s->error());
35 |
36 | unset($s);
37 | ?>
38 | --EXPECTF--
39 | bool(true)
40 | bool(true)
41 | string
42 | bool(true)
43 | bool(false)
44 | bool(true)
45 | string
46 |
--------------------------------------------------------------------------------
/tests/bug_16930.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #16930 - readFrame reports error-frames as "timeout"
3 | --SKIPIF--
4 |
8 | --FILE--
9 | abort('t2');
15 | try {
16 | var_dump($s->readFrame());
17 | } catch(StompException $e) {
18 | var_dump($e->getMessage());
19 | }
20 |
21 | ?>
22 | --EXPECTF--
23 | string(%d) "%s"
24 |
--------------------------------------------------------------------------------
/tests/bug_16936.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #16936 - Module segfaults on readFrame if Frame > STOMP_BUFSIZE
3 | --SKIPIF--
4 |
8 | --FILE--
9 | getMessage());
21 | }
22 |
23 | /* send a message to the queue 'foo' */
24 | $stomp->send($queue, $msg);
25 |
26 | /* subscribe to messages from the queue 'foo' */
27 | $stomp->subscribe($queue, array('ack' => 'auto'));
28 |
29 | /* read a frame */
30 | $frame = $stomp->readFrame();
31 |
32 | if ($frame->body === $msg) {
33 | var_dump($frame->body);
34 | /* acknowledge that the frame was received */
35 | $stomp->ack($frame);
36 | }
37 |
38 | /* close connection */
39 | unset($stomp);
40 |
41 | ?>
42 | --EXPECTF--
43 | string(%d) "%s"
44 |
--------------------------------------------------------------------------------
/tests/config.inc:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------