Commit 2708378d2177da44a4571168cb0f3e9783d9cb96

Authored by Tom Huang
1 parent 294187800e
Exists in master

start

Signed-off-by: Tom Huang <tom_huang@sanlien.com.tw>
... ... @@ -0,0 +1,427 @@
  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
... ...
mosquitto_message.c
... ... @@ -0,0 +1,425 @@
  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 +}
... ...
... ... @@ -0,0 +1,61 @@
  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 +-->
... ...
... ... @@ -0,0 +1,179 @@
  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__ */
... ...