summaryrefslogtreecommitdiff
path: root/libs/libmosquitto
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-12-23 13:53:27 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-12-23 13:53:27 +0300
commita29c9194cf2d9f11839ea833872beab754e19527 (patch)
tree2a1ff6475dd77d41a1e6bf6acfb5be479c5543eb /libs/libmosquitto
parentc1358991022919836c77d630ee9a3719fff86ed0 (diff)
libmosquitto - a helper for MQTT clients
Diffstat (limited to 'libs/libmosquitto')
-rw-r--r--libs/libmosquitto/include/config.h69
-rw-r--r--libs/libmosquitto/include/mosquitto.h2993
-rw-r--r--libs/libmosquitto/include/uthash.h948
-rw-r--r--libs/libmosquitto/include/utlist.h1073
-rw-r--r--libs/libmosquitto/libmosquitto.vcxproj36
-rw-r--r--libs/libmosquitto/libmosquitto.vcxproj.filters4
-rw-r--r--libs/libmosquitto/src/actions.c260
-rw-r--r--libs/libmosquitto/src/callbacks.c120
-rw-r--r--libs/libmosquitto/src/connect.c330
-rw-r--r--libs/libmosquitto/src/dummypthread.h13
-rw-r--r--libs/libmosquitto/src/handle_auth.c49
-rw-r--r--libs/libmosquitto/src/handle_connack.c110
-rw-r--r--libs/libmosquitto/src/handle_disconnect.c62
-rw-r--r--libs/libmosquitto/src/handle_ping.c70
-rw-r--r--libs/libmosquitto/src/handle_pubackcomp.c118
-rw-r--r--libs/libmosquitto/src/handle_publish.c167
-rw-r--r--libs/libmosquitto/src/handle_pubrec.c110
-rw-r--r--libs/libmosquitto/src/handle_pubrel.c126
-rw-r--r--libs/libmosquitto/src/handle_suback.c98
-rw-r--r--libs/libmosquitto/src/handle_unsuback.c87
-rw-r--r--libs/libmosquitto/src/helpers.c227
-rw-r--r--libs/libmosquitto/src/logging_mosq.c59
-rw-r--r--libs/libmosquitto/src/logging_mosq.h23
-rw-r--r--libs/libmosquitto/src/loop.c390
-rw-r--r--libs/libmosquitto/src/memory_mosq.c160
-rw-r--r--libs/libmosquitto/src/memory_mosq.h41
-rw-r--r--libs/libmosquitto/src/messages_mosq.c348
-rw-r--r--libs/libmosquitto/src/messages_mosq.h32
-rw-r--r--libs/libmosquitto/src/mosquitto.c612
-rw-r--r--libs/libmosquitto/src/mosquitto_internal.h358
-rw-r--r--libs/libmosquitto/src/mqtt_protocol.h158
-rw-r--r--libs/libmosquitto/src/net_mosq.c1090
-rw-r--r--libs/libmosquitto/src/net_mosq.h82
-rw-r--r--libs/libmosquitto/src/net_mosq_ocsp.c159
-rw-r--r--libs/libmosquitto/src/options.c486
-rw-r--r--libs/libmosquitto/src/packet_datatypes.c271
-rw-r--r--libs/libmosquitto/src/packet_mosq.c456
-rw-r--r--libs/libmosquitto/src/packet_mosq.h56
-rw-r--r--libs/libmosquitto/src/property_mosq.c1181
-rw-r--r--libs/libmosquitto/src/property_mosq.h50
-rw-r--r--libs/libmosquitto/src/read_handle.c70
-rw-r--r--libs/libmosquitto/src/read_handle.h40
-rw-r--r--libs/libmosquitto/src/send_connect.c204
-rw-r--r--libs/libmosquitto/src/send_disconnect.c85
-rw-r--r--libs/libmosquitto/src/send_mosq.c188
-rw-r--r--libs/libmosquitto/src/send_mosq.h38
-rw-r--r--libs/libmosquitto/src/send_publish.c215
-rw-r--r--libs/libmosquitto/src/send_subscribe.c96
-rw-r--r--libs/libmosquitto/src/send_unsubscribe.c99
-rw-r--r--libs/libmosquitto/src/socks_mosq.c460
-rw-r--r--libs/libmosquitto/src/socks_mosq.h23
-rw-r--r--libs/libmosquitto/src/srv_mosq.c112
-rw-r--r--libs/libmosquitto/src/stdafx.cxx2
-rw-r--r--libs/libmosquitto/src/stdafx.h1
-rw-r--r--libs/libmosquitto/src/thread_mosq.c133
-rw-r--r--libs/libmosquitto/src/time_mosq.c61
-rw-r--r--libs/libmosquitto/src/time_mosq.h22
-rw-r--r--libs/libmosquitto/src/tls_mosq.c183
-rw-r--r--libs/libmosquitto/src/tls_mosq.h36
-rw-r--r--libs/libmosquitto/src/utf8_mosq.c109
-rw-r--r--libs/libmosquitto/src/util_mosq.c354
-rw-r--r--libs/libmosquitto/src/util_mosq.h47
-rw-r--r--libs/libmosquitto/src/util_topic.c252
-rw-r--r--libs/libmosquitto/src/will_mosq.c126
-rw-r--r--libs/libmosquitto/src/will_mosq.h26
65 files changed, 16064 insertions, 0 deletions
diff --git a/libs/libmosquitto/include/config.h b/libs/libmosquitto/include/config.h
new file mode 100644
index 0000000000..f717d00c8a
--- /dev/null
+++ b/libs/libmosquitto/include/config.h
@@ -0,0 +1,69 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+/* ============================================================
+ * Platform options
+ * ============================================================ */
+
+#ifdef __APPLE__
+# define __DARWIN_C_SOURCE
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__SYMBIAN32__) || defined(__QNX__)
+# define _XOPEN_SOURCE 700
+# define __BSD_VISIBLE 1
+# define HAVE_NETINET_IN_H
+#else
+# define _XOPEN_SOURCE 700
+# define _DEFAULT_SOURCE 1
+# define _POSIX_C_SOURCE 200809L
+#endif
+
+#define _GNU_SOURCE
+
+#define OPENSSL_LOAD_CONF
+
+/* ============================================================
+ * Compatibility defines
+ * ============================================================ */
+#if defined(_MSC_VER) && _MSC_VER < 1900
+# define snprintf sprintf_s
+# define EPROTO ECONNABORTED
+#endif
+
+#ifdef WIN32
+# ifndef strcasecmp
+# define strcasecmp strcmpi
+# endif
+# define strtok_r strtok_s
+# define strerror_r(e, b, l) strerror_s(b, l, e)
+#endif
+
+
+#define uthash_malloc(sz) mosquitto__malloc(sz)
+#define uthash_free(ptr,sz) mosquitto__free(ptr)
+
+
+#ifdef WITH_TLS
+# include <openssl/opensslconf.h>
+# if defined(WITH_TLS_PSK) && !defined(OPENSSL_NO_PSK)
+# define FINAL_WITH_TLS_PSK
+# endif
+#endif
+
+
+#ifdef __COVERITY__
+# include <stdint.h>
+/* These are "wrong", but we don't use them so it doesn't matter */
+# define _Float32 uint32_t
+# define _Float32x uint32_t
+# define _Float64 uint64_t
+# define _Float64x uint64_t
+# define _Float128 uint64_t
+#endif
+
+#define UNUSED(A) (void)(A)
+
+/* Android Bionic libpthread implementation doesn't have pthread_cancel */
+#ifndef ANDROID
+# define HAVE_PTHREAD_CANCEL
+#endif
+
+#endif
diff --git a/libs/libmosquitto/include/mosquitto.h b/libs/libmosquitto/include/mosquitto.h
new file mode 100644
index 0000000000..09bba66e08
--- /dev/null
+++ b/libs/libmosquitto/include/mosquitto.h
@@ -0,0 +1,2993 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef MOSQUITTO_H
+#define MOSQUITTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(WIN32) && !defined(WITH_BROKER) && !defined(LIBMOSQUITTO_STATIC)
+# ifdef libmosquitto_EXPORTS
+# define libmosq_EXPORT __declspec(dllexport)
+# else
+# define libmosq_EXPORT __declspec(dllimport)
+# endif
+#else
+# define libmosq_EXPORT
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+# ifndef __cplusplus
+# define bool char
+# define true 1
+# define false 0
+# endif
+#else
+# ifndef __cplusplus
+# include <stdbool.h>
+# endif
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define LIBMOSQUITTO_MAJOR 1
+#define LIBMOSQUITTO_MINOR 6
+#define LIBMOSQUITTO_REVISION 3
+/* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */
+#define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION)
+
+/* Log types */
+#define MOSQ_LOG_NONE 0
+#define MOSQ_LOG_INFO (1<<0)
+#define MOSQ_LOG_NOTICE (1<<1)
+#define MOSQ_LOG_WARNING (1<<2)
+#define MOSQ_LOG_ERR (1<<3)
+#define MOSQ_LOG_DEBUG (1<<4)
+#define MOSQ_LOG_SUBSCRIBE (1<<5)
+#define MOSQ_LOG_UNSUBSCRIBE (1<<6)
+#define MOSQ_LOG_WEBSOCKETS (1<<7)
+#define MOSQ_LOG_INTERNAL 0x80000000
+#define MOSQ_LOG_ALL 0x7FFFFFFF
+
+/* Error values */
+enum mosq_err_t {
+ MOSQ_ERR_AUTH_CONTINUE = -4,
+ MOSQ_ERR_NO_SUBSCRIBERS = -3,
+ MOSQ_ERR_SUB_EXISTS = -2,
+ MOSQ_ERR_CONN_PENDING = -1,
+ MOSQ_ERR_SUCCESS = 0,
+ MOSQ_ERR_NOMEM = 1,
+ MOSQ_ERR_PROTOCOL = 2,
+ MOSQ_ERR_INVAL = 3,
+ MOSQ_ERR_NO_CONN = 4,
+ MOSQ_ERR_CONN_REFUSED = 5,
+ MOSQ_ERR_NOT_FOUND = 6,
+ MOSQ_ERR_CONN_LOST = 7,
+ MOSQ_ERR_TLS = 8,
+ MOSQ_ERR_PAYLOAD_SIZE = 9,
+ MOSQ_ERR_NOT_SUPPORTED = 10,
+ MOSQ_ERR_AUTH = 11,
+ MOSQ_ERR_ACL_DENIED = 12,
+ MOSQ_ERR_UNKNOWN = 13,
+ MOSQ_ERR_ERRNO = 14,
+ MOSQ_ERR_EAI = 15,
+ MOSQ_ERR_PROXY = 16,
+ MOSQ_ERR_PLUGIN_DEFER = 17,
+ MOSQ_ERR_MALFORMED_UTF8 = 18,
+ MOSQ_ERR_KEEPALIVE = 19,
+ MOSQ_ERR_LOOKUP = 20,
+ MOSQ_ERR_MALFORMED_PACKET = 21,
+ MOSQ_ERR_DUPLICATE_PROPERTY = 22,
+ MOSQ_ERR_TLS_HANDSHAKE = 23,
+ MOSQ_ERR_QOS_NOT_SUPPORTED = 24,
+ MOSQ_ERR_OVERSIZE_PACKET = 25,
+ MOSQ_ERR_OCSP = 26,
+};
+
+/* Option values */
+enum mosq_opt_t {
+ MOSQ_OPT_PROTOCOL_VERSION = 1,
+ MOSQ_OPT_SSL_CTX = 2,
+ MOSQ_OPT_SSL_CTX_WITH_DEFAULTS = 3,
+ MOSQ_OPT_RECEIVE_MAXIMUM = 4,
+ MOSQ_OPT_SEND_MAXIMUM = 5,
+ MOSQ_OPT_TLS_KEYFORM = 6,
+ MOSQ_OPT_TLS_ENGINE = 7,
+ MOSQ_OPT_TLS_ENGINE_KPASS_SHA1 = 8,
+ MOSQ_OPT_TLS_OCSP_REQUIRED = 9,
+ MOSQ_OPT_TLS_ALPN = 10,
+};
+
+
+/* MQTT specification restricts client ids to a maximum of 23 characters */
+#define MOSQ_MQTT_ID_MAX_LENGTH 23
+
+#define MQTT_PROTOCOL_V31 3
+#define MQTT_PROTOCOL_V311 4
+#define MQTT_PROTOCOL_V5 5
+
+struct mosquitto_message{
+ int mid;
+ char *topic;
+ void *payload;
+ int payloadlen;
+ int qos;
+ bool retain;
+};
+
+struct mosquitto;
+typedef struct mqtt5__property mosquitto_property;
+
+/*
+ * Topic: Threads
+ * libmosquitto provides thread safe operation, with the exception of
+ * <mosquitto_lib_init> which is not thread safe.
+ *
+ * If your application uses threads you must use <mosquitto_threaded_set> to
+ * tell the library this is the case, otherwise it makes some optimisations
+ * for the single threaded case that may result in unexpected behaviour for
+ * the multi threaded case.
+ */
+/***************************************************
+ * Important note
+ *
+ * The following functions that deal with network operations will return
+ * MOSQ_ERR_SUCCESS on success, but this does not mean that the operation has
+ * taken place. An attempt will be made to write the network data, but if the
+ * socket is not available for writing at that time then the packet will not be
+ * sent. To ensure the packet is sent, call mosquitto_loop() (which must also
+ * be called to process incoming network data).
+ * This is especially important when disconnecting a client that has a will. If
+ * the broker does not receive the DISCONNECT command, it will assume that the
+ * client has disconnected unexpectedly and send the will.
+ *
+ * mosquitto_connect()
+ * mosquitto_disconnect()
+ * mosquitto_subscribe()
+ * mosquitto_unsubscribe()
+ * mosquitto_publish()
+ ***************************************************/
+
+
+/* ======================================================================
+ *
+ * Section: Library version, init, and cleanup
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_lib_version
+ *
+ * Can be used to obtain version information for the mosquitto library.
+ * This allows the application to compare the library version against the
+ * version it was compiled against by using the LIBMOSQUITTO_MAJOR,
+ * LIBMOSQUITTO_MINOR and LIBMOSQUITTO_REVISION defines.
+ *
+ * Parameters:
+ * major - an integer pointer. If not NULL, the major version of the
+ * library will be returned in this variable.
+ * minor - an integer pointer. If not NULL, the minor version of the
+ * library will be returned in this variable.
+ * revision - an integer pointer. If not NULL, the revision of the library will
+ * be returned in this variable.
+ *
+ * Returns:
+ * LIBMOSQUITTO_VERSION_NUMBER, which is a unique number based on the major,
+ * minor and revision values.
+ * See Also:
+ * <mosquitto_lib_cleanup>, <mosquitto_lib_init>
+ */
+libmosq_EXPORT int mosquitto_lib_version(int *major, int *minor, int *revision);
+
+/*
+ * Function: mosquitto_lib_init
+ *
+ * Must be called before any other mosquitto functions.
+ *
+ * This function is *not* thread safe.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - always
+ *
+ * See Also:
+ * <mosquitto_lib_cleanup>, <mosquitto_lib_version>
+ */
+libmosq_EXPORT int mosquitto_lib_init(void);
+
+/*
+ * Function: mosquitto_lib_cleanup
+ *
+ * Call to free resources associated with the library.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - always
+ *
+ * See Also:
+ * <mosquitto_lib_init>, <mosquitto_lib_version>
+ */
+libmosq_EXPORT int mosquitto_lib_cleanup(void);
+
+
+/* ======================================================================
+ *
+ * Section: Client creation, destruction, and reinitialisation
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_new
+ *
+ * Create a new mosquitto client instance.
+ *
+ * Parameters:
+ * id - String to use as the client id. If NULL, a random client id
+ * will be generated. If id is NULL, clean_session must be true.
+ * clean_session - set to true to instruct the broker to clean all messages
+ * and subscriptions on disconnect, false to instruct it to
+ * keep them. See the man page mqtt(7) for more details.
+ * Note that a client will never discard its own outgoing
+ * messages on disconnect. Calling <mosquitto_connect> or
+ * <mosquitto_reconnect> will cause the messages to be resent.
+ * Use <mosquitto_reinitialise> to reset a client to its
+ * original state.
+ * Must be set to true if the id parameter is NULL.
+ * obj - A user pointer that will be passed as an argument to any
+ * callbacks that are specified.
+ *
+ * Returns:
+ * Pointer to a struct mosquitto on success.
+ * NULL on failure. Interrogate errno to determine the cause for the failure:
+ * - ENOMEM on out of memory.
+ * - EINVAL on invalid input parameters.
+ *
+ * See Also:
+ * <mosquitto_reinitialise>, <mosquitto_destroy>, <mosquitto_user_data_set>
+ */
+libmosq_EXPORT struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj);
+
+/*
+ * Function: mosquitto_destroy
+ *
+ * Use to free memory associated with a mosquitto client instance.
+ *
+ * Parameters:
+ * mosq - a struct mosquitto pointer to free.
+ *
+ * See Also:
+ * <mosquitto_new>, <mosquitto_reinitialise>
+ */
+libmosq_EXPORT void mosquitto_destroy(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_reinitialise
+ *
+ * This function allows an existing mosquitto client to be reused. Call on a
+ * mosquitto instance to close any open network connections, free memory
+ * and reinitialise the client with the new parameters. The end result is the
+ * same as the output of <mosquitto_new>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * id - string to use as the client id. If NULL, a random client id
+ * will be generated. If id is NULL, clean_session must be true.
+ * clean_session - set to true to instruct the broker to clean all messages
+ * and subscriptions on disconnect, false to instruct it to
+ * keep them. See the man page mqtt(7) for more details.
+ * Must be set to true if the id parameter is NULL.
+ * obj - A user pointer that will be passed as an argument to any
+ * callbacks that are specified.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * See Also:
+ * <mosquitto_new>, <mosquitto_destroy>
+ */
+libmosq_EXPORT int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *obj);
+
+
+/* ======================================================================
+ *
+ * Section: Will
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_will_set
+ *
+ * Configure will information for a mosquitto instance. By default, clients do
+ * not have a will. This must be called before calling <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * topic - the topic on which to publish the will.
+ * payloadlen - the size of the payload (bytes). Valid values are between 0 and
+ * 268,435,455.
+ * payload - pointer to the data to send. If payloadlen > 0 this must be a
+ * valid memory location.
+ * qos - integer value 0, 1 or 2 indicating the Quality of Service to be
+ * used for the will.
+ * retain - set to true to make the will a retained message.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8.
+ */
+libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain);
+
+/*
+ * Function: mosquitto_will_set_v5
+ *
+ * Configure will information for a mosquitto instance, with attached
+ * properties. By default, clients do not have a will. This must be called
+ * before calling <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * topic - the topic on which to publish the will.
+ * payloadlen - the size of the payload (bytes). Valid values are between 0 and
+ * 268,435,455.
+ * payload - pointer to the data to send. If payloadlen > 0 this must be a
+ * valid memory location.
+ * qos - integer value 0, 1 or 2 indicating the Quality of Service to be
+ * used for the will.
+ * retain - set to true to make the will a retained message.
+ * properties - list of MQTT 5 properties. Can be NULL. On success only, the
+ * property list becomes the property of libmosquitto once this
+ * function is called and will be freed by the library. The
+ * property list must be freed by the application on error.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8.
+ * MOSQ_ERR_NOT_SUPPORTED - if properties is not NULL and the client is not
+ * using MQTT v5
+ * MOSQ_ERR_PROTOCOL - if a property is invalid for use with wills.
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ */
+libmosq_EXPORT int mosquitto_will_set_v5(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties);
+
+/*
+ * Function: mosquitto_will_clear
+ *
+ * Remove a previously configured will. This must be called before calling
+ * <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ */
+libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq);
+
+
+/* ======================================================================
+ *
+ * Section: Username and password
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_username_pw_set
+ *
+ * Configure username and password for a mosquitton instance. This is only
+ * supported by brokers that implement the MQTT spec v3.1. By default, no
+ * username or password will be sent.
+ * If username is NULL, the password argument is ignored.
+ * This must be called before calling mosquitto_connect().
+ *
+ * This is must be called before calling <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * username - the username to send as a string, or NULL to disable
+ * authentication.
+ * password - the password to send as a string. Set to NULL when username is
+ * valid in order to send just a username.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ */
+libmosq_EXPORT int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password);
+
+
+/* ======================================================================
+ *
+ * Section: Connecting, reconnecting, disconnecting
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_connect
+ *
+ * Connect to an MQTT broker.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the hostname or ip address of the broker to connect to.
+ * port - the network port to connect to. Usually 1883.
+ * keepalive - the number of seconds after which the broker should send a PING
+ * message to the client if no other messages have been exchanged
+ * in that time.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect_bind>, <mosquitto_connect_async>, <mosquitto_reconnect>, <mosquitto_disconnect>, <mosquitto_tls_set>
+ */
+libmosq_EXPORT int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive);
+
+/*
+ * Function: mosquitto_connect_bind
+ *
+ * Connect to an MQTT broker. This extends the functionality of
+ * <mosquitto_connect> by adding the bind_address parameter. Use this function
+ * if you need to restrict network communication over a particular interface.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the hostname or ip address of the broker to connect to.
+ * port - the network port to connect to. Usually 1883.
+ * keepalive - the number of seconds after which the broker should send a PING
+ * message to the client if no other messages have been exchanged
+ * in that time.
+ * bind_address - the hostname or ip address of the local network interface to
+ * bind to.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect>, <mosquitto_connect_async>, <mosquitto_connect_bind_async>
+ */
+libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address);
+
+/*
+ * Function: mosquitto_connect_bind_v5
+ *
+ * Connect to an MQTT broker. This extends the functionality of
+ * <mosquitto_connect> by adding the bind_address parameter. Use this function
+ * if you need to restrict network communication over a particular interface.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the hostname or ip address of the broker to connect to.
+ * port - the network port to connect to. Usually 1883.
+ * keepalive - the number of seconds after which the broker should send a PING
+ * message to the client if no other messages have been exchanged
+ * in that time.
+ * bind_address - the hostname or ip address of the local network interface to
+ * bind to.
+ * properties - the MQTT 5 properties for the connect (not for the Will).
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ * MOSQ_ERR_PROTOCOL - if any property is invalid for use with CONNECT.
+ *
+ * See Also:
+ * <mosquitto_connect>, <mosquitto_connect_async>, <mosquitto_connect_bind_async>
+ */
+libmosq_EXPORT int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties);
+
+/*
+ * Function: mosquitto_connect_async
+ *
+ * Connect to an MQTT broker. This is a non-blocking call. If you use
+ * <mosquitto_connect_async> your client must use the threaded interface
+ * <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use
+ * <mosquitto_connect> to connect the client.
+ *
+ * May be called before or after <mosquitto_loop_start>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the hostname or ip address of the broker to connect to.
+ * port - the network port to connect to. Usually 1883.
+ * keepalive - the number of seconds after which the broker should send a PING
+ * message to the client if no other messages have been exchanged
+ * in that time.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect_bind_async>, <mosquitto_connect>, <mosquitto_reconnect>, <mosquitto_disconnect>, <mosquitto_tls_set>
+ */
+libmosq_EXPORT int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive);
+
+/*
+ * Function: mosquitto_connect_bind_async
+ *
+ * Connect to an MQTT broker. This is a non-blocking call. If you use
+ * <mosquitto_connect_bind_async> your client must use the threaded interface
+ * <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use
+ * <mosquitto_connect> to connect the client.
+ *
+ * This extends the functionality of <mosquitto_connect_async> by adding the
+ * bind_address parameter. Use this function if you need to restrict network
+ * communication over a particular interface.
+ *
+ * May be called before or after <mosquitto_loop_start>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the hostname or ip address of the broker to connect to.
+ * port - the network port to connect to. Usually 1883.
+ * keepalive - the number of seconds after which the broker should send a PING
+ * message to the client if no other messages have been exchanged
+ * in that time.
+ * bind_address - the hostname or ip address of the local network interface to
+ * bind to.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect_async>, <mosquitto_connect>, <mosquitto_connect_bind>
+ */
+libmosq_EXPORT int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address);
+
+/*
+ * Function: mosquitto_connect_srv
+ *
+ * Connect to an MQTT broker. This is a non-blocking call. If you use
+ * <mosquitto_connect_async> your client must use the threaded interface
+ * <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use
+ * <mosquitto_connect> to connect the client.
+ *
+ * This extends the functionality of <mosquitto_connect_async> by adding the
+ * bind_address parameter. Use this function if you need to restrict network
+ * communication over a particular interface.
+ *
+ * May be called before or after <mosquitto_loop_start>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the hostname or ip address of the broker to connect to.
+ * keepalive - the number of seconds after which the broker should send a PING
+ * message to the client if no other messages have been exchanged
+ * in that time.
+ * bind_address - the hostname or ip address of the local network interface to
+ * bind to.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect_async>, <mosquitto_connect>, <mosquitto_connect_bind>
+ */
+libmosq_EXPORT int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address);
+
+/*
+ * Function: mosquitto_reconnect
+ *
+ * Reconnect to a broker.
+ *
+ * This function provides an easy way of reconnecting to a broker after a
+ * connection has been lost. It uses the values that were provided in the
+ * <mosquitto_connect> call. It must not be called before
+ * <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect>, <mosquitto_disconnect>, <mosquitto_reconnect_async>
+ */
+libmosq_EXPORT int mosquitto_reconnect(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_reconnect_async
+ *
+ * Reconnect to a broker. Non blocking version of <mosquitto_reconnect>.
+ *
+ * This function provides an easy way of reconnecting to a broker after a
+ * connection has been lost. It uses the values that were provided in the
+ * <mosquitto_connect> or <mosquitto_connect_async> calls. It must not be
+ * called before <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_connect>, <mosquitto_disconnect>
+ */
+libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_disconnect
+ *
+ * Disconnect from the broker.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ */
+libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_disconnect_v5
+ *
+ * Disconnect from the broker, with attached MQTT properties.
+ *
+ * Use <mosquitto_property_add_*> to create a list of properties, then attach
+ * them to this publish. Properties need freeing with
+ * <mosquitto_property_free_all>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * reason_code - the disconnect reason code.
+ * properties - a valid mosquitto_property list, or NULL.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ * MOSQ_ERR_PROTOCOL - if any property is invalid for use with DISCONNECT.
+ */
+libmosq_EXPORT int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties);
+
+
+/* ======================================================================
+ *
+ * Section: Publishing, subscribing, unsubscribing
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_publish
+ *
+ * Publish a message on a given topic.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - pointer to an int. If not NULL, the function will set this
+ * to the message id of this particular message. This can be then
+ * used with the publish callback to determine when the message
+ * has been sent.
+ * Note that although the MQTT protocol doesn't use message ids
+ * for messages with QoS=0, libmosquitto assigns them message ids
+ * so they can be tracked with this parameter.
+ * topic - null terminated string of the topic to publish to.
+ * payloadlen - the size of the payload (bytes). Valid values are between 0 and
+ * 268,435,455.
+ * payload - pointer to the data to send. If payloadlen > 0 this must be a
+ * valid memory location.
+ * qos - integer value 0, 1 or 2 indicating the Quality of Service to be
+ * used for the message.
+ * retain - set to true to make the message retained.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
+ * broker.
+ * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by
+ * the broker.
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ *
+ * See Also:
+ * <mosquitto_max_inflight_messages_set>
+ */
+libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain);
+
+
+/*
+ * Function: mosquitto_publish_v5
+ *
+ * Publish a message on a given topic, with attached MQTT properties.
+ *
+ * Use <mosquitto_property_add_*> to create a list of properties, then attach
+ * them to this publish. Properties need freeing with
+ * <mosquitto_property_free_all>.
+ *
+ * Requires the mosquitto instance to be connected with MQTT 5.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - pointer to an int. If not NULL, the function will set this
+ * to the message id of this particular message. This can be then
+ * used with the publish callback to determine when the message
+ * has been sent.
+ * Note that although the MQTT protocol doesn't use message ids
+ * for messages with QoS=0, libmosquitto assigns them message ids
+ * so they can be tracked with this parameter.
+ * topic - null terminated string of the topic to publish to.
+ * payloadlen - the size of the payload (bytes). Valid values are between 0 and
+ * 268,435,455.
+ * payload - pointer to the data to send. If payloadlen > 0 this must be a
+ * valid memory location.
+ * qos - integer value 0, 1 or 2 indicating the Quality of Service to be
+ * used for the message.
+ * retain - set to true to make the message retained.
+ * properties - a valid mosquitto_property list, or NULL.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
+ * broker.
+ * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH.
+ * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by
+ * the broker.
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_publish_v5(
+ struct mosquitto *mosq,
+ int *mid,
+ const char *topic,
+ int payloadlen,
+ const void *payload,
+ int qos,
+ bool retain,
+ const mosquitto_property *properties);
+
+
+/*
+ * Function: mosquitto_subscribe
+ *
+ * Subscribe to a topic.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - a pointer to an int. If not NULL, the function will set this to
+ * the message id of this particular message. This can be then used
+ * with the subscribe callback to determine when the message has been
+ * sent.
+ * sub - the subscription pattern.
+ * qos - the requested Quality of Service for this subscription.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos);
+
+/*
+ * Function: mosquitto_subscribe_v5
+ *
+ * Subscribe to a topic, with attached MQTT properties.
+ *
+ * Use <mosquitto_property_add_*> to create a list of properties, then attach
+ * them to this subscribe. Properties need freeing with
+ * <mosquitto_property_free_all>.
+ *
+ * Requires the mosquitto instance to be connected with MQTT 5.
+ *
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - a pointer to an int. If not NULL, the function will set this to
+ * the message id of this particular message. This can be then used
+ * with the subscribe callback to determine when the message has been
+ * sent.
+ * sub - the subscription pattern.
+ * qos - the requested Quality of Service for this subscription.
+ * options - options to apply to this subscription, OR'd together. Set to 0 to
+ * use the default options, otherwise choose from the list:
+ * MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client
+ * publishes to a topic to which it is subscribed, the
+ * broker will not publish the message back to the
+ * client.
+ * MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages
+ * published for this subscription will keep the
+ * retain flag as was set by the publishing client.
+ * The default behaviour without this option set has
+ * the retain flag indicating whether a message is
+ * fresh/stale.
+ * MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set,
+ * pre-existing retained messages are sent as soon as
+ * the subscription is made, even if the subscription
+ * already exists. This is the default behaviour, so
+ * it is not necessary to set this option.
+ * MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing
+ * retained messages for this subscription will be
+ * sent when the subscription is made, but only if the
+ * subscription does not already exist.
+ * MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set,
+ * pre-existing retained messages will never be sent
+ * for this subscription.
+ * properties - a valid mosquitto_property list, or NULL.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE.
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties);
+
+/*
+ * Function: mosquitto_subscribe_multiple
+ *
+ * Subscribe to multiple topics.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - a pointer to an int. If not NULL, the function will set this to
+ * the message id of this particular message. This can be then used
+ * with the subscribe callback to determine when the message has been
+ * sent.
+ * sub_count - the count of subscriptions to be made
+ * sub - array of sub_count pointers, each pointing to a subscription string.
+ * The "char *const *const" datatype ensures that neither the array of
+ * pointers nor the strings that they point to are mutable. If you aren't
+ * familiar with this, just think of it as a safer "char **",
+ * equivalent to "const char *" for a simple string pointer.
+ * qos - the requested Quality of Service for each subscription.
+ * options - options to apply to this subscription, OR'd together. Set to 0 to
+ * use the default options, otherwise choose from the list:
+ * MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client
+ * publishes to a topic to which it is subscribed, the
+ * broker will not publish the message back to the
+ * client.
+ * MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages
+ * published for this subscription will keep the
+ * retain flag as was set by the publishing client.
+ * The default behaviour without this option set has
+ * the retain flag indicating whether a message is
+ * fresh/stale.
+ * MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set,
+ * pre-existing retained messages are sent as soon as
+ * the subscription is made, even if the subscription
+ * already exists. This is the default behaviour, so
+ * it is not necessary to set this option.
+ * MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing
+ * retained messages for this subscription will be
+ * sent when the subscription is made, but only if the
+ * subscription does not already exist.
+ * MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set,
+ * pre-existing retained messages will never be sent
+ * for this subscription.
+ * properties - a valid mosquitto_property list, or NULL. Only used with MQTT
+ * v5 clients.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties);
+
+/*
+ * Function: mosquitto_unsubscribe
+ *
+ * Unsubscribe from a topic.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - a pointer to an int. If not NULL, the function will set this to
+ * the message id of this particular message. This can be then used
+ * with the unsubscribe callback to determine when the message has been
+ * sent.
+ * sub - the unsubscription pattern.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub);
+
+/*
+ * Function: mosquitto_unsubscribe_v5
+ *
+ * Unsubscribe from a topic, with attached MQTT properties.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - a pointer to an int. If not NULL, the function will set this to
+ * the message id of this particular message. This can be then used
+ * with the unsubscribe callback to determine when the message has been
+ * sent.
+ * sub - the unsubscription pattern.
+ * properties - a valid mosquitto_property list, or NULL. Only used with MQTT
+ * v5 clients.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ * MOSQ_ERR_PROTOCOL - if any property is invalid for use with UNSUBSCRIBE.
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties);
+
+/*
+ * Function: mosquitto_unsubscribe_multiple
+ *
+ * Unsubscribe from multiple topics.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * mid - a pointer to an int. If not NULL, the function will set this to
+ * the message id of this particular message. This can be then used
+ * with the subscribe callback to determine when the message has been
+ * sent.
+ * sub_count - the count of unsubscriptions to be made
+ * sub - array of sub_count pointers, each pointing to an unsubscription string.
+ * The "char *const *const" datatype ensures that neither the array of
+ * pointers nor the strings that they point to are mutable. If you aren't
+ * familiar with this, just think of it as a safer "char **",
+ * equivalent to "const char *" for a simple string pointer.
+ * properties - a valid mosquitto_property list, or NULL. Only used with MQTT
+ * v5 clients.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8
+ * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than
+ * supported by the broker.
+ */
+libmosq_EXPORT int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties);
+
+
+/* ======================================================================
+ *
+ * Section: Struct mosquitto_message helper functions
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_message_copy
+ *
+ * Copy the contents of a mosquitto message to another message.
+ * Useful for preserving a message received in the on_message() callback.
+ *
+ * Parameters:
+ * dst - a pointer to a valid mosquitto_message struct to copy to.
+ * src - a pointer to a valid mosquitto_message struct to copy from.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * See Also:
+ * <mosquitto_message_free>
+ */
+libmosq_EXPORT int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src);
+
+/*
+ * Function: mosquitto_message_free
+ *
+ * Completely free a mosquitto_message struct.
+ *
+ * Parameters:
+ * message - pointer to a mosquitto_message pointer to free.
+ *
+ * See Also:
+ * <mosquitto_message_copy>, <mosquitto_message_free_contents>
+ */
+libmosq_EXPORT void mosquitto_message_free(struct mosquitto_message **message);
+
+/*
+ * Function: mosquitto_message_free_contents
+ *
+ * Free a mosquitto_message struct contents, leaving the struct unaffected.
+ *
+ * Parameters:
+ * message - pointer to a mosquitto_message struct to free its contents.
+ *
+ * See Also:
+ * <mosquitto_message_copy>, <mosquitto_message_free>
+ */
+libmosq_EXPORT void mosquitto_message_free_contents(struct mosquitto_message *message);
+
+
+/* ======================================================================
+ *
+ * Section: Network loop (managed by libmosquitto)
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_loop
+ *
+ * The main network loop for the client. You must call this frequently in order
+ * to keep communications between the client and broker working. If incoming
+ * data is present it will then be processed. Outgoing commands, from e.g.
+ * <mosquitto_publish>, are normally sent immediately that their function is
+ * called, but this is not always possible. <mosquitto_loop> will also attempt
+ * to send any remaining outgoing messages, which also includes commands that
+ * are part of the flow for messages with QoS>0.
+ *
+ * An alternative approach is to use <mosquitto_loop_start> to run the client
+ * loop in its own thread.
+ *
+ * This calls select() to monitor the client network socket. If you want to
+ * integrate mosquitto client operation with your own select() call, use
+ * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write> and
+ * <mosquitto_loop_misc>.
+ *
+ * Threads:
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * timeout - Maximum number of milliseconds to wait for network activity
+ * in the select() call before timing out. Set to 0 for instant
+ * return. Set negative to use the default of 1000ms.
+ * max_packets - this parameter is currently unused and should be set to 1 for
+ * future compatibility.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost.
+ * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
+ * broker.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ * See Also:
+ * <mosquitto_loop_forever>, <mosquitto_loop_start>, <mosquitto_loop_stop>
+ */
+libmosq_EXPORT int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets);
+
+/*
+ * Function: mosquitto_loop_forever
+ *
+ * This function call loop() for you in an infinite blocking loop. It is useful
+ * for the case where you only want to run the MQTT client loop in your
+ * program.
+ *
+ * It handles reconnecting in case server connection is lost. If you call
+ * mosquitto_disconnect() in a callback it will return.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * timeout - Maximum number of milliseconds to wait for network activity
+ * in the select() call before timing out. Set to 0 for instant
+ * return. Set negative to use the default of 1000ms.
+ * max_packets - this parameter is currently unused and should be set to 1 for
+ * future compatibility.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost.
+ * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
+ * broker.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_loop>, <mosquitto_loop_start>
+ */
+libmosq_EXPORT int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets);
+
+/*
+ * Function: mosquitto_loop_start
+ *
+ * This is part of the threaded client interface. Call this once to start a new
+ * thread to process network traffic. This provides an alternative to
+ * repeatedly calling <mosquitto_loop> yourself.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available.
+ *
+ * See Also:
+ * <mosquitto_connect_async>, <mosquitto_loop>, <mosquitto_loop_forever>, <mosquitto_loop_stop>
+ */
+libmosq_EXPORT int mosquitto_loop_start(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_loop_stop
+ *
+ * This is part of the threaded client interface. Call this once to stop the
+ * network thread previously created with <mosquitto_loop_start>. This call
+ * will block until the network thread finishes. For the network thread to end,
+ * you must have previously called <mosquitto_disconnect> or have set the force
+ * parameter to true.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * force - set to true to force thread cancellation. If false,
+ * <mosquitto_disconnect> must have already been called.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available.
+ *
+ * See Also:
+ * <mosquitto_loop>, <mosquitto_loop_start>
+ */
+libmosq_EXPORT int mosquitto_loop_stop(struct mosquitto *mosq, bool force);
+
+
+/* ======================================================================
+ *
+ * Section: Network loop (for use in other event loops)
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_loop_read
+ *
+ * Carry out network read operations.
+ * This should only be used if you are not using mosquitto_loop() and are
+ * monitoring the client network socket for activity yourself.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * max_packets - this parameter is currently unused and should be set to 1 for
+ * future compatibility.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost.
+ * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
+ * broker.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_socket>, <mosquitto_loop_write>, <mosquitto_loop_misc>
+ */
+libmosq_EXPORT int mosquitto_loop_read(struct mosquitto *mosq, int max_packets);
+
+/*
+ * Function: mosquitto_loop_write
+ *
+ * Carry out network write operations.
+ * This should only be used if you are not using mosquitto_loop() and are
+ * monitoring the client network socket for activity yourself.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * max_packets - this parameter is currently unused and should be set to 1 for
+ * future compatibility.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost.
+ * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
+ * broker.
+ * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
+ * contains the error code, even on Windows.
+ * Use strerror_r() where available or FormatMessage() on
+ * Windows.
+ *
+ * See Also:
+ * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_misc>, <mosquitto_want_write>
+ */
+libmosq_EXPORT int mosquitto_loop_write(struct mosquitto *mosq, int max_packets);
+
+/*
+ * Function: mosquitto_loop_misc
+ *
+ * Carry out miscellaneous operations required as part of the network loop.
+ * This should only be used if you are not using mosquitto_loop() and are
+ * monitoring the client network socket for activity yourself.
+ *
+ * This function deals with handling PINGs and checking whether messages need
+ * to be retried, so should be called fairly frequently.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
+ *
+ * See Also:
+ * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write>
+ */
+libmosq_EXPORT int mosquitto_loop_misc(struct mosquitto *mosq);
+
+
+/* ======================================================================
+ *
+ * Section: Network loop (helper functions)
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_socket
+ *
+ * Return the socket handle for a mosquitto instance. Useful if you want to
+ * include a mosquitto client in your own select() calls.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * The socket for the mosquitto client or -1 on failure.
+ */
+libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_want_write
+ *
+ * Returns true if there is data ready to be written on the socket.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * See Also:
+ * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write>
+ */
+libmosq_EXPORT bool mosquitto_want_write(struct mosquitto *mosq);
+
+/*
+ * Function: mosquitto_threaded_set
+ *
+ * Used to tell the library that your application is using threads, but not
+ * using <mosquitto_loop_start>. The library operates slightly differently when
+ * not in threaded mode in order to simplify its operation. If you are managing
+ * your own threads and do not use this function you will experience crashes
+ * due to race conditions.
+ *
+ * When using <mosquitto_loop_start>, this is set automatically.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * threaded - true if your application is using threads, false otherwise.
+ */
+libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded);
+
+
+/* ======================================================================
+ *
+ * Section: Client options
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_opts_set
+ *
+ * Used to set options for the client.
+ *
+ * This function is deprecated, the replacement <mosquitto_int_option> and
+ * <mosquitto_void_option> functions should be used instead.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * option - the option to set.
+ * value - the option specific value.
+ *
+ * Options:
+ * MOSQ_OPT_PROTOCOL_VERSION
+ * Value must be an int, set to either MQTT_PROTOCOL_V31 or
+ * MQTT_PROTOCOL_V311. Must be set before the client connects.
+ * Defaults to MQTT_PROTOCOL_V31.
+ *
+ * MOSQ_OPT_SSL_CTX
+ * Pass an openssl SSL_CTX to be used when creating TLS connections
+ * rather than libmosquitto creating its own. This must be called
+ * before connecting to have any effect. If you use this option, the
+ * onus is on you to ensure that you are using secure settings.
+ * Setting to NULL means that libmosquitto will use its own SSL_CTX
+ * if TLS is to be used.
+ * This option is only available for openssl 1.1.0 and higher.
+ *
+ * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS
+ * Value must be an int set to 1 or 0. If set to 1, then the user
+ * specified SSL_CTX passed in using MOSQ_OPT_SSL_CTX will have the
+ * default options applied to it. This means that you only need to
+ * change the values that are relevant to you. If you use this
+ * option then you must configure the TLS options as normal, i.e.
+ * you should use <mosquitto_tls_set> to configure the cafile/capath
+ * as a minimum.
+ * This option is only available for openssl 1.1.0 and higher.
+ */
+libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value);
+
+/*
+ * Function: mosquitto_int_option
+ *
+ * Used to set integer options for the client.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * option - the option to set.
+ * value - the option specific value.
+ *
+ * Options:
+ * MOSQ_OPT_PROTOCOL_VERSION
+ * Value must be set to either MQTT_PROTOCOL_V31,
+ * MQTT_PROTOCOL_V311, or MQTT_PROTOCOL_V5. Must be set before the
+ * client connects. Defaults to MQTT_PROTOCOL_V311.
+ *
+ * MOSQ_OPT_RECEIVE_MAXIMUM
+ * Value can be set between 1 and 65535 inclusive, and represents
+ * the maximum number of incoming QoS 1 and QoS 2 messages that this
+ * client wants to process at once. Defaults to 20. This option is
+ * not valid for MQTT v3.1 or v3.1.1 clients.
+ * Note that if the MQTT_PROP_RECEIVE_MAXIMUM property is in the
+ * proplist passed to mosquitto_connect_v5(), then that property
+ * will override this option. Using this option is the recommended
+ * method however.
+ *
+ * MOSQ_OPT_SEND_MAXIMUM
+ * Value can be set between 1 and 65535 inclusive, and represents
+ * the maximum number of outgoing QoS 1 and QoS 2 messages that this
+ * client will attempt to have "in flight" at once. Defaults to 20.
+ * This option is not valid for MQTT v3.1 or v3.1.1 clients.
+ * Note that if the broker being connected to sends a
+ * MQTT_PROP_RECEIVE_MAXIMUM property that has a lower value than
+ * this option, then the broker provided value will be used.
+ *
+ * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS
+ * If value is set to a non zero value, then the user specified
+ * SSL_CTX passed in using MOSQ_OPT_SSL_CTX will have the default
+ * options applied to it. This means that you only need to change
+ * the values that are relevant to you. If you use this option then
+ * you must configure the TLS options as normal, i.e. you should
+ * use <mosquitto_tls_set> to configure the cafile/capath as a
+ * minimum.
+ * This option is only available for openssl 1.1.0 and higher.
+ * MOSQ_OPT_TLS_OCSP_REQUIRED
+ * Set whether OCSP checking on TLS connections is required. Set to
+ * 1 to enable checking, or 0 (the default) for no checking.
+ */
+libmosq_EXPORT int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value);
+
+
+/*
+ * Function: mosquitto_void_option
+ *
+ * Used to set void* options for the client.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * option - the option to set.
+ * value - the option specific value.
+ *
+ * Options:
+ * MOSQ_OPT_SSL_CTX
+ * Pass an openssl SSL_CTX to be used when creating TLS connections
+ * rather than libmosquitto creating its own. This must be called
+ * before connecting to have any effect. If you use this option, the
+ * onus is on you to ensure that you are using secure settings.
+ * Setting to NULL means that libmosquitto will use its own SSL_CTX
+ * if TLS is to be used.
+ * This option is only available for openssl 1.1.0 and higher.
+ */
+libmosq_EXPORT int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value);
+
+
+/*
+ * Function: mosquitto_reconnect_delay_set
+ *
+ * Control the behaviour of the client when it has unexpectedly disconnected in
+ * <mosquitto_loop_forever> or after <mosquitto_loop_start>. The default
+ * behaviour if this function is not used is to repeatedly attempt to reconnect
+ * with a delay of 1 second until the connection succeeds.
+ *
+ * Use reconnect_delay parameter to change the delay between successive
+ * reconnection attempts. You may also enable exponential backoff of the time
+ * between reconnections by setting reconnect_exponential_backoff to true and
+ * set an upper bound on the delay with reconnect_delay_max.
+ *
+ * Example 1:
+ * delay=2, delay_max=10, exponential_backoff=False
+ * Delays would be: 2, 4, 6, 8, 10, 10, ...
+ *
+ * Example 2:
+ * delay=3, delay_max=30, exponential_backoff=True
+ * Delays would be: 3, 6, 12, 24, 30, 30, ...
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * reconnect_delay - the number of seconds to wait between
+ * reconnects.
+ * reconnect_delay_max - the maximum number of seconds to wait
+ * between reconnects.
+ * reconnect_exponential_backoff - use exponential backoff between
+ * reconnect attempts. Set to true to enable
+ * exponential backoff.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ */
+libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff);
+
+/*
+ * Function: mosquitto_max_inflight_messages_set
+ *
+ * This function is deprected. Use the <mosquitto_int_option> function with the
+ * MOSQ_OPT_SEND_MAXIMUM option instead.
+ *
+ * Set the number of QoS 1 and 2 messages that can be "in flight" at one time.
+ * An in flight message is part way through its delivery flow. Attempts to send
+ * further messages with <mosquitto_publish> will result in the messages being
+ * queued until the number of in flight messages reduces.
+ *
+ * A higher number here results in greater message throughput, but if set
+ * higher than the maximum in flight messages on the broker may lead to
+ * delays in the messages being acknowledged.
+ *
+ * Set to 0 for no maximum.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * max_inflight_messages - the maximum number of inflight messages. Defaults
+ * to 20.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ */
+libmosq_EXPORT int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages);
+
+/*
+ * Function: mosquitto_message_retry_set
+ *
+ * This function now has no effect.
+ */
+libmosq_EXPORT void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry);
+
+/*
+ * Function: mosquitto_user_data_set
+ *
+ * When <mosquitto_new> is called, the pointer given as the "obj" parameter
+ * will be passed to the callbacks as user data. The <mosquitto_user_data_set>
+ * function allows this obj parameter to be updated at any time. This function
+ * will not modify the memory pointed to by the current user data pointer. If
+ * it is dynamically allocated memory you must free it yourself.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * obj - A user pointer that will be passed as an argument to any callbacks
+ * that are specified.
+ */
+libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj);
+
+/* Function: mosquitto_userdata
+ *
+ * Retrieve the "userdata" variable for a mosquitto client.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ *
+ * Returns:
+ * A pointer to the userdata member variable.
+ */
+libmosq_EXPORT void *mosquitto_userdata(struct mosquitto *mosq);
+
+
+/* ======================================================================
+ *
+ * Section: TLS support
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_tls_set
+ *
+ * Configure the client for certificate based SSL/TLS support. Must be called
+ * before <mosquitto_connect>.
+ *
+ * Cannot be used in conjunction with <mosquitto_tls_psk_set>.
+ *
+ * Define the Certificate Authority certificates to be trusted (ie. the server
+ * certificate must be signed with one of these certificates) using cafile.
+ *
+ * If the server you are connecting to requires clients to provide a
+ * certificate, define certfile and keyfile with your client certificate and
+ * private key. If your private key is encrypted, provide a password callback
+ * function or you will have to enter the password at the command line.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * cafile - path to a file containing the PEM encoded trusted CA
+ * certificate files. Either cafile or capath must not be NULL.
+ * capath - path to a directory containing the PEM encoded trusted CA
+ * certificate files. See mosquitto.conf for more details on
+ * configuring this directory. Either cafile or capath must not
+ * be NULL.
+ * certfile - path to a file containing the PEM encoded certificate file
+ * for this client. If NULL, keyfile must also be NULL and no
+ * client certificate will be used.
+ * keyfile - path to a file containing the PEM encoded private key for
+ * this client. If NULL, certfile must also be NULL and no
+ * client certificate will be used.
+ * pw_callback - if keyfile is encrypted, set pw_callback to allow your client
+ * to pass the correct password for decryption. If set to NULL,
+ * the password must be entered on the command line.
+ * Your callback must write the password into "buf", which is
+ * "size" bytes long. The return value must be the length of the
+ * password. "userdata" will be set to the calling mosquitto
+ * instance. The mosquitto userdata member variable can be
+ * retrieved using <mosquitto_userdata>.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * See Also:
+ * <mosquitto_tls_opts_set>, <mosquitto_tls_psk_set>,
+ * <mosquitto_tls_insecure_set>, <mosquitto_userdata>
+ */
+libmosq_EXPORT int mosquitto_tls_set(struct mosquitto *mosq,
+ const char *cafile, const char *capath,
+ const char *certfile, const char *keyfile,
+ int (*pw_callback)(char *buf, int size, int rwflag, void *userdata));
+
+/*
+ * Function: mosquitto_tls_insecure_set
+ *
+ * Configure verification of the server hostname in the server certificate. If
+ * value is set to true, it is impossible to guarantee that the host you are
+ * connecting to is not impersonating your server. This can be useful in
+ * initial server testing, but makes it possible for a malicious third party to
+ * impersonate your server through DNS spoofing, for example.
+ * Do not use this function in a real system. Setting value to true makes the
+ * connection encryption pointless.
+ * Must be called before <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * value - 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.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ *
+ * See Also:
+ * <mosquitto_tls_set>
+ */
+libmosq_EXPORT int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value);
+
+/*
+ * Function: mosquitto_tls_opts_set
+ *
+ * Set advanced SSL/TLS options. Must be called before <mosquitto_connect>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * cert_reqs - an integer defining the verification requirements the client
+ * will impose on the server. This can be one of:
+ * * SSL_VERIFY_NONE (0): the server will not be verified in any way.
+ * * SSL_VERIFY_PEER (1): the server certificate will be verified
+ * and the connection aborted if the verification fails.
+ * The default and recommended value is SSL_VERIFY_PEER. Using
+ * SSL_VERIFY_NONE provides no security.
+ * tls_version - the version of the SSL/TLS protocol to use as a string. If NULL,
+ * the default value is used. The default value and the
+ * available values depend on the version of openssl that the
+ * library was compiled against. For openssl >= 1.0.1, the
+ * available options are tlsv1.2, tlsv1.1 and tlsv1, with tlv1.2
+ * as the default. For openssl < 1.0.1, only tlsv1 is available.
+ * ciphers - a string describing the ciphers available for use. See the
+ * "openssl ciphers" tool for more information. If NULL, the
+ * default ciphers will be used.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * See Also:
+ * <mosquitto_tls_set>
+ */
+libmosq_EXPORT int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers);
+
+/*
+ * Function: mosquitto_tls_psk_set
+ *
+ * Configure the client for pre-shared-key based TLS support. Must be called
+ * before <mosquitto_connect>.
+ *
+ * Cannot be used in conjunction with <mosquitto_tls_set>.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * psk - the pre-shared-key in hex format with no leading "0x".
+ * identity - the identity of this client. May be used as the username
+ * depending on the server settings.
+ * ciphers - a string describing the PSK ciphers available for use. See the
+ * "openssl ciphers" tool for more information. If NULL, the
+ * default ciphers will be used.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ *
+ * See Also:
+ * <mosquitto_tls_set>
+ */
+libmosq_EXPORT int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers);
+
+
+/* ======================================================================
+ *
+ * Section: Callbacks
+ *
+ * ====================================================================== */
+/*
+ * Function: mosquitto_connect_callback_set
+ *
+ * Set the connect callback. This is called when the broker sends a CONNACK
+ * message in response to a connection.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_connect - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int rc)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * rc - the return code of the connection response, one of:
+ *
+ * * 0 - success
+ * * 1 - connection refused (unacceptable protocol version)
+ * * 2 - connection refused (identifier rejected)
+ * * 3 - connection refused (broker unavailable)
+ * * 4-255 - reserved for future use
+ */
+libmosq_EXPORT void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int));
+
+/*
+ * Function: mosquitto_connect_with_flags_callback_set
+ *
+ * Set the connect callback. This is called when the broker sends a CONNACK
+ * message in response to a connection.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_connect - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int rc)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * rc - the return code of the connection response, one of:
+ * flags - the connect flags.
+ *
+ * * 0 - success
+ * * 1 - connection refused (unacceptable protocol version)
+ * * 2 - connection refused (identifier rejected)
+ * * 3 - connection refused (broker unavailable)
+ * * 4-255 - reserved for future use
+ */
+libmosq_EXPORT void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int));
+
+/*
+ * Function: mosquitto_connect_v5_callback_set
+ *
+ * Set the connect callback. This is called when the broker sends a CONNACK
+ * message in response to a connection.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_connect - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int rc)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * rc - the return code of the connection response, one of:
+ * * 0 - success
+ * * 1 - connection refused (unacceptable protocol version)
+ * * 2 - connection refused (identifier rejected)
+ * * 3 - connection refused (broker unavailable)
+ * * 4-255 - reserved for future use
+ * flags - the connect flags.
+ * props - list of MQTT 5 properties, or NULL
+ *
+ */
+libmosq_EXPORT void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *props));
+
+/*
+ * Function: mosquitto_disconnect_callback_set
+ *
+ * Set the disconnect callback. This is called when the broker has received the
+ * DISCONNECT command and has disconnected the client.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_disconnect - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * rc - integer value indicating the reason for the disconnect. A value of 0
+ * means the client has called <mosquitto_disconnect>. Any other value
+ * indicates that the disconnect is unexpected.
+ */
+libmosq_EXPORT void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int));
+
+/*
+ * Function: mosquitto_disconnect_v5_callback_set
+ *
+ * Set the disconnect callback. This is called when the broker has received the
+ * DISCONNECT command and has disconnected the client.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_disconnect - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * rc - integer value indicating the reason for the disconnect. A value of 0
+ * means the client has called <mosquitto_disconnect>. Any other value
+ * indicates that the disconnect is unexpected.
+ * props - list of MQTT 5 properties, or NULL
+ */
+libmosq_EXPORT void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *));
+
+/*
+ * Function: mosquitto_publish_callback_set
+ *
+ * Set the publish callback. This is called when a message initiated with
+ * <mosquitto_publish> has been sent to the broker successfully.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_publish - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int mid)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * mid - the message id of the sent message.
+ */
+libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int));
+
+/*
+ * Function: mosquitto_publish_v5_callback_set
+ *
+ * Set the publish callback. This is called when a message initiated with
+ * <mosquitto_publish> has been sent to the broker. This callback will be
+ * called both if the message is sent successfully, or if the broker responded
+ * with an error, which will be reflected in the reason_code parameter.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_publish - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int mid)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * mid - the message id of the sent message.
+ * reason_code - the MQTT 5 reason code
+ * props - list of MQTT 5 properties, or NULL
+ */
+libmosq_EXPORT void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *));
+
+/*
+ * Function: mosquitto_message_callback_set
+ *
+ * Set the message callback. This is called when a message is received from the
+ * broker.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_message - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * message - the message data. This variable and associated memory will be
+ * freed by the library after the callback completes. The client
+ * should make copies of any of the data it requires.
+ *
+ * See Also:
+ * <mosquitto_message_copy>
+ */
+libmosq_EXPORT void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *));
+
+/*
+ * Function: mosquitto_message_v5_callback_set
+ *
+ * Set the message callback. This is called when a message is received from the
+ * broker.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_message - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * message - the message data. This variable and associated memory will be
+ * freed by the library after the callback completes. The client
+ * should make copies of any of the data it requires.
+ * props - list of MQTT 5 properties, or NULL
+ *
+ * See Also:
+ * <mosquitto_message_copy>
+ */
+libmosq_EXPORT void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *));
+
+/*
+ * Function: mosquitto_subscribe_callback_set
+ *
+ * Set the subscribe callback. This is called when the broker responds to a
+ * subscription request.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_subscribe - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * mid - the message id of the subscribe message.
+ * qos_count - the number of granted subscriptions (size of granted_qos).
+ * granted_qos - an array of integers indicating the granted QoS for each of
+ * the subscriptions.
+ */
+libmosq_EXPORT void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *));
+
+/*
+ * Function: mosquitto_subscribe_v5_callback_set
+ *
+ * Set the subscribe callback. This is called when the broker responds to a
+ * subscription request.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_subscribe - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * mid - the message id of the subscribe message.
+ * qos_count - the number of granted subscriptions (size of granted_qos).
+ * granted_qos - an array of integers indicating the granted QoS for each of
+ * the subscriptions.
+ * props - list of MQTT 5 properties, or NULL
+ */
+libmosq_EXPORT void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *));
+
+/*
+ * Function: mosquitto_unsubscribe_callback_set
+ *
+ * Set the unsubscribe callback. This is called when the broker responds to a
+ * unsubscription request.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_unsubscribe - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int mid)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * mid - the message id of the unsubscribe message.
+ */
+libmosq_EXPORT void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int));
+
+/*
+ * Function: mosquitto_unsubscribe_v5_callback_set
+ *
+ * Set the unsubscribe callback. This is called when the broker responds to a
+ * unsubscription request.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * on_unsubscribe - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int mid)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * mid - the message id of the unsubscribe message.
+ * props - list of MQTT 5 properties, or NULL
+ */
+libmosq_EXPORT void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *));
+
+/*
+ * Function: mosquitto_log_callback_set
+ *
+ * Set the logging callback. This should be used if you want event logging
+ * information from the client library.
+ *
+ * mosq - a valid mosquitto instance.
+ * on_log - a callback function in the following form:
+ * void callback(struct mosquitto *mosq, void *obj, int level, const char *str)
+ *
+ * Callback Parameters:
+ * mosq - the mosquitto instance making the callback.
+ * obj - the user data provided in <mosquitto_new>
+ * level - the log message level from the values:
+ * MOSQ_LOG_INFO
+ * MOSQ_LOG_NOTICE
+ * MOSQ_LOG_WARNING
+ * MOSQ_LOG_ERR
+ * MOSQ_LOG_DEBUG
+ * str - the message string.
+ */
+libmosq_EXPORT void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *));
+
+/*
+ * Function: mosquitto_string_option
+ *
+ * Used to set const char* options for the client.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * option - the option to set.
+ * value - the option specific value.
+ *
+ * Options:
+ * MOSQ_OPT_TLS_ENGINE
+ * Configure the client for TLS Engine support. Pass a TLS Engine ID
+ * to be used when creating TLS connections.
+ * Must be set before <mosquitto_connect>.
+ * MOSQ_OPT_TLS_KEYFORM
+ * Configure the client to treat the keyfile differently depending
+ * on its type. Must be set before <mosquitto_connect>.
+ * Set as either "pem" or "engine", to determine from where the
+ * private key for a TLS connection will be obtained. Defaults to
+ * "pem", a normal private key file.
+ * MOSQ_OPT_TLS_KPASS_SHA1
+ * Where the TLS Engine requires the use of a password to be
+ * accessed, this option allows a hex encoded SHA1 hash of the
+ * private key password to be passed to the engine directly.
+ * Must be set before <mosquitto_connect>.
+ * MOSQ_OPT_TLS_ALPN
+ * If the broker being connected to has multiple services available
+ * on a single TLS port, such as both MQTT and WebSockets, use this
+ * option to configure the ALPN option for the connection.
+ */
+libmosq_EXPORT int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, const char *value);
+
+
+/*
+ * Function: mosquitto_reconnect_delay_set
+ *
+ * Control the behaviour of the client when it has unexpectedly disconnected in
+ * <mosquitto_loop_forever> or after <mosquitto_loop_start>. The default
+ * behaviour if this function is not used is to repeatedly attempt to reconnect
+ * with a delay of 1 second until the connection succeeds.
+ *
+ * Use reconnect_delay parameter to change the delay between successive
+ * reconnection attempts. You may also enable exponential backoff of the time
+ * between reconnections by setting reconnect_exponential_backoff to true and
+ * set an upper bound on the delay with reconnect_delay_max.
+ *
+ * Example 1:
+ * delay=2, delay_max=10, exponential_backoff=False
+ * Delays would be: 2, 4, 6, 8, 10, 10, ...
+ *
+ * Example 2:
+ * delay=3, delay_max=30, exponential_backoff=True
+ * Delays would be: 3, 6, 12, 24, 30, 30, ...
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * reconnect_delay - the number of seconds to wait between
+ * reconnects.
+ * reconnect_delay_max - the maximum number of seconds to wait
+ * between reconnects.
+ * reconnect_exponential_backoff - use exponential backoff between
+ * reconnect attempts. Set to true to enable
+ * exponential backoff.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success.
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ */
+libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff);
+
+
+/* =============================================================================
+ *
+ * Section: SOCKS5 proxy functions
+ *
+ * =============================================================================
+ */
+
+/*
+ * Function: mosquitto_socks5_set
+ *
+ * Configure the client to use a SOCKS5 proxy when connecting. Must be called
+ * before connecting. "None" and "username/password" authentication is
+ * supported.
+ *
+ * Parameters:
+ * mosq - a valid mosquitto instance.
+ * host - the SOCKS5 proxy host to connect to.
+ * port - the SOCKS5 proxy port to use.
+ * username - if not NULL, use this username when authenticating with the proxy.
+ * password - if not NULL and username is not NULL, use this password when
+ * authenticating with the proxy.
+ */
+libmosq_EXPORT int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password);
+
+
+/* =============================================================================
+ *
+ * Section: Utility functions
+ *
+ * =============================================================================
+ */
+
+/*
+ * Function: mosquitto_strerror
+ *
+ * Call to obtain a const string description of a mosquitto error number.
+ *
+ * Parameters:
+ * mosq_errno - a mosquitto error number.
+ *
+ * Returns:
+ * A constant string describing the error.
+ */
+libmosq_EXPORT const char *mosquitto_strerror(int mosq_errno);
+
+/*
+ * Function: mosquitto_connack_string
+ *
+ * Call to obtain a const string description of an MQTT connection result.
+ *
+ * Parameters:
+ * connack_code - an MQTT connection result.
+ *
+ * Returns:
+ * A constant string describing the result.
+ */
+libmosq_EXPORT const char *mosquitto_connack_string(int connack_code);
+
+/*
+ * Function: mosquitto_reason_string
+ *
+ * Call to obtain a const string description of an MQTT reason code.
+ *
+ * Parameters:
+ * reason_code - an MQTT reason code.
+ *
+ * Returns:
+ * A constant string describing the reason.
+ */
+libmosq_EXPORT const char *mosquitto_reason_string(int reason_code);
+
+/* Function: mosquitto_string_to_command
+ *
+ * Take a string input representing an MQTT command and convert it to the
+ * libmosquitto integer representation.
+ *
+ * Parameters:
+ * str - the string to parse.
+ * cmd - pointer to an int, for the result.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - on an invalid input.
+ *
+ * Example:
+ * mosquitto_string_to_command("CONNECT", &cmd);
+ * // cmd == CMD_CONNECT
+ */
+libmosq_EXPORT int mosquitto_string_to_command(const char *str, int *cmd);
+
+/*
+ * Function: mosquitto_sub_topic_tokenise
+ *
+ * Tokenise a topic or subscription string into an array of strings
+ * representing the topic hierarchy.
+ *
+ * For example:
+ *
+ * subtopic: "a/deep/topic/hierarchy"
+ *
+ * Would result in:
+ *
+ * topics[0] = "a"
+ * topics[1] = "deep"
+ * topics[2] = "topic"
+ * topics[3] = "hierarchy"
+ *
+ * and:
+ *
+ * subtopic: "/a/deep/topic/hierarchy/"
+ *
+ * Would result in:
+ *
+ * topics[0] = NULL
+ * topics[1] = "a"
+ * topics[2] = "deep"
+ * topics[3] = "topic"
+ * topics[4] = "hierarchy"
+ *
+ * Parameters:
+ * subtopic - the subscription/topic to tokenise
+ * topics - a pointer to store the array of strings
+ * count - an int pointer to store the number of items in the topics array.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8
+ *
+ * Example:
+ *
+ * > char **topics;
+ * > int topic_count;
+ * > int i;
+ * >
+ * > mosquitto_sub_topic_tokenise("$SYS/broker/uptime", &topics, &topic_count);
+ * >
+ * > for(i=0; i<token_count; i++){
+ * > printf("%d: %s\n", i, topics[i]);
+ * > }
+ *
+ * See Also:
+ * <mosquitto_sub_topic_tokens_free>
+ */
+libmosq_EXPORT int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count);
+
+/*
+ * Function: mosquitto_sub_topic_tokens_free
+ *
+ * Free memory that was allocated in <mosquitto_sub_topic_tokenise>.
+ *
+ * Parameters:
+ * topics - pointer to string array.
+ * count - count of items in string array.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ *
+ * See Also:
+ * <mosquitto_sub_topic_tokenise>
+ */
+libmosq_EXPORT int mosquitto_sub_topic_tokens_free(char ***topics, int count);
+
+/*
+ * Function: mosquitto_topic_matches_sub
+ * Function: mosquitto_topic_matches_sub2
+ *
+ * Check whether a topic matches a subscription.
+ *
+ * For example:
+ *
+ * foo/bar would match the subscription foo/# or +/bar
+ * non/matching would not match the subscription non/+/+
+ *
+ * Parameters:
+ * sub - subscription string to check topic against.
+ * sublen - length in bytes of sub string
+ * topic - topic to check.
+ * topiclen - length in bytes of topic string
+ * result - bool pointer to hold result. Will be set to true if the topic
+ * matches the subscription.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if the input parameters were invalid.
+ * MOSQ_ERR_NOMEM - if an out of memory condition occurred.
+ */
+libmosq_EXPORT int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result);
+libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result);
+
+/*
+ * Function: mosquitto_pub_topic_check
+ *
+ * Check whether a topic to be used for publishing is valid.
+ *
+ * This searches for + or # in a topic and checks its length.
+ *
+ * This check is already carried out in <mosquitto_publish> and
+ * <mosquitto_will_set>, there is no need to call it directly before them. It
+ * may be useful if you wish to check the validity of a topic in advance of
+ * making a connection for example.
+ *
+ * Parameters:
+ * topic - the topic to check
+ * topiclen - length of the topic in bytes
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - for a valid topic
+ * MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long.
+ * MOSQ_ERR_MALFORMED_UTF8 - if sub or topic is not valid UTF-8
+ *
+ * See Also:
+ * <mosquitto_sub_topic_check>
+ */
+libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic);
+libmosq_EXPORT int mosquitto_pub_topic_check2(const char *topic, size_t topiclen);
+
+/*
+ * Function: mosquitto_sub_topic_check
+ *
+ * Check whether a topic to be used for subscribing is valid.
+ *
+ * This searches for + or # in a topic and checks that they aren't in invalid
+ * positions, such as with foo/#/bar, foo/+bar or foo/bar#, and checks its
+ * length.
+ *
+ * This check is already carried out in <mosquitto_subscribe> and
+ * <mosquitto_unsubscribe>, there is no need to call it directly before them.
+ * It may be useful if you wish to check the validity of a topic in advance of
+ * making a connection for example.
+ *
+ * Parameters:
+ * topic - the topic to check
+ * topiclen - the length in bytes of the topic
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - for a valid topic
+ * MOSQ_ERR_INVAL - if the topic contains a + or a # that is in an
+ * invalid position, or if it is too long.
+ * MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8
+ *
+ * See Also:
+ * <mosquitto_sub_topic_check>
+ */
+libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic);
+libmosq_EXPORT int mosquitto_sub_topic_check2(const char *topic, size_t topiclen);
+
+
+struct libmosquitto_will {
+ char *topic;
+ void *payload;
+ int payloadlen;
+ int qos;
+ bool retain;
+};
+
+struct libmosquitto_auth {
+ char *username;
+ char *password;
+};
+
+struct libmosquitto_tls {
+ char *cafile;
+ char *capath;
+ char *certfile;
+ char *keyfile;
+ char *ciphers;
+ char *tls_version;
+ int (*pw_callback)(char *buf, int size, int rwflag, void *userdata);
+ int cert_reqs;
+};
+
+/*
+ * Function: mosquitto_subscribe_simple
+ *
+ * Helper function to make subscribing to a topic and retrieving some messages
+ * very straightforward.
+ *
+ * This connects to a broker, subscribes to a topic, waits for msg_count
+ * messages to be received, then returns after disconnecting cleanly.
+ *
+ * Parameters:
+ * messages - pointer to a "struct mosquitto_message *". The received
+ * messages will be returned here. On error, this will be set to
+ * NULL.
+ * msg_count - the number of messages to retrieve.
+ * want_retained - if set to true, stale retained messages will be treated as
+ * normal messages with regards to msg_count. If set to
+ * false, they will be ignored.
+ * topic - the subscription topic to use (wildcards are allowed).
+ * qos - the qos to use for the subscription.
+ * host - the broker to connect to.
+ * port - the network port the broker is listening on.
+ * client_id - the client id to use, or NULL if a random client id should be
+ * generated.
+ * keepalive - the MQTT keepalive value.
+ * clean_session - the MQTT clean session flag.
+ * username - the username string, or NULL for no username authentication.
+ * password - the password string, or NULL for an empty password.
+ * will - a libmosquitto_will struct containing will information, or NULL for
+ * no will.
+ * tls - a libmosquitto_tls struct containing TLS related parameters, or NULL
+ * for no use of TLS.
+ *
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * >0 - on error.
+ */
+libmosq_EXPORT int mosquitto_subscribe_simple(
+ struct mosquitto_message **messages,
+ int msg_count,
+ bool want_retained,
+ const char *topic,
+ int qos,
+ const char *host,
+ int port,
+ const char *client_id,
+ int keepalive,
+ bool clean_session,
+ const char *username,
+ const char *password,
+ const struct libmosquitto_will *will,
+ const struct libmosquitto_tls *tls);
+
+
+/*
+ * Function: mosquitto_subscribe_callback
+ *
+ * Helper function to make subscribing to a topic and processing some messages
+ * very straightforward.
+ *
+ * This connects to a broker, subscribes to a topic, then passes received
+ * messages to a user provided callback. If the callback returns a 1, it then
+ * disconnects cleanly and returns.
+ *
+ * Parameters:
+ * callback - a callback function in the following form:
+ * int callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
+ * Note that this is the same as the normal on_message callback,
+ * except that it returns an int.
+ * userdata - user provided pointer that will be passed to the callback.
+ * topic - the subscription topic to use (wildcards are allowed).
+ * qos - the qos to use for the subscription.
+ * host - the broker to connect to.
+ * port - the network port the broker is listening on.
+ * client_id - the client id to use, or NULL if a random client id should be
+ * generated.
+ * keepalive - the MQTT keepalive value.
+ * clean_session - the MQTT clean session flag.
+ * username - the username string, or NULL for no username authentication.
+ * password - the password string, or NULL for an empty password.
+ * will - a libmosquitto_will struct containing will information, or NULL for
+ * no will.
+ * tls - a libmosquitto_tls struct containing TLS related parameters, or NULL
+ * for no use of TLS.
+ *
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * >0 - on error.
+ */
+libmosq_EXPORT int mosquitto_subscribe_callback(
+ int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *),
+ void *userdata,
+ const char *topic,
+ int qos,
+ const char *host,
+ int port,
+ const char *client_id,
+ int keepalive,
+ bool clean_session,
+ const char *username,
+ const char *password,
+ const struct libmosquitto_will *will,
+ const struct libmosquitto_tls *tls);
+
+
+/*
+ * Function: mosquitto_validate_utf8
+ *
+ * Helper function to validate whether a UTF-8 string is valid, according to
+ * the UTF-8 spec and the MQTT additions.
+ *
+ * Parameters:
+ * str - a string to check
+ * len - the length of the string in bytes
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if str is NULL or len<0 or len>65536
+ * MOSQ_ERR_MALFORMED_UTF8 - if str is not valid UTF-8
+ */
+libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len);
+
+
+/* =============================================================================
+ *
+ * Section: Properties
+ *
+ * =============================================================================
+ */
+
+
+/*
+ * Function: mosquitto_property_add_byte
+ *
+ * Add a new byte property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - integer value for the new property
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_byte(&proplist, MQTT_PROP_PAYLOAD_FORMAT_IDENTIFIER, 1);
+ */
+libmosq_EXPORT int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value);
+
+/*
+ * Function: mosquitto_property_add_int16
+ *
+ * Add a new int16 property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_RECEIVE_MAXIMUM)
+ * value - integer value for the new property
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_int16(&proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1000);
+ */
+libmosq_EXPORT int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value);
+
+/*
+ * Function: mosquitto_property_add_int32
+ *
+ * Add a new int32 property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_MESSAGE_EXPIRY_INTERVAL)
+ * value - integer value for the new property
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_int32(&proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 86400);
+ */
+libmosq_EXPORT int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value);
+
+/*
+ * Function: mosquitto_property_add_varint
+ *
+ * Add a new varint property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_SUBSCRIPTION_IDENTIFIER)
+ * value - integer value for the new property
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_varint(&proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 1);
+ */
+libmosq_EXPORT int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value);
+
+/*
+ * Function: mosquitto_property_add_binary
+ *
+ * Add a new binary property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to the property data
+ * len - length of property data in bytes
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_binary(&proplist, MQTT_PROP_AUTHENTICATION_DATA, auth_data, auth_data_len);
+ */
+libmosq_EXPORT int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len);
+
+/*
+ * Function: mosquitto_property_add_string
+ *
+ * Add a new string property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_CONTENT_TYPE)
+ * value - string value for the new property, must be UTF-8 and zero terminated
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, if value is NULL, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ * MOSQ_ERR_MALFORMED_UTF8 - value is not valid UTF-8.
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_string(&proplist, MQTT_PROP_CONTENT_TYPE, "application/json");
+ */
+libmosq_EXPORT int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value);
+
+/*
+ * Function: mosquitto_property_add_string_pair
+ *
+ * Add a new string pair property to a property list.
+ *
+ * If *proplist == NULL, a new list will be created, otherwise the new property
+ * will be appended to the list.
+ *
+ * Parameters:
+ * proplist - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_USER_PROPERTY)
+ * name - string name for the new property, must be UTF-8 and zero terminated
+ * value - string value for the new property, must be UTF-8 and zero terminated
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if identifier is invalid, if name or value is NULL, or if proplist is NULL
+ * MOSQ_ERR_NOMEM - on out of memory
+ * MOSQ_ERR_MALFORMED_UTF8 - if name or value are not valid UTF-8.
+ *
+ * Example:
+ * mosquitto_property *proplist = NULL;
+ * mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "client", "mosquitto_pub");
+ */
+libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value);
+
+/*
+ * Function: mosquitto_property_read_byte
+ *
+ * Attempt to read a byte property matching an identifier, from a property list
+ * or single property. This function can search for multiple entries of the
+ * same identifier by using the returned value and skip_first. Note however
+ * that it is forbidden for most properties to be duplicated.
+ *
+ * If the property is not found, *value will not be modified, so it is safe to
+ * pass a variable with a default value to be potentially overwritten:
+ *
+ * uint16_t keepalive = 60; // default value
+ * // Get value from property list, or keep default if not found.
+ * mosquitto_property_read_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, &keepalive, false);
+ *
+ * Parameters:
+ * proplist - mosquitto_property pointer, the list of properties or single property
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to store the value, or NULL if the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL.
+ *
+ * Example:
+ * // proplist is obtained from a callback
+ * mosquitto_property *prop;
+ * prop = mosquitto_property_read_byte(proplist, identifier, &value, false);
+ * while(prop){
+ * printf("value: %s\n", value);
+ * prop = mosquitto_property_read_byte(prop, identifier, &value);
+ * }
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_byte(
+ const mosquitto_property *proplist,
+ int identifier,
+ uint8_t *value,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_read_int16
+ *
+ * Read an int16 property value from a property.
+ *
+ * Parameters:
+ * property - property to read
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to store the value, or NULL if the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL.
+ *
+ * Example:
+ * See <mosquitto_property_read_byte>
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int16(
+ const mosquitto_property *proplist,
+ int identifier,
+ uint16_t *value,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_read_int32
+ *
+ * Read an int32 property value from a property.
+ *
+ * Parameters:
+ * property - pointer to mosquitto_property pointer, the list of properties
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to store the value, or NULL if the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL.
+ *
+ * Example:
+ * See <mosquitto_property_read_byte>
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int32(
+ const mosquitto_property *proplist,
+ int identifier,
+ uint32_t *value,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_read_varint
+ *
+ * Read a varint property value from a property.
+ *
+ * Parameters:
+ * property - property to read
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to store the value, or NULL if the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL.
+ *
+ * Example:
+ * See <mosquitto_property_read_byte>
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_varint(
+ const mosquitto_property *proplist,
+ int identifier,
+ uint32_t *value,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_read_binary
+ *
+ * Read a binary property value from a property.
+ *
+ * On success, value must be free()'d by the application.
+ *
+ * Parameters:
+ * property - property to read
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to store the value, or NULL if the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred.
+ *
+ * Example:
+ * See <mosquitto_property_read_byte>
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_binary(
+ const mosquitto_property *proplist,
+ int identifier,
+ void **value,
+ uint16_t *len,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_read_string
+ *
+ * Read a string property value from a property.
+ *
+ * On success, value must be free()'d by the application.
+ *
+ * Parameters:
+ * property - property to read
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * value - pointer to char*, for the property data to be stored in, or NULL if
+ * the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred.
+ *
+ * Example:
+ * See <mosquitto_property_read_byte>
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string(
+ const mosquitto_property *proplist,
+ int identifier,
+ char **value,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_read_string_pair
+ *
+ * Read a string pair property value pair from a property.
+ *
+ * On success, name and value must be free()'d by the application.
+ *
+ * Parameters:
+ * property - property to read
+ * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR)
+ * name - pointer to char* for the name property data to be stored in, or NULL
+ * if the name is not required.
+ * value - pointer to char*, for the property data to be stored in, or NULL if
+ * the value is not required.
+ * skip_first - boolean that indicates whether the first item in the list
+ * should be ignored or not. Should usually be set to false.
+ *
+ * Returns:
+ * A valid property pointer if the property is found
+ * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred.
+ *
+ * Example:
+ * See <mosquitto_property_read_byte>
+ */
+libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string_pair(
+ const mosquitto_property *proplist,
+ int identifier,
+ char **name,
+ char **value,
+ bool skip_first);
+
+/*
+ * Function: mosquitto_property_free_all
+ *
+ * Free all properties from a list of properties. Frees the list and sets *properties to NULL.
+ *
+ * Parameters:
+ * properties - list of properties to free
+ *
+ * Example:
+ * mosquitto_properties *properties = NULL;
+ * // Add properties
+ * mosquitto_property_free_all(&properties);
+ */
+libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties);
+
+/*
+ * Function: mosquitto_property_copy_all
+ *
+ * Parameters:
+ * dest : pointer for new property list
+ * src : property list
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on successful copy
+ * MOSQ_ERR_INVAL - if dest is NULL
+ * MOSQ_ERR_NOMEM - on out of memory (dest will be set to NULL)
+ */
+libmosq_EXPORT int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_property *src);
+
+/*
+ * Function: mosquitto_property_check_command
+ *
+ * Check whether a property identifier is valid for the given command.
+ *
+ * Parameters:
+ * command - MQTT command (e.g. CMD_CONNECT)
+ * identifier - MQTT property (e.g. MQTT_PROP_USER_PROPERTY)
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - if the identifier is valid for command
+ * MOSQ_ERR_PROTOCOL - if the identifier is not valid for use with command.
+ */
+libmosq_EXPORT int mosquitto_property_check_command(int command, int identifier);
+
+
+/*
+ * Function: mosquitto_property_check_all
+ *
+ * Check whether a list of properties are valid for a particular command,
+ * whether there are duplicates, and whether the values are valid where
+ * possible.
+ *
+ * Note that this function is used internally in the library whenever
+ * properties are passed to it, so in basic use this is not needed, but should
+ * be helpful to check property lists *before* the point of using them.
+ *
+ * Parameters:
+ * command - MQTT command (e.g. CMD_CONNECT)
+ * properties - list of MQTT properties to check.
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - if all properties are valid
+ * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
+ * MOSQ_ERR_PROTOCOL - if any property is invalid
+ */
+libmosq_EXPORT int mosquitto_property_check_all(int command, const mosquitto_property *properties);
+
+/* Function: mosquitto_string_to_property_info
+ *
+ * Parse a property name string and convert to a property identifier and data type.
+ * The property name is as defined in the MQTT specification, with - as a
+ * separator, for example: payload-format-indicator.
+ *
+ * Parameters:
+ * propname - the string to parse
+ * identifier - pointer to an int to receive the property identifier
+ * type - pointer to an int to receive the property type
+ *
+ * Returns:
+ * MOSQ_ERR_SUCCESS - on success
+ * MOSQ_ERR_INVAL - if the string does not match a property
+ *
+ * Example:
+ * mosquitto_string_to_property_info("response-topic", &id, &type);
+ * // id == MQTT_PROP_RESPONSE_TOPIC
+ * // type == MQTT_PROP_TYPE_STRING
+ */
+libmosq_EXPORT int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libs/libmosquitto/include/uthash.h b/libs/libmosquitto/include/uthash.h
new file mode 100644
index 0000000000..915a8254ee
--- /dev/null
+++ b/libs/libmosquitto/include/uthash.h
@@ -0,0 +1,948 @@
+/*
+Copyright (c) 2003-2013, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#include <string.h> /* memcmp,strlen */
+#include <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#else /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ char **_da_dst = (char**)(&(dst)); \
+ *_da_dst = (char*)(src); \
+} while(0)
+#else
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ (dst) = DECLTYPE(dst)(src); \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on win32 */
+#ifdef _MSC_VER
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#else
+#include <inttypes.h> /* uint32_t */
+#endif
+
+#define UTHASH_VERSION 1.9.8
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
+#endif
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr) /* free fcn */
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl) /* can be defined to log expands */
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out) \
+do { \
+ unsigned _hf_bkt,_hf_hashv; \
+ out=NULL; \
+ if (head) { \
+ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
+ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
+ keyptr,keylen,out); \
+ } \
+ } \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl) \
+do { \
+ (tbl)->bloom_nbits = HASH_BLOOM; \
+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
+ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
+ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl) \
+do { \
+ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv) \
+ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv) \
+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0
+#endif
+
+#define HASH_MAKE_TABLE(hh,head) \
+do { \
+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
+ sizeof(UT_hash_table)); \
+ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
+ (head)->hh.tbl->tail = &((head)->hh); \
+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl->buckets, 0, \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_MAKE((head)->hh.tbl); \
+ (head)->hh.tbl->signature = HASH_SIGNATURE; \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
+ HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
+do { \
+ replaced=NULL; \
+ HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \
+ if (replaced!=NULL) { \
+ HASH_DELETE(hh,head,replaced); \
+ }; \
+ HASH_ADD(hh,head,fieldname,keylen_in,add); \
+} while(0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
+do { \
+ unsigned _ha_bkt; \
+ (add)->hh.next = NULL; \
+ (add)->hh.key = (char*)keyptr; \
+ (add)->hh.keylen = (unsigned)keylen_in; \
+ if (!(head)) { \
+ head = (add); \
+ (head)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh,head); \
+ } else { \
+ (head)->hh.tbl->tail->next = (add); \
+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
+ (head)->hh.tbl->tail = &((add)->hh); \
+ } \
+ (head)->hh.tbl->num_items++; \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
+ (add)->hh.hashv, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
+ HASH_FSCK(hh,head); \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
+do { \
+ bkt = ((hashv) & ((num_bkts) - 1)); \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ * HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr) \
+do { \
+ unsigned _hd_bkt; \
+ struct UT_hash_handle *_hd_hh_del; \
+ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ head = NULL; \
+ } else { \
+ _hd_hh_del = &((delptr)->hh); \
+ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
+ (head)->hh.tbl->tail = \
+ (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho); \
+ } \
+ if ((delptr)->hh.prev) { \
+ ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \
+ } else { \
+ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
+ } \
+ if (_hd_hh_del->next) { \
+ ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \
+ (head)->hh.tbl->hho))->prev = \
+ _hd_hh_del->prev; \
+ } \
+ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
+ (head)->hh.tbl->num_items--; \
+ } \
+ HASH_FSCK(hh,head); \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out) \
+ HASH_FIND(hh,head,findstr,strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add) \
+ HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
+#define HASH_REPLACE_STR(head,strfield,add,replaced) \
+ HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced)
+#define HASH_FIND_INT(head,findint,out) \
+ HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add) \
+ HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced) \
+ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out) \
+ HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add) \
+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add) \
+ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr) \
+ HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head) \
+do { \
+ unsigned _bkt_i; \
+ unsigned _count, _bkt_count; \
+ char *_prev; \
+ struct UT_hash_handle *_thh; \
+ if (head) { \
+ _count = 0; \
+ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
+ _bkt_count = 0; \
+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
+ _prev = NULL; \
+ while (_thh) { \
+ if (_prev != (char*)(_thh->hh_prev)) { \
+ HASH_OOPS("invalid hh_prev %p, actual %p\n", \
+ _thh->hh_prev, _prev ); \
+ } \
+ _bkt_count++; \
+ _prev = (char*)(_thh); \
+ _thh = _thh->hh_next; \
+ } \
+ _count += _bkt_count; \
+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
+ HASH_OOPS("invalid bucket count %d, actual %d\n", \
+ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
+ } \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid hh item count %d, actual %d\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ /* traverse hh in app order; check next/prev integrity, count */ \
+ _count = 0; \
+ _prev = NULL; \
+ _thh = &(head)->hh; \
+ while (_thh) { \
+ _count++; \
+ if (_prev !=(char*)(_thh->prev)) { \
+ HASH_OOPS("invalid prev %p, actual %p\n", \
+ _thh->prev, _prev ); \
+ } \
+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
+ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
+ (head)->hh.tbl->hho) : NULL ); \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid app item count %d, actual %d\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ } \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
+do { \
+ unsigned _klen = fieldlen; \
+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
+ write(HASH_EMIT_KEYS, keyptr, fieldlen); \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6 */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hb_keylen=keylen; \
+ char *_hb_key=(char*)(key); \
+ (hashv) = 0; \
+ while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
+ bkt = (hashv) & (num_bkts-1); \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _sx_i; \
+ char *_hs_key=(char*)(key); \
+ hashv = 0; \
+ for(_sx_i=0; _sx_i < keylen; _sx_i++) \
+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while (0)
+
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _fn_i; \
+ char *_hf_key=(char*)(key); \
+ hashv = 2166136261UL; \
+ for(_fn_i=0; _fn_i < keylen; _fn_i++) \
+ hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _ho_i; \
+ char *_ho_key=(char*)(key); \
+ hashv = 0; \
+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
+ hashv += _ho_key[_ho_i]; \
+ hashv += (hashv << 10); \
+ hashv ^= (hashv >> 6); \
+ } \
+ hashv += (hashv << 3); \
+ hashv ^= (hashv >> 11); \
+ hashv += (hashv << 15); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c) \
+do { \
+ a -= b; a -= c; a ^= ( c >> 13 ); \
+ b -= c; b -= a; b ^= ( a << 8 ); \
+ c -= a; c -= b; c ^= ( b >> 13 ); \
+ a -= b; a -= c; a ^= ( c >> 12 ); \
+ b -= c; b -= a; b ^= ( a << 16 ); \
+ c -= a; c -= b; c ^= ( b >> 5 ); \
+ a -= b; a -= c; a ^= ( c >> 3 ); \
+ b -= c; b -= a; b ^= ( a << 10 ); \
+ c -= a; c -= b; c ^= ( b >> 15 ); \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hj_i,_hj_j,_hj_k; \
+ unsigned char *_hj_key=(unsigned char*)(key); \
+ hashv = 0xfeedbeef; \
+ _hj_i = _hj_j = 0x9e3779b9; \
+ _hj_k = (unsigned)keylen; \
+ while (_hj_k >= 12) { \
+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ + ( (unsigned)_hj_key[2] << 16 ) \
+ + ( (unsigned)_hj_key[3] << 24 ) ); \
+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ + ( (unsigned)_hj_key[6] << 16 ) \
+ + ( (unsigned)_hj_key[7] << 24 ) ); \
+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ + ( (unsigned)_hj_key[10] << 16 ) \
+ + ( (unsigned)_hj_key[11] << 24 ) ); \
+ \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ \
+ _hj_key += 12; \
+ _hj_k -= 12; \
+ } \
+ hashv += keylen; \
+ switch ( _hj_k ) { \
+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
+ case 5: _hj_j += _hj_key[4]; \
+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
+ case 1: _hj_i += _hj_key[0]; \
+ } \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned char *_sfh_key=(unsigned char*)(key); \
+ uint32_t _sfh_tmp, _sfh_len = keylen; \
+ \
+ int _sfh_rem = _sfh_len & 3; \
+ _sfh_len >>= 2; \
+ hashv = 0xcafebabe; \
+ \
+ /* Main loop */ \
+ for (;_sfh_len > 0; _sfh_len--) { \
+ hashv += get16bits (_sfh_key); \
+ _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \
+ hashv = (hashv << 16) ^ _sfh_tmp; \
+ _sfh_key += 2*sizeof (uint16_t); \
+ hashv += hashv >> 11; \
+ } \
+ \
+ /* Handle end cases */ \
+ switch (_sfh_rem) { \
+ case 3: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 16; \
+ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \
+ hashv += hashv >> 11; \
+ break; \
+ case 2: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 11; \
+ hashv += hashv >> 17; \
+ break; \
+ case 1: hashv += *_sfh_key; \
+ hashv ^= hashv << 10; \
+ hashv += hashv >> 1; \
+ } \
+ \
+ /* Force "avalanching" of final 127 bits */ \
+ hashv ^= hashv << 3; \
+ hashv += hashv >> 5; \
+ hashv ^= hashv << 4; \
+ hashv += hashv >> 17; \
+ hashv ^= hashv << 25; \
+ hashv += hashv >> 6; \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ * gcc -m64 -dM -E - < /dev/null (on gcc)
+ * cc -## a.c (where a.c is a simple test file) (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
+ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
+ MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do { \
+ _h ^= _h >> 16; \
+ _h *= 0x85ebca6b; \
+ _h ^= _h >> 13; \
+ _h *= 0xc2b2ae35l; \
+ _h ^= _h >> 16; \
+} while(0)
+
+#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ const uint8_t *_mur_data = (const uint8_t*)(key); \
+ const int _mur_nblocks = (keylen) / 4; \
+ uint32_t _mur_h1 = 0xf88D5353; \
+ uint32_t _mur_c1 = 0xcc9e2d51; \
+ uint32_t _mur_c2 = 0x1b873593; \
+ uint32_t _mur_k1 = 0; \
+ const uint8_t *_mur_tail; \
+ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
+ int _mur_i; \
+ for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
+ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ \
+ _mur_h1 ^= _mur_k1; \
+ _mur_h1 = MUR_ROTL32(_mur_h1,13); \
+ _mur_h1 = _mur_h1*5+0xe6546b64; \
+ } \
+ _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
+ _mur_k1=0; \
+ switch((keylen) & 3) { \
+ case 3: _mur_k1 ^= _mur_tail[2] << 16; \
+ case 2: _mur_k1 ^= _mur_tail[1] << 8; \
+ case 1: _mur_k1 ^= _mur_tail[0]; \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ _mur_h1 ^= _mur_k1; \
+ } \
+ _mur_h1 ^= (keylen); \
+ MUR_FMIX(_mur_h1); \
+ hashv = _mur_h1; \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+#endif /* HASH_USING_NO_STRICT_ALIASING */
+
+/* key comparison function; return 0 if keys equal */
+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
+do { \
+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
+ else out=NULL; \
+ while (out) { \
+ if ((out)->hh.keylen == keylen_in) { \
+ if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \
+ } \
+ if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
+ else out = NULL; \
+ } \
+} while(0)
+
+/* add an item to a bucket */
+#define HASH_ADD_TO_BKT(head,addhh) \
+do { \
+ head.count++; \
+ (addhh)->hh_next = head.hh_head; \
+ (addhh)->hh_prev = NULL; \
+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
+ (head).hh_head=addhh; \
+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
+ && (addhh)->tbl->noexpand != 1) { \
+ HASH_EXPAND_BUCKETS((addhh)->tbl); \
+ } \
+} while(0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del) \
+ (head).count--; \
+ if ((head).hh_head == hh_del) { \
+ (head).hh_head = hh_del->hh_next; \
+ } \
+ if (hh_del->hh_prev) { \
+ hh_del->hh_prev->hh_next = hh_del->hh_next; \
+ } \
+ if (hh_del->hh_next) { \
+ hh_del->hh_next->hh_prev = hh_del->hh_prev; \
+ }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ * ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl) \
+do { \
+ unsigned _he_bkt; \
+ unsigned _he_bkt_i; \
+ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
+ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
+ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
+ memset(_he_new_buckets, 0, \
+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ tbl->ideal_chain_maxlen = \
+ (tbl->num_items >> (tbl->log2_num_buckets+1)) + \
+ ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
+ tbl->nonideal_items = 0; \
+ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
+ { \
+ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
+ while (_he_thh) { \
+ _he_hh_nxt = _he_thh->hh_next; \
+ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
+ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
+ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
+ tbl->nonideal_items++; \
+ _he_newbkt->expand_mult = _he_newbkt->count / \
+ tbl->ideal_chain_maxlen; \
+ } \
+ _he_thh->hh_prev = NULL; \
+ _he_thh->hh_next = _he_newbkt->hh_head; \
+ if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
+ _he_thh; \
+ _he_newbkt->hh_head = _he_thh; \
+ _he_thh = _he_hh_nxt; \
+ } \
+ } \
+ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ tbl->num_buckets *= 2; \
+ tbl->log2_num_buckets++; \
+ tbl->buckets = _he_new_buckets; \
+ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
+ (tbl->ineff_expands+1) : 0; \
+ if (tbl->ineff_expands > 1) { \
+ tbl->noexpand=1; \
+ uthash_noexpand_fyi(tbl); \
+ } \
+ uthash_expand_fyi(tbl); \
+} while(0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn) \
+do { \
+ unsigned _hs_i; \
+ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
+ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
+ if (head) { \
+ _hs_insize = 1; \
+ _hs_looping = 1; \
+ _hs_list = &((head)->hh); \
+ while (_hs_looping) { \
+ _hs_p = _hs_list; \
+ _hs_list = NULL; \
+ _hs_tail = NULL; \
+ _hs_nmerges = 0; \
+ while (_hs_p) { \
+ _hs_nmerges++; \
+ _hs_q = _hs_p; \
+ _hs_psize = 0; \
+ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
+ _hs_psize++; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ if (! (_hs_q) ) break; \
+ } \
+ _hs_qsize = _hs_insize; \
+ while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
+ if (_hs_psize == 0) { \
+ _hs_e = _hs_q; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_qsize--; \
+ } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
+ _hs_e = _hs_p; \
+ if (_hs_p){ \
+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \
+ ((void*)((char*)(_hs_p->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ } \
+ _hs_psize--; \
+ } else if (( \
+ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+ ) <= 0) { \
+ _hs_e = _hs_p; \
+ if (_hs_p){ \
+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \
+ ((void*)((char*)(_hs_p->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ } \
+ _hs_psize--; \
+ } else { \
+ _hs_e = _hs_q; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_qsize--; \
+ } \
+ if ( _hs_tail ) { \
+ _hs_tail->next = ((_hs_e) ? \
+ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
+ } else { \
+ _hs_list = _hs_e; \
+ } \
+ if (_hs_e) { \
+ _hs_e->prev = ((_hs_tail) ? \
+ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
+ } \
+ _hs_tail = _hs_e; \
+ } \
+ _hs_p = _hs_q; \
+ } \
+ if (_hs_tail){ \
+ _hs_tail->next = NULL; \
+ } \
+ if ( _hs_nmerges <= 1 ) { \
+ _hs_looping=0; \
+ (head)->hh.tbl->tail = _hs_tail; \
+ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
+ } \
+ _hs_insize *= 2; \
+ } \
+ HASH_FSCK(hh,head); \
+ } \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
+do { \
+ unsigned _src_bkt, _dst_bkt; \
+ void *_last_elt=NULL, *_elt; \
+ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
+ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
+ if (src) { \
+ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
+ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
+ _src_hh; \
+ _src_hh = _src_hh->hh_next) { \
+ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
+ if (cond(_elt)) { \
+ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
+ _dst_hh->key = _src_hh->key; \
+ _dst_hh->keylen = _src_hh->keylen; \
+ _dst_hh->hashv = _src_hh->hashv; \
+ _dst_hh->prev = _last_elt; \
+ _dst_hh->next = NULL; \
+ if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
+ if (!dst) { \
+ DECLTYPE_ASSIGN(dst,_elt); \
+ HASH_MAKE_TABLE(hh_dst,dst); \
+ } else { \
+ _dst_hh->tbl = (dst)->hh_dst.tbl; \
+ } \
+ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
+ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
+ (dst)->hh_dst.tbl->num_items++; \
+ _last_elt = _elt; \
+ _last_elt_hh = _dst_hh; \
+ } \
+ } \
+ } \
+ } \
+ HASH_FSCK(hh_dst,dst); \
+} while (0)
+
+#define HASH_CLEAR(hh,head) \
+do { \
+ if (head) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head)=NULL; \
+ } \
+} while(0)
+
+#define HASH_OVERHEAD(hh,head) \
+ (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
+ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
+ (sizeof(UT_hash_table)) + \
+ (HASH_BLOOM_BYTELEN)))
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp) \
+for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
+ el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
+#else
+#define HASH_ITER(hh,head,el,tmp) \
+for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
+ el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+
+typedef struct UT_hash_bucket {
+ struct UT_hash_handle *hh_head;
+ unsigned count;
+
+ /* expand_mult is normally set to 0. In this situation, the max chain length
+ * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+ * the bucket's chain exceeds this length, bucket expansion is triggered).
+ * However, setting expand_mult to a non-zero value delays bucket expansion
+ * (that would be triggered by additions to this particular bucket)
+ * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+ * (The multiplier is simply expand_mult+1). The whole idea of this
+ * multiplier is to reduce bucket expansions, since they are expensive, in
+ * situations where we know that a particular bucket tends to be overused.
+ * It is better to let its chain length grow to a longer yet-still-bounded
+ * value, than to do an O(n) bucket expansion too often.
+ */
+ unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1
+#define HASH_BLOOM_SIGNATURE 0xb12220f2
+
+typedef struct UT_hash_table {
+ UT_hash_bucket *buckets;
+ unsigned num_buckets, log2_num_buckets;
+ unsigned num_items;
+ struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
+ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+ /* in an ideal situation (all buckets used equally), no bucket would have
+ * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+ unsigned ideal_chain_maxlen;
+
+ /* nonideal_items is the number of items in the hash whose chain position
+ * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+ * hash distribution; reaching them in a chain traversal takes >ideal steps */
+ unsigned nonideal_items;
+
+ /* ineffective expands occur when a bucket doubling was performed, but
+ * afterward, more than half the items in the hash had nonideal chain
+ * positions. If this happens on two consecutive expansions we inhibit any
+ * further expansion, as it's not helping; this happens when the hash
+ * function isn't a good fit for the key domain. When expansion is inhibited
+ * the hash will still work, albeit no longer in constant time. */
+ unsigned ineff_expands, noexpand;
+
+ uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+ uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+ uint8_t *bloom_bv;
+ char bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+ struct UT_hash_table *tbl;
+ void *prev; /* prev element in app order */
+ void *next; /* next element in app order */
+ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
+ struct UT_hash_handle *hh_next; /* next hh in bucket order */
+ void *key; /* ptr to enclosing struct's key */
+ unsigned keylen; /* enclosing struct's key len */
+ unsigned hashv; /* result of hash-fcn(key) */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/libs/libmosquitto/include/utlist.h b/libs/libmosquitto/include/utlist.h
new file mode 100644
index 0000000000..5bb1ac9b72
--- /dev/null
+++ b/libs/libmosquitto/include/utlist.h
@@ -0,0 +1,1073 @@
+/*
+Copyright (c) 2007-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTLIST_H
+#define UTLIST_H
+
+#define UTLIST_VERSION 2.1.0
+
+#include <assert.h>
+
+/*
+ * This file contains macros to manipulate singly and doubly-linked lists.
+ *
+ * 1. LL_ macros: singly-linked lists.
+ * 2. DL_ macros: doubly-linked lists.
+ * 3. CDL_ macros: circular doubly-linked lists.
+ *
+ * To use singly-linked lists, your structure must have a "next" pointer.
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+ * Either way, the pointer to the head of the list must be initialized to NULL.
+ *
+ * ----------------.EXAMPLE -------------------------
+ * struct item {
+ * int id;
+ * struct item *prev, *next;
+ * }
+ *
+ * struct item *list = NULL:
+ *
+ * int main() {
+ * struct item *item;
+ * ... allocate and populate item ...
+ * DL_APPEND(list, item);
+ * }
+ * --------------------------------------------------
+ *
+ * For doubly-linked lists, the append and delete macros are O(1)
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+ */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE)
+#if defined(_MSC_VER) /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define LDECLTYPE(x) decltype(x)
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#endif
+#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#else /* GNU, Sun and other compilers */
+#define LDECLTYPE(x) __typeof(x)
+#endif
+#endif
+
+/* for VS2008 we use some workarounds to get around the lack of decltype,
+ * namely, we always reassign our tmp variable to the list head if we need
+ * to dereference its prev/next pointers, and save/restore the real head.*/
+#ifdef NO_DECLTYPE
+#define IF_NO_DECLTYPE(x) x
+#define LDECLTYPE(x) char*
+#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next))
+#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */
+#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+#else
+#define IF_NO_DECLTYPE(x)
+#define UTLIST_SV(elt,list)
+#define UTLIST_NEXT(elt,list,next) ((elt)->next)
+#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
+/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */
+#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
+#define UTLIST_RS(list)
+#define UTLIST_CASTASGN(a,b) (a)=(b)
+#endif
+
+/******************************************************************************
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
+ * Unwieldy variable names used here to avoid shadowing passed-in variables. *
+ *****************************************************************************/
+#define LL_SORT(list, cmp) \
+ LL_SORT2(list, cmp, next)
+
+#define LL_SORT2(list, cmp, next) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ UTLIST_CASTASGN(_ls_p,list); \
+ (list) = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \
+ } else { \
+ UTLIST_CASTASGN(list,_ls_e); \
+ } \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \
+ } \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } \
+} while (0)
+
+
+#define DL_SORT(list, cmp) \
+ DL_SORT2(list, cmp, prev, next)
+
+#define DL_SORT2(list, cmp, prev, next) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ UTLIST_CASTASGN(_ls_p,list); \
+ (list) = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } else if ((_ls_qsize == 0) || (!_ls_q)) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \
+ } else { \
+ UTLIST_CASTASGN(list,_ls_e); \
+ } \
+ UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ UTLIST_CASTASGN((list)->prev, _ls_tail); \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } \
+} while (0)
+
+#define CDL_SORT(list, cmp) \
+ CDL_SORT2(list, cmp, prev, next)
+
+#define CDL_SORT2(list, cmp, prev, next) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ LDECLTYPE(list) _ls_oldhead; \
+ LDECLTYPE(list) _tmp; \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ UTLIST_CASTASGN(_ls_p,list); \
+ UTLIST_CASTASGN(_ls_oldhead,list); \
+ (list) = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ UTLIST_SV(_ls_q,list); \
+ if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \
+ _ls_q = NULL; \
+ } else { \
+ _ls_q = UTLIST_NEXT(_ls_q,list,next); \
+ } \
+ UTLIST_RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
+ } else { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \
+ } else { \
+ UTLIST_CASTASGN(list,_ls_e); \
+ } \
+ UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ UTLIST_CASTASGN((list)->prev,_ls_tail); \
+ UTLIST_CASTASGN(_tmp,list); \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } \
+} while (0)
+
+/******************************************************************************
+ * singly linked list macros (non-circular) *
+ *****************************************************************************/
+#define LL_PREPEND(head,add) \
+ LL_PREPEND2(head,add,next)
+
+#define LL_PREPEND2(head,add,next) \
+do { \
+ (add)->next = (head); \
+ (head) = (add); \
+} while (0)
+
+#define LL_CONCAT(head1,head2) \
+ LL_CONCAT2(head1,head2,next)
+
+#define LL_CONCAT2(head1,head2,next) \
+do { \
+ LDECLTYPE(head1) _tmp; \
+ if (head1) { \
+ _tmp = (head1); \
+ while (_tmp->next) { _tmp = _tmp->next; } \
+ _tmp->next=(head2); \
+ } else { \
+ (head1)=(head2); \
+ } \
+} while (0)
+
+#define LL_APPEND(head,add) \
+ LL_APPEND2(head,add,next)
+
+#define LL_APPEND2(head,add,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ (add)->next=NULL; \
+ if (head) { \
+ _tmp = (head); \
+ while (_tmp->next) { _tmp = _tmp->next; } \
+ _tmp->next=(add); \
+ } else { \
+ (head)=(add); \
+ } \
+} while (0)
+
+#define LL_INSERT_INORDER(head,add,cmp) \
+ LL_INSERT_INORDER2(head,add,cmp,next)
+
+#define LL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if (head) { \
+ LL_LOWER_BOUND2(head, _tmp, add, cmp, next); \
+ LL_APPEND_ELEM2(head, _tmp, add, next); \
+ } else { \
+ (head) = (add); \
+ (head)->next = NULL; \
+ } \
+} while (0)
+
+#define LL_LOWER_BOUND(head,elt,like,cmp) \
+ LL_LOWER_BOUND2(head,elt,like,cmp,next)
+
+#define LL_LOWER_BOUND2(head,elt,like,cmp,next) \
+ do { \
+ if ((head) == NULL || (cmp(head, like)) >= 0) { \
+ (elt) = NULL; \
+ } else { \
+ for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \
+ if (cmp((elt)->next, like) >= 0) { \
+ break; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define LL_DELETE(head,del) \
+ LL_DELETE2(head,del,next)
+
+#define LL_DELETE2(head,del,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if ((head) == (del)) { \
+ (head)=(head)->next; \
+ } else { \
+ _tmp = (head); \
+ while (_tmp->next && (_tmp->next != (del))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = (del)->next; \
+ } \
+ } \
+} while (0)
+
+#define LL_COUNT(head,el,counter) \
+ LL_COUNT2(head,el,counter,next) \
+
+#define LL_COUNT2(head,el,counter,next) \
+do { \
+ (counter) = 0; \
+ LL_FOREACH2(head,el,next) { ++(counter); } \
+} while (0)
+
+#define LL_FOREACH(head,el) \
+ LL_FOREACH2(head,el,next)
+
+#define LL_FOREACH2(head,el,next) \
+ for ((el) = (head); el; (el) = (el)->next)
+
+#define LL_FOREACH_SAFE(head,el,tmp) \
+ LL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define LL_FOREACH_SAFE2(head,el,tmp,next) \
+ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
+
+#define LL_SEARCH_SCALAR(head,out,field,val) \
+ LL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define LL_SEARCH_SCALAR2(head,out,field,val,next) \
+do { \
+ LL_FOREACH2(head,out,next) { \
+ if ((out)->field == (val)) break; \
+ } \
+} while (0)
+
+#define LL_SEARCH(head,out,elt,cmp) \
+ LL_SEARCH2(head,out,elt,cmp,next)
+
+#define LL_SEARCH2(head,out,elt,cmp,next) \
+do { \
+ LL_FOREACH2(head,out,next) { \
+ if ((cmp(out,elt))==0) break; \
+ } \
+} while (0)
+
+#define LL_REPLACE_ELEM2(head, el, add, next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ _tmp = (head); \
+ while (_tmp->next && (_tmp->next != (el))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = (add); \
+ } \
+ } \
+} while (0)
+
+#define LL_REPLACE_ELEM(head, el, add) \
+ LL_REPLACE_ELEM2(head, el, add, next)
+
+#define LL_PREPEND_ELEM2(head, el, add, next) \
+do { \
+ if (el) { \
+ LDECLTYPE(head) _tmp; \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ _tmp = (head); \
+ while (_tmp->next && (_tmp->next != (el))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = (add); \
+ } \
+ } \
+ } else { \
+ LL_APPEND2(head, add, next); \
+ } \
+} while (0) \
+
+#define LL_PREPEND_ELEM(head, el, add) \
+ LL_PREPEND_ELEM2(head, el, add, next)
+
+#define LL_APPEND_ELEM2(head, el, add, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ (el)->next = (add); \
+ } else { \
+ LL_PREPEND2(head, add, next); \
+ } \
+} while (0) \
+
+#define LL_APPEND_ELEM(head, el, add) \
+ LL_APPEND_ELEM2(head, el, add, next)
+
+#ifdef NO_DECLTYPE
+/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
+
+#undef LL_CONCAT2
+#define LL_CONCAT2(head1,head2,next) \
+do { \
+ char *_tmp; \
+ if (head1) { \
+ _tmp = (char*)(head1); \
+ while ((head1)->next) { (head1) = (head1)->next; } \
+ (head1)->next = (head2); \
+ UTLIST_RS(head1); \
+ } else { \
+ (head1)=(head2); \
+ } \
+} while (0)
+
+#undef LL_APPEND2
+#define LL_APPEND2(head,add,next) \
+do { \
+ if (head) { \
+ (add)->next = head; /* use add->next as a temp variable */ \
+ while ((add)->next->next) { (add)->next = (add)->next->next; } \
+ (add)->next->next=(add); \
+ } else { \
+ (head)=(add); \
+ } \
+ (add)->next=NULL; \
+} while (0)
+
+#undef LL_INSERT_INORDER2
+#define LL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ if ((head) == NULL || (cmp(head, add)) >= 0) { \
+ (add)->next = (head); \
+ (head) = (add); \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \
+ (head) = (head)->next; \
+ } \
+ (add)->next = (head)->next; \
+ (head)->next = (add); \
+ UTLIST_RS(head); \
+ } \
+} while (0)
+
+#undef LL_DELETE2
+#define LL_DELETE2(head,del,next) \
+do { \
+ if ((head) == (del)) { \
+ (head)=(head)->next; \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((head)->next && ((head)->next != (del))) { \
+ (head) = (head)->next; \
+ } \
+ if ((head)->next) { \
+ (head)->next = ((del)->next); \
+ } \
+ UTLIST_RS(head); \
+ } \
+} while (0)
+
+#undef LL_REPLACE_ELEM2
+#define LL_REPLACE_ELEM2(head, el, add, next) \
+do { \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ (add)->next = head; \
+ while ((add)->next->next && ((add)->next->next != (el))) { \
+ (add)->next = (add)->next->next; \
+ } \
+ if ((add)->next->next) { \
+ (add)->next->next = (add); \
+ } \
+ } \
+ (add)->next = (el)->next; \
+} while (0)
+
+#undef LL_PREPEND_ELEM2
+#define LL_PREPEND_ELEM2(head, el, add, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ (add)->next = (head); \
+ while ((add)->next->next && ((add)->next->next != (el))) { \
+ (add)->next = (add)->next->next; \
+ } \
+ if ((add)->next->next) { \
+ (add)->next->next = (add); \
+ } \
+ } \
+ (add)->next = (el); \
+ } else { \
+ LL_APPEND2(head, add, next); \
+ } \
+} while (0) \
+
+#endif /* NO_DECLTYPE */
+
+/******************************************************************************
+ * doubly linked list macros (non-circular) *
+ *****************************************************************************/
+#define DL_PREPEND(head,add) \
+ DL_PREPEND2(head,add,prev,next)
+
+#define DL_PREPEND2(head,add,prev,next) \
+do { \
+ (add)->next = (head); \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (head)->prev = (add); \
+ } else { \
+ (add)->prev = (add); \
+ } \
+ (head) = (add); \
+} while (0)
+
+#define DL_APPEND(head,add) \
+ DL_APPEND2(head,add,prev,next)
+
+#define DL_APPEND2(head,add,prev,next) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (head)->prev->next = (add); \
+ (head)->prev = (add); \
+ (add)->next = NULL; \
+ } else { \
+ (head)=(add); \
+ (head)->prev = (head); \
+ (head)->next = NULL; \
+ } \
+} while (0)
+
+#define DL_INSERT_INORDER(head,add,cmp) \
+ DL_INSERT_INORDER2(head,add,cmp,prev,next)
+
+#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if (head) { \
+ DL_LOWER_BOUND2(head, _tmp, add, cmp, next); \
+ DL_APPEND_ELEM2(head, _tmp, add, prev, next); \
+ } else { \
+ (head) = (add); \
+ (head)->prev = (head); \
+ (head)->next = NULL; \
+ } \
+} while (0)
+
+#define DL_LOWER_BOUND(head,elt,like,cmp) \
+ DL_LOWER_BOUND2(head,elt,like,cmp,next)
+
+#define DL_LOWER_BOUND2(head,elt,like,cmp,next) \
+do { \
+ if ((head) == NULL || (cmp(head, like)) >= 0) { \
+ (elt) = NULL; \
+ } else { \
+ for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \
+ if ((cmp((elt)->next, like)) >= 0) { \
+ break; \
+ } \
+ } \
+ } \
+} while (0)
+
+#define DL_CONCAT(head1,head2) \
+ DL_CONCAT2(head1,head2,prev,next)
+
+#define DL_CONCAT2(head1,head2,prev,next) \
+do { \
+ LDECLTYPE(head1) _tmp; \
+ if (head2) { \
+ if (head1) { \
+ UTLIST_CASTASGN(_tmp, (head2)->prev); \
+ (head2)->prev = (head1)->prev; \
+ (head1)->prev->next = (head2); \
+ UTLIST_CASTASGN((head1)->prev, _tmp); \
+ } else { \
+ (head1)=(head2); \
+ } \
+ } \
+} while (0)
+
+#define DL_DELETE(head,del) \
+ DL_DELETE2(head,del,prev,next)
+
+#define DL_DELETE2(head,del,prev,next) \
+do { \
+ assert((head) != NULL); \
+ assert((del)->prev != NULL); \
+ if ((del)->prev == (del)) { \
+ (head)=NULL; \
+ } else if ((del)==(head)) { \
+ (del)->next->prev = (del)->prev; \
+ (head) = (del)->next; \
+ } else { \
+ (del)->prev->next = (del)->next; \
+ if ((del)->next) { \
+ (del)->next->prev = (del)->prev; \
+ } else { \
+ (head)->prev = (del)->prev; \
+ } \
+ } \
+} while (0)
+
+#define DL_COUNT(head,el,counter) \
+ DL_COUNT2(head,el,counter,next) \
+
+#define DL_COUNT2(head,el,counter,next) \
+do { \
+ (counter) = 0; \
+ DL_FOREACH2(head,el,next) { ++(counter); } \
+} while (0)
+
+#define DL_FOREACH(head,el) \
+ DL_FOREACH2(head,el,next)
+
+#define DL_FOREACH2(head,el,next) \
+ for ((el) = (head); el; (el) = (el)->next)
+
+/* this version is safe for deleting the elements during iteration */
+#define DL_FOREACH_SAFE(head,el,tmp) \
+ DL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define DL_FOREACH_SAFE2(head,el,tmp,next) \
+ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
+
+/* these are identical to their singly-linked list counterparts */
+#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+#define DL_SEARCH LL_SEARCH
+#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
+#define DL_SEARCH2 LL_SEARCH2
+
+#define DL_REPLACE_ELEM2(head, el, add, prev, next) \
+do { \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ (add)->next = (el)->next; \
+ if ((el)->next == NULL) { \
+ (add)->prev = (add); \
+ } else { \
+ (add)->prev = (el)->prev; \
+ (add)->next->prev = (add); \
+ } \
+ } else { \
+ (add)->next = (el)->next; \
+ (add)->prev = (el)->prev; \
+ (add)->prev->next = (add); \
+ if ((el)->next == NULL) { \
+ (head)->prev = (add); \
+ } else { \
+ (add)->next->prev = (add); \
+ } \
+ } \
+} while (0)
+
+#define DL_REPLACE_ELEM(head, el, add) \
+ DL_REPLACE_ELEM2(head, el, add, prev, next)
+
+#define DL_PREPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el); \
+ (add)->prev = (el)->prev; \
+ (el)->prev = (add); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ (add)->prev->next = (add); \
+ } \
+ } else { \
+ DL_APPEND2(head, add, prev, next); \
+ } \
+} while (0) \
+
+#define DL_PREPEND_ELEM(head, el, add) \
+ DL_PREPEND_ELEM2(head, el, add, prev, next)
+
+#define DL_APPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ (add)->prev = (el); \
+ (el)->next = (add); \
+ if ((add)->next) { \
+ (add)->next->prev = (add); \
+ } else { \
+ (head)->prev = (add); \
+ } \
+ } else { \
+ DL_PREPEND2(head, add, prev, next); \
+ } \
+} while (0) \
+
+#define DL_APPEND_ELEM(head, el, add) \
+ DL_APPEND_ELEM2(head, el, add, prev, next)
+
+#ifdef NO_DECLTYPE
+/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
+
+#undef DL_INSERT_INORDER2
+#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \
+do { \
+ if ((head) == NULL) { \
+ (add)->prev = (add); \
+ (add)->next = NULL; \
+ (head) = (add); \
+ } else if ((cmp(head, add)) >= 0) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (head) = (add); \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((head)->next && (cmp((head)->next, add)) < 0) { \
+ (head) = (head)->next; \
+ } \
+ (add)->prev = (head); \
+ (add)->next = (head)->next; \
+ (head)->next = (add); \
+ UTLIST_RS(head); \
+ if ((add)->next) { \
+ (add)->next->prev = (add); \
+ } else { \
+ (head)->prev = (add); \
+ } \
+ } \
+} while (0)
+#endif /* NO_DECLTYPE */
+
+/******************************************************************************
+ * circular doubly linked list macros *
+ *****************************************************************************/
+#define CDL_APPEND(head,add) \
+ CDL_APPEND2(head,add,prev,next)
+
+#define CDL_APPEND2(head,add,prev,next) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (add)->prev->next = (add); \
+ } else { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ (head) = (add); \
+ } \
+} while (0)
+
+#define CDL_PREPEND(head,add) \
+ CDL_PREPEND2(head,add,prev,next)
+
+#define CDL_PREPEND2(head,add,prev,next) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (add)->prev->next = (add); \
+ } else { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ } \
+ (head) = (add); \
+} while (0)
+
+#define CDL_INSERT_INORDER(head,add,cmp) \
+ CDL_INSERT_INORDER2(head,add,cmp,prev,next)
+
+#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if (head) { \
+ CDL_LOWER_BOUND2(head, _tmp, add, cmp, next); \
+ CDL_APPEND_ELEM2(head, _tmp, add, prev, next); \
+ } else { \
+ (head) = (add); \
+ (head)->next = (head); \
+ (head)->prev = (head); \
+ } \
+} while (0)
+
+#define CDL_LOWER_BOUND(head,elt,like,cmp) \
+ CDL_LOWER_BOUND2(head,elt,like,cmp,next)
+
+#define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \
+do { \
+ if ((head) == NULL || (cmp(head, like)) >= 0) { \
+ (elt) = NULL; \
+ } else { \
+ for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \
+ if ((cmp((elt)->next, like)) >= 0) { \
+ break; \
+ } \
+ } \
+ } \
+} while (0)
+
+#define CDL_DELETE(head,del) \
+ CDL_DELETE2(head,del,prev,next)
+
+#define CDL_DELETE2(head,del,prev,next) \
+do { \
+ if (((head)==(del)) && ((head)->next == (head))) { \
+ (head) = NULL; \
+ } else { \
+ (del)->next->prev = (del)->prev; \
+ (del)->prev->next = (del)->next; \
+ if ((del) == (head)) (head)=(del)->next; \
+ } \
+} while (0)
+
+#define CDL_COUNT(head,el,counter) \
+ CDL_COUNT2(head,el,counter,next) \
+
+#define CDL_COUNT2(head, el, counter,next) \
+do { \
+ (counter) = 0; \
+ CDL_FOREACH2(head,el,next) { ++(counter); } \
+} while (0)
+
+#define CDL_FOREACH(head,el) \
+ CDL_FOREACH2(head,el,next)
+
+#define CDL_FOREACH2(head,el,next) \
+ for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next))
+
+#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
+ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
+
+#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \
+ for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \
+ (el) && ((tmp2) = (el)->next, 1); \
+ (el) = ((el) == (tmp1) ? NULL : (tmp2)))
+
+#define CDL_SEARCH_SCALAR(head,out,field,val) \
+ CDL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \
+do { \
+ CDL_FOREACH2(head,out,next) { \
+ if ((out)->field == (val)) break; \
+ } \
+} while (0)
+
+#define CDL_SEARCH(head,out,elt,cmp) \
+ CDL_SEARCH2(head,out,elt,cmp,next)
+
+#define CDL_SEARCH2(head,out,elt,cmp,next) \
+do { \
+ CDL_FOREACH2(head,out,next) { \
+ if ((cmp(out,elt))==0) break; \
+ } \
+} while (0)
+
+#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \
+do { \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ if ((el)->next == (el)) { \
+ (add)->next = (add); \
+ (add)->prev = (add); \
+ (head) = (add); \
+ } else { \
+ (add)->next = (el)->next; \
+ (add)->prev = (el)->prev; \
+ (add)->next->prev = (add); \
+ (add)->prev->next = (add); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } \
+ } \
+} while (0)
+
+#define CDL_REPLACE_ELEM(head, el, add) \
+ CDL_REPLACE_ELEM2(head, el, add, prev, next)
+
+#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el); \
+ (add)->prev = (el)->prev; \
+ (el)->prev = (add); \
+ (add)->prev->next = (add); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } \
+ } else { \
+ CDL_APPEND2(head, add, prev, next); \
+ } \
+} while (0)
+
+#define CDL_PREPEND_ELEM(head, el, add) \
+ CDL_PREPEND_ELEM2(head, el, add, prev, next)
+
+#define CDL_APPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ (add)->prev = (el); \
+ (el)->next = (add); \
+ (add)->next->prev = (add); \
+ } else { \
+ CDL_PREPEND2(head, add, prev, next); \
+ } \
+} while (0)
+
+#define CDL_APPEND_ELEM(head, el, add) \
+ CDL_APPEND_ELEM2(head, el, add, prev, next)
+
+#ifdef NO_DECLTYPE
+/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
+
+#undef CDL_INSERT_INORDER2
+#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \
+do { \
+ if ((head) == NULL) { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ (head) = (add); \
+ } else if ((cmp(head, add)) >= 0) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (add)->prev->next = (add); \
+ (head)->prev = (add); \
+ (head) = (add); \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \
+ (head) = (head)->next; \
+ } \
+ (add)->prev = (head); \
+ (add)->next = (head)->next; \
+ (add)->next->prev = (add); \
+ (head)->next = (add); \
+ UTLIST_RS(head); \
+ } \
+} while (0)
+#endif /* NO_DECLTYPE */
+
+#endif /* UTLIST_H */
diff --git a/libs/libmosquitto/libmosquitto.vcxproj b/libs/libmosquitto/libmosquitto.vcxproj
new file mode 100644
index 0000000000..a9154fd38c
--- /dev/null
+++ b/libs/libmosquitto/libmosquitto.vcxproj
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{6D19209B-ECE7-4B9C-941C-1AA2B484F199}</ProjectGuid>
+ <ProjectName>libmosquitto</ProjectName>
+ <TargetName>libmosquitto</TargetName>
+ </PropertyGroup>
+ <Import Project="$(ProjectDir)..\..\build\vc.common\lib.props" />
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\include\;.\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>libmosquitto_EXPORTS;WIN32;WITH_TLS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>libeay32.lib;ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+</Project> \ No newline at end of file
diff --git a/libs/libmosquitto/libmosquitto.vcxproj.filters b/libs/libmosquitto/libmosquitto.vcxproj.filters
new file mode 100644
index 0000000000..8f90aeb3d5
--- /dev/null
+++ b/libs/libmosquitto/libmosquitto.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project>
diff --git a/libs/libmosquitto/src/actions.c b/libs/libmosquitto/src/actions.c
new file mode 100644
index 0000000000..a5bf673fa9
--- /dev/null
+++ b/libs/libmosquitto/src/actions.c
@@ -0,0 +1,260 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <string.h>
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+
+int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
+{
+ return mosquitto_publish_v5(mosq, mid, topic, payloadlen, payload, qos, retain, NULL);
+}
+
+int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain, const mosquitto_property *properties)
+{
+ struct mosquitto_message_all *message;
+ uint16_t local_mid;
+ const mosquitto_property *p;
+ const mosquitto_property *outgoing_properties = NULL;
+ mosquitto_property local_property;
+ bool have_topic_alias;
+ int rc;
+ int tlen = 0;
+ uint32_t remaining_length;
+
+ if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL;
+ if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
+ if(qos > mosq->maximum_qos) return MOSQ_ERR_QOS_NOT_SUPPORTED;
+
+ if(properties){
+ if(properties->client_generated){
+ outgoing_properties = properties;
+ }else{
+ memcpy(&local_property, properties, sizeof(mosquitto_property));
+ local_property.client_generated = true;
+ local_property.next = NULL;
+ outgoing_properties = &local_property;
+ }
+ rc = mosquitto_property_check_all(CMD_PUBLISH, outgoing_properties);
+ if(rc) return rc;
+ }
+
+ if(!topic || STREMPTY(topic)){
+ if(topic) topic = NULL;
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ p = outgoing_properties;
+ have_topic_alias = false;
+ while(p){
+ if(p->identifier == MQTT_PROP_TOPIC_ALIAS){
+ have_topic_alias = true;
+ break;
+ }
+ p = p->next;
+ }
+ if(have_topic_alias == false){
+ return MOSQ_ERR_INVAL;
+ }
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+ }else{
+ tlen = strlen(topic);
+ if(mosquitto_validate_utf8(topic, tlen)) return MOSQ_ERR_MALFORMED_UTF8;
+ if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE;
+ if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+
+ if(mosq->maximum_packet_size > 0){
+ remaining_length = 1 + 2+tlen + payloadlen + property__get_length_all(outgoing_properties);
+ if(qos > 0){
+ remaining_length++;
+ }
+ if(packet__check_oversize(mosq, remaining_length)){
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }
+ }
+
+ local_mid = mosquitto__mid_generate(mosq);
+ if(mid){
+ *mid = local_mid;
+ }
+
+ if(qos == 0){
+ return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL, 0);
+ }else{
+ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all));
+ if(!message) return MOSQ_ERR_NOMEM;
+
+ message->next = NULL;
+ message->timestamp = mosquitto_time();
+ message->msg.mid = local_mid;
+ if(topic){
+ message->msg.topic = mosquitto__strdup(topic);
+ if(!message->msg.topic){
+ message__cleanup(&message);
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+ if(payloadlen){
+ message->msg.payloadlen = payloadlen;
+ message->msg.payload = mosquitto__malloc(payloadlen*sizeof(uint8_t));
+ if(!message->msg.payload){
+ message__cleanup(&message);
+ return MOSQ_ERR_NOMEM;
+ }
+ memcpy(message->msg.payload, payload, payloadlen*sizeof(uint8_t));
+ }else{
+ message->msg.payloadlen = 0;
+ message->msg.payload = NULL;
+ }
+ message->msg.qos = qos;
+ message->msg.retain = retain;
+ message->dup = false;
+
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ message->state = mosq_ms_invalid;
+ message__queue(mosq, message, mosq_md_out);
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ return MOSQ_ERR_SUCCESS;
+ }
+}
+
+
+int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
+{
+ return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, 0, NULL);
+}
+
+
+int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties)
+{
+ return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, options, properties);
+}
+
+
+int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties)
+{
+ const mosquitto_property *outgoing_properties = NULL;
+ mosquitto_property local_property;
+ int i;
+ int rc;
+ uint32_t remaining_length = 0;
+ int slen;
+
+ if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL;
+ if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
+ if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL;
+ if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL;
+ if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+ if(properties){
+ if(properties->client_generated){
+ outgoing_properties = properties;
+ }else{
+ memcpy(&local_property, properties, sizeof(mosquitto_property));
+ local_property.client_generated = true;
+ local_property.next = NULL;
+ outgoing_properties = &local_property;
+ }
+ rc = mosquitto_property_check_all(CMD_SUBSCRIBE, outgoing_properties);
+ if(rc) return rc;
+ }
+
+ for(i=0; i<sub_count; i++){
+ if(mosquitto_sub_topic_check(sub[i])) return MOSQ_ERR_INVAL;
+ slen = strlen(sub[i]);
+ if(mosquitto_validate_utf8(sub[i], slen)) return MOSQ_ERR_MALFORMED_UTF8;
+ remaining_length += 2+slen + 1;
+ }
+
+ if(mosq->maximum_packet_size > 0){
+ remaining_length += 2 + property__get_length_all(outgoing_properties);
+ if(packet__check_oversize(mosq, remaining_length)){
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }
+ }
+
+ return send__subscribe(mosq, mid, sub_count, sub, qos|options, outgoing_properties);
+}
+
+
+int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub)
+{
+ return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, NULL);
+}
+
+int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties)
+{
+ return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, properties);
+}
+
+int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties)
+{
+ const mosquitto_property *outgoing_properties = NULL;
+ mosquitto_property local_property;
+ int rc;
+ int i;
+ uint32_t remaining_length = 0;
+ int slen;
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
+ if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+ if(properties){
+ if(properties->client_generated){
+ outgoing_properties = properties;
+ }else{
+ memcpy(&local_property, properties, sizeof(mosquitto_property));
+ local_property.client_generated = true;
+ local_property.next = NULL;
+ outgoing_properties = &local_property;
+ }
+ rc = mosquitto_property_check_all(CMD_UNSUBSCRIBE, outgoing_properties);
+ if(rc) return rc;
+ }
+
+ for(i=0; i<sub_count; i++){
+ if(mosquitto_sub_topic_check(sub[i])) return MOSQ_ERR_INVAL;
+ slen = strlen(sub[i]);
+ if(mosquitto_validate_utf8(sub[i], slen)) return MOSQ_ERR_MALFORMED_UTF8;
+ remaining_length += 2+slen;
+ }
+
+ if(mosq->maximum_packet_size > 0){
+ remaining_length += 2 + property__get_length_all(outgoing_properties);
+ if(packet__check_oversize(mosq, remaining_length)){
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }
+ }
+
+ return send__unsubscribe(mosq, mid, sub_count, sub, outgoing_properties);
+}
+
diff --git a/libs/libmosquitto/src/callbacks.c b/libs/libmosquitto/src/callbacks.c
new file mode 100644
index 0000000000..17f5161bff
--- /dev/null
+++ b/libs/libmosquitto/src/callbacks.c
@@ -0,0 +1,120 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+
+
+void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_connect = on_connect;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_connect_with_flags = on_connect;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_connect_v5 = on_connect;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_disconnect = on_disconnect;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_disconnect_v5 = on_disconnect;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_publish = on_publish;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *props))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_publish_v5 = on_publish;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_message = on_message;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *props))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_message_v5 = on_message;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_subscribe = on_subscribe;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *props))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_subscribe_v5 = on_subscribe;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_unsubscribe = on_unsubscribe;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *props))
+{
+ pthread_mutex_lock(&mosq->callback_mutex);
+ mosq->on_unsubscribe_v5 = on_unsubscribe;
+ pthread_mutex_unlock(&mosq->callback_mutex);
+}
+
+void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *))
+{
+ pthread_mutex_lock(&mosq->log_callback_mutex);
+ mosq->on_log = on_log;
+ pthread_mutex_unlock(&mosq->log_callback_mutex);
+}
+
diff --git a/libs/libmosquitto/src/connect.c b/libs/libmosquitto/src/connect.c
new file mode 100644
index 0000000000..7543d4af74
--- /dev/null
+++ b/libs/libmosquitto/src/connect.c
@@ -0,0 +1,330 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <string.h>
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "messages_mosq.h"
+#include "memory_mosq.h"
+#include "packet_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "send_mosq.h"
+#include "socks_mosq.h"
+#include "util_mosq.h"
+
+static char alphanum[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties);
+static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address);
+
+
+static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
+{
+ int i;
+ int rc;
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(!host || port <= 0) return MOSQ_ERR_INVAL;
+
+ if(mosq->id == NULL && (mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311)){
+ mosq->id = (char *)mosquitto__calloc(24, sizeof(char));
+ if(!mosq->id){
+ return MOSQ_ERR_NOMEM;
+ }
+ mosq->id[0] = 'm';
+ mosq->id[1] = 'o';
+ mosq->id[2] = 's';
+ mosq->id[3] = 'q';
+ mosq->id[4] = '/';
+
+ rc = util__random_bytes(&mosq->id[5], 18);
+ if(rc) return rc;
+
+ for(i=5; i<23; i++){
+ mosq->id[i] = alphanum[(mosq->id[i]&0x7F)%(sizeof(alphanum)-1)];
+ }
+ }
+
+ mosquitto__free(mosq->host);
+ mosq->host = mosquitto__strdup(host);
+ if(!mosq->host) return MOSQ_ERR_NOMEM;
+ mosq->port = port;
+
+ mosquitto__free(mosq->bind_address);
+ if(bind_address){
+ mosq->bind_address = mosquitto__strdup(bind_address);
+ if(!mosq->bind_address) return MOSQ_ERR_NOMEM;
+ }
+
+ mosq->keepalive = keepalive;
+ mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum;
+ mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum;
+
+ if(mosq->sockpairR != INVALID_SOCKET){
+ COMPAT_CLOSE(mosq->sockpairR);
+ mosq->sockpairR = INVALID_SOCKET;
+ }
+ if(mosq->sockpairW != INVALID_SOCKET){
+ COMPAT_CLOSE(mosq->sockpairW);
+ mosq->sockpairW = INVALID_SOCKET;
+ }
+
+ if(net__socketpair(&mosq->sockpairR, &mosq->sockpairW)){
+ log__printf(mosq, MOSQ_LOG_WARNING,
+ "Warning: Unable to open socket pair, outgoing publish commands may be delayed.");
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive)
+{
+ return mosquitto_connect_bind(mosq, host, port, keepalive, NULL);
+}
+
+
+int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
+{
+ return mosquitto_connect_bind_v5(mosq, host, port, keepalive, bind_address, NULL);
+}
+
+int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties)
+{
+ int rc;
+
+ if(properties){
+ rc = mosquitto_property_check_all(CMD_CONNECT, properties);
+ if(rc) return rc;
+ }
+
+ rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address);
+ if(rc) return rc;
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_new;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ return mosquitto__reconnect(mosq, true, properties);
+}
+
+
+int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive)
+{
+ return mosquitto_connect_bind_async(mosq, host, port, keepalive, NULL);
+}
+
+
+int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
+{
+ int rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address);
+ if(rc) return rc;
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_connect_async;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ return mosquitto__reconnect(mosq, false, NULL);
+}
+
+
+int mosquitto_reconnect_async(struct mosquitto *mosq)
+{
+ return mosquitto__reconnect(mosq, false, NULL);
+}
+
+
+int mosquitto_reconnect(struct mosquitto *mosq)
+{
+ return mosquitto__reconnect(mosq, true, NULL);
+}
+
+
+static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties)
+{
+ const mosquitto_property *outgoing_properties = NULL;
+ mosquitto_property local_property;
+ int rc;
+ struct mosquitto__packet *packet;
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL;
+ if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
+
+ if(properties){
+ if(properties->client_generated){
+ outgoing_properties = properties;
+ }else{
+ memcpy(&local_property, properties, sizeof(mosquitto_property));
+ local_property.client_generated = true;
+ local_property.next = NULL;
+ outgoing_properties = &local_property;
+ }
+ rc = mosquitto_property_check_all(CMD_CONNECT, outgoing_properties);
+ if(rc) return rc;
+ }
+
+ pthread_mutex_lock(&mosq->state_mutex);
+#ifdef WITH_SOCKS
+ if(mosq->socks5_host){
+ mosq->state = mosq_cs_socks5_new;
+ }else
+#endif
+ {
+ mosq->state = mosq_cs_new;
+ }
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->last_msg_in = mosquitto_time();
+ mosq->next_msg_out = mosq->last_msg_in + mosq->keepalive;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+
+ mosq->ping_t = 0;
+
+ packet__cleanup(&mosq->in_packet);
+
+ pthread_mutex_lock(&mosq->current_out_packet_mutex);
+ pthread_mutex_lock(&mosq->out_packet_mutex);
+
+ if(mosq->out_packet && !mosq->current_out_packet){
+ mosq->current_out_packet = mosq->out_packet;
+ mosq->out_packet = mosq->out_packet->next;
+ }
+
+ while(mosq->current_out_packet){
+ packet = mosq->current_out_packet;
+ /* Free data and reset values */
+ mosq->current_out_packet = mosq->out_packet;
+ if(mosq->out_packet){
+ mosq->out_packet = mosq->out_packet->next;
+ }
+
+ packet__cleanup(packet);
+ mosquitto__free(packet);
+ }
+ pthread_mutex_unlock(&mosq->out_packet_mutex);
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+
+ message__reconnect_reset(mosq);
+
+ if(mosq->sock != INVALID_SOCKET){
+ net__socket_close(mosq); //close socket
+ }
+
+#ifdef WITH_SOCKS
+ if(mosq->socks5_host){
+ rc = net__socket_connect(mosq, mosq->socks5_host, mosq->socks5_port, mosq->bind_address, blocking);
+ }else
+#endif
+ {
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_connecting;
+ pthread_mutex_unlock(&mosq->state_mutex);
+ rc = net__socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking);
+ }
+ if(rc>0){
+ return rc;
+ }
+
+#ifdef WITH_SOCKS
+ if(mosq->socks5_host){
+ return socks5__send(mosq);
+ }else
+#endif
+ {
+ return send__connect(mosq, mosq->keepalive, mosq->clean_start, outgoing_properties);
+ }
+}
+
+
+int mosquitto_disconnect(struct mosquitto *mosq)
+{
+ return mosquitto_disconnect_v5(mosq, 0, NULL);
+}
+
+int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties)
+{
+ const mosquitto_property *outgoing_properties = NULL;
+ mosquitto_property local_property;
+ int rc;
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
+
+ if(properties){
+ if(properties->client_generated){
+ outgoing_properties = properties;
+ }else{
+ memcpy(&local_property, properties, sizeof(mosquitto_property));
+ local_property.client_generated = true;
+ local_property.next = NULL;
+ outgoing_properties = &local_property;
+ }
+ rc = mosquitto_property_check_all(CMD_DISCONNECT, outgoing_properties);
+ if(rc) return rc;
+ }
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_disconnecting;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+ return send__disconnect(mosq, reason_code, outgoing_properties);
+}
+
+
+void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties)
+{
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_disconnecting;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ net__socket_close(mosq);
+
+ /* Free data and reset values */
+ pthread_mutex_lock(&mosq->out_packet_mutex);
+ mosq->current_out_packet = mosq->out_packet;
+ if(mosq->out_packet){
+ mosq->out_packet = mosq->out_packet->next;
+ if(!mosq->out_packet){
+ mosq->out_packet_last = NULL;
+ }
+ }
+ pthread_mutex_unlock(&mosq->out_packet_mutex);
+
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_disconnect){
+ mosq->in_callback = true;
+ mosq->on_disconnect(mosq, mosq->userdata, reason_code);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_disconnect_v5){
+ mosq->in_callback = true;
+ mosq->on_disconnect_v5(mosq, mosq->userdata, reason_code, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+}
+
diff --git a/libs/libmosquitto/src/dummypthread.h b/libs/libmosquitto/src/dummypthread.h
new file mode 100644
index 0000000000..4207f3d68c
--- /dev/null
+++ b/libs/libmosquitto/src/dummypthread.h
@@ -0,0 +1,13 @@
+#ifndef DUMMYPTHREAD_H
+#define DUMMYPTHREAD_H
+
+#define pthread_create(A, B, C, D)
+#define pthread_join(A, B)
+#define pthread_cancel(A)
+
+#define pthread_mutex_init(A, B)
+#define pthread_mutex_destroy(A)
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+
+#endif
diff --git a/libs/libmosquitto/src/handle_auth.c b/libs/libmosquitto/src/handle_auth.c
new file mode 100644
index 0000000000..5b84d3de31
--- /dev/null
+++ b/libs/libmosquitto/src/handle_auth.c
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "logging_mosq.h"
+#include "mosquitto_internal.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+
+
+int handle__auth(struct mosquitto *mosq)
+{
+ int rc = 0;
+ uint8_t reason_code;
+ mosquitto_property *properties = NULL;
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received AUTH", mosq->id);
+
+ if(mosq->protocol != mosq_p_mqtt5){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ if(packet__read_byte(&mosq->in_packet, &reason_code)) return 1;
+
+ rc = property__read_all(CMD_AUTH, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
+
+ return MOSQ_ERR_SUCCESS;
+}
diff --git a/libs/libmosquitto/src/handle_connack.c b/libs/libmosquitto/src/handle_connack.c
new file mode 100644
index 0000000000..19b6a66160
--- /dev/null
+++ b/libs/libmosquitto/src/handle_connack.c
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "read_handle.h"
+
+int handle__connack(struct mosquitto *mosq)
+{
+ uint8_t connect_flags;
+ uint8_t reason_code;
+ int rc;
+ mosquitto_property *properties = NULL;
+ char *clientid = NULL;
+
+ assert(mosq);
+ rc = packet__read_byte(&mosq->in_packet, &connect_flags);
+ if(rc) return rc;
+ rc = packet__read_byte(&mosq->in_packet, &reason_code);
+ if(rc) return rc;
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ rc = property__read_all(CMD_CONNACK, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ }
+
+ mosquitto_property_read_string(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, &clientid, false);
+ if(clientid){
+ if(mosq->id){
+ /* We've been sent a client identifier but already have one. This
+ * shouldn't happen. */
+ free(clientid);
+ mosquitto_property_free_all(&properties);
+ return MOSQ_ERR_PROTOCOL;
+ }else{
+ mosq->id = clientid;
+ clientid = NULL;
+ }
+ }
+
+ mosquitto_property_read_byte(properties, MQTT_PROP_MAXIMUM_QOS, &mosq->maximum_qos, false);
+ mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->msgs_out.inflight_maximum, false);
+ mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false);
+ mosquitto_property_read_int32(properties, MQTT_PROP_MAXIMUM_PACKET_SIZE, &mosq->maximum_packet_size, false);
+
+ mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum;
+
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code);
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_connect){
+ mosq->in_callback = true;
+ mosq->on_connect(mosq, mosq->userdata, reason_code);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_connect_with_flags){
+ mosq->in_callback = true;
+ mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_connect_v5){
+ mosq->in_callback = true;
+ mosq->on_connect_v5(mosq, mosq->userdata, reason_code, connect_flags, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ mosquitto_property_free_all(&properties);
+
+ switch(reason_code){
+ case 0:
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state != mosq_cs_disconnecting){
+ mosq->state = mosq_cs_connected;
+ }
+ pthread_mutex_unlock(&mosq->state_mutex);
+ message__retry_check(mosq);
+ return MOSQ_ERR_SUCCESS;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ return MOSQ_ERR_CONN_REFUSED;
+ default:
+ return MOSQ_ERR_PROTOCOL;
+ }
+}
+
diff --git a/libs/libmosquitto/src/handle_disconnect.c b/libs/libmosquitto/src/handle_disconnect.c
new file mode 100644
index 0000000000..0ec1c8b3cb
--- /dev/null
+++ b/libs/libmosquitto/src/handle_disconnect.c
@@ -0,0 +1,62 @@
+/*
+Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "logging_mosq.h"
+#include "mqtt_protocol.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+int handle__disconnect(struct mosquitto *mosq)
+{
+ int rc;
+ uint8_t reason_code;
+ mosquitto_property *properties = NULL;
+
+ if(!mosq){
+ return MOSQ_ERR_INVAL;
+ }
+
+ if(mosq->protocol != mosq_p_mqtt5){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ rc = packet__read_byte(&mosq->in_packet, &reason_code);
+ if(rc) return rc;
+
+ if(mosq->in_packet.remaining_length > 2){
+ rc = property__read_all(CMD_DISCONNECT, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ mosquitto_property_free_all(&properties);
+ }
+
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Received DISCONNECT (%d)", reason_code);
+
+ do_client_disconnect(mosq, reason_code, properties);
+
+ mosquitto_property_free_all(&properties);
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/handle_ping.c b/libs/libmosquitto/src/handle_ping.c
new file mode 100644
index 0000000000..56d89a3c3f
--- /dev/null
+++ b/libs/libmosquitto/src/handle_ping.c
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+int handle__pingreq(struct mosquitto *mosq)
+{
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received PINGREQ from %s", mosq->id);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGREQ", mosq->id);
+#endif
+ return send__pingresp(mosq);
+}
+
+int handle__pingresp(struct mosquitto *mosq)
+{
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ mosq->ping_t = 0; /* No longer waiting for a PINGRESP. */
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received PINGRESP from %s", mosq->id);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGRESP", mosq->id);
+#endif
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/handle_pubackcomp.c b/libs/libmosquitto/src/handle_pubackcomp.c
new file mode 100644
index 0000000000..67921494e2
--- /dev/null
+++ b/libs/libmosquitto/src/handle_pubackcomp.c
@@ -0,0 +1,118 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+
+#ifdef WITH_BROKER
+int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type)
+#else
+int handle__pubackcomp(struct mosquitto *mosq, const char *type)
+#endif
+{
+ uint8_t reason_code = 0;
+ uint16_t mid;
+ int rc;
+ mosquitto_property *properties = NULL;
+ int qos;
+
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ util__increment_send_quota(mosq);
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+
+ rc = packet__read_uint16(&mosq->in_packet, &mid);
+ if(rc) return rc;
+ qos = type[3] == 'A'?1:2; /* pubAck or pubComp */
+ if(mid == 0) return MOSQ_ERR_PROTOCOL;
+
+ if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
+ rc = packet__read_byte(&mosq->in_packet, &reason_code);
+ if(rc) return rc;
+
+ if(mosq->in_packet.remaining_length > 3){
+ rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ }
+ }
+
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d, RC:%d)", type, mosq->id, mid, reason_code);
+
+ /* Immediately free, we don't do anything with Reason String or User Property at the moment */
+ mosquitto_property_free_all(&properties);
+
+ rc = db__message_delete_outgoing(db, mosq, mid, mosq_ms_wait_for_pubcomp, qos);
+ if(rc == MOSQ_ERR_NOT_FOUND){
+ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received %s from %s for an unknown packet identifier %d.", type, mosq->id, mid);
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ return rc;
+ }
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d, RC:%d)", mosq->id, type, mid, reason_code);
+
+ rc = message__delete(mosq, mid, mosq_md_out, qos);
+ if(rc){
+ return rc;
+ }else{
+ /* Only inform the client the message has been sent once. */
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_publish){
+ mosq->in_callback = true;
+ mosq->on_publish(mosq, mosq->userdata, mid);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_publish_v5){
+ mosq->in_callback = true;
+ mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ mosquitto_property_free_all(&properties);
+ }
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ message__release_to_inflight(mosq, mosq_md_out);
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+
+ return MOSQ_ERR_SUCCESS;
+#endif
+}
+
diff --git a/libs/libmosquitto/src/handle_publish.c b/libs/libmosquitto/src/handle_publish.c
new file mode 100644
index 0000000000..8c93e3cefb
--- /dev/null
+++ b/libs/libmosquitto/src/handle_publish.c
@@ -0,0 +1,167 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "messages_mosq.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "util_mosq.h"
+
+
+int handle__publish(struct mosquitto *mosq)
+{
+ uint8_t header;
+ struct mosquitto_message_all *message;
+ int rc = 0;
+ uint16_t mid;
+ int slen;
+ mosquitto_property *properties = NULL;
+
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all));
+ if(!message) return MOSQ_ERR_NOMEM;
+
+ header = mosq->in_packet.command;
+
+ message->dup = (header & 0x08)>>3;
+ message->msg.qos = (header & 0x06)>>1;
+ message->msg.retain = (header & 0x01);
+
+ rc = packet__read_string(&mosq->in_packet, &message->msg.topic, &slen);
+ if(rc){
+ message__cleanup(&message);
+ return rc;
+ }
+ if(!slen){
+ message__cleanup(&message);
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ if(message->msg.qos > 0){
+ if(mosq->protocol == mosq_p_mqtt5){
+ if(mosq->msgs_in.inflight_quota == 0){
+ message__cleanup(&message);
+ /* FIXME - should send a DISCONNECT here */
+ return MOSQ_ERR_PROTOCOL;
+ }
+ }
+
+ rc = packet__read_uint16(&mosq->in_packet, &mid);
+ if(rc){
+ message__cleanup(&message);
+ return rc;
+ }
+ if(mid == 0){
+ message__cleanup(&message);
+ return MOSQ_ERR_PROTOCOL;
+ }
+ message->msg.mid = (int)mid;
+ }
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ rc = property__read_all(CMD_PUBLISH, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ }
+
+ message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos;
+ if(message->msg.payloadlen){
+ message->msg.payload = mosquitto__calloc(message->msg.payloadlen+1, sizeof(uint8_t));
+ if(!message->msg.payload){
+ message__cleanup(&message);
+ mosquitto_property_free_all(&properties);
+ return MOSQ_ERR_NOMEM;
+ }
+ rc = packet__read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen);
+ if(rc){
+ message__cleanup(&message);
+ mosquitto_property_free_all(&properties);
+ return rc;
+ }
+ }
+ log__printf(mosq, MOSQ_LOG_DEBUG,
+ "Client %s received PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))",
+ mosq->id, message->dup, message->msg.qos, message->msg.retain,
+ message->msg.mid, message->msg.topic,
+ (long)message->msg.payloadlen);
+
+ message->timestamp = mosquitto_time();
+ switch(message->msg.qos){
+ case 0:
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_message){
+ mosq->in_callback = true;
+ mosq->on_message(mosq, mosq->userdata, &message->msg);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_message_v5){
+ mosq->in_callback = true;
+ mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ message__cleanup(&message);
+ mosquitto_property_free_all(&properties);
+ return MOSQ_ERR_SUCCESS;
+ case 1:
+ util__decrement_receive_quota(mosq);
+ rc = send__puback(mosq, message->msg.mid, 0);
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_message){
+ mosq->in_callback = true;
+ mosq->on_message(mosq, mosq->userdata, &message->msg);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_message_v5){
+ mosq->in_callback = true;
+ mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ message__cleanup(&message);
+ mosquitto_property_free_all(&properties);
+ return rc;
+ case 2:
+ util__decrement_receive_quota(mosq);
+ rc = send__pubrec(mosq, message->msg.mid, 0);
+ pthread_mutex_lock(&mosq->msgs_in.mutex);
+ message->state = mosq_ms_wait_for_pubrel;
+ message__queue(mosq, message, mosq_md_in);
+ pthread_mutex_unlock(&mosq->msgs_in.mutex);
+ mosquitto_property_free_all(&properties);
+ return rc;
+ default:
+ message__cleanup(&message);
+ mosquitto_property_free_all(&properties);
+ return MOSQ_ERR_PROTOCOL;
+ }
+}
+
diff --git a/libs/libmosquitto/src/handle_pubrec.c b/libs/libmosquitto/src/handle_pubrec.c
new file mode 100644
index 0000000000..81f1b4962a
--- /dev/null
+++ b/libs/libmosquitto/src/handle_pubrec.c
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq)
+{
+ uint8_t reason_code = 0;
+ uint16_t mid;
+ int rc;
+ mosquitto_property *properties = NULL;
+
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ rc = packet__read_uint16(&mosq->in_packet, &mid);
+ if(rc) return rc;
+ if(mid == 0) return MOSQ_ERR_PROTOCOL;
+
+ if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
+ rc = packet__read_byte(&mosq->in_packet, &reason_code);
+ if(rc) return rc;
+
+ if(mosq->in_packet.remaining_length > 3){
+ rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ /* Immediately free, we don't do anything with Reason String or User Property at the moment */
+ mosquitto_property_free_all(&properties);
+ }
+ }
+
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid);
+
+ if(reason_code < 0x80){
+ rc = db__message_update_outgoing(mosq, mid, mosq_ms_wait_for_pubcomp, 2);
+ }else{
+ return db__message_delete_outgoing(db, mosq, mid, mosq_ms_wait_for_pubrec, 2);
+ }
+#else
+ UNUSED(db);
+
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid);
+
+ if(reason_code < 0x80 || mosq->protocol != mosq_p_mqtt5){
+ rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp, 2);
+ }else{
+ if(!message__delete(mosq, mid, mosq_md_out, 2)){
+ /* Only inform the client the message has been sent once. */
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_publish_v5){
+ mosq->in_callback = true;
+ mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ }
+ util__increment_send_quota(mosq);
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ message__release_to_inflight(mosq, mosq_md_out);
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ return MOSQ_ERR_SUCCESS;
+ }
+#endif
+ if(rc == MOSQ_ERR_NOT_FOUND){
+ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREC from %s for an unknown packet identifier %d.", mosq->id, mid);
+ }else if(rc != MOSQ_ERR_SUCCESS){
+ return rc;
+ }
+ rc = send__pubrel(mosq, mid);
+ if(rc) return rc;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/handle_pubrel.c b/libs/libmosquitto/src/handle_pubrel.c
new file mode 100644
index 0000000000..d4a90652d2
--- /dev/null
+++ b/libs/libmosquitto/src/handle_pubrel.c
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+
+int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq)
+{
+ uint8_t reason_code;
+ uint16_t mid;
+#ifndef WITH_BROKER
+ struct mosquitto_message_all *message = NULL;
+#endif
+ int rc;
+ mosquitto_property *properties = NULL;
+
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ if(mosq->protocol != mosq_p_mqtt31){
+ if((mosq->in_packet.command&0x0F) != 0x02){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ }
+ rc = packet__read_uint16(&mosq->in_packet, &mid);
+ if(rc) return rc;
+ if(mid == 0) return MOSQ_ERR_PROTOCOL;
+
+ if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
+ rc = packet__read_byte(&mosq->in_packet, &reason_code);
+ if(rc) return rc;
+
+ if(mosq->in_packet.remaining_length > 3){
+ rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ }
+ }
+
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid);
+
+ /* Immediately free, we don't do anything with Reason String or User Property at the moment */
+ mosquitto_property_free_all(&properties);
+
+ rc = db__message_release_incoming(db, mosq, mid);
+ if(rc == MOSQ_ERR_PROTOCOL){
+ return rc;
+ }else if(rc != MOSQ_ERR_SUCCESS){
+ /* Message not found. Still send a PUBCOMP anyway because this could be
+ * due to a repeated PUBREL after a client has reconnected. */
+ }
+
+ rc = send__pubcomp(mosq, mid);
+ if(rc) return rc;
+#else
+ UNUSED(db);
+
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid);
+
+ rc = send__pubcomp(mosq, mid);
+ if(rc){
+ message__remove(mosq, mid, mosq_md_in, &message, 2);
+ return rc;
+ }
+
+ rc = message__remove(mosq, mid, mosq_md_in, &message, 2);
+ if(rc){
+ return rc;
+ }else{
+ /* Only pass the message on if we have removed it from the queue - this
+ * prevents multiple callbacks for the same message. */
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_message){
+ mosq->in_callback = true;
+ mosq->on_message(mosq, mosq->userdata, &message->msg);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_message_v5){
+ mosq->in_callback = true;
+ mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ mosquitto_property_free_all(&properties);
+ message__cleanup(&message);
+ }
+#endif
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/handle_suback.c b/libs/libmosquitto/src/handle_suback.c
new file mode 100644
index 0000000000..dadebcd79f
--- /dev/null
+++ b/libs/libmosquitto/src/handle_suback.c
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+
+
+int handle__suback(struct mosquitto *mosq)
+{
+ uint16_t mid;
+ uint8_t qos;
+ int *granted_qos;
+ int qos_count;
+ int i = 0;
+ int rc;
+ mosquitto_property *properties = NULL;
+
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK", mosq->id);
+#endif
+ rc = packet__read_uint16(&mosq->in_packet, &mid);
+ if(rc) return rc;
+ if(mid == 0) return MOSQ_ERR_PROTOCOL;
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ rc = property__read_all(CMD_SUBACK, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ }
+
+ qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos;
+ granted_qos = mosquitto__malloc(qos_count*sizeof(int));
+ if(!granted_qos) return MOSQ_ERR_NOMEM;
+ while(mosq->in_packet.pos < mosq->in_packet.remaining_length){
+ rc = packet__read_byte(&mosq->in_packet, &qos);
+ if(rc){
+ mosquitto__free(granted_qos);
+ return rc;
+ }
+ granted_qos[i] = (int)qos;
+ i++;
+ }
+#ifdef WITH_BROKER
+ /* Immediately free, we don't do anything with Reason String or User Property at the moment */
+ mosquitto_property_free_all(&properties);
+#else
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_subscribe){
+ mosq->in_callback = true;
+ mosq->on_subscribe(mosq, mosq->userdata, mid, qos_count, granted_qos);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_subscribe_v5){
+ mosq->in_callback = true;
+ mosq->on_subscribe_v5(mosq, mosq->userdata, mid, qos_count, granted_qos, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ mosquitto_property_free_all(&properties);
+#endif
+ mosquitto__free(granted_qos);
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/handle_unsuback.c b/libs/libmosquitto/src/handle_unsuback.c
new file mode 100644
index 0000000000..3ced0e5280
--- /dev/null
+++ b/libs/libmosquitto/src/handle_unsuback.c
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+
+int handle__unsuback(struct mosquitto *mosq)
+{
+ uint16_t mid;
+ int rc;
+ mosquitto_property *properties = NULL;
+
+ assert(mosq);
+
+ if(mosq->state != mosq_cs_connected){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBACK from %s", mosq->id);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received UNSUBACK", mosq->id);
+#endif
+ rc = packet__read_uint16(&mosq->in_packet, &mid);
+ if(rc) return rc;
+ if(mid == 0) return MOSQ_ERR_PROTOCOL;
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ rc = property__read_all(CMD_UNSUBACK, &mosq->in_packet, &properties);
+ if(rc) return rc;
+ }
+
+#ifdef WITH_BROKER
+ /* Immediately free, we don't do anything with Reason String or User Property at the moment */
+ mosquitto_property_free_all(&properties);
+#else
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_unsubscribe){
+ mosq->in_callback = true;
+ mosq->on_unsubscribe(mosq, mosq->userdata, mid);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_unsubscribe_v5){
+ mosq->in_callback = true;
+ mosq->on_unsubscribe_v5(mosq, mosq->userdata, mid, properties);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ mosquitto_property_free_all(&properties);
+#endif
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/helpers.c b/libs/libmosquitto/src/helpers.c
new file mode 100644
index 0000000000..0f60501edc
--- /dev/null
+++ b/libs/libmosquitto/src/helpers.c
@@ -0,0 +1,227 @@
+/*
+Copyright (c) 2016-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+
+struct userdata__callback {
+ const char *topic;
+ int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *);
+ void *userdata;
+ int qos;
+ int rc;
+};
+
+struct userdata__simple {
+ struct mosquitto_message *messages;
+ int max_msg_count;
+ int message_count;
+ bool want_retained;
+};
+
+
+static void on_connect(struct mosquitto *mosq, void *obj, int rc)
+{
+ struct userdata__callback *userdata = obj;
+
+ UNUSED(rc);
+
+ mosquitto_subscribe(mosq, NULL, userdata->topic, userdata->qos);
+}
+
+
+static void on_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
+{
+ int rc;
+ struct userdata__callback *userdata = obj;
+
+ rc = userdata->callback(mosq, userdata->userdata, message);
+ if(rc){
+ mosquitto_disconnect(mosq);
+ }
+}
+
+static int on_message_simple(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
+{
+ struct userdata__simple *userdata = obj;
+ int rc;
+
+ if(userdata->max_msg_count == 0){
+ return 0;
+ }
+
+ /* Don't process stale retained messages if 'want_retained' was false */
+ if(!userdata->want_retained && message->retain){
+ return 0;
+ }
+
+ userdata->max_msg_count--;
+
+ rc = mosquitto_message_copy(&userdata->messages[userdata->message_count], message);
+ if(rc){
+ return rc;
+ }
+ userdata->message_count++;
+ if(userdata->max_msg_count == 0){
+ mosquitto_disconnect(mosq);
+ }
+ return 0;
+}
+
+
+libmosq_EXPORT int mosquitto_subscribe_simple(
+ struct mosquitto_message **messages,
+ int msg_count,
+ bool want_retained,
+ const char *topic,
+ int qos,
+ const char *host,
+ int port,
+ const char *client_id,
+ int keepalive,
+ bool clean_session,
+ const char *username,
+ const char *password,
+ const struct libmosquitto_will *will,
+ const struct libmosquitto_tls *tls)
+{
+ struct userdata__simple userdata;
+ int rc;
+ int i;
+
+ if(!topic || msg_count < 1 || !messages){
+ return MOSQ_ERR_INVAL;
+ }
+
+ *messages = NULL;
+
+ userdata.messages = calloc(sizeof(struct mosquitto_message), msg_count);
+ if(!userdata.messages){
+ return MOSQ_ERR_NOMEM;
+ }
+ userdata.message_count = 0;
+ userdata.max_msg_count = msg_count;
+ userdata.want_retained = want_retained;
+
+ rc = mosquitto_subscribe_callback(
+ on_message_simple, &userdata,
+ topic, qos,
+ host, port,
+ client_id, keepalive, clean_session,
+ username, password,
+ will, tls);
+
+ if(!rc && userdata.max_msg_count == 0){
+ *messages = userdata.messages;
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ for(i=0; i<msg_count; i++){
+ mosquitto_message_free_contents(&userdata.messages[i]);
+ }
+ free(userdata.messages);
+ userdata.messages = NULL;
+ return rc;
+ }
+}
+
+
+libmosq_EXPORT int mosquitto_subscribe_callback(
+ int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *),
+ void *userdata,
+ const char *topic,
+ int qos,
+ const char *host,
+ int port,
+ const char *client_id,
+ int keepalive,
+ bool clean_session,
+ const char *username,
+ const char *password,
+ const struct libmosquitto_will *will,
+ const struct libmosquitto_tls *tls)
+{
+ struct mosquitto *mosq;
+ struct userdata__callback cb_userdata;
+ int rc;
+
+ if(!callback || !topic){
+ return MOSQ_ERR_INVAL;
+ }
+
+ cb_userdata.topic = topic;
+ cb_userdata.qos = qos;
+ cb_userdata.rc = 0;
+ cb_userdata.userdata = userdata;
+ cb_userdata.callback = callback;
+
+ mosq = mosquitto_new(client_id, clean_session, &cb_userdata);
+ if(!mosq){
+ return MOSQ_ERR_NOMEM;
+ }
+
+ if(will){
+ rc = mosquitto_will_set(mosq, will->topic, will->payloadlen, will->payload, will->qos, will->retain);
+ if(rc){
+ mosquitto_destroy(mosq);
+ return rc;
+ }
+ }
+ if(username){
+ rc = mosquitto_username_pw_set(mosq, username, password);
+ if(rc){
+ mosquitto_destroy(mosq);
+ return rc;
+ }
+ }
+ if(tls){
+ rc = mosquitto_tls_set(mosq, tls->cafile, tls->capath, tls->certfile, tls->keyfile, tls->pw_callback);
+ if(rc){
+ mosquitto_destroy(mosq);
+ return rc;
+ }
+ rc = mosquitto_tls_opts_set(mosq, tls->cert_reqs, tls->tls_version, tls->ciphers);
+ if(rc){
+ mosquitto_destroy(mosq);
+ return rc;
+ }
+ }
+
+ mosquitto_connect_callback_set(mosq, on_connect);
+ mosquitto_message_callback_set(mosq, on_message_callback);
+
+ rc = mosquitto_connect(mosq, host, port, keepalive);
+ if(rc){
+ mosquitto_destroy(mosq);
+ return rc;
+ }
+ rc = mosquitto_loop_forever(mosq, -1, 1);
+ mosquitto_destroy(mosq);
+ if(cb_userdata.rc){
+ rc = cb_userdata.rc;
+ }
+ //if(!rc && cb_userdata.max_msg_count == 0){
+ //return MOSQ_ERR_SUCCESS;
+ //}else{
+ //return rc;
+ //}
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/logging_mosq.c b/libs/libmosquitto/src/logging_mosq.c
new file mode 100644
index 0000000000..eab6356239
--- /dev/null
+++ b/libs/libmosquitto/src/logging_mosq.c
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+#include "memory_mosq.h"
+
+int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...)
+{
+ va_list va;
+ char *s;
+ int len;
+
+ assert(mosq);
+ assert(fmt);
+
+ pthread_mutex_lock(&mosq->log_callback_mutex);
+ if(mosq->on_log){
+ len = strlen(fmt) + 500;
+ s = mosquitto__malloc(len*sizeof(char));
+ if(!s){
+ pthread_mutex_unlock(&mosq->log_callback_mutex);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ va_start(va, fmt);
+ vsnprintf(s, len, fmt, va);
+ va_end(va);
+ s[len-1] = '\0'; /* Ensure string is null terminated. */
+
+ mosq->on_log(mosq, mosq->userdata, priority, s);
+
+ mosquitto__free(s);
+ }
+ pthread_mutex_unlock(&mosq->log_callback_mutex);
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/logging_mosq.h b/libs/libmosquitto/src/logging_mosq.h
new file mode 100644
index 0000000000..c3cc29d9ee
--- /dev/null
+++ b/libs/libmosquitto/src/logging_mosq.h
@@ -0,0 +1,23 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef LOGGING_MOSQ_H
+#define LOGGING_MOSQ_H
+
+#include "mosquitto.h"
+
+int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...);
+
+#endif
diff --git a/libs/libmosquitto/src/loop.c b/libs/libmosquitto/src/loop.c
new file mode 100644
index 0000000000..2342c945aa
--- /dev/null
+++ b/libs/libmosquitto/src/loop.c
@@ -0,0 +1,390 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <errno.h>
+#ifndef WIN32
+#include <sys/select.h>
+#include <time.h>
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "socks_mosq.h"
+#include "tls_mosq.h"
+#include "util_mosq.h"
+
+#if !defined(WIN32) && !defined(__SYMBIAN32__)
+#define HAVE_PSELECT
+#endif
+
+int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets)
+{
+#ifdef HAVE_PSELECT
+ struct timespec local_timeout;
+#else
+ struct timeval local_timeout;
+#endif
+ fd_set readfds, writefds;
+ int fdcount;
+ int rc;
+ char pairbuf;
+ int maxfd = 0;
+ time_t now;
+
+ if(!mosq || max_packets < 1) return MOSQ_ERR_INVAL;
+#ifndef WIN32
+ if(mosq->sock >= FD_SETSIZE || mosq->sockpairR >= FD_SETSIZE){
+ return MOSQ_ERR_INVAL;
+ }
+#endif
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ if(mosq->sock != INVALID_SOCKET){
+ maxfd = mosq->sock;
+ FD_SET(mosq->sock, &readfds);
+ pthread_mutex_lock(&mosq->current_out_packet_mutex);
+ pthread_mutex_lock(&mosq->out_packet_mutex);
+ if(mosq->out_packet || mosq->current_out_packet){
+ FD_SET(mosq->sock, &writefds);
+ }
+#ifdef WITH_TLS
+ if(mosq->ssl){
+ if(mosq->want_write){
+ FD_SET(mosq->sock, &writefds);
+ }else if(mosq->want_connect){
+ /* Remove possible FD_SET from above, we don't want to check
+ * for writing if we are still connecting, unless want_write is
+ * definitely set. The presence of outgoing packets does not
+ * matter yet. */
+ FD_CLR(mosq->sock, &writefds);
+ }
+ }
+#endif
+ pthread_mutex_unlock(&mosq->out_packet_mutex);
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+ }else{
+#ifdef WITH_SRV
+ if(mosq->achan){
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state == mosq_cs_connect_srv){
+ rc = ares_fds(mosq->achan, &readfds, &writefds);
+ if(rc > maxfd){
+ maxfd = rc;
+ }
+ }else{
+ pthread_mutex_unlock(&mosq->state_mutex);
+ return MOSQ_ERR_NO_CONN;
+ }
+ pthread_mutex_unlock(&mosq->state_mutex);
+ }
+#else
+ return MOSQ_ERR_NO_CONN;
+#endif
+ }
+ if(mosq->sockpairR != INVALID_SOCKET){
+ /* sockpairR is used to break out of select() before the timeout, on a
+ * call to publish() etc. */
+ FD_SET(mosq->sockpairR, &readfds);
+ if(mosq->sockpairR > maxfd){
+ maxfd = mosq->sockpairR;
+ }
+ }
+
+ if(timeout < 0){
+ timeout = 1000;
+ }
+
+ now = mosquitto_time();
+ if(mosq->next_msg_out && now + timeout/1000 > mosq->next_msg_out){
+ timeout = (mosq->next_msg_out - now)*1000;
+ }
+
+ if(timeout < 0){
+ /* There has been a delay somewhere which means we should have already
+ * sent a message. */
+ timeout = 0;
+ }
+
+ local_timeout.tv_sec = timeout/1000;
+#ifdef HAVE_PSELECT
+ local_timeout.tv_nsec = (timeout-local_timeout.tv_sec*1000)*1e6;
+#else
+ local_timeout.tv_usec = (timeout-local_timeout.tv_sec*1000)*1000;
+#endif
+
+#ifdef HAVE_PSELECT
+ fdcount = pselect(maxfd+1, &readfds, &writefds, NULL, &local_timeout, NULL);
+#else
+ fdcount = select(maxfd+1, &readfds, &writefds, NULL, &local_timeout);
+#endif
+ if(fdcount == -1){
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EINTR){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ return MOSQ_ERR_ERRNO;
+ }
+ }else{
+ if(mosq->sock != INVALID_SOCKET){
+ if(FD_ISSET(mosq->sock, &readfds)){
+ rc = mosquitto_loop_read(mosq, max_packets);
+ if(rc || mosq->sock == INVALID_SOCKET){
+ return rc;
+ }
+ }
+ if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){
+#ifndef WIN32
+ if(read(mosq->sockpairR, &pairbuf, 1) == 0){
+ }
+#else
+ recv(mosq->sockpairR, &pairbuf, 1, 0);
+#endif
+ /* Fake write possible, to stimulate output write even though
+ * we didn't ask for it, because at that point the publish or
+ * other command wasn't present. */
+ if(mosq->sock != INVALID_SOCKET)
+ FD_SET(mosq->sock, &writefds);
+ }
+ if(mosq->sock != INVALID_SOCKET && FD_ISSET(mosq->sock, &writefds)){
+#ifdef WITH_TLS
+ if(mosq->want_connect){
+ rc = net__socket_connect_tls(mosq);
+ if(rc) return rc;
+ }else
+#endif
+ {
+ rc = mosquitto_loop_write(mosq, max_packets);
+ if(rc || mosq->sock == INVALID_SOCKET){
+ return rc;
+ }
+ }
+ }
+ }
+#ifdef WITH_SRV
+ if(mosq->achan){
+ ares_process(mosq->achan, &readfds, &writefds);
+ }
+#endif
+ }
+ return mosquitto_loop_misc(mosq);
+}
+
+
+int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets)
+{
+ int run = 1;
+ int rc;
+ unsigned int reconnects = 0;
+ unsigned long reconnect_delay;
+#ifndef WIN32
+ struct timespec req, rem;
+#endif
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ if(mosq->state == mosq_cs_connect_async){
+ mosquitto_reconnect(mosq);
+ }
+
+ while(run){
+ do{
+ rc = mosquitto_loop(mosq, timeout, max_packets);
+ if (reconnects !=0 && rc == MOSQ_ERR_SUCCESS){
+ reconnects = 0;
+ }
+ }while(run && rc == MOSQ_ERR_SUCCESS);
+ /* Quit after fatal errors. */
+ switch(rc){
+ case MOSQ_ERR_NOMEM:
+ case MOSQ_ERR_PROTOCOL:
+ case MOSQ_ERR_INVAL:
+ case MOSQ_ERR_NOT_FOUND:
+ case MOSQ_ERR_TLS:
+ case MOSQ_ERR_PAYLOAD_SIZE:
+ case MOSQ_ERR_NOT_SUPPORTED:
+ case MOSQ_ERR_AUTH:
+ case MOSQ_ERR_ACL_DENIED:
+ case MOSQ_ERR_UNKNOWN:
+ case MOSQ_ERR_EAI:
+ case MOSQ_ERR_PROXY:
+ return rc;
+ case MOSQ_ERR_ERRNO:
+ break;
+ }
+ if(errno == EPROTO){
+ return rc;
+ }
+ do{
+ rc = MOSQ_ERR_SUCCESS;
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state == mosq_cs_disconnecting){
+ run = 0;
+ pthread_mutex_unlock(&mosq->state_mutex);
+ }else{
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ if(mosq->reconnect_delay_max > mosq->reconnect_delay){
+ if(mosq->reconnect_exponential_backoff){
+ reconnect_delay = mosq->reconnect_delay*(reconnects+1)*(reconnects+1);
+ }else{
+ reconnect_delay = mosq->reconnect_delay*(reconnects+1);
+ }
+ }else{
+ reconnect_delay = mosq->reconnect_delay;
+ }
+
+ if(reconnect_delay > mosq->reconnect_delay_max){
+ reconnect_delay = mosq->reconnect_delay_max;
+ }else{
+ reconnects++;
+ }
+
+#ifdef WIN32
+ Sleep(reconnect_delay*1000);
+#else
+ req.tv_sec = reconnect_delay;
+ req.tv_nsec = 0;
+ while(nanosleep(&req, &rem) == -1 && errno == EINTR){
+ req = rem;
+ }
+#endif
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state == mosq_cs_disconnecting){
+ run = 0;
+ pthread_mutex_unlock(&mosq->state_mutex);
+ }else{
+ pthread_mutex_unlock(&mosq->state_mutex);
+ rc = mosquitto_reconnect(mosq);
+ }
+ }
+ }while(run && rc != MOSQ_ERR_SUCCESS);
+ }
+ return rc;
+}
+
+
+int mosquitto_loop_misc(struct mosquitto *mosq)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+ return mosquitto__check_keepalive(mosq);
+}
+
+
+static int mosquitto__loop_rc_handle(struct mosquitto *mosq, int rc)
+{
+ if(rc){
+ net__socket_close(mosq);
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state == mosq_cs_disconnecting){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+ pthread_mutex_unlock(&mosq->state_mutex);
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_disconnect){
+ mosq->in_callback = true;
+ mosq->on_disconnect(mosq, mosq->userdata, rc);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_disconnect_v5){
+ mosq->in_callback = true;
+ mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ return rc;
+ }
+ return rc;
+}
+
+
+int mosquitto_loop_read(struct mosquitto *mosq, int max_packets)
+{
+ int rc;
+ int i;
+ if(max_packets < 1) return MOSQ_ERR_INVAL;
+
+#ifdef WITH_TLS
+ if(mosq->want_connect){
+ return net__socket_connect_tls(mosq);
+ }
+#endif
+
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ max_packets = mosq->msgs_out.queue_len;
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+
+ pthread_mutex_lock(&mosq->msgs_in.mutex);
+ max_packets += mosq->msgs_in.queue_len;
+ pthread_mutex_unlock(&mosq->msgs_in.mutex);
+
+ if(max_packets < 1) max_packets = 1;
+ /* Queue len here tells us how many messages are awaiting processing and
+ * have QoS > 0. We should try to deal with that many in this loop in order
+ * to keep up. */
+ for(i=0; i<max_packets || SSL_DATA_PENDING(mosq); i++){
+#ifdef WITH_SOCKS
+ if(mosq->socks5_host){
+ rc = socks5__read(mosq);
+ }else
+#endif
+ {
+ rc = packet__read(mosq);
+ }
+ if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return mosquitto__loop_rc_handle(mosq, rc);
+ }
+ }
+ return rc;
+}
+
+
+int mosquitto_loop_write(struct mosquitto *mosq, int max_packets)
+{
+ int rc;
+ int i;
+ if(max_packets < 1) return MOSQ_ERR_INVAL;
+
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ max_packets = mosq->msgs_out.queue_len;
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+
+ pthread_mutex_lock(&mosq->msgs_in.mutex);
+ max_packets += mosq->msgs_in.queue_len;
+ pthread_mutex_unlock(&mosq->msgs_in.mutex);
+
+ if(max_packets < 1) max_packets = 1;
+ /* Queue len here tells us how many messages are awaiting processing and
+ * have QoS > 0. We should try to deal with that many in this loop in order
+ * to keep up. */
+ for(i=0; i<max_packets; i++){
+ rc = packet__write(mosq);
+ if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return mosquitto__loop_rc_handle(mosq, rc);
+ }
+ }
+ return rc;
+}
+
diff --git a/libs/libmosquitto/src/memory_mosq.c b/libs/libmosquitto/src/memory_mosq.c
new file mode 100644
index 0000000000..a9b01e5477
--- /dev/null
+++ b/libs/libmosquitto/src/memory_mosq.c
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "memory_mosq.h"
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+# if defined(__APPLE__)
+# include <malloc/malloc.h>
+# define malloc_usable_size malloc_size
+# elif defined(__FreeBSD__)
+# include <malloc_np.h>
+# else
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+static unsigned long memcount = 0;
+static unsigned long max_memcount = 0;
+#endif
+
+#ifdef WITH_BROKER
+static size_t mem_limit = 0;
+void memory__set_limit(size_t lim)
+{
+ mem_limit = lim;
+}
+#endif
+
+void *mosquitto__calloc(size_t nmemb, size_t size)
+{
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem_limit && memcount + size > mem_limit){
+ return NULL;
+ }
+#endif
+ void *mem = calloc(nmemb, size);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem){
+ memcount += malloc_usable_size(mem);
+ if(memcount > max_memcount){
+ max_memcount = memcount;
+ }
+ }
+#endif
+
+ return mem;
+}
+
+void mosquitto__free(void *mem)
+{
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(!mem){
+ return;
+ }
+ memcount -= malloc_usable_size(mem);
+#endif
+ free(mem);
+}
+
+void *mosquitto__malloc(size_t size)
+{
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem_limit && memcount + size > mem_limit){
+ return NULL;
+ }
+#endif
+ void *mem = malloc(size);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem){
+ memcount += malloc_usable_size(mem);
+ if(memcount > max_memcount){
+ max_memcount = memcount;
+ }
+ }
+#endif
+
+ return mem;
+}
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+unsigned long mosquitto__memory_used(void)
+{
+ return memcount;
+}
+
+unsigned long mosquitto__max_memory_used(void)
+{
+ return max_memcount;
+}
+#endif
+
+void *mosquitto__realloc(void *ptr, size_t size)
+{
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem_limit && memcount + size > mem_limit){
+ return NULL;
+ }
+#endif
+ void *mem;
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(ptr){
+ memcount -= malloc_usable_size(ptr);
+ }
+#endif
+ mem = realloc(ptr, size);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem){
+ memcount += malloc_usable_size(mem);
+ if(memcount > max_memcount){
+ max_memcount = memcount;
+ }
+ }
+#endif
+
+ return mem;
+}
+
+char *mosquitto__strdup(const char *s)
+{
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(mem_limit && memcount + strlen(s) > mem_limit){
+ return NULL;
+ }
+#endif
+ char *str = strdup(s);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+ if(str){
+ memcount += malloc_usable_size(str);
+ if(memcount > max_memcount){
+ max_memcount = memcount;
+ }
+ }
+#endif
+
+ return str;
+}
+
diff --git a/libs/libmosquitto/src/memory_mosq.h b/libs/libmosquitto/src/memory_mosq.h
new file mode 100644
index 0000000000..63386a2115
--- /dev/null
+++ b/libs/libmosquitto/src/memory_mosq.h
@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef MEMORY_MOSQ_H
+#define MEMORY_MOSQ_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined(WITH_MEMORY_TRACKING) && defined(WITH_BROKER) && defined(__GLIBC__)
+#define REAL_WITH_MEMORY_TRACKING
+#endif
+
+void *mosquitto__calloc(size_t nmemb, size_t size);
+void mosquitto__free(void *mem);
+void *mosquitto__malloc(size_t size);
+#ifdef REAL_WITH_MEMORY_TRACKING
+unsigned long mosquitto__memory_used(void);
+unsigned long mosquitto__max_memory_used(void);
+#endif
+void *mosquitto__realloc(void *ptr, size_t size);
+char *mosquitto__strdup(const char *s);
+
+#ifdef WITH_BROKER
+void memory__set_limit(size_t lim);
+#endif
+
+#endif
diff --git a/libs/libmosquitto/src/messages_mosq.c b/libs/libmosquitto/src/messages_mosq.c
new file mode 100644
index 0000000000..bf77f5e64b
--- /dev/null
+++ b/libs/libmosquitto/src/messages_mosq.c
@@ -0,0 +1,348 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utlist.h>
+
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "util_mosq.h"
+
+void message__cleanup(struct mosquitto_message_all **message)
+{
+ struct mosquitto_message_all *msg;
+
+ if(!message || !*message) return;
+
+ msg = *message;
+
+ mosquitto__free(msg->msg.topic);
+ mosquitto__free(msg->msg.payload);
+ mosquitto__free(msg);
+}
+
+void message__cleanup_all(struct mosquitto *mosq)
+{
+ struct mosquitto_message_all *tail, *tmp;
+
+ assert(mosq);
+
+ DL_FOREACH_SAFE(mosq->msgs_in.inflight, tail, tmp){
+ DL_DELETE(mosq->msgs_in.inflight, tail);
+ message__cleanup(&tail);
+ }
+ DL_FOREACH_SAFE(mosq->msgs_out.inflight, tail, tmp){
+ DL_DELETE(mosq->msgs_out.inflight, tail);
+ message__cleanup(&tail);
+ }
+}
+
+int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src)
+{
+ if(!dst || !src) return MOSQ_ERR_INVAL;
+
+ dst->mid = src->mid;
+ dst->topic = mosquitto__strdup(src->topic);
+ if(!dst->topic) return MOSQ_ERR_NOMEM;
+ dst->qos = src->qos;
+ dst->retain = src->retain;
+ if(src->payloadlen){
+ dst->payload = mosquitto__calloc(src->payloadlen+1, sizeof(uint8_t));
+ if(!dst->payload){
+ mosquitto__free(dst->topic);
+ return MOSQ_ERR_NOMEM;
+ }
+ memcpy(dst->payload, src->payload, src->payloadlen);
+ dst->payloadlen = src->payloadlen;
+ }else{
+ dst->payloadlen = 0;
+ dst->payload = NULL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos)
+{
+ struct mosquitto_message_all *message;
+ int rc;
+ assert(mosq);
+
+ rc = message__remove(mosq, mid, dir, &message, qos);
+ if(rc == MOSQ_ERR_SUCCESS){
+ message__cleanup(&message);
+ }
+ return rc;
+}
+
+void mosquitto_message_free(struct mosquitto_message **message)
+{
+ struct mosquitto_message *msg;
+
+ if(!message || !*message) return;
+
+ msg = *message;
+
+ mosquitto__free(msg->topic);
+ mosquitto__free(msg->payload);
+ mosquitto__free(msg);
+}
+
+void mosquitto_message_free_contents(struct mosquitto_message *message)
+{
+ if(!message) return;
+
+ mosquitto__free(message->topic);
+ mosquitto__free(message->payload);
+}
+
+int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir)
+{
+ /* mosq->*_message_mutex should be locked before entering this function */
+ assert(mosq);
+ assert(message);
+ assert(message->msg.qos != 0);
+
+ if(dir == mosq_md_out){
+ DL_APPEND(mosq->msgs_out.inflight, message);
+ mosq->msgs_out.queue_len++;
+ }else{
+ DL_APPEND(mosq->msgs_in.inflight, message);
+ mosq->msgs_in.queue_len++;
+ }
+
+ return message__release_to_inflight(mosq, dir);
+}
+
+void message__reconnect_reset(struct mosquitto *mosq)
+{
+ struct mosquitto_message_all *message, *tmp;
+ assert(mosq);
+
+ pthread_mutex_lock(&mosq->msgs_in.mutex);
+ mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum;
+ mosq->msgs_in.queue_len = 0;
+ DL_FOREACH_SAFE(mosq->msgs_in.inflight, message, tmp){
+ mosq->msgs_in.queue_len++;
+ message->timestamp = 0;
+ if(message->msg.qos != 2){
+ DL_DELETE(mosq->msgs_in.inflight, message);
+ message__cleanup(&message);
+ }else{
+ /* Message state can be preserved here because it should match
+ * whatever the client has got. */
+ util__decrement_receive_quota(mosq);
+ }
+ }
+ pthread_mutex_unlock(&mosq->msgs_in.mutex);
+
+
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum;
+ mosq->msgs_out.queue_len = 0;
+ DL_FOREACH_SAFE(mosq->msgs_out.inflight, message, tmp){
+ mosq->msgs_out.queue_len++;
+
+ message->timestamp = 0;
+ if(mosq->msgs_out.inflight_quota != 0){
+ util__decrement_send_quota(mosq);
+ if(message->msg.qos == 1){
+ message->state = mosq_ms_publish_qos1;
+ }else if(message->msg.qos == 2){
+ if(message->state == mosq_ms_wait_for_pubrec){
+ message->state = mosq_ms_publish_qos2;
+ }else if(message->state == mosq_ms_wait_for_pubcomp){
+ message->state = mosq_ms_resend_pubrel;
+ }
+ /* Should be able to preserve state. */
+ }
+ }else{
+ message->state = mosq_ms_invalid;
+ }
+ }
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+}
+
+
+int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir)
+{
+ /* mosq->*_message_mutex should be locked before entering this function */
+ struct mosquitto_message_all *cur, *tmp;
+ int rc = MOSQ_ERR_SUCCESS;
+
+ if(dir == mosq_md_out){
+ DL_FOREACH_SAFE(mosq->msgs_out.inflight, cur, tmp){
+ if(mosq->msgs_out.inflight_quota > 0){
+ if(cur->msg.qos > 0 && cur->state == mosq_ms_invalid){
+ if(cur->msg.qos == 1){
+ cur->state = mosq_ms_wait_for_puback;
+ }else if(cur->msg.qos == 2){
+ cur->state = mosq_ms_wait_for_pubrec;
+ }
+ rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL, NULL, 0);
+ if(rc){
+ return rc;
+ }
+ util__decrement_send_quota(mosq);
+ }
+ }else{
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos)
+{
+ struct mosquitto_message_all *cur, *tmp;
+ bool found = false;
+ assert(mosq);
+ assert(message);
+
+ if(dir == mosq_md_out){
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+
+ DL_FOREACH_SAFE(mosq->msgs_out.inflight, cur, tmp){
+ if(found == false && cur->msg.mid == mid){
+ if(cur->msg.qos != qos){
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ return MOSQ_ERR_PROTOCOL;
+ }
+ DL_DELETE(mosq->msgs_out.inflight, cur);
+
+ *message = cur;
+ mosq->msgs_out.queue_len--;
+ found = true;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ if(found){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ return MOSQ_ERR_NOT_FOUND;
+ }
+ }else{
+ pthread_mutex_lock(&mosq->msgs_in.mutex);
+ DL_FOREACH_SAFE(mosq->msgs_in.inflight, cur, tmp){
+ if(cur->msg.mid == mid){
+ if(cur->msg.qos != qos){
+ pthread_mutex_unlock(&mosq->msgs_in.mutex);
+ return MOSQ_ERR_PROTOCOL;
+ }
+ DL_DELETE(mosq->msgs_in.inflight, cur);
+ *message = cur;
+ mosq->msgs_in.queue_len--;
+ found = true;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&mosq->msgs_in.mutex);
+ if(found){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ return MOSQ_ERR_NOT_FOUND;
+ }
+ }
+}
+
+void message__retry_check(struct mosquitto *mosq)
+{
+ struct mosquitto_message_all *msg;
+ time_t now = mosquitto_time();
+ assert(mosq);
+
+#ifdef WITH_THREADING
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+#endif
+
+ DL_FOREACH(mosq->msgs_out.inflight, msg){
+ switch(msg->state){
+ case mosq_ms_publish_qos1:
+ case mosq_ms_publish_qos2:
+ msg->timestamp = now;
+ msg->dup = true;
+ send__publish(mosq, msg->msg.mid, msg->msg.topic, msg->msg.payloadlen, msg->msg.payload, msg->msg.qos, msg->msg.retain, msg->dup, NULL, NULL, 0);
+ break;
+ case mosq_ms_wait_for_pubrel:
+ msg->timestamp = now;
+ msg->dup = true;
+ send__pubrec(mosq, msg->msg.mid, 0);
+ break;
+ case mosq_ms_resend_pubrel:
+ case mosq_ms_wait_for_pubcomp:
+ msg->timestamp = now;
+ msg->dup = true;
+ send__pubrel(mosq, msg->msg.mid);
+ break;
+ default:
+ break;
+ }
+ }
+#ifdef WITH_THREADING
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+#endif
+}
+
+
+void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry)
+{
+ UNUSED(mosq);
+ UNUSED(message_retry);
+}
+
+int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos)
+{
+ struct mosquitto_message_all *message, *tmp;
+ assert(mosq);
+
+ pthread_mutex_lock(&mosq->msgs_out.mutex);
+ DL_FOREACH_SAFE(mosq->msgs_out.inflight, message, tmp){
+ if(message->msg.mid == mid){
+ if(message->msg.qos != qos){
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ return MOSQ_ERR_PROTOCOL;
+ }
+ message->state = state;
+ message->timestamp = mosquitto_time();
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ pthread_mutex_unlock(&mosq->msgs_out.mutex);
+ return MOSQ_ERR_NOT_FOUND;
+}
+
+int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ mosq->send_maximum = max_inflight_messages;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/messages_mosq.h b/libs/libmosquitto/src/messages_mosq.h
new file mode 100644
index 0000000000..1951bfc79c
--- /dev/null
+++ b/libs/libmosquitto/src/messages_mosq.h
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef MESSAGES_MOSQ_H
+#define MESSAGES_MOSQ_H
+
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+
+void message__cleanup_all(struct mosquitto *mosq);
+void message__cleanup(struct mosquitto_message_all **message);
+int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos);
+int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir);
+void message__reconnect_reset(struct mosquitto *mosq);
+int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir);
+int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos);
+void message__retry_check(struct mosquitto *mosq);
+int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos);
+
+#endif
diff --git a/libs/libmosquitto/src/mosquitto.c b/libs/libmosquitto/src/mosquitto.c
new file mode 100644
index 0000000000..4b5768f38b
--- /dev/null
+++ b/libs/libmosquitto/src/mosquitto.c
@@ -0,0 +1,612 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "will_mosq.h"
+
+
+void mosquitto__destroy(struct mosquitto *mosq);
+
+int mosquitto_lib_version(int *major, int *minor, int *revision)
+{
+ if(major) *major = LIBMOSQUITTO_MAJOR;
+ if(minor) *minor = LIBMOSQUITTO_MINOR;
+ if(revision) *revision = LIBMOSQUITTO_REVISION;
+ return LIBMOSQUITTO_VERSION_NUMBER;
+}
+
+int mosquitto_lib_init(void)
+{
+#ifdef WIN32
+ srand(GetTickCount64());
+#elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK)
+ struct timespec tp;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ srand(tp.tv_nsec);
+#elif defined(__APPLE__)
+ uint64_t ticks;
+
+ ticks = mach_absolute_time();
+ srand((unsigned int)ticks);
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ srand(tv.tv_sec*1000 + tv.tv_usec/1000);
+#endif
+
+ return net__init();
+}
+
+int mosquitto_lib_cleanup(void)
+{
+ net__cleanup();
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata)
+{
+ struct mosquitto *mosq = NULL;
+ int rc;
+
+ if(clean_start == false && id == NULL){
+ errno = EINVAL;
+ return NULL;
+ }
+
+#ifndef WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ mosq = (struct mosquitto *)mosquitto__calloc(1, sizeof(struct mosquitto));
+ if(mosq){
+ mosq->sock = INVALID_SOCKET;
+ mosq->sockpairR = INVALID_SOCKET;
+ mosq->sockpairW = INVALID_SOCKET;
+#ifdef WITH_THREADING
+ mosq->thread_id = pthread_self();
+#endif
+ rc = mosquitto_reinitialise(mosq, id, clean_start, userdata);
+ if(rc){
+ mosquitto_destroy(mosq);
+ if(rc == MOSQ_ERR_INVAL){
+ errno = EINVAL;
+ }else if(rc == MOSQ_ERR_NOMEM){
+ errno = ENOMEM;
+ }
+ return NULL;
+ }
+ }else{
+ errno = ENOMEM;
+ }
+ return mosq;
+}
+
+int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_start, void *userdata)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ if(clean_start == false && id == NULL){
+ return MOSQ_ERR_INVAL;
+ }
+
+ mosquitto__destroy(mosq);
+ memset(mosq, 0, sizeof(struct mosquitto));
+
+ if(userdata){
+ mosq->userdata = userdata;
+ }else{
+ mosq->userdata = mosq;
+ }
+ mosq->protocol = mosq_p_mqtt311;
+ mosq->sock = INVALID_SOCKET;
+ mosq->sockpairR = INVALID_SOCKET;
+ mosq->sockpairW = INVALID_SOCKET;
+ mosq->keepalive = 60;
+ mosq->clean_start = clean_start;
+ if(id){
+ if(STREMPTY(id)){
+ return MOSQ_ERR_INVAL;
+ }
+ if(mosquitto_validate_utf8(id, strlen(id))){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ mosq->id = mosquitto__strdup(id);
+ }
+ mosq->in_packet.payload = NULL;
+ packet__cleanup(&mosq->in_packet);
+ mosq->out_packet = NULL;
+ mosq->current_out_packet = NULL;
+ mosq->last_msg_in = mosquitto_time();
+ mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
+ mosq->ping_t = 0;
+ mosq->last_mid = 0;
+ mosq->state = mosq_cs_new;
+ mosq->maximum_qos = 2;
+ mosq->msgs_in.inflight_maximum = 20;
+ mosq->msgs_out.inflight_maximum = 20;
+ mosq->msgs_in.inflight_quota = 20;
+ mosq->msgs_out.inflight_quota = 20;
+ mosq->will = NULL;
+ mosq->on_connect = NULL;
+ mosq->on_publish = NULL;
+ mosq->on_message = NULL;
+ mosq->on_subscribe = NULL;
+ mosq->on_unsubscribe = NULL;
+ mosq->host = NULL;
+ mosq->port = 1883;
+ mosq->in_callback = false;
+ mosq->reconnect_delay = 1;
+ mosq->reconnect_delay_max = 1;
+ mosq->reconnect_exponential_backoff = false;
+ mosq->threaded = mosq_ts_none;
+#ifdef WITH_TLS
+ mosq->ssl = NULL;
+ mosq->ssl_ctx = NULL;
+ mosq->tls_cert_reqs = SSL_VERIFY_PEER;
+ mosq->tls_insecure = false;
+ mosq->want_write = false;
+ mosq->tls_ocsp_required = false;
+#endif
+#ifdef WITH_THREADING
+ pthread_mutex_init(&mosq->callback_mutex, NULL);
+ pthread_mutex_init(&mosq->log_callback_mutex, NULL);
+ pthread_mutex_init(&mosq->state_mutex, NULL);
+ pthread_mutex_init(&mosq->out_packet_mutex, NULL);
+ pthread_mutex_init(&mosq->current_out_packet_mutex, NULL);
+ pthread_mutex_init(&mosq->msgtime_mutex, NULL);
+ pthread_mutex_init(&mosq->msgs_in.mutex, NULL);
+ pthread_mutex_init(&mosq->msgs_out.mutex, NULL);
+ pthread_mutex_init(&mosq->mid_mutex, NULL);
+ mosq->thread_id = pthread_self();
+#endif
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void mosquitto__destroy(struct mosquitto *mosq)
+{
+ struct mosquitto__packet *packet;
+ if(!mosq) return;
+
+#ifdef WITH_THREADING
+# ifdef HAVE_PTHREAD_CANCEL
+ if(mosq->threaded == mosq_ts_self && !pthread_equal(mosq->thread_id, pthread_self())){
+ pthread_cancel(mosq->thread_id);
+ pthread_join(mosq->thread_id, NULL);
+ mosq->threaded = mosq_ts_none;
+ }
+# endif
+
+ if(mosq->id){
+ /* If mosq->id is not NULL then the client has already been initialised
+ * and so the mutexes need destroying. If mosq->id is NULL, the mutexes
+ * haven't been initialised. */
+ pthread_mutex_destroy(&mosq->callback_mutex);
+ pthread_mutex_destroy(&mosq->log_callback_mutex);
+ pthread_mutex_destroy(&mosq->state_mutex);
+ pthread_mutex_destroy(&mosq->out_packet_mutex);
+ pthread_mutex_destroy(&mosq->current_out_packet_mutex);
+ pthread_mutex_destroy(&mosq->msgtime_mutex);
+ pthread_mutex_destroy(&mosq->msgs_in.mutex);
+ pthread_mutex_destroy(&mosq->msgs_out.mutex);
+ pthread_mutex_destroy(&mosq->mid_mutex);
+ }
+#endif
+ if(mosq->sock != INVALID_SOCKET){
+ net__socket_close(mosq);
+ }
+ message__cleanup_all(mosq);
+ will__clear(mosq);
+#ifdef WITH_TLS
+ if(mosq->ssl){
+ SSL_free(mosq->ssl);
+ }
+ if(mosq->ssl_ctx){
+ SSL_CTX_free(mosq->ssl_ctx);
+ }
+ mosquitto__free(mosq->tls_cafile);
+ mosquitto__free(mosq->tls_capath);
+ mosquitto__free(mosq->tls_certfile);
+ mosquitto__free(mosq->tls_keyfile);
+ if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL;
+ mosquitto__free(mosq->tls_version);
+ mosquitto__free(mosq->tls_ciphers);
+ mosquitto__free(mosq->tls_psk);
+ mosquitto__free(mosq->tls_psk_identity);
+ mosquitto__free(mosq->tls_alpn);
+#endif
+
+ mosquitto__free(mosq->address);
+ mosq->address = NULL;
+
+ mosquitto__free(mosq->id);
+ mosq->id = NULL;
+
+ mosquitto__free(mosq->username);
+ mosq->username = NULL;
+
+ mosquitto__free(mosq->password);
+ mosq->password = NULL;
+
+ mosquitto__free(mosq->host);
+ mosq->host = NULL;
+
+ mosquitto__free(mosq->bind_address);
+ mosq->bind_address = NULL;
+
+ /* Out packet cleanup */
+ if(mosq->out_packet && !mosq->current_out_packet){
+ mosq->current_out_packet = mosq->out_packet;
+ mosq->out_packet = mosq->out_packet->next;
+ }
+ while(mosq->current_out_packet){
+ packet = mosq->current_out_packet;
+ /* Free data and reset values */
+ mosq->current_out_packet = mosq->out_packet;
+ if(mosq->out_packet){
+ mosq->out_packet = mosq->out_packet->next;
+ }
+
+ packet__cleanup(packet);
+ mosquitto__free(packet);
+ }
+
+ packet__cleanup(&mosq->in_packet);
+ if(mosq->sockpairR != INVALID_SOCKET){
+ COMPAT_CLOSE(mosq->sockpairR);
+ mosq->sockpairR = INVALID_SOCKET;
+ }
+ if(mosq->sockpairW != INVALID_SOCKET){
+ COMPAT_CLOSE(mosq->sockpairW);
+ mosq->sockpairW = INVALID_SOCKET;
+ }
+}
+
+void mosquitto_destroy(struct mosquitto *mosq)
+{
+ if(!mosq) return;
+
+ mosquitto__destroy(mosq);
+ mosquitto__free(mosq);
+}
+
+int mosquitto_socket(struct mosquitto *mosq)
+{
+ if(!mosq) return INVALID_SOCKET;
+ return mosq->sock;
+}
+
+
+bool mosquitto_want_write(struct mosquitto *mosq)
+{
+ bool result = false;
+ if(mosq->out_packet || mosq->current_out_packet){
+ result = true;
+ }
+#ifdef WITH_TLS
+ if(mosq->ssl){
+ if (mosq->want_write) {
+ result = true;
+ }else if(mosq->want_connect){
+ result = false;
+ }
+ }
+#endif
+ return result;
+}
+
+
+const char *mosquitto_strerror(int mosq_errno)
+{
+ switch(mosq_errno){
+ case MOSQ_ERR_AUTH_CONTINUE:
+ return "Continue with authentication.";
+ case MOSQ_ERR_NO_SUBSCRIBERS:
+ return "No subscribers.";
+ case MOSQ_ERR_SUB_EXISTS:
+ return "Subscription already exists.";
+ case MOSQ_ERR_CONN_PENDING:
+ return "Connection pending.";
+ case MOSQ_ERR_SUCCESS:
+ return "No error.";
+ case MOSQ_ERR_NOMEM:
+ return "Out of memory.";
+ case MOSQ_ERR_PROTOCOL:
+ return "A network protocol error occurred when communicating with the broker.";
+ case MOSQ_ERR_INVAL:
+ return "Invalid function arguments provided.";
+ case MOSQ_ERR_NO_CONN:
+ return "The client is not currently connected.";
+ case MOSQ_ERR_CONN_REFUSED:
+ return "The connection was refused.";
+ case MOSQ_ERR_NOT_FOUND:
+ return "Message not found (internal error).";
+ case MOSQ_ERR_CONN_LOST:
+ return "The connection was lost.";
+ case MOSQ_ERR_TLS:
+ return "A TLS error occurred.";
+ case MOSQ_ERR_PAYLOAD_SIZE:
+ return "Payload too large.";
+ case MOSQ_ERR_NOT_SUPPORTED:
+ return "This feature is not supported.";
+ case MOSQ_ERR_AUTH:
+ return "Authorisation failed.";
+ case MOSQ_ERR_ACL_DENIED:
+ return "Access denied by ACL.";
+ case MOSQ_ERR_UNKNOWN:
+ return "Unknown error.";
+ case MOSQ_ERR_ERRNO:
+ return strerror(errno);
+ case MOSQ_ERR_EAI:
+ return "Lookup error.";
+ case MOSQ_ERR_PROXY:
+ return "Proxy error.";
+ case MOSQ_ERR_MALFORMED_UTF8:
+ return "Malformed UTF-8";
+ case MOSQ_ERR_DUPLICATE_PROPERTY:
+ return "Duplicate property in property list";
+ case MOSQ_ERR_TLS_HANDSHAKE:
+ return "TLS handshake failed.";
+ case MOSQ_ERR_QOS_NOT_SUPPORTED:
+ return "Requested QoS not supported on server.";
+ case MOSQ_ERR_OVERSIZE_PACKET:
+ return "Packet larger than supported by the server.";
+ case MOSQ_ERR_OCSP:
+ return "OCSP error.";
+ default:
+ return "Unknown error.";
+ }
+}
+
+const char *mosquitto_connack_string(int connack_code)
+{
+ switch(connack_code){
+ case 0:
+ return "Connection Accepted.";
+ case 1:
+ return "Connection Refused: unacceptable protocol version.";
+ case 2:
+ return "Connection Refused: identifier rejected.";
+ case 3:
+ return "Connection Refused: broker unavailable.";
+ case 4:
+ return "Connection Refused: bad user name or password.";
+ case 5:
+ return "Connection Refused: not authorised.";
+ default:
+ return "Connection Refused: unknown reason.";
+ }
+}
+
+const char *mosquitto_reason_string(int reason_code)
+{
+ switch(reason_code){
+ case MQTT_RC_SUCCESS:
+ return "Success";
+ case MQTT_RC_GRANTED_QOS1:
+ return "Granted QoS 1";
+ case MQTT_RC_GRANTED_QOS2:
+ return "Granted QoS 2";
+ case MQTT_RC_DISCONNECT_WITH_WILL_MSG:
+ return "Disconnect with Will Message";
+ case MQTT_RC_NO_MATCHING_SUBSCRIBERS:
+ return "No matching subscribers";
+ case MQTT_RC_NO_SUBSCRIPTION_EXISTED:
+ return "No subscription existed";
+ case MQTT_RC_CONTINUE_AUTHENTICATION:
+ return "Continue authentication";
+ case MQTT_RC_REAUTHENTICATE:
+ return "Re-authenticate";
+
+ case MQTT_RC_UNSPECIFIED:
+ return "Unspecified error";
+ case MQTT_RC_MALFORMED_PACKET:
+ return "Malformed Packet";
+ case MQTT_RC_PROTOCOL_ERROR:
+ return "Protocol Error";
+ case MQTT_RC_IMPLEMENTATION_SPECIFIC:
+ return "Implementation specific error";
+ case MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION:
+ return "Unsupported Protocol Version";
+ case MQTT_RC_CLIENTID_NOT_VALID:
+ return "Client Identifier not valid";
+ case MQTT_RC_BAD_USERNAME_OR_PASSWORD:
+ return "Bad User Name or Password";
+ case MQTT_RC_NOT_AUTHORIZED:
+ return "Not authorized";
+ case MQTT_RC_SERVER_UNAVAILABLE:
+ return "Server unavailable";
+ case MQTT_RC_SERVER_BUSY:
+ return "Server busy";
+ case MQTT_RC_BANNED:
+ return "Banned";
+ case MQTT_RC_SERVER_SHUTTING_DOWN:
+ return "Server shutting down";
+ case MQTT_RC_BAD_AUTHENTICATION_METHOD:
+ return "Bad authentication method";
+ case MQTT_RC_KEEP_ALIVE_TIMEOUT:
+ return "Keep Alive timeout";
+ case MQTT_RC_SESSION_TAKEN_OVER:
+ return "Session taken over";
+ case MQTT_RC_TOPIC_FILTER_INVALID:
+ return "Topic Filter invalid";
+ case MQTT_RC_TOPIC_NAME_INVALID:
+ return "Topic Name invalid";
+ case MQTT_RC_PACKET_ID_IN_USE:
+ return "Packet Identifier in use";
+ case MQTT_RC_PACKET_ID_NOT_FOUND:
+ return "Packet Identifier not found";
+ case MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED:
+ return "Receive Maximum exceeded";
+ case MQTT_RC_TOPIC_ALIAS_INVALID:
+ return "Topic Alias invalid";
+ case MQTT_RC_PACKET_TOO_LARGE:
+ return "Packet too large";
+ case MQTT_RC_MESSAGE_RATE_TOO_HIGH:
+ return "Message rate too high";
+ case MQTT_RC_QUOTA_EXCEEDED:
+ return "Quota exceeded";
+ case MQTT_RC_ADMINISTRATIVE_ACTION:
+ return "Administrative action";
+ case MQTT_RC_PAYLOAD_FORMAT_INVALID:
+ return "Payload format invalid";
+ case MQTT_RC_RETAIN_NOT_SUPPORTED:
+ return "Retain not supported";
+ case MQTT_RC_QOS_NOT_SUPPORTED:
+ return "QoS not supported";
+ case MQTT_RC_USE_ANOTHER_SERVER:
+ return "Use another server";
+ case MQTT_RC_SERVER_MOVED:
+ return "Server moved";
+ case MQTT_RC_SHARED_SUBS_NOT_SUPPORTED:
+ return "Shared Subscriptions not supported";
+ case MQTT_RC_CONNECTION_RATE_EXCEEDED:
+ return "Connection rate exceeded";
+ case MQTT_RC_MAXIMUM_CONNECT_TIME:
+ return "Maximum connect time";
+ case MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED:
+ return "Subscription identifiers not supported";
+ case MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED:
+ return "Wildcard Subscriptions not supported";
+ default:
+ return "Unknown reason";
+ }
+}
+
+
+int mosquitto_string_to_command(const char *str, int *cmd)
+{
+ if(!strcasecmp(str, "connect")){
+ *cmd = CMD_CONNECT;
+ }else if(!strcasecmp(str, "connack")){
+ *cmd = CMD_CONNACK;
+ }else if(!strcasecmp(str, "publish")){
+ *cmd = CMD_PUBLISH;
+ }else if(!strcasecmp(str, "puback")){
+ *cmd = CMD_PUBACK;
+ }else if(!strcasecmp(str, "pubrec")){
+ *cmd = CMD_PUBREC;
+ }else if(!strcasecmp(str, "pubrel")){
+ *cmd = CMD_PUBREL;
+ }else if(!strcasecmp(str, "pubcomp")){
+ *cmd = CMD_PUBCOMP;
+ }else if(!strcasecmp(str, "subscribe")){
+ *cmd = CMD_SUBSCRIBE;
+ }else if(!strcasecmp(str, "unsubscribe")){
+ *cmd = CMD_UNSUBSCRIBE;
+ }else if(!strcasecmp(str, "disconnect")){
+ *cmd = CMD_DISCONNECT;
+ }else if(!strcasecmp(str, "auth")){
+ *cmd = CMD_AUTH;
+ }else if(!strcasecmp(str, "will")){
+ *cmd = CMD_WILL;
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count)
+{
+ int len;
+ int hier_count = 1;
+ int start, stop;
+ int hier;
+ int tlen;
+ int i, j;
+
+ if(!subtopic || !topics || !count) return MOSQ_ERR_INVAL;
+
+ len = strlen(subtopic);
+
+ for(i=0; i<len; i++){
+ if(subtopic[i] == '/'){
+ if(i > len-1){
+ /* Separator at end of line */
+ }else{
+ hier_count++;
+ }
+ }
+ }
+
+ (*topics) = mosquitto__calloc(hier_count, sizeof(char *));
+ if(!(*topics)) return MOSQ_ERR_NOMEM;
+
+ start = 0;
+ stop = 0;
+ hier = 0;
+
+ for(i=0; i<len+1; i++){
+ if(subtopic[i] == '/' || subtopic[i] == '\0'){
+ stop = i;
+ if(start != stop){
+ tlen = stop-start + 1;
+ (*topics)[hier] = mosquitto__calloc(tlen, sizeof(char));
+ if(!(*topics)[hier]){
+ for(j=0; j<hier; j++){
+ mosquitto__free((*topics)[j]);
+ }
+ mosquitto__free((*topics));
+ return MOSQ_ERR_NOMEM;
+ }
+ for(j=start; j<stop; j++){
+ (*topics)[hier][j-start] = subtopic[j];
+ }
+ }
+ start = i+1;
+ hier++;
+ }
+ }
+
+ *count = hier_count;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_sub_topic_tokens_free(char ***topics, int count)
+{
+ int i;
+
+ if(!topics || !(*topics) || count<1) return MOSQ_ERR_INVAL;
+
+ for(i=0; i<count; i++){
+ mosquitto__free((*topics)[i]);
+ }
+ mosquitto__free(*topics);
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/mosquitto_internal.h b/libs/libmosquitto/src/mosquitto_internal.h
new file mode 100644
index 0000000000..ff656a4375
--- /dev/null
+++ b/libs/libmosquitto/src/mosquitto_internal.h
@@ -0,0 +1,358 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+ Tatsuzo Osawa - Add epoll.
+*/
+
+#ifndef MOSQUITTO_INTERNAL_H
+#define MOSQUITTO_INTERNAL_H
+
+#include "config.h"
+
+#ifdef WIN32
+# include <winsock2.h>
+#endif
+
+#ifdef WITH_TLS
+# include <openssl/ssl.h>
+#else
+# include <time.h>
+#endif
+#include <stdlib.h>
+
+#if defined(WITH_THREADING) && !defined(WITH_BROKER)
+# include <pthread.h>
+#else
+# include <dummypthread.h>
+#endif
+
+#ifdef WITH_SRV
+# include <ares.h>
+#endif
+
+#ifdef WIN32
+# if _MSC_VER < 1600
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+ typedef unsigned long long uint64_t;
+# else
+# include <stdint.h>
+# endif
+#else
+# include <stdint.h>
+#endif
+
+#include "mosquitto.h"
+#include "time_mosq.h"
+#ifdef WITH_BROKER
+# ifdef __linux__
+# include <netdb.h>
+# endif
+# include "uthash.h"
+struct mosquitto_client_msg;
+#endif
+
+#ifdef WIN32
+typedef SOCKET mosq_sock_t;
+#else
+typedef int mosq_sock_t;
+#endif
+
+enum mosquitto_msg_direction {
+ mosq_md_in = 0,
+ mosq_md_out = 1
+};
+
+enum mosquitto_msg_state {
+ mosq_ms_invalid = 0,
+ mosq_ms_publish_qos0 = 1,
+ mosq_ms_publish_qos1 = 2,
+ mosq_ms_wait_for_puback = 3,
+ mosq_ms_publish_qos2 = 4,
+ mosq_ms_wait_for_pubrec = 5,
+ mosq_ms_resend_pubrel = 6,
+ mosq_ms_wait_for_pubrel = 7,
+ mosq_ms_resend_pubcomp = 8,
+ mosq_ms_wait_for_pubcomp = 9,
+ mosq_ms_send_pubrec = 10,
+ mosq_ms_queued = 11
+};
+
+enum mosquitto_client_state {
+ mosq_cs_new = 0,
+ mosq_cs_connected = 1,
+ mosq_cs_disconnecting = 2,
+ mosq_cs_connect_async = 3,
+ mosq_cs_connect_pending = 4,
+ mosq_cs_connect_srv = 5,
+ mosq_cs_disconnect_ws = 6,
+ mosq_cs_disconnected = 7,
+ mosq_cs_socks5_new = 8,
+ mosq_cs_socks5_start = 9,
+ mosq_cs_socks5_request = 10,
+ mosq_cs_socks5_reply = 11,
+ mosq_cs_socks5_auth_ok = 12,
+ mosq_cs_socks5_userpass_reply = 13,
+ mosq_cs_socks5_send_userpass = 14,
+ mosq_cs_expiring = 15,
+ mosq_cs_connecting = 16,
+ mosq_cs_duplicate = 17, /* client that has been taken over by another with the same id */
+ mosq_cs_disconnect_with_will = 18,
+ mosq_cs_disused = 19, /* client that has been added to the disused list to be freed */
+ mosq_cs_authenticating = 20, /* Client has sent CONNECT but is still undergoing extended authentication */
+ mosq_cs_reauthenticating = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */
+};
+
+enum mosquitto__protocol {
+ mosq_p_invalid = 0,
+ mosq_p_mqtt31 = 1,
+ mosq_p_mqtt311 = 2,
+ mosq_p_mqtts = 3,
+ mosq_p_mqtt5 = 5,
+};
+
+enum mosquitto__threaded_state {
+ mosq_ts_none, /* No threads in use */
+ mosq_ts_self, /* Threads started by libmosquitto */
+ mosq_ts_external /* Threads started by external code */
+};
+
+enum mosquitto__transport {
+ mosq_t_invalid = 0,
+ mosq_t_tcp = 1,
+ mosq_t_ws = 2,
+ mosq_t_sctp = 3
+};
+
+
+struct mosquitto__alias{
+ char *topic;
+ uint16_t alias;
+};
+
+struct session_expiry_list {
+ struct mosquitto *context;
+ struct session_expiry_list *prev;
+ struct session_expiry_list *next;
+};
+
+struct mosquitto__packet{
+ uint8_t *payload;
+ struct mosquitto__packet *next;
+ uint32_t remaining_mult;
+ uint32_t remaining_length;
+ uint32_t packet_length;
+ uint32_t to_process;
+ uint32_t pos;
+ uint16_t mid;
+ uint8_t command;
+ int8_t remaining_count;
+};
+
+struct mosquitto_message_all{
+ struct mosquitto_message_all *next;
+ struct mosquitto_message_all *prev;
+ mosquitto_property *properties;
+ time_t timestamp;
+ //enum mosquitto_msg_direction direction;
+ enum mosquitto_msg_state state;
+ bool dup;
+ struct mosquitto_message msg;
+ uint32_t expiry_interval;
+};
+
+#ifdef WITH_TLS
+enum mosquitto__keyform {
+ mosq_k_pem = 0,
+ mosq_k_engine = 1,
+};
+#endif
+
+struct will_delay_list {
+ struct mosquitto *context;
+ struct will_delay_list *prev;
+ struct will_delay_list *next;
+};
+
+struct mosquitto_msg_data{
+#ifdef WITH_BROKER
+ struct mosquitto_client_msg *inflight;
+ struct mosquitto_client_msg *queued;
+ unsigned long msg_bytes;
+ unsigned long msg_bytes12;
+ int msg_count;
+ int msg_count12;
+#else
+ struct mosquitto_message_all *inflight;
+ int queue_len;
+# ifdef WITH_THREADING
+ pthread_mutex_t mutex;
+# endif
+#endif
+ int inflight_quota;
+ uint16_t inflight_maximum;
+};
+
+
+struct mosquitto {
+ mosq_sock_t sock;
+#ifndef WITH_BROKER
+ mosq_sock_t sockpairR, sockpairW;
+#endif
+#if defined(__GLIBC__) && defined(WITH_ADNS)
+ struct gaicb *adns; /* For getaddrinfo_a */
+#endif
+ enum mosquitto__protocol protocol;
+ char *address;
+ char *id;
+ char *username;
+ char *password;
+ uint16_t keepalive;
+ uint16_t last_mid;
+ enum mosquitto_client_state state;
+ time_t last_msg_in;
+ time_t next_msg_out;
+ time_t ping_t;
+ struct mosquitto__packet in_packet;
+ struct mosquitto__packet *current_out_packet;
+ struct mosquitto__packet *out_packet;
+ struct mosquitto_message_all *will;
+ struct mosquitto__alias *aliases;
+ struct will_delay_list *will_delay_entry;
+ uint32_t maximum_packet_size;
+ int alias_count;
+ uint32_t will_delay_interval;
+ time_t will_delay_time;
+#ifdef WITH_TLS
+ SSL *ssl;
+ SSL_CTX *ssl_ctx;
+ char *tls_cafile;
+ char *tls_capath;
+ char *tls_certfile;
+ char *tls_keyfile;
+ int (*tls_pw_callback)(char *buf, int size, int rwflag, void *userdata);
+ char *tls_version;
+ char *tls_ciphers;
+ char *tls_psk;
+ char *tls_psk_identity;
+ int tls_cert_reqs;
+ bool tls_insecure;
+ bool ssl_ctx_defaults;
+ bool tls_ocsp_required;
+ char *tls_engine;
+ char *tls_engine_kpass_sha1;
+ enum mosquitto__keyform tls_keyform;
+ char *tls_alpn;
+#endif
+ bool want_write;
+ bool want_connect;
+#if defined(WITH_THREADING) && !defined(WITH_BROKER)
+ pthread_mutex_t callback_mutex;
+ pthread_mutex_t log_callback_mutex;
+ pthread_mutex_t msgtime_mutex;
+ pthread_mutex_t out_packet_mutex;
+ pthread_mutex_t current_out_packet_mutex;
+ pthread_mutex_t state_mutex;
+ pthread_mutex_t mid_mutex;
+ pthread_t thread_id;
+#endif
+ bool clean_start;
+ uint32_t session_expiry_interval;
+ time_t session_expiry_time;
+#ifdef WITH_BROKER
+ bool removed_from_by_id; /* True if removed from by_id hash */
+ bool is_dropping;
+ bool is_bridge;
+ struct mosquitto__bridge *bridge;
+ struct mosquitto_msg_data msgs_in;
+ struct mosquitto_msg_data msgs_out;
+ struct mosquitto__acl_user *acl_list;
+ struct mosquitto__listener *listener;
+ struct mosquitto__packet *out_packet_last;
+ struct mosquitto__subhier **subs;
+ struct mosquitto__subshared_ref **shared_subs;
+ char *auth_method;
+ int sub_count;
+ int shared_sub_count;
+ int pollfd_index;
+# ifdef WITH_WEBSOCKETS
+# if defined(LWS_LIBRARY_VERSION_NUMBER)
+ struct lws *wsi;
+# else
+ struct libwebsocket_context *ws_context;
+ struct libwebsocket *wsi;
+# endif
+# endif
+ bool ws_want_write;
+ bool assigned_id;
+#else
+# ifdef WITH_SOCKS
+ char *socks5_host;
+ int socks5_port;
+ char *socks5_username;
+ char *socks5_password;
+# endif
+ void *userdata;
+ bool in_callback;
+ struct mosquitto_msg_data msgs_in;
+ struct mosquitto_msg_data msgs_out;
+ void (*on_connect)(struct mosquitto *, void *userdata, int rc);
+ void (*on_connect_with_flags)(struct mosquitto *, void *userdata, int rc, int flags);
+ void (*on_connect_v5)(struct mosquitto *, void *userdata, int rc, int flags, const mosquitto_property *props);
+ void (*on_disconnect)(struct mosquitto *, void *userdata, int rc);
+ void (*on_disconnect_v5)(struct mosquitto *, void *userdata, int rc, const mosquitto_property *props);
+ void (*on_publish)(struct mosquitto *, void *userdata, int mid);
+ void (*on_publish_v5)(struct mosquitto *, void *userdata, int mid, int reason_code, const mosquitto_property *props);
+ void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message);
+ void (*on_message_v5)(struct mosquitto *, void *userdata, const struct mosquitto_message *message, const mosquitto_property *props);
+ void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos);
+ void (*on_subscribe_v5)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos, const mosquitto_property *props);
+ void (*on_unsubscribe)(struct mosquitto *, void *userdata, int mid);
+ void (*on_unsubscribe_v5)(struct mosquitto *, void *userdata, int mid, const mosquitto_property *props);
+ void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str);
+ //void (*on_error)();
+ char *host;
+ int port;
+ char *bind_address;
+ unsigned int reconnect_delay;
+ unsigned int reconnect_delay_max;
+ bool reconnect_exponential_backoff;
+ char threaded;
+ struct mosquitto__packet *out_packet_last;
+# ifdef WITH_SRV
+ ares_channel achan;
+# endif
+ uint16_t send_maximum;
+ uint16_t receive_maximum;
+#endif
+ uint8_t maximum_qos;
+
+#ifdef WITH_BROKER
+ UT_hash_handle hh_id;
+ UT_hash_handle hh_sock;
+ struct mosquitto *for_free_next;
+ struct session_expiry_list *expiry_list_item;
+#endif
+#ifdef WITH_EPOLL
+ uint32_t events;
+#endif
+};
+
+#define STREMPTY(str) (str[0] == '\0')
+
+void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties);
+
+#endif
+
diff --git a/libs/libmosquitto/src/mqtt_protocol.h b/libs/libmosquitto/src/mqtt_protocol.h
new file mode 100644
index 0000000000..672d50b767
--- /dev/null
+++ b/libs/libmosquitto/src/mqtt_protocol.h
@@ -0,0 +1,158 @@
+/*
+Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef MQTT_PROTOCOL_H
+#define MQTT_PROTOCOL_H
+
+#define PROTOCOL_NAME_v31 "MQIsdp"
+#define PROTOCOL_VERSION_v31 3
+
+#define PROTOCOL_NAME "MQTT"
+
+#define PROTOCOL_VERSION_v311 4
+#define PROTOCOL_VERSION_v5 5
+
+
+/* Message types */
+#define CMD_CONNECT 0x10
+#define CMD_CONNACK 0x20
+#define CMD_PUBLISH 0x30
+#define CMD_PUBACK 0x40
+#define CMD_PUBREC 0x50
+#define CMD_PUBREL 0x60
+#define CMD_PUBCOMP 0x70
+#define CMD_SUBSCRIBE 0x80
+#define CMD_SUBACK 0x90
+#define CMD_UNSUBSCRIBE 0xA0
+#define CMD_UNSUBACK 0xB0
+#define CMD_PINGREQ 0xC0
+#define CMD_PINGRESP 0xD0
+#define CMD_DISCONNECT 0xE0
+#define CMD_AUTH 0xF0
+
+/* Mosquitto only: for distinguishing CONNECT and WILL properties */
+#define CMD_WILL 0x100
+
+enum mqtt311_connack_codes {
+ CONNACK_ACCEPTED = 0,
+ CONNACK_REFUSED_PROTOCOL_VERSION = 1,
+ CONNACK_REFUSED_IDENTIFIER_REJECTED = 2,
+ CONNACK_REFUSED_SERVER_UNAVAILABLE = 3,
+ CONNACK_REFUSED_BAD_USERNAME_PASSWORD = 4,
+ CONNACK_REFUSED_NOT_AUTHORIZED = 5,
+};
+
+
+enum mqtt5_return_codes {
+ MQTT_RC_SUCCESS = 0, /* CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH */
+ MQTT_RC_NORMAL_DISCONNECTION = 0, /* DISCONNECT */
+ MQTT_RC_GRANTED_QOS0 = 0, /* SUBACK */
+ MQTT_RC_GRANTED_QOS1 = 1, /* SUBACK */
+ MQTT_RC_GRANTED_QOS2 = 2, /* SUBACK */
+ MQTT_RC_DISCONNECT_WITH_WILL_MSG = 4, /* DISCONNECT */
+ MQTT_RC_NO_MATCHING_SUBSCRIBERS = 16, /* PUBACK, PUBREC */
+ MQTT_RC_NO_SUBSCRIPTION_EXISTED = 17, /* UNSUBACK */
+ MQTT_RC_CONTINUE_AUTHENTICATION = 24, /* AUTH */
+ MQTT_RC_REAUTHENTICATE = 25, /* AUTH */
+
+ MQTT_RC_UNSPECIFIED = 128, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */
+ MQTT_RC_MALFORMED_PACKET = 129, /* CONNACK, DISCONNECT */
+ MQTT_RC_PROTOCOL_ERROR = 130, /* DISCONNECT */
+ MQTT_RC_IMPLEMENTATION_SPECIFIC = 131, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */
+ MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION = 132, /* CONNACK */
+ MQTT_RC_CLIENTID_NOT_VALID = 133, /* CONNACK */
+ MQTT_RC_BAD_USERNAME_OR_PASSWORD = 134, /* CONNACK */
+ MQTT_RC_NOT_AUTHORIZED = 135, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */
+ MQTT_RC_SERVER_UNAVAILABLE = 136, /* CONNACK */
+ MQTT_RC_SERVER_BUSY = 137, /* CONNACK, DISCONNECT */
+ MQTT_RC_BANNED = 138, /* CONNACK */
+ MQTT_RC_SERVER_SHUTTING_DOWN = 139, /* DISCONNECT */
+ MQTT_RC_BAD_AUTHENTICATION_METHOD = 140, /* CONNACK */
+ MQTT_RC_KEEP_ALIVE_TIMEOUT = 141, /* DISCONNECT */
+ MQTT_RC_SESSION_TAKEN_OVER = 142, /* DISCONNECT */
+ MQTT_RC_TOPIC_FILTER_INVALID = 143, /* SUBACK, UNSUBACK, DISCONNECT */
+ MQTT_RC_TOPIC_NAME_INVALID = 144, /* CONNACK, PUBACK, PUBREC, DISCONNECT */
+ MQTT_RC_PACKET_ID_IN_USE = 145, /* PUBACK, SUBACK, UNSUBACK */
+ MQTT_RC_PACKET_ID_NOT_FOUND = 146, /* PUBREL, PUBCOMP */
+ MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED = 147, /* DISCONNECT */
+ MQTT_RC_TOPIC_ALIAS_INVALID = 148, /* DISCONNECT */
+ MQTT_RC_PACKET_TOO_LARGE = 149, /* CONNACK, PUBACK, PUBREC, DISCONNECT */
+ MQTT_RC_MESSAGE_RATE_TOO_HIGH = 150, /* DISCONNECT */
+ MQTT_RC_QUOTA_EXCEEDED = 151, /* PUBACK, PUBREC, SUBACK, DISCONNECT */
+ MQTT_RC_ADMINISTRATIVE_ACTION = 152, /* DISCONNECT */
+ MQTT_RC_PAYLOAD_FORMAT_INVALID = 153, /* CONNACK, DISCONNECT */
+ MQTT_RC_RETAIN_NOT_SUPPORTED = 154, /* CONNACK, DISCONNECT */
+ MQTT_RC_QOS_NOT_SUPPORTED = 155, /* CONNACK, DISCONNECT */
+ MQTT_RC_USE_ANOTHER_SERVER = 156, /* CONNACK, DISCONNECT */
+ MQTT_RC_SERVER_MOVED = 157, /* CONNACK, DISCONNECT */
+ MQTT_RC_SHARED_SUBS_NOT_SUPPORTED = 158, /* SUBACK, DISCONNECT */
+ MQTT_RC_CONNECTION_RATE_EXCEEDED = 159, /* CONNACK, DISCONNECT */
+ MQTT_RC_MAXIMUM_CONNECT_TIME = 160, /* DISCONNECT */
+ MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED = 161, /* SUBACK, DISCONNECT */
+ MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED = 162, /* SUBACK, DISCONNECT */
+};
+
+enum mqtt5_property {
+ MQTT_PROP_PAYLOAD_FORMAT_INDICATOR = 1, /* Byte : PUBLISH, Will Properties */
+ MQTT_PROP_MESSAGE_EXPIRY_INTERVAL = 2, /* 4 byte int : PUBLISH, Will Properties */
+ MQTT_PROP_CONTENT_TYPE = 3, /* UTF-8 string : PUBLISH, Will Properties */
+ MQTT_PROP_RESPONSE_TOPIC = 8, /* UTF-8 string : PUBLISH, Will Properties */
+ MQTT_PROP_CORRELATION_DATA = 9, /* Binary Data : PUBLISH, Will Properties */
+ MQTT_PROP_SUBSCRIPTION_IDENTIFIER = 11, /* Variable byte int : PUBLISH, SUBSCRIBE */
+ MQTT_PROP_SESSION_EXPIRY_INTERVAL = 17, /* 4 byte int : CONNECT, CONNACK, DISCONNECT */
+ MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER = 18, /* UTF-8 string : CONNACK */
+ MQTT_PROP_SERVER_KEEP_ALIVE = 19, /* 2 byte int : CONNACK */
+ MQTT_PROP_AUTHENTICATION_METHOD = 21, /* UTF-8 string : CONNECT, CONNACK, AUTH */
+ MQTT_PROP_AUTHENTICATION_DATA = 22, /* Binary Data : CONNECT, CONNACK, AUTH */
+ MQTT_PROP_REQUEST_PROBLEM_INFORMATION = 23, /* Byte : CONNECT */
+ MQTT_PROP_WILL_DELAY_INTERVAL = 24, /* 4 byte int : Will properties */
+ MQTT_PROP_REQUEST_RESPONSE_INFORMATION = 25,/* Byte : CONNECT */
+ MQTT_PROP_RESPONSE_INFORMATION = 26, /* UTF-8 string : CONNACK */
+ MQTT_PROP_SERVER_REFERENCE = 28, /* UTF-8 string : CONNACK, DISCONNECT */
+ MQTT_PROP_REASON_STRING = 31, /* UTF-8 string : All except Will properties */
+ MQTT_PROP_RECEIVE_MAXIMUM = 33, /* 2 byte int : CONNECT, CONNACK */
+ MQTT_PROP_TOPIC_ALIAS_MAXIMUM = 34, /* 2 byte int : CONNECT, CONNACK */
+ MQTT_PROP_TOPIC_ALIAS = 35, /* 2 byte int : PUBLISH */
+ MQTT_PROP_MAXIMUM_QOS = 36, /* Byte : CONNACK */
+ MQTT_PROP_RETAIN_AVAILABLE = 37, /* Byte : CONNACK */
+ MQTT_PROP_USER_PROPERTY = 38, /* UTF-8 string pair : All */
+ MQTT_PROP_MAXIMUM_PACKET_SIZE = 39, /* 4 byte int : CONNECT, CONNACK */
+ MQTT_PROP_WILDCARD_SUB_AVAILABLE = 40, /* Byte : CONNACK */
+ MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE = 41, /* Byte : CONNACK */
+ MQTT_PROP_SHARED_SUB_AVAILABLE = 42, /* Byte : CONNACK */
+};
+
+enum mqtt5_property_type {
+ MQTT_PROP_TYPE_BYTE = 1,
+ MQTT_PROP_TYPE_INT16 = 2,
+ MQTT_PROP_TYPE_INT32 = 3,
+ MQTT_PROP_TYPE_VARINT = 4,
+ MQTT_PROP_TYPE_BINARY = 5,
+ MQTT_PROP_TYPE_STRING = 6,
+ MQTT_PROP_TYPE_STRING_PAIR = 7
+};
+
+enum mqtt5_sub_options {
+ MQTT_SUB_OPT_NO_LOCAL = 0x04,
+ MQTT_SUB_OPT_RETAIN_AS_PUBLISHED = 0x08,
+ MQTT_SUB_OPT_SEND_RETAIN_ALWAYS = 0x00,
+ MQTT_SUB_OPT_SEND_RETAIN_NEW = 0x10,
+ MQTT_SUB_OPT_SEND_RETAIN_NEVER = 0x20,
+};
+
+#define MQTT_MAX_PAYLOAD 268435455
+
+#endif
diff --git a/libs/libmosquitto/src/net_mosq.c b/libs/libmosquitto/src/net_mosq.c
new file mode 100644
index 0000000000..f207e32aea
--- /dev/null
+++ b/libs/libmosquitto/src/net_mosq.c
@@ -0,0 +1,1090 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#define _GNU_SOURCE
+#include <netdb.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#ifdef __ANDROID__
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <sys/endian.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef __QNX__
+#include <net/netbyte.h>
+#endif
+
+#ifdef WITH_TLS
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/ui.h>
+#include <tls_mosq.h>
+#endif
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+# ifdef WITH_WEBSOCKETS
+# include <libwebsockets.h>
+# endif
+#else
+# include "read_handle.h"
+#endif
+
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "time_mosq.h"
+#include "util_mosq.h"
+
+#ifdef WITH_TLS
+int tls_ex_index_mosq = -1;
+UI_METHOD *_ui_method = NULL;
+
+/* Functions taken from OpenSSL s_server/s_client */
+static int ui_open(UI *ui)
+{
+ return UI_method_get_opener(UI_OpenSSL())(ui);
+}
+
+static int ui_read(UI *ui, UI_STRING *uis)
+{
+ return UI_method_get_reader(UI_OpenSSL())(ui, uis);
+}
+
+static int ui_write(UI *ui, UI_STRING *uis)
+{
+ return UI_method_get_writer(UI_OpenSSL())(ui, uis);
+}
+
+static int ui_close(UI *ui)
+{
+ return UI_method_get_closer(UI_OpenSSL())(ui);
+}
+
+static void setup_ui_method(void)
+{
+ _ui_method = UI_create_method("OpenSSL application user interface");
+ UI_method_set_opener(_ui_method, ui_open);
+ UI_method_set_reader(_ui_method, ui_read);
+ UI_method_set_writer(_ui_method, ui_write);
+ UI_method_set_closer(_ui_method, ui_close);
+}
+
+static void cleanup_ui_method(void)
+{
+ if(_ui_method){
+ UI_destroy_method(_ui_method);
+ _ui_method = NULL;
+ }
+}
+
+UI_METHOD *net__get_ui_method(void)
+{
+ return _ui_method;
+}
+#endif
+
+int net__init(void)
+{
+#ifdef WIN32
+ WSADATA wsaData;
+ if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
+ return MOSQ_ERR_UNKNOWN;
+ }
+#endif
+
+#ifdef WITH_SRV
+ ares_library_init(ARES_LIB_INIT_ALL);
+#endif
+
+#ifdef WITH_TLS
+# if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+# else
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
+ | OPENSSL_INIT_ADD_ALL_DIGESTS \
+ | OPENSSL_INIT_LOAD_CONFIG, NULL);
+# endif
+#if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_load_builtin_engines();
+#endif
+ setup_ui_method();
+ if(tls_ex_index_mosq == -1){
+ tls_ex_index_mosq = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
+ }
+#endif
+ return MOSQ_ERR_SUCCESS;
+}
+
+void net__cleanup(void)
+{
+#ifdef WITH_TLS
+# if OPENSSL_VERSION_NUMBER < 0x10100000L
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+ ERR_remove_thread_state(NULL);
+ EVP_cleanup();
+
+# if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_cleanup();
+# endif
+# endif
+
+ CONF_modules_unload(1);
+ cleanup_ui_method();
+#endif
+
+#ifdef WITH_SRV
+ ares_library_cleanup();
+#endif
+
+#ifdef WIN32
+ WSACleanup();
+#endif
+}
+
+
+/* Close a socket associated with a context and set it to -1.
+ * Returns 1 on failure (context is NULL)
+ * Returns 0 on success.
+ */
+#ifdef WITH_BROKER
+int net__socket_close(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+int net__socket_close(struct mosquitto *mosq)
+#endif
+{
+ int rc = 0;
+
+ assert(mosq);
+#ifdef WITH_TLS
+#ifdef WITH_WEBSOCKETS
+ if(!mosq->wsi)
+#endif
+ {
+ if(mosq->ssl){
+ SSL_shutdown(mosq->ssl);
+ SSL_free(mosq->ssl);
+ mosq->ssl = NULL;
+ }
+ }
+#endif
+
+#ifdef WITH_WEBSOCKETS
+ if(mosq->wsi)
+ {
+ if(mosq->state != mosq_cs_disconnecting){
+ context__set_state(mosq, mosq_cs_disconnect_ws);
+ }
+ libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
+ }else
+#endif
+ {
+ if(mosq->sock != INVALID_SOCKET){
+#ifdef WITH_BROKER
+ HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
+#endif
+ rc = COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ }
+ }
+
+#ifdef WITH_BROKER
+ if(mosq->listener){
+ mosq->listener->client_count--;
+ }
+#endif
+
+ return rc;
+}
+
+
+#ifdef FINAL_WITH_TLS_PSK
+static unsigned int psk_client_callback(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ struct mosquitto *mosq;
+ int len;
+
+ UNUSED(hint);
+
+ mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq);
+ if(!mosq) return 0;
+
+ snprintf(identity, max_identity_len, "%s", mosq->tls_psk_identity);
+
+ len = mosquitto__hex2bin(mosq->tls_psk, psk, max_psk_len);
+ if (len < 0) return 0;
+ return len;
+}
+#endif
+
+#if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS)
+/* Async connect, part 1 (dns lookup) */
+int net__try_connect_step1(struct mosquitto *mosq, const char *host)
+{
+ int s;
+ void *sevp = NULL;
+ struct addrinfo *hints;
+
+ if(mosq->adns){
+ gai_cancel(mosq->adns);
+ mosquitto__free((struct addrinfo *)mosq->adns->ar_request);
+ mosquitto__free(mosq->adns);
+ }
+ mosq->adns = mosquitto__calloc(1, sizeof(struct gaicb));
+ if(!mosq->adns){
+ return MOSQ_ERR_NOMEM;
+ }
+
+ hints = mosquitto__calloc(1, sizeof(struct addrinfo));
+ if(!hints){
+ mosquitto__free(mosq->adns);
+ mosq->adns = NULL;
+ return MOSQ_ERR_NOMEM;
+ }
+
+ hints->ai_family = AF_UNSPEC;
+ hints->ai_socktype = SOCK_STREAM;
+
+ mosq->adns->ar_name = host;
+ mosq->adns->ar_request = hints;
+
+ s = getaddrinfo_a(GAI_NOWAIT, &mosq->adns, 1, sevp);
+ if(s){
+ errno = s;
+ if(mosq->adns){
+ mosquitto__free((struct addrinfo *)mosq->adns->ar_request);
+ mosquitto__free(mosq->adns);
+ mosq->adns = NULL;
+ }
+ return MOSQ_ERR_EAI;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+/* Async connect part 2, the connection. */
+int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock)
+{
+ struct addrinfo *ainfo, *rp;
+ int rc;
+
+ ainfo = mosq->adns->ar_result;
+
+ for(rp = ainfo; rp != NULL; rp = rp->ai_next){
+ *sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if(*sock == INVALID_SOCKET) continue;
+
+ if(rp->ai_family == AF_INET){
+ ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port);
+ }else if(rp->ai_family == AF_INET6){
+ ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port);
+ }else{
+ COMPAT_CLOSE(*sock);
+ *sock = INVALID_SOCKET;
+ continue;
+ }
+
+ /* Set non-blocking */
+ if(net__socket_nonblock(sock)){
+ continue;
+ }
+
+ rc = connect(*sock, rp->ai_addr, rp->ai_addrlen);
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){
+ if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){
+ rc = MOSQ_ERR_CONN_PENDING;
+ }
+
+ /* Set non-blocking */
+ if(net__socket_nonblock(sock)){
+ continue;
+ }
+ break;
+ }
+
+ COMPAT_CLOSE(*sock);
+ *sock = INVALID_SOCKET;
+ }
+ freeaddrinfo(mosq->adns->ar_result);
+ mosq->adns->ar_result = NULL;
+
+ mosquitto__free((struct addrinfo *)mosq->adns->ar_request);
+ mosquitto__free(mosq->adns);
+ mosq->adns = NULL;
+
+ if(!rp){
+ return MOSQ_ERR_ERRNO;
+ }
+
+ return rc;
+}
+
+#endif
+
+
+int net__try_connect(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking)
+{
+ struct addrinfo hints;
+ struct addrinfo *ainfo, *rp;
+ struct addrinfo *ainfo_bind, *rp_bind;
+ int s;
+ int rc = MOSQ_ERR_SUCCESS;
+#ifdef WIN32
+ uint32_t val = 1;
+#endif
+
+ *sock = INVALID_SOCKET;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ s = getaddrinfo(host, NULL, &hints, &ainfo);
+ if(s){
+ errno = s;
+ return MOSQ_ERR_EAI;
+ }
+
+ if(bind_address){
+ s = getaddrinfo(bind_address, NULL, &hints, &ainfo_bind);
+ if(s){
+ freeaddrinfo(ainfo);
+ errno = s;
+ return MOSQ_ERR_EAI;
+ }
+ }
+
+ for(rp = ainfo; rp != NULL; rp = rp->ai_next){
+ *sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if(*sock == INVALID_SOCKET) continue;
+
+ if(rp->ai_family == AF_INET){
+ ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port);
+ }else if(rp->ai_family == AF_INET6){
+ ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port);
+ }else{
+ COMPAT_CLOSE(*sock);
+ *sock = INVALID_SOCKET;
+ continue;
+ }
+
+ if(bind_address){
+ for(rp_bind = ainfo_bind; rp_bind != NULL; rp_bind = rp_bind->ai_next){
+ if(bind(*sock, rp_bind->ai_addr, rp_bind->ai_addrlen) == 0){
+ break;
+ }
+ }
+ if(!rp_bind){
+ COMPAT_CLOSE(*sock);
+ *sock = INVALID_SOCKET;
+ continue;
+ }
+ }
+
+ if(!blocking){
+ /* Set non-blocking */
+ if(net__socket_nonblock(sock)){
+ continue;
+ }
+ }
+
+ rc = connect(*sock, rp->ai_addr, rp->ai_addrlen);
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){
+ if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){
+ rc = MOSQ_ERR_CONN_PENDING;
+ }
+
+ if(blocking){
+ /* Set non-blocking */
+ if(net__socket_nonblock(sock)){
+ continue;
+ }
+ }
+ break;
+ }
+
+ COMPAT_CLOSE(*sock);
+ *sock = INVALID_SOCKET;
+ }
+ freeaddrinfo(ainfo);
+ if(bind_address){
+ freeaddrinfo(ainfo_bind);
+ }
+ if(!rp){
+ return MOSQ_ERR_ERRNO;
+ }
+ return rc;
+}
+
+
+#ifdef WITH_TLS
+void net__print_ssl_error(struct mosquitto *mosq)
+{
+ char ebuf[256];
+ unsigned long e;
+
+ e = ERR_get_error();
+ while(e){
+ log__printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error: %s", ERR_error_string(e, ebuf));
+ e = ERR_get_error();
+ }
+}
+
+
+int net__socket_connect_tls(struct mosquitto *mosq)
+{
+ int ret, err;
+
+ ERR_clear_error();
+ long res;
+ if (mosq->tls_ocsp_required) {
+ // Note: OCSP is available in all currently supported OpenSSL versions.
+ if ((res=SSL_set_tlsext_status_type(mosq->ssl, TLSEXT_STATUSTYPE_ocsp)) != 1) {
+ log__printf(mosq, MOSQ_LOG_ERR, "Could not activate OCSP (error: %ld)", res);
+ return MOSQ_ERR_OCSP;
+ }
+ if ((res=SSL_CTX_set_tlsext_status_cb(mosq->ssl_ctx, mosquitto__verify_ocsp_status_cb)) != 1) {
+ log__printf(mosq, MOSQ_LOG_ERR, "Could not activate OCSP (error: %ld)", res);
+ return MOSQ_ERR_OCSP;
+ }
+ if ((res=SSL_CTX_set_tlsext_status_arg(mosq->ssl_ctx, mosq)) != 1) {
+ log__printf(mosq, MOSQ_LOG_ERR, "Could not activate OCSP (error: %ld)", res);
+ return MOSQ_ERR_OCSP;
+ }
+ }
+
+ ret = SSL_connect(mosq->ssl);
+ if(ret != 1) {
+ err = SSL_get_error(mosq->ssl, ret);
+ if (err == SSL_ERROR_SYSCALL) {
+ mosq->want_connect = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ if(err == SSL_ERROR_WANT_READ){
+ mosq->want_connect = true;
+ /* We always try to read anyway */
+ }else if(err == SSL_ERROR_WANT_WRITE){
+ mosq->want_write = true;
+ mosq->want_connect = true;
+ }else{
+ net__print_ssl_error(mosq);
+
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ }else{
+ mosq->want_connect = false;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+#endif
+
+
+#ifdef WITH_TLS
+static int net__init_ssl_ctx(struct mosquitto *mosq)
+{
+ int ret;
+ ENGINE *engine = NULL;
+ uint8_t tls_alpn_wire[256];
+ uint8_t tls_alpn_len;
+
+ if(mosq->ssl_ctx){
+ if(!mosq->ssl_ctx_defaults){
+ return MOSQ_ERR_SUCCESS;
+ }else if(!mosq->tls_cafile && !mosq->tls_capath && !mosq->tls_psk){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: MOSQ_OPT_SSL_CTX_WITH_DEFAULTS used without specifying cafile, capath or psk.");
+ return MOSQ_ERR_INVAL;
+ }
+ }
+
+ /* Apply default SSL_CTX settings. This is only used if MOSQ_OPT_SSL_CTX
+ * has not been set, or if both of MOSQ_OPT_SSL_CTX and
+ * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS are set. */
+ if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){
+ if(!mosq->ssl_ctx){
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ mosq->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+#else
+ mosq->ssl_ctx = SSL_CTX_new(TLS_client_method());
+#endif
+
+ if(!mosq->ssl_ctx){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ }
+
+ if(!mosq->tls_version){
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
+#ifdef SSL_OP_NO_TLSv1_3
+ }else if(!strcmp(mosq->tls_version, "tlsv1.3")){
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
+ }else if(!strcmp(mosq->tls_version, "tlsv1.2")){
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_3);
+ }else if(!strcmp(mosq->tls_version, "tlsv1.1")){
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3);
+#else
+ }else if(!strcmp(mosq->tls_version, "tlsv1.2")){
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
+ }else if(!strcmp(mosq->tls_version, "tlsv1.1")){
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
+#endif
+ }else{
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version);
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ return MOSQ_ERR_INVAL;
+ }
+
+ /* Disable compression */
+ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_COMPRESSION);
+
+ /* Set ALPN */
+ if(mosq->tls_alpn) {
+ tls_alpn_len = (uint8_t) strnlen(mosq->tls_alpn, 254);
+ tls_alpn_wire[0] = tls_alpn_len; // first byte is length of string
+ memcpy(tls_alpn_wire + 1, mosq->tls_alpn, tls_alpn_len);
+ SSL_CTX_set_alpn_protos(mosq->ssl_ctx, tls_alpn_wire, tls_alpn_len + 1);
+ }
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ /* Use even less memory per SSL connection. */
+ SSL_CTX_set_mode(mosq->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+
+#if !defined(OPENSSL_NO_ENGINE)
+ if(mosq->tls_engine){
+ engine = ENGINE_by_id(mosq->tls_engine);
+ if(!engine){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error loading %s engine\n", mosq->tls_engine);
+ COMPAT_CLOSE(mosq->sock);
+ return MOSQ_ERR_TLS;
+ }
+ if(!ENGINE_init(engine)){
+ log__printf(mosq, MOSQ_LOG_ERR, "Failed engine initialisation\n");
+ ENGINE_free(engine);
+ COMPAT_CLOSE(mosq->sock);
+ return MOSQ_ERR_TLS;
+ }
+ ENGINE_set_default(engine, ENGINE_METHOD_ALL);
+ ENGINE_free(engine); /* release the structural reference from ENGINE_by_id() */
+ }
+#endif
+
+ if(mosq->tls_ciphers){
+ ret = SSL_CTX_set_cipher_list(mosq->ssl_ctx, mosq->tls_ciphers);
+ if(ret == 0){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", mosq->tls_ciphers);
+#if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_FINISH(engine);
+#endif
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ }
+ if(mosq->tls_cafile || mosq->tls_capath){
+ ret = SSL_CTX_load_verify_locations(mosq->ssl_ctx, mosq->tls_cafile, mosq->tls_capath);
+ if(ret == 0){
+#ifdef WITH_BROKER
+ if(mosq->tls_cafile && mosq->tls_capath){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\" and bridge_capath \"%s\".", mosq->tls_cafile, mosq->tls_capath);
+ }else if(mosq->tls_cafile){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\".", mosq->tls_cafile);
+ }else{
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_capath \"%s\".", mosq->tls_capath);
+ }
+#else
+ if(mosq->tls_cafile && mosq->tls_capath){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\" and capath \"%s\".", mosq->tls_cafile, mosq->tls_capath);
+ }else if(mosq->tls_cafile){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\".", mosq->tls_cafile);
+ }else{
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check capath \"%s\".", mosq->tls_capath);
+ }
+#endif
+#if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_FINISH(engine);
+#endif
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ if(mosq->tls_cert_reqs == 0){
+ SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_NONE, NULL);
+ }else{
+ SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_PEER, mosquitto__server_certificate_verify);
+ }
+
+ if(mosq->tls_pw_callback){
+ SSL_CTX_set_default_passwd_cb(mosq->ssl_ctx, mosq->tls_pw_callback);
+ SSL_CTX_set_default_passwd_cb_userdata(mosq->ssl_ctx, mosq);
+ }
+
+ if(mosq->tls_certfile){
+ ret = SSL_CTX_use_certificate_chain_file(mosq->ssl_ctx, mosq->tls_certfile);
+ if(ret != 1){
+#ifdef WITH_BROKER
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate, check bridge_certfile \"%s\".", mosq->tls_certfile);
+#else
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate \"%s\".", mosq->tls_certfile);
+#endif
+#if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_FINISH(engine);
+#endif
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ }
+ if(mosq->tls_keyfile){
+ if(mosq->tls_keyform == mosq_k_engine){
+#if !defined(OPENSSL_NO_ENGINE)
+ UI_METHOD *ui_method = net__get_ui_method();
+ if(mosq->tls_engine_kpass_sha1){
+ if(!ENGINE_ctrl_cmd(engine, ENGINE_SECRET_MODE, ENGINE_SECRET_MODE_SHA, NULL, NULL, 0)){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set engine secret mode sha1");
+ ENGINE_FINISH(engine);
+ COMPAT_CLOSE(mosq->sock);
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ if(!ENGINE_ctrl_cmd(engine, ENGINE_PIN, 0, mosq->tls_engine_kpass_sha1, NULL, 0)){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set engine pin");
+ ENGINE_FINISH(engine);
+ COMPAT_CLOSE(mosq->sock);
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ ui_method = NULL;
+ }
+ EVP_PKEY *pkey = ENGINE_load_private_key(engine, mosq->tls_keyfile, ui_method, NULL);
+ if(!pkey){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load engine private key file \"%s\".", mosq->tls_keyfile);
+ ENGINE_FINISH(engine);
+ COMPAT_CLOSE(mosq->sock);
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ if(SSL_CTX_use_PrivateKey(mosq->ssl_ctx, pkey) <= 0){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to use engine private key file \"%s\".", mosq->tls_keyfile);
+ ENGINE_FINISH(engine);
+ COMPAT_CLOSE(mosq->sock);
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+#endif
+ }else{
+ ret = SSL_CTX_use_PrivateKey_file(mosq->ssl_ctx, mosq->tls_keyfile, SSL_FILETYPE_PEM);
+ if(ret != 1){
+#ifdef WITH_BROKER
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file, check bridge_keyfile \"%s\".", mosq->tls_keyfile);
+#else
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file \"%s\".", mosq->tls_keyfile);
+#endif
+#if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_FINISH(engine);
+#endif
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ }
+ ret = SSL_CTX_check_private_key(mosq->ssl_ctx);
+ if(ret != 1){
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Client certificate/key are inconsistent.");
+#if !defined(OPENSSL_NO_ENGINE)
+ ENGINE_FINISH(engine);
+#endif
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ }
+#ifdef FINAL_WITH_TLS_PSK
+ }else if(mosq->tls_psk){
+ SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback);
+#endif
+ }
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+#endif
+
+
+int net__socket_connect_step3(struct mosquitto *mosq, const char *host)
+{
+#ifdef WITH_TLS
+ BIO *bio;
+
+ int rc = net__init_ssl_ctx(mosq);
+ if(rc) return rc;
+
+ if(mosq->ssl_ctx){
+ if(mosq->ssl){
+ SSL_free(mosq->ssl);
+ }
+ mosq->ssl = SSL_new(mosq->ssl_ctx);
+ if(!mosq->ssl){
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+
+ SSL_set_ex_data(mosq->ssl, tls_ex_index_mosq, mosq);
+ bio = BIO_new_socket(mosq->sock, BIO_NOCLOSE);
+ if(!bio){
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ net__print_ssl_error(mosq);
+ return MOSQ_ERR_TLS;
+ }
+ SSL_set_bio(mosq->ssl, bio, bio);
+
+ /*
+ * required for the SNI resolving
+ */
+ if(SSL_set_tlsext_host_name(mosq->ssl, host) != 1) {
+ COMPAT_CLOSE(mosq->sock);
+ mosq->sock = INVALID_SOCKET;
+ return MOSQ_ERR_TLS;
+ }
+
+ if(net__socket_connect_tls(mosq)){
+ return MOSQ_ERR_TLS;
+ }
+
+ }
+#endif
+ return MOSQ_ERR_SUCCESS;
+}
+
+/* Create a socket and connect it to 'ip' on port 'port'. */
+int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking)
+{
+ mosq_sock_t sock = INVALID_SOCKET;
+ int rc, rc2;
+
+ if(!mosq || !host || !port) return MOSQ_ERR_INVAL;
+
+ rc = net__try_connect(host, port, &sock, bind_address, blocking);
+ if(rc > 0) return rc;
+
+ mosq->sock = sock;
+
+#if defined(WITH_SOCKS) && !defined(WITH_BROKER)
+ if(!mosq->socks5_host)
+#endif
+ {
+ rc2 = net__socket_connect_step3(mosq, host);
+ if(rc2) return rc2;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+ssize_t net__read(struct mosquitto *mosq, void *buf, size_t count)
+{
+#ifdef WITH_TLS
+ int ret;
+ int err;
+#endif
+ assert(mosq);
+ errno = 0;
+#ifdef WITH_TLS
+ if(mosq->ssl){
+ ERR_clear_error();
+ ret = SSL_read(mosq->ssl, buf, count);
+ if(ret <= 0){
+ err = SSL_get_error(mosq->ssl, ret);
+ if(err == SSL_ERROR_WANT_READ){
+ ret = -1;
+ errno = EAGAIN;
+ }else if(err == SSL_ERROR_WANT_WRITE){
+ ret = -1;
+ mosq->want_write = true;
+ errno = EAGAIN;
+ }else{
+ net__print_ssl_error(mosq);
+ errno = EPROTO;
+ }
+#ifdef WIN32
+ WSASetLastError(errno);
+#endif
+ }
+ return (ssize_t )ret;
+ }else{
+ /* Call normal read/recv */
+
+#endif
+
+#ifndef WIN32
+ return read(mosq->sock, buf, count);
+#else
+ return recv(mosq->sock, buf, count, 0);
+#endif
+
+#ifdef WITH_TLS
+ }
+#endif
+}
+
+ssize_t net__write(struct mosquitto *mosq, void *buf, size_t count)
+{
+#ifdef WITH_TLS
+ int ret;
+ int err;
+#endif
+ assert(mosq);
+
+ errno = 0;
+#ifdef WITH_TLS
+ if(mosq->ssl){
+ mosq->want_write = false;
+ ERR_clear_error();
+ ret = SSL_write(mosq->ssl, buf, count);
+ if(ret < 0){
+ err = SSL_get_error(mosq->ssl, ret);
+ if(err == SSL_ERROR_WANT_READ){
+ ret = -1;
+ errno = EAGAIN;
+ }else if(err == SSL_ERROR_WANT_WRITE){
+ ret = -1;
+ mosq->want_write = true;
+ errno = EAGAIN;
+ }else{
+ net__print_ssl_error(mosq);
+ errno = EPROTO;
+ }
+#ifdef WIN32
+ WSASetLastError(errno);
+#endif
+ }
+ return (ssize_t )ret;
+ }else{
+ /* Call normal write/send */
+#endif
+
+#ifndef WIN32
+ return write(mosq->sock, buf, count);
+#else
+ return send(mosq->sock, buf, count, 0);
+#endif
+
+#ifdef WITH_TLS
+ }
+#endif
+}
+
+
+int net__socket_nonblock(mosq_sock_t *sock)
+{
+#ifndef WIN32
+ int opt;
+ /* Set non-blocking */
+ opt = fcntl(*sock, F_GETFL, 0);
+ if(opt == -1){
+ COMPAT_CLOSE(*sock);
+ *sock = INVALID_SOCKET;
+ return MOSQ_ERR_ERRNO;
+ }
+ if(fcntl(*sock, F_SETFL, opt | O_NONBLOCK) == -1){
+ /* If either fcntl fails, don't want to allow this client to connect. */
+ COMPAT_CLOSE(*sock);
+ return MOSQ_ERR_ERRNO;
+ }
+#else
+ unsigned long opt = 1;
+ if(ioctlsocket(*sock, FIONBIO, &opt)){
+ COMPAT_CLOSE(*sock);
+ return MOSQ_ERR_ERRNO;
+ }
+#endif
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+#ifndef WITH_BROKER
+int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
+{
+#ifdef WIN32
+ int family[2] = {AF_INET, AF_INET6};
+ int i;
+ struct sockaddr_storage ss;
+ struct sockaddr_in *sa = (struct sockaddr_in *)&ss;
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&ss;
+ socklen_t ss_len;
+ mosq_sock_t spR, spW;
+
+ mosq_sock_t listensock;
+
+ *pairR = INVALID_SOCKET;
+ *pairW = INVALID_SOCKET;
+
+ for(i=0; i<2; i++){
+ memset(&ss, 0, sizeof(ss));
+ if(family[i] == AF_INET){
+ sa->sin_family = family[i];
+ sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sa->sin_port = 0;
+ ss_len = sizeof(struct sockaddr_in);
+ }else if(family[i] == AF_INET6){
+ sa6->sin6_family = family[i];
+ sa6->sin6_addr = in6addr_loopback;
+ sa6->sin6_port = 0;
+ ss_len = sizeof(struct sockaddr_in6);
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+
+ listensock = socket(family[i], SOCK_STREAM, IPPROTO_TCP);
+ if(listensock == -1){
+ continue;
+ }
+
+ if(bind(listensock, (struct sockaddr *)&ss, ss_len) == -1){
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+
+ if(listen(listensock, 1) == -1){
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+ memset(&ss, 0, sizeof(ss));
+ ss_len = sizeof(ss);
+ if(getsockname(listensock, (struct sockaddr *)&ss, &ss_len) < 0){
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+
+ if(family[i] == AF_INET){
+ sa->sin_family = family[i];
+ sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ ss_len = sizeof(struct sockaddr_in);
+ }else if(family[i] == AF_INET6){
+ sa6->sin6_family = family[i];
+ sa6->sin6_addr = in6addr_loopback;
+ ss_len = sizeof(struct sockaddr_in6);
+ }
+
+ spR = socket(family[i], SOCK_STREAM, IPPROTO_TCP);
+ if(spR == -1){
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+ if(net__socket_nonblock(&spR)){
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+ if(connect(spR, (struct sockaddr *)&ss, ss_len) < 0){
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){
+ COMPAT_CLOSE(spR);
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+ }
+ spW = accept(listensock, NULL, 0);
+ if(spW == -1){
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){
+ COMPAT_CLOSE(spR);
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+ }
+
+ if(net__socket_nonblock(&spW)){
+ COMPAT_CLOSE(spR);
+ COMPAT_CLOSE(listensock);
+ continue;
+ }
+ COMPAT_CLOSE(listensock);
+
+ *pairR = spR;
+ *pairW = spW;
+ return MOSQ_ERR_SUCCESS;
+ }
+ return MOSQ_ERR_UNKNOWN;
+#else
+ int sv[2];
+
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1){
+ return MOSQ_ERR_ERRNO;
+ }
+ if(net__socket_nonblock(&sv[0])){
+ COMPAT_CLOSE(sv[1]);
+ return MOSQ_ERR_ERRNO;
+ }
+ if(net__socket_nonblock(&sv[1])){
+ COMPAT_CLOSE(sv[0]);
+ return MOSQ_ERR_ERRNO;
+ }
+ *pairR = sv[0];
+ *pairW = sv[1];
+ return MOSQ_ERR_SUCCESS;
+#endif
+}
+#endif
diff --git a/libs/libmosquitto/src/net_mosq.h b/libs/libmosquitto/src/net_mosq.h
new file mode 100644
index 0000000000..b843ebe388
--- /dev/null
+++ b/libs/libmosquitto/src/net_mosq.h
@@ -0,0 +1,82 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef NET_MOSQ_H
+#define NET_MOSQ_H
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <winsock2.h>
+typedef SSIZE_T ssize_t;
+#endif
+
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+
+#ifdef WITH_BROKER
+struct mosquitto_db;
+#endif
+
+#ifdef WIN32
+# define COMPAT_CLOSE(a) closesocket(a)
+# define COMPAT_ECONNRESET WSAECONNRESET
+# define COMPAT_EWOULDBLOCK WSAEWOULDBLOCK
+#else
+# define COMPAT_CLOSE(a) close(a)
+# define COMPAT_ECONNRESET ECONNRESET
+# define COMPAT_EWOULDBLOCK EWOULDBLOCK
+#endif
+
+/* For when not using winsock libraries. */
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET -1
+#endif
+
+/* Macros for accessing the MSB and LSB of a uint16_t */
+#define MOSQ_MSB(A) (uint8_t)((A & 0xFF00) >> 8)
+#define MOSQ_LSB(A) (uint8_t)(A & 0x00FF)
+
+int net__init(void);
+void net__cleanup(void);
+
+int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking);
+#ifdef WITH_BROKER
+int net__socket_close(struct mosquitto_db *db, struct mosquitto *mosq);
+#else
+int net__socket_close(struct mosquitto *mosq);
+#endif
+int net__try_connect(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking);
+int net__try_connect_step1(struct mosquitto *mosq, const char *host);
+int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock);
+int net__socket_connect_step3(struct mosquitto *mosq, const char *host);
+int net__socket_nonblock(mosq_sock_t *sock);
+int net__socketpair(mosq_sock_t *sp1, mosq_sock_t *sp2);
+
+ssize_t net__read(struct mosquitto *mosq, void *buf, size_t count);
+ssize_t net__write(struct mosquitto *mosq, void *buf, size_t count);
+
+#ifdef WITH_TLS
+int net__socket_apply_tls(struct mosquitto *mosq);
+int net__socket_connect_tls(struct mosquitto *mosq);
+int mosquitto__verify_ocsp_status_cb(SSL * ssl, void *arg);
+UI_METHOD *net__get_ui_method(void);
+#define ENGINE_FINISH(e) if(e) ENGINE_finish(e)
+#define ENGINE_SECRET_MODE "SECRET_MODE"
+#define ENGINE_SECRET_MODE_SHA 0x1000
+#define ENGINE_PIN "PIN"
+#endif
+
+#endif
diff --git a/libs/libmosquitto/src/net_mosq_ocsp.c b/libs/libmosquitto/src/net_mosq_ocsp.c
new file mode 100644
index 0000000000..32f2a3e321
--- /dev/null
+++ b/libs/libmosquitto/src/net_mosq_ocsp.c
@@ -0,0 +1,159 @@
+/*
+Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
+Copyright (c) 2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG), Dr. Lars Voelker <lars.voelker@bmw.de>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Dr. Lars Voelker, BMW AG
+*/
+
+/*
+COPYRIGHT AND PERMISSION NOTICE of curl on which the ocsp code is based:
+
+Copyright (c) 1996 - 2016, Daniel Stenberg, <daniel@haxx.se>, and many
+contributors, see the THANKS file.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
+*/
+
+#ifdef WITH_TLS
+#include <logging_mosq.h>
+#include <mosquitto_internal.h>
+#include <net_mosq.h>
+
+#include <openssl/safestack.h>
+#include <openssl/tls1.h>
+#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
+
+int mosquitto__verify_ocsp_status_cb(SSL * ssl, void *arg)
+{
+ struct mosquitto *mosq = (struct mosquitto *)arg;
+ int ocsp_status, result2, i;
+ unsigned char *p;
+ const unsigned char *cp;
+ OCSP_RESPONSE *rsp = NULL;
+ OCSP_BASICRESP *br = NULL;
+ X509_STORE *st = NULL;
+ STACK_OF(X509) *ch = NULL;
+
+ long len = SSL_get_tlsext_status_ocsp_resp(mosq->ssl, &p);
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL_get_tlsext_status_ocsp_resp returned %ld bytes", len);
+
+ // the following functions expect a const pointer
+ cp = (const unsigned char *)p;
+
+ if (!cp || len <= 0) {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: no response");
+ goto end;
+ }
+
+
+ rsp = d2i_OCSP_RESPONSE(NULL, &cp, len);
+ if (rsp==NULL) {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: invalid response");
+ goto end;
+ }
+
+ ocsp_status = OCSP_response_status(rsp);
+ if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: invalid status: %s (%d)",
+ OCSP_response_status_str(ocsp_status), ocsp_status);
+ goto end;
+ }
+
+ br = OCSP_response_get1_basic(rsp);
+ if (!br) {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: invalid response");
+ goto end;
+ }
+
+ ch = SSL_get_peer_cert_chain(mosq->ssl);
+ if (sk_X509_num(ch) <= 0) {
+ log__printf(mosq, MOSQ_LOG_ERR, "OCSP: we did not receive certificates of the server (num: %d)", sk_X509_num(ch));
+ goto end;
+ }
+
+ st = SSL_CTX_get_cert_store(mosq->ssl_ctx);
+
+ // Note:
+ // Other checkers often fix problems in OpenSSL before 1.0.2a (e.g. libcurl).
+ // For all currently supported versions of the OpenSSL project, this is not needed anymore.
+
+ if ((result2=OCSP_basic_verify(br, ch, st, 0)) <= 0) {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: response verification failed (error: %d)", result2);
+ goto end;
+ }
+
+ for(i = 0; i < OCSP_resp_count(br); i++) {
+ int cert_status, crl_reason;
+ OCSP_SINGLERESP *single = NULL;
+
+ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+
+ single = OCSP_resp_get0(br, i);
+ if(!single)
+ continue;
+
+ cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, &thisupd, &nextupd);
+
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL certificate status: %s (%d)",
+ OCSP_cert_status_str(cert_status), cert_status);
+
+ switch(cert_status) {
+ case V_OCSP_CERTSTATUS_GOOD:
+ // Note: A OCSP stapling result will be accepted up to 5 minutes after it expired!
+ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: OCSP response has expired");
+ goto end;
+ }
+ break;
+
+ case V_OCSP_CERTSTATUS_REVOKED:
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL certificate revocation reason: %s (%d)",
+ OCSP_crl_reason_str(crl_reason), crl_reason);
+ goto end;
+
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ goto end;
+
+ default:
+ log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL certificate revocation status unknown");
+ goto end;
+ }
+ }
+
+ if (br!=NULL) OCSP_BASICRESP_free(br);
+ if (rsp!=NULL) OCSP_RESPONSE_free(rsp);
+ return 1; // OK
+
+end:
+ if (br!=NULL) OCSP_BASICRESP_free(br);
+ if (rsp!=NULL) OCSP_RESPONSE_free(rsp);
+ return 0; // Not OK
+}
+#endif
diff --git a/libs/libmosquitto/src/options.c b/libs/libmosquitto/src/options.c
new file mode 100644
index 0000000000..7bab736628
--- /dev/null
+++ b/libs/libmosquitto/src/options.c
@@ -0,0 +1,486 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#ifndef WIN32
+# include <strings.h>
+#endif
+
+#include <string.h>
+
+#ifdef WITH_TLS
+# ifdef WIN32
+# include <winsock2.h>
+# endif
+# include <openssl/engine.h>
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "util_mosq.h"
+#include "will_mosq.h"
+
+
+int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
+{
+ return mosquitto_will_set_v5(mosq, topic, payloadlen, payload, qos, retain, NULL);
+}
+
+
+int mosquitto_will_set_v5(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties)
+{
+ int rc;
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ if(properties){
+ rc = mosquitto_property_check_all(CMD_WILL, properties);
+ if(rc) return rc;
+ }
+
+ return will__set(mosq, topic, payloadlen, payload, qos, retain, properties);
+}
+
+
+int mosquitto_will_clear(struct mosquitto *mosq)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+ return will__clear(mosq);
+}
+
+
+int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ if(mosq->protocol == mosq_p_mqtt311 || mosq->protocol == mosq_p_mqtt31){
+ if(password != NULL && username == NULL){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+
+ mosquitto__free(mosq->username);
+ mosq->username = NULL;
+
+ mosquitto__free(mosq->password);
+ mosq->password = NULL;
+
+ if(username){
+ if(mosquitto_validate_utf8(username, strlen(username))){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ mosq->username = mosquitto__strdup(username);
+ if(!mosq->username) return MOSQ_ERR_NOMEM;
+ }
+
+ if(password){
+ mosq->password = mosquitto__strdup(password);
+ if(!mosq->password){
+ mosquitto__free(mosq->username);
+ mosq->username = NULL;
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ if(reconnect_delay == 0) reconnect_delay = 1;
+
+ mosq->reconnect_delay = reconnect_delay;
+ mosq->reconnect_delay_max = reconnect_delay_max;
+ mosq->reconnect_exponential_backoff = reconnect_exponential_backoff;
+
+ return MOSQ_ERR_SUCCESS;
+
+}
+
+
+int mosquitto_tls_set(struct mosquitto *mosq, const char *cafile, const char *capath, const char *certfile, const char *keyfile, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata))
+{
+#ifdef WITH_TLS
+ FILE *fptr;
+
+ if(!mosq || (!cafile && !capath) || (certfile && !keyfile) || (!certfile && keyfile)) return MOSQ_ERR_INVAL;
+
+ mosquitto__free(mosq->tls_cafile);
+ mosq->tls_cafile = NULL;
+ if(cafile){
+ fptr = mosquitto__fopen(cafile, "rt", false);
+ if(fptr){
+ fclose(fptr);
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->tls_cafile = mosquitto__strdup(cafile);
+
+ if(!mosq->tls_cafile){
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+
+ mosquitto__free(mosq->tls_capath);
+ mosq->tls_capath = NULL;
+ if(capath){
+ mosq->tls_capath = mosquitto__strdup(capath);
+ if(!mosq->tls_capath){
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+
+ mosquitto__free(mosq->tls_certfile);
+ mosq->tls_certfile = NULL;
+ if(certfile){
+ fptr = mosquitto__fopen(certfile, "rt", false);
+ if(fptr){
+ fclose(fptr);
+ }else{
+ mosquitto__free(mosq->tls_cafile);
+ mosq->tls_cafile = NULL;
+
+ mosquitto__free(mosq->tls_capath);
+ mosq->tls_capath = NULL;
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->tls_certfile = mosquitto__strdup(certfile);
+ if(!mosq->tls_certfile){
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+
+ mosquitto__free(mosq->tls_keyfile);
+ mosq->tls_keyfile = NULL;
+ if(keyfile){
+ fptr = mosquitto__fopen(keyfile, "rt", false);
+ if(fptr){
+ fclose(fptr);
+ }else{
+ mosquitto__free(mosq->tls_cafile);
+ mosq->tls_cafile = NULL;
+
+ mosquitto__free(mosq->tls_capath);
+ mosq->tls_capath = NULL;
+
+ mosquitto__free(mosq->tls_certfile);
+ mosq->tls_certfile = NULL;
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->tls_keyfile = mosquitto__strdup(keyfile);
+ if(!mosq->tls_keyfile){
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+
+ mosq->tls_pw_callback = pw_callback;
+
+
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+
+#endif
+}
+
+
+int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers)
+{
+#ifdef WITH_TLS
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ mosq->tls_cert_reqs = cert_reqs;
+ if(tls_version){
+ if(!strcasecmp(tls_version, "tlsv1.3")
+ || !strcasecmp(tls_version, "tlsv1.2")
+ || !strcasecmp(tls_version, "tlsv1.1")){
+
+ mosq->tls_version = mosquitto__strdup(tls_version);
+ if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+ }else{
+ mosq->tls_version = mosquitto__strdup("tlsv1.2");
+ if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
+ }
+ if(ciphers){
+ mosq->tls_ciphers = mosquitto__strdup(ciphers);
+ if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM;
+ }else{
+ mosq->tls_ciphers = NULL;
+ }
+
+
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+
+#endif
+}
+
+
+int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value)
+{
+#ifdef WITH_TLS
+ if(!mosq) return MOSQ_ERR_INVAL;
+ mosq->tls_insecure = value;
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+
+int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, const char *value)
+{
+#ifdef WITH_TLS
+ ENGINE *eng;
+ char *str;
+#endif
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ switch(option){
+ case MOSQ_OPT_TLS_ENGINE:
+#ifdef WITH_TLS
+# if !defined(OPENSSL_NO_ENGINE)
+ eng = ENGINE_by_id(value);
+ if(!eng){
+ return MOSQ_ERR_INVAL;
+ }
+ ENGINE_free(eng); /* release the structural reference from ENGINE_by_id() */
+ mosq->tls_engine = mosquitto__strdup(value);
+ if(!mosq->tls_engine){
+ return MOSQ_ERR_NOMEM;
+ }
+ return MOSQ_ERR_SUCCESS;
+#endif
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ break;
+
+ case MOSQ_OPT_TLS_KEYFORM:
+#ifdef WITH_TLS
+ if(!value) return MOSQ_ERR_INVAL;
+ if(!strcasecmp(value, "pem")){
+ mosq->tls_keyform = mosq_k_pem;
+ }else if (!strcasecmp(value, "engine")){
+ mosq->tls_keyform = mosq_k_engine;
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ break;
+
+
+ case MOSQ_OPT_TLS_ENGINE_KPASS_SHA1:
+#ifdef WITH_TLS
+ if(mosquitto__hex2bin_sha1(value, (unsigned char**)&str) != MOSQ_ERR_SUCCESS){
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->tls_engine_kpass_sha1 = str;
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ break;
+
+ case MOSQ_OPT_TLS_ALPN:
+#ifdef WITH_TLS
+ mosq->tls_alpn = mosquitto__strdup(value);
+ if(!mosq->tls_alpn){
+ return MOSQ_ERR_NOMEM;
+ }
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ break;
+
+ default:
+ return MOSQ_ERR_INVAL;
+ }
+
+ return MOSQ_ERR_INVAL;
+}
+
+
+int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers)
+{
+#ifdef FINAL_WITH_TLS_PSK
+ if(!mosq || !psk || !identity) return MOSQ_ERR_INVAL;
+
+ /* Check for hex only digits */
+ if(strspn(psk, "0123456789abcdefABCDEF") < strlen(psk)){
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->tls_psk = mosquitto__strdup(psk);
+ if(!mosq->tls_psk) return MOSQ_ERR_NOMEM;
+
+ mosq->tls_psk_identity = mosquitto__strdup(identity);
+ if(!mosq->tls_psk_identity){
+ mosquitto__free(mosq->tls_psk);
+ return MOSQ_ERR_NOMEM;
+ }
+ if(ciphers){
+ mosq->tls_ciphers = mosquitto__strdup(ciphers);
+ if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM;
+ }else{
+ mosq->tls_ciphers = NULL;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+
+int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value)
+{
+ int ival;
+
+ if(!mosq || !value) return MOSQ_ERR_INVAL;
+
+ switch(option){
+ case MOSQ_OPT_PROTOCOL_VERSION:
+ ival = *((int *)value);
+ return mosquitto_int_option(mosq, option, ival);
+ case MOSQ_OPT_SSL_CTX:
+#ifdef WITH_TLS
+ mosq->ssl_ctx = (SSL_CTX *)value;
+ if(mosq->ssl_ctx){
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+ SSL_CTX_up_ref(mosq->ssl_ctx);
+#else
+ CRYPTO_add(&(mosq->ssl_ctx)->references, 1, CRYPTO_LOCK_SSL_CTX);
+#endif
+ }
+ break;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ default:
+ return MOSQ_ERR_INVAL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ switch(option){
+ case MOSQ_OPT_PROTOCOL_VERSION:
+ if(value == MQTT_PROTOCOL_V31){
+ mosq->protocol = mosq_p_mqtt31;
+ }else if(value == MQTT_PROTOCOL_V311){
+ mosq->protocol = mosq_p_mqtt311;
+ }else if(value == MQTT_PROTOCOL_V5){
+ mosq->protocol = mosq_p_mqtt5;
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+ break;
+
+ case MOSQ_OPT_RECEIVE_MAXIMUM:
+ if(value < 0 || value > 65535){
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->receive_maximum = value;
+ break;
+
+ case MOSQ_OPT_SEND_MAXIMUM:
+ if(value < 0 || value > 65535){
+ return MOSQ_ERR_INVAL;
+ }
+ mosq->send_maximum = value;
+ break;
+
+ case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS:
+#if defined(WITH_TLS) && OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if(value){
+ mosq->ssl_ctx_defaults = true;
+ }else{
+ mosq->ssl_ctx_defaults = false;
+ }
+ break;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+
+ case MOSQ_OPT_TLS_OCSP_REQUIRED:
+#ifdef WITH_TLS
+ mosq->tls_ocsp_required = (bool)value;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ break;
+
+ default:
+ return MOSQ_ERR_INVAL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value)
+{
+ if(!mosq || !value) return MOSQ_ERR_INVAL;
+
+ switch(option){
+ case MOSQ_OPT_SSL_CTX:
+#ifdef WITH_TLS
+ mosq->ssl_ctx = (SSL_CTX *)value;
+ if(mosq->ssl_ctx){
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+ SSL_CTX_up_ref(mosq->ssl_ctx);
+#else
+ CRYPTO_add(&(mosq->ssl_ctx)->references, 1, CRYPTO_LOCK_SSL_CTX);
+#endif
+ }
+ break;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+ default:
+ return MOSQ_ERR_INVAL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void mosquitto_user_data_set(struct mosquitto *mosq, void *userdata)
+{
+ if(mosq){
+ mosq->userdata = userdata;
+ }
+}
+
+void *mosquitto_userdata(struct mosquitto *mosq)
+{
+ return mosq->userdata;
+}
diff --git a/libs/libmosquitto/src/packet_datatypes.c b/libs/libmosquitto/src/packet_datatypes.c
new file mode 100644
index 0000000000..335cb9f02d
--- /dev/null
+++ b/libs/libmosquitto/src/packet_datatypes.c
@@ -0,0 +1,271 @@
+/*
+Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+# ifdef WITH_WEBSOCKETS
+# include <libwebsockets.h>
+# endif
+#else
+# include "read_handle.h"
+#endif
+
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#ifdef WITH_BROKER
+# include "sys_tree.h"
+#else
+# define G_BYTES_RECEIVED_INC(A)
+# define G_BYTES_SENT_INC(A)
+# define G_MSGS_SENT_INC(A)
+# define G_PUB_MSGS_SENT_INC(A)
+#endif
+
+
+int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte)
+{
+ assert(packet);
+ if(packet->pos+1 > packet->remaining_length) return MOSQ_ERR_PROTOCOL;
+
+ *byte = packet->payload[packet->pos];
+ packet->pos++;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte)
+{
+ assert(packet);
+ assert(packet->pos+1 <= packet->packet_length);
+
+ packet->payload[packet->pos] = byte;
+ packet->pos++;
+}
+
+
+int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count)
+{
+ assert(packet);
+ if(packet->pos+count > packet->remaining_length) return MOSQ_ERR_PROTOCOL;
+
+ memcpy(bytes, &(packet->payload[packet->pos]), count);
+ packet->pos += count;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count)
+{
+ assert(packet);
+ assert(packet->pos+count <= packet->packet_length);
+
+ memcpy(&(packet->payload[packet->pos]), bytes, count);
+ packet->pos += count;
+}
+
+
+int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length)
+{
+ uint16_t slen;
+ int rc;
+
+ assert(packet);
+ rc = packet__read_uint16(packet, &slen);
+ if(rc) return rc;
+
+ if(slen == 0){
+ *data = NULL;
+ *length = 0;
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ if(packet->pos+slen > packet->remaining_length) return MOSQ_ERR_PROTOCOL;
+
+ *data = mosquitto__malloc(slen+1);
+ if(*data){
+ memcpy(*data, &(packet->payload[packet->pos]), slen);
+ ((uint8_t *)(*data))[slen] = '\0';
+ packet->pos += slen;
+ }else{
+ return MOSQ_ERR_NOMEM;
+ }
+
+ *length = slen;
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int packet__read_string(struct mosquitto__packet *packet, char **str, int *length)
+{
+ int rc;
+
+ rc = packet__read_binary(packet, (uint8_t **)str, length);
+ if(rc) return rc;
+ if(*length == 0) return MOSQ_ERR_SUCCESS;
+
+ if(mosquitto_validate_utf8(*str, *length)){
+ mosquitto__free(*str);
+ *str = NULL;
+ *length = -1;
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void packet__write_string(struct mosquitto__packet *packet, const char *str, uint16_t length)
+{
+ assert(packet);
+ packet__write_uint16(packet, length);
+ packet__write_bytes(packet, str, length);
+}
+
+
+int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word)
+{
+ uint8_t msb, lsb;
+
+ assert(packet);
+ if(packet->pos+2 > packet->remaining_length) return MOSQ_ERR_PROTOCOL;
+
+ msb = packet->payload[packet->pos];
+ packet->pos++;
+ lsb = packet->payload[packet->pos];
+ packet->pos++;
+
+ *word = (msb<<8) + lsb;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word)
+{
+ packet__write_byte(packet, MOSQ_MSB(word));
+ packet__write_byte(packet, MOSQ_LSB(word));
+}
+
+
+int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word)
+{
+ uint32_t val = 0;
+ int i;
+
+ assert(packet);
+ if(packet->pos+4 > packet->remaining_length) return MOSQ_ERR_PROTOCOL;
+
+ for(i=0; i<4; i++){
+ val = (val << 8) + packet->payload[packet->pos];
+ packet->pos++;
+ }
+
+ *word = val;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word)
+{
+ packet__write_byte(packet, (word & 0xFF000000) >> 24);
+ packet__write_byte(packet, (word & 0x00FF0000) >> 16);
+ packet__write_byte(packet, (word & 0x0000FF00) >> 8);
+ packet__write_byte(packet, (word & 0x000000FF));
+}
+
+
+int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, int8_t *bytes)
+{
+ int i;
+ uint8_t byte;
+ int remaining_mult = 1;
+ int32_t lword = 0;
+ uint8_t lbytes = 0;
+
+ for(i=0; i<4; i++){
+ if(packet->pos < packet->remaining_length){
+ lbytes++;
+ byte = packet->payload[packet->pos];
+ lword += (byte & 127) * remaining_mult;
+ remaining_mult *= 128;
+ packet->pos++;
+ if((byte & 128) == 0){
+ if(lbytes > 1 && byte == 0){
+ /* Catch overlong encodings */
+ return MOSQ_ERR_PROTOCOL;
+ }else{
+ *word = lword;
+ if(bytes) (*bytes) = lbytes;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ }else{
+ return MOSQ_ERR_PROTOCOL;
+ }
+ }
+ return MOSQ_ERR_PROTOCOL;
+}
+
+
+int packet__write_varint(struct mosquitto__packet *packet, int32_t word)
+{
+ uint8_t byte;
+ int count = 0;
+
+ do{
+ byte = word % 128;
+ word = word / 128;
+ /* If there are more digits to encode, set the top bit of this digit */
+ if(word > 0){
+ byte = byte | 0x80;
+ }
+ packet__write_byte(packet, byte);
+ count++;
+ }while(word > 0 && count < 5);
+
+ if(count == 5){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int packet__varint_bytes(int32_t word)
+{
+ if(word < 128){
+ return 1;
+ }else if(word < 16384){
+ return 2;
+ }else if(word < 2097152){
+ return 3;
+ }else if(word < 268435456){
+ return 4;
+ }else{
+ return 5;
+ }
+}
diff --git a/libs/libmosquitto/src/packet_mosq.c b/libs/libmosquitto/src/packet_mosq.c
new file mode 100644
index 0000000000..0f7af7426c
--- /dev/null
+++ b/libs/libmosquitto/src/packet_mosq.c
@@ -0,0 +1,456 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+# ifdef WITH_WEBSOCKETS
+# include <libwebsockets.h>
+# endif
+#else
+# include "read_handle.h"
+#endif
+
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#ifdef WITH_BROKER
+# include "sys_tree.h"
+# include "send_mosq.h"
+#else
+# define G_BYTES_RECEIVED_INC(A)
+# define G_BYTES_SENT_INC(A)
+# define G_MSGS_SENT_INC(A)
+# define G_PUB_MSGS_SENT_INC(A)
+#endif
+
+int packet__alloc(struct mosquitto__packet *packet)
+{
+ uint8_t remaining_bytes[5], byte;
+ uint32_t remaining_length;
+ int i;
+
+ assert(packet);
+
+ remaining_length = packet->remaining_length;
+ packet->payload = NULL;
+ packet->remaining_count = 0;
+ do{
+ byte = remaining_length % 128;
+ remaining_length = remaining_length / 128;
+ /* If there are more digits to encode, set the top bit of this digit */
+ if(remaining_length > 0){
+ byte = byte | 0x80;
+ }
+ remaining_bytes[packet->remaining_count] = byte;
+ packet->remaining_count++;
+ }while(remaining_length > 0 && packet->remaining_count < 5);
+ if(packet->remaining_count == 5) return MOSQ_ERR_PAYLOAD_SIZE;
+ packet->packet_length = packet->remaining_length + 1 + packet->remaining_count;
+#ifdef WITH_WEBSOCKETS
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING);
+#else
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
+#endif
+ if(!packet->payload) return MOSQ_ERR_NOMEM;
+
+ packet->payload[0] = packet->command;
+ for(i=0; i<packet->remaining_count; i++){
+ packet->payload[i+1] = remaining_bytes[i];
+ }
+ packet->pos = 1 + packet->remaining_count;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+void packet__cleanup(struct mosquitto__packet *packet)
+{
+ if(!packet) return;
+
+ /* Free data and reset values */
+ packet->command = 0;
+ packet->remaining_count = 0;
+ packet->remaining_mult = 1;
+ packet->remaining_length = 0;
+ mosquitto__free(packet->payload);
+ packet->payload = NULL;
+ packet->to_process = 0;
+ packet->pos = 0;
+}
+
+int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet)
+{
+#ifndef WITH_BROKER
+ char sockpair_data = 0;
+#endif
+ assert(mosq);
+ assert(packet);
+
+ packet->pos = 0;
+ packet->to_process = packet->packet_length;
+
+ packet->next = NULL;
+ pthread_mutex_lock(&mosq->out_packet_mutex);
+ if(mosq->out_packet){
+ mosq->out_packet_last->next = packet;
+ }else{
+ mosq->out_packet = packet;
+ }
+ mosq->out_packet_last = packet;
+ pthread_mutex_unlock(&mosq->out_packet_mutex);
+#ifdef WITH_BROKER
+# ifdef WITH_WEBSOCKETS
+ if(mosq->wsi){
+ libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ return packet__write(mosq);
+ }
+# else
+ return packet__write(mosq);
+# endif
+#else
+
+ /* Write a single byte to sockpairW (connected to sockpairR) to break out
+ * of select() if in threaded mode. */
+ if(mosq->sockpairW != INVALID_SOCKET){
+#ifndef WIN32
+ if(write(mosq->sockpairW, &sockpair_data, 1)){
+ }
+#else
+ send(mosq->sockpairW, &sockpair_data, 1, 0);
+#endif
+ }
+
+ if(mosq->in_callback == false && mosq->threaded == mosq_ts_none){
+ return packet__write(mosq);
+ }else{
+ return MOSQ_ERR_SUCCESS;
+ }
+#endif
+}
+
+
+int packet__check_oversize(struct mosquitto *mosq, uint32_t remaining_length)
+{
+ uint32_t len;
+
+ if(mosq->maximum_packet_size == 0) return MOSQ_ERR_SUCCESS;
+
+ len = remaining_length + packet__varint_bytes(remaining_length);
+ if(len > mosq->maximum_packet_size){
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }else{
+ return MOSQ_ERR_SUCCESS;
+ }
+}
+
+
+int packet__write(struct mosquitto *mosq)
+{
+ ssize_t write_length;
+ struct mosquitto__packet *packet;
+
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+ pthread_mutex_lock(&mosq->current_out_packet_mutex);
+ pthread_mutex_lock(&mosq->out_packet_mutex);
+ if(mosq->out_packet && !mosq->current_out_packet){
+ mosq->current_out_packet = mosq->out_packet;
+ mosq->out_packet = mosq->out_packet->next;
+ if(!mosq->out_packet){
+ mosq->out_packet_last = NULL;
+ }
+ }
+ pthread_mutex_unlock(&mosq->out_packet_mutex);
+
+#if defined(WITH_TLS) && !defined(WITH_BROKER)
+ if((mosq->state == mosq_cs_connect_pending) || mosq->want_connect){
+#else
+ if(mosq->state == mosq_cs_connect_pending){
+#endif
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ while(mosq->current_out_packet){
+ packet = mosq->current_out_packet;
+
+ while(packet->to_process > 0){
+ write_length = net__write(mosq, &(packet->payload[packet->pos]), packet->to_process);
+ if(write_length > 0){
+ G_BYTES_SENT_INC(write_length);
+ packet->to_process -= write_length;
+ packet->pos += write_length;
+ }else{
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+ switch(errno){
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }
+
+ G_MSGS_SENT_INC(1);
+ if(((packet->command)&0xF6) == CMD_PUBLISH){
+ G_PUB_MSGS_SENT_INC(1);
+#ifndef WITH_BROKER
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_publish){
+ /* This is a QoS=0 message */
+ mosq->in_callback = true;
+ mosq->on_publish(mosq, mosq->userdata, packet->mid);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_publish_v5){
+ /* This is a QoS=0 message */
+ mosq->in_callback = true;
+ mosq->on_publish_v5(mosq, mosq->userdata, packet->mid, 0, NULL);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ }else if(((packet->command)&0xF0) == CMD_DISCONNECT){
+ do_client_disconnect(mosq, MOSQ_ERR_SUCCESS, NULL);
+ packet__cleanup(packet);
+ mosquitto__free(packet);
+ return MOSQ_ERR_SUCCESS;
+#endif
+ }
+
+ /* Free data and reset values */
+ pthread_mutex_lock(&mosq->out_packet_mutex);
+ mosq->current_out_packet = mosq->out_packet;
+ if(mosq->out_packet){
+ mosq->out_packet = mosq->out_packet->next;
+ if(!mosq->out_packet){
+ mosq->out_packet_last = NULL;
+ }
+ }
+ pthread_mutex_unlock(&mosq->out_packet_mutex);
+
+ packet__cleanup(packet);
+ mosquitto__free(packet);
+
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ }
+ pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+#ifdef WITH_BROKER
+int packet__read(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+int packet__read(struct mosquitto *mosq)
+#endif
+{
+ uint8_t byte;
+ ssize_t read_length;
+ int rc = 0;
+
+ if(!mosq){
+ return MOSQ_ERR_INVAL;
+ }
+ if(mosq->sock == INVALID_SOCKET){
+ return MOSQ_ERR_NO_CONN;
+ }
+ if(mosq->state == mosq_cs_connect_pending){
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ /* This gets called if pselect() indicates that there is network data
+ * available - ie. at least one byte. What we do depends on what data we
+ * already have.
+ * If we've not got a command, attempt to read one and save it. This should
+ * always work because it's only a single byte.
+ * Then try to read the remaining length. This may fail because it is may
+ * be more than one byte - will need to save data pending next read if it
+ * does fail.
+ * Then try to read the remaining payload, where 'payload' here means the
+ * combined variable header and actual payload. This is the most likely to
+ * fail due to longer length, so save current data and current position.
+ * After all data is read, send to mosquitto__handle_packet() to deal with.
+ * Finally, free the memory and reset everything to starting conditions.
+ */
+ if(!mosq->in_packet.command){
+ read_length = net__read(mosq, &byte, 1);
+ if(read_length == 1){
+ mosq->in_packet.command = byte;
+#ifdef WITH_BROKER
+ G_BYTES_RECEIVED_INC(1);
+ /* Clients must send CONNECT as their first command. */
+ if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CMD_CONNECT){
+ return MOSQ_ERR_PROTOCOL;
+ }
+#endif
+ }else{
+ if(read_length == 0){
+ return MOSQ_ERR_CONN_LOST; /* EOF */
+ }
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ switch(errno){
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }
+ /* remaining_count is the number of bytes that the remaining_length
+ * parameter occupied in this incoming packet. We don't use it here as such
+ * (it is used when allocating an outgoing packet), but we must be able to
+ * determine whether all of the remaining_length parameter has been read.
+ * remaining_count has three states here:
+ * 0 means that we haven't read any remaining_length bytes
+ * <0 means we have read some remaining_length bytes but haven't finished
+ * >0 means we have finished reading the remaining_length bytes.
+ */
+ if(mosq->in_packet.remaining_count <= 0){
+ do{
+ read_length = net__read(mosq, &byte, 1);
+ if(read_length == 1){
+ mosq->in_packet.remaining_count--;
+ /* Max 4 bytes length for remaining length as defined by protocol.
+ * Anything more likely means a broken/malicious client.
+ */
+ if(mosq->in_packet.remaining_count < -4){
+ return MOSQ_ERR_PROTOCOL;
+ }
+
+ G_BYTES_RECEIVED_INC(1);
+ mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult;
+ mosq->in_packet.remaining_mult *= 128;
+ }else{
+ if(read_length == 0){
+ return MOSQ_ERR_CONN_LOST; /* EOF */
+ }
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ switch(errno){
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }while((byte & 128) != 0);
+ /* We have finished reading remaining_length, so make remaining_count
+ * positive. */
+ mosq->in_packet.remaining_count *= -1;
+
+#ifdef WITH_BROKER
+ if(db->config->max_packet_size > 0 && mosq->in_packet.remaining_length+1 > db->config->max_packet_size){
+ log__printf(NULL, MOSQ_LOG_INFO, "Client %s sent too large packet %d, disconnecting.", mosq->id, mosq->in_packet.remaining_length+1);
+ if(mosq->protocol == mosq_p_mqtt5){
+ send__disconnect(mosq, MQTT_RC_PACKET_TOO_LARGE, NULL);
+ }
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }
+#else
+ // FIXME - client case for incoming message received from broker too large
+#endif
+ if(mosq->in_packet.remaining_length > 0){
+ mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));
+ if(!mosq->in_packet.payload){
+ return MOSQ_ERR_NOMEM;
+ }
+ mosq->in_packet.to_process = mosq->in_packet.remaining_length;
+ }
+ }
+ while(mosq->in_packet.to_process>0){
+ read_length = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
+ if(read_length > 0){
+ G_BYTES_RECEIVED_INC(read_length);
+ mosq->in_packet.to_process -= read_length;
+ mosq->in_packet.pos += read_length;
+ }else{
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ if(mosq->in_packet.to_process > 1000){
+ /* Update last_msg_in time if more than 1000 bytes left to
+ * receive. Helps when receiving large messages.
+ * This is an arbitrary limit, but with some consideration.
+ * If a client can't send 1000 bytes in a second it
+ * probably shouldn't be using a 1 second keep alive. */
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->last_msg_in = mosquitto_time();
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ }
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ switch(errno){
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }
+
+ /* All data for this packet is read. */
+ mosq->in_packet.pos = 0;
+#ifdef WITH_BROKER
+ G_MSGS_RECEIVED_INC(1);
+ if(((mosq->in_packet.command)&0xF5) == CMD_PUBLISH){
+ G_PUB_MSGS_RECEIVED_INC(1);
+ }
+ rc = handle__packet(db, mosq);
+#else
+ rc = handle__packet(mosq);
+#endif
+
+ /* Free data and reset values */
+ packet__cleanup(&mosq->in_packet);
+
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->last_msg_in = mosquitto_time();
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ return rc;
+}
diff --git a/libs/libmosquitto/src/packet_mosq.h b/libs/libmosquitto/src/packet_mosq.h
new file mode 100644
index 0000000000..5967f09406
--- /dev/null
+++ b/libs/libmosquitto/src/packet_mosq.h
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef PACKET_MOSQ_H
+#define PACKET_MOSQ_H
+
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+
+#ifdef WITH_BROKER
+struct mosquitto_db;
+#endif
+
+int packet__alloc(struct mosquitto__packet *packet);
+void packet__cleanup(struct mosquitto__packet *packet);
+int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet);
+
+int packet__check_oversize(struct mosquitto *mosq, uint32_t remaining_length);
+
+int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte);
+int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count);
+int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length);
+int packet__read_string(struct mosquitto__packet *packet, char **str, int *length);
+int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word);
+int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word);
+int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, int8_t *bytes);
+
+void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte);
+void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count);
+void packet__write_string(struct mosquitto__packet *packet, const char *str, uint16_t length);
+void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word);
+void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word);
+int packet__write_varint(struct mosquitto__packet *packet, int32_t word);
+
+int packet__varint_bytes(int32_t word);
+
+int packet__write(struct mosquitto *mosq);
+#ifdef WITH_BROKER
+int packet__read(struct mosquitto_db *db, struct mosquitto *mosq);
+#else
+int packet__read(struct mosquitto *mosq);
+#endif
+
+#endif
diff --git a/libs/libmosquitto/src/property_mosq.c b/libs/libmosquitto/src/property_mosq.c
new file mode 100644
index 0000000000..76158e584d
--- /dev/null
+++ b/libs/libmosquitto/src/property_mosq.c
@@ -0,0 +1,1181 @@
+/*
+Copyright (c) 2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+
+
+int property__read(struct mosquitto__packet *packet, int32_t *len, mosquitto_property *property)
+{
+ int rc;
+ int32_t property_identifier;
+ uint8_t byte;
+ int8_t byte_count;
+ uint16_t uint16;
+ uint32_t uint32;
+ int32_t varint;
+ char *str1, *str2;
+ int slen1, slen2;
+
+ if(!property) return MOSQ_ERR_INVAL;
+
+ rc = packet__read_varint(packet, &property_identifier, NULL);
+ if(rc) return rc;
+ *len -= 1;
+
+ memset(property, 0, sizeof(mosquitto_property));
+
+ property->identifier = property_identifier;
+
+ switch(property_identifier){
+ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
+ case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
+ case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
+ case MQTT_PROP_MAXIMUM_QOS:
+ case MQTT_PROP_RETAIN_AVAILABLE:
+ case MQTT_PROP_WILDCARD_SUB_AVAILABLE:
+ case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE:
+ case MQTT_PROP_SHARED_SUB_AVAILABLE:
+ rc = packet__read_byte(packet, &byte);
+ if(rc) return rc;
+ *len -= 1; /* byte */
+ property->value.i8 = byte;
+ break;
+
+ case MQTT_PROP_SERVER_KEEP_ALIVE:
+ case MQTT_PROP_RECEIVE_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS:
+ rc = packet__read_uint16(packet, &uint16);
+ if(rc) return rc;
+ *len -= 2; /* uint16 */
+ property->value.i16 = uint16;
+ break;
+
+ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
+ case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
+ case MQTT_PROP_WILL_DELAY_INTERVAL:
+ case MQTT_PROP_MAXIMUM_PACKET_SIZE:
+ rc = packet__read_uint32(packet, &uint32);
+ if(rc) return rc;
+ *len -= 4; /* uint32 */
+ property->value.i32 = uint32;
+ break;
+
+ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
+ rc = packet__read_varint(packet, &varint, &byte_count);
+ if(rc) return rc;
+ *len -= byte_count;
+ property->value.varint = varint;
+ break;
+
+ case MQTT_PROP_CONTENT_TYPE:
+ case MQTT_PROP_RESPONSE_TOPIC:
+ case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
+ case MQTT_PROP_AUTHENTICATION_METHOD:
+ case MQTT_PROP_RESPONSE_INFORMATION:
+ case MQTT_PROP_SERVER_REFERENCE:
+ case MQTT_PROP_REASON_STRING:
+ rc = packet__read_string(packet, &str1, &slen1);
+ if(rc) return rc;
+ *len = (*len) - 2 - slen1; /* uint16, string len */
+ property->value.s.v = str1;
+ property->value.s.len = slen1;
+ break;
+
+ case MQTT_PROP_AUTHENTICATION_DATA:
+ case MQTT_PROP_CORRELATION_DATA:
+ rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1);
+ if(rc) return rc;
+ *len = (*len) - 2 - slen1; /* uint16, binary len */
+ property->value.bin.v = str1;
+ property->value.bin.len = slen1;
+ break;
+
+ case MQTT_PROP_USER_PROPERTY:
+ rc = packet__read_string(packet, &str1, &slen1);
+ if(rc) return rc;
+ *len = (*len) - 2 - slen1; /* uint16, string len */
+
+ rc = packet__read_string(packet, &str2, &slen2);
+ if(rc){
+ mosquitto__free(str1);
+ return rc;
+ }
+ *len = (*len) - 2 - slen2; /* uint16, string len */
+
+ property->name.v = str1;
+ property->name.len = slen1;
+ property->value.s.v = str2;
+ property->value.s.len = slen2;
+ break;
+
+ default:
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property_identifier);
+ return MOSQ_ERR_MALFORMED_PACKET;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int property__read_all(int command, struct mosquitto__packet *packet, mosquitto_property **properties)
+{
+ int rc;
+ int32_t proplen;
+ mosquitto_property *p, *tail = NULL;
+
+ rc = packet__read_varint(packet, &proplen, NULL);
+ if(rc) return rc;
+
+ *properties = NULL;
+
+ /* The order of properties must be preserved for some types, so keep the
+ * same order for all */
+ while(proplen > 0){
+ p = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!p){
+ mosquitto_property_free_all(properties);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ rc = property__read(packet, &proplen, p);
+ if(rc){
+ mosquitto__free(p);
+ mosquitto_property_free_all(properties);
+ return rc;
+ }
+
+ if(!(*properties)){
+ *properties = p;
+ }else{
+ tail->next = p;
+ }
+ tail = p;
+
+ }
+
+ rc = mosquitto_property_check_all(command, *properties);
+ if(rc){
+ mosquitto_property_free_all(properties);
+ return rc;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+void property__free(mosquitto_property **property)
+{
+ if(!property || !(*property)) return;
+
+ switch((*property)->identifier){
+ case MQTT_PROP_CONTENT_TYPE:
+ case MQTT_PROP_RESPONSE_TOPIC:
+ case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
+ case MQTT_PROP_AUTHENTICATION_METHOD:
+ case MQTT_PROP_RESPONSE_INFORMATION:
+ case MQTT_PROP_SERVER_REFERENCE:
+ case MQTT_PROP_REASON_STRING:
+ mosquitto__free((*property)->value.s.v);
+ break;
+
+ case MQTT_PROP_AUTHENTICATION_DATA:
+ case MQTT_PROP_CORRELATION_DATA:
+ mosquitto__free((*property)->value.bin.v);
+ break;
+
+ case MQTT_PROP_USER_PROPERTY:
+ mosquitto__free((*property)->name.v);
+ mosquitto__free((*property)->value.s.v);
+ break;
+
+ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
+ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
+ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
+ case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
+ case MQTT_PROP_SERVER_KEEP_ALIVE:
+ case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
+ case MQTT_PROP_WILL_DELAY_INTERVAL:
+ case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
+ case MQTT_PROP_RECEIVE_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS:
+ case MQTT_PROP_MAXIMUM_QOS:
+ case MQTT_PROP_RETAIN_AVAILABLE:
+ case MQTT_PROP_MAXIMUM_PACKET_SIZE:
+ case MQTT_PROP_WILDCARD_SUB_AVAILABLE:
+ case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE:
+ case MQTT_PROP_SHARED_SUB_AVAILABLE:
+ /* Nothing to free */
+ break;
+ }
+
+ free(*property);
+ *property = NULL;
+}
+
+
+void mosquitto_property_free_all(mosquitto_property **property)
+{
+ mosquitto_property *p, *next;
+
+ if(!property) return;
+
+ p = *property;
+ while(p){
+ next = p->next;
+ property__free(&p);
+ p = next;
+ }
+ *property = NULL;
+}
+
+
+int property__get_length(const mosquitto_property *property)
+{
+ if(!property) return 0;
+
+ switch(property->identifier){
+ /* Byte */
+ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
+ case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
+ case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
+ case MQTT_PROP_MAXIMUM_QOS:
+ case MQTT_PROP_RETAIN_AVAILABLE:
+ case MQTT_PROP_WILDCARD_SUB_AVAILABLE:
+ case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE:
+ case MQTT_PROP_SHARED_SUB_AVAILABLE:
+ return 2; /* 1 (identifier) + 1 byte */
+
+ /* uint16 */
+ case MQTT_PROP_SERVER_KEEP_ALIVE:
+ case MQTT_PROP_RECEIVE_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS:
+ return 3; /* 1 (identifier) + 2 bytes */
+
+ /* uint32 */
+ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
+ case MQTT_PROP_WILL_DELAY_INTERVAL:
+ case MQTT_PROP_MAXIMUM_PACKET_SIZE:
+ case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
+ return 5; /* 1 (identifier) + 4 bytes */
+
+ /* varint */
+ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
+ if(property->value.varint < 128){
+ return 2;
+ }else if(property->value.varint < 16384){
+ return 3;
+ }else if(property->value.varint < 2097152){
+ return 4;
+ }else if(property->value.varint < 268435456){
+ return 5;
+ }else{
+ return 0;
+ }
+
+ /* binary */
+ case MQTT_PROP_CORRELATION_DATA:
+ case MQTT_PROP_AUTHENTICATION_DATA:
+ return 3 + property->value.bin.len; /* 1 + 2 bytes (len) + X bytes (payload) */
+
+ /* string */
+ case MQTT_PROP_CONTENT_TYPE:
+ case MQTT_PROP_RESPONSE_TOPIC:
+ case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
+ case MQTT_PROP_AUTHENTICATION_METHOD:
+ case MQTT_PROP_RESPONSE_INFORMATION:
+ case MQTT_PROP_SERVER_REFERENCE:
+ case MQTT_PROP_REASON_STRING:
+ return 3 + property->value.s.len; /* 1 + 2 bytes (len) + X bytes (string) */
+
+ /* string pair */
+ case MQTT_PROP_USER_PROPERTY:
+ return 5 + property->value.s.len + property->name.len; /* 1 + 2*(2 bytes (len) + X bytes (string))*/
+
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+
+int property__get_length_all(const mosquitto_property *property)
+{
+ const mosquitto_property *p;
+ int len = 0;
+
+ p = property;
+ while(p){
+ len += property__get_length(p);
+ p = p->next;
+ }
+ return len;
+}
+
+
+int property__write(struct mosquitto__packet *packet, const mosquitto_property *property)
+{
+ int rc;
+
+ rc = packet__write_varint(packet, property->identifier);
+ if(rc) return rc;
+
+ switch(property->identifier){
+ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
+ case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
+ case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
+ case MQTT_PROP_MAXIMUM_QOS:
+ case MQTT_PROP_RETAIN_AVAILABLE:
+ case MQTT_PROP_WILDCARD_SUB_AVAILABLE:
+ case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE:
+ case MQTT_PROP_SHARED_SUB_AVAILABLE:
+ packet__write_byte(packet, property->value.i8);
+ break;
+
+ case MQTT_PROP_SERVER_KEEP_ALIVE:
+ case MQTT_PROP_RECEIVE_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS:
+ packet__write_uint16(packet, property->value.i16);
+ break;
+
+ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
+ case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
+ case MQTT_PROP_WILL_DELAY_INTERVAL:
+ case MQTT_PROP_MAXIMUM_PACKET_SIZE:
+ packet__write_uint32(packet, property->value.i32);
+ break;
+
+ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
+ return packet__write_varint(packet, property->value.varint);
+
+ case MQTT_PROP_CONTENT_TYPE:
+ case MQTT_PROP_RESPONSE_TOPIC:
+ case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
+ case MQTT_PROP_AUTHENTICATION_METHOD:
+ case MQTT_PROP_RESPONSE_INFORMATION:
+ case MQTT_PROP_SERVER_REFERENCE:
+ case MQTT_PROP_REASON_STRING:
+ packet__write_string(packet, property->value.s.v, property->value.s.len);
+ break;
+
+ case MQTT_PROP_AUTHENTICATION_DATA:
+ case MQTT_PROP_CORRELATION_DATA:
+ packet__write_uint16(packet, property->value.bin.len);
+ packet__write_bytes(packet, property->value.bin.v, property->value.bin.len);
+ break;
+
+ case MQTT_PROP_USER_PROPERTY:
+ packet__write_string(packet, property->name.v, property->name.len);
+ packet__write_string(packet, property->value.s.v, property->value.s.len);
+ break;
+
+ default:
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property->identifier);
+ return MOSQ_ERR_INVAL;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *properties, bool write_len)
+{
+ int rc;
+ const mosquitto_property *p;
+
+ if(write_len){
+ rc = packet__write_varint(packet, property__get_length_all(properties));
+ if(rc) return rc;
+ }
+
+ p = properties;
+ while(p){
+ rc = property__write(packet, p);
+ if(rc) return rc;
+ p = p->next;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_check_command(int command, int identifier)
+{
+ switch(identifier){
+ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
+ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
+ case MQTT_PROP_CONTENT_TYPE:
+ case MQTT_PROP_RESPONSE_TOPIC:
+ case MQTT_PROP_CORRELATION_DATA:
+ if(command != CMD_PUBLISH && command != CMD_WILL){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
+ if(command != CMD_PUBLISH && command != CMD_SUBSCRIBE){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
+ if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_DISCONNECT){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_AUTHENTICATION_METHOD:
+ case MQTT_PROP_AUTHENTICATION_DATA:
+ if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_AUTH){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
+ case MQTT_PROP_SERVER_KEEP_ALIVE:
+ case MQTT_PROP_RESPONSE_INFORMATION:
+ case MQTT_PROP_MAXIMUM_QOS:
+ case MQTT_PROP_RETAIN_AVAILABLE:
+ case MQTT_PROP_WILDCARD_SUB_AVAILABLE:
+ case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE:
+ case MQTT_PROP_SHARED_SUB_AVAILABLE:
+ if(command != CMD_CONNACK){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_WILL_DELAY_INTERVAL:
+ if(command != CMD_WILL){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
+ case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
+ if(command != CMD_CONNECT){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_SERVER_REFERENCE:
+ if(command != CMD_CONNACK && command != CMD_DISCONNECT){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_REASON_STRING:
+ if(command == CMD_CONNECT || command == CMD_PUBLISH || command == CMD_SUBSCRIBE || command == CMD_UNSUBSCRIBE){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_RECEIVE_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
+ case MQTT_PROP_MAXIMUM_PACKET_SIZE:
+ if(command != CMD_CONNECT && command != CMD_CONNACK){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_TOPIC_ALIAS:
+ if(command != CMD_PUBLISH){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ break;
+
+ case MQTT_PROP_USER_PROPERTY:
+ break;
+
+ default:
+ return MOSQ_ERR_PROTOCOL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type)
+{
+ if(!propname) return MOSQ_ERR_INVAL;
+
+ if(!strcasecmp(propname, "payload-format-indicator")){
+ *identifier = MQTT_PROP_PAYLOAD_FORMAT_INDICATOR;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "message-expiry-interval")){
+ *identifier = MQTT_PROP_MESSAGE_EXPIRY_INTERVAL;
+ *type = MQTT_PROP_TYPE_INT32;
+ }else if(!strcasecmp(propname, "content-type")){
+ *identifier = MQTT_PROP_CONTENT_TYPE;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "response-topic")){
+ *identifier = MQTT_PROP_RESPONSE_TOPIC;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "correlation-data")){
+ *identifier = MQTT_PROP_CORRELATION_DATA;
+ *type = MQTT_PROP_TYPE_BINARY;
+ }else if(!strcasecmp(propname, "subscription-identifier")){
+ *identifier = MQTT_PROP_SUBSCRIPTION_IDENTIFIER;
+ *type = MQTT_PROP_TYPE_VARINT;
+ }else if(!strcasecmp(propname, "session-expiry-interval")){
+ *identifier = MQTT_PROP_SESSION_EXPIRY_INTERVAL;
+ *type = MQTT_PROP_TYPE_INT32;
+ }else if(!strcasecmp(propname, "assigned-client-identifier")){
+ *identifier = MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "server-keep-alive")){
+ *identifier = MQTT_PROP_SERVER_KEEP_ALIVE;
+ *type = MQTT_PROP_TYPE_INT16;
+ }else if(!strcasecmp(propname, "authentication-method")){
+ *identifier = MQTT_PROP_AUTHENTICATION_METHOD;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "authentication-data")){
+ *identifier = MQTT_PROP_AUTHENTICATION_DATA;
+ *type = MQTT_PROP_TYPE_BINARY;
+ }else if(!strcasecmp(propname, "request-problem-information")){
+ *identifier = MQTT_PROP_REQUEST_PROBLEM_INFORMATION;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "will-delay-interval")){
+ *identifier = MQTT_PROP_WILL_DELAY_INTERVAL;
+ *type = MQTT_PROP_TYPE_INT32;
+ }else if(!strcasecmp(propname, "request-response-information")){
+ *identifier = MQTT_PROP_REQUEST_RESPONSE_INFORMATION;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "response-information")){
+ *identifier = MQTT_PROP_RESPONSE_INFORMATION;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "server-reference")){
+ *identifier = MQTT_PROP_SERVER_REFERENCE;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "reason-string")){
+ *identifier = MQTT_PROP_REASON_STRING;
+ *type = MQTT_PROP_TYPE_STRING;
+ }else if(!strcasecmp(propname, "receive-maximum")){
+ *identifier = MQTT_PROP_RECEIVE_MAXIMUM;
+ *type = MQTT_PROP_TYPE_INT16;
+ }else if(!strcasecmp(propname, "topic-alias-maximum")){
+ *identifier = MQTT_PROP_TOPIC_ALIAS_MAXIMUM;
+ *type = MQTT_PROP_TYPE_INT16;
+ }else if(!strcasecmp(propname, "topic-alias")){
+ *identifier = MQTT_PROP_TOPIC_ALIAS;
+ *type = MQTT_PROP_TYPE_INT16;
+ }else if(!strcasecmp(propname, "maximum-qos")){
+ *identifier = MQTT_PROP_MAXIMUM_QOS;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "retain-available")){
+ *identifier = MQTT_PROP_RETAIN_AVAILABLE;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "user-property")){
+ *identifier = MQTT_PROP_USER_PROPERTY;
+ *type = MQTT_PROP_TYPE_STRING_PAIR;
+ }else if(!strcasecmp(propname, "maximum-packet-size")){
+ *identifier = MQTT_PROP_MAXIMUM_PACKET_SIZE;
+ *type = MQTT_PROP_TYPE_INT32;
+ }else if(!strcasecmp(propname, "wildcard-subscription-available")){
+ *identifier = MQTT_PROP_WILDCARD_SUB_AVAILABLE;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "subscription-identifier-available")){
+ *identifier = MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else if(!strcasecmp(propname, "shared-subscription-available")){
+ *identifier = MQTT_PROP_SHARED_SUB_AVAILABLE;
+ *type = MQTT_PROP_TYPE_BYTE;
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+static void property__add(mosquitto_property **proplist, struct mqtt5__property *prop)
+{
+ mosquitto_property *p;
+
+ if(!(*proplist)){
+ *proplist = prop;
+ }
+
+ p = *proplist;
+ while(p->next){
+ p = p->next;
+ }
+ p->next = prop;
+ prop->next = NULL;
+}
+
+
+int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value)
+{
+ mosquitto_property *prop;
+
+ if(!proplist) return MOSQ_ERR_INVAL;
+ if(identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR
+ && identifier != MQTT_PROP_REQUEST_PROBLEM_INFORMATION
+ && identifier != MQTT_PROP_REQUEST_RESPONSE_INFORMATION
+ && identifier != MQTT_PROP_MAXIMUM_QOS
+ && identifier != MQTT_PROP_RETAIN_AVAILABLE
+ && identifier != MQTT_PROP_WILDCARD_SUB_AVAILABLE
+ && identifier != MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE
+ && identifier != MQTT_PROP_SHARED_SUB_AVAILABLE){
+ return MOSQ_ERR_INVAL;
+ }
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+ prop->value.i8 = value;
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value)
+{
+ mosquitto_property *prop;
+
+ if(!proplist) return MOSQ_ERR_INVAL;
+ if(identifier != MQTT_PROP_SERVER_KEEP_ALIVE
+ && identifier != MQTT_PROP_RECEIVE_MAXIMUM
+ && identifier != MQTT_PROP_TOPIC_ALIAS_MAXIMUM
+ && identifier != MQTT_PROP_TOPIC_ALIAS){
+ return MOSQ_ERR_INVAL;
+ }
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+ prop->value.i16 = value;
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value)
+{
+ mosquitto_property *prop;
+
+ if(!proplist) return MOSQ_ERR_INVAL;
+ if(identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL
+ && identifier != MQTT_PROP_SESSION_EXPIRY_INTERVAL
+ && identifier != MQTT_PROP_WILL_DELAY_INTERVAL
+ && identifier != MQTT_PROP_MAXIMUM_PACKET_SIZE){
+
+ return MOSQ_ERR_INVAL;
+ }
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+ prop->value.i32 = value;
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value)
+{
+ mosquitto_property *prop;
+
+ if(!proplist || value > 268435455) return MOSQ_ERR_INVAL;
+ if(identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER) return MOSQ_ERR_INVAL;
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+ prop->value.varint = value;
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len)
+{
+ mosquitto_property *prop;
+
+ if(!proplist) return MOSQ_ERR_INVAL;
+ if(identifier != MQTT_PROP_CORRELATION_DATA
+ && identifier != MQTT_PROP_AUTHENTICATION_DATA){
+
+ return MOSQ_ERR_INVAL;
+ }
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+
+ if(len){
+ prop->value.bin.v = mosquitto__malloc(len);
+ if(!prop->value.bin.v){
+ mosquitto__free(prop);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ memcpy(prop->value.bin.v, value, len);
+ prop->value.bin.len = len;
+ }
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value)
+{
+ mosquitto_property *prop;
+
+ if(!proplist) return MOSQ_ERR_INVAL;
+ if(value){
+ if(mosquitto_validate_utf8(value, strlen(value))) return MOSQ_ERR_MALFORMED_UTF8;
+ }
+
+ if(identifier != MQTT_PROP_CONTENT_TYPE
+ && identifier != MQTT_PROP_RESPONSE_TOPIC
+ && identifier != MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER
+ && identifier != MQTT_PROP_AUTHENTICATION_METHOD
+ && identifier != MQTT_PROP_RESPONSE_INFORMATION
+ && identifier != MQTT_PROP_SERVER_REFERENCE
+ && identifier != MQTT_PROP_REASON_STRING){
+
+ return MOSQ_ERR_INVAL;
+ }
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+ if(value && strlen(value)){
+ prop->value.s.v = mosquitto__strdup(value);
+ if(!prop->value.s.v){
+ mosquitto__free(prop);
+ return MOSQ_ERR_NOMEM;
+ }
+ prop->value.s.len = strlen(value);
+ }
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+
+int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value)
+{
+ mosquitto_property *prop;
+
+ if(!proplist) return MOSQ_ERR_INVAL;
+ if(identifier != MQTT_PROP_USER_PROPERTY) return MOSQ_ERR_INVAL;
+ if(name){
+ if(mosquitto_validate_utf8(name, strlen(name))) return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ if(value){
+ if(mosquitto_validate_utf8(value, strlen(value))) return MOSQ_ERR_MALFORMED_UTF8;
+ }
+
+ prop = mosquitto__calloc(1, sizeof(mosquitto_property));
+ if(!prop) return MOSQ_ERR_NOMEM;
+
+ prop->client_generated = true;
+ prop->identifier = identifier;
+
+ if(name && strlen(name)){
+ prop->name.v = mosquitto__strdup(name);
+ if(!prop->name.v){
+ mosquitto__free(prop);
+ return MOSQ_ERR_NOMEM;
+ }
+ prop->name.len = strlen(name);
+ }
+
+ if(value && strlen(value)){
+ prop->value.s.v = mosquitto__strdup(value);
+ if(!prop->value.s.v){
+ mosquitto__free(prop->name.v);
+ mosquitto__free(prop);
+ return MOSQ_ERR_NOMEM;
+ }
+ prop->value.s.len = strlen(value);
+ }
+
+ property__add(proplist, prop);
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_property_check_all(int command, const mosquitto_property *properties)
+{
+ const mosquitto_property *p, *tail;
+ int rc;
+
+ p = properties;
+
+ while(p){
+ /* Validity checks */
+ if(p->identifier == MQTT_PROP_REQUEST_PROBLEM_INFORMATION
+ || p->identifier == MQTT_PROP_REQUEST_RESPONSE_INFORMATION
+ || p->identifier == MQTT_PROP_MAXIMUM_QOS
+ || p->identifier == MQTT_PROP_RETAIN_AVAILABLE
+ || p->identifier == MQTT_PROP_WILDCARD_SUB_AVAILABLE
+ || p->identifier == MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE
+ || p->identifier == MQTT_PROP_SHARED_SUB_AVAILABLE){
+
+ if(p->value.i8 > 1){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ }else if(p->identifier == MQTT_PROP_MAXIMUM_PACKET_SIZE){
+ if( p->value.i32 == 0){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ }else if(p->identifier == MQTT_PROP_RECEIVE_MAXIMUM
+ || p->identifier == MQTT_PROP_TOPIC_ALIAS){
+
+ if(p->value.i16 == 0){
+ return MOSQ_ERR_PROTOCOL;
+ }
+ }
+
+ /* Check for properties on incorrect commands */
+ rc = mosquitto_property_check_command(command, p->identifier);
+ if(rc) return rc;
+
+ /* Check for duplicates */
+ tail = p->next;
+ while(tail){
+ if(p->identifier == tail->identifier
+ && p->identifier != MQTT_PROP_USER_PROPERTY){
+
+ return MOSQ_ERR_DUPLICATE_PROPERTY;
+ }
+ tail = tail->next;
+ }
+
+ p = p->next;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+const mosquitto_property *property__get_property(const mosquitto_property *proplist, int identifier, bool skip_first)
+{
+ const mosquitto_property *p;
+ bool is_first = true;
+
+ p = proplist;
+
+ while(p){
+ if(p->identifier == identifier){
+ if(!is_first || !skip_first){
+ return p;
+ }
+ is_first = false;
+ }
+ p = p->next;
+ }
+ return NULL;
+}
+
+
+const mosquitto_property *mosquitto_property_read_byte(const mosquitto_property *proplist, int identifier, uint8_t *value, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR
+ && p->identifier != MQTT_PROP_REQUEST_PROBLEM_INFORMATION
+ && p->identifier != MQTT_PROP_REQUEST_RESPONSE_INFORMATION
+ && p->identifier != MQTT_PROP_MAXIMUM_QOS
+ && p->identifier != MQTT_PROP_RETAIN_AVAILABLE
+ && p->identifier != MQTT_PROP_WILDCARD_SUB_AVAILABLE
+ && p->identifier != MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE
+ && p->identifier != MQTT_PROP_SHARED_SUB_AVAILABLE){
+ return NULL;
+ }
+
+ if(value) *value = p->value.i8;
+
+ return p;
+}
+
+
+const mosquitto_property *mosquitto_property_read_int16(const mosquitto_property *proplist, int identifier, uint16_t *value, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_SERVER_KEEP_ALIVE
+ && p->identifier != MQTT_PROP_RECEIVE_MAXIMUM
+ && p->identifier != MQTT_PROP_TOPIC_ALIAS_MAXIMUM
+ && p->identifier != MQTT_PROP_TOPIC_ALIAS){
+ return NULL;
+ }
+
+ if(value) *value = p->value.i16;
+
+ return p;
+}
+
+
+const mosquitto_property *mosquitto_property_read_int32(const mosquitto_property *proplist, int identifier, uint32_t *value, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL
+ && p->identifier != MQTT_PROP_SESSION_EXPIRY_INTERVAL
+ && p->identifier != MQTT_PROP_WILL_DELAY_INTERVAL
+ && p->identifier != MQTT_PROP_MAXIMUM_PACKET_SIZE){
+
+ return NULL;
+ }
+
+ if(value) *value = p->value.i32;
+
+ return p;
+}
+
+
+const mosquitto_property *mosquitto_property_read_varint(const mosquitto_property *proplist, int identifier, uint32_t *value, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER){
+ return NULL;
+ }
+
+ if(value) *value = p->value.varint;
+
+ return p;
+}
+
+
+const mosquitto_property *mosquitto_property_read_binary(const mosquitto_property *proplist, int identifier, void **value, uint16_t *len, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist || (value && !len) || (!value && len)) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_CORRELATION_DATA
+ && p->identifier != MQTT_PROP_AUTHENTICATION_DATA){
+
+ return NULL;
+ }
+
+ if(value){
+ *len = p->value.bin.len;
+ *value = malloc(*len);
+ if(!(*value)) return NULL;
+
+ memcpy(*value, p->value.bin.v, *len);
+ }
+
+ return p;
+}
+
+
+const mosquitto_property *mosquitto_property_read_string(const mosquitto_property *proplist, int identifier, char **value, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_CONTENT_TYPE
+ && p->identifier != MQTT_PROP_RESPONSE_TOPIC
+ && p->identifier != MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER
+ && p->identifier != MQTT_PROP_AUTHENTICATION_METHOD
+ && p->identifier != MQTT_PROP_RESPONSE_INFORMATION
+ && p->identifier != MQTT_PROP_SERVER_REFERENCE
+ && p->identifier != MQTT_PROP_REASON_STRING){
+
+ return NULL;
+ }
+
+ if(value){
+ *value = calloc(1, p->value.s.len+1);
+ if(!(*value)) return NULL;
+
+ memcpy(*value, p->value.s.v, p->value.s.len);
+ }
+
+ return p;
+}
+
+
+const mosquitto_property *mosquitto_property_read_string_pair(const mosquitto_property *proplist, int identifier, char **name, char **value, bool skip_first)
+{
+ const mosquitto_property *p;
+ if(!proplist) return NULL;
+
+ p = property__get_property(proplist, identifier, skip_first);
+ if(!p) return NULL;
+ if(p->identifier != MQTT_PROP_USER_PROPERTY) return NULL;
+
+ if(name){
+ *name = calloc(1, p->name.len+1);
+ if(!(*name)) return NULL;
+ memcpy(*name, p->name.v, p->name.len);
+ }
+
+ if(value){
+ *value = calloc(1, p->value.s.len+1);
+ if(!(*value)){
+ if(name) free(*name);
+ return NULL;
+ }
+ memcpy(*value, p->value.s.v, p->value.s.len);
+ }
+
+ return p;
+}
+
+
+int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_property *src)
+{
+ mosquitto_property *pnew, *plast = NULL;
+
+ if(!src) return MOSQ_ERR_SUCCESS;
+ if(!dest) return MOSQ_ERR_INVAL;
+
+ *dest = NULL;
+
+ while(src){
+ pnew = calloc(1, sizeof(mosquitto_property));
+ if(!pnew){
+ mosquitto_property_free_all(dest);
+ return MOSQ_ERR_NOMEM;
+ }
+ if(plast){
+ plast->next = pnew;
+ }else{
+ *dest = pnew;
+ }
+ plast = pnew;
+
+ pnew->identifier = src->identifier;
+ switch(pnew->identifier){
+ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
+ case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
+ case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
+ case MQTT_PROP_MAXIMUM_QOS:
+ case MQTT_PROP_RETAIN_AVAILABLE:
+ case MQTT_PROP_WILDCARD_SUB_AVAILABLE:
+ case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE:
+ case MQTT_PROP_SHARED_SUB_AVAILABLE:
+ pnew->value.i8 = src->value.i8;
+ break;
+
+ case MQTT_PROP_SERVER_KEEP_ALIVE:
+ case MQTT_PROP_RECEIVE_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
+ case MQTT_PROP_TOPIC_ALIAS:
+ pnew->value.i16 = src->value.i16;
+ break;
+
+ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
+ case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
+ case MQTT_PROP_WILL_DELAY_INTERVAL:
+ case MQTT_PROP_MAXIMUM_PACKET_SIZE:
+ pnew->value.i32 = src->value.i32;
+ break;
+
+ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
+ pnew->value.varint = src->value.varint;
+ break;
+
+ case MQTT_PROP_CONTENT_TYPE:
+ case MQTT_PROP_RESPONSE_TOPIC:
+ case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
+ case MQTT_PROP_AUTHENTICATION_METHOD:
+ case MQTT_PROP_RESPONSE_INFORMATION:
+ case MQTT_PROP_SERVER_REFERENCE:
+ case MQTT_PROP_REASON_STRING:
+ pnew->value.s.len = src->value.s.len;
+ pnew->value.s.v = strdup(src->value.s.v);
+ if(!pnew->value.s.v){
+ mosquitto_property_free_all(dest);
+ return MOSQ_ERR_NOMEM;
+ }
+ break;
+
+ case MQTT_PROP_AUTHENTICATION_DATA:
+ case MQTT_PROP_CORRELATION_DATA:
+ pnew->value.bin.len = src->value.bin.len;
+ pnew->value.bin.v = malloc(pnew->value.bin.len);
+ if(!pnew->value.bin.v){
+ mosquitto_property_free_all(dest);
+ return MOSQ_ERR_NOMEM;
+ }
+ memcpy(pnew->value.bin.v, src->value.bin.v, pnew->value.bin.len);
+ break;
+
+ case MQTT_PROP_USER_PROPERTY:
+ pnew->value.s.len = src->value.s.len;
+ pnew->value.s.v = strdup(src->value.s.v);
+ if(!pnew->value.s.v){
+ mosquitto_property_free_all(dest);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ pnew->name.len = src->name.len;
+ pnew->name.v = strdup(src->name.v);
+ if(!pnew->name.v){
+ mosquitto_property_free_all(dest);
+ return MOSQ_ERR_NOMEM;
+ }
+ break;
+
+ default:
+ mosquitto_property_free_all(dest);
+ return MOSQ_ERR_INVAL;
+ }
+
+ src = src->next;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
diff --git a/libs/libmosquitto/src/property_mosq.h b/libs/libmosquitto/src/property_mosq.h
new file mode 100644
index 0000000000..d965d8a3e6
--- /dev/null
+++ b/libs/libmosquitto/src/property_mosq.h
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef PROPERTY_MOSQ_H
+#define PROPERTY_MOSQ_H
+
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+
+struct mqtt__string {
+ char *v;
+ int len;
+};
+
+struct mqtt5__property {
+ struct mqtt5__property *next;
+ union {
+ uint8_t i8;
+ uint16_t i16;
+ uint32_t i32;
+ uint32_t varint;
+ struct mqtt__string bin;
+ struct mqtt__string s;
+ } value;
+ struct mqtt__string name;
+ int32_t identifier;
+ bool client_generated;
+};
+
+
+int property__read_all(int command, struct mosquitto__packet *packet, mosquitto_property **property);
+int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *property, bool write_len);
+void property__free(mosquitto_property **property);
+
+int property__get_length(const mosquitto_property *property);
+int property__get_length_all(const mosquitto_property *property);
+
+#endif
diff --git a/libs/libmosquitto/src/read_handle.c b/libs/libmosquitto/src/read_handle.c
new file mode 100644
index 0000000000..19c0c35b1e
--- /dev/null
+++ b/libs/libmosquitto/src/read_handle.c
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "messages_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "util_mosq.h"
+
+int handle__packet(struct mosquitto *mosq)
+{
+ assert(mosq);
+
+ switch((mosq->in_packet.command)&0xF0){
+ case CMD_PINGREQ:
+ return handle__pingreq(mosq);
+ case CMD_PINGRESP:
+ return handle__pingresp(mosq);
+ case CMD_PUBACK:
+ return handle__pubackcomp(mosq, "PUBACK");
+ case CMD_PUBCOMP:
+ return handle__pubackcomp(mosq, "PUBCOMP");
+ case CMD_PUBLISH:
+ return handle__publish(mosq);
+ case CMD_PUBREC:
+ return handle__pubrec(NULL, mosq);
+ case CMD_PUBREL:
+ return handle__pubrel(NULL, mosq);
+ case CMD_CONNACK:
+ return handle__connack(mosq);
+ case CMD_SUBACK:
+ return handle__suback(mosq);
+ case CMD_UNSUBACK:
+ return handle__unsuback(mosq);
+ case CMD_DISCONNECT:
+ return handle__disconnect(mosq);
+ case CMD_AUTH:
+ return handle__auth(mosq);
+ default:
+ /* If we don't recognise the command, return an error straight away. */
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unrecognised command %d\n", (mosq->in_packet.command)&0xF0);
+ return MOSQ_ERR_PROTOCOL;
+ }
+}
+
diff --git a/libs/libmosquitto/src/read_handle.h b/libs/libmosquitto/src/read_handle.h
new file mode 100644
index 0000000000..2a6936d817
--- /dev/null
+++ b/libs/libmosquitto/src/read_handle.h
@@ -0,0 +1,40 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef READ_HANDLE_H
+#define READ_HANDLE_H
+
+#include "mosquitto.h"
+struct mosquitto_db;
+
+int handle__pingreq(struct mosquitto *mosq);
+int handle__pingresp(struct mosquitto *mosq);
+#ifdef WITH_BROKER
+int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type);
+#else
+int handle__packet(struct mosquitto *mosq);
+int handle__connack(struct mosquitto *mosq);
+int handle__disconnect(struct mosquitto *mosq);
+int handle__pubackcomp(struct mosquitto *mosq, const char *type);
+int handle__publish(struct mosquitto *mosq);
+int handle__auth(struct mosquitto *mosq);
+#endif
+int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq);
+int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq);
+int handle__suback(struct mosquitto *mosq);
+int handle__unsuback(struct mosquitto *mosq);
+
+
+#endif
diff --git a/libs/libmosquitto/src/send_connect.c b/libs/libmosquitto/src/send_connect.c
new file mode 100644
index 0000000000..210f125a80
--- /dev/null
+++ b/libs/libmosquitto/src/send_connect.c
@@ -0,0 +1,204 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+
+int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties)
+{
+ struct mosquitto__packet *packet = NULL;
+ int payloadlen;
+ uint8_t will = 0;
+ uint8_t byte;
+ int rc;
+ uint8_t version;
+ char *clientid, *username, *password;
+ int headerlen;
+ int proplen = 0, will_proplen, varbytes;
+ mosquitto_property *local_props = NULL;
+ uint16_t receive_maximum;
+
+ assert(mosq);
+
+ if(mosq->protocol == mosq_p_mqtt31 && !mosq->id) return MOSQ_ERR_PROTOCOL;
+
+#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
+ if(mosq->bridge){
+ clientid = mosq->bridge->remote_clientid;
+ username = mosq->bridge->remote_username;
+ password = mosq->bridge->remote_password;
+ }else{
+ clientid = mosq->id;
+ username = mosq->username;
+ password = mosq->password;
+ }
+#else
+ clientid = mosq->id;
+ username = mosq->username;
+ password = mosq->password;
+#endif
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ /* Generate properties from options */
+ if(!mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &receive_maximum, false)){
+ rc = mosquitto_property_add_int16(&local_props, MQTT_PROP_RECEIVE_MAXIMUM, mosq->msgs_in.inflight_maximum);
+ if(rc) return rc;
+ }else{
+ mosq->msgs_in.inflight_maximum = receive_maximum;
+ mosq->msgs_in.inflight_quota = receive_maximum;
+ }
+
+ version = MQTT_PROTOCOL_V5;
+ headerlen = 10;
+ proplen = 0;
+ proplen += property__get_length_all(properties);
+ proplen += property__get_length_all(local_props);
+ varbytes = packet__varint_bytes(proplen);
+ headerlen += proplen + varbytes;
+ }else if(mosq->protocol == mosq_p_mqtt311){
+ version = MQTT_PROTOCOL_V311;
+ headerlen = 10;
+ }else if(mosq->protocol == mosq_p_mqtt31){
+ version = MQTT_PROTOCOL_V31;
+ headerlen = 12;
+ }else{
+ return MOSQ_ERR_INVAL;
+ }
+
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ if(clientid){
+ payloadlen = 2+strlen(clientid);
+ }else{
+ payloadlen = 2;
+ }
+ if(mosq->will){
+ will = 1;
+ assert(mosq->will->msg.topic);
+
+ payloadlen += 2+strlen(mosq->will->msg.topic) + 2+mosq->will->msg.payloadlen;
+ if(mosq->protocol == mosq_p_mqtt5){
+ will_proplen = property__get_length_all(mosq->will->properties);
+ varbytes = packet__varint_bytes(will_proplen);
+ payloadlen += will_proplen + varbytes;
+ }
+ }
+
+ /* After this check we can be sure that the username and password are
+ * always valid for the current protocol, so there is no need to check
+ * username before checking password. */
+ if(mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311){
+ if(password != NULL && username == NULL){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+
+ if(username){
+ payloadlen += 2+strlen(username);
+ }
+ if(password){
+ payloadlen += 2+strlen(password);
+ }
+
+ packet->command = CMD_CONNECT;
+ packet->remaining_length = headerlen + payloadlen;
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+
+ /* Variable header */
+ if(version == MQTT_PROTOCOL_V31){
+ packet__write_string(packet, PROTOCOL_NAME_v31, strlen(PROTOCOL_NAME_v31));
+ }else{
+ packet__write_string(packet, PROTOCOL_NAME, strlen(PROTOCOL_NAME));
+ }
+#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
+ if(mosq->bridge && mosq->bridge->try_private && mosq->bridge->try_private_accepted){
+ version |= 0x80;
+ }else{
+ }
+#endif
+ packet__write_byte(packet, version);
+ byte = (clean_session&0x1)<<1;
+ if(will){
+ byte = byte | ((mosq->will->msg.retain&0x1)<<5) | ((mosq->will->msg.qos&0x3)<<3) | ((will&0x1)<<2);
+ }
+ if(username){
+ byte = byte | 0x1<<7;
+ }
+ if(mosq->password){
+ byte = byte | 0x1<<6;
+ }
+ packet__write_byte(packet, byte);
+ packet__write_uint16(packet, keepalive);
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ /* Write properties */
+ packet__write_varint(packet, proplen);
+ property__write_all(packet, properties, false);
+ property__write_all(packet, local_props, false);
+ }
+
+ /* Payload */
+ if(clientid){
+ packet__write_string(packet, clientid, strlen(clientid));
+ }else{
+ packet__write_uint16(packet, 0);
+ }
+ if(will){
+ if(mosq->protocol == mosq_p_mqtt5){
+ /* Write will properties */
+ property__write_all(packet, mosq->will->properties, true);
+ }
+ packet__write_string(packet, mosq->will->msg.topic, strlen(mosq->will->msg.topic));
+ packet__write_string(packet, (const char *)mosq->will->msg.payload, mosq->will->msg.payloadlen);
+ }
+
+ if(username){
+ packet__write_string(packet, username, strlen(username));
+ }
+ if(password){
+ packet__write_string(packet, password, strlen(password));
+ }
+
+ mosq->keepalive = keepalive;
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending CONNECT", clientid);
+# endif
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending CONNECT", clientid);
+#endif
+ return packet__queue(mosq, packet);
+}
+
diff --git a/libs/libmosquitto/src/send_disconnect.c b/libs/libmosquitto/src/send_disconnect.c
new file mode 100644
index 0000000000..3598988755
--- /dev/null
+++ b/libs/libmosquitto/src/send_disconnect.c
@@ -0,0 +1,85 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "send_mosq.h"
+
+
+int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitto_property *properties)
+{
+ struct mosquitto__packet *packet = NULL;
+ int rc;
+ int proplen, varbytes;
+
+ assert(mosq);
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+ if(mosq->bridge){
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending DISCONNECT", mosq->id);
+ }else
+# else
+ {
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Sending DISCONNECT to %s (rc%d)", mosq->id, reason_code);
+ }
+# endif
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending DISCONNECT", mosq->id);
+#endif
+ assert(mosq);
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ packet->command = CMD_DISCONNECT;
+ if(mosq->protocol == mosq_p_mqtt5 && (reason_code != 0 || properties)){
+ packet->remaining_length = 1;
+ if(properties){
+ proplen = property__get_length_all(properties);
+ varbytes = packet__varint_bytes(proplen);
+ packet->remaining_length += proplen + varbytes;
+ }
+ }else{
+ packet->remaining_length = 0;
+ }
+
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+ if(mosq->protocol == mosq_p_mqtt5 && (reason_code != 0 || properties)){
+ packet__write_byte(packet, reason_code);
+ if(properties){
+ property__write_all(packet, properties, true);
+ }
+ }
+
+ return packet__queue(mosq, packet);
+}
+
diff --git a/libs/libmosquitto/src/send_mosq.c b/libs/libmosquitto/src/send_mosq.c
new file mode 100644
index 0000000000..27bc1fda17
--- /dev/null
+++ b/libs/libmosquitto/src/send_mosq.c
@@ -0,0 +1,188 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+# include "sys_tree.h"
+#else
+# define G_PUB_BYTES_SENT_INC(A)
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "mqtt_protocol.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "util_mosq.h"
+
+int send__pingreq(struct mosquitto *mosq)
+{
+ int rc;
+ assert(mosq);
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGREQ to %s", mosq->id);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGREQ", mosq->id);
+#endif
+ rc = send__simple_command(mosq, CMD_PINGREQ);
+ if(rc == MOSQ_ERR_SUCCESS){
+ mosq->ping_t = mosquitto_time();
+ }
+ return rc;
+}
+
+int send__pingresp(struct mosquitto *mosq)
+{
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGRESP to %s", mosq->id);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGRESP", mosq->id);
+#endif
+ return send__simple_command(mosq, CMD_PINGRESP);
+}
+
+int send__puback(struct mosquitto *mosq, uint16_t mid, uint8_t reason_code)
+{
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBACK to %s (m%d, rc%d)", mosq->id, mid, reason_code);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (m%d, rc%d)", mosq->id, mid, reason_code);
+#endif
+ util__increment_receive_quota(mosq);
+ /* We don't use Reason String or User Property yet. */
+ return send__command_with_mid(mosq, CMD_PUBACK, mid, false, reason_code, NULL);
+}
+
+int send__pubcomp(struct mosquitto *mosq, uint16_t mid)
+{
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBCOMP to %s (m%d)", mosq->id, mid);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (m%d)", mosq->id, mid);
+#endif
+ util__increment_receive_quota(mosq);
+ /* We don't use Reason String or User Property yet. */
+ return send__command_with_mid(mosq, CMD_PUBCOMP, mid, false, 0, NULL);
+}
+
+
+int send__pubrec(struct mosquitto *mosq, uint16_t mid, uint8_t reason_code)
+{
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREC to %s (m%d, rc%d)", mosq->id, mid, reason_code);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (m%d, rc%d)", mosq->id, mid, reason_code);
+#endif
+ if(reason_code >= 0x80 && mosq->protocol == mosq_p_mqtt5){
+ util__increment_receive_quota(mosq);
+ }
+ /* We don't use Reason String or User Property yet. */
+ return send__command_with_mid(mosq, CMD_PUBREC, mid, false, reason_code, NULL);
+}
+
+int send__pubrel(struct mosquitto *mosq, uint16_t mid)
+{
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREL to %s (m%d)", mosq->id, mid);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (m%d)", mosq->id, mid);
+#endif
+ /* We don't use Reason String or User Property yet. */
+ return send__command_with_mid(mosq, CMD_PUBREL|2, mid, false, 0, NULL);
+}
+
+/* For PUBACK, PUBCOMP, PUBREC, and PUBREL */
+int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties)
+{
+ struct mosquitto__packet *packet = NULL;
+ int rc;
+ int proplen, varbytes;
+
+ assert(mosq);
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ packet->command = command;
+ if(dup){
+ packet->command |= 8;
+ }
+ packet->remaining_length = 2;
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ if(reason_code != 0 || properties){
+ packet->remaining_length += 1;
+ }
+
+ if(properties){
+ proplen = property__get_length_all(properties);
+ varbytes = packet__varint_bytes(proplen);
+ packet->remaining_length += varbytes + proplen;
+ }
+ }
+
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+
+ packet__write_uint16(packet, mid);
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ if(reason_code != 0 || properties){
+ packet__write_byte(packet, reason_code);
+ }
+ if(properties){
+ property__write_all(packet, properties, true);
+ }
+ }
+
+ return packet__queue(mosq, packet);
+}
+
+/* For DISCONNECT, PINGREQ and PINGRESP */
+int send__simple_command(struct mosquitto *mosq, uint8_t command)
+{
+ struct mosquitto__packet *packet = NULL;
+ int rc;
+
+ assert(mosq);
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ packet->command = command;
+ packet->remaining_length = 0;
+
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+
+ return packet__queue(mosq, packet);
+}
+
diff --git a/libs/libmosquitto/src/send_mosq.h b/libs/libmosquitto/src/send_mosq.h
new file mode 100644
index 0000000000..4b76f2f952
--- /dev/null
+++ b/libs/libmosquitto/src/send_mosq.h
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef SEND_MOSQ_H
+#define SEND_MOSQ_H
+
+#include "mosquitto.h"
+#include "property_mosq.h"
+
+int send__simple_command(struct mosquitto *mosq, uint8_t command);
+int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties);
+int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval);
+
+int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties);
+int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitto_property *properties);
+int send__pingreq(struct mosquitto *mosq);
+int send__pingresp(struct mosquitto *mosq);
+int send__puback(struct mosquitto *mosq, uint16_t mid, uint8_t reason_code);
+int send__pubcomp(struct mosquitto *mosq, uint16_t mid);
+int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval);
+int send__pubrec(struct mosquitto *mosq, uint16_t mid, uint8_t reason_code);
+int send__pubrel(struct mosquitto *mosq, uint16_t mid);
+int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const mosquitto_property *properties);
+int send__unsubscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, const mosquitto_property *properties);
+
+#endif
diff --git a/libs/libmosquitto/src/send_publish.c b/libs/libmosquitto/src/send_publish.c
new file mode 100644
index 0000000000..f07c539d40
--- /dev/null
+++ b/libs/libmosquitto/src/send_publish.c
@@ -0,0 +1,215 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+# include "sys_tree.h"
+#else
+# define G_PUB_BYTES_SENT_INC(A)
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "mqtt_protocol.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "send_mosq.h"
+
+
+int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval)
+{
+#ifdef WITH_BROKER
+ size_t len;
+#ifdef WITH_BRIDGE
+ int i;
+ struct mosquitto__bridge_topic *cur_topic;
+ bool match;
+ int rc;
+ char *mapped_topic = NULL;
+ char *topic_temp = NULL;
+#endif
+#endif
+ assert(mosq);
+
+#if defined(WITH_BROKER) && defined(WITH_WEBSOCKETS)
+ if(mosq->sock == INVALID_SOCKET && !mosq->wsi) return MOSQ_ERR_NO_CONN;
+#else
+ if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+#endif
+
+#ifdef WITH_BROKER
+ if(mosq->listener && mosq->listener->mount_point){
+ len = strlen(mosq->listener->mount_point);
+ if(len < strlen(topic)){
+ topic += len;
+ }else{
+ /* Invalid topic string. Should never happen, but silently swallow the message anyway. */
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+#ifdef WITH_BRIDGE
+ if(mosq->bridge && mosq->bridge->topics && mosq->bridge->topic_remapping){
+ for(i=0; i<mosq->bridge->topic_count; i++){
+ cur_topic = &mosq->bridge->topics[i];
+ if((cur_topic->direction == bd_both || cur_topic->direction == bd_out)
+ && (cur_topic->remote_prefix || cur_topic->local_prefix)){
+ /* Topic mapping required on this topic if the message matches */
+
+ rc = mosquitto_topic_matches_sub(cur_topic->local_topic, topic, &match);
+ if(rc){
+ return rc;
+ }
+ if(match){
+ mapped_topic = mosquitto__strdup(topic);
+ if(!mapped_topic) return MOSQ_ERR_NOMEM;
+ if(cur_topic->local_prefix){
+ /* This prefix needs removing. */
+ if(!strncmp(cur_topic->local_prefix, mapped_topic, strlen(cur_topic->local_prefix))){
+ topic_temp = mosquitto__strdup(mapped_topic+strlen(cur_topic->local_prefix));
+ mosquitto__free(mapped_topic);
+ if(!topic_temp){
+ return MOSQ_ERR_NOMEM;
+ }
+ mapped_topic = topic_temp;
+ }
+ }
+
+ if(cur_topic->remote_prefix){
+ /* This prefix needs adding. */
+ len = strlen(mapped_topic) + strlen(cur_topic->remote_prefix)+1;
+ topic_temp = mosquitto__malloc(len+1);
+ if(!topic_temp){
+ mosquitto__free(mapped_topic);
+ return MOSQ_ERR_NOMEM;
+ }
+ snprintf(topic_temp, len, "%s%s", cur_topic->remote_prefix, mapped_topic);
+ topic_temp[len] = '\0';
+ mosquitto__free(mapped_topic);
+ mapped_topic = topic_temp;
+ }
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen);
+ G_PUB_BYTES_SENT_INC(payloadlen);
+ rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props, expiry_interval);
+ mosquitto__free(mapped_topic);
+ return rc;
+ }
+ }
+ }
+ }
+#endif
+ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen);
+ G_PUB_BYTES_SENT_INC(payloadlen);
+#else
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen);
+#endif
+
+ return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props, expiry_interval);
+}
+
+
+int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval)
+{
+ struct mosquitto__packet *packet = NULL;
+ int packetlen;
+ int proplen = 0, varbytes;
+ int rc;
+ mosquitto_property expiry_prop;
+
+ assert(mosq);
+
+ if(topic){
+ packetlen = 2+strlen(topic) + payloadlen;
+ }else{
+ packetlen = 2 + payloadlen;
+ }
+ if(qos > 0) packetlen += 2; /* For message id */
+ if(mosq->protocol == mosq_p_mqtt5){
+ proplen = 0;
+ proplen += property__get_length_all(cmsg_props);
+ proplen += property__get_length_all(store_props);
+ if(expiry_interval > 0){
+ expiry_prop.next = NULL;
+ expiry_prop.value.i32 = expiry_interval;
+ expiry_prop.identifier = MQTT_PROP_MESSAGE_EXPIRY_INTERVAL;
+ expiry_prop.client_generated = false;
+
+ proplen += property__get_length_all(&expiry_prop);
+ }
+
+ varbytes = packet__varint_bytes(proplen);
+ if(varbytes > 4){
+ /* FIXME - Properties too big, don't publish any - should remove some first really */
+ cmsg_props = NULL;
+ store_props = NULL;
+ expiry_interval = 0;
+ }else{
+ packetlen += proplen + varbytes;
+ }
+ }
+ if(packet__check_oversize(mosq, packetlen)){
+#ifdef WITH_BROKER
+ log__printf(NULL, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH for %s (%d bytes)", mosq->id, packetlen);
+#else
+ log__printf(NULL, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH (%d bytes)", packetlen);
+#endif
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }
+
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ packet->mid = mid;
+ packet->command = CMD_PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain;
+ packet->remaining_length = packetlen;
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+ /* Variable header (topic string) */
+ if(topic){
+ packet__write_string(packet, topic, strlen(topic));
+ }else{
+ packet__write_uint16(packet, 0);
+ }
+ if(qos > 0){
+ packet__write_uint16(packet, mid);
+ }
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ packet__write_varint(packet, proplen);
+ property__write_all(packet, cmsg_props, false);
+ property__write_all(packet, store_props, false);
+ if(expiry_interval > 0){
+ property__write_all(packet, &expiry_prop, false);
+ }
+ }
+
+ /* Payload */
+ if(payloadlen){
+ packet__write_bytes(packet, payload, payloadlen);
+ }
+
+ return packet__queue(mosq, packet);
+}
diff --git a/libs/libmosquitto/src/send_subscribe.c b/libs/libmosquitto/src/send_subscribe.c
new file mode 100644
index 0000000000..1f2760f985
--- /dev/null
+++ b/libs/libmosquitto/src/send_subscribe.c
@@ -0,0 +1,96 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "util_mosq.h"
+
+
+int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos, const mosquitto_property *properties)
+{
+ struct mosquitto__packet *packet = NULL;
+ uint32_t packetlen;
+ uint16_t local_mid;
+ int rc;
+ int i;
+ int proplen, varbytes;
+
+ assert(mosq);
+ assert(topic);
+
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ packetlen = 2;
+ if(mosq->protocol == mosq_p_mqtt5){
+ proplen = property__get_length_all(properties);
+ varbytes = packet__varint_bytes(proplen);
+ packetlen += proplen + varbytes;
+ }
+ for(i=0; i<topic_count; i++){
+ packetlen += 2+strlen(topic[i]) + 1;
+ }
+
+ packet->command = CMD_SUBSCRIBE | (1<<1);
+ packet->remaining_length = packetlen;
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+
+ /* Variable header */
+ local_mid = mosquitto__mid_generate(mosq);
+ if(mid) *mid = (int)local_mid;
+ packet__write_uint16(packet, local_mid);
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ property__write_all(packet, properties, true);
+ }
+
+ /* Payload */
+ for(i=0; i<topic_count; i++){
+ packet__write_string(packet, topic[i], strlen(topic[i]));
+ packet__write_byte(packet, topic_qos);
+ }
+
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d, Options: 0x%02x)", mosq->id, local_mid, topic[0], topic_qos&0x03, topic_qos&0xFC);
+# endif
+#else
+ for(i=0; i<topic_count; i++){
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d, Options: 0x%02x)", mosq->id, local_mid, topic[i], topic_qos&0x03, topic_qos&0xFC);
+ }
+#endif
+
+ return packet__queue(mosq, packet);
+}
+
diff --git a/libs/libmosquitto/src/send_unsubscribe.c b/libs/libmosquitto/src/send_unsubscribe.c
new file mode 100644
index 0000000000..e7317151a5
--- /dev/null
+++ b/libs/libmosquitto/src/send_unsubscribe.c
@@ -0,0 +1,99 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "packet_mosq.h"
+#include "property_mosq.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+
+
+int send__unsubscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, const mosquitto_property *properties)
+{
+ /* FIXME - only deals with a single topic */
+ struct mosquitto__packet *packet = NULL;
+ uint32_t packetlen;
+ uint16_t local_mid;
+ int rc;
+ int proplen, varbytes;
+ int i;
+
+ assert(mosq);
+ assert(topic);
+
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ packetlen = 2;
+
+ for(i=0; i<topic_count; i++){
+ packetlen += 2+strlen(topic[i]);
+ }
+ if(mosq->protocol == mosq_p_mqtt5){
+ proplen = property__get_length_all(properties);
+ varbytes = packet__varint_bytes(proplen);
+ packetlen += proplen + varbytes;
+ }
+
+ packet->command = CMD_UNSUBSCRIBE | (1<<1);
+ packet->remaining_length = packetlen;
+ rc = packet__alloc(packet);
+ if(rc){
+ mosquitto__free(packet);
+ return rc;
+ }
+
+ /* Variable header */
+ local_mid = mosquitto__mid_generate(mosq);
+ if(mid) *mid = (int)local_mid;
+ packet__write_uint16(packet, local_mid);
+
+ if(mosq->protocol == mosq_p_mqtt5){
+ /* We don't use User Property yet. */
+ property__write_all(packet, properties, true);
+ }
+
+ /* Payload */
+ for(i=0; i<topic_count; i++){
+ packet__write_string(packet, topic[i], strlen(topic[i]));
+ }
+
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+ for(i=0; i<topic_count; i++){
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic[i]);
+ }
+# endif
+#else
+ for(i=0; i<topic_count; i++){
+ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic[i]);
+ }
+#endif
+ return packet__queue(mosq, packet);
+}
+
diff --git a/libs/libmosquitto/src/socks_mosq.c b/libs/libmosquitto/src/socks_mosq.c
new file mode 100644
index 0000000000..0df58a4b65
--- /dev/null
+++ b/libs/libmosquitto/src/socks_mosq.c
@@ -0,0 +1,460 @@
+/*
+Copyright (c) 2014-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#ifdef WIN32
+# include <ws2tcpip.h>
+#elif __QNX__
+# include <sys/socket.h>
+# include <netinet/in.h>
+#else
+# include <arpa/inet.h>
+#endif
+#ifdef __FreeBSD__
+# include <sys/socket.h>
+# include <netinet/in.h>
+#endif
+
+#include "mosquitto_internal.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "packet_mosq.h"
+#include "send_mosq.h"
+
+#define SOCKS_AUTH_NONE 0x00
+#define SOCKS_AUTH_GSS 0x01
+#define SOCKS_AUTH_USERPASS 0x02
+#define SOCKS_AUTH_NO_ACCEPTABLE 0xFF
+
+#define SOCKS_ATYPE_IP_V4 1 /* four bytes */
+#define SOCKS_ATYPE_DOMAINNAME 3 /* one byte length, followed by fqdn no null, 256 max chars */
+#define SOCKS_ATYPE_IP_V6 4 /* 16 bytes */
+
+#define SOCKS_REPLY_SUCCEEDED 0x00
+#define SOCKS_REPLY_GENERAL_FAILURE 0x01
+#define SOCKS_REPLY_CONNECTION_NOT_ALLOWED 0x02
+#define SOCKS_REPLY_NETWORK_UNREACHABLE 0x03
+#define SOCKS_REPLY_HOST_UNREACHABLE 0x04
+#define SOCKS_REPLY_CONNECTION_REFUSED 0x05
+#define SOCKS_REPLY_TTL_EXPIRED 0x06
+#define SOCKS_REPLY_COMMAND_NOT_SUPPORTED 0x07
+#define SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED 0x08
+
+int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password)
+{
+#ifdef WITH_SOCKS
+ if(!mosq) return MOSQ_ERR_INVAL;
+ if(!host || strlen(host) > 256) return MOSQ_ERR_INVAL;
+ if(port < 1 || port > 65535) return MOSQ_ERR_INVAL;
+
+ mosquitto__free(mosq->socks5_host);
+ mosq->socks5_host = NULL;
+
+ mosq->socks5_host = mosquitto__strdup(host);
+ if(!mosq->socks5_host){
+ return MOSQ_ERR_NOMEM;
+ }
+
+ mosq->socks5_port = port;
+
+ mosquitto__free(mosq->socks5_username);
+ mosq->socks5_username = NULL;
+
+ mosquitto__free(mosq->socks5_password);
+ mosq->socks5_password = NULL;
+
+ if(username){
+ mosq->socks5_username = mosquitto__strdup(username);
+ if(!mosq->socks5_username){
+ return MOSQ_ERR_NOMEM;
+ }
+
+ if(password){
+ mosq->socks5_password = mosquitto__strdup(password);
+ if(!mosq->socks5_password){
+ mosquitto__free(mosq->socks5_username);
+ return MOSQ_ERR_NOMEM;
+ }
+ }
+ }
+
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+#ifdef WITH_SOCKS
+int socks5__send(struct mosquitto *mosq)
+{
+ struct mosquitto__packet *packet;
+ int slen;
+ int ulen, plen;
+
+ struct in_addr addr_ipv4;
+ struct in6_addr addr_ipv6;
+ int ipv4_pton_result;
+ int ipv6_pton_result;
+
+ if(mosq->state == mosq_cs_socks5_new){
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ if(mosq->socks5_username){
+ packet->packet_length = 4;
+ }else{
+ packet->packet_length = 3;
+ }
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
+
+ packet->payload[0] = 0x05;
+ if(mosq->socks5_username){
+ packet->payload[1] = 2;
+ packet->payload[2] = SOCKS_AUTH_NONE;
+ packet->payload[3] = SOCKS_AUTH_USERPASS;
+ }else{
+ packet->payload[1] = 1;
+ packet->payload[2] = SOCKS_AUTH_NONE;
+ }
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_socks5_start;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ mosq->in_packet.pos = 0;
+ mosq->in_packet.packet_length = 2;
+ mosq->in_packet.to_process = 2;
+ mosq->in_packet.payload = mosquitto__malloc(sizeof(uint8_t)*2);
+ if(!mosq->in_packet.payload){
+ mosquitto__free(packet->payload);
+ mosquitto__free(packet);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ return packet__queue(mosq, packet);
+ }else if(mosq->state == mosq_cs_socks5_auth_ok){
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ ipv4_pton_result = inet_pton(AF_INET, mosq->host, &addr_ipv4);
+ ipv6_pton_result = inet_pton(AF_INET6, mosq->host, &addr_ipv6);
+
+ if(ipv4_pton_result == 1){
+ packet->packet_length = 10;
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
+ if(!packet->payload){
+ mosquitto__free(packet);
+ return MOSQ_ERR_NOMEM;
+ }
+ packet->payload[3] = SOCKS_ATYPE_IP_V4;
+ memcpy(&(packet->payload[4]), (const void*)&addr_ipv4, 4);
+ packet->payload[4+4] = MOSQ_MSB(mosq->port);
+ packet->payload[4+4+1] = MOSQ_LSB(mosq->port);
+
+ }else if(ipv6_pton_result == 1){
+ packet->packet_length = 22;
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
+ if(!packet->payload){
+ mosquitto__free(packet);
+ return MOSQ_ERR_NOMEM;
+ }
+ packet->payload[3] = SOCKS_ATYPE_IP_V6;
+ memcpy(&(packet->payload[4]), (const void*)&addr_ipv6, 16);
+ packet->payload[4+16] = MOSQ_MSB(mosq->port);
+ packet->payload[4+16+1] = MOSQ_LSB(mosq->port);
+
+ }else{
+ slen = strlen(mosq->host);
+ if(slen > UCHAR_MAX){
+ return MOSQ_ERR_NOMEM;
+ }
+ packet->packet_length = 7 + slen;
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
+ if(!packet->payload){
+ mosquitto__free(packet);
+ return MOSQ_ERR_NOMEM;
+ }
+ packet->payload[3] = SOCKS_ATYPE_DOMAINNAME;
+ packet->payload[4] = (uint8_t)slen;
+ memcpy(&(packet->payload[5]), mosq->host, slen);
+ packet->payload[5+slen] = MOSQ_MSB(mosq->port);
+ packet->payload[6+slen] = MOSQ_LSB(mosq->port);
+ }
+ packet->payload[0] = 0x05;
+ packet->payload[1] = 0x01;
+ packet->payload[2] = 0x00;
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_socks5_request;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ mosq->in_packet.pos = 0;
+ mosq->in_packet.packet_length = 5;
+ mosq->in_packet.to_process = 5;
+ mosq->in_packet.payload = mosquitto__malloc(sizeof(uint8_t)*5);
+ if(!mosq->in_packet.payload){
+ mosquitto__free(packet->payload);
+ mosquitto__free(packet);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ return packet__queue(mosq, packet);
+ }else if(mosq->state == mosq_cs_socks5_send_userpass){
+ packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
+ if(!packet) return MOSQ_ERR_NOMEM;
+
+ ulen = strlen(mosq->socks5_username);
+ plen = strlen(mosq->socks5_password);
+ packet->packet_length = 3 + ulen + plen;
+ packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
+
+
+ packet->payload[0] = 0x01;
+ packet->payload[1] = ulen;
+ memcpy(&(packet->payload[2]), mosq->socks5_username, ulen);
+ packet->payload[2+ulen] = plen;
+ memcpy(&(packet->payload[3+ulen]), mosq->socks5_password, plen);
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_socks5_userpass_reply;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ mosq->in_packet.pos = 0;
+ mosq->in_packet.packet_length = 2;
+ mosq->in_packet.to_process = 2;
+ mosq->in_packet.payload = mosquitto__malloc(sizeof(uint8_t)*2);
+ if(!mosq->in_packet.payload){
+ mosquitto__free(packet->payload);
+ mosquitto__free(packet);
+ return MOSQ_ERR_NOMEM;
+ }
+
+ return packet__queue(mosq, packet);
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+int socks5__read(struct mosquitto *mosq)
+{
+ ssize_t len;
+ uint8_t *payload;
+ uint8_t i;
+
+ if(mosq->state == mosq_cs_socks5_start){
+ while(mosq->in_packet.to_process > 0){
+ len = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
+ if(len > 0){
+ mosq->in_packet.pos += len;
+ mosq->in_packet.to_process -= len;
+ }else{
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ packet__cleanup(&mosq->in_packet);
+ switch(errno){
+ case 0:
+ return MOSQ_ERR_PROXY;
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }
+ if(mosq->in_packet.payload[0] != 5){
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_PROXY;
+ }
+ switch(mosq->in_packet.payload[1]){
+ case SOCKS_AUTH_NONE:
+ packet__cleanup(&mosq->in_packet);
+ mosq->state = mosq_cs_socks5_auth_ok;
+ return socks5__send(mosq);
+ case SOCKS_AUTH_USERPASS:
+ packet__cleanup(&mosq->in_packet);
+ mosq->state = mosq_cs_socks5_send_userpass;
+ return socks5__send(mosq);
+ default:
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_AUTH;
+ }
+ }else if(mosq->state == mosq_cs_socks5_userpass_reply){
+ while(mosq->in_packet.to_process > 0){
+ len = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
+ if(len > 0){
+ mosq->in_packet.pos += len;
+ mosq->in_packet.to_process -= len;
+ }else{
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ packet__cleanup(&mosq->in_packet);
+ switch(errno){
+ case 0:
+ return MOSQ_ERR_PROXY;
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }
+ if(mosq->in_packet.payload[0] != 1){
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_PROXY;
+ }
+ if(mosq->in_packet.payload[1] == 0){
+ packet__cleanup(&mosq->in_packet);
+ mosq->state = mosq_cs_socks5_auth_ok;
+ return socks5__send(mosq);
+ }else{
+ i = mosq->in_packet.payload[1];
+ packet__cleanup(&mosq->in_packet);
+ switch(i){
+ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED:
+ return MOSQ_ERR_AUTH;
+
+ case SOCKS_REPLY_NETWORK_UNREACHABLE:
+ case SOCKS_REPLY_HOST_UNREACHABLE:
+ case SOCKS_REPLY_CONNECTION_REFUSED:
+ return MOSQ_ERR_NO_CONN;
+
+ case SOCKS_REPLY_GENERAL_FAILURE:
+ case SOCKS_REPLY_TTL_EXPIRED:
+ case SOCKS_REPLY_COMMAND_NOT_SUPPORTED:
+ case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED:
+ return MOSQ_ERR_PROXY;
+
+ default:
+ return MOSQ_ERR_INVAL;
+ }
+ return MOSQ_ERR_PROXY;
+ }
+ }else if(mosq->state == mosq_cs_socks5_request){
+ while(mosq->in_packet.to_process > 0){
+ len = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
+ if(len > 0){
+ mosq->in_packet.pos += len;
+ mosq->in_packet.to_process -= len;
+ }else{
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ packet__cleanup(&mosq->in_packet);
+ switch(errno){
+ case 0:
+ return MOSQ_ERR_PROXY;
+ case COMPAT_ECONNRESET:
+ return MOSQ_ERR_CONN_LOST;
+ default:
+ return MOSQ_ERR_ERRNO;
+ }
+ }
+ }
+ }
+
+ if(mosq->in_packet.packet_length == 5){
+ /* First part of the packet has been received, we now know what else to expect. */
+ if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V4){
+ mosq->in_packet.to_process += 4+2-1; /* 4 bytes IPv4, 2 bytes port, -1 byte because we've already read the first byte */
+ mosq->in_packet.packet_length += 4+2-1;
+ }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V6){
+ mosq->in_packet.to_process += 16+2-1; /* 16 bytes IPv6, 2 bytes port, -1 byte because we've already read the first byte */
+ mosq->in_packet.packet_length += 16+2-1;
+ }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_DOMAINNAME){
+ if(mosq->in_packet.payload[4] > 0){
+ mosq->in_packet.to_process += mosq->in_packet.payload[4];
+ mosq->in_packet.packet_length += mosq->in_packet.payload[4];
+ }
+ }else{
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_PROTOCOL;
+ }
+ payload = mosquitto__realloc(mosq->in_packet.payload, mosq->in_packet.packet_length);
+ if(payload){
+ mosq->in_packet.payload = payload;
+ }else{
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_NOMEM;
+ }
+ payload = mosquitto__realloc(mosq->in_packet.payload, mosq->in_packet.packet_length);
+ if(payload){
+ mosq->in_packet.payload = payload;
+ }else{
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_NOMEM;
+ }
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ /* Entire packet is now read. */
+ if(mosq->in_packet.payload[0] != 5){
+ packet__cleanup(&mosq->in_packet);
+ return MOSQ_ERR_PROXY;
+ }
+ if(mosq->in_packet.payload[1] == 0){
+ /* Auth passed */
+ packet__cleanup(&mosq->in_packet);
+ mosq->state = mosq_cs_new;
+ if(mosq->socks5_host){
+ int rc = net__socket_connect_step3(mosq, mosq->host);
+ if(rc) return rc;
+ }
+ return send__connect(mosq, mosq->keepalive, mosq->clean_start, NULL);
+ }else{
+ i = mosq->in_packet.payload[1];
+ packet__cleanup(&mosq->in_packet);
+ mosq->state = mosq_cs_socks5_new;
+ switch(i){
+ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED:
+ return MOSQ_ERR_AUTH;
+
+ case SOCKS_REPLY_NETWORK_UNREACHABLE:
+ case SOCKS_REPLY_HOST_UNREACHABLE:
+ case SOCKS_REPLY_CONNECTION_REFUSED:
+ return MOSQ_ERR_NO_CONN;
+
+ case SOCKS_REPLY_GENERAL_FAILURE:
+ case SOCKS_REPLY_TTL_EXPIRED:
+ case SOCKS_REPLY_COMMAND_NOT_SUPPORTED:
+ case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED:
+ return MOSQ_ERR_PROXY;
+
+ default:
+ return MOSQ_ERR_INVAL;
+ }
+ }
+ }else{
+ return packet__read(mosq);
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+#endif
diff --git a/libs/libmosquitto/src/socks_mosq.h b/libs/libmosquitto/src/socks_mosq.h
new file mode 100644
index 0000000000..27b3dc3f31
--- /dev/null
+++ b/libs/libmosquitto/src/socks_mosq.h
@@ -0,0 +1,23 @@
+/*
+Copyright (c) 2014-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef SOCKS_MOSQ_H
+#define SOCKS_MOSQ_H
+
+int socks5__send(struct mosquitto *mosq);
+int socks5__read(struct mosquitto *mosq);
+
+#endif
diff --git a/libs/libmosquitto/src/srv_mosq.c b/libs/libmosquitto/src/srv_mosq.c
new file mode 100644
index 0000000000..d08c2bd0cc
--- /dev/null
+++ b/libs/libmosquitto/src/srv_mosq.c
@@ -0,0 +1,112 @@
+/*
+Copyright (c) 2013-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#ifdef WITH_SRV
+# include <ares.h>
+
+# include <arpa/nameser.h>
+# include <stdio.h>
+# include <string.h>
+#endif
+
+#include "logging_mosq.h"
+#include "memory_mosq.h"
+#include "mosquitto_internal.h"
+#include "mosquitto.h"
+
+#ifdef WITH_SRV
+static void srv_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
+{
+ struct mosquitto *mosq = arg;
+ struct ares_srv_reply *reply = NULL;
+ if(status == ARES_SUCCESS){
+ status = ares_parse_srv_reply(abuf, alen, &reply);
+ if(status == ARES_SUCCESS){
+ // FIXME - choose which answer to use based on rfc2782 page 3. */
+ mosquitto_connect(mosq, reply->host, reply->port, mosq->keepalive);
+ }
+ }else{
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: SRV lookup failed (%d).", status);
+ /* FIXME - calling on_disconnect here isn't correct. */
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_disconnect){
+ mosq->in_callback = true;
+ mosq->on_disconnect(mosq, mosq->userdata, MOSQ_ERR_LOOKUP);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_disconnect_v5){
+ mosq->in_callback = true;
+ mosq->on_disconnect_v5(mosq, mosq->userdata, MOSQ_ERR_LOOKUP, NULL);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+ }
+}
+#endif
+
+int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address)
+{
+#ifdef WITH_SRV
+ char *h;
+ int rc;
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ rc = ares_init(&mosq->achan);
+ if(rc != ARES_SUCCESS){
+ return MOSQ_ERR_UNKNOWN;
+ }
+
+ if(!host){
+ // get local domain
+ }else{
+#ifdef WITH_TLS
+ if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){
+ h = mosquitto__malloc(strlen(host) + strlen("_secure-mqtt._tcp.") + 1);
+ if(!h) return MOSQ_ERR_NOMEM;
+ sprintf(h, "_secure-mqtt._tcp.%s", host);
+ }else{
+#endif
+ h = mosquitto__malloc(strlen(host) + strlen("_mqtt._tcp.") + 1);
+ if(!h) return MOSQ_ERR_NOMEM;
+ sprintf(h, "_mqtt._tcp.%s", host);
+#ifdef WITH_TLS
+ }
+#endif
+ ares_search(mosq->achan, h, ns_c_in, ns_t_srv, srv_callback, mosq);
+ mosquitto__free(h);
+ }
+
+ pthread_mutex_lock(&mosq->state_mutex);
+ mosq->state = mosq_cs_connect_srv;
+ pthread_mutex_unlock(&mosq->state_mutex);
+
+ mosq->keepalive = keepalive;
+
+ return MOSQ_ERR_SUCCESS;
+
+#else
+ UNUSED(mosq);
+ UNUSED(host);
+ UNUSED(keepalive);
+ UNUSED(bind_address);
+
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+
diff --git a/libs/libmosquitto/src/stdafx.cxx b/libs/libmosquitto/src/stdafx.cxx
new file mode 100644
index 0000000000..1647228cd0
--- /dev/null
+++ b/libs/libmosquitto/src/stdafx.cxx
@@ -0,0 +1,2 @@
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/libs/libmosquitto/src/stdafx.h b/libs/libmosquitto/src/stdafx.h
new file mode 100644
index 0000000000..6f70f09bee
--- /dev/null
+++ b/libs/libmosquitto/src/stdafx.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/libs/libmosquitto/src/thread_mosq.c b/libs/libmosquitto/src/thread_mosq.c
new file mode 100644
index 0000000000..7bde453d3d
--- /dev/null
+++ b/libs/libmosquitto/src/thread_mosq.c
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2011-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#ifndef WIN32
+#include <time.h>
+#endif
+
+#include "mosquitto_internal.h"
+#include "net_mosq.h"
+
+void *mosquitto__thread_main(void *obj);
+
+int mosquitto_loop_start(struct mosquitto *mosq)
+{
+#if defined(WITH_THREADING) && defined(HAVE_PTHREAD_CANCEL)
+ if(!mosq || mosq->threaded != mosq_ts_none) return MOSQ_ERR_INVAL;
+
+ mosq->threaded = mosq_ts_self;
+ if(!pthread_create(&mosq->thread_id, NULL, mosquitto__thread_main, mosq)){
+ return MOSQ_ERR_SUCCESS;
+ }else{
+ return MOSQ_ERR_ERRNO;
+ }
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+int mosquitto_loop_stop(struct mosquitto *mosq, bool force)
+{
+#if defined(WITH_THREADING) && defined(HAVE_PTHREAD_CANCEL)
+# ifndef WITH_BROKER
+ char sockpair_data = 0;
+# endif
+
+ if(!mosq || mosq->threaded != mosq_ts_self) return MOSQ_ERR_INVAL;
+
+
+ /* Write a single byte to sockpairW (connected to sockpairR) to break out
+ * of select() if in threaded mode. */
+ if(mosq->sockpairW != INVALID_SOCKET){
+#ifndef WIN32
+ if(write(mosq->sockpairW, &sockpair_data, 1)){
+ }
+#else
+ send(mosq->sockpairW, &sockpair_data, 1, 0);
+#endif
+ }
+
+ if(force){
+ pthread_cancel(mosq->thread_id);
+ }
+ pthread_join(mosq->thread_id, NULL);
+ mosq->thread_id = pthread_self();
+ mosq->threaded = mosq_ts_none;
+
+ return MOSQ_ERR_SUCCESS;
+#else
+ return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+#ifdef WITH_THREADING
+void *mosquitto__thread_main(void *obj)
+{
+ struct mosquitto *mosq = obj;
+ int state;
+#ifndef WIN32
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 10000000;
+#endif
+
+ if(!mosq) return NULL;
+
+ do{
+ pthread_mutex_lock(&mosq->state_mutex);
+ state = mosq->state;
+ pthread_mutex_unlock(&mosq->state_mutex);
+ if(state == mosq_cs_new){
+#ifdef WIN32
+ Sleep(10);
+#else
+ nanosleep(&ts, NULL);
+#endif
+ }else{
+ break;
+ }
+ }while(1);
+
+ if(state == mosq_cs_connect_async){
+ mosquitto_reconnect(mosq);
+ }
+
+ if(!mosq->keepalive){
+ /* Sleep for a day if keepalive disabled. */
+ mosquitto_loop_forever(mosq, 1000*86400, 1);
+ }else{
+ /* Sleep for our keepalive value. publish() etc. will wake us up. */
+ mosquitto_loop_forever(mosq, mosq->keepalive*1000, 1);
+ }
+
+ return obj;
+}
+#endif
+
+int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded)
+{
+ if(!mosq) return MOSQ_ERR_INVAL;
+
+ if(threaded){
+ mosq->threaded = mosq_ts_external;
+ }else{
+ mosq->threaded = mosq_ts_none;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
diff --git a/libs/libmosquitto/src/time_mosq.c b/libs/libmosquitto/src/time_mosq.c
new file mode 100644
index 0000000000..c66d985444
--- /dev/null
+++ b/libs/libmosquitto/src/time_mosq.c
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2013-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif
+
+#ifdef WIN32
+# define _WIN32_WINNT _WIN32_WINNT_VISTA
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+#include <time.h>
+
+#include "mosquitto.h"
+#include "time_mosq.h"
+
+time_t mosquitto_time(void)
+{
+#ifdef WIN32
+ return GetTickCount64()/1000;
+#elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK)
+ struct timespec tp;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ return tp.tv_sec;
+#elif defined(__APPLE__)
+ static mach_timebase_info_data_t tb;
+ uint64_t ticks;
+ uint64_t sec;
+
+ ticks = mach_absolute_time();
+
+ if(tb.denom == 0){
+ mach_timebase_info(&tb);
+ }
+ sec = ticks*tb.numer/tb.denom/1000000000;
+
+ return (time_t)sec;
+#else
+ return time(NULL);
+#endif
+}
+
diff --git a/libs/libmosquitto/src/time_mosq.h b/libs/libmosquitto/src/time_mosq.h
new file mode 100644
index 0000000000..75758a8291
--- /dev/null
+++ b/libs/libmosquitto/src/time_mosq.h
@@ -0,0 +1,22 @@
+/*
+Copyright (c) 2013-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef TIME_MOSQ_H
+#define TIME_MOSQ_H
+
+time_t mosquitto_time(void);
+
+#endif
diff --git a/libs/libmosquitto/src/tls_mosq.c b/libs/libmosquitto/src/tls_mosq.c
new file mode 100644
index 0000000000..c2f1204f42
--- /dev/null
+++ b/libs/libmosquitto/src/tls_mosq.c
@@ -0,0 +1,183 @@
+/*
+Copyright (c) 2013-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifdef WITH_TLS
+
+#include "config.h"
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <arpa/inet.h>
+# include <sys/socket.h>
+# include <strings.h>
+#endif
+
+#include <string.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "tls_mosq.h"
+
+extern int tls_ex_index_mosq;
+
+int mosquitto__server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx)
+{
+ /* Preverify should have already checked expiry, revocation.
+ * We need to verify the hostname. */
+ struct mosquitto *mosq;
+ SSL *ssl;
+ X509 *cert;
+
+ /* Always reject if preverify_ok has failed. */
+ if(!preverify_ok) return 0;
+
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq);
+ if(!mosq) return 0;
+
+ if(mosq->tls_insecure == false){
+ if(X509_STORE_CTX_get_error_depth(ctx) == 0){
+ /* FIXME - use X509_check_host() etc. for sufficiently new openssl (>=1.1.x) */
+ cert = X509_STORE_CTX_get_current_cert(ctx);
+ /* This is the peer certificate, all others are upwards in the chain. */
+#if defined(WITH_BROKER)
+ preverify_ok = mosquitto__verify_certificate_hostname(cert, mosq->bridge->addresses[mosq->bridge->cur_address].address);
+#else
+ preverify_ok = mosquitto__verify_certificate_hostname(cert, mosq->host);
+#endif
+ if (preverify_ok != 1) {
+ log__printf(mosq, MOSQ_LOG_ERR, "Error: host name verification failed.");
+ }
+ return preverify_ok;
+ }else{
+ return preverify_ok;
+ }
+ }else{
+ return preverify_ok;
+ }
+}
+
+int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname)
+{
+ int i;
+ int len;
+
+ if(!certname || !hostname){
+ return 1;
+ }
+
+ if(certname[0] == '*'){
+ if(certname[1] != '.'){
+ return 1;
+ }
+ certname += 2;
+ len = strlen(hostname);
+ for(i=0; i<len-1; i++){
+ if(hostname[i] == '.'){
+ hostname += i+1;
+ break;
+ }
+ }
+ return strcasecmp(certname, hostname);
+ }else{
+ return strcasecmp(certname, hostname);
+ }
+}
+
+/* This code is based heavily on the example provided in "Secure Programming
+ * Cookbook for C and C++".
+ */
+int mosquitto__verify_certificate_hostname(X509 *cert, const char *hostname)
+{
+ int i;
+ char name[256];
+ X509_NAME *subj;
+ bool have_san_dns = false;
+ STACK_OF(GENERAL_NAME) *san;
+ const GENERAL_NAME *nval;
+ const unsigned char *data;
+ unsigned char ipv6_addr[16];
+ unsigned char ipv4_addr[4];
+ int ipv6_ok;
+ int ipv4_ok;
+
+#ifdef WIN32
+ ipv6_ok = InetPton(AF_INET6, hostname, &ipv6_addr);
+ ipv4_ok = InetPton(AF_INET, hostname, &ipv4_addr);
+#else
+ ipv6_ok = inet_pton(AF_INET6, hostname, &ipv6_addr);
+ ipv4_ok = inet_pton(AF_INET, hostname, &ipv4_addr);
+#endif
+
+ san = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if(san){
+ for(i=0; i<sk_GENERAL_NAME_num(san); i++){
+ nval = sk_GENERAL_NAME_value(san, i);
+ if(nval->type == GEN_DNS){
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ data = ASN1_STRING_data(nval->d.dNSName);
+#else
+ data = ASN1_STRING_get0_data(nval->d.dNSName);
+#endif
+ if(data && !mosquitto__cmp_hostname_wildcard((char *)data, hostname)){
+ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
+ return 1;
+ }
+ have_san_dns = true;
+ }else if(nval->type == GEN_IPADD){
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ data = ASN1_STRING_data(nval->d.iPAddress);
+#else
+ data = ASN1_STRING_get0_data(nval->d.iPAddress);
+#endif
+ if(nval->d.iPAddress->length == 4 && ipv4_ok){
+ if(!memcmp(ipv4_addr, data, 4)){
+ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
+ return 1;
+ }
+ }else if(nval->d.iPAddress->length == 16 && ipv6_ok){
+ if(!memcmp(ipv6_addr, data, 16)){
+ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
+ return 1;
+ }
+ }
+ }
+ }
+ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
+ if(have_san_dns){
+ /* Only check CN if subjectAltName DNS entry does not exist. */
+ return 0;
+ }
+ }
+
+ subj = X509_get_subject_name(cert);
+ if(X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0){
+ name[sizeof(name) - 1] = '\0';
+ if (!mosquitto__cmp_hostname_wildcard(name, hostname)) return 1;
+ }
+ return 0;
+}
+
+#endif
+
diff --git a/libs/libmosquitto/src/tls_mosq.h b/libs/libmosquitto/src/tls_mosq.h
new file mode 100644
index 0000000000..5a1cda54fc
--- /dev/null
+++ b/libs/libmosquitto/src/tls_mosq.h
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2013-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef TLS_MOSQ_H
+#define TLS_MOSQ_H
+
+#ifdef WITH_TLS
+# define SSL_DATA_PENDING(A) ((A)->ssl && SSL_pending((A)->ssl))
+#else
+# define SSL_DATA_PENDING(A) 0
+#endif
+
+#ifdef WITH_TLS
+
+#include <openssl/ssl.h>
+#include <openssl/engine.h>
+
+int mosquitto__server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx);
+int mosquitto__verify_certificate_hostname(X509 *cert, const char *hostname);
+
+#endif /* WITH_TLS */
+
+#endif
diff --git a/libs/libmosquitto/src/utf8_mosq.c b/libs/libmosquitto/src/utf8_mosq.c
new file mode 100644
index 0000000000..875c1c7f27
--- /dev/null
+++ b/libs/libmosquitto/src/utf8_mosq.c
@@ -0,0 +1,109 @@
+/*
+Copyright (c) 2016-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include "mosquitto.h"
+
+int mosquitto_validate_utf8(const char *str, int len)
+{
+ int i;
+ int j;
+ int codelen;
+ int codepoint;
+ const unsigned char *ustr = (const unsigned char *)str;
+
+ if(!str) return MOSQ_ERR_INVAL;
+ if(len < 0 || len > 65536) return MOSQ_ERR_INVAL;
+
+ for(i=0; i<len; i++){
+ if(ustr[i] == 0){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }else if(ustr[i] <= 0x7f){
+ codelen = 1;
+ codepoint = ustr[i];
+ }else if((ustr[i] & 0xE0) == 0xC0){
+ /* 110xxxxx - 2 byte sequence */
+ if(ustr[i] == 0xC0 || ustr[i] == 0xC1){
+ /* Invalid bytes */
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ codelen = 2;
+ codepoint = (ustr[i] & 0x1F);
+ }else if((ustr[i] & 0xF0) == 0xE0){
+ // 1110xxxx - 3 byte sequence
+ codelen = 3;
+ codepoint = (ustr[i] & 0x0F);
+ }else if((ustr[i] & 0xF8) == 0xF0){
+ // 11110xxx - 4 byte sequence
+ if(ustr[i] > 0xF4){
+ /* Invalid, this would produce values > 0x10FFFF. */
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ codelen = 4;
+ codepoint = (ustr[i] & 0x07);
+ }else{
+ /* Unexpected continuation byte. */
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+
+ /* Reconstruct full code point */
+ if(i == len-codelen+1){
+ /* Not enough data */
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ for(j=0; j<codelen-1; j++){
+ if((ustr[++i] & 0xC0) != 0x80){
+ /* Not a continuation byte */
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ codepoint = (codepoint<<6) | (ustr[i] & 0x3F);
+ }
+
+ /* Check for UTF-16 high/low surrogates */
+ if(codepoint >= 0xD800 && codepoint <= 0xDFFF){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+
+ /* Check for overlong or out of range encodings */
+ /* Checking codelen == 2 isn't necessary here, because it is already
+ * covered above in the C0 and C1 checks.
+ * if(codelen == 2 && codepoint < 0x0080){
+ * return MOSQ_ERR_MALFORMED_UTF8;
+ * }else
+ */
+ if(codelen == 3 && codepoint < 0x0800){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }else if(codelen == 4 && (codepoint < 0x10000 || codepoint > 0x10FFFF)){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+
+ /* Check for non-characters */
+ if(codepoint >= 0xFDD0 && codepoint <= 0xFDEF){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ if((codepoint & 0xFFFF) == 0xFFFE || (codepoint & 0xFFFF) == 0xFFFF){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ /* Check for control characters */
+ if(codepoint <= 0x001F || (codepoint >= 0x007F && codepoint <= 0x009F)){
+ return MOSQ_ERR_MALFORMED_UTF8;
+ }
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/util_mosq.c b/libs/libmosquitto/src/util_mosq.c
new file mode 100644
index 0000000000..5e1065e7c4
--- /dev/null
+++ b/libs/libmosquitto/src/util_mosq.c
@@ -0,0 +1,354 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <aclapi.h>
+# include <io.h>
+# include <lmcons.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#if !defined(WITH_TLS) && defined(__linux__) && defined(__GLIBC__)
+# if __GLIBC_PREREQ(2, 25)
+# include <sys/random.h>
+# define HAVE_GETRANDOM 1
+# endif
+#endif
+
+#ifdef WITH_TLS
+# include <openssl/bn.h>
+# include <openssl/rand.h>
+#endif
+
+#ifdef WITH_BROKER
+#include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "tls_mosq.h"
+#include "util_mosq.h"
+
+#ifdef WITH_WEBSOCKETS
+#include <libwebsockets.h>
+#endif
+
+#ifdef WITH_BROKER
+int mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+int mosquitto__check_keepalive(struct mosquitto *mosq)
+#endif
+{
+ time_t next_msg_out;
+ time_t last_msg_in;
+ time_t now = mosquitto_time();
+#ifndef WITH_BROKER
+ int rc;
+#endif
+
+ assert(mosq);
+#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
+ /* Check if a lazy bridge should be timed out due to idle. */
+ if(mosq->bridge && mosq->bridge->start_type == bst_lazy
+ && mosq->sock != INVALID_SOCKET
+ && now - mosq->next_msg_out - mosq->keepalive >= mosq->bridge->idle_timeout){
+
+ log__printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id);
+ net__socket_close(db, mosq);
+ return MOSQ_ERR_SUCCESS;
+ }
+#endif
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ next_msg_out = mosq->next_msg_out;
+ last_msg_in = mosq->last_msg_in;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ if(mosq->keepalive && mosq->sock != INVALID_SOCKET &&
+ (now >= next_msg_out || now - last_msg_in >= mosq->keepalive)){
+
+ if(mosq->state == mosq_cs_connected && mosq->ping_t == 0){
+ send__pingreq(mosq);
+ /* Reset last msg times to give the server time to send a pingresp */
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->last_msg_in = now;
+ mosq->next_msg_out = now + mosq->keepalive;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ }else{
+#ifdef WITH_BROKER
+ net__socket_close(db, mosq);
+#else
+ net__socket_close(mosq);
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state == mosq_cs_disconnecting){
+ rc = MOSQ_ERR_SUCCESS;
+ }else{
+ rc = MOSQ_ERR_KEEPALIVE;
+ }
+ pthread_mutex_unlock(&mosq->state_mutex);
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_disconnect){
+ mosq->in_callback = true;
+ mosq->on_disconnect(mosq, mosq->userdata, rc);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_disconnect_v5){
+ mosq->in_callback = true;
+ mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+
+ return rc;
+#endif
+ }
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+uint16_t mosquitto__mid_generate(struct mosquitto *mosq)
+{
+ /* FIXME - this would be better with atomic increment, but this is safer
+ * for now for a bug fix release.
+ *
+ * If this is changed to use atomic increment, callers of this function
+ * will have to be aware that they may receive a 0 result, which may not be
+ * used as a mid.
+ */
+ uint16_t mid;
+ assert(mosq);
+
+ pthread_mutex_lock(&mosq->mid_mutex);
+ mosq->last_mid++;
+ if(mosq->last_mid == 0) mosq->last_mid++;
+ mid = mosq->last_mid;
+ pthread_mutex_unlock(&mosq->mid_mutex);
+
+ return mid;
+}
+
+
+#ifdef WITH_TLS
+int mosquitto__hex2bin_sha1(const char *hex, unsigned char **bin)
+{
+ unsigned char *sha, tmp[SHA_DIGEST_LENGTH];
+
+ if(mosquitto__hex2bin(hex, tmp, SHA_DIGEST_LENGTH) != SHA_DIGEST_LENGTH){
+ return MOSQ_ERR_INVAL;
+ }
+
+ sha = mosquitto__malloc(SHA_DIGEST_LENGTH);
+ memcpy(sha, tmp, SHA_DIGEST_LENGTH);
+ *bin = sha;
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len)
+{
+ BIGNUM *bn = NULL;
+ int len;
+ int leading_zero = 0;
+ int start = 0;
+ size_t i = 0;
+
+ /* Count the number of leading zero */
+ for(i=0; i<strlen(hex); i=i+2) {
+ if(strncmp(hex + i, "00", 2) == 0) {
+ leading_zero++;
+ /* output leading zero to bin */
+ bin[start++] = 0;
+ }else{
+ break;
+ }
+ }
+
+ if(BN_hex2bn(&bn, hex) == 0){
+ if(bn) BN_free(bn);
+ return 0;
+ }
+ if(BN_num_bytes(bn) + leading_zero > bin_max_len){
+ BN_free(bn);
+ return 0;
+ }
+
+ len = BN_bn2bin(bn, bin + leading_zero);
+ BN_free(bn);
+ return len + leading_zero;
+}
+#endif
+
+FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
+{
+#ifdef WIN32
+ char buf[4096];
+ int rc;
+ rc = ExpandEnvironmentStrings(path, buf, 4096);
+ if(rc == 0 || rc > 4096){
+ return NULL;
+ }else{
+ if (restrict_read) {
+ HANDLE hfile;
+ SECURITY_ATTRIBUTES sec;
+ EXPLICIT_ACCESS ea;
+ PACL pacl = NULL;
+ char username[UNLEN + 1];
+ int ulen = UNLEN;
+ SECURITY_DESCRIPTOR sd;
+ DWORD dwCreationDisposition;
+
+ switch(mode[0]){
+ case 'a':
+ dwCreationDisposition = OPEN_ALWAYS;
+ break;
+ case 'r':
+ dwCreationDisposition = OPEN_EXISTING;
+ break;
+ case 'w':
+ dwCreationDisposition = CREATE_ALWAYS;
+ break;
+ default:
+ return NULL;
+ }
+
+ GetUserName(username, &ulen);
+ if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
+ return NULL;
+ }
+ BuildExplicitAccessWithName(&ea, username, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);
+ if (SetEntriesInAcl(1, &ea, NULL, &pacl) != ERROR_SUCCESS) {
+ return NULL;
+ }
+ if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) {
+ LocalFree(pacl);
+ return NULL;
+ }
+
+ sec.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sec.bInheritHandle = FALSE;
+ sec.lpSecurityDescriptor = &sd;
+
+ hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0,
+ &sec,
+ dwCreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ LocalFree(pacl);
+
+ int fd = _open_osfhandle((intptr_t)hfile, 0);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ FILE *fptr = _fdopen(fd, mode);
+ if (!fptr) {
+ _close(fd);
+ return NULL;
+ }
+ return fptr;
+
+ }else {
+ return fopen(buf, mode);
+ }
+ }
+#else
+ if (restrict_read) {
+ FILE *fptr;
+ mode_t old_mask;
+
+ old_mask = umask(0077);
+ fptr = fopen(path, mode);
+ umask(old_mask);
+
+ return fptr;
+ }else{
+ return fopen(path, mode);
+ }
+#endif
+}
+
+void util__increment_receive_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_in.inflight_quota < mosq->msgs_in.inflight_maximum){
+ mosq->msgs_in.inflight_quota++;
+ }
+}
+
+void util__increment_send_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_out.inflight_quota < mosq->msgs_out.inflight_maximum){
+ mosq->msgs_out.inflight_quota++;
+ }
+}
+
+
+void util__decrement_receive_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_in.inflight_quota > 0){
+ mosq->msgs_in.inflight_quota--;
+ }
+}
+
+void util__decrement_send_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_out.inflight_quota > 0){
+ mosq->msgs_out.inflight_quota--;
+ }
+}
+
+
+int util__random_bytes(void *bytes, int count)
+{
+ int rc = MOSQ_ERR_UNKNOWN;
+
+#ifdef WITH_TLS
+ if(RAND_bytes(bytes, count) == 1){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+#elif defined(HAVE_GETRANDOM)
+ if(getrandom(bytes, count, 0) == count){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+#elif defined(WIN32)
+ HCRYPTPROV provider;
+
+ if(!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){
+ return MOSQ_ERR_UNKNOWN;
+ }
+
+ if(CryptGenRandom(provider, count, bytes)){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+
+ CryptReleaseContext(provider, 0);
+#else
+ int i;
+
+ for(i=0; i<count; i++){
+ ((uint8_t *)bytes)[i] = (uint8_t )(random()&0xFF);
+ }
+ rc = MOSQ_ERR_SUCCESS;
+#endif
+ return rc;
+}
diff --git a/libs/libmosquitto/src/util_mosq.h b/libs/libmosquitto/src/util_mosq.h
new file mode 100644
index 0000000000..9ee570f3e9
--- /dev/null
+++ b/libs/libmosquitto/src/util_mosq.h
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+#ifndef UTIL_MOSQ_H
+#define UTIL_MOSQ_H
+
+#include <stdio.h>
+
+#include "tls_mosq.h"
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#ifdef WITH_BROKER
+int mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq);
+#else
+int mosquitto__check_keepalive(struct mosquitto *mosq);
+#endif
+uint16_t mosquitto__mid_generate(struct mosquitto *mosq);
+FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read);
+
+#ifdef WITH_TLS
+int mosquitto__hex2bin_sha1(const char *hex, unsigned char **bin);
+int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len);
+#endif
+
+int util__random_bytes(void *bytes, int count);
+
+void util__increment_receive_quota(struct mosquitto *mosq);
+void util__increment_send_quota(struct mosquitto *mosq);
+void util__decrement_receive_quota(struct mosquitto *mosq);
+void util__decrement_send_quota(struct mosquitto *mosq);
+#endif
diff --git a/libs/libmosquitto/src/util_topic.c b/libs/libmosquitto/src/util_topic.c
new file mode 100644
index 0000000000..67b78782ef
--- /dev/null
+++ b/libs/libmosquitto/src/util_topic.c
@@ -0,0 +1,252 @@
+/*
+Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <aclapi.h>
+# include <io.h>
+# include <lmcons.h>
+#else
+# include <sys/stat.h>
+#endif
+
+
+#ifdef WITH_BROKER
+#include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "tls_mosq.h"
+#include "util_mosq.h"
+
+/* Check that a topic used for publishing is valid.
+ * Search for + or # in a topic. Return MOSQ_ERR_INVAL if found.
+ * Also returns MOSQ_ERR_INVAL if the topic string is too long.
+ * Returns MOSQ_ERR_SUCCESS if everything is fine.
+ */
+int mosquitto_pub_topic_check(const char *str)
+{
+ int len = 0;
+ while(str && str[0]){
+ if(str[0] == '+' || str[0] == '#'){
+ return MOSQ_ERR_INVAL;
+ }
+ len++;
+ str = &str[1];
+ }
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_pub_topic_check2(const char *str, size_t len)
+{
+ size_t i;
+
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ for(i=0; i<len; i++){
+ if(str[i] == '+' || str[i] == '#'){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+/* Check that a topic used for subscriptions is valid.
+ * Search for + or # in a topic, check they aren't in invalid positions such as
+ * foo/#/bar, foo/+bar or foo/bar#.
+ * Return MOSQ_ERR_INVAL if invalid position found.
+ * Also returns MOSQ_ERR_INVAL if the topic string is too long.
+ * Returns MOSQ_ERR_SUCCESS if everything is fine.
+ */
+int mosquitto_sub_topic_check(const char *str)
+{
+ char c = '\0';
+ int len = 0;
+ while(str && str[0]){
+ if(str[0] == '+'){
+ if((c != '\0' && c != '/') || (str[1] != '\0' && str[1] != '/')){
+ return MOSQ_ERR_INVAL;
+ }
+ }else if(str[0] == '#'){
+ if((c != '\0' && c != '/') || str[1] != '\0'){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+ len++;
+ c = str[0];
+ str = &str[1];
+ }
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_sub_topic_check2(const char *str, size_t len)
+{
+ char c = '\0';
+ size_t i;
+
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ for(i=0; i<len; i++){
+ if(str[i] == '+'){
+ if((c != '\0' && c != '/') || (i<len-1 && str[i+1] != '/')){
+ return MOSQ_ERR_INVAL;
+ }
+ }else if(str[i] == '#'){
+ if((c != '\0' && c != '/') || i<len-1){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+ c = str[i];
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result)
+{
+ return mosquitto_topic_matches_sub2(sub, 0, topic, 0, result);
+}
+
+/* Does a topic match a subscription? */
+int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result)
+{
+ size_t spos;
+
+ UNUSED(sublen);
+ UNUSED(topiclen);
+
+ if(!result) return MOSQ_ERR_INVAL;
+ *result = false;
+
+ if(!sub || !topic || sub[0] == 0 || topic[0] == 0){
+ return MOSQ_ERR_INVAL;
+ }
+
+ if((sub[0] == '$' && topic[0] != '$')
+ || (topic[0] == '$' && sub[0] != '$')){
+
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ spos = 0;
+
+ while(sub[0] != 0){
+ if(topic[0] == '+' || topic[0] == '#'){
+ return MOSQ_ERR_INVAL;
+ }
+ if(sub[0] != topic[0] || topic[0] == 0){ /* Check for wildcard matches */
+ if(sub[0] == '+'){
+ /* Check for bad "+foo" or "a/+foo" subscription */
+ if(spos > 0 && sub[-1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ /* Check for bad "foo+" or "foo+/a" subscription */
+ if(sub[1] != 0 && sub[1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ spos++;
+ sub++;
+ while(topic[0] != 0 && topic[0] != '/'){
+ topic++;
+ }
+ if(topic[0] == 0 && sub[0] == 0){
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }else if(sub[0] == '#'){
+ /* Check for bad "foo#" subscription */
+ if(spos > 0 && sub[-1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ /* Check for # not the final character of the sub, e.g. "#foo" */
+ if(sub[1] != 0){
+ return MOSQ_ERR_INVAL;
+ }else{
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }else{
+ /* Check for e.g. foo/bar matching foo/+/# */
+ if(topic[0] == 0
+ && spos > 0
+ && sub[-1] == '+'
+ && sub[0] == '/'
+ && sub[1] == '#')
+ {
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ /* There is no match at this point, but is the sub invalid? */
+ while(sub[0] != 0){
+ if(sub[0] == '#' && sub[1] != 0){
+ return MOSQ_ERR_INVAL;
+ }
+ spos++;
+ sub++;
+ }
+
+ /* Valid input, but no match */
+ return MOSQ_ERR_SUCCESS;
+ }
+ }else{
+ /* sub[spos] == topic[tpos] */
+ if(topic[1] == 0){
+ /* Check for e.g. foo matching foo/# */
+ if(sub[1] == '/'
+ && sub[2] == '#'
+ && sub[3] == 0){
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ spos++;
+ sub++;
+ topic++;
+ if(sub[0] == 0 && topic[0] == 0){
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }else if(topic[0] == 0 && sub[0] == '+' && sub[1] == 0){
+ if(spos > 0 && sub[-1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ spos++;
+ sub++;
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ }
+ if((topic[0] != 0 || sub[0] != 0)){
+ *result = false;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
diff --git a/libs/libmosquitto/src/will_mosq.c b/libs/libmosquitto/src/will_mosq.c
new file mode 100644
index 0000000000..f9f1f32a56
--- /dev/null
+++ b/libs/libmosquitto/src/will_mosq.c
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+# include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "logging_mosq.h"
+#include "messages_mosq.h"
+#include "memory_mosq.h"
+#include "mqtt_protocol.h"
+#include "net_mosq.h"
+#include "read_handle.h"
+#include "send_mosq.h"
+#include "util_mosq.h"
+#include "will_mosq.h"
+
+int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties)
+{
+ int rc = MOSQ_ERR_SUCCESS;
+ mosquitto_property *p;
+
+ if(!mosq || !topic) return MOSQ_ERR_INVAL;
+ if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE;
+ if(payloadlen > 0 && !payload) return MOSQ_ERR_INVAL;
+
+ if(mosquitto_pub_topic_check(topic)) return MOSQ_ERR_INVAL;
+ if(mosquitto_validate_utf8(topic, strlen(topic))) return MOSQ_ERR_MALFORMED_UTF8;
+
+ if(properties){
+ if(mosq->protocol != mosq_p_mqtt5){
+ return MOSQ_ERR_NOT_SUPPORTED;
+ }
+ p = properties;
+ while(p){
+ rc = mosquitto_property_check_command(CMD_WILL, p->identifier);
+ if(rc) return rc;
+ p = p->next;
+ }
+ }
+
+ if(mosq->will){
+ mosquitto__free(mosq->will->msg.topic);
+ mosquitto__free(mosq->will->msg.payload);
+ mosquitto_property_free_all(&mosq->will->properties);
+ mosquitto__free(mosq->will);
+ }
+
+ mosq->will = mosquitto__calloc(1, sizeof(struct mosquitto_message_all));
+ if(!mosq->will) return MOSQ_ERR_NOMEM;
+ mosq->will->msg.topic = mosquitto__strdup(topic);
+ if(!mosq->will->msg.topic){
+ rc = MOSQ_ERR_NOMEM;
+ goto cleanup;
+ }
+ mosq->will->msg.payloadlen = payloadlen;
+ if(mosq->will->msg.payloadlen > 0){
+ if(!payload){
+ rc = MOSQ_ERR_INVAL;
+ goto cleanup;
+ }
+ mosq->will->msg.payload = mosquitto__malloc(sizeof(char)*mosq->will->msg.payloadlen);
+ if(!mosq->will->msg.payload){
+ rc = MOSQ_ERR_NOMEM;
+ goto cleanup;
+ }
+
+ memcpy(mosq->will->msg.payload, payload, payloadlen);
+ }
+ mosq->will->msg.qos = qos;
+ mosq->will->msg.retain = retain;
+
+ mosq->will->properties = properties;
+
+ return MOSQ_ERR_SUCCESS;
+
+cleanup:
+ if(mosq->will){
+ mosquitto__free(mosq->will->msg.topic);
+ mosquitto__free(mosq->will->msg.payload);
+
+ mosquitto__free(mosq->will);
+ mosq->will = NULL;
+ }
+
+ return rc;
+}
+
+int will__clear(struct mosquitto *mosq)
+{
+ if(!mosq->will) return MOSQ_ERR_SUCCESS;
+
+ mosquitto__free(mosq->will->msg.topic);
+ mosq->will->msg.topic = NULL;
+
+ mosquitto__free(mosq->will->msg.payload);
+ mosq->will->msg.payload = NULL;
+
+ mosquitto_property_free_all(&mosq->will->properties);
+
+ mosquitto__free(mosq->will);
+ mosq->will = NULL;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/libs/libmosquitto/src/will_mosq.h b/libs/libmosquitto/src/will_mosq.h
new file mode 100644
index 0000000000..c96dad1a71
--- /dev/null
+++ b/libs/libmosquitto/src/will_mosq.h
@@ -0,0 +1,26 @@
+/*
+Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#ifndef WILL_MOSQ_H
+#define WILL_MOSQ_H
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+
+int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties);
+int will__clear(struct mosquitto *mosq);
+
+#endif