Commit 2708378d2177da44a4571168cb0f3e9783d9cb96

Authored by Tom Huang
1 parent 294187800e
Exists in master

start

Signed-off-by: Tom Huang <tom_huang@sanlien.com.tw>
File was created 1 # Mosquitto-PHP
2
3 This is an extension to allow using the [Mosquitto MQTT library](http://mosquitto.org) with PHP. See the examples/ directory for usage.
4
5 [![Build Status](https://travis-ci.org/mgdm/Mosquitto-PHP.svg?branch=master)](https://travis-ci.org/mgdm/Mosquitto-PHP)
6
7 ## Requirements
8
9 * PHP 5.3+
10 * libmosquitto 1.2.x
11 * Linux or Mac OS X. I do not have a Windows machine handy, though patches or
12 pull requests are of course very welcome!
13
14 ## Installation
15
16 You may obtain this package using [PECL](http://pecl.php.net):
17
18 ````
19 pecl install Mosquitto-alpha
20 ````
21
22 Alternatively, you can use the normal extension build process:
23
24 ````
25 phpize
26 ./configure --with-mosquitto=/path/to/libmosquitto
27 make
28 make install
29 ````
30
31 Then add `extension=mosquitto.so` to your `php.ini`.
32
33 The `--with-mosquitto` argument is optional, and only required if your
34 libmosquitto install cannot be found.
35
36 ## Documentation
37
38 The classes in this extension are namespaced.
39
40 ### Class Mosquitto\Client
41
42 This is the actual Mosquitto client.
43
44 1. [__construct](#__construct) - create a new client
45 1. [setCredentials](#setcredentials) - set the credentials to use on connection
46 1. [setTlsCertificates](#settlscertificates) - set the TLS certificate sources
47 1. [setTlsInsecure](#settlsinsecure) - Set verification of the server hostname
48 in TLS certificates
49 1. [setTlsOptions](#settlsoptions) - Set advanced TLS options
50 1. [setTlsPSK](#settlspsk) - Configure the client for pre-shared-key based TLS
51 support.
52 1. [setWill](#setwill) - set the client will, to be delivered if disconnected
53 uncleanly
54 1. [clearWill](#clearwill) - clear a previously-set will
55 1. [setReconnectDelay](#setreconnectdelay) - set the behaviour if disconnected
56 uncleanly
57 1. [connect](#connect) - connect to an MQTT broker
58 1. [disconnect](#disconnect) - disconnect from an MQTT broker
59 1. [onConnect](#onconnect) - set the connect callback
60 1. [onDisconnect](#ondisconnect) - set the disconnect callback
61 1. [onLog](#onlog) - set the logging callback
62 1. [onSubscribe](#onsubscribe) - set the subscribe callback
63 1. [onMessage](#onmessage) - set the callback fired when a message is received
64 1. [setMaxInFlightMessages](#setmaxinflightmessages) - set the number of QoS
65 1 and 2 messages that can be "in flight" at once
66 1. [setMessageRetry](#setmessageretry) - set the number of seconds to wait
67 before retrying messages
68 1. [publish](#publish) - publish a message to a broker
69 1. [subscribe](#subscribe) - subscribe to a topic
70 1. [unsubscribe](#unsubscribe) - unsubscribe from a topic
71 1. [loop](#loop) - The main network loop
72 1. [loopForever](#loopforever) - run loop() in an infinite blocking loop
73
74 #### __construct
75
76 Creates a new Client instance.
77
78 | Parameter | Type | Description |
79 | --- | --- | ---- |
80 | id | string | Client ID. Optional. If not supplied or NULL, one will be generated at random. |
81 | clean_session | boolean | Set to true to instruct the broker to clean all messages and subscriptions on disconnect. |
82
83 #### setCredentials
84
85 Set the username and password to use on connecting to the broker. Must be
86 called before connect().
87
88 | Parameter | Type | Description |
89 | --- | --- | ---- |
90 | Username | string | Username to supply to the broker |
91 | Password | string | Password to supply to the broker |
92
93 #### setTlsCertificates
94
95 Configure the client for certificate based SSL/TLS support. Must be called
96 before connect(). Cannot be used in conjunction with setTlsPSK().
97
98 Define the Certificate Authority certificates to be trusted (ie. the server
99 certificate must be signed with one of these certificates) using cafile.
100 If the server you are connecting to requires clients to provide a certificate,
101 define certfile and keyfile with your client certificate and private key. If
102 your private key is encrypted, provide the password as the fourth parameter, or
103 you will have to enter the password at the command line.
104
105 | Parameter | Type | Description |
106 | --- | --- | ---- |
107 | capath | string | Path to the PEM encoded trusted CA certificate files, or to a directory containing them |
108 | certfile | string | Path to the PEM encoded certificate file for this client. Optional. |
109 | keyfile | string | Path to a file containing the PEM encoded private key for this client. Required if certfile is set. |
110 | password | string | The password for the keyfile, if it is encrypted. If null, the password will be asked for on the command line. |
111
112 #### setTlsInsecure
113
114 Configure verification of the server hostname in the server certificate. If
115 value is set to true, it is impossible to guarantee that the host you are
116 connecting to is not impersonating your server. Do not use this function in
117 a real system. Must be called before connect().
118
119 | Parameter | Type | Description |
120 | --- | --- | ---- |
121 | value | boolean | If set to false, the default, certificate hostname checking is performed. If set to true, no hostname checking is performed and the connection is insecure. |
122
123 #### setTlsOptions
124
125 Set advanced SSL/TLS options. Must be called before connect().
126
127 | Parameter | Type | Description |
128 | --- | --- | ---- |
129 | certReqs | int | Whether or not to verify the server. Can be Mosquitto\Client::SSL_VERIFY_NONE, to disable certificate verification, or Mosquitto\Client::SSL_VERIFY_PEER (the default), to verify the server certificate. |
130 | tlsVersion | string | The TLS version to use. If NULL, a default is used. The default value depends on the version of OpenSSL the library was compiled against. Available options on OpenSSL >= 1.0.1 are 'tlsv1.2', 'tlsv1.1' and 'tlsv1'. |
131 | cipers | string | A string describing the ciphers available for use. See the `openssl ciphers` tool for more information. If NULL, the default set will be used. |
132
133 #### setTlsPSK
134
135 Configure the client for pre-shared-key based TLS support. Must be called before connect(). Cannot be used in conjunction with setTlsCertificates.
136
137 | Parameter | Type | Description |
138 | --- | --- | ---- |
139 | psk | string | The pre-shared key in hex format with no leading "0x".
140 | identity | string | The identity of this client. May be used as the username depending on server settings. |
141 | cipers | string | Optional. A string describing the ciphers available for use. See the `openssl ciphers` tool for more information. If NULL, the default set will be used. |
142
143 #### setWill
144
145 Set the client "last will and testament", which will be sent on an unclean
146 disconnection from the broker. Must be called before connect().
147
148 | Parameter | Type | Description |
149 | --- | --- | ---- |
150 | topic | string | The topic on which to publish the will. |
151 | payload | string | The data to send. |
152 | qos | int | Optional. Default 0. Integer 0, 1, or 2 indicating the Quality of Service to be used. |
153 | retain | boolean | Optional. Default false. If true, the message will be retained. |
154
155 #### clearWill
156
157 Remove a previously-set will. No parameters.
158
159 #### setReconnectDelay
160
161 Control the behaviour of the client when it has unexpectedly disconnected in
162 loopForever. The default behaviour if this method is not used is to
163 repeatedly attempt to reconnect with a delay of 1 second until the connection
164 succeeds.
165
166 | Parameter | Type | Description |
167 | --- | --- | ---- |
168 | reconnect_delay | int | Set delay between successive reconnection attempts. |
169 | reconnect_delay | int | Set max delay between successive reconnection attempts when exponential backoff is enabled |
170 | exponential_backoff | bool | Enable exponential backoff |
171
172 #### connect
173
174 Connect to an MQTT broker.
175
176 | Parameter | Type | Description |
177 | --- | --- | ---- |
178 | host | string | Hostname to connect to |
179 | port | int | Optional. Port number to connect to. Defaults to 1883. |
180 | keepalive | int | Optional. Number of sections after which the broker should PING the client if no messages have been recieved. |
181 | interface | string | Optional. The address or hostname of a local interface to bind to for this connection. |
182
183 #### disconnect
184
185 Disconnect from the broker. No parameters.
186
187 #### onConnect
188
189 Set the connect callback. This is called when the broker sends a CONNACK message in response to a connection.
190
191 | Parameter | Type | Description |
192 | --- | --- | ---- |
193 | callback | callback | The callback |
194
195 The callback should take parameters of the form:
196
197 | Parameter | Type | Description |
198 | --- | --- | ---- |
199 | rc | int | Response code from the broker. |
200 | message | string | String description of the response code. |
201
202 Response codes are as follows:
203
204 | Code | Meaning |
205 | --- | --- |
206 | 0 | Success |
207 | 1 | Connection refused (unacceptable protocol version) |
208 | 2 | Connection refused (identifier rejected) |
209 | 3 | Connection refused (broker unavailable ) |
210 | 4-255 | Reserved for future use |
211
212 #### onDisconnect
213
214 Set the disconnect callback. This is called when the broker has received the
215 DISCONNECT command and has disconnected the client.
216
217 | Parameter | Type | Description |
218 | --- | --- | ---- |
219 | callback | callback | The callback |
220
221 The callback should take parameters of the form:
222
223 | Parameter | Type | Description |
224 | --- | --- | ---- |
225 | rc | int | Reason for the disconnection. 0 means the client requested it. Any other value indicates an unexpected disconnection. |
226
227 #### onLog
228
229 Set the logging callback.
230
231 | Parameter | Type | Description |
232 | --- | --- | ---- |
233 | callback | callback | The callback |
234
235 The callback should take parameters of the form:
236
237 | Parameter | Type | Description |
238 | --- | --- | ---- |
239 | level | int | The log message level from the values below |
240 | str | string | The message string.
241
242 The level can be one of:
243
244 * Mosquitto\Client::LOG_DEBUG
245 * Mosquitto\Client::LOG_INFO
246 * Mosquitto\Client::LOG_NOTICE
247 * Mosquitto\Client::LOG_WARNING
248 * Mosquitto\Client::LOG_ERR
249
250 #### onSubscribe
251
252 Set the subscribe callback. This is called when the broker responds to
253 a subscription request.
254
255 | Parameter | Type | Description |
256 | --- | --- | ---- |
257 | callback | callback | The callback |
258
259 The callback should take parameters of the form:
260
261 | Parameter | Type | Description |
262 | --- | --- | ---- |
263 | mid | int | Message ID of the subscribe message |
264 | qos_count | int | Number of granted subscriptions |
265
266 This function needs to return the granted QoS for each subscription, but
267 currently cannot.
268
269 #### onUnsubscribe
270
271 Set the unsubscribe callback. This is called when the broker responds to
272 a unsubscribe request.
273
274 | Parameter | Type | Description |
275 | --- | --- | ---- |
276 | callback | callback | The callback |
277
278 The callback should take parameters of the form:
279
280 | Parameter | Type | Description |
281 | --- | --- | ---- |
282 | mid | int | Message ID of the unsubscribe message |
283
284 #### onMessage
285
286 Set the message callback. This is called when a message is received from the broker.
287
288 | Parameter | Type | Description |
289 | --- | --- | ---- |
290 | callback | callback | The callback |
291
292 The callback should take parameters of the form:
293
294 | Parameter | Type | Description |
295 | --- | --- | ---- |
296 | message | Mosquitto\Message | A Message object containing the message data |
297
298
299 #### setMaxInFlightMessages
300
301 Set the number of QoS 1 and 2 messages that can be โ€œin flightโ€ at one time. An
302 in flight message is part way through its delivery flow. Attempts to send
303 further messages with publish() will result in the messages being queued until
304 the number of in flight messages reduces.
305
306 Set to 0 for no maximum.
307
308 | Parameter | Type | Description |
309 | --- | --- | ---- |
310 | max_inflight_messages | int | The maximum |
311
312 #### setMessageRetry
313
314 Set the number of seconds to wait before retrying messages. This applies to
315 publish messages with QoS>0. May be called at any time.
316
317 | Parameter | Type | Description |
318 | --- | --- | ---- |
319 | message_retry | int | The retry period |
320
321 #### publish
322
323 Publish a message on a given topic.
324
325 | Parameter | Type | Description |
326 | --- | --- | ---- |
327 | topic | string | The topic to publish on |
328 | payload | string | The message payload |
329 | qos | int | Integer value 0, 1 or 2 indicating the QoS for this message |
330 | retain | boolean | If true, make this message retained |
331
332 #### subscribe
333
334 Subscribe to a topic.
335
336 | Parameter | Type | Description |
337 | --- | --- | ---- |
338 | topic | string | The topic. |
339 | qos | The QoS to request for this subscription |
340
341 Returns the message ID of the subscription message, so this can be matched up
342 in the onSubscribe callback.
343
344 #### unsubscribe
345
346 Unsubscribe from a topic.
347
348 | Parameter | Type | Description |
349 | --- | --- | ---- |
350 | topic | string | The topic. |
351 | qos | The QoS to request for this subscription |
352
353 Returns the message ID of the subscription message, so this can be matched up
354 in the onUnsubscribe callback.
355
356 #### loop
357
358 The main network loop for the client. You must call this frequently in order
359 to keep communications between the client and broker working. If incoming data
360 is present it will then be processed. Outgoing commands, from e.g. publish(),
361 are normally sent immediately that their function is called, but this is not
362 always possible. loop() will also attempt to send any remaining outgoing
363 messages, which also includes commands that are part of the flow for messages
364 with QoS>0.
365
366 | Parameter | Type | Description |
367 | --- | --- | ---- |
368 | timeout | int | Optional. Number of milliseconds to wait for network activity. Pass 0 for instant timeout. Defaults to 1000. |
369 | max_packets | int | Currently unused. |
370
371 #### loopForever
372
373 Call loop() in an infinite blocking loop. Callbacks will be called as required.
374 This will handle reconnecting if the connection is lost. Call disconnect() in
375 a callback to return from the loop.
376
377 Note: exceptions thrown in callbacks do not currently cause the loop to exit. To work around this, use loop() and wrap your own loop structure around it such as a while().
378
379 | Parameter | Type | Description |
380 | --- | --- | ---- |
381 | timeout | int | Optional. Number of milliseconds to wait for network activity. Pass 0 for instant timeout. Defaults to 1000. |
382 | max_packets | int | Currently unused. |
383
384 ### Class Mosquitto\Message
385
386 Represents a message received from a broker. All data is represented as
387 properties.
388
389 | Property | Type | Description |
390 | --- | --- | --- |
391 | topic | string | The topic this message was delivered to. |
392 | payload | string | The payload of this message. |
393 | mid | int | The ID of this message. |
394 | qos | int | The QoS value applied to this message. |
395 | retain | bool | Whether this is a retained message or not. |
396
397 This class has two static methods.
398
399 #### topicMatchesSub
400
401 Returns true if the supplied topic matches the supplied description, and
402 otherwise false.
403
404 | Parameter | Type | Description |
405 | --- | --- | ---- |
406 | topic | string | The topic to match |
407 | subscription | string | The subscription to match |
408
409 #### tokeniseTopic
410
411 Tokenise a topic or subscription string into an array of strings representing the topic hierarchy.
412
413 | Parameter | Type | Description |
414 | --- | --- | ---- |
415 | topic | string | The topic to tokenise |
416
417 ### Class Mosquitto\Exception
418
419 This is an exception that may be thrown by many of the operations in the Client
420 object.
421
422 ## To do
423
424 * Arginfo
425 * Logging callbacks
426 * TLS support
427 * Tests
428
mosquitto_message.c
File was created 1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "php.h"
6 #include "php_ini.h"
7 #include "zend_variables.h"
8 #include "zend_exceptions.h"
9 #include "zend_API.h"
10 #include "ext/standard/info.h"
11 #include "php_mosquitto.h"
12
13 zend_class_entry *mosquitto_ce_message;
14 static zend_object_handlers mosquitto_message_object_handlers;
15 static HashTable php_mosquitto_message_properties;
16
17 /* {{{ Arginfo */
18
19 ZEND_BEGIN_ARG_INFO(Mosquitto_Message_topicMatchesSub_args, ZEND_SEND_BY_VAL)
20 ZEND_ARG_INFO(0, topic)
21 ZEND_ARG_INFO(0, subscription)
22 ZEND_END_ARG_INFO()
23
24 ZEND_BEGIN_ARG_INFO(Mosquitto_Message_tokeniseTopic_args, ZEND_SEND_BY_VAL)
25 ZEND_ARG_INFO(0, topic)
26 ZEND_END_ARG_INFO()
27
28 /* }}} */
29
30 PHP_METHOD(Mosquitto_Message, __construct)
31 {
32 PHP_MOSQUITTO_ERROR_HANDLING();
33 if (zend_parse_parameters_none() == FAILURE) {
34 PHP_MOSQUITTO_RESTORE_ERRORS();
35 return;
36 }
37 PHP_MOSQUITTO_RESTORE_ERRORS();
38 }
39
40 /* {{{ Mosquitto\Message::topicMatchesSub() */
41 PHP_METHOD(Mosquitto_Message, topicMatchesSub)
42 {
43 char *topic = NULL, *subscription = NULL;
44 int topic_len, subscription_len;
45 zend_bool result;
46
47 PHP_MOSQUITTO_ERROR_HANDLING();
48 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
49 &topic, &topic_len, &subscription, &subscription_len) == FAILURE) {
50 PHP_MOSQUITTO_RESTORE_ERRORS();
51 return;
52 }
53 PHP_MOSQUITTO_RESTORE_ERRORS();
54
55 mosquitto_topic_matches_sub(subscription, topic, (bool *) &result);
56 RETURN_BOOL(result);
57 }
58 /* }}} */
59
60 /* {{{ Mosquitto\Message::tokeniseTopic() */
61 PHP_METHOD(Mosquitto_Message, tokeniseTopic)
62 {
63 char *topic = NULL, **topics = NULL;
64 int topic_len = 0, retval = 0, count = 0, i = 0;
65
66 PHP_MOSQUITTO_ERROR_HANDLING();
67 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &topic, &topic_len) == FAILURE) {
68 PHP_MOSQUITTO_RESTORE_ERRORS();
69 return;
70 }
71 PHP_MOSQUITTO_RESTORE_ERRORS();
72
73 retval = mosquitto_sub_topic_tokenise(topic, &topics, &count);
74
75 if (retval == MOSQ_ERR_NOMEM) {
76 zend_throw_exception_ex(mosquitto_ce_exception, 0 TSRMLS_CC, "Failed to tokenise topic");
77 return;
78 }
79
80 array_init(return_value);
81 for (i = 0; i < count; i++) {
82 if (topics[i] == NULL) {
83 add_next_index_null(return_value);
84 } else {
85 add_next_index_string(return_value, topics[i], 1);
86 }
87 }
88
89 mosquitto_sub_topic_tokens_free(&topics, count);
90 }
91 /* }}} */
92
93 PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_READER_FUNCTION(mid);
94 PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_READER_FUNCTION(qos);
95
96 static int php_mosquitto_message_read_retain(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC)
97 {
98 MAKE_STD_ZVAL(*retval);
99 ZVAL_BOOL(*retval, mosquitto_object->message.retain);
100 return SUCCESS;
101 }
102
103 static int php_mosquitto_message_read_topic(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC)
104 {
105 MAKE_STD_ZVAL(*retval);
106
107 if (mosquitto_object->message.topic != NULL) {
108 ZVAL_STRINGL(*retval, mosquitto_object->message.topic, strlen(mosquitto_object->message.topic), 1);
109 } else {
110 ZVAL_NULL(*retval);
111 }
112
113 return SUCCESS;
114 }
115
116 static int php_mosquitto_message_read_payload(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC)
117 {
118 MAKE_STD_ZVAL(*retval);
119 ZVAL_STRINGL(*retval, mosquitto_object->message.payload, mosquitto_object->message.payloadlen, 1);
120 return SUCCESS;
121 }
122
123 PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_WRITER_FUNCTION(mid);
124 PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_WRITER_FUNCTION(qos);
125
126 static int php_mosquitto_message_write_retain(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC)
127 {
128 zval ztmp;
129 if (Z_TYPE_P(newval) != IS_BOOL) {
130 ztmp = *newval;
131 zval_copy_ctor(&ztmp);
132 convert_to_boolean(&ztmp);
133 newval = &ztmp;
134 }
135
136 mosquitto_object->message.retain = Z_LVAL_P(newval);
137
138 if (newval == &ztmp) {
139 zval_dtor(newval);
140 }
141
142 return SUCCESS;
143 }
144
145 static int php_mosquitto_message_write_topic(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC)
146 {
147 zval ztmp;
148 if (Z_TYPE_P(newval) != IS_STRING) {
149 ztmp = *newval;
150 zval_copy_ctor(&ztmp);
151 convert_to_string(&ztmp);
152 newval = &ztmp;
153 }
154
155 if (mosquitto_object->message.topic && mosquitto_object->owned_topic) {
156 efree(mosquitto_object->message.topic);
157 }
158
159 mosquitto_object->message.topic = estrdup(Z_STRVAL_P(newval));
160 mosquitto_object->owned_topic = 1;
161
162 if (newval == &ztmp) {
163 zval_dtor(newval);
164 }
165
166 return SUCCESS;
167 }
168
169 static int php_mosquitto_message_write_payload(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC)
170 {
171 zval ztmp;
172 if (Z_TYPE_P(newval) != IS_STRING) {
173 ztmp = *newval;
174 zval_copy_ctor(&ztmp);
175 convert_to_string(&ztmp);
176 newval = &ztmp;
177 }
178
179 if (mosquitto_object->message.payload && mosquitto_object->owned_payload) {
180 efree(mosquitto_object->message.payload);
181 mosquitto_object->message.payloadlen = 0;
182 }
183
184 mosquitto_object->message.payload = estrdup(Z_STRVAL_P(newval));
185 mosquitto_object->message.payloadlen = Z_STRLEN_P(newval);
186 mosquitto_object->owned_payload = 1;
187
188 if (newval == &ztmp) {
189 zval_dtor(newval);
190 }
191
192 return SUCCESS;
193 }
194
195 const php_mosquitto_prop_handler php_mosquitto_message_property_entries[] = {
196 PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(mid),
197 PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(topic),
198 PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(payload),
199 PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(qos),
200 PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(retain),
201 {NULL, 0, NULL, NULL}
202 };
203
204 zval *php_mosquitto_message_read_property(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC)
205 {
206 zval tmp_member;
207 zval *retval;
208 mosquitto_message_object *message_object;
209 php_mosquitto_prop_handler *hnd;
210 int ret;
211
212 message_object = (mosquitto_message_object *) zend_object_store_get_object(object TSRMLS_CC);
213
214 if (Z_TYPE_P(member) != IS_STRING) {
215 tmp_member = *member;
216 zval_copy_ctor(&tmp_member);
217 convert_to_string(&tmp_member);
218 member = &tmp_member;
219 }
220
221 ret = zend_hash_find(&php_mosquitto_message_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
222
223 if (ret == SUCCESS && hnd->read_func) {
224 ret = hnd->read_func(message_object, &retval TSRMLS_CC);
225 if (ret == SUCCESS) {
226 /* ensure we're creating a temporary variable */
227 Z_SET_REFCOUNT_P(retval, 0);
228 } else {
229 retval = EG(uninitialized_zval_ptr);
230 }
231 } else {
232 zend_object_handlers * std_hnd = zend_get_std_object_handlers();
233 retval = std_hnd->read_property(object, member, type ZEND_LITERAL_KEY_CC TSRMLS_CC);
234 }
235
236 if (member == &tmp_member) {
237 zval_dtor(member);
238 }
239
240 return(retval);
241 }
242
243 void php_mosquitto_message_write_property(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC)
244 {
245 zval tmp_member;
246 mosquitto_message_object *obj;
247 php_mosquitto_prop_handler *hnd;
248 int ret;
249
250 if (Z_TYPE_P(member) != IS_STRING) {
251 tmp_member = *member;
252 zval_copy_ctor(&tmp_member);
253 convert_to_string(&tmp_member);
254 member = &tmp_member;
255 }
256
257 ret = FAILURE;
258 obj = (mosquitto_message_object *)zend_objects_get_address(object TSRMLS_CC);
259
260 ret = zend_hash_find(&php_mosquitto_message_properties, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &hnd);
261
262 if (ret == SUCCESS && hnd->write_func) {
263 hnd->write_func(obj, value TSRMLS_CC);
264 if (! PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
265 Z_ADDREF_P(value);
266 zval_ptr_dtor(&value);
267 }
268 } else {
269 zend_object_handlers * std_hnd = zend_get_std_object_handlers();
270 std_hnd->write_property(object, member, value ZEND_LITERAL_KEY_CC TSRMLS_CC);
271 }
272
273 if (member == &tmp_member) {
274 zval_dtor(member);
275 }
276 }
277
278 static int php_mosquitto_message_has_property(zval *object, zval *member, int has_set_exists ZEND_LITERAL_KEY_DC TSRMLS_DC)
279 {
280 php_mosquitto_prop_handler *hnd;
281 int ret = 0;
282
283 if (zend_hash_find(&php_mosquitto_message_properties, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **)&hnd) == SUCCESS) {
284 switch (has_set_exists) {
285 case 2:
286 ret = 1;
287 break;
288 case 0: {
289 zval *value = php_mosquitto_message_read_property(object, member, BP_VAR_IS ZEND_LITERAL_KEY_CC TSRMLS_CC);
290 if (value != EG(uninitialized_zval_ptr)) {
291 ret = Z_TYPE_P(value) != IS_NULL? 1:0;
292 /* refcount is 0 */
293 Z_ADDREF_P(value);
294 zval_ptr_dtor(&value);
295 }
296 break;
297 }
298 default: {
299 zval *value = php_mosquitto_message_read_property(object, member, BP_VAR_IS ZEND_LITERAL_KEY_CC TSRMLS_CC);
300 if (value != EG(uninitialized_zval_ptr)) {
301 convert_to_boolean(value);
302 ret = Z_BVAL_P(value)? 1:0;
303 /* refcount is 0 */
304 Z_ADDREF_P(value);
305 zval_ptr_dtor(&value);
306 }
307 break;
308 }
309 }
310 } else {
311 zend_object_handlers * std_hnd = zend_get_std_object_handlers();
312 ret = std_hnd->has_property(object, member, has_set_exists ZEND_LITERAL_KEY_CC TSRMLS_CC);
313 }
314 return ret;
315 }
316
317 static HashTable *php_mosquitto_message_get_properties(zval *object TSRMLS_DC)
318 {
319 mosquitto_message_object *obj;
320 php_mosquitto_prop_handler *hnd;
321 HashTable *props;
322 zval *val;
323 char *key;
324 uint key_len;
325 HashPosition pos;
326 ulong num_key;
327
328 obj = (mosquitto_message_object *)zend_objects_get_address(object TSRMLS_CC);
329 props = zend_std_get_properties(object TSRMLS_CC);
330
331 zend_hash_internal_pointer_reset_ex(&php_mosquitto_message_properties, &pos);
332
333 while (zend_hash_get_current_data_ex(&php_mosquitto_message_properties, (void**)&hnd, &pos) == SUCCESS) {
334 zend_hash_get_current_key_ex(&php_mosquitto_message_properties, &key, &key_len, &num_key, 0, &pos);
335 if (!hnd->read_func || hnd->read_func(obj, &val TSRMLS_CC) != SUCCESS) {
336 val = EG(uninitialized_zval_ptr);
337 Z_ADDREF_P(val);
338 }
339 zend_hash_update(props, key, key_len, (void *)&val, sizeof(zval *), NULL);
340 zend_hash_move_forward_ex(&php_mosquitto_message_properties, &pos);
341 }
342 return obj->std.properties;
343 }
344
345
346 void php_mosquitto_message_add_property(HashTable *h, const char *name, size_t name_length, php_mosquitto_read_t read_func, php_mosquitto_write_t write_func TSRMLS_DC)
347 {
348 php_mosquitto_prop_handler p;
349
350 p.name = (char*) name;
351 p.name_length = name_length;
352 p.read_func = (read_func) ? read_func : NULL;
353 p.write_func = (write_func) ? write_func : NULL;
354 zend_hash_add(h, (char *)name, name_length + 1, &p, sizeof(php_mosquitto_prop_handler), NULL);
355 }
356
357 static void mosquitto_message_object_destroy(void *object TSRMLS_DC)
358 {
359 mosquitto_message_object *message = (mosquitto_message_object *) object;
360 zend_hash_destroy(message->std.properties);
361 FREE_HASHTABLE(message->std.properties);
362
363 if (message->owned_topic == 1) {
364 efree(message->message.topic);
365 }
366
367 if (message->owned_payload == 1) {
368 efree(message->message.payload);
369 }
370
371 efree(object);
372 }
373
374 static zend_object_value mosquitto_message_object_new(zend_class_entry *ce TSRMLS_DC) {
375
376 zend_object_value retval;
377 mosquitto_message_object *message_obj;
378 #if PHP_VERSION_ID < 50399
379 zval *temp;
380 #endif
381
382 message_obj = ecalloc(1, sizeof(mosquitto_message_object));
383 message_obj->std.ce = ce;
384
385 #ifdef ZTS
386 message_obj->TSRMLS_C = TSRMLS_C;
387 #endif
388
389 ALLOC_HASHTABLE(message_obj->std.properties);
390 zend_hash_init(message_obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
391 #if PHP_VERSION_ID < 50399
392 zend_hash_copy(message_obj->std.properties, &mosquitto_ce_message->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &temp, sizeof(zval *));
393 #else
394 object_properties_init(&message_obj->std, mosquitto_ce_message);
395 #endif
396 retval.handle = zend_objects_store_put(message_obj, NULL, (zend_objects_free_object_storage_t) mosquitto_message_object_destroy, NULL TSRMLS_CC);
397 retval.handlers = &mosquitto_message_object_handlers;
398 return retval;
399 }
400
401 const zend_function_entry mosquitto_message_methods[] = {
402 PHP_ME(Mosquitto_Message, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
403 PHP_ME(Mosquitto_Message, topicMatchesSub, Mosquitto_Message_topicMatchesSub_args, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
404 PHP_ME(Mosquitto_Message, tokeniseTopic, Mosquitto_Message_tokeniseTopic_args, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
405 PHP_FE_END
406 };
407
408 PHP_MINIT_FUNCTION(mosquitto_message)
409 {
410 zend_class_entry message_ce;
411 memcpy(&mosquitto_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
412 mosquitto_message_object_handlers.read_property = php_mosquitto_message_read_property;
413 mosquitto_message_object_handlers.write_property = php_mosquitto_message_write_property;
414 mosquitto_message_object_handlers.has_property = php_mosquitto_message_has_property;
415 mosquitto_message_object_handlers.get_properties = php_mosquitto_message_get_properties;
416
417 INIT_NS_CLASS_ENTRY(message_ce, "Mosquitto", "Message", mosquitto_message_methods);
418 mosquitto_ce_message = zend_register_internal_class(&message_ce TSRMLS_CC);
419 mosquitto_ce_message->create_object = mosquitto_message_object_new;
420
421 zend_hash_init(&php_mosquitto_message_properties, 0, NULL, NULL, 1);
422 PHP_MOSQUITTO_ADD_PROPERTIES(&php_mosquitto_message_properties, php_mosquitto_message_property_entries);
423
424 return SUCCESS;
425 }
426
File was created 1 <?xml version="1.0" encoding="UTF-8"?>
2 <package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.4.7" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
3 <name>Mosquitto</name>
4 <channel>pecl.mgdm.net</channel>
5 <summary>Extension for libmosquitto</summary>
6 <description>Mosquitto provides support for the MQTT protocol, including publishing, subscribing, and an event loop.</description>
7 <lead>
8 <name>Michael Maclean</name>
9 <user>mgdm</user>
10 <email>mgdm@php.net</email>
11 <active>yes</active>
12 </lead>
13
14 <date>2014-04-28</date>
15 <version><release>0.2.2</release><api>0.2.0</api></version>
16 <stability><release>alpha</release><api>alpha</api></stability>
17 <license uri="http://opensource.org/licenses/BSD-3-Clause">BSD 3-Clause License</license>
18 <notes>
19 * Add missing unsubscribe method
20 </notes>
21
22 <contents>
23 <dir name="/">
24 <file role="doc" name="README.md"/>
25 <file role="doc" name="CREDITS"/>
26 <file role="doc" name="LICENSE"/>
27
28 <file role="src" name="php_mosquitto.h"/>
29
30 <file role="src" name="mosquitto.c"/>
31 <file role="src" name="mosquitto_message.c"/>
32
33 <file role="src" name="config.m4"/>
34 <file role="src" name="config.w32"/>
35 </dir>
36 </contents>
37
38 <dependencies>
39 <required>
40 <php>
41 <min>5.3.0</min>
42 </php>
43 <pearinstaller>
44 <min>1.4.0</min>
45 </pearinstaller>
46 </required>
47
48 </dependencies>
49
50 <providesextension>mosquitto</providesextension>
51
52 <extsrcrelease>
53 <configureoption default="autodetect" name="with-mosquitto" prompt="Please provide the prefix of the libmosquitto installation" />
54 </extsrcrelease>
55
56 <changelog>
57 </changelog>
58 </package>
59 <!--
60 vim:et:ts=1:sw=1
61 -->
62
File was created 1 #ifndef PHP_MOSQUITTO_H
2 #define PHP_MOSQUITTO_H
3
4 #define PHP_MOSQUITTO_VERSION "0.2.2"
5
6 extern zend_module_entry mosquitto_module_entry;
7 #define phpext_mosquitto_ptr &mosquitto_module_entry
8
9 #ifdef PHP_WIN32
10 # define PHP_MOSQUITTO_API __declspec(dllexport)
11 #elif defined(__GNUC__) && __GNUC__ >= 4
12 # define PHP_MOSQUITTO_API __attribute__ ((visibility("default")))
13 #else
14 # define PHP_MOSQUITTO_API
15 #endif
16
17 #ifdef __GLIBC__
18 #define POSSIBLY_UNUSED __attribute__((unused))
19 #else
20 #define POSSIBLY_UNUSED
21 #endif
22
23 #if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50399)
24 # define ZEND_LITERAL_KEY_DC , const zend_literal *_zend_literal_key
25 # define ZEND_LITERAL_KEY_CC , _zend_literal_key
26 # define ZEND_LITERAL_NIL_CC , NULL
27 #else
28 # define ZEND_LITERAL_KEY_DC
29 # define ZEND_LITERAL_KEY_CC
30 # define ZEND_LITERAL_NIL_CC
31 #endif
32
33 #ifdef ZTS
34 #include "TSRM.h"
35 #endif
36
37 #include <mosquitto.h>
38
39 typedef struct _mosquitto_client_object {
40 zend_object std;
41 struct mosquitto *client;
42
43 zend_fcall_info connect_callback;
44 zend_fcall_info_cache connect_callback_cache;
45 zend_fcall_info subscribe_callback;
46 zend_fcall_info_cache subscribe_callback_cache;
47 zend_fcall_info unsubscribe_callback;
48 zend_fcall_info_cache unsubscribe_callback_cache;
49 zend_fcall_info message_callback;
50 zend_fcall_info_cache message_callback_cache;
51 zend_fcall_info disconnect_callback;
52 zend_fcall_info_cache disconnect_callback_cache;
53 zend_fcall_info log_callback;
54 zend_fcall_info_cache log_callback_cache;
55
56 int looping;
57
58 #ifdef ZTS
59 TSRMLS_D;
60 #endif
61 } mosquitto_client_object;
62
63 typedef struct _mosquitto_message_object {
64 zend_object std;
65 struct mosquitto_message message;
66 zend_bool owned_topic;
67 zend_bool owned_payload;
68 #ifdef ZTS
69 TSRMLS_D;
70 #endif
71 } mosquitto_message_object;
72
73 typedef int (*php_mosquitto_read_t)(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC);
74 typedef int (*php_mosquitto_write_t)(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC);
75
76 typedef struct _php_mosquitto_prop_handler {
77 const char *name;
78 size_t name_length;
79 php_mosquitto_read_t read_func;
80 php_mosquitto_write_t write_func;
81 } php_mosquitto_prop_handler;
82
83
84 #define PHP_MOSQUITTO_ERROR_HANDLING() \
85 zend_replace_error_handling(EH_THROW, mosquitto_ce_exception, &MQTTG(mosquitto_original_error_handling) TSRMLS_CC)
86
87 #define PHP_MOSQUITTO_RESTORE_ERRORS() \
88 zend_restore_error_handling(&MQTTG(mosquitto_original_error_handling) TSRMLS_CC)
89
90
91 #define PHP_MOSQUITTO_FREE_CALLBACK(CALLBACK) \
92 if (ZEND_FCI_INITIALIZED(client->CALLBACK ## _callback)) { \
93 zval_ptr_dtor(&client->CALLBACK ## _callback.function_name); \
94 } \
95 \
96 if (client->CALLBACK ## _callback.object_ptr != NULL) { \
97 zval_ptr_dtor(&client->CALLBACK ## _callback.object_ptr); \
98 }
99
100
101 #define PHP_MOSQUITTO_MESSAGE_PROPERTY_ENTRY_RECORD(name) \
102 { "" #name "", sizeof("" #name "") - 1, php_mosquitto_message_read_##name, php_mosquitto_message_write_##name }
103
104 #define PHP_MOSQUITTO_ADD_PROPERTIES(a, b) \
105 { \
106 int i = 0; \
107 while (b[i].name != NULL) { \
108 php_mosquitto_message_add_property((a), (b)[i].name, (b)[i].name_length, \
109 (php_mosquitto_read_t)(b)[i].read_func, (php_mosquitto_write_t)(b)[i].write_func TSRMLS_CC); \
110 i++; \
111 } \
112 }
113
114 #define PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_READER_FUNCTION(name) \
115 static int php_mosquitto_message_read_##name(mosquitto_message_object *mosquitto_object, zval **retval TSRMLS_DC) \
116 { \
117 MAKE_STD_ZVAL(*retval); \
118 ZVAL_LONG(*retval, mosquitto_object->message.name); \
119 return SUCCESS; \
120 }
121
122 #define PHP_MOSQUITTO_MESSAGE_LONG_PROPERTY_WRITER_FUNCTION(name) \
123 static int php_mosquitto_message_write_##name(mosquitto_message_object *mosquitto_object, zval *newval TSRMLS_DC) \
124 { \
125 zval ztmp; \
126 if (Z_TYPE_P(newval) != IS_LONG) { \
127 ztmp = *newval; \
128 zval_copy_ctor(&ztmp); \
129 convert_to_long(&ztmp); \
130 newval = &ztmp; \
131 } \
132 \
133 mosquitto_object->message.name = Z_LVAL_P(newval); \
134 \
135 if (newval == &ztmp) { \
136 zval_dtor(newval); \
137 } \
138 return SUCCESS; \
139 }
140
141 ZEND_BEGIN_MODULE_GLOBALS(mosquitto)
142 char *client_key;
143 int client_key_len;
144 zend_object_handlers mosquitto_std_object_handlers;
145 zend_error_handling mosquitto_original_error_handling;
146 ZEND_END_MODULE_GLOBALS(mosquitto)
147
148 #ifdef ZTS
149 # define MQTTG(v) TSRMG(mosquitto_globals_id, zend_mosquitto_globals *, v)
150 #else
151 # define MQTTG(v) (mosquitto_globals.v)
152 #endif
153
154 ZEND_EXTERN_MODULE_GLOBALS(mosquitto)
155
156 extern zend_class_entry *mosquitto_ce_exception;
157 extern zend_class_entry *mosquitto_ce_client;
158 extern zend_class_entry *mosquitto_ce_message;
159
160 PHP_MOSQUITTO_API void php_mosquitto_connect_callback(struct mosquitto *mosq, void *obj, int rc);
161 PHP_MOSQUITTO_API void php_mosquitto_disconnect_callback(struct mosquitto *mosq, void *obj, int rc);
162 PHP_MOSQUITTO_API void php_mosquitto_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str);
163 PHP_MOSQUITTO_API void php_mosquitto_message_callback(struct mosquitto *mosq, void *client_obj, const struct mosquitto_message *message);
164 PHP_MOSQUITTO_API void php_mosquitto_subscribe_callback(struct mosquitto *mosq, void *client_obj, int mid, int qos_count, const int *granted_qos);
165 PHP_MOSQUITTO_API void php_mosquitto_unsubscribe_callback(struct mosquitto *mosq, void *client_obj, int mid);
166 PHP_MOSQUITTO_API void php_mosquitto_disconnect_callback(struct mosquitto *mosq, void *obj, int rc);
167
168 PHP_MOSQUITTO_API char *php_mosquitto_strerror_wrapper(int err);
169 void php_mosquitto_handle_errno(int retval, int err TSRMLS_DC);
170 void php_mosquitto_exit_loop(mosquitto_client_object *object);
171
172 PHP_MINIT_FUNCTION(mosquitto);
173 PHP_MINIT_FUNCTION(mosquitto_message);
174 PHP_MSHUTDOWN_FUNCTION(mosquitto);
175 PHP_MINFO_FUNCTION(mosquitto);
176
177 #endif /* PHP_MOSQUITTO_H */
178
179 /* __footer_here__ */
180