netutils: introduce MQTT library and APIs
authorWonsang Ryou <wonsang.yoo@samsung.com>
Fri, 17 Mar 2017 08:02:51 +0000 (17:02 +0900)
committerHeesub Shin <heesub.shin@samsung.com>
Mon, 17 Apr 2017 10:55:27 +0000 (19:55 +0900)
This commit adds MQTT library and APIs.
 - MQTT library : mosquitto-1.4.10
 - MQTT APIs : for MQTT client (subscriber/publisher) function

Change-Id: I8c13d808fe05206f0bc6b2c0716b23d2c1bc1f52
Signed-off-by: Wonsang Ryou <wonsang.yoo@samsung.com>
39 files changed:
apps/include/netutils/mqtt_api.h [new file with mode: 0644]
apps/netutils/Kconfig
apps/netutils/mqtt/Kconfig [new file with mode: 0644]
apps/netutils/mqtt/Makefile [new file with mode: 0644]
apps/netutils/mqtt/config.h [new file with mode: 0644]
apps/netutils/mqtt/config.mk [new file with mode: 0644]
apps/netutils/mqtt/lib/Makefile [new file with mode: 0644]
apps/netutils/mqtt/lib/logging_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/logging_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/memory_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/memory_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/messages_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/messages_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/mosquitto.c [new file with mode: 0644]
apps/netutils/mqtt/lib/mosquitto.h [new file with mode: 0644]
apps/netutils/mqtt/lib/mosquitto_internal.h [new file with mode: 0644]
apps/netutils/mqtt/lib/mqtt3_protocol.h [new file with mode: 0644]
apps/netutils/mqtt/lib/net_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/net_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/read_handle.c [new file with mode: 0644]
apps/netutils/mqtt/lib/read_handle.h [new file with mode: 0644]
apps/netutils/mqtt/lib/read_handle_client.c [new file with mode: 0644]
apps/netutils/mqtt/lib/read_handle_shared.c [new file with mode: 0644]
apps/netutils/mqtt/lib/send_client_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/send_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/send_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/socks_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/socks_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/srv_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/thread_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/time_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/time_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/tls_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/tls_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/util_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/util_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/lib/will_mosq.c [new file with mode: 0644]
apps/netutils/mqtt/lib/will_mosq.h [new file with mode: 0644]
apps/netutils/mqtt/mqtt_api.c [new file with mode: 0644]

diff --git a/apps/include/netutils/mqtt_api.h b/apps/include/netutils/mqtt_api.h
new file mode 100644 (file)
index 0000000..f93dfb2
--- /dev/null
@@ -0,0 +1,214 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/**
+ * @defgroup MQTT MQTT Client
+ * @ingroup NETWORK
+ * @{
+ */
+/**
+ * @file mqtt_api.h
+ * @brief APIs for MQTT Client(Subscriber/Publisher)
+ */
+
+#ifndef __MQTT_API_H__
+#define __MQTT_API_H__
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+#include <tinyara/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define MQTT_DEFAULT_BROKER_PORT                       1883
+#define MQTT_SECURITY_BROKER_PORT                      8883
+#define MQTT_DEFAULT_KEEP_ALIVE_TIME           60
+
+/****************************************************************************
+ * Enumeration
+ ****************************************************************************/
+/**
+ * @brief This enumeration describes the state of the MQTT client
+ */
+enum mqtt_client_state_e {
+       MQTT_CLIENT_STATE_NOT_CONNECTED = 0,
+       MQTT_CLIENT_STATE_CONNECTED,
+       MQTT_CLIENT_STATE_CONNECT_REQUEST,
+       MQTT_CLIENT_STATE_SUBSCRIBE_REQUEST,
+       MQTT_CLIENT_STATE_UNSUBSCRIBE_REQUEST,
+       MQTT_CLIENT_STATE_PUBLISH_REQUEST,
+       MQTT_CLIENT_STATE_DISCONNECT_REQUEST,
+};
+
+/**
+ * @brief This enumeration describes the state of the MQTT connection result
+ */
+enum mqtt_connection_result_e {
+       MQTT_CONN_ACCEPTED = 0,
+       MQTT_CONN_REFUSED_UNACCEPTABLE_PROTOCOL_VER,
+       MQTT_CONN_REFUSED_ID_REJECTED,
+       MQTT_CONN_REFUSED_BROKER_UNAVAILABLE,
+       MQTT_CONN_REFUSED_BAD_USER_NAME_OR_PASSWORD,
+       MQTT_CONN_REFUSED_NOT_AUTHORIZED,
+};
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+/**
+ * @brief Structure of MQTT message
+ */
+typedef struct _mqtt_msg_t {
+       int msg_id;     /**< message identification */
+       char *topic; /**< message topic */
+       void *payload; /**< message payload content */
+       int payload_len; /**< message pay load length */
+       int qos; /**< message qos flag */
+       int retain;     /**< message retain flag */
+} mqtt_msg_t;
+
+/**
+ * @brief Structure of MQTT security information
+ */
+typedef struct _mqtt_tls_param_t {
+       const unsigned char *ca_cert;   /* CA certificate, common between client and MQTT Broker */
+       const unsigned char *cert;      /* Client certificate */
+       const unsigned char *key;       /* Client private key */
+       int ca_cert_len;                        /* the length of CA certificate  */
+       int cert_len;                           /* the length of Client certificate */
+       int key_len;                            /* the length of key */
+} mqtt_tls_param_t;
+
+/**
+ * @brief Structure of MQTT client configuration
+ */
+typedef struct _mqtt_client_config_t {
+       char *client_id; /**< client identification */
+       char *user_name; /**< client user name */
+       char *password; /**< password corresponding to the user name */
+       bool clean_session;     /**< mqtt clean session flag */
+       bool debug;     /**< mqtt debug flag */
+       mqtt_tls_param_t *tls; /**< mqtt tls parameter */
+
+       void (*on_connect)(void *client, int result);
+       /**< on_connect call back function */
+       void (*on_disconnect)(void *client, int result);
+       /**< on_disconnect call back function */
+       void (*on_publish)(void *client, int msg_id);
+       /**< on_publish call back function */
+       void (*on_message)(void *client, mqtt_msg_t *msg);
+       /**< on_message call back function */
+       void (*on_subscribe)(void *client, int msg_id, int qos_count, const int *granted_qos);
+       /**< on_subscribe call back function */
+       void (*on_unsubscribe)(void *client, int msg_id);
+       /**< on_unsubscribe call back function */
+
+       void *user_data; /**< user defined data */
+} mqtt_client_config_t;
+
+/**
+ * @brief Structure of MQTT client object
+ */
+typedef struct _mqtt_client_t {
+       int lib_version; /**< mqtt library version */
+       void *mosq;     /**< mqtt library client pointer */
+       mqtt_client_config_t *config; /**< mqtt config */
+       int state; /**< mqtt client state */
+} mqtt_client_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+/**
+ * @brief mqtt_init_client() initializes MQTT client
+ *
+ * @param[in] config the information of MQTT client object configuration
+ * @return On success, the handle of MQTT client object is returned. On failure, NULL is returned.
+ *
+ */
+mqtt_client_t *mqtt_init_client(mqtt_client_config_t *config);
+
+/**
+ * @brief mqtt_deinit_client() de-initializes MQTT client
+ *
+ * @param[in] handle  the handle of MQTT client object
+ * @return On success, 0 is returned. On failure, a negative value is returned.
+ *
+ */
+int mqtt_deinit_client(mqtt_client_t *handle);
+
+/**
+ * @brief mqtt_connect() connects to a MQTT broker
+ *
+ * @param[in] handle  the handle of MQTT client object
+ * @param[in] addr  MQTT broker address
+ * @param[in] port  MQTT broker port
+ * @param[in] keep_alive  MQTT keep-alive time in second
+ * @return On success, 0 is returned. On failure, a negative value is returned.
+ *
+ */
+int mqtt_connect(mqtt_client_t *handle, char *addr, int port, int keep_alive);
+
+/**
+ * @brief mqtt_disconnect() disconnects from a MQTT broker
+ *
+ * @param[in] handle  the handle of MQTT client object
+ * @return On success, 0 is returned. On failure, a negative value is returned.
+ *
+ */
+int mqtt_disconnect(mqtt_client_t *handle);
+
+/**
+ * @brief mqtt_publish() pusblishes message to a MQTT broker on the given topic
+ *
+ * @param[in] handle  the handle of MQTT client object
+ * @param[in] topic  the topic on which the message to be published
+ * @param[in] data  the message to publish
+ * @param[in] data_len  the length of message
+ * @param[in] qos  the Quality of Service to be used for the message. QoS value should be 0,1 or 2.
+ * @param[in] retain  the flag to make the message retained.
+ * @return On success, 0 is returned. On failure, a negative value is returned.
+ *
+ */
+int mqtt_publish(mqtt_client_t *handle, char *topic, char *data, uint32_t data_len, uint8_t qos, uint8_t retain);
+
+/**
+ * @brief mqtt_subscribe() subscribes for the specified topic with MQTT broker
+ *
+ * @param[in] handle  the handle of MQTT client object
+ * @param[in] topic  the topic on which the message to be unsubscribed
+ * @param[in] qos  the Quality of Service for the subscription.  QoS value should be 0,1 or 2.
+ * @return On success, 0 is returned. On failure, a negative value is returned.
+ *
+ */
+int mqtt_subscribe(mqtt_client_t *handle, char *topic, uint8_t qos);
+
+/**
+ * @brief mqtt_unsubscribe() unsubscribes from the specified topic
+ *
+ * @param[in] handle  the handle of MQTT client object
+ * @param[in] topic  the topic on which the message to be unsubscribed
+ * @return On success, 0 is returned. On failure, a negative value is returned.
+ *
+ */
+int mqtt_unsubscribe(mqtt_client_t *handle, char *topic);
+
+#endif                                                 /* __MQTT_API_H__ */
+
+/** @} */// end of MQTT group
index c11d727..b8bf7f0 100644 (file)
@@ -21,4 +21,5 @@ source "$APPSDIR/netutils/ntpclient/Kconfig"
 source "$APPSDIR/netutils/xmlrpc/Kconfig"
 source "$APPSDIR/netutils/mdns/Kconfig"
 source "$APPSDIR/netutils/wifi/Kconfig"
+source "$APPSDIR/netutils/mqtt/Kconfig"
 endmenu
diff --git a/apps/netutils/mqtt/Kconfig b/apps/netutils/mqtt/Kconfig
new file mode 100644 (file)
index 0000000..37273f5
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# For a description of the syntax of this configuration file,
+# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
+#
+
+config NETUTILS_MQTT
+       bool "MQTT"
+       default n
+       ---help---
+               Enable support for MQTT. MQTT provides a lightweight method of
+               carrying out messaging using a publish/subscribe model. This makes
+               it suitable for "Internet of Things" messaging such as with low power
+               sensors or mobile devices such as phones, embedded computers. You can
+                get more information about MQTT at https://mosquitto.org/.
+
+if NETUTILS_MQTT
+
+config NETUTILS_MQTT_SECURITY
+        bool "MQTT with security"
+        default n
+       depends on NET_SECURITY_TLS
+       ---help---
+               Enable support for security mode in MQTT.
+               MQTT security mode will work with mbedTLS library.
+               If you want to change Certificate of Key file or change
+                configurations of security, Please reference mqtt examples.
+
+endif # NETUTILS_MQTT
+
diff --git a/apps/netutils/mqtt/Makefile b/apps/netutils/mqtt/Makefile
new file mode 100644 (file)
index 0000000..3f6273a
--- /dev/null
@@ -0,0 +1,139 @@
+###########################################################################
+#
+# Copyright 2016 Samsung Electronics All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+###########################################################################
+############################################################################
+# apps/netutils/mqtt/Makefile
+#
+#   Copyright (C) 2014 Gregory Nutt. All rights reserved.
+#   Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# 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.
+#
+############################################################################
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+include $(APPDIR)/Make.defs
+include config.mk
+
+ASRCS =
+CSRCS =
+
+# mqtt api
+CSRCS += mqtt_api.c
+
+# lib directory
+CSRCS += lib/tls_mosq.c
+CSRCS += lib/net_mosq.c
+CSRCS += lib/send_client_mosq.c
+CSRCS += lib/messages_mosq.c
+CSRCS += lib/util_mosq.c
+CSRCS += lib/socks_mosq.c
+CSRCS += lib/will_mosq.c
+CSRCS += lib/mosquitto.c
+CSRCS += lib/logging_mosq.c
+CSRCS += lib/send_mosq.c
+CSRCS += lib/read_handle_shared.c
+CSRCS += lib/srv_mosq.c
+CSRCS += lib/thread_mosq.c
+CSRCS += lib/read_handle_client.c
+CSRCS += lib/read_handle.c
+CSRCS += lib/time_mosq.c
+CSRCS += lib/memory_mosq.c
+
+# include directory
+CFLAGS += $(MQTT_LIB_CFLAGS)
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+ifeq ($(CONFIG_WINDOWS_NATIVE),y)
+  BIN = ..\..\libapps$(LIBEXT)
+else
+ifeq ($(WINTOOL),y)
+  BIN = ..\\..\\libapps$(LIBEXT)
+else
+  BIN = ../../libapps$(LIBEXT)
+endif
+endif
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: context depend clean distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+       $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+       $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+       $(call ARCHIVE, $(BIN), $(OBJS))
+       $(Q) touch .built
+
+install:
+
+context:
+
+.depend: Makefile $(SRCS)
+       $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
+       $(Q) touch $@
+
+depend: .depend
+
+clean:
+       $(call DELFILE, .built)
+       $(call CLEAN)
+
+distclean: clean
+       $(call DELFILE, Make.dep)
+       $(call DELFILE, .depend)
+
+-include Make.dep
diff --git a/apps/netutils/mqtt/config.h b/apps/netutils/mqtt/config.h
new file mode 100644 (file)
index 0000000..c0a8dd0
--- /dev/null
@@ -0,0 +1,62 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+
+/* ============================================================
+ * Control compile time options.
+ * ============================================================
+ *
+ * Compile time options have moved to config.mk.
+ */
+
+
+/* ============================================================
+ * Compatibility defines
+ *
+ * Generally for Windows native support.
+ * ============================================================ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#  define snprintf sprintf_s
+#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)
+
+#ifndef EPROTO
+#  define EPROTO ECONNABORTED
+#endif
+
+#ifdef WITH_MBEDTLS
+#include "tls/ssl.h"
+#include "tls/net.h"
+#include "tls/x509_crt.h"
+#include "tls/pk.h"
+#include "tls/ctr_drbg.h"
+#include "tls/ssl_cache.h"
+#include "tls/entropy.h"
+#endif
+
diff --git a/apps/netutils/mqtt/config.mk b/apps/netutils/mqtt/config.mk
new file mode 100644 (file)
index 0000000..d8d7aa6
--- /dev/null
@@ -0,0 +1,114 @@
+###########################################################################
+#
+# Copyright 2016 Samsung Electronics All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+###########################################################################
+# =============================================================================
+# User configuration section.
+#
+# These options control compilation on all systems apart from Windows and Mac
+# OS X. Use CMake to compile on Windows and Mac.
+#
+# Largely, these are options that are designed to make mosquitto run more
+# easily in restrictive environments by removing features.
+#
+# Modify the variable below to enable/disable features.
+#
+# Can also be overriden at the command line, e.g.:
+#
+# make WITH_TLS=no
+# =============================================================================
+
+# Uncomment to compile the broker with tcpd/libwrap support.
+#WITH_WRAP:=yes
+
+# Comment out to disable SSL/TLS support in the broker and client.
+# Disabling this will also mean that passwords must be stored in plain text. It
+# is strongly recommended that you only disable WITH_TLS if you are not using
+# password authentication at all.
+WITH_TLS:=no
+
+# Comment out to disable TLS/PSK support in the broker and client. Requires
+# WITH_TLS=yes.
+# This must be disabled if using openssl < 1.0.
+WITH_TLS_PSK:=no
+
+# Comment out to disable client client threading support.
+WITH_THREADING:=yes
+
+# Comment out to remove bridge support from the broker. This allow the broker
+# to connect to other brokers and subscribe/publish to topics. You probably
+# want to leave this included unless you want to save a very small amount of
+# memory size and CPU time.
+WITH_BRIDGE:=no
+
+# Comment out to remove persistent database support from the broker. This
+# allows the broker to store retained messages and durable subscriptions to a
+# file periodically and on shutdown. This is usually desirable (and is
+# suggested by the MQTT spec), but it can be disabled if required.
+WITH_PERSISTENCE:=no
+
+# Comment out to remove memory tracking support from the broker. If disabled,
+# mosquitto won't track heap memory usage nor export '$SYS/broker/heap/current
+# size', but will use slightly less memory and CPU time.
+WITH_MEMORY_TRACKING:=no
+
+# Compile with database upgrading support? If disabled, mosquitto won't
+# automatically upgrade old database versions.
+# Not currently supported.
+#WITH_DB_UPGRADE:=yes
+
+# Comment out to remove publishing of the $SYS topic hierarchy containing
+# information about the broker state.
+WITH_SYS_TREE:=no
+
+# Build with SRV lookup support.
+WITH_SRV:=no
+
+# Build using libuuid for clientid generation (Linux only - please report if
+# supported on your platform).
+WITH_UUID:=no
+
+# Build with websockets support on the broker.
+WITH_WEBSOCKETS:=no
+
+# Use elliptic keys in broker
+WITH_EC:=no
+
+# Build man page documentation by default.
+WITH_DOCS:=no
+
+# Build with client support for SOCK5 proxy.
+WITH_SOCKS:=no
+
+# =============================================================================
+# End of user configuration
+# =============================================================================
+-include $(TOPDIR)/.config
+
+MQTT_TOP=$(APPDIR)/netutils/mqtt
+VERSION=1.4.10
+
+ifeq ($(WITH_THREADING),yes)
+       LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_THREADING
+endif
+
+ifeq ($(CONFIG_NETUTILS_MQTT_SECURITY),y)
+       LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_MBEDTLS
+endif
+
+MQTT_LIB_CFLAGS := $(LIB_CFLAGS) -D__TINYARA__ -DVERSION="\"${VERSION}\""
+MQTT_LIB_CFLAGS += -I$(MQTT_TOP) -I$(MQTT_TOP)/lib
+
diff --git a/apps/netutils/mqtt/lib/Makefile b/apps/netutils/mqtt/lib/Makefile
new file mode 100644 (file)
index 0000000..825fcea
--- /dev/null
@@ -0,0 +1,100 @@
+include ../config.mk
+
+.PHONY : really clean install
+
+MOSQ_OBJS=mosquitto.o \
+                 logging_mosq.o \
+                 memory_mosq.o \
+                 messages_mosq.o \
+                 net_mosq.o \
+                 read_handle.o \
+                 read_handle_client.o \
+                 read_handle_shared.o \
+                 send_mosq.o \
+                 send_client_mosq.o \
+                 socks_mosq.o \
+                 srv_mosq.o \
+                 thread_mosq.o \
+                 time_mosq.o \
+                 tls_mosq.o \
+                 util_mosq.o \
+                 will_mosq.o
+
+all : libmosquitto.so.${SOVERSION} libmosquitto.a
+       $(MAKE) -C cpp
+
+install : all
+       $(INSTALL) -d ${DESTDIR}$(prefix)/lib${LIB_SUFFIX}/
+       $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so.${SOVERSION}
+       ln -sf libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so
+       $(INSTALL) -d ${DESTDIR}${prefix}/include/
+       $(INSTALL) mosquitto.h ${DESTDIR}${prefix}/include/mosquitto.h
+       $(MAKE) -C cpp install
+
+uninstall :
+       -rm -f ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so.${SOVERSION}
+       -rm -f ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so
+       -rm -f ${DESTDIR}${prefix}/include/mosquitto.h
+
+reallyclean : clean
+
+clean :
+       -rm -f *.o libmosquitto.so.${SOVERSION} libmosquitto.so libmosquitto.a
+       $(MAKE) -C cpp clean
+
+libmosquitto.so.${SOVERSION} : ${MOSQ_OBJS}
+       ${CROSS_COMPILE}$(CC) -shared $(LIB_LDFLAGS) $^ -o $@ ${LIB_LIBS}
+
+libmosquitto.a : ${MOSQ_OBJS}
+       ${CROSS_COMPILE}$(AR) cr $@ $^
+mosquitto.o : mosquitto.c mosquitto.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+logging_mosq.o : logging_mosq.c logging_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+messages_mosq.o : messages_mosq.c messages_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+memory_mosq.o : memory_mosq.c memory_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+net_mosq.o : net_mosq.c net_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+read_handle.o : read_handle.c read_handle.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+read_handle_client.o : read_handle_client.c read_handle.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+read_handle_shared.o : read_handle_shared.c read_handle.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+send_mosq.o : send_mosq.c send_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+send_client_mosq.o : send_client_mosq.c send_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+socks_mosq.o : socks_mosq.c
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+srv_mosq.o : srv_mosq.c
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+thread_mosq.o : thread_mosq.c
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+time_mosq.o : time_mosq.c
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+tls_mosq.o : tls_mosq.c
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+util_mosq.o : util_mosq.c util_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
+will_mosq.o : will_mosq.c will_mosq.h
+       ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
+
diff --git a/apps/netutils/mqtt/lib/logging_mosq.c b/apps/netutils/mqtt/lib/logging_mosq.c
new file mode 100644 (file)
index 0000000..358e322
--- /dev/null
@@ -0,0 +1,73 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <mosquitto_internal.h>
+#include <mosquitto.h>
+#include <memory_mosq.h>
+
+int _mosquitto_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/apps/netutils/mqtt/lib/logging_mosq.h b/apps/netutils/mqtt/lib/logging_mosq.h
new file mode 100644 (file)
index 0000000..e32a919
--- /dev/null
@@ -0,0 +1,40 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 _mosquitto_log_printf(struct mosquitto *mosq, int priority, const char *fmt, ...);
+
+#endif
diff --git a/apps/netutils/mqtt/lib/memory_mosq.c b/apps/netutils/mqtt/lib/memory_mosq.c
new file mode 100644 (file)
index 0000000..4399552
--- /dev/null
@@ -0,0 +1,141 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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
+
+void *_mosquitto_calloc(size_t nmemb, size_t size)
+{
+       void *mem = calloc(nmemb, size);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+       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)
+{
+       void *mem = malloc(size);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+       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)
+{
+       void *mem;
+#ifdef REAL_WITH_MEMORY_TRACKING
+       if(ptr){
+               memcount -= malloc_usable_size(ptr);
+       }
+#endif
+       mem = realloc(ptr, size);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+       memcount += malloc_usable_size(mem);
+       if(memcount > max_memcount){
+               max_memcount = memcount;
+       }
+#endif
+
+       return mem;
+}
+
+char *_mosquitto_strdup(const char *s)
+{
+       char *str = strdup(s);
+
+#ifdef REAL_WITH_MEMORY_TRACKING
+       memcount += malloc_usable_size(str);
+       if(memcount > max_memcount){
+               max_memcount = memcount;
+       }
+#endif
+
+       return str;
+}
+
diff --git a/apps/netutils/mqtt/lib/memory_mosq.h b/apps/netutils/mqtt/lib/memory_mosq.h
new file mode 100644 (file)
index 0000000..a69b167
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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(WIN32) && !defined(__SYMBIAN32__) && !defined(__ANDROID__) && !defined(__UCLIBC__) && !defined(__OpenBSD__)
+#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);
+
+#endif
diff --git a/apps/netutils/mqtt/lib/messages_mosq.c b/apps/netutils/mqtt/lib/messages_mosq.c
new file mode 100644 (file)
index 0000000..b28e3f3
--- /dev/null
@@ -0,0 +1,416 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mosquitto_internal.h>
+#include <mosquitto.h>
+#include <memory_mosq.h>
+#include <messages_mosq.h>
+#include <send_mosq.h>
+#include <time_mosq.h>
+
+void _mosquitto_message_cleanup(struct mosquitto_message_all **message)
+{
+       struct mosquitto_message_all *msg;
+
+       if(!message || !*message) return;
+
+       msg = *message;
+
+       if(msg->msg.topic) _mosquitto_free(msg->msg.topic);
+       if(msg->msg.payload) _mosquitto_free(msg->msg.payload);
+       _mosquitto_free(msg);
+}
+
+void _mosquitto_message_cleanup_all(struct mosquitto *mosq)
+{
+       struct mosquitto_message_all *tmp;
+
+       assert(mosq);
+
+       while(mosq->in_messages){
+               tmp = mosq->in_messages->next;
+               _mosquitto_message_cleanup(&mosq->in_messages);
+               mosq->in_messages = tmp;
+       }
+       while(mosq->out_messages){
+               tmp = mosq->out_messages->next;
+               _mosquitto_message_cleanup(&mosq->out_messages);
+               mosq->out_messages = tmp;
+       }
+}
+
+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_malloc(src->payloadlen);
+               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 _mosquitto_message_delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir)
+{
+       struct mosquitto_message_all *message;
+       int rc;
+       assert(mosq);
+
+       rc = _mosquitto_message_remove(mosq, mid, dir, &message);
+       if(rc == MOSQ_ERR_SUCCESS){
+               _mosquitto_message_cleanup(&message);
+       }
+       return rc;
+}
+
+void mosquitto_message_free(struct mosquitto_message **message)
+{
+       struct mosquitto_message *msg;
+
+       if(!message || !*message) return;
+
+       msg = *message;
+
+       if(msg->topic) _mosquitto_free(msg->topic);
+       if(msg->payload) _mosquitto_free(msg->payload);
+       _mosquitto_free(msg);
+}
+
+
+/*
+ * Function: _mosquitto_message_queue
+ *
+ * Returns:
+ *     0 - to indicate an outgoing message can be started
+ *     1 - to indicate that the outgoing message queue is full (inflight limit has been reached)
+ */
+int _mosquitto_message_queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir)
+{
+       int rc = 0;
+
+       /* mosq->*_message_mutex should be locked before entering this function */
+       assert(mosq);
+       assert(message);
+
+       if(dir == mosq_md_out){
+               mosq->out_queue_len++;
+               message->next = NULL;
+               if(mosq->out_messages_last){
+                       mosq->out_messages_last->next = message;
+               }else{
+                       mosq->out_messages = message;
+               }
+               mosq->out_messages_last = message;
+               if(message->msg.qos > 0){
+                       if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){
+                               mosq->inflight_messages++;
+                       }else{
+                               rc = 1;
+                       }
+               }
+       }else{
+               mosq->in_queue_len++;
+               message->next = NULL;
+               if(mosq->in_messages_last){
+                       mosq->in_messages_last->next = message;
+               }else{
+                       mosq->in_messages = message;
+               }
+               mosq->in_messages_last = message;
+       }
+       return rc;
+}
+
+void _mosquitto_messages_reconnect_reset(struct mosquitto *mosq)
+{
+       struct mosquitto_message_all *message;
+       struct mosquitto_message_all *prev = NULL;
+       assert(mosq);
+
+       pthread_mutex_lock(&mosq->in_message_mutex);
+       message = mosq->in_messages;
+       mosq->in_queue_len = 0;
+       while(message){
+               mosq->in_queue_len++;
+               message->timestamp = 0;
+               if(message->msg.qos != 2){
+                       if(prev){
+                               prev->next = message->next;
+                               _mosquitto_message_cleanup(&message);
+                               message = prev;
+                       }else{
+                               mosq->in_messages = message->next;
+                               _mosquitto_message_cleanup(&message);
+                               message = mosq->in_messages;
+                       }
+               }else{
+                       /* Message state can be preserved here because it should match
+                       * whatever the client has got. */
+               }
+               prev = message;
+               message = message->next;
+       }
+       mosq->in_messages_last = prev;
+       pthread_mutex_unlock(&mosq->in_message_mutex);
+
+
+       pthread_mutex_lock(&mosq->out_message_mutex);
+       mosq->inflight_messages = 0;
+       message = mosq->out_messages;
+       mosq->out_queue_len = 0;
+       while(message){
+               mosq->out_queue_len++;
+               message->timestamp = 0;
+
+               if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){
+                       if(message->msg.qos > 0){
+                               mosq->inflight_messages++;
+                       }
+                       if(message->msg.qos == 1){
+                               message->state = mosq_ms_wait_for_puback;
+                       }else if(message->msg.qos == 2){
+                               /* Should be able to preserve state. */
+                       }
+               }else{
+                       message->state = mosq_ms_invalid;
+               }
+               prev = message;
+               message = message->next;
+       }
+       mosq->out_messages_last = prev;
+       pthread_mutex_unlock(&mosq->out_message_mutex);
+}
+
+int _mosquitto_message_remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message)
+{
+       struct mosquitto_message_all *cur, *prev = NULL;
+       bool found = false;
+       int rc;
+       assert(mosq);
+       assert(message);
+
+       if(dir == mosq_md_out){
+               pthread_mutex_lock(&mosq->out_message_mutex);
+               cur = mosq->out_messages;
+               while(cur){
+                       if(cur->msg.mid == mid){
+                               if(prev){
+                                       prev->next = cur->next;
+                               }else{
+                                       mosq->out_messages = cur->next;
+                               }
+                               *message = cur;
+                               mosq->out_queue_len--;
+                               if(cur->next == NULL){
+                                       mosq->out_messages_last = prev;
+                               }else if(!mosq->out_messages){
+                                       mosq->out_messages_last = NULL;
+                               }
+                               if(cur->msg.qos > 0){
+                                       mosq->inflight_messages--;
+                               }
+                               found = true;
+                               break;
+                       }
+                       prev = cur;
+                       cur = cur->next;
+               }
+
+               if(found){
+                       cur = mosq->out_messages;
+                       while(cur){
+                               if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){
+                                       if(cur->msg.qos > 0 && cur->state == mosq_ms_invalid){
+                                               mosq->inflight_messages++;
+                                               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 = _mosquitto_send_publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup);
+                                               if(rc){
+                                                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                                                       return rc;
+                                               }
+                                       }
+                               }else{
+                                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                                       return MOSQ_ERR_SUCCESS;
+                               }
+                               cur = cur->next;
+                       }
+                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                       return MOSQ_ERR_SUCCESS;
+               }else{
+                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                       return MOSQ_ERR_NOT_FOUND;
+               }
+       }else{
+               pthread_mutex_lock(&mosq->in_message_mutex);
+               cur = mosq->in_messages;
+               while(cur){
+                       if(cur->msg.mid == mid){
+                               if(prev){
+                                       prev->next = cur->next;
+                               }else{
+                                       mosq->in_messages = cur->next;
+                               }
+                               *message = cur;
+                               mosq->in_queue_len--;
+                               if(cur->next == NULL){
+                                       mosq->in_messages_last = prev;
+                               }else if(!mosq->in_messages){
+                                       mosq->in_messages_last = NULL;
+                               }
+                               found = true;
+                               break;
+                       }
+                       prev = cur;
+                       cur = cur->next;
+               }
+
+               pthread_mutex_unlock(&mosq->in_message_mutex);
+               if(found){
+                       return MOSQ_ERR_SUCCESS;
+               }else{
+                       return MOSQ_ERR_NOT_FOUND;
+               }
+       }
+}
+
+#ifdef WITH_THREADING
+void _mosquitto_message_retry_check_actual(struct mosquitto *mosq, struct mosquitto_message_all *messages, pthread_mutex_t *mutex)
+#else
+void _mosquitto_message_retry_check_actual(struct mosquitto *mosq, struct mosquitto_message_all *messages)
+#endif
+{
+       time_t now = mosquitto_time();
+       assert(mosq);
+
+#ifdef WITH_THREADING
+       pthread_mutex_lock(mutex);
+#endif
+
+       while(messages){
+               if(messages->timestamp + mosq->message_retry < now){
+                       switch(messages->state){
+                               case mosq_ms_wait_for_puback:
+                               case mosq_ms_wait_for_pubrec:
+                                       messages->timestamp = now;
+                                       messages->dup = true;
+                                       _mosquitto_send_publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup);
+                                       break;
+                               case mosq_ms_wait_for_pubrel:
+                                       messages->timestamp = now;
+                                       messages->dup = true;
+                                       _mosquitto_send_pubrec(mosq, messages->msg.mid);
+                                       break;
+                               case mosq_ms_wait_for_pubcomp:
+                                       messages->timestamp = now;
+                                       messages->dup = true;
+                                       _mosquitto_send_pubrel(mosq, messages->msg.mid);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               messages = messages->next;
+       }
+#ifdef WITH_THREADING
+       pthread_mutex_unlock(mutex);
+#endif
+}
+
+void _mosquitto_message_retry_check(struct mosquitto *mosq)
+{
+#ifdef WITH_THREADING
+       _mosquitto_message_retry_check_actual(mosq, mosq->out_messages, &mosq->out_message_mutex);
+       _mosquitto_message_retry_check_actual(mosq, mosq->in_messages, &mosq->in_message_mutex);
+#else
+       _mosquitto_message_retry_check_actual(mosq, mosq->out_messages);
+       _mosquitto_message_retry_check_actual(mosq, mosq->in_messages);
+#endif
+}
+
+void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry)
+{
+       assert(mosq);
+       if(mosq) mosq->message_retry = message_retry;
+}
+
+int _mosquitto_message_out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state)
+{
+       struct mosquitto_message_all *message;
+       assert(mosq);
+
+       pthread_mutex_lock(&mosq->out_message_mutex);
+       message = mosq->out_messages;
+       while(message){
+               if(message->msg.mid == mid){
+                       message->state = state;
+                       message->timestamp = mosquitto_time();
+                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                       return MOSQ_ERR_SUCCESS;
+               }
+               message = message->next;
+       }
+       pthread_mutex_unlock(&mosq->out_message_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->max_inflight_messages = max_inflight_messages;
+
+       return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/apps/netutils/mqtt/lib/messages_mosq.h b/apps/netutils/mqtt/lib/messages_mosq.h
new file mode 100644 (file)
index 0000000..b1123ec
--- /dev/null
@@ -0,0 +1,48 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 _mosquitto_message_cleanup_all(struct mosquitto *mosq);
+void _mosquitto_message_cleanup(struct mosquitto_message_all **message);
+int _mosquitto_message_delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir);
+int _mosquitto_message_queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir);
+void _mosquitto_messages_reconnect_reset(struct mosquitto *mosq);
+int _mosquitto_message_remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message);
+void _mosquitto_message_retry_check(struct mosquitto *mosq);
+int _mosquitto_message_out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state);
+
+#endif
diff --git a/apps/netutils/mqtt/lib/mosquitto.c b/apps/netutils/mqtt/lib/mosquitto.c
new file mode 100644 (file)
index 0000000..ada7061
--- /dev/null
@@ -0,0 +1,1712 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
+#else
+#include <winsock2.h>
+#include <windows.h>
+typedef int ssize_t;
+#endif
+
+#include <mosquitto.h>
+#include <mosquitto_internal.h>
+#include <logging_mosq.h>
+#include <messages_mosq.h>
+#include <memory_mosq.h>
+#include <mqtt3_protocol.h>
+#include <net_mosq.h>
+#include <read_handle.h>
+#include <send_mosq.h>
+#include <socks_mosq.h>
+#include <time_mosq.h>
+#include <tls_mosq.h>
+#include <util_mosq.h>
+#include <will_mosq.h>
+
+#include "config.h"
+
+#if defined(__TINYARA__)
+#include <netdb.h>
+#endif
+
+#if !defined(WIN32) && !defined(__SYMBIAN32__) && !defined(__TINYARA__)
+#define HAVE_PSELECT
+#endif
+
+#if defined(__TINYARA__)
+#ifndef FD_SETSIZE
+#define FD_SETSIZE     (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)
+#endif
+#endif
+
+void _mosquitto_destroy(struct mosquitto *mosq);
+static int _mosquitto_reconnect(struct mosquitto *mosq, bool blocking);
+static int _mosquitto_connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address);
+
+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(GetTickCount());
+#else
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       srand(tv.tv_sec*1000 + tv.tv_usec/1000);
+#endif
+
+       _mosquitto_net_init();
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_lib_cleanup(void)
+{
+       _mosquitto_net_cleanup();
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *userdata)
+{
+       struct mosquitto *mosq = NULL;
+       int rc;
+
+       if(clean_session == false && id == NULL){
+               errno = EINVAL;
+               return NULL;
+       }
+
+#if !defined(WIN32) && !defined(__TINYARA__)
+       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_session, 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_session, void *userdata)
+{
+       int i;
+
+       if(!mosq) return MOSQ_ERR_INVAL;
+
+       if(clean_session == 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_mqtt31;
+       mosq->sock = INVALID_SOCKET;
+       mosq->sockpairR = INVALID_SOCKET;
+       mosq->sockpairW = INVALID_SOCKET;
+       mosq->keepalive = 60;
+       mosq->message_retry = 20;
+       mosq->last_retry_check = 0;
+       mosq->clean_session = clean_session;
+       if(id){
+               if(STREMPTY(id)){
+                       return MOSQ_ERR_INVAL;
+               }
+               mosq->id = _mosquitto_strdup(id);
+       }else{
+               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] = '/';
+
+               for(i=5; i<23; i++){
+                       mosq->id[i] = (rand()%73)+48;
+               }
+       }
+       mosq->in_packet.payload = NULL;
+       _mosquitto_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->in_messages = NULL;
+       mosq->in_messages_last = NULL;
+       mosq->out_messages = NULL;
+       mosq->out_messages_last = NULL;
+       mosq->max_inflight_messages = 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->in_queue_len = 0;
+       mosq->out_queue_len = 0;
+       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->tls_cert_reqs = SSL_VERIFY_PEER;
+       mosq->tls_insecure = false;
+       mosq->want_write = false;
+#endif
+#ifdef WITH_MBEDTLS
+       mosq->mbedtls_state = mosq_mbedtls_state_disabled;
+       mosq->ssl = NULL;
+       mosq->ssl_ctx = NULL;
+       mosq->tls_cert_reqs = MBEDTLS_SSL_VERIFY_REQUIRED;
+       mosq->tls_hostname = NULL;
+       mosq->want_write = false;
+       mosq->tls_insecure = 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->in_message_mutex, NULL);
+       pthread_mutex_init(&mosq->out_message_mutex, NULL);
+       pthread_mutex_init(&mosq->mid_mutex, NULL);
+       mosq->thread_id = pthread_self();
+#endif
+
+#if defined(__TINYARA__)
+       mosq->in_select = false;
+       mosq->connect_ainfo = NULL;
+       mosq->connect_ainfo_bind = NULL;
+#endif
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
+{
+       if(!mosq) return MOSQ_ERR_INVAL;
+       return _mosquitto_will_set(mosq, topic, payloadlen, payload, qos, retain);
+}
+
+int mosquitto_will_clear(struct mosquitto *mosq)
+{
+       if(!mosq) return MOSQ_ERR_INVAL;
+       return _mosquitto_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->username){
+               _mosquitto_free(mosq->username);
+               mosq->username = NULL;
+       }
+       if(mosq->password){
+               _mosquitto_free(mosq->password);
+               mosq->password = NULL;
+       }
+
+       if(username){
+               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;
+       
+       mosq->reconnect_delay = reconnect_delay;
+       mosq->reconnect_delay_max = reconnect_delay_max;
+       mosq->reconnect_exponential_backoff = reconnect_exponential_backoff;
+       
+       return MOSQ_ERR_SUCCESS;
+       
+}
+
+void _mosquitto_destroy(struct mosquitto *mosq)
+{
+       struct _mosquitto_packet *packet;
+       if(!mosq) return;
+
+#ifdef WITH_THREADING
+       if(mosq->threaded == mosq_ts_self && !pthread_equal(mosq->thread_id, pthread_self())){
+#if defined(__TINYARA__)
+               if((mosq->sockpairW != INVALID_SOCKET) && mosq->in_select)
+               {
+                       char sockpair_data = 0xff;
+                       if (send(mosq->sockpairW, &sockpair_data, 1, 0) == -1)
+                       {
+                               _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: send() fail in _mosquitto_destroy");
+                               pthread_cancel(mosq->thread_id);
+                       }
+               }
+               else
+               {
+                       pthread_cancel(mosq->thread_id);
+               }
+
+               pthread_join(mosq->thread_id, NULL);
+               mosq->threaded = mosq_ts_none;
+#else
+               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->in_message_mutex);
+               pthread_mutex_destroy(&mosq->out_message_mutex);
+               pthread_mutex_destroy(&mosq->mid_mutex);
+       }
+#endif
+       if(mosq->sock != INVALID_SOCKET){
+               _mosquitto_socket_close(mosq);
+       }
+       _mosquitto_message_cleanup_all(mosq);
+       _mosquitto_will_clear(mosq);
+#ifdef WITH_TLS
+       if(mosq->ssl){
+               SSL_free(mosq->ssl);
+       }
+       if(mosq->ssl_ctx){
+               SSL_CTX_free(mosq->ssl_ctx);
+       }
+       if(mosq->tls_cafile) _mosquitto_free(mosq->tls_cafile);
+       if(mosq->tls_capath) _mosquitto_free(mosq->tls_capath);
+       if(mosq->tls_certfile) _mosquitto_free(mosq->tls_certfile);
+       if(mosq->tls_keyfile) _mosquitto_free(mosq->tls_keyfile);
+       if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL;
+       if(mosq->tls_version) _mosquitto_free(mosq->tls_version);
+       if(mosq->tls_ciphers) _mosquitto_free(mosq->tls_ciphers);
+       if(mosq->tls_psk) _mosquitto_free(mosq->tls_psk);
+       if(mosq->tls_psk_identity) _mosquitto_free(mosq->tls_psk_identity);
+#endif
+#ifdef WITH_MBEDTLS
+        if(mosq->cert) {
+               mbedtls_x509_crt_free(mosq->cert);
+               free(mosq->cert);
+       }
+       if(mosq->pkey) {
+               mbedtls_pk_free(mosq->pkey);
+               free(mosq->pkey);
+       }
+       if(mosq->entropy) {
+               mbedtls_entropy_free(mosq->entropy);
+               free(mosq->entropy);
+       }
+       if(mosq->ctr_drbg) {
+               mbedtls_ctr_drbg_free(mosq->ctr_drbg);
+               free(mosq->ctr_drbg);
+       }
+       if(mosq->cache) {
+               mbedtls_ssl_cache_free(mosq->cache);
+               free(mosq->cache);
+       }
+       if(mosq->ssl) {
+               mbedtls_ssl_config_free(mosq->ssl);
+               free(mosq->ssl);
+       }
+       if(mosq->net) {
+               free(mosq->net);
+       }
+       if(mosq->ssl_ctx) {
+               mbedtls_ssl_free(mosq->ssl_ctx);
+               free(mosq->ssl_ctx);
+       }
+#endif
+
+       if(mosq->address){
+               _mosquitto_free(mosq->address);
+               mosq->address = NULL;
+       }
+       if(mosq->id){
+               _mosquitto_free(mosq->id);
+               mosq->id = NULL;
+       }
+       if(mosq->username){
+               _mosquitto_free(mosq->username);
+               mosq->username = NULL;
+       }
+       if(mosq->password){
+               _mosquitto_free(mosq->password);
+               mosq->password = NULL;
+       }
+       if(mosq->host){
+               _mosquitto_free(mosq->host);
+               mosq->host = NULL;
+       }
+       if(mosq->bind_address){
+               _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;
+               }
+
+               _mosquitto_packet_cleanup(packet);
+               _mosquitto_free(packet);
+       }
+
+       _mosquitto_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;
+       }
+
+#if defined(__TINYARA__)
+       if(mosq->connect_ainfo){
+               freeaddrinfo(mosq->connect_ainfo);
+               mosq->connect_ainfo = NULL;
+       }
+       if(mosq->connect_ainfo_bind){
+               freeaddrinfo(mosq->connect_ainfo_bind);
+               mosq->connect_ainfo_bind = NULL;
+       }
+#endif
+}
+
+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;
+}
+
+static int _mosquitto_connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
+{
+       if(!mosq) return MOSQ_ERR_INVAL;
+       if(!host || port <= 0) return MOSQ_ERR_INVAL;
+
+       if(mosq->host) _mosquitto_free(mosq->host);
+       mosq->host = _mosquitto_strdup(host);
+       if(!mosq->host) return MOSQ_ERR_NOMEM;
+       mosq->port = port;
+
+       if(mosq->bind_address) _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;
+
+       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(_mosquitto_socketpair(&mosq->sockpairR, &mosq->sockpairW)){
+               _mosquitto_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)
+{
+       int 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);
+}
+
+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);
+}
+
+int mosquitto_reconnect_async(struct mosquitto *mosq)
+{
+       return _mosquitto_reconnect(mosq, false);
+}
+
+int mosquitto_reconnect(struct mosquitto *mosq)
+{
+       return _mosquitto_reconnect(mosq, true);
+}
+
+static int _mosquitto_reconnect(struct mosquitto *mosq, bool blocking)
+{
+       int rc;
+       struct _mosquitto_packet *packet;
+       if(!mosq) return MOSQ_ERR_INVAL;
+       if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL;
+
+       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;
+
+       _mosquitto_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;
+               }
+
+               _mosquitto_packet_cleanup(packet);
+               _mosquitto_free(packet);
+       }
+       pthread_mutex_unlock(&mosq->out_packet_mutex);
+       pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+
+       _mosquitto_messages_reconnect_reset(mosq);
+
+#ifdef WITH_SOCKS
+       if(mosq->socks5_host){
+               rc = _mosquitto_socket_connect(mosq, mosq->socks5_host, mosq->socks5_port, mosq->bind_address, blocking);
+       }else
+#endif
+       {
+               rc = _mosquitto_socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking);
+       }
+       if(rc>0){
+               return rc;
+       }
+
+#ifdef WITH_SOCKS
+       if(mosq->socks5_host){
+               return mosquitto__socks5_send(mosq);
+       }else
+#endif
+       {
+               return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session);
+       }
+}
+
+int mosquitto_disconnect(struct mosquitto *mosq)
+{
+       if(!mosq) return MOSQ_ERR_INVAL;
+
+       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 _mosquitto_send_disconnect(mosq);
+}
+
+int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
+{
+       struct mosquitto_message_all *message;
+       uint16_t local_mid;
+       int queue_status;
+
+       if(!mosq || !topic || qos<0 || qos>2) return MOSQ_ERR_INVAL;
+       if(STREMPTY(topic)) return MOSQ_ERR_INVAL;
+       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;
+       }
+
+       local_mid = _mosquitto_mid_generate(mosq);
+       if(mid){
+               *mid = local_mid;
+       }
+
+       if(qos == 0){
+               return _mosquitto_send_publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false);
+       }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;
+               message->msg.topic = _mosquitto_strdup(topic);
+               if(!message->msg.topic){
+                       _mosquitto_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){
+                               _mosquitto_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->out_message_mutex);
+               queue_status = _mosquitto_message_queue(mosq, message, mosq_md_out);
+               if(queue_status == 0){
+                       if(qos == 1){
+                               message->state = mosq_ms_wait_for_puback;
+                       }else if(qos == 2){
+                               message->state = mosq_ms_wait_for_pubrec;
+                       }
+                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                       return _mosquitto_send_publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup);
+               }else{
+                       message->state = mosq_ms_invalid;
+                       pthread_mutex_unlock(&mosq->out_message_mutex);
+                       return MOSQ_ERR_SUCCESS;
+               }
+       }
+}
+
+int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
+{
+       if(!mosq) return MOSQ_ERR_INVAL;
+       if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+       if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL;
+
+       return _mosquitto_send_subscribe(mosq, mid, sub, qos);
+}
+
+int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub)
+{
+       if(!mosq) return MOSQ_ERR_INVAL;
+       if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+       if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL;
+
+       return _mosquitto_send_unsubscribe(mosq, mid, sub);
+}
+
+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;
+
+       if(cafile){
+               fptr = _mosquitto_fopen(cafile, "rt");
+               if(fptr){
+                       fclose(fptr);
+               }else{
+                       return MOSQ_ERR_INVAL;
+               }
+               mosq->tls_cafile = _mosquitto_strdup(cafile);
+
+               if(!mosq->tls_cafile){
+                       return MOSQ_ERR_NOMEM;
+               }
+       }else if(mosq->tls_cafile){
+               _mosquitto_free(mosq->tls_cafile);
+               mosq->tls_cafile = NULL;
+       }
+
+       if(capath){
+               mosq->tls_capath = _mosquitto_strdup(capath);
+               if(!mosq->tls_capath){
+                       return MOSQ_ERR_NOMEM;
+               }
+       }else if(mosq->tls_capath){
+               _mosquitto_free(mosq->tls_capath);
+               mosq->tls_capath = NULL;
+       }
+
+       if(certfile){
+               fptr = _mosquitto_fopen(certfile, "rt");
+               if(fptr){
+                       fclose(fptr);
+               }else{
+                       if(mosq->tls_cafile){
+                               _mosquitto_free(mosq->tls_cafile);
+                               mosq->tls_cafile = NULL;
+                       }
+                       if(mosq->tls_capath){
+                               _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;
+               }
+       }else{
+               if(mosq->tls_certfile) _mosquitto_free(mosq->tls_certfile);
+               mosq->tls_certfile = NULL;
+       }
+
+       if(keyfile){
+               fptr = _mosquitto_fopen(keyfile, "rt");
+               if(fptr){
+                       fclose(fptr);
+               }else{
+                       if(mosq->tls_cafile){
+                               _mosquitto_free(mosq->tls_cafile);
+                               mosq->tls_cafile = NULL;
+                       }
+                       if(mosq->tls_capath){
+                               _mosquitto_free(mosq->tls_capath);
+                               mosq->tls_capath = NULL;
+                       }
+                       if(mosq->tls_certfile){
+                               _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;
+               }
+       }else{
+               if(mosq->tls_keyfile) _mosquitto_free(mosq->tls_keyfile);
+               mosq->tls_keyfile = NULL;
+       }
+
+       mosq->tls_pw_callback = pw_callback;
+
+
+       return MOSQ_ERR_SUCCESS;
+#else
+#ifdef WITH_MBEDTLS
+       int r;
+
+       if(!mosq || !cafile)
+               return MOSQ_ERR_INVAL;
+
+       mosq->tls_ca_cert = (char *) cafile;
+       mosq->tls_cert = (char *) certfile;
+       mosq->tls_key = (char *) keyfile;
+
+       mosq->cert = malloc(sizeof(mbedtls_x509_crt));
+       mosq->pkey = malloc(sizeof(mbedtls_pk_context));
+       mosq->entropy = malloc(sizeof(mbedtls_entropy_context));
+       mosq->ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context));
+       mosq->cache = malloc(sizeof(mbedtls_ssl_cache_context));
+
+       if(!mosq->cert || !mosq->pkey || !mosq->entropy || !mosq->ctr_drbg || !mosq->cache) {
+               return MOSQ_ERR_NOMEM;
+       }
+
+       /* 0. Initialize tls sub params */
+        mbedtls_x509_crt_init(mosq->cert);
+        mbedtls_pk_init(mosq->pkey);
+        mbedtls_entropy_init(mosq->entropy);
+        mbedtls_ctr_drbg_init(mosq->ctr_drbg);
+        mbedtls_ssl_cache_init(mosq->cache);
+
+        /* 1. Load the certificates and private RSA key */
+       if (mosq->tls_cert) {
+               if ((r = mbedtls_x509_crt_parse(mosq->cert,
+                       (const unsigned char *)mosq->tls_cert, mosq->tls_cert_len)) != 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_x509_crt_parse fail");
+                       return MOSQ_ERR_TLS;
+               }
+       }
+
+        if ((r = mbedtls_x509_crt_parse(mosq->cert,
+                (const unsigned char *)mosq->tls_ca_cert, mosq->tls_ca_cert_len)) != 0) {
+                _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_x509_crt_parse_ca fail");
+                return MOSQ_ERR_TLS;
+        }
+
+#if defined(CONFIG_TLS_WITH_SSS) && defined(CONFIG_HW_RSA)
+       const mbedtls_pk_info_t *pk_info;
+
+       if((pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))== NULL)
+               return MOSQ_ERR_TLS;
+
+       if((r = mbedtls_pk_setup(mosq->pkey, pk_info)) != 0)
+               return MOSQ_ERR_TLS;
+
+       mbedtls_rsa_init((mbedtls_rsa_context*)((mbedtls_pk_context*)mosq->pkey)->pk_ctx,
+                        MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);
+       ((mbedtls_rsa_context *)((mbedtls_pk_context*)mosq->pkey)->pk_ctx)->key_index = \
+                                                               (unsigned int)mosq->tls_key;
+       ((mbedtls_rsa_context *)((mbedtls_pk_context*)mosq->pkey)->pk_ctx)->len = 256;
+#else
+       if (mosq->tls_key) {
+               if ((r = mbedtls_pk_parse_key(mosq->pkey,
+                       (const unsigned char *)mosq->tls_key, mosq->tls_key_len, NULL, 0)) != 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_pk_parse_key fail");
+                       return MOSQ_ERR_TLS;
+               }
+       }
+#endif
+        if ((r = mbedtls_ctr_drbg_seed(mosq->ctr_drbg, mbedtls_entropy_func,
+                                        mosq->entropy, NULL, 0)) != 0) {
+                _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ctr_drbg_seed fail");
+                return MOSQ_ERR_TLS;
+        }
+
+        /* 2. Set ssl */
+        mosq->ssl = malloc(sizeof(mbedtls_ssl_config));
+
+        if(!mosq->ssl) {
+               return MOSQ_ERR_NOMEM;
+        }
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+       mbedtls_ssl_conf_session_tickets(mosq->ssl, 0);
+#endif
+        mbedtls_ssl_config_init(mosq->ssl);
+
+        if ((r = mbedtls_ssl_config_defaults(mosq->ssl, MBEDTLS_SSL_IS_CLIENT,
+                MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+                _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ssl_config_defaults fail");
+                return MOSQ_ERR_TLS;
+        }
+
+        mbedtls_ssl_conf_rng(mosq->ssl, mbedtls_ctr_drbg_random, mosq->ctr_drbg);
+
+#if defined(CONFIG_HW_RSA)
+       mbedtls_ssl_conf_ca_chain(mosq->ssl, ((mbedtls_x509_crt *)mosq->cert)->next, NULL);
+
+       if ((r = mbedtls_ssl_conf_own_cert(mosq->ssl, mosq->cert, mosq->pkey)) != 0) {
+               _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ssl_conf_own_cert fail");
+               return MOSQ_ERR_TLS;
+       }
+#else
+       if(mosq->tls_cert && mosq->tls_key) {
+               mbedtls_ssl_conf_ca_chain(mosq->ssl, ((mbedtls_x509_crt *)mosq->cert)->next, NULL);
+
+               if ((r = mbedtls_ssl_conf_own_cert(mosq->ssl, mosq->cert, mosq->pkey)) != 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ssl_conf_own_cert fail");
+                       return MOSQ_ERR_TLS;
+               }
+       }
+       else if(mosq->tls_cert) {
+               mbedtls_ssl_conf_ca_chain(mosq->ssl, ((mbedtls_x509_crt *)mosq->cert)->next, NULL);
+
+               if ((r = mbedtls_ssl_conf_own_cert(mosq->ssl, mosq->cert, NULL)) != 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ssl_conf_own_cert fail");
+                       return MOSQ_ERR_TLS;
+               }
+       }
+       else {
+               mbedtls_ssl_conf_ca_chain(mosq->ssl, ((mbedtls_x509_crt *)mosq->cert), NULL);
+       }
+#endif
+
+       mbedtls_ssl_conf_authmode(mosq->ssl, mosq->tls_cert_reqs);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+       mbedtls_ssl_cache_init(mosq->cache);
+       mbedtls_ssl_conf_session_cache(mosq->ssl, mosq->cache,
+                                   mbedtls_ssl_cache_get, mbedtls_ssl_cache_set);
+#endif
+
+       mosq->mbedtls_state = mosq_mbedtls_state_enabled;
+
+       return MOSQ_ERR_SUCCESS;
+#endif
+       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 OPENSSL_VERSION_NUMBER >= 0x10001000L
+               if(!strcasecmp(tls_version, "tlsv1.2")
+                               || !strcasecmp(tls_version, "tlsv1.1")
+                               || !strcasecmp(tls_version, "tlsv1")){
+
+                       mosq->tls_version = _mosquitto_strdup(tls_version);
+                       if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
+               }else{
+                       return MOSQ_ERR_INVAL;
+               }
+#else
+               if(!strcasecmp(tls_version, "tlsv1")){
+                       mosq->tls_version = _mosquitto_strdup(tls_version);
+                       if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
+               }else{
+                       return MOSQ_ERR_INVAL;
+               }
+#endif
+       }else{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+               mosq->tls_version = _mosquitto_strdup("tlsv1.2");
+#else
+               mosq->tls_version = _mosquitto_strdup("tlsv1");
+#endif
+               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
+#ifdef WITH_MBEDTLS
+       if(!mosq) return MOSQ_ERR_INVAL;
+       mosq->tls_insecure = value;
+       return MOSQ_ERR_SUCCESS;
+#endif
+       return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+
+int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers)
+{
+#ifdef REAL_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_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
+#ifdef WITH_MBEDTLS
+                if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && 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;
+       }
+
+       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
+
+#if defined(__TINYARA__)
+       mosq->in_select = true;
+#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 defined(__TINYARA__)
+       mosq->in_select = false;
+#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)){
+#ifdef WITH_TLS
+                               if(mosq->want_connect){
+                                       rc = mosquitto__socket_connect_tls(mosq);
+                                       if(rc) return rc;
+                               }else
+#endif
+#ifdef WITH_MBEDTLS
+                               if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->want_connect){
+                                       rc = mosquitto__socket_connect_tls(mosq);
+                                       if(rc) return rc;
+                               }else
+#endif
+                               {
+                                       do{
+                                               rc = mosquitto_loop_read(mosq, max_packets);
+                                               if(rc || mosq->sock == INVALID_SOCKET){
+                                                       return rc;
+                                               }
+                                       }while(SSL_DATA_PENDING(mosq));
+                               }
+                       }
+                       if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){
+#ifndef WIN32
+#if defined(__TINYARA__)
+                               if(read(mosq->sockpairR, &pairbuf, 1) == 1){
+                                       if (pairbuf == 0xff)
+                                       {
+                                               return MOSQ_ERR_FORCE_EXIT;
+                                       }
+                               }
+#else
+                               if(read(mosq->sockpairR, &pairbuf, 1) == 0){
+                               }
+#endif /* __TINYARA__ */
+#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. */
+                               FD_SET(mosq->sock, &writefds);
+                       }
+                       if(FD_ISSET(mosq->sock, &writefds)){
+#ifdef WITH_TLS
+                               if(mosq->want_connect){
+                                       rc = mosquitto__socket_connect_tls(mosq);
+                                       if(rc) return rc;
+                               }else
+#endif
+#ifdef WITH_MBEDTLS
+                               if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->want_connect){
+                                       rc = mosquitto__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;
+
+       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:
+#if defined(__TINYARA__)
+                       case MOSQ_ERR_FORCE_EXIT:
+#endif
+                               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 > 0 && mosq->reconnect_exponential_backoff){
+                                       reconnect_delay = mosq->reconnect_delay*reconnects*reconnects;
+                               }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
+                               sleep(reconnect_delay);
+#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)
+{
+       time_t now;
+       int rc;
+
+       if(!mosq) return MOSQ_ERR_INVAL;
+       if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
+
+       _mosquitto_check_keepalive(mosq);
+       now = mosquitto_time();
+       if(mosq->last_retry_check+1 < now){
+               _mosquitto_message_retry_check(mosq);
+               mosq->last_retry_check = now;
+       }
+       if(mosq->ping_t && now - mosq->ping_t >= mosq->keepalive){
+               /* mosq->ping_t != 0 means we are waiting for a pingresp.
+                * This hasn't happened in the keepalive time so we should disconnect.
+                */
+               _mosquitto_socket_close(mosq);
+               pthread_mutex_lock(&mosq->state_mutex);
+               if(mosq->state == mosq_cs_disconnecting){
+                       rc = MOSQ_ERR_SUCCESS;
+               }else{
+                       rc = 1;
+               }
+               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;
+               }
+               pthread_mutex_unlock(&mosq->callback_mutex);
+               return MOSQ_ERR_CONN_LOST;
+       }
+       return MOSQ_ERR_SUCCESS;
+}
+
+static int _mosquitto_loop_rc_handle(struct mosquitto *mosq, int rc)
+{
+       if(rc){
+               _mosquitto_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;
+               }
+               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;
+
+       pthread_mutex_lock(&mosq->out_message_mutex);
+       max_packets = mosq->out_queue_len;
+       pthread_mutex_unlock(&mosq->out_message_mutex);
+
+       pthread_mutex_lock(&mosq->in_message_mutex);
+       max_packets += mosq->in_queue_len;
+       pthread_mutex_unlock(&mosq->in_message_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++){
+#ifdef WITH_SOCKS
+               if(mosq->socks5_host){
+                       rc = mosquitto__socks5_read(mosq);
+               }else
+#endif
+               {
+                       rc = _mosquitto_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->out_message_mutex);
+       max_packets = mosq->out_queue_len;
+       pthread_mutex_unlock(&mosq->out_message_mutex);
+
+       pthread_mutex_lock(&mosq->in_message_mutex);
+       max_packets += mosq->in_queue_len;
+       pthread_mutex_unlock(&mosq->in_message_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 = _mosquitto_packet_write(mosq);
+               if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
+                       return _mosquitto_loop_rc_handle(mosq, rc);
+               }
+       }
+       return rc;
+}
+
+bool mosquitto_want_write(struct mosquitto *mosq)
+{
+       if(mosq->out_packet || mosq->current_out_packet){
+               return true;
+#ifdef WITH_TLS
+       }else if(mosq->ssl && mosq->want_write){
+               return true;
+#endif
+#ifdef WITH_MBEDTLS
+       }else if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->ssl && mosq->want_write){
+               return true;
+#endif
+       }else{
+               return false;
+       }
+}
+
+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);
+                       if(ival == MQTT_PROTOCOL_V31){
+                               mosq->protocol = mosq_p_mqtt31;
+                       }else if(ival == MQTT_PROTOCOL_V311){
+                               mosq->protocol = mosq_p_mqtt311;
+                       }else{
+                               return MOSQ_ERR_INVAL;
+                       }
+                       break;
+               default:
+                       return MOSQ_ERR_INVAL;
+       }
+       return MOSQ_ERR_SUCCESS;
+}
+
+
+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_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_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_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_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_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_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);
+}
+
+void mosquitto_user_data_set(struct mosquitto *mosq, void *userdata)
+{
+       if(mosq){
+               mosq->userdata = userdata;
+       }
+}
+
+const char *mosquitto_strerror(int mosq_errno)
+{
+       switch(mosq_errno){
+               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.";
+               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.";
+       }
+}
+
+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(i=0; i<hier_count; i++){
+                                               if((*topics)[hier]){
+                                                       _mosquitto_free((*topics)[hier]);
+                                               }
+                                       }
+                                       _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++){
+               if((*topics)[i]) _mosquitto_free((*topics)[i]);
+       }
+       _mosquitto_free(*topics);
+
+       return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/apps/netutils/mqtt/lib/mosquitto.h b/apps/netutils/mqtt/lib/mosquitto.h
new file mode 100644 (file)
index 0000000..5d2f269
--- /dev/null
@@ -0,0 +1,1555 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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)
+#      ifdef libmosquitto_EXPORTS
+#              define libmosq_EXPORT  __declspec(dllexport)
+#      else
+#              define libmosq_EXPORT  __declspec(dllimport)
+#      endif
+#else
+#      define libmosq_EXPORT
+#endif
+
+#ifdef WIN32
+#      ifndef __cplusplus
+#              define bool char
+#              define true 1
+#              define false 0
+#      endif
+#else
+#      ifndef __cplusplus
+#              include <stdbool.h>
+#      endif
+#endif
+
+#define LIBMOSQUITTO_MAJOR 1
+#define LIBMOSQUITTO_MINOR 4
+#define LIBMOSQUITTO_REVISION 10
+/* 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 0x00
+#define MOSQ_LOG_INFO 0x01
+#define MOSQ_LOG_NOTICE 0x02
+#define MOSQ_LOG_WARNING 0x04
+#define MOSQ_LOG_ERR 0x08
+#define MOSQ_LOG_DEBUG 0x10
+#define MOSQ_LOG_SUBSCRIBE 0x20
+#define MOSQ_LOG_UNSUBSCRIBE 0x40
+#define MOSQ_LOG_WEBSOCKETS 0x80
+#define MOSQ_LOG_ALL 0xFFFF
+
+/* Error values */
+enum mosq_err_t {
+       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
+#if defined(__TINYARA__)
+       , MOSQ_ERR_FORCE_EXIT = 255
+#endif
+};
+
+/* Error values */
+enum mosq_opt_t {
+       MOSQ_OPT_PROTOCOL_VERSION = 1,
+};
+
+/* 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
+
+struct mosquitto_message{
+       int mid;
+       char *topic;
+       void *payload;
+       int payloadlen;
+       int qos;
+       bool retain;
+};
+
+struct mosquitto;
+
+/*
+ * 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()
+ ***************************************************/
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/* 
+ * 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.
+ */
+libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain);
+
+/* 
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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_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_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.
+ *
+ * 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_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.
+ */
+libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos);
+
+/*
+ * 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.
+ */
+libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub);
+
+/*
+ * 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>
+ */
+libmosq_EXPORT void mosquitto_message_free(struct mosquitto_message **message);
+
+/*
+ * 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);
+
+/*
+ * 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_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);
+
+/*
+ * 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);
+
+/*
+ * Function: mosquitto_opts_set
+ *
+ * Used to set 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 an int, set to either
+ *                                 MQTT_PROTOCOL_V31 or MQTT_PROTOCOL_V311. Must
+ *                                 be set before the client connects. Defaults to
+ *                                 MQTT_PROTOCOL_V31.
+ */
+libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value);
+
+
+/*
+ * 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.
+ *
+ * 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>
+ */
+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);
+
+/* 
+ * 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_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_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_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_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_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_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_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
+ *
+ * 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
+ *
+ * Set the number of seconds to wait before retrying messages. This applies to
+ * publish messages with QoS>0. May be called at any time.
+ * 
+ * Parameters:
+ *  mosq -          a valid mosquitto instance.
+ *  message_retry - the number of seconds to wait for a response before
+ *                  retrying. Defaults to 20.
+ */
+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);
+
+/* =============================================================================
+ *
+ * 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_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.
+ *
+ * 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
+ *
+ * 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.
+ *     topic - topic to check.
+ *     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);
+
+/*
+ * 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
+ *
+ * Returns:
+ *   MOSQ_ERR_SUCCESS - for a valid topic
+ *   MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long.
+ *
+ * See Also:
+ *   <mosquitto_sub_topic_check>
+ */
+libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic);
+
+/*
+ * 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
+ *
+ * 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.
+ *
+ * See Also:
+ *   <mosquitto_sub_topic_check>
+ */
+libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/netutils/mqtt/lib/mosquitto_internal.h b/apps/netutils/mqtt/lib/mosquitto_internal.h
new file mode 100644 (file)
index 0000000..dd759d0
--- /dev/null
@@ -0,0 +1,331 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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_INTERNAL_H_
+#define _MOSQUITTO_INTERNAL_H_
+
+#include <config.h>
+
+#ifdef WIN32
+#  include <winsock2.h>
+#endif
+
+#ifdef WITH_TLS
+#  include <openssl/ssl.h>
+#else
+#ifdef WITH_MBEDTLS
+#  include <tls/ssl.h>
+#else
+#  include <time.h>
+#endif
+#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
+#if defined(__TINYARA__)
+#include <netdb.h>
+#endif
+
+#include "mosquitto.h"
+#include "time_mosq.h"
+#ifdef WITH_BROKER
+#  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,
+};
+
+enum _mosquitto_protocol {
+       mosq_p_invalid = 0,
+       mosq_p_mqtt31 = 1,
+       mosq_p_mqtt311 = 2,
+       mosq_p_mqtts = 3
+};
+
+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
+};
+
+#ifdef WITH_MBEDTLS
+enum _mosquitto_mbedtls_state {
+       mosq_mbedtls_state_disabled = 0,
+       mosq_mbedtls_state_enabled = 1,
+};
+#endif
+
+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;
+       time_t timestamp;
+       //enum mosquitto_msg_direction direction;
+       enum mosquitto_msg_state state;
+       bool dup;
+       struct mosquitto_message msg;
+};
+
+struct mosquitto {
+       mosq_sock_t sock;
+#ifndef WITH_BROKER
+       mosq_sock_t sockpairR, sockpairW;
+#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 *will;
+#ifdef WITH_MBEDTLS
+       int mbedtls_state;
+       mbedtls_ssl_config *ssl;
+       mbedtls_ssl_context *ssl_ctx;
+        void *cert;
+        void *pkey;
+        void *entropy;
+        void *ctr_drbg;
+       void *net;
+       void *cache;
+       char *tls_ca_cert;
+       char *tls_cert;
+       char *tls_key;
+       char *tls_version;
+       char *tls_ciphers;
+       char *tls_hostname;
+       unsigned int tls_ca_cert_len;
+       unsigned int tls_cert_len;
+       unsigned int tls_key_len;
+       int tls_cert_reqs;
+       bool tls_insecure;
+#endif
+#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;
+#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 in_message_mutex;
+       pthread_mutex_t out_message_mutex;
+       pthread_mutex_t mid_mutex;
+       pthread_t thread_id;
+#endif
+       bool clean_session;
+#ifdef WITH_BROKER
+       bool is_dropping;
+       bool is_bridge;
+       struct _mqtt3_bridge *bridge;
+       struct mosquitto_client_msg *msgs;
+       struct mosquitto_client_msg *last_msg;
+       int msg_count;
+       int msg_count12;
+       struct _mosquitto_acl_user *acl_list;
+       struct _mqtt3_listener *listener;
+       time_t disconnect_t;
+       struct _mosquitto_packet *out_packet_last;
+       struct _mosquitto_subhier **subs;
+       int 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
+#else
+#  ifdef WITH_SOCKS
+       char *socks5_host;
+       int socks5_port;
+       char *socks5_username;
+       char *socks5_password;
+#  endif
+       void *userdata;
+       bool in_callback;
+       unsigned int message_retry;
+       time_t last_retry_check;
+       struct mosquitto_message_all *in_messages;
+       struct mosquitto_message_all *in_messages_last;
+       struct mosquitto_message_all *out_messages;
+       struct mosquitto_message_all *out_messages_last;
+       void (*on_connect)(struct mosquitto *, void *userdata, int rc);
+       void (*on_disconnect)(struct mosquitto *, void *userdata, int rc);
+       void (*on_publish)(struct mosquitto *, void *userdata, int mid);
+       void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message);
+       void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos);
+       void (*on_unsubscribe)(struct mosquitto *, void *userdata, int mid);
+       void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str);
+       //void (*on_error)();
+       char *host;
+       int port;
+       int in_queue_len;
+       int out_queue_len;
+       char *bind_address;
+       unsigned int reconnect_delay;
+       unsigned int reconnect_delay_max;
+       bool reconnect_exponential_backoff;
+       char threaded;
+       struct _mosquitto_packet *out_packet_last;
+       int inflight_messages;
+       int max_inflight_messages;
+#  ifdef WITH_SRV
+       ares_channel achan;
+#  endif
+#endif
+
+#ifdef WITH_BROKER
+       UT_hash_handle hh_id;
+       UT_hash_handle hh_sock;
+       struct mosquitto *for_free_next;
+#endif
+
+#if defined(__TINYARA__)
+       bool in_select;
+       struct addrinfo *connect_ainfo;
+       struct addrinfo *connect_ainfo_bind;
+#endif
+};
+
+#define STREMPTY(str) (str[0] == '\0')
+
+#endif
diff --git a/apps/netutils/mqtt/lib/mqtt3_protocol.h b/apps/netutils/mqtt/lib/mqtt3_protocol.h
new file mode 100644 (file)
index 0000000..0ddf62e
--- /dev/null
@@ -0,0 +1,70 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 _MQTT3_PROTOCOL_H_
+#define _MQTT3_PROTOCOL_H_
+
+/* For version 3 of the MQTT protocol */
+
+#define PROTOCOL_NAME_v31 "MQIsdp"
+#define PROTOCOL_VERSION_v31 3
+
+#define PROTOCOL_NAME_v311 "MQTT"
+#define PROTOCOL_VERSION_v311 4
+
+/* Message types */
+#define CONNECT 0x10
+#define CONNACK 0x20
+#define PUBLISH 0x30
+#define PUBACK 0x40
+#define PUBREC 0x50
+#define PUBREL 0x60
+#define PUBCOMP 0x70
+#define SUBSCRIBE 0x80
+#define SUBACK 0x90
+#define UNSUBSCRIBE 0xA0
+#define UNSUBACK 0xB0
+#define PINGREQ 0xC0
+#define PINGRESP 0xD0
+#define DISCONNECT 0xE0
+
+#define CONNACK_ACCEPTED 0
+#define CONNACK_REFUSED_PROTOCOL_VERSION 1
+#define CONNACK_REFUSED_IDENTIFIER_REJECTED 2
+#define CONNACK_REFUSED_SERVER_UNAVAILABLE 3
+#define CONNACK_REFUSED_BAD_USERNAME_PASSWORD 4
+#define CONNACK_REFUSED_NOT_AUTHORIZED 5
+
+#define MQTT_MAX_PAYLOAD 268435455
+
+#endif
diff --git a/apps/netutils/mqtt/lib/net_mosq.c b/apps/netutils/mqtt/lib/net_mosq.c
new file mode 100644 (file)
index 0000000..e77f2ad
--- /dev/null
@@ -0,0 +1,1400 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#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 __FreeBSD__
+#  include <netinet/in.h>
+#endif
+
+#ifdef __SYMBIAN32__
+#include <netinet/in.h>
+#endif
+
+#ifdef __QNX__
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0
+#endif
+#include <net/netbyte.h>
+#include <netinet/in.h>
+#endif
+
+#ifdef WITH_TLS
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <tls_mosq.h>
+#endif
+
+#ifdef WITH_BROKER
+#  include <mosquitto_broker.h>
+#  ifdef WITH_SYS_TREE
+   extern uint64_t g_bytes_received;
+   extern uint64_t g_bytes_sent;
+   extern unsigned long g_msgs_received;
+   extern unsigned long g_msgs_sent;
+   extern unsigned long g_pub_msgs_received;
+   extern unsigned long g_pub_msgs_sent;
+#  endif
+#  ifdef WITH_WEBSOCKETS
+#    include <libwebsockets.h>
+#  endif
+#else
+#  include <read_handle.h>
+#endif
+
+#include <logging_mosq.h>
+#include <memory_mosq.h>
+#include <mqtt3_protocol.h>
+#include <net_mosq.h>
+#include <time_mosq.h>
+#include <util_mosq.h>
+
+#include "config.h"
+
+#ifdef WITH_TLS
+int tls_ex_index_mosq = -1;
+#endif
+
+void _mosquitto_net_init(void)
+{
+#ifdef WIN32
+       WSADATA wsaData;
+       WSAStartup(MAKEWORD(2,2), &wsaData);
+#endif
+
+#ifdef WITH_SRV
+       ares_library_init(ARES_LIB_INIT_ALL);
+#endif
+
+#ifdef WITH_TLS
+       SSL_load_error_strings();
+       SSL_library_init();
+       OpenSSL_add_all_algorithms();
+       if(tls_ex_index_mosq == -1){
+               tls_ex_index_mosq = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
+       }
+#endif
+}
+
+void _mosquitto_net_cleanup(void)
+{
+#ifdef WITH_TLS
+       ERR_remove_state(0);
+       ENGINE_cleanup();
+       CONF_modules_unload(1);
+       ERR_free_strings();
+       EVP_cleanup();
+       CRYPTO_cleanup_all_ex_data();
+#endif
+
+#ifdef WITH_SRV
+       ares_library_cleanup();
+#endif
+
+#ifdef WIN32
+       WSACleanup();
+#endif
+}
+
+void _mosquitto_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;
+       if(packet->payload) _mosquitto_free(packet->payload);
+       packet->payload = NULL;
+       packet->to_process = 0;
+       packet->pos = 0;
+}
+
+int _mosquitto_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 0;
+       }else{
+               return _mosquitto_packet_write(mosq);
+       }
+#  else
+       return _mosquitto_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
+#if defined(__TINYARA__)
+               if (send(mosq->sockpairW, &sockpair_data, 1, 0) == -1)
+               {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: send() fail in %s in _mosquitto_packet_queue");
+               }
+#else
+               send(mosq->sockpairW, &sockpair_data, 1, 0);
+#endif
+#endif
+       }
+
+       if(mosq->in_callback == false && mosq->threaded == mosq_ts_none){
+               return _mosquitto_packet_write(mosq);
+       }else{
+               return MOSQ_ERR_SUCCESS;
+       }
+#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 _mosquitto_socket_close(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+int _mosquitto_socket_close(struct mosquitto *mosq)
+#endif
+{
+       int rc = 0;
+
+       assert(mosq);
+#ifdef WITH_TLS
+       if(mosq->ssl){
+               SSL_shutdown(mosq->ssl);
+               SSL_free(mosq->ssl);
+               mosq->ssl = NULL;
+       }
+       if(mosq->ssl_ctx){
+               SSL_CTX_free(mosq->ssl_ctx);
+               mosq->ssl_ctx = NULL;
+       }
+#endif
+
+       if((int)mosq->sock >= 0){
+#ifdef WITH_BROKER
+               HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
+#endif
+               rc = COMPAT_CLOSE(mosq->sock);
+               mosq->sock = INVALID_SOCKET;
+#ifdef WITH_WEBSOCKETS
+       }else if(mosq->sock == WEBSOCKET_CLIENT){
+               if(mosq->state != mosq_cs_disconnecting){
+                       mosq->state = mosq_cs_disconnect_ws;
+               }
+               if(mosq->wsi){
+                       libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
+               }
+               mosq->sock = INVALID_SOCKET;
+#endif
+       }
+
+#ifdef WITH_BROKER
+       if(mosq->listener){
+               mosq->listener->client_count--;
+               assert(mosq->listener->client_count >= 0);
+               mosq->listener = NULL;
+       }
+#endif
+
+       return rc;
+}
+
+#ifdef REAL_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;
+
+       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
+
+int _mosquitto_try_connect(struct mosquitto *mosq, 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));
+#ifdef WITH_TLS
+       if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){
+               hints.ai_family = PF_INET;
+       }else
+#endif
+#ifdef WITH_MBEDTLS
+       if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->tls_ca_cert){
+               hints.ai_family = PF_INET;
+       }else
+#endif
+       {
+               hints.ai_family = PF_UNSPEC;
+       }
+       hints.ai_flags = AI_ADDRCONFIG;
+       hints.ai_socktype = SOCK_STREAM;
+
+       s = getaddrinfo(host, NULL, &hints, &ainfo);
+       if(s){
+               _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: getaddrinfo() fail (%d)", s);
+               errno = s;
+               return MOSQ_ERR_EAI;
+       }
+#if defined(__TINYARA__)
+       mosq->connect_ainfo = ainfo;
+#endif
+
+       if(bind_address){
+               s = getaddrinfo(bind_address, NULL, &hints, &ainfo_bind);
+               if(s){
+                       freeaddrinfo(ainfo);
+#if defined(__TINYARA__)
+                       mosq->connect_ainfo = ainfo = NULL;
+#endif
+                       errno = s;
+                       return MOSQ_ERR_EAI;
+               }
+#if defined(__TINYARA__)
+               mosq->connect_ainfo_bind = ainfo_bind;
+#endif
+       }
+
+       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 == PF_INET){
+                       ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port);
+               }else if(rp->ai_family == PF_INET6){
+                       ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port);
+               }else{
+                       COMPAT_CLOSE(*sock);
+                       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);
+                               continue;
+                       }
+               }
+
+               if(!blocking){
+                       /* Set non-blocking */
+                       if(_mosquitto_socket_nonblock(*sock)){
+                               COMPAT_CLOSE(*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(_mosquitto_socket_nonblock(*sock)){
+                                       COMPAT_CLOSE(*sock);
+                                       continue;
+                               }
+                       }
+                       break;
+               }
+
+               COMPAT_CLOSE(*sock);
+               *sock = INVALID_SOCKET;
+       }
+       freeaddrinfo(ainfo);
+#if defined(__TINYARA__)
+       mosq->connect_ainfo = ainfo = NULL;
+#endif
+       if(bind_address){
+               freeaddrinfo(ainfo_bind);
+#if defined(__TINYARA__)
+               mosq->connect_ainfo_bind = ainfo_bind = NULL;
+#endif
+       }
+
+#if defined(__TINYARA__)
+       if(*sock == INVALID_SOCKET)
+       {
+               return MOSQ_ERR_NO_CONN;
+       }
+#endif
+
+       if(!rp){
+               return MOSQ_ERR_ERRNO;
+       }
+
+       return rc;
+}
+
+#ifdef WITH_TLS
+int mosquitto__socket_connect_tls(struct mosquitto *mosq)
+{
+       int ret, err;
+       ret = SSL_connect(mosq->ssl);
+       if(ret != 1) {
+               err = SSL_get_error(mosq->ssl, ret);
+#ifdef WIN32
+               if (err == SSL_ERROR_SYSCALL) {
+                       mosq->want_connect = true;
+                       return MOSQ_ERR_SUCCESS;
+               }
+#endif
+               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{
+                       COMPAT_CLOSE(mosq->sock);
+                       mosq->sock = INVALID_SOCKET;
+                       return MOSQ_ERR_TLS;
+               }
+       }else{
+               mosq->want_connect = false;
+       }
+       return MOSQ_ERR_SUCCESS;
+}
+#endif
+
+#ifdef WITH_MBEDTLS
+int mosquitto__socket_connect_tls(struct mosquitto *mosq)
+{
+       int r;
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Handshake Start.");
+       /* Handshake */
+       while ((r = mbedtls_ssl_handshake(mosq->ssl_ctx)) != 0)
+       {
+               if (r != MBEDTLS_ERR_SSL_WANT_READ &&
+                   r != MBEDTLS_ERR_SSL_WANT_WRITE)
+               {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: handshake fail -%x", -r);
+                       COMPAT_CLOSE(mosq->sock);
+                       mosq->sock = INVALID_SOCKET;
+                       return MOSQ_ERR_TLS;
+               }
+       }
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Handshake End.");
+       return MOSQ_ERR_SUCCESS;
+}
+#endif
+
+/* Create a socket and connect it to 'ip' on port 'port'.
+ * Returns -1 on failure (ip is NULL, socket creation/connection error)
+ * Returns sock number on success.
+ */
+int _mosquitto_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;
+#ifdef WITH_TLS
+       int ret;
+       BIO *bio;
+#endif
+
+       if(!mosq || !host || !port) return MOSQ_ERR_INVAL;
+
+       rc = _mosquitto_try_connect(mosq, host, port, &sock, bind_address, blocking);
+       if(rc > 0) return rc;
+
+#ifdef WITH_MBEDTLS
+       if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->ssl != NULL) {
+               int ret;
+
+               mosq->ssl_ctx = malloc(sizeof(mbedtls_ssl_context));
+
+               if(mosq->ssl_ctx == NULL) {
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_NOMEM;
+               }
+
+               mbedtls_ssl_init(mosq->ssl_ctx);
+
+               if ((ret = mbedtls_ssl_setup(mosq->ssl_ctx, mosq->ssl)) != 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ssl_setup fail");
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_TLS;
+               }
+
+               if (mosq->tls_hostname != NULL) {
+                       if ((ret = mbedtls_ssl_set_hostname(mosq->ssl_ctx, mosq->tls_hostname)) != 0) {
+                               _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: mbedtls_ssl_set_hostname fail");
+                               COMPAT_CLOSE(sock);
+                               return MOSQ_ERR_TLS;
+                       }
+               }
+
+               mosq->net = malloc(sizeof(mbedtls_net_context));
+
+               if (mosq->net == NULL) {
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_TLS;
+               }
+               ((mbedtls_net_context *)mosq->net)->fd = (int) sock;
+               mbedtls_ssl_set_bio(mosq->ssl_ctx, mosq->net,
+                                   mbedtls_net_send, mbedtls_net_recv, NULL);
+
+               if(mosquitto__socket_connect_tls(mosq)){
+                       return MOSQ_ERR_TLS;
+               }
+       }
+#endif
+
+#ifdef WITH_TLS
+       if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+               if(!mosq->tls_version || !strcmp(mosq->tls_version, "tlsv1.2")){
+                       mosq->ssl_ctx = SSL_CTX_new(TLSv1_2_client_method());
+               }else if(!strcmp(mosq->tls_version, "tlsv1.1")){
+                       mosq->ssl_ctx = SSL_CTX_new(TLSv1_1_client_method());
+               }else if(!strcmp(mosq->tls_version, "tlsv1")){
+                       mosq->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
+               }else{
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version);
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_INVAL;
+               }
+#else
+               if(!mosq->tls_version || !strcmp(mosq->tls_version, "tlsv1")){
+                       mosq->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
+               }else{
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version);
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_INVAL;
+               }
+#endif
+               if(!mosq->ssl_ctx){
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_TLS;
+               }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000
+               /* Disable compression */
+               SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_COMPRESSION);
+#endif
+#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(mosq->tls_ciphers){
+                       ret = SSL_CTX_set_cipher_list(mosq->ssl_ctx, mosq->tls_ciphers);
+                       if(ret == 0){
+                               _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", mosq->tls_ciphers);
+                               COMPAT_CLOSE(sock);
+                               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){
+                                       _mosquitto_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){
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\".", mosq->tls_cafile);
+                               }else{
+                                       _mosquitto_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){
+                                       _mosquitto_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){
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\".", mosq->tls_cafile);
+                               }else{
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check capath \"%s\".", mosq->tls_capath);
+                               }
+#endif
+                               COMPAT_CLOSE(sock);
+                               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
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate, check bridge_certfile \"%s\".", mosq->tls_certfile);
+#else
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate \"%s\".", mosq->tls_certfile);
+#endif
+                                       COMPAT_CLOSE(sock);
+                                       return MOSQ_ERR_TLS;
+                               }
+                       }
+                       if(mosq->tls_keyfile){
+                               ret = SSL_CTX_use_PrivateKey_file(mosq->ssl_ctx, mosq->tls_keyfile, SSL_FILETYPE_PEM);
+                               if(ret != 1){
+#ifdef WITH_BROKER
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file, check bridge_keyfile \"%s\".", mosq->tls_keyfile);
+#else
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file \"%s\".", mosq->tls_keyfile);
+#endif
+                                       COMPAT_CLOSE(sock);
+                                       return MOSQ_ERR_TLS;
+                               }
+                               ret = SSL_CTX_check_private_key(mosq->ssl_ctx);
+                               if(ret != 1){
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Client certificate/key are inconsistent.");
+                                       COMPAT_CLOSE(sock);
+                                       return MOSQ_ERR_TLS;
+                               }
+                       }
+#ifdef REAL_WITH_TLS_PSK
+               }else if(mosq->tls_psk){
+                       SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback);
+#endif
+               }
+
+               mosq->ssl = SSL_new(mosq->ssl_ctx);
+               if(!mosq->ssl){
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_TLS;
+               }
+               SSL_set_ex_data(mosq->ssl, tls_ex_index_mosq, mosq);
+               bio = BIO_new_socket(sock, BIO_NOCLOSE);
+               if(!bio){
+                       COMPAT_CLOSE(sock);
+                       return MOSQ_ERR_TLS;
+               }
+               SSL_set_bio(mosq->ssl, bio, bio);
+
+               mosq->sock = sock;
+               if(mosquitto__socket_connect_tls(mosq)){
+                       return MOSQ_ERR_TLS;
+               }
+
+       }
+#endif
+
+       mosq->sock = sock;
+
+       return rc;
+}
+
+int _mosquitto_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 _mosquitto_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 _mosquitto_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 _mosquitto_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 _mosquitto_read_string(struct _mosquitto_packet *packet, char **str)
+{
+       uint16_t len;
+       int rc;
+
+       assert(packet);
+       rc = _mosquitto_read_uint16(packet, &len);
+       if(rc) return rc;
+
+       if(packet->pos+len > packet->remaining_length) return MOSQ_ERR_PROTOCOL;
+
+       *str = _mosquitto_malloc(len+1);
+       if(*str){
+               memcpy(*str, &(packet->payload[packet->pos]), len);
+               (*str)[len] = '\0';
+               packet->pos += len;
+       }else{
+               return MOSQ_ERR_NOMEM;
+       }
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+void _mosquitto_write_string(struct _mosquitto_packet *packet, const char *str, uint16_t length)
+{
+       assert(packet);
+       _mosquitto_write_uint16(packet, length);
+       _mosquitto_write_bytes(packet, str, length);
+}
+
+int _mosquitto_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 _mosquitto_write_uint16(struct _mosquitto_packet *packet, uint16_t word)
+{
+       _mosquitto_write_byte(packet, MOSQ_MSB(word));
+       _mosquitto_write_byte(packet, MOSQ_LSB(word));
+}
+
+ssize_t _mosquitto_net_read(struct mosquitto *mosq, void *buf, size_t count)
+{
+#ifdef WITH_TLS
+       int ret;
+       int err;
+       char ebuf[256];
+       unsigned long e;
+#endif
+       assert(mosq);
+       errno = 0;
+#ifdef WITH_TLS
+       if(mosq->ssl){
+               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{
+                               e = ERR_get_error();
+                               while(e){
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error: %s", ERR_error_string(e, ebuf));
+                                       e = ERR_get_error();
+                               }
+                               errno = EPROTO;
+                       }
+               }
+               return (ssize_t )ret;
+       }else{
+               /* Call normal read/recv */
+
+#endif
+#ifdef WITH_MBEDTLS
+       int ret;
+       if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->ssl_ctx) {
+               ret = mbedtls_ssl_read(mosq->ssl_ctx, buf, count);
+               if(ret < 0) {
+                       if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
+                               ret = -1;
+                               errno = EAGAIN;
+                       }
+                       else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+                               ret = -1;
+                               mosq->want_write = true;
+                               errno = EAGAIN;
+                       }
+                       else {
+                               _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "mbedtls Read Error %d", ret);
+                       }
+               } else if (ret == 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_INFO, "finish Read");
+               }
+               return (ssize_t )ret;
+       } else {
+               /* Call normal write/send */
+#endif
+
+
+#ifndef WIN32
+       return read(mosq->sock, buf, count);
+#else
+       return recv(mosq->sock, buf, count, 0);
+#endif
+
+#ifdef WITH_MBEDTLS
+       }
+#endif
+#ifdef WITH_TLS
+       }
+#endif
+}
+
+ssize_t _mosquitto_net_write(struct mosquitto *mosq, void *buf, size_t count)
+{
+#ifdef WITH_TLS
+       int ret;
+       int err;
+       char ebuf[256];
+       unsigned long e;
+#endif
+       assert(mosq);
+
+       errno = 0;
+#ifdef WITH_TLS
+       if(mosq->ssl){
+               mosq->want_write = false;
+               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{
+                               e = ERR_get_error();
+                               while(e){
+                                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error: %s", ERR_error_string(e, ebuf));
+                                       e = ERR_get_error();
+                               }
+                               errno = EPROTO;
+                       }
+               }
+               return (ssize_t )ret;
+       }else{
+               /* Call normal write/send */
+#endif
+#ifdef WITH_MBEDTLS
+       int ret;
+       if((mosq->mbedtls_state == mosq_mbedtls_state_enabled) && mosq->ssl_ctx) {
+               ret = mbedtls_ssl_write(mosq->ssl_ctx, buf, count);
+               if(ret < 0) {
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "mbedtls Write Error");
+               }
+               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_MBEDTLS
+       }
+#endif
+#ifdef WITH_TLS
+       }
+#endif
+}
+
+int _mosquitto_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(mosq->state == mosq_cs_connect_pending){
+               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 = _mosquitto_net_write(mosq, &(packet->payload[packet->pos]), packet->to_process);
+                       if(write_length > 0){
+#if defined(WITH_BROKER) && defined(WITH_SYS_TREE)
+                               g_bytes_sent += write_length;
+#endif
+                               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;
+                                       }
+                               }
+                       }
+               }
+
+#ifdef WITH_BROKER
+#  ifdef WITH_SYS_TREE
+               g_msgs_sent++;
+               if(((packet->command)&0xF6) == PUBLISH){
+                       g_pub_msgs_sent++;
+               }
+#  endif
+#else
+               if(((packet->command)&0xF6) == PUBLISH){
+                       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;
+                       }
+                       pthread_mutex_unlock(&mosq->callback_mutex);
+               }else if(((packet->command)&0xF0) == DISCONNECT){
+                       /* FIXME what cleanup needs doing here?
+                        * incoming/outgoing messages? */
+                       _mosquitto_socket_close(mosq);
+
+                       /* Start of duplicate, possibly unnecessary code.
+                        * This does leave things in a consistent state at least. */
+                       /* 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);
+
+                       _mosquitto_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);
+                       /* End of duplicate, possibly unnecessary code */
+
+                       pthread_mutex_lock(&mosq->callback_mutex);
+                       if(mosq->on_disconnect){
+                               mosq->in_callback = true;
+                               mosq->on_disconnect(mosq, mosq->userdata, 0);
+                               mosq->in_callback = false;
+                       }
+                       pthread_mutex_unlock(&mosq->callback_mutex);
+                       pthread_mutex_unlock(&mosq->current_out_packet_mutex);
+                       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);
+
+               _mosquitto_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 _mosquitto_packet_read(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+int _mosquitto_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 = _mosquitto_net_read(mosq, &byte, 1);
+               if(read_length == 1){
+                       mosq->in_packet.command = byte;
+#ifdef WITH_BROKER
+#  ifdef WITH_SYS_TREE
+                       g_bytes_received++;
+#  endif
+                       /* Clients must send CONNECT as their first command. */
+                       if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != 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 = _mosquitto_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;
+
+#if defined(WITH_BROKER) && defined(WITH_SYS_TREE)
+                               g_bytes_received++;
+#endif
+                               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;
+
+               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 = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
+               if(read_length > 0){
+#if defined(WITH_BROKER) && defined(WITH_SYS_TREE)
+                       g_bytes_received += read_length;
+#endif
+                       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
+#  ifdef WITH_SYS_TREE
+       g_msgs_received++;
+       if(((mosq->in_packet.command)&0xF5) == PUBLISH){
+               g_pub_msgs_received++;
+       }
+#  endif
+       rc = mqtt3_packet_handle(db, mosq);
+#else
+       rc = _mosquitto_packet_handle(mosq);
+#endif
+
+       /* Free data and reset values */
+       _mosquitto_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;
+}
+
+int _mosquitto_socket_nonblock(mosq_sock_t sock)
+{
+#ifndef WIN32
+       int opt;
+
+#if defined(__TINYARA__)
+       if(sock == INVALID_SOCKET)
+       {
+               return 1;
+       }
+#endif
+
+       /* Set non-blocking */
+       opt = fcntl(sock, F_GETFL, 0);
+       if(opt == -1){
+#if ! defined(__TINYARA__) /* caller will close sock */
+               COMPAT_CLOSE(sock);
+#endif
+               return 1;
+       }
+       if(fcntl(sock, F_SETFL, opt | O_NONBLOCK) == -1){
+               /* If either fcntl fails, don't want to allow this client to connect. */
+#if ! defined(__TINYARA__) /* caller will close sock */
+               COMPAT_CLOSE(sock);
+#endif
+               return 1;
+       }
+#else
+       unsigned long opt = 1;
+       if(ioctlsocket(sock, FIONBIO, &opt)){
+#if ! defined(__TINYARA__) /* caller will close sock */
+               COMPAT_CLOSE(sock);
+#endif
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+
+#ifndef WITH_BROKER
+int _mosquitto_socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
+{
+#if defined(WIN32) || defined(__TINYARA__)
+       int family[2] = {AF_INET, AF_INET6};
+       int i;
+       struct sockaddr_storage ss;
+       struct sockaddr_in *sa = (struct sockaddr_in *)&ss;
+#if ! defined(__TINYARA__)
+       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&ss;
+#endif
+       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);
+               }
+#if ! defined(__TINYARA__)
+               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);
+               }
+#endif
+               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);
+               }
+#if ! defined(__TINYARA__)
+               else if(family[i] == AF_INET6){
+                       sa6->sin6_family = family[i];
+                       sa6->sin6_addr = in6addr_loopback;
+                       ss_len = sizeof(struct sockaddr_in6);
+               }
+#endif
+
+               spR = socket(family[i], SOCK_STREAM, IPPROTO_TCP);
+               if(spR == -1){
+                       COMPAT_CLOSE(listensock);
+                       continue;
+               }
+               if(_mosquitto_socket_nonblock(spR)){
+                       COMPAT_CLOSE(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 ! defined(__TINYARA__)
+                       if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK)
+#endif
+                       {
+
+                               COMPAT_CLOSE(spR);
+                               COMPAT_CLOSE(listensock);
+                               continue;
+                       }
+               }
+
+               if(_mosquitto_socket_nonblock(spW)){
+                       COMPAT_CLOSE(spR);
+                       COMPAT_CLOSE(spW);
+                       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(_mosquitto_socket_nonblock(sv[0])){
+               COMPAT_CLOSE(sv[0]);
+               COMPAT_CLOSE(sv[1]);
+               return MOSQ_ERR_ERRNO;
+       }
+       if(_mosquitto_socket_nonblock(sv[1])){
+               COMPAT_CLOSE(sv[0]);
+               COMPAT_CLOSE(sv[1]);
+               return MOSQ_ERR_ERRNO;
+       }
+       *pairR = sv[0];
+       *pairW = sv[1];
+       return MOSQ_ERR_SUCCESS;
+#endif
+}
+#endif
diff --git a/apps/netutils/mqtt/lib/net_mosq.h b/apps/netutils/mqtt/lib/net_mosq.h
new file mode 100644 (file)
index 0000000..526fc3e
--- /dev/null
@@ -0,0 +1,113 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 int 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)
+
+void _mosquitto_net_init(void);
+void _mosquitto_net_cleanup(void);
+
+void _mosquitto_packet_cleanup(struct _mosquitto_packet *packet);
+int _mosquitto_packet_queue(struct mosquitto *mosq, struct _mosquitto_packet *packet);
+int _mosquitto_socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking);
+#ifdef WITH_BROKER
+int _mosquitto_socket_close(struct mosquitto_db *db, struct mosquitto *mosq);
+#else
+int _mosquitto_socket_close(struct mosquitto *mosq);
+#endif
+int _mosquitto_try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking);
+int _mosquitto_socket_nonblock(mosq_sock_t sock);
+int _mosquitto_socketpair(mosq_sock_t *sp1, mosq_sock_t *sp2);
+
+int _mosquitto_read_byte(struct _mosquitto_packet *packet, uint8_t *byte);
+int _mosquitto_read_bytes(struct _mosquitto_packet *packet, void *bytes, uint32_t count);
+int _mosquitto_read_string(struct _mosquitto_packet *packet, char **str);
+int _mosquitto_read_uint16(struct _mosquitto_packet *packet, uint16_t *word);
+
+void _mosquitto_write_byte(struct _mosquitto_packet *packet, uint8_t byte);
+void _mosquitto_write_bytes(struct _mosquitto_packet *packet, const void *bytes, uint32_t count);
+void _mosquitto_write_string(struct _mosquitto_packet *packet, const char *str, uint16_t length);
+void _mosquitto_write_uint16(struct _mosquitto_packet *packet, uint16_t word);
+
+ssize_t _mosquitto_net_read(struct mosquitto *mosq, void *buf, size_t count);
+ssize_t _mosquitto_net_write(struct mosquitto *mosq, void *buf, size_t count);
+
+int _mosquitto_packet_write(struct mosquitto *mosq);
+#ifdef WITH_BROKER
+int _mosquitto_packet_read(struct mosquitto_db *db, struct mosquitto *mosq);
+#else
+int _mosquitto_packet_read(struct mosquitto *mosq);
+#endif
+
+#ifdef WITH_TLS
+int _mosquitto_socket_apply_tls(struct mosquitto *mosq);
+int mosquitto__socket_connect_tls(struct mosquitto *mosq);
+#endif
+
+#ifdef WITH_MBEDTLS
+int mosquitto__socket_connect_tls(struct mosquitto *mosq);
+#endif
+
+#endif
diff --git a/apps/netutils/mqtt/lib/read_handle.c b/apps/netutils/mqtt/lib/read_handle.c
new file mode 100644 (file)
index 0000000..ebdac2a
--- /dev/null
@@ -0,0 +1,172 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <mosquitto.h>
+#include <logging_mosq.h>
+#include <memory_mosq.h>
+#include <messages_mosq.h>
+#include <mqtt3_protocol.h>
+#include <net_mosq.h>
+#include <read_handle.h>
+#include <send_mosq.h>
+#include <time_mosq.h>
+#include <util_mosq.h>
+
+int _mosquitto_packet_handle(struct mosquitto *mosq)
+{
+       assert(mosq);
+
+       switch((mosq->in_packet.command)&0xF0){
+               case PINGREQ:
+                       return _mosquitto_handle_pingreq(mosq);
+               case PINGRESP:
+                       return _mosquitto_handle_pingresp(mosq);
+               case PUBACK:
+                       return _mosquitto_handle_pubackcomp(mosq, "PUBACK");
+               case PUBCOMP:
+                       return _mosquitto_handle_pubackcomp(mosq, "PUBCOMP");
+               case PUBLISH:
+                       return _mosquitto_handle_publish(mosq);
+               case PUBREC:
+                       return _mosquitto_handle_pubrec(mosq);
+               case PUBREL:
+                       return _mosquitto_handle_pubrel(NULL, mosq);
+               case CONNACK:
+                       return _mosquitto_handle_connack(mosq);
+               case SUBACK:
+                       return _mosquitto_handle_suback(mosq);
+               case UNSUBACK:
+                       return _mosquitto_handle_unsuback(mosq);
+               default:
+                       /* If we don't recognise the command, return an error straight away. */
+                       _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unrecognised command %d\n", (mosq->in_packet.command)&0xF0);
+                       return MOSQ_ERR_PROTOCOL;
+       }
+}
+
+int _mosquitto_handle_publish(struct mosquitto *mosq)
+{
+       uint8_t header;
+       struct mosquitto_message_all *message;
+       int rc = 0;
+       uint16_t mid;
+
+       assert(mosq);
+
+       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 = _mosquitto_read_string(&mosq->in_packet, &message->msg.topic);
+       if(rc){
+               _mosquitto_message_cleanup(&message);
+               return rc;
+       }
+       if(!strlen(message->msg.topic)){
+               _mosquitto_message_cleanup(&message);
+               return MOSQ_ERR_PROTOCOL;
+       }
+
+       if(message->msg.qos > 0){
+               rc = _mosquitto_read_uint16(&mosq->in_packet, &mid);
+               if(rc){
+                       _mosquitto_message_cleanup(&message);
+                       return rc;
+               }
+               message->msg.mid = (int)mid;
+       }
+
+       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){
+                       _mosquitto_message_cleanup(&message);
+                       return MOSQ_ERR_NOMEM;
+               }
+               rc = _mosquitto_read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen);
+               if(rc){
+                       _mosquitto_message_cleanup(&message);
+                       return rc;
+               }
+       }
+       _mosquitto_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;
+                       }
+                       pthread_mutex_unlock(&mosq->callback_mutex);
+                       _mosquitto_message_cleanup(&message);
+                       return MOSQ_ERR_SUCCESS;
+               case 1:
+                       rc = _mosquitto_send_puback(mosq, message->msg.mid);
+                       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;
+                       }
+                       pthread_mutex_unlock(&mosq->callback_mutex);
+                       _mosquitto_message_cleanup(&message);
+                       return rc;
+               case 2:
+                       rc = _mosquitto_send_pubrec(mosq, message->msg.mid);
+                       pthread_mutex_lock(&mosq->in_message_mutex);
+                       message->state = mosq_ms_wait_for_pubrel;
+                       _mosquitto_message_queue(mosq, message, mosq_md_in);
+                       pthread_mutex_unlock(&mosq->in_message_mutex);
+                       return rc;
+               default:
+                       _mosquitto_message_cleanup(&message);
+                       return MOSQ_ERR_PROTOCOL;
+       }
+}
+
diff --git a/apps/netutils/mqtt/lib/read_handle.h b/apps/netutils/mqtt/lib/read_handle.h
new file mode 100644 (file)
index 0000000..ed1808a
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 _mosquitto_packet_handle(struct mosquitto *mosq);
+int _mosquitto_handle_connack(struct mosquitto *mosq);
+int _mosquitto_handle_pingreq(struct mosquitto *mosq);
+int _mosquitto_handle_pingresp(struct mosquitto *mosq);
+#ifdef WITH_BROKER
+int _mosquitto_handle_pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type);
+#else
+int _mosquitto_handle_pubackcomp(struct mosquitto *mosq, const char *type);
+#endif
+int _mosquitto_handle_publish(struct mosquitto *mosq);
+int _mosquitto_handle_pubrec(struct mosquitto *mosq);
+int _mosquitto_handle_pubrel(struct mosquitto_db *db, struct mosquitto *mosq);
+int _mosquitto_handle_suback(struct mosquitto *mosq);
+int _mosquitto_handle_unsuback(struct mosquitto *mosq);
+
+
+#endif
diff --git a/apps/netutils/mqtt/lib/read_handle_client.c b/apps/netutils/mqtt/lib/read_handle_client.c
new file mode 100644 (file)
index 0000000..6d3e218
--- /dev/null
@@ -0,0 +1,77 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+
+#include <mosquitto.h>
+#include <logging_mosq.h>
+#include <memory_mosq.h>
+#include <net_mosq.h>
+#include <read_handle.h>
+
+int _mosquitto_handle_connack(struct mosquitto *mosq)
+{
+       uint8_t byte;
+       uint8_t result;
+       int rc;
+
+       assert(mosq);
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK", mosq->id);
+       rc = _mosquitto_read_byte(&mosq->in_packet, &byte); // Reserved byte, not used
+       if(rc) return rc;
+       rc = _mosquitto_read_byte(&mosq->in_packet, &result);
+       if(rc) return rc;
+       pthread_mutex_lock(&mosq->callback_mutex);
+       if(mosq->on_connect){
+               mosq->in_callback = true;
+               mosq->on_connect(mosq, mosq->userdata, result);
+               mosq->in_callback = false;
+       }
+       pthread_mutex_unlock(&mosq->callback_mutex);
+       switch(result){
+               case 0:
+                       if(mosq->state != mosq_cs_disconnecting){
+                               mosq->state = mosq_cs_connected;
+                       }
+                       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/apps/netutils/mqtt/lib/read_handle_shared.c b/apps/netutils/mqtt/lib/read_handle_shared.c
new file mode 100644 (file)
index 0000000..c555fd9
--- /dev/null
@@ -0,0 +1,259 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <mosquitto.h>
+#include <logging_mosq.h>
+#include <memory_mosq.h>
+#include <messages_mosq.h>
+#include <mqtt3_protocol.h>
+#include <net_mosq.h>
+#include <read_handle.h>
+#include <send_mosq.h>
+#include <util_mosq.h>
+#ifdef WITH_BROKER
+#include <mosquitto_broker.h>
+#endif
+
+int _mosquitto_handle_pingreq(struct mosquitto *mosq)
+{
+       assert(mosq);
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PINGREQ from %s", mosq->id);
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGREQ", mosq->id);
+#endif
+       return _mosquitto_send_pingresp(mosq);
+}
+
+int _mosquitto_handle_pingresp(struct mosquitto *mosq)
+{
+       assert(mosq);
+       mosq->ping_t = 0; /* No longer waiting for a PINGRESP. */
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PINGRESP from %s", mosq->id);
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGRESP", mosq->id);
+#endif
+       return MOSQ_ERR_SUCCESS;
+}
+
+#ifdef WITH_BROKER
+int _mosquitto_handle_pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type)
+#else
+int _mosquitto_handle_pubackcomp(struct mosquitto *mosq, const char *type)
+#endif
+{
+       uint16_t mid;
+       int rc;
+
+       assert(mosq);
+       rc = _mosquitto_read_uint16(&mosq->in_packet, &mid);
+       if(rc) return rc;
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d)", type, mosq->id, mid);
+
+       if(mid){
+               rc = mqtt3_db_message_delete(db, mosq, mid, mosq_md_out);
+               if(rc == MOSQ_ERR_NOT_FOUND){
+                       _mosquitto_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
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d)", mosq->id, type, mid);
+
+       if(!_mosquitto_message_delete(mosq, mid, mosq_md_out)){
+               /* 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;
+               }
+               pthread_mutex_unlock(&mosq->callback_mutex);
+       }
+#endif
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+int _mosquitto_handle_pubrec(struct mosquitto *mosq)
+{
+       uint16_t mid;
+       int rc;
+
+       assert(mosq);
+       rc = _mosquitto_read_uint16(&mosq->in_packet, &mid);
+       if(rc) return rc;
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid);
+
+       rc = mqtt3_db_message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp);
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid);
+
+       rc = _mosquitto_message_out_update(mosq, mid, mosq_ms_wait_for_pubcomp);
+#endif
+       if(rc == MOSQ_ERR_NOT_FOUND){
+               _mosquitto_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 = _mosquitto_send_pubrel(mosq, mid);
+       if(rc) return rc;
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+int _mosquitto_handle_pubrel(struct mosquitto_db *db, struct mosquitto *mosq)
+{
+       uint16_t mid;
+#ifndef WITH_BROKER
+       struct mosquitto_message_all *message = NULL;
+#endif
+       int rc;
+
+       assert(mosq);
+       if(mosq->protocol == mosq_p_mqtt311){
+               if((mosq->in_packet.command&0x0F) != 0x02){
+                       return MOSQ_ERR_PROTOCOL;
+               }
+       }
+       rc = _mosquitto_read_uint16(&mosq->in_packet, &mid);
+       if(rc) return rc;
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid);
+
+       if(mqtt3_db_message_release(db, mosq, mid, mosq_md_in)){
+               /* Message not found. Still send a PUBCOMP anyway because this could be
+                * due to a repeated PUBREL after a client has reconnected. */
+               _mosquitto_log_printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREL from %s for an unknown packet identifier %d.", mosq->id, mid);
+       }
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid);
+
+       if(!_mosquitto_message_remove(mosq, mid, mosq_md_in, &message)){
+               /* 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;
+               }
+               pthread_mutex_unlock(&mosq->callback_mutex);
+               _mosquitto_message_cleanup(&message);
+       }
+#endif
+       rc = _mosquitto_send_pubcomp(mosq, mid);
+       if(rc) return rc;
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+int _mosquitto_handle_suback(struct mosquitto *mosq)
+{
+       uint16_t mid;
+       uint8_t qos;
+       int *granted_qos;
+       int qos_count;
+       int i = 0;
+       int rc;
+
+       assert(mosq);
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id);
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK", mosq->id);
+#endif
+       rc = _mosquitto_read_uint16(&mosq->in_packet, &mid);
+       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 = _mosquitto_read_byte(&mosq->in_packet, &qos);
+               if(rc){
+                       _mosquitto_free(granted_qos);
+                       return rc;
+               }
+               granted_qos[i] = (int)qos;
+               i++;
+       }
+#ifndef WITH_BROKER
+       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;
+       }
+       pthread_mutex_unlock(&mosq->callback_mutex);
+#endif
+       _mosquitto_free(granted_qos);
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+int _mosquitto_handle_unsuback(struct mosquitto *mosq)
+{
+       uint16_t mid;
+       int rc;
+
+       assert(mosq);
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBACK from %s", mosq->id);
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received UNSUBACK", mosq->id);
+#endif
+       rc = _mosquitto_read_uint16(&mosq->in_packet, &mid);
+       if(rc) return rc;
+#ifndef WITH_BROKER
+       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;
+       }
+       pthread_mutex_unlock(&mosq->callback_mutex);
+#endif
+
+       return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/apps/netutils/mqtt/lib/send_client_mosq.c b/apps/netutils/mqtt/lib/send_client_mosq.c
new file mode 100644 (file)
index 0000000..ef9692d
--- /dev/null
@@ -0,0 +1,263 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <string.h>
+
+#include <mosquitto.h>
+#include <logging_mosq.h>
+#include <memory_mosq.h>
+#include <mqtt3_protocol.h>
+#include <net_mosq.h>
+#include <send_mosq.h>
+#include <util_mosq.h>
+
+#ifdef WITH_BROKER
+#include <mosquitto_broker.h>
+#endif
+
+int _mosquitto_send_connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session)
+{
+       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;
+
+       assert(mosq);
+       assert(mosq->id);
+
+#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_mqtt31){
+               version = MQTT_PROTOCOL_V31;
+               headerlen = 12;
+       }else if(mosq->protocol == mosq_p_mqtt311){
+               version = MQTT_PROTOCOL_V311;
+               headerlen = 10;
+       }else{
+               return MOSQ_ERR_INVAL;
+       }
+
+       packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet));
+       if(!packet) return MOSQ_ERR_NOMEM;
+
+       payloadlen = 2+strlen(clientid);
+       if(mosq->will){
+               will = 1;
+               assert(mosq->will->topic);
+
+               payloadlen += 2+strlen(mosq->will->topic) + 2+mosq->will->payloadlen;
+       }
+       if(username){
+               payloadlen += 2+strlen(username);
+               if(password){
+                       payloadlen += 2+strlen(password);
+               }
+       }
+
+       packet->command = CONNECT;
+       packet->remaining_length = headerlen+payloadlen;
+       rc = _mosquitto_packet_alloc(packet);
+       if(rc){
+               _mosquitto_free(packet);
+               return rc;
+       }
+
+       /* Variable header */
+       if(version == MQTT_PROTOCOL_V31){
+               _mosquitto_write_string(packet, PROTOCOL_NAME_v31, strlen(PROTOCOL_NAME_v31));
+       }else if(version == MQTT_PROTOCOL_V311){
+               _mosquitto_write_string(packet, PROTOCOL_NAME_v311, strlen(PROTOCOL_NAME_v311));
+       }
+#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
+       if(mosq->bridge && mosq->bridge->try_private && mosq->bridge->try_private_accepted){
+               version |= 0x80;
+       }else{
+       }
+#endif
+       _mosquitto_write_byte(packet, version);
+       byte = (clean_session&0x1)<<1;
+       if(will){
+               byte = byte | ((mosq->will->retain&0x1)<<5) | ((mosq->will->qos&0x3)<<3) | ((will&0x1)<<2);
+       }
+       if(username){
+               byte = byte | 0x1<<7;
+               if(mosq->password){
+                       byte = byte | 0x1<<6;
+               }
+       }
+       _mosquitto_write_byte(packet, byte);
+       _mosquitto_write_uint16(packet, keepalive);
+
+       /* Payload */
+       _mosquitto_write_string(packet, clientid, strlen(clientid));
+       if(will){
+               _mosquitto_write_string(packet, mosq->will->topic, strlen(mosq->will->topic));
+               _mosquitto_write_string(packet, (const char *)mosq->will->payload, mosq->will->payloadlen);
+       }
+       if(username){
+               _mosquitto_write_string(packet, username, strlen(username));
+               if(password){
+                       _mosquitto_write_string(packet, password, strlen(password));
+               }
+       }
+
+       mosq->keepalive = keepalive;
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending CONNECT", clientid);
+# endif
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending CONNECT", clientid);
+#endif
+       return _mosquitto_packet_queue(mosq, packet);
+}
+
+int _mosquitto_send_disconnect(struct mosquitto *mosq)
+{
+       assert(mosq);
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending DISCONNECT", mosq->id);
+# endif
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending DISCONNECT", mosq->id);
+#endif
+       return _mosquitto_send_simple_command(mosq, DISCONNECT);
+}
+
+int _mosquitto_send_subscribe(struct mosquitto *mosq, int *mid, const char *topic, uint8_t topic_qos)
+{
+       /* FIXME - only deals with a single topic */
+       struct _mosquitto_packet *packet = NULL;
+       uint32_t packetlen;
+       uint16_t local_mid;
+       int rc;
+
+       assert(mosq);
+       assert(topic);
+
+       packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet));
+       if(!packet) return MOSQ_ERR_NOMEM;
+
+       packetlen = 2 + 2+strlen(topic) + 1;
+
+       packet->command = SUBSCRIBE | (1<<1);
+       packet->remaining_length = packetlen;
+       rc = _mosquitto_packet_alloc(packet);
+       if(rc){
+               _mosquitto_free(packet);
+               return rc;
+       }
+
+       /* Variable header */
+       local_mid = _mosquitto_mid_generate(mosq);
+       if(mid) *mid = (int)local_mid;
+       _mosquitto_write_uint16(packet, local_mid);
+
+       /* Payload */
+       _mosquitto_write_string(packet, topic, strlen(topic));
+       _mosquitto_write_byte(packet, topic_qos);
+
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic, topic_qos);
+# endif
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic, topic_qos);
+#endif
+
+       return _mosquitto_packet_queue(mosq, packet);
+}
+
+
+int _mosquitto_send_unsubscribe(struct mosquitto *mosq, int *mid, const char *topic)
+{
+       /* FIXME - only deals with a single topic */
+       struct _mosquitto_packet *packet = NULL;
+       uint32_t packetlen;
+       uint16_t local_mid;
+       int rc;
+
+       assert(mosq);
+       assert(topic);
+
+       packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet));
+       if(!packet) return MOSQ_ERR_NOMEM;
+
+       packetlen = 2 + 2+strlen(topic);
+
+       packet->command = UNSUBSCRIBE | (1<<1);
+       packet->remaining_length = packetlen;
+       rc = _mosquitto_packet_alloc(packet);
+       if(rc){
+               _mosquitto_free(packet);
+               return rc;
+       }
+
+       /* Variable header */
+       local_mid = _mosquitto_mid_generate(mosq);
+       if(mid) *mid = (int)local_mid;
+       _mosquitto_write_uint16(packet, local_mid);
+
+       /* Payload */
+       _mosquitto_write_string(packet, topic, strlen(topic));
+
+#ifdef WITH_BROKER
+# ifdef WITH_BRIDGE
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic);
+# endif
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic);
+#endif
+       return _mosquitto_packet_queue(mosq, packet);
+}
+
diff --git a/apps/netutils/mqtt/lib/send_mosq.c b/apps/netutils/mqtt/lib/send_mosq.c
new file mode 100644 (file)
index 0000000..3c002c1
--- /dev/null
@@ -0,0 +1,299 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WITH_BROKER
+#include <mosquitto_broker.h>
+#  ifdef WITH_SYS_TREE
+extern uint64_t g_pub_bytes_sent;
+#  endif
+#endif
+
+#include <mosquitto.h>
+#include <mosquitto_internal.h>
+#include <logging_mosq.h>
+#include <mqtt3_protocol.h>
+#include <memory_mosq.h>
+#include <net_mosq.h>
+#include <send_mosq.h>
+#include <time_mosq.h>
+#include <util_mosq.h>
+
+int _mosquitto_send_pingreq(struct mosquitto *mosq)
+{
+       int rc;
+       assert(mosq);
+#ifdef WITH_BROKER
+       _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGREQ to %s", mosq->id);
+#else
+       _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGREQ", mosq->id);
+#endif
+       rc = _mosquitto_send_simple_command(mosq, PINGREQ);
+       if(rc == MOSQ_ERR_SUCCESS){
+               mosq->ping_t = mosquitto_time();
+       }
+       return rc;
+}
+
+int _mosquitto_send_pingresp(struct mosquitto *mosq)
+{
+#ifdef WITH_BROKER
+       if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGRESP to %s", mosq->id);
+#else
+       if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGRESP", mosq->id);
+#endif
+       return _mosquitto_send_simple_command(mosq, PINGRESP);
+}
+
+int _mosquitto_send_puback(struct mosquitto *mosq, uint16_t mid)
+{
+#ifdef WITH_BROKER
+       if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBACK to %s (Mid: %d)", mosq->id, mid);
+#else
+       if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid);
+#endif
+       return _mosquitto_send_command_with_mid(mosq, PUBACK, mid, false);
+}
+
+int _mosquitto_send_pubcomp(struct mosquitto *mosq, uint16_t mid)
+{
+#ifdef WITH_BROKER
+       if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBCOMP to %s (Mid: %d)", mosq->id, mid);
+#else
+       if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid);
+#endif
+       return _mosquitto_send_command_with_mid(mosq, PUBCOMP, mid, false);
+}
+
+int _mosquitto_send_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup)
+{
+#ifdef WITH_BROKER
+       size_t len;
+#ifdef WITH_BRIDGE
+       int i;
+       struct _mqtt3_bridge_topic *cur_topic;
+       bool match;
+       int rc;
+       char *mapped_topic = NULL;
+       char *topic_temp = NULL;
+#endif
+#endif
+       assert(mosq);
+       assert(topic);
+
+#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;
+                                       }
+                                       _mosquitto_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);
+#ifdef WITH_SYS_TREE
+                                       g_pub_bytes_sent += payloadlen;
+#endif
+                                       rc =  _mosquitto_send_real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup);
+                                       _mosquitto_free(mapped_topic);
+                                       return rc;
+                               }
+                       }
+               }
+       }
+#endif
+       _mosquitto_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);
+#  ifdef WITH_SYS_TREE
+       g_pub_bytes_sent += payloadlen;
+#  endif
+#else
+       _mosquitto_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 _mosquitto_send_real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup);
+}
+
+int _mosquitto_send_pubrec(struct mosquitto *mosq, uint16_t mid)
+{
+#ifdef WITH_BROKER
+       if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREC to %s (Mid: %d)", mosq->id, mid);
+#else
+       if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid);
+#endif
+       return _mosquitto_send_command_with_mid(mosq, PUBREC, mid, false);
+}
+
+int _mosquitto_send_pubrel(struct mosquitto *mosq, uint16_t mid)
+{
+#ifdef WITH_BROKER
+       if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREL to %s (Mid: %d)", mosq->id, mid);
+#else
+       if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (Mid: %d)", mosq->id, mid);
+#endif
+       return _mosquitto_send_command_with_mid(mosq, PUBREL|2, mid, false);
+}
+
+/* For PUBACK, PUBCOMP, PUBREC, and PUBREL */
+int _mosquitto_send_command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup)
+{
+       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;
+       if(dup){
+               packet->command |= 8;
+       }
+       packet->remaining_length = 2;
+       rc = _mosquitto_packet_alloc(packet);
+       if(rc){
+               _mosquitto_free(packet);
+               return rc;
+       }
+
+       packet->payload[packet->pos+0] = MOSQ_MSB(mid);
+       packet->payload[packet->pos+1] = MOSQ_LSB(mid);
+
+       return _mosquitto_packet_queue(mosq, packet);
+}
+
+/* For DISCONNECT, PINGREQ and PINGRESP */
+int _mosquitto_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 = _mosquitto_packet_alloc(packet);
+       if(rc){
+               _mosquitto_free(packet);
+               return rc;
+       }
+
+       return _mosquitto_packet_queue(mosq, packet);
+}
+
+int _mosquitto_send_real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup)
+{
+       struct _mosquitto_packet *packet = NULL;
+       int packetlen;
+       int rc;
+
+       assert(mosq);
+       assert(topic);
+
+       packetlen = 2+strlen(topic) + payloadlen;
+       if(qos > 0) packetlen += 2; /* For message id */
+       packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet));
+       if(!packet) return MOSQ_ERR_NOMEM;
+
+       packet->mid = mid;
+       packet->command = PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain;
+       packet->remaining_length = packetlen;
+       rc = _mosquitto_packet_alloc(packet);
+       if(rc){
+               _mosquitto_free(packet);
+               return rc;
+       }
+       /* Variable header (topic string) */
+       _mosquitto_write_string(packet, topic, strlen(topic));
+       if(qos > 0){
+               _mosquitto_write_uint16(packet, mid);
+       }
+
+       /* Payload */
+       if(payloadlen){
+               _mosquitto_write_bytes(packet, payload, payloadlen);
+       }
+
+       return _mosquitto_packet_queue(mosq, packet);
+}
diff --git a/apps/netutils/mqtt/lib/send_mosq.h b/apps/netutils/mqtt/lib/send_mosq.h
new file mode 100644 (file)
index 0000000..d1d7cb9
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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>
+
+int _mosquitto_send_simple_command(struct mosquitto *mosq, uint8_t command);
+int _mosquitto_send_command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup);
+int _mosquitto_send_real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup);
+
+int _mosquitto_send_connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session);
+int _mosquitto_send_disconnect(struct mosquitto *mosq);
+int _mosquitto_send_pingreq(struct mosquitto *mosq);
+int _mosquitto_send_pingresp(struct mosquitto *mosq);
+int _mosquitto_send_puback(struct mosquitto *mosq, uint16_t mid);
+int _mosquitto_send_pubcomp(struct mosquitto *mosq, uint16_t mid);
+int _mosquitto_send_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup);
+int _mosquitto_send_pubrec(struct mosquitto *mosq, uint16_t mid);
+int _mosquitto_send_pubrel(struct mosquitto *mosq, uint16_t mid);
+int _mosquitto_send_subscribe(struct mosquitto *mosq, int *mid, const char *topic, uint8_t topic_qos);
+int _mosquitto_send_unsubscribe(struct mosquitto *mosq, int *mid, const char *topic);
+
+#endif
diff --git a/apps/netutils/mqtt/lib/socks_mosq.c b/apps/netutils/mqtt/lib/socks_mosq.c
new file mode 100644 (file)
index 0000000..e98935a
--- /dev/null
@@ -0,0 +1,413 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2014 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 <errno.h>
+#include <string.h>
+
+#include "mosquitto_internal.h"
+#include "memory_mosq.h"
+#include "net_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;
+
+       if(mosq->socks5_host){
+               _mosquitto_free(mosq->socks5_host);
+       }
+
+       mosq->socks5_host = _mosquitto_strdup(host);
+       if(!mosq->socks5_host){
+               return MOSQ_ERR_NOMEM;
+       }
+
+       mosq->socks5_port = port;
+
+       if(mosq->socks5_username){
+               _mosquitto_free(mosq->socks5_username);
+       }
+       if(mosq->socks5_password){
+               _mosquitto_free(mosq->socks5_password);
+       }
+
+       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 mosquitto__socks5_send(struct mosquitto *mosq)
+{
+       struct _mosquitto_packet *packet;
+       int slen;
+       int ulen, plen;
+
+       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 _mosquitto_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;
+
+               packet->packet_length = 7+strlen(mosq->host);
+               packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length);
+
+               slen = strlen(mosq->host);
+
+               packet->payload[0] = 0x05;
+               packet->payload[1] = 1;
+               packet->payload[2] = 0;
+               packet->payload[3] = SOCKS_ATYPE_DOMAINNAME;
+               packet->payload[4] = slen;
+               memcpy(&(packet->payload[5]), mosq->host, slen);
+               packet->payload[5+slen] = MOSQ_MSB(mosq->port);
+               packet->payload[6+slen] = MOSQ_LSB(mosq->port);
+
+               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 _mosquitto_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 _mosquitto_packet_queue(mosq, packet);
+       }
+       return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto__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 = _mosquitto_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{
+                                       _mosquitto_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){
+                       _mosquitto_packet_cleanup(&mosq->in_packet);
+                       return MOSQ_ERR_PROXY;
+               }
+               switch(mosq->in_packet.payload[1]){
+                       case SOCKS_AUTH_NONE:
+                               _mosquitto_packet_cleanup(&mosq->in_packet);
+                               mosq->state = mosq_cs_socks5_auth_ok;
+                               return mosquitto__socks5_send(mosq);
+                       case SOCKS_AUTH_USERPASS:
+                               _mosquitto_packet_cleanup(&mosq->in_packet);
+                               mosq->state = mosq_cs_socks5_send_userpass;
+                               return mosquitto__socks5_send(mosq);
+                       default:
+                               _mosquitto_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 = _mosquitto_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{
+                                       _mosquitto_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){
+                       _mosquitto_packet_cleanup(&mosq->in_packet);
+                       return MOSQ_ERR_PROXY;
+               }
+               if(mosq->in_packet.payload[1] == 0){
+                       _mosquitto_packet_cleanup(&mosq->in_packet);
+                       mosq->state = mosq_cs_socks5_auth_ok;
+                       return mosquitto__socks5_send(mosq);
+               }else{
+                       i = mosq->in_packet.payload[1];
+                       _mosquitto_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 = _mosquitto_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{
+                                       _mosquitto_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.payload[4] <= 255){
+                                       mosq->in_packet.to_process += mosq->in_packet.payload[4];
+                                       mosq->in_packet.packet_length += mosq->in_packet.payload[4];
+                               }
+                       }else{
+                               _mosquitto_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{
+                               _mosquitto_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){
+                       _mosquitto_packet_cleanup(&mosq->in_packet);
+                       return MOSQ_ERR_PROXY;
+               }
+               if(mosq->in_packet.payload[1] == 0){
+                       /* Auth passed */
+                       _mosquitto_packet_cleanup(&mosq->in_packet);
+                       mosq->state = mosq_cs_new;
+                       return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session);
+               }else{
+                       i = mosq->in_packet.payload[1];
+                       _mosquitto_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 _mosquitto_packet_read(mosq);
+       }
+       return MOSQ_ERR_SUCCESS;
+}
+#endif
diff --git a/apps/netutils/mqtt/lib/socks_mosq.h b/apps/netutils/mqtt/lib/socks_mosq.h
new file mode 100644 (file)
index 0000000..eb28bb4
--- /dev/null
@@ -0,0 +1,40 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2014 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 mosquitto__socks5_send(struct mosquitto *mosq);
+int mosquitto__socks5_read(struct mosquitto *mosq);
+
+#endif
diff --git a/apps/netutils/mqtt/lib/srv_mosq.c b/apps/netutils/mqtt/lib/srv_mosq.c
new file mode 100644 (file)
index 0000000..6bbda81
--- /dev/null
@@ -0,0 +1,117 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2013,2014 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_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{
+               _mosquitto_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, 2);
+                       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
+       return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+
diff --git a/apps/netutils/mqtt/lib/thread_mosq.c b/apps/netutils/mqtt/lib/thread_mosq.c
new file mode 100644 (file)
index 0000000..c853d08
--- /dev/null
@@ -0,0 +1,162 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2011-2014 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 <unistd.h>
+#endif
+
+#include <mosquitto_internal.h>
+#include <net_mosq.h>
+
+#if defined(__TINYARA__)
+#define TINYARA_MQTT_PTHREAD_STACK_SIZE                (8 * 1024)
+#endif
+
+void *_mosquitto_thread_main(void *obj);
+
+int mosquitto_loop_start(struct mosquitto *mosq)
+{
+#ifdef WITH_THREADING
+       if(!mosq || mosq->threaded != mosq_ts_none) return MOSQ_ERR_INVAL;
+
+#if defined(__TINYARA__)
+       char threadname[40];
+       pthread_attr_t attr;
+
+       mosq->threaded = mosq_ts_self;
+       pthread_attr_init(&attr);
+       pthread_attr_setstacksize(&attr, TINYARA_MQTT_PTHREAD_STACK_SIZE);
+       
+       if( pthread_create(&mosq->thread_id, &attr, _mosquitto_thread_main, mosq) != 0){
+               return MOSQ_ERR_ERRNO;
+       }
+       
+       snprintf(threadname, sizeof(threadname), "%s-%s", "MQTT", mosq->id);
+       pthread_setname_np(mosq->thread_id, threadname);
+       pthread_detach(mosq->thread_id);
+               
+       return MOSQ_ERR_SUCCESS;
+
+#else
+       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;
+       }
+#endif
+       
+#else
+       return MOSQ_ERR_NOT_SUPPORTED;
+#endif
+}
+
+int mosquitto_loop_stop(struct mosquitto *mosq, bool force)
+{
+#ifdef WITH_THREADING
+#  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;
+
+       if(!mosq) return NULL;
+
+       pthread_mutex_lock(&mosq->state_mutex);
+       if(mosq->state == mosq_cs_connect_async){
+               pthread_mutex_unlock(&mosq->state_mutex);
+               mosquitto_reconnect(mosq);
+       }else{
+               pthread_mutex_unlock(&mosq->state_mutex);
+       }
+
+       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);
+       }
+
+#if defined(__TINYARA__)
+       mosq->threaded = mosq_ts_none;
+#endif
+
+       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/apps/netutils/mqtt/lib/time_mosq.c b/apps/netutils/mqtt/lib/time_mosq.c
new file mode 100644 (file)
index 0000000..113cace
--- /dev/null
@@ -0,0 +1,99 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2013,2014 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 __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"
+
+#ifdef WIN32
+static bool tick64 = false;
+
+void _windows_time_version_check(void)
+{
+       OSVERSIONINFO vi;
+
+       tick64 = false;
+
+       memset(&vi, 0, sizeof(OSVERSIONINFO));
+       vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+       if(GetVersionEx(&vi)){
+               if(vi.dwMajorVersion > 5){
+                       tick64 = true;
+               }
+       }
+}
+#endif
+
+time_t mosquitto_time(void)
+{
+#ifdef WIN32
+       if(tick64){
+               return GetTickCount64()/1000;
+       }else{
+               return GetTickCount()/1000; /* FIXME - need to deal with overflow. */
+       }
+#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/apps/netutils/mqtt/lib/time_mosq.h b/apps/netutils/mqtt/lib/time_mosq.h
new file mode 100644 (file)
index 0000000..ff168b9
--- /dev/null
@@ -0,0 +1,39 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2013,2014 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/apps/netutils/mqtt/lib/tls_mosq.c b/apps/netutils/mqtt/lib/tls_mosq.c
new file mode 100644 (file)
index 0000000..a2cddca
--- /dev/null
@@ -0,0 +1,184 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2013,2014 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
+
+#ifdef WIN32
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+#else
+#  include <arpa/inet.h>
+#  include <sys/socket.h>
+#endif
+
+#include <string.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+
+#ifdef WITH_BROKER
+#  include "mosquitto_broker.h"
+#endif
+#include "mosquitto_internal.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)
+                       return _mosquitto_verify_certificate_hostname(cert, mosq->bridge->addresses[mosq->bridge->cur_address].address);
+#else
+                       return _mosquitto_verify_certificate_hostname(cert, mosq->host);
+#endif
+               }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){
+                               data = ASN1_STRING_data(nval->d.dNSName);
+                               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){
+                               data = ASN1_STRING_data(nval->d.iPAddress);
+                               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/apps/netutils/mqtt/lib/tls_mosq.h b/apps/netutils/mqtt/lib/tls_mosq.h
new file mode 100644 (file)
index 0000000..298f04b
--- /dev/null
@@ -0,0 +1,59 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2013,2014 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>
+#ifdef WITH_TLS_PSK
+#  if OPENSSL_VERSION_NUMBER >= 0x10000000
+#    define REAL_WITH_TLS_PSK
+#  else
+#    warning "TLS-PSK not supported, openssl too old."
+#  endif
+#endif
+
+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/apps/netutils/mqtt/lib/util_mosq.c b/apps/netutils/mqtt/lib/util_mosq.c
new file mode 100644 (file)
index 0000000..d1636a9
--- /dev/null
@@ -0,0 +1,373 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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 <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <winsock2.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_BROKER
+#include <mosquitto_broker.h>
+#endif
+
+#ifdef WITH_WEBSOCKETS
+#include <libwebsockets.h>
+#endif
+
+int _mosquitto_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;
+}
+
+#ifdef WITH_BROKER
+void _mosquitto_check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+void _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){
+
+               _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id);
+               _mosquitto_socket_close(db, mosq);
+               return;
+       }
+#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){
+                       _mosquitto_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
+                       if(mosq->listener){
+                               mosq->listener->client_count--;
+                               assert(mosq->listener->client_count >= 0);
+                       }
+                       mosq->listener = NULL;
+                       _mosquitto_socket_close(db, mosq);
+#else
+                       _mosquitto_socket_close(mosq);
+                       pthread_mutex_lock(&mosq->state_mutex);
+                       if(mosq->state == mosq_cs_disconnecting){
+                               rc = MOSQ_ERR_SUCCESS;
+                       }else{
+                               rc = 1;
+                       }
+                       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;
+                       }
+                       pthread_mutex_unlock(&mosq->callback_mutex);
+#endif
+               }
+       }
+}
+
+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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* Does a topic match a subscription? */
+int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result)
+{
+       int slen, tlen;
+       int spos, tpos;
+       bool multilevel_wildcard = false;
+
+       if(!sub || !topic || !result) return MOSQ_ERR_INVAL;
+
+       slen = strlen(sub);
+       tlen = strlen(topic);
+
+       if(!slen || !tlen){
+               *result = false;
+               return MOSQ_ERR_INVAL;
+       }
+
+       if(slen && tlen){
+               if((sub[0] == '$' && topic[0] != '$')
+                               || (topic[0] == '$' && sub[0] != '$')){
+
+                       *result = false;
+                       return MOSQ_ERR_SUCCESS;
+               }
+       }
+
+       spos = 0;
+       tpos = 0;
+
+       while(spos < slen && tpos <= tlen){
+               if(sub[spos] == topic[tpos]){
+                       if(tpos == tlen-1){
+                               /* Check for e.g. foo matching foo/# */
+                               if(spos == slen-3 
+                                               && sub[spos+1] == '/'
+                                               && sub[spos+2] == '#'){
+                                       *result = true;
+                                       multilevel_wildcard = true;
+                                       return MOSQ_ERR_SUCCESS;
+                               }
+                       }
+                       spos++;
+                       tpos++;
+                       if(spos == slen && tpos == tlen){
+                               *result = true;
+                               return MOSQ_ERR_SUCCESS;
+                       }else if(tpos == tlen && spos == slen-1 && sub[spos] == '+'){
+                               if(spos > 0 && sub[spos-1] != '/'){
+                                       *result = false;
+                                       return MOSQ_ERR_INVAL;
+                               }
+                               spos++;
+                               *result = true;
+                               return MOSQ_ERR_SUCCESS;
+                       }
+               }else{
+                       if(sub[spos] == '+'){
+                               /* Check for bad "+foo" or "a/+foo" subscription */
+                               if(spos > 0 && sub[spos-1] != '/'){
+                                       *result = false;
+                                       return MOSQ_ERR_INVAL;
+                               }
+                               /* Check for bad "foo+" or "foo+/a" subscription */
+                               if(spos < slen-1 && sub[spos+1] != '/'){
+                                       *result = false;
+                                       return MOSQ_ERR_INVAL;
+                               }
+                               spos++;
+                               while(tpos < tlen && topic[tpos] != '/'){
+                                       tpos++;
+                               }
+                               if(tpos == tlen && spos == slen){
+                                       *result = true;
+                                       return MOSQ_ERR_SUCCESS;
+                               }
+                       }else if(sub[spos] == '#'){
+                               if(spos > 0 && sub[spos-1] != '/'){
+                                       *result = false;
+                                       return MOSQ_ERR_INVAL;
+                               }
+                               multilevel_wildcard = true;
+                               if(spos+1 != slen){
+                                       *result = false;
+                                       return MOSQ_ERR_INVAL;
+                               }else{
+                                       *result = true;
+                                       return MOSQ_ERR_SUCCESS;
+                               }
+                       }else{
+                               *result = false;
+                               return MOSQ_ERR_SUCCESS;
+                       }
+               }
+       }
+       if(multilevel_wildcard == false && (tpos < tlen || spos < slen)){
+               *result = false;
+       }
+
+       return MOSQ_ERR_SUCCESS;
+}
+
+#ifdef REAL_WITH_TLS_PSK
+int _mosquitto_hex2bin(const char *hex, unsigned char *bin, int bin_max_len)
+{
+       BIGNUM *bn = NULL;
+       int len;
+
+       if(BN_hex2bn(&bn, hex) == 0){
+               if(bn) BN_free(bn);
+               return 0;
+       }
+       if(BN_num_bytes(bn) > bin_max_len){
+               BN_free(bn);
+               return 0;
+       }
+
+       len = BN_bn2bin(bn, bin);
+       BN_free(bn);
+       return len;
+}
+#endif
+
+FILE *_mosquitto_fopen(const char *path, const char *mode)
+{
+#ifdef WIN32
+       char buf[4096];
+       int rc;
+       rc = ExpandEnvironmentStrings(path, buf, 4096);
+       if(rc == 0 || rc > 4096){
+               return NULL;
+       }else{
+               return fopen(buf, mode);
+       }
+#else
+       return fopen(path, mode);
+#endif
+}
+
diff --git a/apps/netutils/mqtt/lib/util_mosq.h b/apps/netutils/mqtt/lib/util_mosq.h
new file mode 100644 (file)
index 0000000..4b84486
--- /dev/null
@@ -0,0 +1,58 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2009-2014 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.h"
+#endif
+
+int _mosquitto_packet_alloc(struct _mosquitto_packet *packet);
+#ifdef WITH_BROKER
+void _mosquitto_check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq);
+#else
+void _mosquitto_check_keepalive(struct mosquitto *mosq);
+#endif
+uint16_t _mosquitto_mid_generate(struct mosquitto *mosq);
+FILE *_mosquitto_fopen(const char *path, const char *mode);
+
+#ifdef REAL_WITH_TLS_PSK
+int _mosquitto_hex2bin(const char *hex, unsigned char *bin, int bin_max_len);
+#endif
+
+#endif
diff --git a/apps/netutils/mqtt/lib/will_mosq.c b/apps/netutils/mqtt/lib/will_mosq.c
new file mode 100644 (file)
index 0000000..6510729
--- /dev/null
@@ -0,0 +1,118 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 <stdio.h>
+#include <string.h>
+
+#include <mosquitto_internal.h>
+#include <memory_mosq.h>
+#include <mqtt3_protocol.h>
+
+int _mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
+{
+       int rc = MOSQ_ERR_SUCCESS;
+
+       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(mosq->will){
+               if(mosq->will->topic){
+                       _mosquitto_free(mosq->will->topic);
+                       mosq->will->topic = NULL;
+               }
+               if(mosq->will->payload){
+                       _mosquitto_free(mosq->will->payload);
+                       mosq->will->payload = NULL;
+               }
+               _mosquitto_free(mosq->will);
+               mosq->will = NULL;
+       }
+
+       mosq->will = _mosquitto_calloc(1, sizeof(struct mosquitto_message));
+       if(!mosq->will) return MOSQ_ERR_NOMEM;
+       mosq->will->topic = _mosquitto_strdup(topic);
+       if(!mosq->will->topic){
+               rc = MOSQ_ERR_NOMEM;
+               goto cleanup;
+       }
+       mosq->will->payloadlen = payloadlen;
+       if(mosq->will->payloadlen > 0){
+               if(!payload){
+                       rc = MOSQ_ERR_INVAL;
+                       goto cleanup;
+               }
+               mosq->will->payload = _mosquitto_malloc(sizeof(char)*mosq->will->payloadlen);
+               if(!mosq->will->payload){
+                       rc = MOSQ_ERR_NOMEM;
+                       goto cleanup;
+               }
+
+               memcpy(mosq->will->payload, payload, payloadlen);
+       }
+       mosq->will->qos = qos;
+       mosq->will->retain = retain;
+
+       return MOSQ_ERR_SUCCESS;
+
+cleanup:
+       if(mosq->will){
+               if(mosq->will->topic) _mosquitto_free(mosq->will->topic);
+               if(mosq->will->payload) _mosquitto_free(mosq->will->payload);
+       }
+       _mosquitto_free(mosq->will);
+       mosq->will = NULL;
+
+       return rc;
+}
+
+int _mosquitto_will_clear(struct mosquitto *mosq)
+{
+       if(!mosq->will) return MOSQ_ERR_SUCCESS;
+
+       if(mosq->will->topic){
+               _mosquitto_free(mosq->will->topic);
+               mosq->will->topic = NULL;
+       }
+       if(mosq->will->payload){
+               _mosquitto_free(mosq->will->payload);
+               mosq->will->payload = NULL;
+       }
+       _mosquitto_free(mosq->will);
+       mosq->will = NULL;
+
+       return MOSQ_ERR_SUCCESS;
+}
+
diff --git a/apps/netutils/mqtt/lib/will_mosq.h b/apps/netutils/mqtt/lib/will_mosq.h
new file mode 100644 (file)
index 0000000..30b3954
--- /dev/null
@@ -0,0 +1,43 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/*
+Copyright (c) 2010-2014 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 _mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain);
+int _mosquitto_will_clear(struct mosquitto *mosq);
+
+#endif
diff --git a/apps/netutils/mqtt/mqtt_api.c b/apps/netutils/mqtt/mqtt_api.c
new file mode 100644 (file)
index 0000000..aaf0dfe
--- /dev/null
@@ -0,0 +1,685 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/**
+ * @file mqtt_api.c
+ * @brief MQTT API
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <debug.h>
+#include <errno.h>
+
+#include "mosquitto.h"
+#include "mosquitto_internal.h"
+#include "memory_mosq.h"
+
+#include <apps/netutils/mqtt_api.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions Prototype
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static mqtt_client_t *create_mqtt_client(void)
+{
+       mqtt_client_t *mqtt_client = NULL;
+       mqtt_client = (mqtt_client_t *) _mosquitto_malloc(sizeof(mqtt_client_t));
+       if (mqtt_client == NULL) {
+               ndbg("ERROR: mqtt_client is null.\n");
+       }
+
+       return mqtt_client;
+}
+
+static void destroy_mqtt_client(mqtt_client_t *client)
+{
+       if (client) {
+               if (client->mosq) {
+                       mosquitto_destroy((struct mosquitto *)client->mosq);
+               }
+               client->mosq = NULL;
+
+               mosquitto_lib_cleanup();
+
+               _mosquitto_free(client);
+       }
+}
+
+static void on_connect_callback(struct mosquitto *client, void *data, int result)
+{
+       mqtt_client_t *mqtt_client = (mqtt_client_t *) data;
+
+       if (mqtt_client) {
+               mqtt_client->state = MQTT_CLIENT_STATE_CONNECTED;
+               if (mqtt_client->config && mqtt_client->config->on_connect) {
+                       mqtt_client->config->on_connect(mqtt_client, result);
+               }
+       }
+}
+
+static void on_disconnect_callback(struct mosquitto *client, void *data, int result)
+{
+       mqtt_client_t *mqtt_client = (mqtt_client_t *) data;
+
+       if (mqtt_client) {
+               mqtt_client->state = MQTT_CLIENT_STATE_NOT_CONNECTED;
+               if (mqtt_client->config && mqtt_client->config->on_disconnect) {
+                       mqtt_client->config->on_disconnect(mqtt_client, result);
+               }
+       }
+}
+
+static void on_message_callback(struct mosquitto *client, void *data, const struct mosquitto_message *msg)
+{
+       mqtt_client_t *mqtt_client = (mqtt_client_t *) data;
+       mqtt_msg_t *received_msg;
+
+       received_msg = (mqtt_msg_t *) _mosquitto_malloc(sizeof(mqtt_msg_t));
+       if (!received_msg) {
+               ndbg("ERROR: received_msg is null.");
+               return;
+       }
+
+       received_msg->msg_id = msg->mid;
+       received_msg->topic = msg->topic;
+       received_msg->payload = msg->payload;
+       received_msg->payload_len = msg->payloadlen;
+       received_msg->qos = msg->qos;
+       received_msg->retain = msg->retain;
+
+       if (mqtt_client && mqtt_client->config && mqtt_client->config->on_message) {
+               mqtt_client->config->on_message(mqtt_client, received_msg);
+       }
+
+       _mosquitto_free(received_msg);
+}
+
+static void on_publish_callback(struct mosquitto *client, void *data, int msg_id)
+{
+       mqtt_client_t *mqtt_client = (mqtt_client_t *) data;
+
+       if (mqtt_client) {
+               mqtt_client->state = MQTT_CLIENT_STATE_CONNECTED;
+               if (mqtt_client->config && mqtt_client->config->on_publish) {
+                       mqtt_client->config->on_publish(mqtt_client, msg_id);
+               }
+       }
+}
+
+static void on_subscribe_callback(struct mosquitto *client, void *data, int msg_id, int qos_count, const int *granted_qos)
+{
+       mqtt_client_t *mqtt_client = (mqtt_client_t *) data;
+
+       if (mqtt_client) {
+               mqtt_client->state = MQTT_CLIENT_STATE_CONNECTED;
+               if (mqtt_client->config && mqtt_client->config->on_subscribe) {
+                       mqtt_client->config->on_subscribe(mqtt_client, msg_id, qos_count, granted_qos);
+               }
+       }
+}
+
+static void on_unsubscribe_callback(struct mosquitto *client, void *data, int msg_id)
+{
+       mqtt_client_t *mqtt_client = (mqtt_client_t *) data;
+
+       if (mqtt_client) {
+               mqtt_client->state = MQTT_CLIENT_STATE_CONNECTED;
+               if (mqtt_client->config && mqtt_client->config->on_unsubscribe) {
+                       mqtt_client->config->on_unsubscribe(mqtt_client, msg_id);
+               }
+       }
+}
+
+static void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)
+{
+       printf("%s\n", str);
+}
+
+static void get_mqtt_client_state_string(int state, char *result_str)
+{
+       switch (state) {
+       case MQTT_CLIENT_STATE_NOT_CONNECTED:
+               snprintf(result_str, 20, "NOT_CONNECTED");
+               break;
+       case MQTT_CLIENT_STATE_CONNECTED:
+               snprintf(result_str, 20, "CONNECTED");
+               break;
+       case MQTT_CLIENT_STATE_CONNECT_REQUEST:
+               snprintf(result_str, 20, "CONNECT_REQUEST");
+               break;
+       case MQTT_CLIENT_STATE_SUBSCRIBE_REQUEST:
+               snprintf(result_str, 20, "SUBSCRIBE_REQUEST");
+               break;
+       case MQTT_CLIENT_STATE_UNSUBSCRIBE_REQUEST:
+               snprintf(result_str, 20, "UNSUBSCRIBE_REQUEST");
+               break;
+       case MQTT_CLIENT_STATE_PUBLISH_REQUEST:
+               snprintf(result_str, 20, "PUBLISH_REQUEST");
+               break;
+       case MQTT_CLIENT_STATE_DISCONNECT_REQUEST:
+               snprintf(result_str, 20, "DISCONNECT_REQUEST");
+               break;
+       default:
+               snprintf(result_str, 20, "UNKNOWN");
+               break;
+       }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mqtt_init_client
+ *
+ * Description:
+ *      Initializes MQTT object.
+ *
+ * Parameters:
+ *     config : the information of MQTT client object configuration
+ *
+ * Returned Value:
+ *      On success, the handle of MQTT client object is returned. On failure, NULL is returned.
+ *
+ ****************************************************************************/
+mqtt_client_t *mqtt_init_client(mqtt_client_config_t *config)
+{
+       int result = -1;
+       mqtt_client_t *mqtt_client = NULL;
+       int ret = 0;
+       int major, minor, revision;
+
+       if (config == NULL) {
+               ndbg("ERROR: mqtt config is null.\n");
+               goto done;
+       }
+
+       mqtt_client = create_mqtt_client();
+       if (!mqtt_client) {
+               ndbg("ERROR: mqtt_client is null.\n");
+               goto done;
+       }
+
+       memset(mqtt_client, 0, sizeof(*mqtt_client));
+
+       mosquitto_lib_version(&major, &minor, &revision);
+       mqtt_client->lib_version = major * 1000000 + minor * 1000 + revision;
+       mqtt_client->config = config;
+       mqtt_client->state = MQTT_CLIENT_STATE_NOT_CONNECTED;
+       mosquitto_lib_init();
+
+       mqtt_client->mosq = mosquitto_new(config->client_id, config->clean_session, NULL);
+       if (!mqtt_client->mosq) {
+               switch (errno) {
+               case ENOMEM:
+                       ndbg("ERROR: mosquitto_new() failed. (reason: out of memory)\n");
+                       break;
+               case EINVAL:
+                       ndbg("ERROR: mosquitto_new() failed. (reason: invalid id)\n");
+                       break;
+               }
+               goto done;
+       }
+
+       if (config->user_name != NULL && config->password != NULL) {
+               ret = mosquitto_username_pw_set((struct mosquitto *)mqtt_client->mosq, config->user_name, config->password);
+               if (ret != MOSQ_ERR_SUCCESS) {
+                       goto done;
+               }
+       }
+
+       /* set userdata */
+       mosquitto_user_data_set((struct mosquitto *)mqtt_client->mosq, mqtt_client);
+
+       /* set callback */
+       if (config->debug) {
+               mosquitto_log_callback_set((struct mosquitto *)mqtt_client->mosq, my_log_callback);
+       }
+       mosquitto_connect_callback_set((struct mosquitto *)mqtt_client->mosq, on_connect_callback);
+       mosquitto_disconnect_callback_set((struct mosquitto *)mqtt_client->mosq, on_disconnect_callback);
+       mosquitto_publish_callback_set((struct mosquitto *)mqtt_client->mosq, on_publish_callback);
+       mosquitto_message_callback_set((struct mosquitto *)mqtt_client->mosq, on_message_callback);
+       mosquitto_subscribe_callback_set((struct mosquitto *)mqtt_client->mosq, on_subscribe_callback);
+       mosquitto_unsubscribe_callback_set((struct mosquitto *)mqtt_client->mosq, on_unsubscribe_callback);
+
+#if defined(CONFIG_NETUTILS_MQTT_SECURITY)
+       if (config->tls) {
+               struct mosquitto *tmp = (struct mosquitto *)mqtt_client->mosq;
+
+               tmp->tls_ca_cert_len = config->tls->ca_cert_len;
+               tmp->tls_cert_len = config->tls->cert_len;
+               tmp->tls_key_len = config->tls->key_len;
+
+               ret = mosquitto_tls_set(tmp, (const char *)config->tls->ca_cert, NULL, (const char *)config->tls->cert, (const char *)config->tls->key, NULL);
+               if (ret != 0) {
+                       ndbg("ERROR: mosquitto_tls_set() failed. (ret: %d)\n", ret);
+                       goto done;
+               }
+       }
+#else
+       if (config->tls) {
+               ndbg("this version doesn't support MQTT over TLS.\n");
+       }
+#endif
+       /* result is success */
+       result = 0;
+
+done:
+       if (result != 0) {
+               destroy_mqtt_client(mqtt_client);
+               mqtt_client = NULL;
+       }
+       return mqtt_client;
+}
+
+/****************************************************************************
+ * Name: mqtt_deinit_client
+ *
+ * Description:
+ *      De-initializes MQTT object.
+ *
+ * Parameters:
+ *     handle : the handle of MQTT client object
+ *
+ * Returned Value:
+ *      On success, 0 is returned. On failure, a negative value is returned.
+ *
+ ****************************************************************************/
+int mqtt_deinit_client(mqtt_client_t *handle)
+{
+       int result = -1;
+
+       if (handle) {
+               destroy_mqtt_client(handle);
+               result = 0;
+       }
+
+       return result;
+}
+
+/****************************************************************************
+ * Name: mqtt_connect
+ *
+ * Description:
+ *      Establishes connection with MQTT broker.
+ *
+ * Parameters:
+ *     handle : the handle of MQTT client object
+ *     addr : MQTT broker address
+ *     port : MQTT broker port
+ *     keep_alive : MQTT keep-alive time in second
+ *
+ * Returned Value:
+ *      On success, 0 is returned. On failure, a negative value is returned.
+ *
+ ****************************************************************************/
+int mqtt_connect(mqtt_client_t *handle, char *addr, int port, int keep_alive)
+{
+       int result = -1;
+       int ret = 0;
+       struct mosquitto *mosq = NULL;
+       mqtt_client_config_t *mqtt_config = NULL;
+
+       if (handle == NULL) {
+               ndbg("ERROR: mqtt_client handle is null.\n");
+               goto done;
+       }
+
+       mosq = (struct mosquitto *)handle->mosq;
+       if (mosq == NULL) {
+               ndbg("ERROR: mosquitto handle is null.\n");
+               goto done;
+       }
+
+       if (handle->state == MQTT_CLIENT_STATE_CONNECTED) {
+               ndbg("ERROR: mqtt_client is already connected.\n");
+               result = 0;
+               goto done;
+       }
+
+       if (handle->state > MQTT_CLIENT_STATE_CONNECTED) {
+               char state_str[20];
+               get_mqtt_client_state_string(handle->state, state_str);
+               ndbg("ERROR: mqtt_client is busy.(current state: %s)\n", state_str);
+               goto done;
+       }
+
+       mqtt_config = handle->config;
+       if (mqtt_config == NULL) {
+               ndbg("ERROR: mqtt_config is null.\n");
+               goto done;
+       }
+
+       if (addr == NULL) {
+               ndbg("ERROR: addr is null.\n");
+               goto done;
+       }
+
+       if (port == 0) {
+               port = MQTT_DEFAULT_BROKER_PORT;
+       }
+
+       handle->state = MQTT_CLIENT_STATE_CONNECT_REQUEST;
+       ret = mosquitto_connect(mosq, addr, port, keep_alive);
+       if (ret != 0) {
+               ndbg("ERROR: mosquitto_connect() failed. (ret: %d)\n", ret);
+               handle->state = MQTT_CLIENT_STATE_NOT_CONNECTED;
+               goto done;
+       }
+
+       if (!mosq->threaded) {
+               ret = mosquitto_loop_start(mosq);
+               if (ret != 0) {
+                       ndbg("ERROR: mosquitto_loop_start() failed. (ret: %d)\n", ret);
+                       ret = mosquitto_disconnect(mosq);
+                       if (ret != 0) {
+                               ndbg("ERROR: mosquitto_disconnect() failed. (ret: %d)\n", ret);
+                       }
+                       goto done;
+               }
+       }
+
+       /* result is success */
+       result = 0;
+
+done:
+       return result;
+}
+
+/****************************************************************************
+ * Name: mqtt_disconnect
+ *
+ * Description:
+ *      Disconnect from MQTT broker.
+ *
+ * Parameters:
+ *     handle : the handle of MQTT client object
+ *
+ * Returned Value:
+ *      On success, 0 is returned. On failure, a negative value is returned.
+ *
+ ****************************************************************************/
+int mqtt_disconnect(mqtt_client_t *handle)
+{
+       int result = -1;
+       int ret = 0;
+       struct mosquitto *mosq = NULL;
+
+       if (handle == NULL) {
+               ndbg("ERROR: mqtt_client handle is null.\n");
+               goto done;
+       }
+
+       mosq = (struct mosquitto *)handle->mosq;
+       if (mosq == NULL) {
+               ndbg("ERROR: mosquitto handle is null.\n");
+               goto done;
+       }
+
+       if (handle->state == MQTT_CLIENT_STATE_NOT_CONNECTED) {
+               ndbg("ERROR: mqtt_client is already disconnected.\n");
+               result = 0;
+               goto done;
+       }
+
+       if (handle->state > MQTT_CLIENT_STATE_CONNECTED) {
+               char state_str[20];
+               get_mqtt_client_state_string(handle->state, state_str);
+               ndbg("ERROR: mqtt_client is busy. (current state: %s)\n", state_str);
+               goto done;
+       }
+
+       handle->state = MQTT_CLIENT_STATE_DISCONNECT_REQUEST;
+       ret = mosquitto_disconnect(mosq);
+       if (ret != 0) {
+               ndbg("ERROR: mosquitto_disconnect() failed.\n");
+               handle->state = MQTT_CLIENT_STATE_CONNECTED;
+               goto done;
+       }
+
+       /* result is success */
+       result = 0;
+
+done:
+       return result;
+}
+
+/****************************************************************************
+ * Name: mqtt_publish
+ *
+ * Description:
+ *      Publish message to MQTT Broker on the given Topic.
+ *
+ * Parameters:
+ *     handle : the handle of MQTT client object
+ *     topic : the topic on which the message to be published
+ *     data : the message to publish
+ *     data_len : the length of message
+ *     qos : the Quality of Service to be used for the message. QoS value should be 0,1 or 2.
+ *     retain : the flag to make the message retained
+ *
+ * Returned Value:
+ *      On success, 0 is returned. On failure, a negative value is returned.
+ *
+ ****************************************************************************/
+int mqtt_publish(mqtt_client_t *handle, char *topic, char *data, uint32_t data_len, uint8_t qos, uint8_t retain)
+{
+       int result = -1;
+       int ret = 0;
+       struct mosquitto *mosq = NULL;
+
+       if (handle == NULL) {
+               ndbg("ERROR: mqtt_client handle is null.\n");
+               goto done;
+       }
+
+       mosq = (struct mosquitto *)handle->mosq;
+       if (mosq == NULL) {
+               ndbg("ERROR: mosquitto handle is null.\n");
+               goto done;
+       }
+
+       if (handle->state == MQTT_CLIENT_STATE_NOT_CONNECTED) {
+               ndbg("ERROR: mqtt_client is disconnected.\n");
+               goto done;
+       }
+
+       if (handle->state > MQTT_CLIENT_STATE_CONNECTED) {
+               char state_str[20];
+               get_mqtt_client_state_string(handle->state, state_str);
+               ndbg("ERROR: mqtt_client is busy. (current state: %s)\n", state_str);
+               goto done;
+       }
+
+       if (topic == NULL) {
+               ndbg("ERROR: topic is null.\n");
+               goto done;
+       }
+
+       if (qos > 2) {
+               ndbg("ERROR: invalid qos: %d (valid range: 0 ~ 2)\n", qos);
+               goto done;
+       }
+
+       handle->state = MQTT_CLIENT_STATE_PUBLISH_REQUEST;
+       ret = mosquitto_publish(mosq, NULL, (const char *)topic, data_len, data, qos, retain != 0 ? true : false);
+       if (ret != 0) {
+               ndbg("ERROR: mosquitto_publish() failed. (ret: %d)\n", ret);
+               handle->state = MQTT_CLIENT_STATE_CONNECTED;
+               goto done;
+       }
+
+       /* result is success */
+       result = 0;
+
+done:
+       return result;
+}
+
+/****************************************************************************
+ * Name: mqtt_subscribe
+ *
+ * Description:
+ *      Subscribe for a topic with MQTT Broker.
+ *
+ * Parameters:
+ *     handle  the handle of MQTT client object
+ *     topic  the topic on which the message to be unsubscribed
+ *     qos  the Quality of Service for the subscription.  QoS value should be 0,1 or 2.
+ *
+ * Returned Value:
+ *      On success, the handle of MQTT client object is returned. On failure, NULL is returned.
+ *
+ ****************************************************************************/
+int mqtt_subscribe(mqtt_client_t *handle, char *topic, uint8_t qos)
+{
+       int result = -1;
+       int ret = 0;
+       struct mosquitto *mosq = NULL;
+
+       if (handle == NULL) {
+               ndbg("ERROR: mqtt_client handle is null.\n");
+               goto done;
+       }
+
+       mosq = (struct mosquitto *)handle->mosq;
+       if (mosq == NULL) {
+               ndbg("ERROR: mosquitto handle is null.\n");
+               goto done;
+       }
+
+       if (handle->state == MQTT_CLIENT_STATE_NOT_CONNECTED) {
+               ndbg("ERROR: mqtt_client is disconnected.\n");
+               goto done;
+       }
+
+       if (handle->state > MQTT_CLIENT_STATE_CONNECTED) {
+               char state_str[20];
+               get_mqtt_client_state_string(handle->state, state_str);
+               ndbg("ERROR: mqtt_client is busy. (current state: %s)\n", state_str);
+               goto done;
+       }
+
+       if (topic == NULL) {
+               ndbg("ERROR: topic is null.\n");
+               goto done;
+       }
+
+       if (qos > 2) {
+               ndbg("ERROR: invalid qos: %d (valid range: 0 ~ 2) \n", qos);
+               goto done;
+       }
+
+       handle->state = MQTT_CLIENT_STATE_SUBSCRIBE_REQUEST;
+       ret = mosquitto_subscribe(mosq, NULL, (const char *)topic, qos);
+       if (ret != 0) {
+               ndbg("ERROR: mqtt_subscribe() failed. (ret: %d)\n", ret);
+               handle->state = MQTT_CLIENT_STATE_CONNECTED;
+               goto done;
+       }
+
+       /* result is success */
+       result = 0;
+
+done:
+       return result;
+}
+
+/****************************************************************************
+ * Name: mqtt_unsubscribe
+ *
+ * Description:
+ *      Unsubscribe the topic from MQTT Broker.
+ *
+ * Parameters:
+ *     handle  the handle of MQTT client object
+ *     topic  the topic on which the message to be unsubscribed
+ *
+ * Returned Value:
+ *      On success, the handle of MQTT client object is returned. On failure, NULL is returned.
+ *
+ ****************************************************************************/
+int mqtt_unsubscribe(mqtt_client_t *handle, char *topic)
+{
+       int result = -1;
+       int ret = 0;
+       struct mosquitto *mosq = NULL;
+
+       if (handle == NULL) {
+               ndbg("ERROR: mqtt_client handle is null.\n");
+               goto done;
+       }
+
+       mosq = (struct mosquitto *)handle->mosq;
+       if (mosq == NULL) {
+               ndbg("ERROR: mosquitto handle is null.\n");
+               goto done;
+       }
+
+       if (handle->state == MQTT_CLIENT_STATE_NOT_CONNECTED) {
+               ndbg("ERROR: mqtt_client is disconnected.\n");
+               goto done;
+       }
+
+       if (handle->state > MQTT_CLIENT_STATE_CONNECTED) {
+               char state_str[20];
+               get_mqtt_client_state_string(handle->state, state_str);
+               ndbg("ERROR: mqtt_client is busy. (current state: %s)\n", state_str);
+               goto done;
+       }
+
+       if (topic == NULL) {
+               ndbg("ERROR: topic is null.\n");
+               goto done;
+       }
+
+       handle->state = MQTT_CLIENT_STATE_UNSUBSCRIBE_REQUEST;
+       ret = mosquitto_unsubscribe(mosq, NULL, (const char *)topic);
+       if (ret != 0) {
+               ndbg("ERROR: mosquitto_unsubscribe() failed. (ret: %d)\n");
+               handle->state = MQTT_CLIENT_STATE_CONNECTED;
+               goto done;
+       }
+
+       /* result is success */
+       result = 0;
+
+done:
+       return result;
+}