mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-23 02:42:08 +00:00
Merge: Snapmaker Orca 2.1.2
This commit is contained in:
173
src/mqtt/CMakeLists.txt
Normal file
173
src/mqtt/CMakeLists.txt
Normal file
@@ -0,0 +1,173 @@
|
||||
# CMakeLists.txt
|
||||
#
|
||||
# Top-level CMake file for the Paho C++ library.
|
||||
#
|
||||
#*******************************************************************************
|
||||
# This is part of the Paho MQTT C++ client library.
|
||||
#
|
||||
# Copyright (c) 2016-2017, Guilherme Maciel Ferreira
|
||||
# Copyright (c) 2017-2023, Frank Pagliughi
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v2.0
|
||||
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at
|
||||
# http://www.eclipse.org/legal/epl-v20.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Guilherme Maciel Ferreira - initial version
|
||||
# Frank Pagliughi
|
||||
#*******************************************************************************/
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(PahoMqttCpp VERSION "1.4.0")
|
||||
|
||||
## --- Build options ---
|
||||
|
||||
if(WIN32)
|
||||
option(PAHO_BUILD_STATIC "Build static library" TRUE)
|
||||
option(PAHO_BUILD_SHARED "Build shared library (DLL)" FALSE)
|
||||
option(PAHO_WITH_SSL "Build SSL-enabled library" ON)
|
||||
else()
|
||||
option(PAHO_BUILD_STATIC "Build static library" TRUE)
|
||||
option(PAHO_BUILD_SHARED "Build shared library" FALSE)
|
||||
option(PAHO_WITH_SSL "Build SSL-enabled library" ON)
|
||||
option(PAHO_BUILD_DEB_PACKAGE "Build debian package" FALSE)
|
||||
endif()
|
||||
|
||||
option(PAHO_BUILD_SAMPLES "Build sample/example programs" FALSE)
|
||||
option(PAHO_BUILD_EXAMPLES "Build sample/example programs" FALSE)
|
||||
option(PAHO_BUILD_TESTS "Build tests (requires Catch2)" FALSE)
|
||||
option(PAHO_BUILD_DOCUMENTATION "Create and install the API documentation (requires Doxygen)" FALSE)
|
||||
option(PAHO_WITH_MQTT_C "Build Paho C from the internal GIT submodule." TRUE)
|
||||
|
||||
if(NOT PAHO_BUILD_SHARED AND NOT PAHO_BUILD_STATIC)
|
||||
message(FATAL_ERROR "You must set either PAHO_BUILD_SHARED, PAHO_BUILD_STATIC, or both")
|
||||
endif()
|
||||
|
||||
## --- Find Paho C or build it, if reqested ---
|
||||
|
||||
if(PAHO_WITH_SSL)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
set(PAHO_MQTT_C_LIB paho-mqtt3as)
|
||||
else()
|
||||
set(PAHO_MQTT_C_LIB paho-mqtt3a)
|
||||
endif()
|
||||
|
||||
if(PAHO_WITH_MQTT_C)
|
||||
message(STATUS "Paho C: Bundled")
|
||||
|
||||
## Build the Paho C library from the submodule
|
||||
set(PAHO_ENABLE_TESTING FALSE CACHE BOOL "No Paho C tests")
|
||||
set(PAHO_HIGH_PERFORMANCE TRUE CACHE BOOL "Paho C high performance")
|
||||
|
||||
# TODO: Remove this when the next Paho C update is released.
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/externals/paho-mqtt-c)
|
||||
|
||||
## Alias namespace so that the full names can be used with the subdir.
|
||||
if(PAHO_BUILD_SHARED)
|
||||
add_library(eclipse-paho-mqtt-c::paho-mqtt3a ALIAS paho-mqtt3a)
|
||||
list(APPEND PAHO_MQTT_C_LIBS paho-mqtt3a)
|
||||
if(PAHO_WITH_SSL)
|
||||
add_library(eclipse-paho-mqtt-c::paho-mqtt3as ALIAS paho-mqtt3as)
|
||||
list(APPEND PAHO_MQTT_C_LIBS paho-mqtt3as)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PAHO_BUILD_STATIC)
|
||||
add_library(eclipse-paho-mqtt-c::paho-mqtt3a-static ALIAS paho-mqtt3a-static)
|
||||
list(APPEND PAHO_MQTT_C_LIBS paho-mqtt3a-static)
|
||||
if(PAHO_WITH_SSL)
|
||||
add_library(eclipse-paho-mqtt-c::paho-mqtt3as-static ALIAS paho-mqtt3as-static)
|
||||
list(APPEND PAHO_MQTT_C_LIBS paho-mqtt3as-static)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## install paho.mqtt.c library (appending to PahoMqttCpp export)
|
||||
install(TARGETS ${PAHO_MQTT_C_LIBS}
|
||||
EXPORT PahoMqttCpp
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
else()
|
||||
find_package(eclipse-paho-mqtt-c REQUIRED)
|
||||
endif()
|
||||
|
||||
## --- C++11 build flags ---
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Generate position-independent code (-fPIC on UNIX)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# --- System Details ---
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(LIBS_SYSTEM ws2_32)
|
||||
endif()
|
||||
|
||||
## --- Build directories ---
|
||||
|
||||
# --- The headers ---
|
||||
|
||||
add_subdirectory(include/mqtt)
|
||||
|
||||
# For the paho_mqtt_c module
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
add_subdirectory(src)
|
||||
|
||||
# --- Documentation ---
|
||||
|
||||
if(PAHO_BUILD_DOCUMENTATION)
|
||||
add_subdirectory(doc)
|
||||
endif()
|
||||
|
||||
# --- Default library for samples and unit tests ---
|
||||
|
||||
if(PAHO_BUILD_SHARED)
|
||||
set(PAHO_CPP_LIB paho-mqttpp3)
|
||||
else()
|
||||
set(PAHO_CPP_LIB paho-mqttpp3-static)
|
||||
endif()
|
||||
|
||||
# --- Example Apps ---
|
||||
|
||||
if(PAHO_BUILD_SAMPLES OR PAHO_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
# --- Unit Tests ---
|
||||
|
||||
if(PAHO_BUILD_TESTS)
|
||||
add_subdirectory(test/unit)
|
||||
endif()
|
||||
|
||||
## --- Packaging settings ---
|
||||
|
||||
if(WIN32)
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
elseif(UNIX)
|
||||
if(PAHO_BUILD_DEB_PACKAGE)
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
include(cmake/CPackDebConfig.cmake)
|
||||
else()
|
||||
set(CPACK_GENERATOR "TGZ")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
|
||||
add_subdirectory(cmake)
|
||||
46
src/mqtt/cmake/CMakeLists.txt
Normal file
46
src/mqtt/cmake/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
# CMakeLists.txt
|
||||
#
|
||||
# CMake export file for the Paho C++ library.
|
||||
#
|
||||
#*******************************************************************************
|
||||
# This is part of the Paho MQTT C++ client library.
|
||||
#
|
||||
# Copyright (c) 2017-2023, Frank Pagliughi
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v2.0
|
||||
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at
|
||||
# http://www.eclipse.org/legal/epl-v20.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#*******************************************************************************/
|
||||
|
||||
set(package_name PahoMqttCpp)
|
||||
configure_file(${package_name}Config.cmake.in ${package_name}Config.cmake @ONLY)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${package_name}ConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
export(EXPORT ${package_name}
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/${package_name}Targets.cmake"
|
||||
NAMESPACE ${package_name}::
|
||||
)
|
||||
|
||||
install(EXPORT ${package_name}
|
||||
DESTINATION lib/cmake/${package_name}
|
||||
FILE ${package_name}Targets.cmake
|
||||
NAMESPACE ${package_name}::
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${package_name}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${package_name}ConfigVersion.cmake"
|
||||
DESTINATION lib/cmake/${package_name}
|
||||
)
|
||||
10
src/mqtt/cmake/CPackDebConfig.cmake
Normal file
10
src/mqtt/cmake/CPackDebConfig.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
if(CPACK_GENERATOR MATCHES "DEB")
|
||||
set(CPACK_PACKAGE_NAME "libpaho-mqtt.cpp")
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME ${CPACK_PACKAGE_NAME})
|
||||
set(CPACK_PACKAGE_CONTACT "Eclipse")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Eclipse Paho MQTT C++ client")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER " <>")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION ${PACKAGE_VERSION})
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "net")
|
||||
endif()
|
||||
19
src/mqtt/cmake/PahoMqttCppConfig.cmake.in
Normal file
19
src/mqtt/cmake/PahoMqttCppConfig.cmake.in
Normal file
@@ -0,0 +1,19 @@
|
||||
# save build-time options
|
||||
set(PAHO_BUILD_STATIC @PAHO_BUILD_STATIC@)
|
||||
set(PAHO_BUILD_SHARED @PAHO_BUILD_SHARED@)
|
||||
set(PAHO_WITH_SSL @PAHO_WITH_SSL@)
|
||||
set(PAHO_WITH_MQTT_C @PAHO_WITH_MQTT_C@)
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(Threads REQUIRED)
|
||||
|
||||
if (NOT PAHO_WITH_MQTT_C)
|
||||
find_dependency(eclipse-paho-mqtt-c REQUIRED)
|
||||
endif()
|
||||
|
||||
if (PAHO_WITH_SSL)
|
||||
find_dependency(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@package_name@Targets.cmake")
|
||||
131
src/mqtt/externals/paho-mqtt-c/CMakeLists.txt
vendored
Normal file
131
src/mqtt/externals/paho-mqtt-c/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
#*******************************************************************************
|
||||
# Copyright (c) 2015, 2023 logi.cals GmbH and others
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v2.0
|
||||
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at
|
||||
# https://www.eclipse.org/legal/epl-2.0/
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Rainer Poisel - initial version
|
||||
# Genis Riera Perez - Add support for building debian package
|
||||
#*******************************************************************************/
|
||||
|
||||
# Note: on OS X you should install XCode and the associated command-line tools
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
|
||||
PROJECT("Eclipse Paho C" C)
|
||||
MESSAGE(STATUS "CMake version: " ${CMAKE_VERSION})
|
||||
MESSAGE(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME})
|
||||
|
||||
SET(CMAKE_SCRIPTS "${CMAKE_SOURCE_DIR}/cmake")
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
## build settings
|
||||
file(READ version.major PAHO_VERSION_MAJOR)
|
||||
file(READ version.minor PAHO_VERSION_MINOR)
|
||||
file(READ version.patch PAHO_VERSION_PATCH)
|
||||
SET(CLIENT_VERSION ${PAHO_VERSION_MAJOR}.${PAHO_VERSION_MINOR}.${PAHO_VERSION_PATCH})
|
||||
|
||||
INCLUDE(GNUInstallDirs)
|
||||
|
||||
STRING(TIMESTAMP BUILD_TIMESTAMP UTC)
|
||||
MESSAGE(STATUS "Timestamp is ${BUILD_TIMESTAMP}")
|
||||
|
||||
IF(WIN32)
|
||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -DWIN32_LEAN_AND_MEAN)
|
||||
ELSEIF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
ADD_DEFINITIONS(-DOSX)
|
||||
ENDIF()
|
||||
|
||||
## build options
|
||||
SET(PAHO_WITH_SSL ON CACHE BOOL "Flag that defines whether to build ssl-enabled binaries too. " FORCE)
|
||||
SET(PAHO_WITH_LIBUUID FALSE CACHE BOOL "Flag that defines whether libuuid or a custom uuid implementation should be used")
|
||||
SET(PAHO_BUILD_SHARED TRUE CACHE BOOL "Build shared library")
|
||||
SET(PAHO_BUILD_STATIC FALSE CACHE BOOL "Build static library")
|
||||
SET(PAHO_BUILD_DOCUMENTATION FALSE CACHE BOOL "Create and install the HTML based API documentation (requires Doxygen)")
|
||||
SET(PAHO_BUILD_SAMPLES FALSE CACHE BOOL "Build sample programs")
|
||||
SET(PAHO_BUILD_DEB_PACKAGE FALSE CACHE BOOL "Build debian package")
|
||||
SET(PAHO_ENABLE_TESTING TRUE CACHE BOOL "Build tests and run")
|
||||
SET(PAHO_ENABLE_CPACK TRUE CACHE BOOL "Enable CPack")
|
||||
SET(PAHO_HIGH_PERFORMANCE FALSE CACHE BOOL "Disable tracing and heap tracking")
|
||||
SET(PAHO_USE_SELECT FALSE CACHE BOOL "Revert to select system call instead of poll")
|
||||
|
||||
IF (PAHO_HIGH_PERFORMANCE)
|
||||
ADD_DEFINITIONS(-DHIGH_PERFORMANCE=1)
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_USE_SELECT)
|
||||
ADD_DEFINITIONS(-DUSE_SELECT=1)
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_WITH_LIBUUID)
|
||||
ADD_DEFINITIONS(-DUSE_LIBUUID=1)
|
||||
ENDIF()
|
||||
|
||||
IF (NOT PAHO_BUILD_SHARED AND NOT PAHO_BUILD_STATIC)
|
||||
MESSAGE(FATAL_ERROR "You must set either PAHO_BUILD_SHARED, PAHO_BUILD_STATIC, or both")
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_BUILD_SAMPLES AND NOT PAHO_WITH_SSL)
|
||||
MESSAGE(FATAL_ERROR "You must build with SSL to build the samples")
|
||||
ENDIF()
|
||||
|
||||
IF(PAHO_BUILD_DEB_PACKAGE)
|
||||
set(CMAKE_INSTALL_DOCDIR share/doc/libpaho-mqtt)
|
||||
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
|
||||
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY ">=")
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(src)
|
||||
IF(PAHO_BUILD_SAMPLES)
|
||||
ADD_SUBDIRECTORY(src/samples)
|
||||
ENDIF()
|
||||
|
||||
IF(PAHO_BUILD_DOCUMENTATION)
|
||||
ADD_SUBDIRECTORY(doc)
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_ENABLE_CPACK)
|
||||
### packaging settings
|
||||
FILE(GLOB samples "src/samples/*.c")
|
||||
INSTALL(FILES ${samples} DESTINATION ${CMAKE_INSTALL_DOCDIR}/samples)
|
||||
|
||||
SET(CPACK_PACKAGE_VENDOR "Eclipse Paho")
|
||||
SET(CPACK_PACKAGE_NAME "Eclipse-Paho-MQTT-C")
|
||||
|
||||
IF (WIN32)
|
||||
SET(CPACK_GENERATOR "ZIP")
|
||||
ELSEIF(PAHO_BUILD_DEB_PACKAGE)
|
||||
|
||||
SET(CPACK_GENERATOR "DEB")
|
||||
CONFIGURE_FILE(${CMAKE_SCRIPTS}/CPackDebConfig.cmake.in
|
||||
${CMAKE_BINARY_DIR}/CPackDebConfig.cmake @ONLY)
|
||||
SET(CPACK_PROJECT_CONFIG_FILE ${CMAKE_BINARY_DIR}/CPackDebConfig.cmake)
|
||||
ELSE()
|
||||
SET(CPACK_GENERATOR "TGZ")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
FILE(GLOB samples "src/samples/*.c")
|
||||
INSTALL(FILES ${samples} DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
ENDIF()
|
||||
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR ${PAHO_VERSION_MAJOR})
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR ${PAHO_VERSION_MINOR})
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH ${PAHO_VERSION_PATCH})
|
||||
INCLUDE(CPack)
|
||||
|
||||
IF(PAHO_ENABLE_TESTING)
|
||||
ENABLE_TESTING()
|
||||
INCLUDE_DIRECTORIES(test src)
|
||||
ADD_SUBDIRECTORY(test)
|
||||
ELSE()
|
||||
INCLUDE_DIRECTORIES(src)
|
||||
ENDIF()
|
||||
|
||||
# 添加调试输出
|
||||
MESSAGE(STATUS "Root CMake PAHO_WITH_SSL is set to: ${PAHO_WITH_SSL}")
|
||||
88
src/mqtt/externals/paho-mqtt-c/cmake/CPackDebConfig.cmake.in
vendored
Normal file
88
src/mqtt/externals/paho-mqtt-c/cmake/CPackDebConfig.cmake.in
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
IF (CPACK_GENERATOR MATCHES "DEB")
|
||||
FIND_PROGRAM(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
|
||||
IF (DPKG_PROGRAM)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${DPKG_PROGRAM} --print-architecture
|
||||
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
ELSE (DPKG_PROGRAM)
|
||||
MESSAGE(FATAL_ERROR "Could not find an architecture for the package")
|
||||
ENDIF (DPKG_PROGRAM)
|
||||
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND lsb_release -si
|
||||
OUTPUT_VARIABLE CPACK_DEBIAN_DIST_NAME
|
||||
RESULT_VARIABLE DIST_NAME_STATUS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
IF (DIST_NAME_STATUS)
|
||||
MESSAGE(FATAL_ERROR "Could not find a GNU/Linux distribution name")
|
||||
ENDIF (DIST_NAME_STATUS)
|
||||
|
||||
IF (CPACK_DEBIAN_DIST_NAME STREQUAL "")
|
||||
MESSAGE(FATAL_ERROR "Could not find a GNU/Linux distribution name")
|
||||
ENDIF ()
|
||||
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND lsb_release -sc
|
||||
OUTPUT_VARIABLE CPACK_DEBIAN_DIST_CODE
|
||||
RESULT_VARIABLE DIST_CODE_STATUS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
IF (DIST_NAME_STATUS)
|
||||
MESSAGE(FATAL_ERROR "Could not find a GNU/Linux distribution codename")
|
||||
ENDIF (DIST_NAME_STATUS)
|
||||
|
||||
IF (CPACK_DEBIAN_DIST_CODE STREQUAL "")
|
||||
MESSAGE(FATAL_ERROR "Could not find a GNU/Linux distribution codename")
|
||||
ENDIF ()
|
||||
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR @PAHO_VERSION_MAJOR@)
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR @PAHO_VERSION_MINOR@)
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH @PAHO_VERSION_PATCH@)
|
||||
SET(PACKAGE_VERSION
|
||||
"${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
|
||||
IF (PACKAGE_VERSION STREQUAL "")
|
||||
MESSAGE(FATAL_ERROR "Could not find a version number for the package")
|
||||
ENDIF ()
|
||||
|
||||
SET(PAHO_WITH_SSL @PAHO_WITH_SSL@)
|
||||
|
||||
MESSAGE("Package version: ${PACKAGE_VERSION}")
|
||||
MESSAGE("Package built for: ${CPACK_DEBIAN_DIST_NAME} ${CPACK_DEBIAN_DIST_CODE}")
|
||||
IF(PAHO_WITH_SSL)
|
||||
MESSAGE("Package built with ssl-enabled binaries too")
|
||||
ENDIF()
|
||||
|
||||
# Additional lines to a paragraph should start with " "; paragraphs should
|
||||
# be separated with a " ." line
|
||||
SET(CPACK_PACKAGE_NAME "libpaho-mqtt")
|
||||
SET(CPACK_PACKAGE_CONTACT "Eclipse")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Eclipse Paho MQTT C client")
|
||||
SET(CPACK_DEBIAN_PACKAGE_NAME ${CPACK_PACKAGE_NAME})
|
||||
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER
|
||||
"Genis Riera Perez <genis.riera.perez@gmail.com>")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Eclipse Paho MQTT C client library")
|
||||
SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
SET(CPACK_DEBIAN_PACKAGE_VERSION ${PACKAGE_VERSION})
|
||||
SET(CPACK_DEBIAN_PACKAGE_SECTION "net")
|
||||
SET(CPACK_DEBIAN_PACKAGE_CONFLICTS ${CPACK_PACKAGE_NAME})
|
||||
SET(CPACK_PACKAGE_FILE_NAME
|
||||
"${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
|
||||
|
||||
UNSET(PACKAGE_VERSION CACHE)
|
||||
UNSET(CPACK_DEBIAN_PACKAGE_VERSION CACHE)
|
||||
|
||||
#
|
||||
# From CMakeDebHelper
|
||||
# See http://www.cmake.org/Wiki/CMake:CPackPackageGenerators#Overall_usage_.28common_to_all_generators.29
|
||||
#
|
||||
|
||||
# When the DEB-generator runs, we want him to run our install-script
|
||||
#set( CPACK_INSTALL_SCRIPT ${CPACK_DEBIAN_INSTALL_SCRIPT} )
|
||||
|
||||
ENDIF()
|
||||
10
src/mqtt/externals/paho-mqtt-c/cmake/toolchain.linux-arm11.cmake
vendored
Normal file
10
src/mqtt/externals/paho-mqtt-c/cmake/toolchain.linux-arm11.cmake
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# path to compiler and utilities
|
||||
# specify the cross compiler
|
||||
SET(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
|
||||
# Name of the target platform
|
||||
SET(CMAKE_SYSTEM_NAME Linux)
|
||||
SET(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
|
||||
# Version of the system
|
||||
SET(CMAKE_SYSTEM_VERSION 1)
|
||||
15
src/mqtt/externals/paho-mqtt-c/cmake/toolchain.win32.cmake
vendored
Normal file
15
src/mqtt/externals/paho-mqtt-c/cmake/toolchain.win32.cmake
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Name of the target platform
|
||||
SET(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
# Version of the system
|
||||
SET(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
# specify the cross compiler
|
||||
SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
|
||||
SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
|
||||
SET(CMAKE_RC_COMPILER_ENV_VAR "RC")
|
||||
SET(CMAKE_RC_COMPILER "")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS
|
||||
"-fdata-sections -ffunction-sections -Wl,--enable-stdcall-fixup -static-libgcc -static -lpthread" CACHE STRING "" FORCE)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS
|
||||
"-fdata-sections -ffunction-sections -Wl,--enable-stdcall-fixup -static-libgcc -static -lpthread" CACHE STRING "" FORCE)
|
||||
15
src/mqtt/externals/paho-mqtt-c/cmake/toolchain.win64.cmake
vendored
Normal file
15
src/mqtt/externals/paho-mqtt-c/cmake/toolchain.win64.cmake
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Name of the target platform
|
||||
SET(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
# Version of the system
|
||||
SET(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
# specify the cross compiler
|
||||
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
|
||||
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
|
||||
SET(CMAKE_RC_COMPILER_ENV_VAR "RC")
|
||||
SET(CMAKE_RC_COMPILER "")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS
|
||||
"-fdata-sections -ffunction-sections -Wl,--enable-stdcall-fixup -static-libgcc -static -lpthread" CACHE STRING "" FORCE)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS
|
||||
"-fdata-sections -ffunction-sections -Wl,--enable-stdcall-fixup -static-libgcc -static -lpthread" CACHE STRING "" FORCE)
|
||||
352
src/mqtt/externals/paho-mqtt-c/src/Base64.c
vendored
Normal file
352
src/mqtt/externals/paho-mqtt-c/src/Base64.c
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2019 Wind River Systems, Inc. All Rights Reserved.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Keith Holman - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "Base64.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, const char *in, b64_size_t in_len )
|
||||
{
|
||||
b64_size_t ret = 0u;
|
||||
DWORD dw_out_len = (DWORD)out_len;
|
||||
if ( CryptStringToBinaryA( in, in_len, CRYPT_STRING_BASE64, out, &dw_out_len, NULL, NULL ) )
|
||||
ret = (b64_size_t)dw_out_len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
b64_size_t Base64_encode( char *out, b64_size_t out_len, const b64_data_t *in, b64_size_t in_len )
|
||||
{
|
||||
b64_size_t ret = 0u;
|
||||
DWORD dw_out_len = (DWORD)out_len;
|
||||
if ( CryptBinaryToStringA( in, in_len, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, out, &dw_out_len ) )
|
||||
ret = (b64_size_t)dw_out_len;
|
||||
return ret;
|
||||
}
|
||||
#else /* if defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
#if defined(OPENSSL)
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
static b64_size_t Base64_encodeDecode(
|
||||
char *out, b64_size_t out_len, const char *in, b64_size_t in_len, int encode )
|
||||
{
|
||||
b64_size_t ret = 0u;
|
||||
if ( in_len > 0u )
|
||||
{
|
||||
int rv;
|
||||
BIO *bio, *b64, *b_in, *b_out;
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
b64 = BIO_push(b64, bio);
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); /* ignore new-lines */
|
||||
|
||||
if ( encode )
|
||||
{
|
||||
b_in = bio;
|
||||
b_out = b64;
|
||||
}
|
||||
else
|
||||
{
|
||||
b_in = b64;
|
||||
b_out = bio;
|
||||
}
|
||||
|
||||
rv = BIO_write(b_out, in, (int)in_len);
|
||||
BIO_flush(b_out); /* indicate end of encoding */
|
||||
|
||||
if ( rv > 0 )
|
||||
{
|
||||
rv = BIO_read(b_in, out, (int)out_len);
|
||||
if ( rv > 0 )
|
||||
{
|
||||
ret = (b64_size_t)rv;
|
||||
if ( out_len > ret )
|
||||
out[ret] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free_all(b64); /* free all used memory */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, const char *in, b64_size_t in_len )
|
||||
{
|
||||
return Base64_encodeDecode( (char*)out, out_len, in, in_len, 0 );
|
||||
}
|
||||
|
||||
b64_size_t Base64_encode( char *out, b64_size_t out_len, const b64_data_t *in, b64_size_t in_len )
|
||||
{
|
||||
return Base64_encodeDecode( out, out_len, (const char*)in, in_len, 1 );
|
||||
}
|
||||
|
||||
#else /* if defined(OPENSSL) */
|
||||
b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, const char *in, b64_size_t in_len )
|
||||
{
|
||||
#define NV 64
|
||||
static const unsigned char BASE64_DECODE_TABLE[] =
|
||||
{
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 0-15 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 16-31 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, 62, NV, NV, NV, 63, /* 32-47 */
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NV, NV, NV, NV, NV, NV, /* 48-63 */
|
||||
NV, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64-79 */
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NV, NV, NV, NV, NV, /* 80-95 */
|
||||
NV, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96-111 */
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NV, NV, NV, NV, NV, /* 112-127 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 128-143 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 144-159 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 160-175 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 176-191 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 192-207 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 208-223 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 224-239 */
|
||||
NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV /* 240-255 */
|
||||
};
|
||||
|
||||
b64_size_t ret = 0u;
|
||||
b64_size_t out_count = 0u;
|
||||
|
||||
/* in valid base64, length must be multiple of 4's: 0, 4, 8, 12, etc */
|
||||
while ( in_len > 3u && out_count < out_len )
|
||||
{
|
||||
int i;
|
||||
unsigned char c[4];
|
||||
for ( i = 0; i < 4; ++i, ++in )
|
||||
c[i] = BASE64_DECODE_TABLE[(int)(*in)];
|
||||
in_len -= 4u;
|
||||
|
||||
/* first byte */
|
||||
*out = c[0] << 2;
|
||||
*out |= (c[1] & ~0xF) >> 4;
|
||||
++out;
|
||||
++out_count;
|
||||
|
||||
if ( out_count < out_len )
|
||||
{
|
||||
/* second byte */
|
||||
*out = (c[1] & 0xF) << 4;
|
||||
if ( c[2] < NV )
|
||||
{
|
||||
*out |= (c[2] & ~0x3) >> 2;
|
||||
++out;
|
||||
++out_count;
|
||||
|
||||
if ( out_count < out_len )
|
||||
{
|
||||
/* third byte */
|
||||
*out = (c[2] & 0x3) << 6;
|
||||
if ( c[3] < NV )
|
||||
{
|
||||
*out |= c[3];
|
||||
++out;
|
||||
++out_count;
|
||||
}
|
||||
else
|
||||
in_len = 0u;
|
||||
}
|
||||
}
|
||||
else
|
||||
in_len = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
if ( out_count <= out_len )
|
||||
{
|
||||
ret = out_count;
|
||||
if ( out_count < out_len )
|
||||
*out = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
b64_size_t Base64_encode( char *out, b64_size_t out_len, const b64_data_t *in, b64_size_t in_len )
|
||||
{
|
||||
static const char BASE64_ENCODE_TABLE[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/=";
|
||||
b64_size_t ret = 0u;
|
||||
b64_size_t out_count = 0u;
|
||||
|
||||
while ( in_len > 0u && out_count < out_len )
|
||||
{
|
||||
int i;
|
||||
unsigned char c[] = { 0, 0, 64, 64 }; /* index of '=' char */
|
||||
|
||||
/* first character */
|
||||
i = *in;
|
||||
c[0] = (i & ~0x3) >> 2;
|
||||
|
||||
/* second character */
|
||||
c[1] = (i & 0x3) << 4;
|
||||
--in_len;
|
||||
if ( in_len > 0u )
|
||||
{
|
||||
++in;
|
||||
i = *in;
|
||||
c[1] |= (i & ~0xF) >> 4;
|
||||
|
||||
/* third character */
|
||||
c[2] = (i & 0xF) << 2;
|
||||
--in_len;
|
||||
if ( in_len > 0u )
|
||||
{
|
||||
++in;
|
||||
i = *in;
|
||||
c[2] |= (i & ~0x3F) >> 6;
|
||||
|
||||
/* fourth character */
|
||||
c[3] = (i & 0x3F);
|
||||
--in_len;
|
||||
++in;
|
||||
}
|
||||
}
|
||||
|
||||
/* encode the characters */
|
||||
out_count += 4u;
|
||||
for ( i = 0; i < 4 && out_count <= out_len; ++i, ++out )
|
||||
*out = BASE64_ENCODE_TABLE[c[i]];
|
||||
}
|
||||
|
||||
if ( out_count <= out_len )
|
||||
{
|
||||
if ( out_count < out_len )
|
||||
*out = '\0';
|
||||
ret = out_count;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* else if defined(OPENSSL) */
|
||||
#endif /* if else defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
b64_size_t Base64_decodeLength( const char *in, b64_size_t in_len )
|
||||
{
|
||||
b64_size_t pad = 0u;
|
||||
|
||||
if ( in && in_len > 1u )
|
||||
pad += ( in[in_len - 2u] == '=' ? 1u : 0u );
|
||||
if ( in && in_len > 0u )
|
||||
pad += ( in[in_len - 1u] == '=' ? 1u : 0u );
|
||||
return (in_len / 4u * 3u) - pad;
|
||||
}
|
||||
|
||||
b64_size_t Base64_encodeLength( const b64_data_t *in, b64_size_t in_len )
|
||||
{
|
||||
return ((4u * in_len / 3u) + 3u) & ~0x3;
|
||||
}
|
||||
|
||||
#if defined(BASE64_TEST)
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TEST_EXPECT(i,x) if (!(x)) {fprintf( stderr, "failed test: %s (for i == %d)\n", #x, i ); ++fails;}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct _td
|
||||
{
|
||||
const char *in;
|
||||
const char *out;
|
||||
};
|
||||
|
||||
int i;
|
||||
unsigned int fails = 0u;
|
||||
struct _td test_data[] = {
|
||||
{ "", "" },
|
||||
{ "p", "cA==" },
|
||||
{ "pa", "cGE=" },
|
||||
{ "pah", "cGFo" },
|
||||
{ "paho", "cGFobw==" },
|
||||
{ "paho ", "cGFobyA=" },
|
||||
{ "paho w", "cGFobyB3" },
|
||||
{ "paho wi", "cGFobyB3aQ==" },
|
||||
{ "paho wit", "cGFobyB3aXQ=" },
|
||||
{ "paho with", "cGFobyB3aXRo" },
|
||||
{ "paho with ", "cGFobyB3aXRoIA==" },
|
||||
{ "paho with w", "cGFobyB3aXRoIHc=" },
|
||||
{ "paho with we", "cGFobyB3aXRoIHdl" },
|
||||
{ "paho with web", "cGFobyB3aXRoIHdlYg==" },
|
||||
{ "paho with webs", "cGFobyB3aXRoIHdlYnM=" },
|
||||
{ "paho with webso", "cGFobyB3aXRoIHdlYnNv" },
|
||||
{ "paho with websoc", "cGFobyB3aXRoIHdlYnNvYw==" },
|
||||
{ "paho with websock", "cGFobyB3aXRoIHdlYnNvY2s=" },
|
||||
{ "paho with websocke", "cGFobyB3aXRoIHdlYnNvY2tl" },
|
||||
{ "paho with websocket", "cGFobyB3aXRoIHdlYnNvY2tldA==" },
|
||||
{ "paho with websockets", "cGFobyB3aXRoIHdlYnNvY2tldHM=" },
|
||||
{ "paho with websockets.", "cGFobyB3aXRoIHdlYnNvY2tldHMu" },
|
||||
{ "The quick brown fox jumps over the lazy dog",
|
||||
"VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==" },
|
||||
{ "Man is distinguished, not only by his reason, but by this singular passion from\n"
|
||||
"other animals, which is a lust of the mind, that by a perseverance of delight\n"
|
||||
"in the continued and indefatigable generation of knowledge, exceeds the short\n"
|
||||
"vehemence of any carnal pleasure.",
|
||||
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"
|
||||
"IHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"
|
||||
"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu"
|
||||
"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"
|
||||
"ZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* decode tests */
|
||||
i = 0;
|
||||
while ( test_data[i].in != NULL )
|
||||
{
|
||||
int r;
|
||||
char out[512u];
|
||||
r = Base64_decode( out, sizeof(out), test_data[i].out, strlen(test_data[i].out) );
|
||||
TEST_EXPECT( i, r == strlen(test_data[i].in) && strncmp(out, test_data[i].in, strlen(test_data[i].in)) == 0 );
|
||||
++i;
|
||||
}
|
||||
|
||||
/* decode length tests */
|
||||
i = 0;
|
||||
while ( test_data[i].in != NULL )
|
||||
{
|
||||
TEST_EXPECT( i, Base64_decodeLength(test_data[i].out, strlen(test_data[i].out)) == strlen(test_data[i].in));
|
||||
++i;
|
||||
}
|
||||
|
||||
/* encode tests */
|
||||
i = 0;
|
||||
while ( test_data[i].in != NULL )
|
||||
{
|
||||
int r;
|
||||
char out[512u];
|
||||
r = Base64_encode( out, sizeof(out), test_data[i].in, strlen(test_data[i].in) );
|
||||
TEST_EXPECT( i, r == strlen(test_data[i].out) && strncmp(out, test_data[i].out, strlen(test_data[i].out)) == 0 );
|
||||
++i;
|
||||
}
|
||||
|
||||
/* encode length tests */
|
||||
i = 0;
|
||||
while ( test_data[i].in != NULL )
|
||||
{
|
||||
TEST_EXPECT( i, Base64_encodeLength(test_data[i].in, strlen(test_data[i].in)) == strlen(test_data[i].out) );
|
||||
++i;
|
||||
}
|
||||
|
||||
if ( fails )
|
||||
printf( "%u test failed!\n", fails );
|
||||
else
|
||||
printf( "all tests passed\n" );
|
||||
return fails;
|
||||
}
|
||||
#endif /* if defined(BASE64_TEST) */
|
||||
83
src/mqtt/externals/paho-mqtt-c/src/Base64.h
vendored
Normal file
83
src/mqtt/externals/paho-mqtt-c/src/Base64.h
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Keith Holman - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(BASE64_H)
|
||||
#define BASE64_H
|
||||
|
||||
/** type for size of a buffer, it saves passing around @p size_t (unsigned long long or unsigned long int) */
|
||||
typedef unsigned int b64_size_t;
|
||||
/** type for raw base64 data */
|
||||
typedef unsigned char b64_data_t;
|
||||
|
||||
/**
|
||||
* Decodes base64 data
|
||||
*
|
||||
* @param[out] out decoded data
|
||||
* @param[in] out_len length of output buffer
|
||||
* @param[in] in base64 string to decode
|
||||
* @param[in] in_len length of input buffer
|
||||
*
|
||||
* @return the amount of data decoded
|
||||
*
|
||||
* @see Base64_decodeLength
|
||||
* @see Base64_encode
|
||||
*/
|
||||
b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len,
|
||||
const char *in, b64_size_t in_len );
|
||||
|
||||
/**
|
||||
* Size of buffer required to decode base64 data
|
||||
*
|
||||
* @param[in] in base64 string to decode
|
||||
* @param[in] in_len length of input buffer
|
||||
*
|
||||
* @return the size of buffer the decoded string would require
|
||||
*
|
||||
* @see Base64_decode
|
||||
* @see Base64_encodeLength
|
||||
*/
|
||||
b64_size_t Base64_decodeLength( const char *in, b64_size_t in_len );
|
||||
|
||||
/**
|
||||
* Encodes base64 data
|
||||
*
|
||||
* @param[out] out encode base64 string
|
||||
* @param[in] out_len length of output buffer
|
||||
* @param[in] in raw data to encode
|
||||
* @param[in] in_len length of input buffer
|
||||
*
|
||||
* @return the amount of data encoded
|
||||
*
|
||||
* @see Base64_decode
|
||||
* @see Base64_encodeLength
|
||||
*/
|
||||
b64_size_t Base64_encode( char *out, b64_size_t out_len,
|
||||
const b64_data_t *in, b64_size_t in_len );
|
||||
|
||||
/**
|
||||
* Size of buffer required to encode base64 data
|
||||
*
|
||||
* @param[in] in raw data to encode
|
||||
* @param[in] in_len length of input buffer
|
||||
*
|
||||
* @return the size of buffer the encoded string would require
|
||||
*
|
||||
* @see Base64_decodeLength
|
||||
* @see Base64_encode
|
||||
*/
|
||||
b64_size_t Base64_encodeLength( const b64_data_t *in, b64_size_t in_len );
|
||||
|
||||
#endif /* BASE64_H */
|
||||
380
src/mqtt/externals/paho-mqtt-c/src/CMakeLists.txt
vendored
Normal file
380
src/mqtt/externals/paho-mqtt-c/src/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
#*******************************************************************************
|
||||
# Copyright (c) 2015, 2023 logi.cals GmbH and others
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v2.0
|
||||
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at
|
||||
# https://www.eclipse.org/legal/epl-2.0/
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Rainer Poisel - initial version
|
||||
# Ian Craggs (IBM Corp.) - merge master
|
||||
# Ian Craggs - update for MQTTV5 support
|
||||
#*******************************************************************************/
|
||||
|
||||
# Note: on OS X you should install XCode and the associated command-line tools
|
||||
|
||||
## compilation/linkage settings
|
||||
|
||||
CONFIGURE_FILE(VersionInfo.h.in
|
||||
${CMAKE_BINARY_DIR}/VersionInfo.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
SET(common_src
|
||||
MQTTTime.c
|
||||
MQTTProtocolClient.c
|
||||
Clients.c
|
||||
utf-8.c
|
||||
MQTTPacket.c
|
||||
MQTTPacketOut.c
|
||||
Messages.c
|
||||
Tree.c
|
||||
Socket.c
|
||||
Log.c
|
||||
MQTTPersistence.c
|
||||
Thread.c
|
||||
MQTTProtocolOut.c
|
||||
MQTTPersistenceDefault.c
|
||||
SocketBuffer.c
|
||||
LinkedList.c
|
||||
MQTTProperties.c
|
||||
MQTTReasonCodes.c
|
||||
Base64.c
|
||||
SHA1.c
|
||||
WebSocket.c
|
||||
Proxy.c
|
||||
)
|
||||
|
||||
IF (NOT PAHO_HIGH_PERFORMANCE)
|
||||
SET(common_src ${common_src}
|
||||
StackTrace.c
|
||||
Heap.c
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
IF (WIN32)
|
||||
SET(LIBS_SYSTEM ws2_32 crypt32 RpcRT4)
|
||||
ELSEIF (UNIX)
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
SET(LIBS_SYSTEM c dl pthread rt)
|
||||
# anl is only available with glibc so check if it is found before using
|
||||
# it or build will fail on uclibc or musl
|
||||
FIND_LIBRARY(LIB_ANL anl)
|
||||
IF(LIB_ANL)
|
||||
SET(LIBS_SYSTEM "${LIBS_SYSTEM}" anl)
|
||||
ENDIF()
|
||||
IF(PAHO_WITH_LIBUUID)
|
||||
SET(LIBS_SYSTEM "${LIBS_SYSTEM}" uuid)
|
||||
ENDIF()
|
||||
ADD_DEFINITIONS(-D_GNU_SOURCE -fvisibility=hidden)
|
||||
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Android")
|
||||
SET(LIBS_SYSTEM c dl)
|
||||
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
SET(LIBS_SYSTEM compat pthread)
|
||||
ELSE()
|
||||
SET(LIBS_SYSTEM c pthread)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_BUILD_SHARED)
|
||||
# common compilation for libpaho-mqtt3c and libpaho-mqtt3a
|
||||
ADD_LIBRARY(common_obj OBJECT ${common_src})
|
||||
SET_TARGET_PROPERTIES(common_obj PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
COMPILE_DEFINITIONS "PAHO_MQTT_EXPORTS=1")
|
||||
ADD_EXECUTABLE(MQTTVersion MQTTVersion.c)
|
||||
SET_TARGET_PROPERTIES(MQTTVersion PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
COMPILE_DEFINITIONS "PAHO_MQTT_IMPORTS=1")
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_BUILD_STATIC)
|
||||
ADD_LIBRARY(common_obj_static OBJECT ${common_src})
|
||||
SET_TARGET_PROPERTIES(common_obj_static PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
COMPILE_DEFINITIONS "PAHO_MQTT_STATIC=1")
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_BUILD_SHARED)
|
||||
ADD_LIBRARY(paho-mqtt3c SHARED $<TARGET_OBJECTS:common_obj> MQTTClient.c)
|
||||
ADD_LIBRARY(paho-mqtt3a SHARED $<TARGET_OBJECTS:common_obj> MQTTAsync.c MQTTAsyncUtils.c)
|
||||
|
||||
TARGET_LINK_LIBRARIES(paho-mqtt3c ${LIBS_SYSTEM})
|
||||
TARGET_LINK_LIBRARIES(paho-mqtt3a ${LIBS_SYSTEM})
|
||||
TARGET_LINK_LIBRARIES(MQTTVersion paho-mqtt3a paho-mqtt3c ${LIBS_SYSTEM})
|
||||
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3c paho-mqtt3a PROPERTIES
|
||||
VERSION ${CLIENT_VERSION}
|
||||
SOVERSION ${PAHO_VERSION_MAJOR}
|
||||
COMPILE_DEFINITIONS "PAHO_MQTT_EXPORTS=1")
|
||||
|
||||
IF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
SET(MQTTCLIENT_ENTRY_POINT _MQTTClient_init)
|
||||
SET(MQTTASYNC_ENTRY_POINT _MQTTAsync_init)
|
||||
ELSEIF (NOT WIN32)
|
||||
SET(MQTTCLIENT_ENTRY_POINT MQTTClient_init)
|
||||
SET(MQTTASYNC_ENTRY_POINT MQTTAsync_init)
|
||||
ENDIF()
|
||||
|
||||
IF (NOT WIN32)
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3c PROPERTIES
|
||||
LINK_FLAGS "-Wl,-init,${MQTTCLIENT_ENTRY_POINT}")
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3a PROPERTIES
|
||||
LINK_FLAGS "-Wl,-init,${MQTTASYNC_ENTRY_POINT}")
|
||||
ENDIF()
|
||||
|
||||
FOREACH(TARGET paho-mqtt3c paho-mqtt3a)
|
||||
TARGET_INCLUDE_DIRECTORIES(${TARGET}
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR})
|
||||
ENDFOREACH()
|
||||
|
||||
INSTALL(TARGETS paho-mqtt3c paho-mqtt3a
|
||||
EXPORT eclipse-paho-mqtt-cTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
INSTALL(TARGETS MQTTVersion
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_BUILD_STATIC)
|
||||
ADD_LIBRARY(paho-mqtt3c-static STATIC $<TARGET_OBJECTS:common_obj_static> MQTTClient.c)
|
||||
ADD_LIBRARY(paho-mqtt3a-static STATIC $<TARGET_OBJECTS:common_obj_static> MQTTAsync.c MQTTAsyncUtils.c)
|
||||
|
||||
TARGET_LINK_LIBRARIES(paho-mqtt3c-static ${LIBS_SYSTEM})
|
||||
TARGET_LINK_LIBRARIES(paho-mqtt3a-static ${LIBS_SYSTEM})
|
||||
IF (NOT WIN32)
|
||||
SET_TARGET_PROPERTIES(paho-mqtt3c-static PROPERTIES OUTPUT_NAME paho-mqtt3c)
|
||||
SET_TARGET_PROPERTIES(paho-mqtt3a-static PROPERTIES OUTPUT_NAME paho-mqtt3a)
|
||||
ENDIF()
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3c-static paho-mqtt3a-static PROPERTIES
|
||||
VERSION ${CLIENT_VERSION}
|
||||
SOVERSION ${PAHO_VERSION_MAJOR}
|
||||
COMPILE_DEFINITIONS "PAHO_MQTT_STATIC=1")
|
||||
|
||||
FOREACH(TARGET paho-mqtt3c-static paho-mqtt3a-static)
|
||||
TARGET_INCLUDE_DIRECTORIES(${TARGET}
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR})
|
||||
ENDFOREACH()
|
||||
|
||||
message("PAHO_WITH_SSL: ${PAHO_WITH_SSL}")
|
||||
if(PAHO_WITH_SSL)
|
||||
target_compile_definitions(paho-mqtt3a-static PRIVATE OPENSSL=1)
|
||||
message("paho-mqtt3a-static is compiled with SSL")
|
||||
endif()
|
||||
|
||||
IF (NOT PAHO_BUILD_SHARED)
|
||||
INSTALL(TARGETS paho-mqtt3c-static paho-mqtt3a-static
|
||||
EXPORT eclipse-paho-mqtt-cTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
ELSE()
|
||||
INSTALL(TARGETS paho-mqtt3c-static paho-mqtt3a-static
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
INSTALL(FILES MQTTAsync.h MQTTClient.h MQTTClientPersistence.h MQTTProperties.h MQTTReasonCodes.h MQTTSubscribeOpts.h MQTTExportDeclarations.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
IF (PAHO_WITH_SSL)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(NOT OPENSSL_FOUND)
|
||||
message(FATAL_ERROR "OpenSSL not found")
|
||||
endif()
|
||||
message(STATUS "OpenSSL found: ${OPENSSL_INCLUDE_DIR}")
|
||||
|
||||
IF (PAHO_BUILD_SHARED)
|
||||
## common compilation for libpaho-mqtt3cs and libpaho-mqtt3as
|
||||
## Note: SSL libraries must be recompiled due ifdefs
|
||||
ADD_LIBRARY(common_ssl_obj OBJECT ${common_src})
|
||||
TARGET_INCLUDE_DIRECTORIES(common_ssl_obj PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
SET_PROPERTY(TARGET common_ssl_obj PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
SET_PROPERTY(TARGET common_ssl_obj PROPERTY COMPILE_DEFINITIONS "OPENSSL=1;PAHO_MQTT_EXPORTS=1")
|
||||
|
||||
ADD_LIBRARY(paho-mqtt3cs SHARED $<TARGET_OBJECTS:common_ssl_obj> MQTTClient.c SSLSocket.c)
|
||||
ADD_LIBRARY(paho-mqtt3as SHARED $<TARGET_OBJECTS:common_ssl_obj> MQTTAsync.c MQTTAsyncUtils.c SSLSocket.c)
|
||||
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3cs paho-mqtt3as PROPERTIES
|
||||
VERSION ${CLIENT_VERSION}
|
||||
SOVERSION ${PAHO_VERSION_MAJOR}
|
||||
COMPILE_DEFINITIONS "OPENSSL=1;PAHO_MQTT_EXPORTS=1")
|
||||
|
||||
IF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
SET(MQTTCLIENT_ENTRY_POINT _MQTTClient_init)
|
||||
SET(MQTTASYNC_ENTRY_POINT _MQTTAsync_init)
|
||||
ELSEIF (NOT WIN32)
|
||||
SET(MQTTCLIENT_ENTRY_POINT MQTTClient_init)
|
||||
SET(MQTTASYNC_ENTRY_POINT MQTTAsync_init)
|
||||
ENDIF()
|
||||
|
||||
IF (NOT WIN32)
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3cs PROPERTIES
|
||||
LINK_FLAGS "-Wl,-init,${MQTTCLIENT_ENTRY_POINT}")
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3as PROPERTIES
|
||||
LINK_FLAGS "-Wl,-init,${MQTTASYNC_ENTRY_POINT}")
|
||||
ENDIF()
|
||||
|
||||
FOREACH(TARGET paho-mqtt3cs paho-mqtt3as)
|
||||
TARGET_INCLUDE_DIRECTORIES(${TARGET}
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR})
|
||||
TARGET_LINK_LIBRARIES(${TARGET}
|
||||
PUBLIC
|
||||
OpenSSL::SSL OpenSSL::Crypto ${LIBS_SYSTEM})
|
||||
ENDFOREACH()
|
||||
INSTALL(TARGETS paho-mqtt3cs paho-mqtt3as
|
||||
EXPORT eclipse-paho-mqtt-cTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
ENDIF()
|
||||
|
||||
IF (PAHO_BUILD_STATIC)
|
||||
## common compilation for libpaho-mqtt3cs and libpaho-mqtt3as
|
||||
## Note: SSL libraries must be recompiled due ifdefs
|
||||
ADD_LIBRARY(common_ssl_obj_static OBJECT ${common_src})
|
||||
TARGET_INCLUDE_DIRECTORIES(common_ssl_obj_static PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
SET_PROPERTY(TARGET common_ssl_obj_static PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
SET_PROPERTY(TARGET common_ssl_obj_static PROPERTY COMPILE_DEFINITIONS "OPENSSL=1;PAHO_MQTT_STATIC=1")
|
||||
|
||||
ADD_LIBRARY(paho-mqtt3cs-static STATIC $<TARGET_OBJECTS:common_ssl_obj_static> MQTTClient.c SSLSocket.c)
|
||||
ADD_LIBRARY(paho-mqtt3as-static STATIC $<TARGET_OBJECTS:common_ssl_obj_static> MQTTAsync.c MQTTAsyncUtils.c SSLSocket.c)
|
||||
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3cs-static paho-mqtt3as-static PROPERTIES
|
||||
VERSION ${CLIENT_VERSION}
|
||||
SOVERSION ${PAHO_VERSION_MAJOR}
|
||||
COMPILE_DEFINITIONS "OPENSSL=1;PAHO_MQTT_STATIC=1")
|
||||
IF (NOT WIN32)
|
||||
SET_TARGET_PROPERTIES(paho-mqtt3cs-static PROPERTIES OUTPUT_NAME paho-mqtt3cs)
|
||||
SET_TARGET_PROPERTIES(paho-mqtt3as-static PROPERTIES OUTPUT_NAME paho-mqtt3as)
|
||||
ENDIF()
|
||||
|
||||
IF(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
SET(MQTTCLIENT_ENTRY_POINT _MQTTClient_init)
|
||||
SET(MQTTASYNC_ENTRY_POINT _MQTTAsync_init)
|
||||
ELSEIF (NOT WIN32)
|
||||
SET(MQTTCLIENT_ENTRY_POINT MQTTClient_init)
|
||||
SET(MQTTASYNC_ENTRY_POINT MQTTAsync_init)
|
||||
ENDIF()
|
||||
|
||||
IF (NOT WIN32)
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3cs-static PROPERTIES
|
||||
LINK_FLAGS "-Wl,-init,${MQTTCLIENT_ENTRY_POINT}")
|
||||
SET_TARGET_PROPERTIES(
|
||||
paho-mqtt3as-static PROPERTIES
|
||||
LINK_FLAGS "-Wl,-init,${MQTTASYNC_ENTRY_POINT}")
|
||||
ENDIF()
|
||||
|
||||
IF (NOT PAHO_BUILD_SHARED)
|
||||
INSTALL(TARGETS paho-mqtt3cs-static paho-mqtt3as-static
|
||||
EXPORT eclipse-paho-mqtt-cTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
ELSE()
|
||||
INSTALL(TARGETS paho-mqtt3cs-static paho-mqtt3as-static
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
ENDIF()
|
||||
FOREACH(TARGET paho-mqtt3cs-static paho-mqtt3as-static)
|
||||
TARGET_INCLUDE_DIRECTORIES(${TARGET}
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR})
|
||||
TARGET_LINK_LIBRARIES(${TARGET}
|
||||
PUBLIC
|
||||
OpenSSL::SSL OpenSSL::Crypto ${LIBS_SYSTEM})
|
||||
ENDFOREACH()
|
||||
|
||||
# 为所有静态库目标添加 OpenSSL 包含目录
|
||||
IF (PAHO_BUILD_STATIC)
|
||||
# 已有的 paho-mqtt3a-static
|
||||
target_include_directories(paho-mqtt3a-static
|
||||
PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
|
||||
|
||||
# 为 paho-mqtt3cs-static 添加
|
||||
target_include_directories(paho-mqtt3cs-static
|
||||
PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
|
||||
|
||||
# 为 paho-mqtt3c-static 添加
|
||||
target_include_directories(paho-mqtt3c-static
|
||||
PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
|
||||
|
||||
# 确保所有静态库都定义了 OPENSSL 宏
|
||||
foreach(target paho-mqtt3a-static paho-mqtt3cs-static paho-mqtt3c-static)
|
||||
target_compile_definitions(${target} PRIVATE OPENSSL=1)
|
||||
message("${target} is compiled with SSL")
|
||||
endforeach()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
INSTALL(EXPORT eclipse-paho-mqtt-cTargets
|
||||
FILE eclipse-paho-mqtt-cConfig.cmake
|
||||
NAMESPACE eclipse-paho-mqtt-c::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/eclipse-paho-mqtt-c)
|
||||
|
||||
INCLUDE(CMakePackageConfigHelpers)
|
||||
WRITE_BASIC_PACKAGE_VERSION_FILE("eclipse-paho-mqtt-cConfigVersion.cmake"
|
||||
VERSION ${CLIENT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
INSTALL(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eclipse-paho-mqtt-cConfigVersion.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/eclipse-paho-mqtt-c)
|
||||
|
||||
# Base64 test
|
||||
ADD_EXECUTABLE( Base64Test EXCLUDE_FROM_ALL Base64.c Base64.h )
|
||||
TARGET_COMPILE_DEFINITIONS( Base64Test PUBLIC "-DBASE64_TEST" )
|
||||
IF (PAHO_WITH_SSL)
|
||||
ADD_EXECUTABLE( Base64TestOpenSSL EXCLUDE_FROM_ALL Base64.c Base64.h )
|
||||
TARGET_LINK_LIBRARIES( Base64TestOpenSSL OpenSSL::SSL OpenSSL::Crypto)
|
||||
TARGET_COMPILE_DEFINITIONS( Base64TestOpenSSL PUBLIC "-DBASE64_TEST -DOPENSSL=1" )
|
||||
ENDIF (PAHO_WITH_SSL)
|
||||
|
||||
# SHA1 test
|
||||
ADD_EXECUTABLE( Sha1Test EXCLUDE_FROM_ALL SHA1.c SHA1.h )
|
||||
TARGET_COMPILE_DEFINITIONS( Sha1Test PUBLIC "-DSHA1_TEST" )
|
||||
IF (PAHO_WITH_SSL)
|
||||
ADD_EXECUTABLE( Sha1TestOpenSSL EXCLUDE_FROM_ALL SHA1.c SHA1.h )
|
||||
TARGET_LINK_LIBRARIES( Sha1TestOpenSSL OpenSSL::SSL OpenSSL::Crypto)
|
||||
TARGET_COMPILE_DEFINITIONS( Sha1TestOpenSSL PUBLIC "-DSHA1_TEST -DOPENSSL=1" )
|
||||
ENDIF (PAHO_WITH_SSL)
|
||||
|
||||
if(WIN32)
|
||||
option(PAHO_BUILD_STATIC "Build static library" TRUE)
|
||||
option(PAHO_BUILD_SHARED "Build shared library (DLL)" FALSE)
|
||||
option(PAHO_WITH_SSL "Build SSL-enabled library" FALSE)
|
||||
else()
|
||||
option(PAHO_BUILD_STATIC "Build static library" TRUE)
|
||||
option(PAHO_BUILD_SHARED "Build shared library" FALSE)
|
||||
option(PAHO_WITH_SSL "Build SSL-enabled library" TRUE)
|
||||
option(PAHO_BUILD_DEB_PACKAGE "Build debian package" FALSE)
|
||||
endif()
|
||||
55
src/mqtt/externals/paho-mqtt-c/src/Clients.c
vendored
Normal file
55
src/mqtt/externals/paho-mqtt-c/src/Clients.c
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - add SSL support
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief functions which apply to client structures
|
||||
* */
|
||||
|
||||
|
||||
#include "Clients.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing clients by clientid
|
||||
* @param a first integer value
|
||||
* @param b second integer value
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
int clientIDCompare(void* a, void* b)
|
||||
{
|
||||
Clients* client = (Clients*)a;
|
||||
/*printf("comparing clientdIDs %s with %s\n", client->clientID, (char*)b);*/
|
||||
return strcmp(client->clientID, (char*)b) == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing clients by socket
|
||||
* @param a first integer value
|
||||
* @param b second integer value
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
int clientSocketCompare(void* a, void* b)
|
||||
{
|
||||
Clients* client = (Clients*)a;
|
||||
/*printf("comparing %d with %d\n", (char*)a, (char*)b); */
|
||||
return client->net.socket == *(SOCKET*)b;
|
||||
}
|
||||
174
src/mqtt/externals/paho-mqtt-c/src/Clients.h
vendored
Normal file
174
src/mqtt/externals/paho-mqtt-c/src/Clients.h
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp. and Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - add SSL support
|
||||
* Ian Craggs - fix for bug 413429 - connectionLost not called
|
||||
* Ian Craggs - change will payload to binary
|
||||
* Ian Craggs - password to binary
|
||||
* Ian Craggs - MQTT 5 support
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(CLIENTS_H)
|
||||
#define CLIENTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "MQTTTime.h"
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
#if defined(OPENSSL)
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
#include "MQTTClient.h"
|
||||
#include "LinkedList.h"
|
||||
#include "MQTTClientPersistence.h"
|
||||
#include "Socket.h"
|
||||
|
||||
/**
|
||||
* Stored publication data to minimize copying
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *topic;
|
||||
int topiclen;
|
||||
char* payload;
|
||||
int payloadlen;
|
||||
int refcount;
|
||||
uint8_t mask[4];
|
||||
} Publications;
|
||||
|
||||
/**
|
||||
* Client publication message data
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int qos;
|
||||
int retain;
|
||||
int msgid;
|
||||
int MQTTVersion;
|
||||
MQTTProperties properties;
|
||||
Publications *publish;
|
||||
START_TIME_TYPE lastTouch; /**> used for retry and expiry */
|
||||
char nextMessageType; /**> PUBREC, PUBREL, PUBCOMP */
|
||||
int len; /**> length of the whole structure+data */
|
||||
} Messages;
|
||||
|
||||
/**
|
||||
* Client will message data
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *topic;
|
||||
int payloadlen;
|
||||
void *payload;
|
||||
int retained;
|
||||
int qos;
|
||||
} willMessages;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOCKET socket;
|
||||
START_TIME_TYPE lastSent;
|
||||
START_TIME_TYPE lastReceived;
|
||||
START_TIME_TYPE lastPing;
|
||||
#if defined(OPENSSL)
|
||||
SSL* ssl;
|
||||
SSL_CTX* ctx;
|
||||
char *https_proxy;
|
||||
char *https_proxy_auth;
|
||||
#endif
|
||||
char *http_proxy;
|
||||
char *http_proxy_auth;
|
||||
int websocket; /**< socket has been upgraded to use web sockets */
|
||||
char *websocket_key;
|
||||
const MQTTClient_nameValue* httpHeaders;
|
||||
} networkHandles;
|
||||
|
||||
|
||||
/* connection states */
|
||||
/** no connection in progress, see connected value */
|
||||
#define NOT_IN_PROGRESS 0x0
|
||||
/** TCP connection in progress */
|
||||
#define TCP_IN_PROGRESS 0x1
|
||||
/** SSL connection in progress */
|
||||
#define SSL_IN_PROGRESS 0x2
|
||||
/** Websocket connection in progress */
|
||||
#define WEBSOCKET_IN_PROGRESS 0x3
|
||||
/** TCP completed, waiting for MQTT ACK */
|
||||
#define WAIT_FOR_CONNACK 0x4
|
||||
/** Proxy connection in progress */
|
||||
#define PROXY_CONNECT_IN_PROGRESS 0x5
|
||||
/** Disconnecting */
|
||||
#define DISCONNECTING -2
|
||||
|
||||
/**
|
||||
* Data related to one client
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char* clientID; /**< the string id of the client */
|
||||
const char* username; /**< MQTT v3.1 user name */
|
||||
int passwordlen; /**< MQTT password length */
|
||||
const void* password; /**< MQTT v3.1 binary password */
|
||||
unsigned int cleansession : 1; /**< MQTT V3 clean session flag */
|
||||
unsigned int cleanstart : 1; /**< MQTT V5 clean start flag */
|
||||
unsigned int connected : 1; /**< whether it is currently connected */
|
||||
unsigned int good : 1; /**< if we have an error on the socket we turn this off */
|
||||
unsigned int ping_outstanding : 1;
|
||||
unsigned int ping_due : 1; /**< we couldn't send a ping so we should send one when we can */
|
||||
signed int connect_state : 4;
|
||||
START_TIME_TYPE ping_due_time; /**< the time at which the ping should have been sent (ping_due) */
|
||||
networkHandles net; /**< network info for this client */
|
||||
int msgID; /**< the MQTT message id */
|
||||
int keepAliveInterval; /**< the MQTT keep alive interval */
|
||||
int retryInterval; /**< the MQTT retry interval for QoS > 0 */
|
||||
int maxInflightMessages; /**< the max number of inflight outbound messages we allow */
|
||||
willMessages* will; /**< the MQTT will message, if any */
|
||||
List* inboundMsgs; /**< inbound in flight messages */
|
||||
List* outboundMsgs; /**< outbound in flight messages */
|
||||
int connect_count; /**< the number of outbound messages on reconnect - to ensure we send them all */
|
||||
int connect_sent; /**< the current number of outbound messages on reconnect that we've sent */
|
||||
List* messageQueue; /**< inbound complete but undelivered messages */
|
||||
List* outboundQueue; /**< outbound queued messages */
|
||||
unsigned int qentry_seqno;
|
||||
void* phandle; /**< the persistence handle */
|
||||
MQTTClient_persistence* persistence; /**< a persistence implementation */
|
||||
MQTTPersistence_beforeWrite* beforeWrite; /**< persistence write callback */
|
||||
MQTTPersistence_afterRead* afterRead; /**< persistence read callback */
|
||||
void* beforeWrite_context; /**< context to be used with the persistence beforeWrite callbacks */
|
||||
void* afterRead_context; /**< context to be used with the persistence afterRead callback */
|
||||
void* context; /**< calling context - used when calling disconnect_internal */
|
||||
int MQTTVersion; /**< the version of MQTT being used, 3, 4 or 5 */
|
||||
unsigned int sessionExpiry; /**< MQTT 5 session expiry */
|
||||
char* httpProxy; /**< HTTP proxy */
|
||||
char* httpsProxy; /**< HTTPS proxy */
|
||||
#if defined(OPENSSL)
|
||||
MQTTClient_SSLOptions *sslopts; /**< the SSL/TLS connect options */
|
||||
SSL_SESSION* session; /**< SSL session pointer for fast handhake */
|
||||
#endif
|
||||
} Clients;
|
||||
|
||||
int clientIDCompare(void* a, void* b);
|
||||
int clientSocketCompare(void* a, void* b);
|
||||
|
||||
/**
|
||||
* Configuration data related to all clients
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const char* version;
|
||||
List* clients;
|
||||
} ClientStates;
|
||||
|
||||
#endif
|
||||
530
src/mqtt/externals/paho-mqtt-c/src/Heap.c
vendored
Normal file
530
src/mqtt/externals/paho-mqtt-c/src/Heap.c
vendored
Normal file
@@ -0,0 +1,530 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - use tree data structure instead of list
|
||||
* Ian Craggs - change roundup to Heap_roundup to avoid macro name clash on MacOSX
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief functions to manage the heap with the goal of eliminating memory leaks
|
||||
*
|
||||
* For any module to use these functions transparently, simply include the Heap.h
|
||||
* header file. Malloc and free will be redefined, but will behave in exactly the same
|
||||
* way as normal, so no recoding is necessary.
|
||||
*
|
||||
* */
|
||||
|
||||
#include "Tree.h"
|
||||
#include "Log.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#if defined(HEAP_UNIT_TESTS)
|
||||
char* Broker_recordFFDC(char* symptoms);
|
||||
#endif /* HEAP_UNIT_TESTS */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Heap.h"
|
||||
|
||||
#if !defined(NO_HEAP_TRACKING)
|
||||
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mutex_type heap_mutex;
|
||||
#else
|
||||
static pthread_mutex_t heap_mutex_store = PTHREAD_MUTEX_INITIALIZER;
|
||||
static mutex_type heap_mutex = &heap_mutex_store;
|
||||
#endif
|
||||
|
||||
static heap_info state = {0, 0}; /**< global heap state information */
|
||||
|
||||
typedef uint64_t eyecatcherType;
|
||||
static eyecatcherType eyecatcher = (eyecatcherType)0x8888888888888888;
|
||||
#define PRIeyecatcher PRIx64 /**< print eyecatcher in HEX notation */
|
||||
|
||||
/*#define HEAP_STACK 1 */
|
||||
|
||||
/**
|
||||
* Each item on the heap is recorded with this structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char* file; /**< the name of the source file where the storage was allocated */
|
||||
int line; /**< the line no in the source file where it was allocated */
|
||||
void* ptr; /**< pointer to the allocated storage */
|
||||
size_t size; /**< size of the allocated storage */
|
||||
#if defined(HEAP_STACK)
|
||||
char* stack;
|
||||
#endif
|
||||
} storageElement;
|
||||
|
||||
static Tree heap; /**< Tree that holds the allocation records */
|
||||
static const char *errmsg = "Memory allocation error";
|
||||
|
||||
|
||||
static size_t Heap_roundup(size_t size);
|
||||
static int ptrCompare(void* a, void* b, int value);
|
||||
/*static void Heap_check(char* string, void* ptr);*/
|
||||
static void checkEyecatchers(char* file, int line, void* p, size_t size);
|
||||
static int Internal_heap_unlink(char* file, int line, void* p);
|
||||
static void HeapScan(enum LOG_LEVELS log_level);
|
||||
|
||||
|
||||
/**
|
||||
* Round allocation size up to a multiple of the size of an int. Apart from possibly reducing fragmentation,
|
||||
* on the old v3 gcc compilers I was hitting some weird behaviour, which might have been errors in
|
||||
* sizeof() used on structures and related to packing. In any case, this fixes that too.
|
||||
* @param size the size actually needed
|
||||
* @return the rounded up size
|
||||
*/
|
||||
static size_t Heap_roundup(size_t size)
|
||||
{
|
||||
static int multsize = 4*sizeof(int);
|
||||
|
||||
if (size % multsize != 0)
|
||||
size += multsize - (size % multsize);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing storage elements
|
||||
* @param a pointer to the current content in the tree (storageElement*)
|
||||
* @param b pointer to the memory to free
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
static int ptrCompare(void* a, void* b, int value)
|
||||
{
|
||||
a = ((storageElement*)a)->ptr;
|
||||
if (value)
|
||||
b = ((storageElement*)b)->ptr;
|
||||
|
||||
return (a > b) ? -1 : (a == b) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
static void Heap_check(char* string, void* ptr)
|
||||
{
|
||||
Node* curnode = NULL;
|
||||
storageElement* prev, *s = NULL;
|
||||
|
||||
printf("Heap_check start %p\n", ptr);
|
||||
while ((curnode = TreeNextElement(&heap, curnode)) != NULL)
|
||||
{
|
||||
prev = s;
|
||||
s = (storageElement*)(curnode->content);
|
||||
|
||||
if (prev)
|
||||
{
|
||||
if (ptrCompare(s, prev, 1) != -1)
|
||||
{
|
||||
printf("%s: heap order error %d %p %p\n", string, ptrCompare(s, prev, 1), prev->ptr, s->ptr);
|
||||
exit(99);
|
||||
}
|
||||
else
|
||||
printf("%s: heap order good %d %p %p\n", string, ptrCompare(s, prev, 1), prev->ptr, s->ptr);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/**
|
||||
* Allocates a block of memory. A direct replacement for malloc, but keeps track of items
|
||||
* allocated in a list, so that free can check that a item is being freed correctly and that
|
||||
* we can check that all memory is freed at shutdown.
|
||||
* @param file use the __FILE__ macro to indicate which file this item was allocated in
|
||||
* @param line use the __LINE__ macro to indicate which line this item was allocated at
|
||||
* @param size the size of the item to be allocated
|
||||
* @return pointer to the allocated item, or NULL if there was an error
|
||||
*/
|
||||
void* mymalloc(char* file, int line, size_t size)
|
||||
{
|
||||
storageElement* s = NULL;
|
||||
size_t space = sizeof(storageElement);
|
||||
size_t filenamelen = strlen(file)+1;
|
||||
void* rc = NULL;
|
||||
|
||||
Paho_thread_lock_mutex(heap_mutex);
|
||||
size = Heap_roundup(size);
|
||||
if ((s = malloc(sizeof(storageElement))) == NULL)
|
||||
{
|
||||
Log(LOG_ERROR, 13, errmsg);
|
||||
goto exit;
|
||||
}
|
||||
memset(s, 0, sizeof(storageElement));
|
||||
|
||||
s->size = size; /* size without eyecatchers */
|
||||
if ((s->file = malloc(filenamelen)) == NULL)
|
||||
{
|
||||
Log(LOG_ERROR, 13, errmsg);
|
||||
free(s);
|
||||
goto exit;
|
||||
}
|
||||
memset(s->file, 0, sizeof(filenamelen));
|
||||
|
||||
space += filenamelen;
|
||||
strcpy(s->file, file);
|
||||
#if defined(HEAP_STACK)
|
||||
#define STACK_LEN 300
|
||||
if ((s->stack = malloc(STACK_LEN)) == NULL)
|
||||
{
|
||||
Log(LOG_ERROR, 13, errmsg);
|
||||
free(s->file);
|
||||
free(s);
|
||||
goto exit;
|
||||
}
|
||||
memset(s->stack, 0, sizeof(filenamelen));
|
||||
StackTrace_get(Paho_thread_getid(), s->stack, STACK_LEN);
|
||||
#endif
|
||||
s->line = line;
|
||||
/* Add space for eyecatcher at each end */
|
||||
if ((s->ptr = malloc(size + 2*sizeof(eyecatcherType))) == NULL)
|
||||
{
|
||||
Log(LOG_ERROR, 13, errmsg);
|
||||
free(s->file);
|
||||
free(s);
|
||||
goto exit;
|
||||
}
|
||||
memset(s->ptr, 0, size + 2*sizeof(eyecatcherType));
|
||||
space += size + 2*sizeof(eyecatcherType);
|
||||
*(eyecatcherType*)(s->ptr) = eyecatcher; /* start eyecatcher */
|
||||
*(eyecatcherType*)(((char*)(s->ptr)) + (sizeof(eyecatcherType) + size)) = eyecatcher; /* end eyecatcher */
|
||||
Log(TRACE_MAX, -1, "Allocating %d bytes in heap at file %s line %d ptr %p\n", (int)size, file, line, s->ptr);
|
||||
TreeAdd(&heap, s, space);
|
||||
state.current_size += size;
|
||||
if (state.current_size > state.max_size)
|
||||
state.max_size = state.current_size;
|
||||
rc = ((eyecatcherType*)(s->ptr)) + 1; /* skip start eyecatcher */
|
||||
exit:
|
||||
Paho_thread_unlock_mutex(heap_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void checkEyecatchers(char* file, int line, void* p, size_t size)
|
||||
{
|
||||
eyecatcherType *sp = (eyecatcherType*)p;
|
||||
char *cp = (char*)p;
|
||||
eyecatcherType us;
|
||||
static const char *msg = "Invalid %s eyecatcher %" PRIeyecatcher " in heap item at file %s line %d";
|
||||
|
||||
if ((us = *--sp) != eyecatcher)
|
||||
Log(LOG_ERROR, 13, msg, "start", us, file, line);
|
||||
|
||||
cp += size;
|
||||
if ((us = *(eyecatcherType*)cp) != eyecatcher)
|
||||
Log(LOG_ERROR, 13, msg, "end", us, file, line);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an item from the recorded heap without actually freeing it.
|
||||
* Use sparingly!
|
||||
* @param file use the __FILE__ macro to indicate which file this item was allocated in
|
||||
* @param line use the __LINE__ macro to indicate which line this item was allocated at
|
||||
* @param p pointer to the item to be removed
|
||||
*/
|
||||
static int Internal_heap_unlink(char* file, int line, void* p)
|
||||
{
|
||||
Node* e = NULL;
|
||||
int rc = 0;
|
||||
|
||||
e = TreeFind(&heap, ((eyecatcherType*)p)-1);
|
||||
if (e == NULL)
|
||||
Log(LOG_ERROR, 13, "Failed to remove heap item at file %s line %d", file, line);
|
||||
else
|
||||
{
|
||||
storageElement* s = (storageElement*)(e->content);
|
||||
Log(TRACE_MAX, -1, "Freeing %d bytes in heap at file %s line %d, heap use now %d bytes\n",
|
||||
(int)s->size, file, line, (int)state.current_size);
|
||||
checkEyecatchers(file, line, p, s->size);
|
||||
/* free(s->ptr); */
|
||||
free(s->file);
|
||||
state.current_size -= s->size;
|
||||
TreeRemoveNodeIndex(&heap, e, 0);
|
||||
free(s);
|
||||
rc = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Frees a block of memory. A direct replacement for free, but checks that a item is in
|
||||
* the allocates list first.
|
||||
* @param file use the __FILE__ macro to indicate which file this item was allocated in
|
||||
* @param line use the __LINE__ macro to indicate which line this item was allocated at
|
||||
* @param p pointer to the item to be freed
|
||||
*/
|
||||
void myfree(char* file, int line, void* p)
|
||||
{
|
||||
if (p) /* it is legal und usual to call free(NULL) */
|
||||
{
|
||||
Paho_thread_lock_mutex(heap_mutex);
|
||||
if (Internal_heap_unlink(file, line, p))
|
||||
free(((eyecatcherType*)p)-1);
|
||||
Paho_thread_unlock_mutex(heap_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(LOG_ERROR, -1, "Call of free(NULL) in %s,%d",file,line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an item from the recorded heap without actually freeing it.
|
||||
* Use sparingly!
|
||||
* @param file use the __FILE__ macro to indicate which file this item was allocated in
|
||||
* @param line use the __LINE__ macro to indicate which line this item was allocated at
|
||||
* @param p pointer to the item to be removed
|
||||
*/
|
||||
void Heap_unlink(char* file, int line, void* p)
|
||||
{
|
||||
Paho_thread_lock_mutex(heap_mutex);
|
||||
Internal_heap_unlink(file, line, p);
|
||||
Paho_thread_unlock_mutex(heap_mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reallocates a block of memory. A direct replacement for realloc, but keeps track of items
|
||||
* allocated in a list, so that free can check that a item is being freed correctly and that
|
||||
* we can check that all memory is freed at shutdown.
|
||||
* We have to remove the item from the tree, as the memory is in order and so it needs to
|
||||
* be reinserted in the correct place.
|
||||
* @param file use the __FILE__ macro to indicate which file this item was reallocated in
|
||||
* @param line use the __LINE__ macro to indicate which line this item was reallocated at
|
||||
* @param p pointer to the item to be reallocated
|
||||
* @param size the new size of the item
|
||||
* @return pointer to the allocated item, or NULL if there was an error
|
||||
*/
|
||||
void *myrealloc(char* file, int line, void* p, size_t size)
|
||||
{
|
||||
void* rc = NULL;
|
||||
storageElement* s = NULL;
|
||||
|
||||
Paho_thread_lock_mutex(heap_mutex);
|
||||
s = TreeRemoveKey(&heap, ((eyecatcherType*)p)-1);
|
||||
if (s == NULL)
|
||||
Log(LOG_ERROR, 13, "Failed to reallocate heap item at file %s line %d", file, line);
|
||||
else
|
||||
{
|
||||
size_t space = sizeof(storageElement);
|
||||
size_t filenamelen = strlen(file)+1;
|
||||
|
||||
checkEyecatchers(file, line, p, s->size);
|
||||
size = Heap_roundup(size);
|
||||
state.current_size += size - s->size;
|
||||
if (state.current_size > state.max_size)
|
||||
state.max_size = state.current_size;
|
||||
if ((s->ptr = realloc(s->ptr, size + 2*sizeof(eyecatcherType))) == NULL)
|
||||
{
|
||||
Log(LOG_ERROR, 13, errmsg);
|
||||
goto exit;
|
||||
}
|
||||
space += size + 2*sizeof(eyecatcherType) - s->size;
|
||||
*(eyecatcherType*)(s->ptr) = eyecatcher; /* start eyecatcher */
|
||||
*(eyecatcherType*)(((char*)(s->ptr)) + (sizeof(eyecatcherType) + size)) = eyecatcher; /* end eyecatcher */
|
||||
s->size = size;
|
||||
space -= strlen(s->file);
|
||||
s->file = realloc(s->file, filenamelen);
|
||||
space += filenamelen;
|
||||
strcpy(s->file, file);
|
||||
s->line = line;
|
||||
rc = s->ptr;
|
||||
TreeAdd(&heap, s, space);
|
||||
}
|
||||
exit:
|
||||
Paho_thread_unlock_mutex(heap_mutex);
|
||||
return (rc == NULL) ? NULL : ((eyecatcherType*)(rc)) + 1; /* skip start eyecatcher */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility to find an item in the heap. Lets you know if the heap already contains
|
||||
* the memory location in question.
|
||||
* @param p pointer to a memory location
|
||||
* @return pointer to the storage element if found, or NULL
|
||||
*/
|
||||
void* Heap_findItem(void* p)
|
||||
{
|
||||
Node* e = NULL;
|
||||
|
||||
Paho_thread_lock_mutex(heap_mutex);
|
||||
e = TreeFind(&heap, ((eyecatcherType*)p)-1);
|
||||
Paho_thread_unlock_mutex(heap_mutex);
|
||||
return (e == NULL) ? NULL : e->content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans the heap and reports any items currently allocated.
|
||||
* To be used at shutdown if any heap items have not been freed.
|
||||
*/
|
||||
static void HeapScan(enum LOG_LEVELS log_level)
|
||||
{
|
||||
Node* current = NULL;
|
||||
|
||||
Paho_thread_lock_mutex(heap_mutex);
|
||||
Log(log_level, -1, "Heap scan start, total %d bytes", (int)state.current_size);
|
||||
while ((current = TreeNextElement(&heap, current)) != NULL)
|
||||
{
|
||||
storageElement* s = (storageElement*)(current->content);
|
||||
Log(log_level, -1, "Heap element size %d, line %d, file %s, ptr %p", (int)s->size, s->line, s->file, s->ptr);
|
||||
Log(log_level, -1, " Content %.*s", (10 > current->size) ? (int)s->size : 10, (char*)(((eyecatcherType*)s->ptr) + 1));
|
||||
#if defined(HEAP_STACK)
|
||||
Log(log_level, -1, " Stack:\n%s", s->stack);
|
||||
#endif
|
||||
}
|
||||
Log(log_level, -1, "Heap scan end");
|
||||
Paho_thread_unlock_mutex(heap_mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Heap initialization.
|
||||
*/
|
||||
int Heap_initialize(void)
|
||||
{
|
||||
TreeInitializeNoMalloc(&heap, ptrCompare);
|
||||
heap.heap_tracking = 0; /* no recursive heap tracking! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Heap termination.
|
||||
*/
|
||||
void Heap_terminate(void)
|
||||
{
|
||||
Log(TRACE_MIN, -1, "Maximum heap use was %d bytes", (int)state.max_size);
|
||||
if (state.current_size > 20) /* One log list is freed after this function is called */
|
||||
{
|
||||
Log(LOG_ERROR, -1, "Some memory not freed at shutdown, possible memory leak");
|
||||
HeapScan(LOG_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Access to heap state
|
||||
* @return pointer to the heap state structure
|
||||
*/
|
||||
heap_info* Heap_get_info(void)
|
||||
{
|
||||
return &state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dump a string from the heap so that it can be displayed conveniently
|
||||
* @param file file handle to dump the heap contents to
|
||||
* @param str the string to dump, could be NULL
|
||||
*/
|
||||
int HeapDumpString(FILE* file, char* str)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t len = str ? strlen(str) + 1 : 0; /* include the trailing null */
|
||||
|
||||
if (fwrite(&(str), sizeof(char*), 1, file) != 1)
|
||||
rc = -1;
|
||||
else if (fwrite(&(len), sizeof(int), 1 ,file) != 1)
|
||||
rc = -1;
|
||||
else if (len > 0 && fwrite(str, len, 1, file) != 1)
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dump the state of the heap
|
||||
* @param file file handle to dump the heap contents to
|
||||
*/
|
||||
int HeapDump(FILE* file)
|
||||
{
|
||||
int rc = 0;
|
||||
Node* current = NULL;
|
||||
|
||||
while (rc == 0 && (current = TreeNextElement(&heap, current)))
|
||||
{
|
||||
storageElement* s = (storageElement*)(current->content);
|
||||
|
||||
if (fwrite(&(s->ptr), sizeof(s->ptr), 1, file) != 1)
|
||||
rc = -1;
|
||||
else if (fwrite(&(current->size), sizeof(current->size), 1, file) != 1)
|
||||
rc = -1;
|
||||
else if (fwrite(s->ptr, current->size, 1, file) != 1)
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HEAP_UNIT_TESTS)
|
||||
|
||||
void Log(enum LOG_LEVELS log_level, int msgno, char* format, ...)
|
||||
{
|
||||
printf("Log %s", format);
|
||||
}
|
||||
|
||||
char* Broker_recordFFDC(char* symptoms)
|
||||
{
|
||||
printf("recordFFDC");
|
||||
return "";
|
||||
}
|
||||
|
||||
#define malloc(x) mymalloc(__FILE__, __LINE__, x)
|
||||
#define realloc(a, b) myrealloc(__FILE__, __LINE__, a, b)
|
||||
#define free(x) myfree(__FILE__, __LINE__, x)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char* h = NULL;
|
||||
Heap_initialize();
|
||||
|
||||
h = malloc(12);
|
||||
free(h);
|
||||
printf("freed h\n");
|
||||
|
||||
h = malloc(12);
|
||||
h = realloc(h, 14);
|
||||
h = realloc(h, 25);
|
||||
h = realloc(h, 255);
|
||||
h = realloc(h, 2225);
|
||||
h = realloc(h, 22225);
|
||||
printf("freeing h\n");
|
||||
free(h);
|
||||
Heap_terminate();
|
||||
printf("Finishing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HEAP_UNIT_TESTS */
|
||||
|
||||
/* Local Variables: */
|
||||
/* indent-tabs-mode: t */
|
||||
/* c-basic-offset: 8 */
|
||||
/* End: */
|
||||
90
src/mqtt/externals/paho-mqtt-c/src/Heap.h
vendored
Normal file
90
src/mqtt/externals/paho-mqtt-c/src/Heap.h
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2020 IBM Corp. and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - use tree data structure instead of list
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#if !defined(HEAP_H)
|
||||
#define HEAP_H
|
||||
|
||||
#if defined(HIGH_PERFORMANCE)
|
||||
#define NO_HEAP_TRACKING 1
|
||||
#endif
|
||||
|
||||
#define PAHO_MEMORY_ERROR -99
|
||||
|
||||
#include "MQTTExportDeclarations.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(NO_HEAP_TRACKING)
|
||||
|
||||
#if !defined(TREE_C)
|
||||
/**
|
||||
* redefines malloc to use "mymalloc" so that heap allocation can be tracked
|
||||
* @param x the size of the item to be allocated
|
||||
* @return the pointer to the item allocated, or NULL
|
||||
*/
|
||||
#define malloc(x) mymalloc(__FILE__, __LINE__, x)
|
||||
|
||||
/**
|
||||
* redefines realloc to use "myrealloc" so that heap allocation can be tracked
|
||||
* @param a the heap item to be reallocated
|
||||
* @param b the new size of the item
|
||||
* @return the new pointer to the heap item
|
||||
*/
|
||||
#define realloc(a, b) myrealloc(__FILE__, __LINE__, a, b)
|
||||
|
||||
/**
|
||||
* redefines free to use "myfree" so that heap allocation can be tracked
|
||||
* @param x the pointer to the item to be freed
|
||||
*/
|
||||
#define free(x) myfree(__FILE__, __LINE__, x)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Information about the state of the heap.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t current_size; /**< current size of the heap in bytes */
|
||||
size_t max_size; /**< max size the heap has reached in bytes */
|
||||
} heap_info;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* mymalloc(char*, int, size_t size);
|
||||
void* myrealloc(char*, int, void* p, size_t size);
|
||||
void myfree(char*, int, void* p);
|
||||
|
||||
void Heap_scan(FILE* file);
|
||||
int Heap_initialize(void);
|
||||
void Heap_terminate(void);
|
||||
LIBMQTT_API heap_info* Heap_get_info(void);
|
||||
int HeapDump(FILE* file);
|
||||
int HeapDumpString(FILE* file, char* str);
|
||||
void* Heap_findItem(void* p);
|
||||
void Heap_unlink(char* file, int line, void* p);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
22
src/mqtt/externals/paho-mqtt-c/src/Keysight_ws_add
vendored
Normal file
22
src/mqtt/externals/paho-mqtt-c/src/Keysight_ws_add
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
#if WINVER <= _WIN32_WINNT_WIN8
|
||||
#define HTON(x) hton((uint64_t) (x), sizeof(x))
|
||||
uint64_t hton(uint64_t x, size_t n)
|
||||
{
|
||||
uint64_t y = 0;
|
||||
size_t i = 0;
|
||||
|
||||
for (i=0; i < n; ++i)
|
||||
{
|
||||
y = (y << 8) | (x & 0xff);
|
||||
x = (x >> 8);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
#define htons(x) (uint16_t) HTON(x)
|
||||
#define htonl(x) (uint32_t) HTON(x)
|
||||
#define htonll(x) (uint64_t) HTON(x)
|
||||
|
||||
#define ntohs(x) htons(x)
|
||||
#define ntohl(x) htonl(x)
|
||||
#define ntohll(x) htonll(x)
|
||||
#endif
|
||||
508
src/mqtt/externals/paho-mqtt-c/src/LinkedList.c
vendored
Normal file
508
src/mqtt/externals/paho-mqtt-c/src/LinkedList.c
vendored
Normal file
@@ -0,0 +1,508 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - updates for the async client
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief functions which apply to linked list structures.
|
||||
*
|
||||
* These linked lists can hold data of any sort, pointed to by the content pointer of the
|
||||
* ListElement structure. ListElements hold the points to the next and previous items in the
|
||||
* list.
|
||||
* */
|
||||
|
||||
#include "LinkedList.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Heap.h"
|
||||
|
||||
|
||||
static int ListUnlink(List* aList, void* content, int(*callback)(void*, void*), int freeContent);
|
||||
|
||||
|
||||
/**
|
||||
* Sets a list structure to empty - all null values. Does not remove any items from the list.
|
||||
* @param newl a pointer to the list structure to be initialized
|
||||
*/
|
||||
void ListZero(List* newl)
|
||||
{
|
||||
memset(newl, '\0', sizeof(List));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocates and initializes a new list structure.
|
||||
* @return a pointer to the new list structure
|
||||
*/
|
||||
List* ListInitialize(void)
|
||||
{
|
||||
List* newl = malloc(sizeof(List));
|
||||
if (newl)
|
||||
ListZero(newl);
|
||||
return newl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append an already allocated ListElement and content to a list. Can be used to move
|
||||
* an item from one list to another.
|
||||
* @param aList the list to which the item is to be added
|
||||
* @param content the list item content itself
|
||||
* @param newel the ListElement to be used in adding the new item
|
||||
* @param size the size of the element
|
||||
*/
|
||||
void ListAppendNoMalloc(List* aList, void* content, ListElement* newel, size_t size)
|
||||
{ /* for heap use */
|
||||
newel->content = content;
|
||||
newel->next = NULL;
|
||||
newel->prev = aList->last;
|
||||
if (aList->first == NULL)
|
||||
aList->first = newel;
|
||||
else
|
||||
aList->last->next = newel;
|
||||
aList->last = newel;
|
||||
++(aList->count);
|
||||
aList->size += size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append an item to a list.
|
||||
* @param aList the list to which the item is to be added
|
||||
* @param content the list item content itself
|
||||
* @param size the size of the element
|
||||
*/
|
||||
ListElement* ListAppend(List* aList, void* content, size_t size)
|
||||
{
|
||||
ListElement* newel = malloc(sizeof(ListElement));
|
||||
if (newel)
|
||||
ListAppendNoMalloc(aList, content, newel, size);
|
||||
return newel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert an item to a list at a specific position.
|
||||
* @param aList the list to which the item is to be added
|
||||
* @param content the list item content itself
|
||||
* @param size the size of the element
|
||||
* @param index the position in the list. If NULL, this function is equivalent
|
||||
* to ListAppend.
|
||||
*/
|
||||
ListElement* ListInsert(List* aList, void* content, size_t size, ListElement* index)
|
||||
{
|
||||
ListElement* newel = malloc(sizeof(ListElement));
|
||||
|
||||
if (newel == NULL)
|
||||
return newel;
|
||||
if ( index == NULL )
|
||||
ListAppendNoMalloc(aList, content, newel, size);
|
||||
else
|
||||
{
|
||||
newel->content = content;
|
||||
newel->next = index;
|
||||
newel->prev = index->prev;
|
||||
|
||||
index->prev = newel;
|
||||
if ( newel->prev != NULL )
|
||||
newel->prev->next = newel;
|
||||
else
|
||||
aList->first = newel;
|
||||
|
||||
++(aList->count);
|
||||
aList->size += size;
|
||||
}
|
||||
return newel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds an element in a list by comparing the content pointers, rather than the contents
|
||||
* @param aList the list in which the search is to be conducted
|
||||
* @param content pointer to the list item content itself
|
||||
* @return the list item found, or NULL
|
||||
*/
|
||||
ListElement* ListFind(List* aList, void* content)
|
||||
{
|
||||
return ListFindItem(aList, content, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds an element in a list by comparing the content or pointer to the content. A callback
|
||||
* function is used to define the method of comparison for each element.
|
||||
* @param aList the list in which the search is to be conducted
|
||||
* @param content pointer to the content to look for
|
||||
* @param callback pointer to a function which compares each element (NULL means compare by content pointer)
|
||||
* @return the list element found, or NULL
|
||||
*/
|
||||
ListElement* ListFindItem(List* aList, void* content, int(*callback)(void*, void*))
|
||||
{
|
||||
ListElement* rc = NULL;
|
||||
|
||||
if (aList->current != NULL && ((callback == NULL && aList->current->content == content) ||
|
||||
(callback != NULL && callback(aList->current->content, content))))
|
||||
rc = aList->current;
|
||||
else
|
||||
{
|
||||
ListElement* current = NULL;
|
||||
|
||||
/* find the content */
|
||||
while (ListNextElement(aList, ¤t) != NULL)
|
||||
{
|
||||
if (callback == NULL)
|
||||
{
|
||||
if (current->content == content)
|
||||
{
|
||||
rc = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (callback(current->content, content))
|
||||
{
|
||||
rc = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rc != NULL)
|
||||
aList->current = rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and optionally frees an element in a list by comparing the content.
|
||||
* A callback function is used to define the method of comparison for each element.
|
||||
* @param aList the list in which the search is to be conducted
|
||||
* @param content pointer to the content to look for
|
||||
* @param callback pointer to a function which compares each element
|
||||
* @param freeContent boolean value to indicate whether the item found is to be freed
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
static int ListUnlink(List* aList, void* content, int(*callback)(void*, void*), int freeContent)
|
||||
{
|
||||
ListElement* next = NULL;
|
||||
ListElement* saved = aList->current;
|
||||
int saveddeleted = 0;
|
||||
|
||||
if (!ListFindItem(aList, content, callback))
|
||||
return 0; /* false, did not remove item */
|
||||
|
||||
if (aList->current->prev == NULL)
|
||||
/* so this is the first element, and we have to update the "first" pointer */
|
||||
aList->first = aList->current->next;
|
||||
else
|
||||
aList->current->prev->next = aList->current->next;
|
||||
|
||||
if (aList->current->next == NULL)
|
||||
aList->last = aList->current->prev;
|
||||
else
|
||||
aList->current->next->prev = aList->current->prev;
|
||||
|
||||
next = aList->current->next;
|
||||
if (freeContent)
|
||||
{
|
||||
free(aList->current->content);
|
||||
aList->current->content = NULL;
|
||||
}
|
||||
if (saved == aList->current)
|
||||
saveddeleted = 1;
|
||||
free(aList->current);
|
||||
if (saveddeleted)
|
||||
aList->current = next;
|
||||
else
|
||||
aList->current = saved;
|
||||
--(aList->count);
|
||||
return 1; /* successfully removed item */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes but does not free an item in a list by comparing the pointer to the content.
|
||||
* @param aList the list in which the search is to be conducted
|
||||
* @param content pointer to the content to look for
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
int ListDetach(List* aList, void* content)
|
||||
{
|
||||
return ListUnlink(aList, content, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and frees an item in a list by comparing the pointer to the content.
|
||||
* @param aList the list from which the item is to be removed
|
||||
* @param content pointer to the content to look for
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
int ListRemove(List* aList, void* content)
|
||||
{
|
||||
return ListUnlink(aList, content, NULL, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and frees an the first item in a list.
|
||||
* @param aList the list from which the item is to be removed
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
void* ListDetachHead(List* aList)
|
||||
{
|
||||
void *content = NULL;
|
||||
if (aList->count > 0)
|
||||
{
|
||||
ListElement* first = aList->first;
|
||||
if (aList->current == first)
|
||||
aList->current = first->next;
|
||||
if (aList->last == first) /* i.e. no of items in list == 1 */
|
||||
aList->last = NULL;
|
||||
content = first->content;
|
||||
aList->first = aList->first->next;
|
||||
if (aList->first)
|
||||
aList->first->prev = NULL;
|
||||
free(first);
|
||||
--(aList->count);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and frees an the first item in a list.
|
||||
* @param aList the list from which the item is to be removed
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
int ListRemoveHead(List* aList)
|
||||
{
|
||||
free(ListDetachHead(aList));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes but does not free the last item in a list.
|
||||
* @param aList the list from which the item is to be removed
|
||||
* @return the last item removed (or NULL if none was)
|
||||
*/
|
||||
void* ListPopTail(List* aList)
|
||||
{
|
||||
void* content = NULL;
|
||||
if (aList->count > 0)
|
||||
{
|
||||
ListElement* last = aList->last;
|
||||
if (aList->current == last)
|
||||
aList->current = last->prev;
|
||||
if (aList->first == last) /* i.e. no of items in list == 1 */
|
||||
aList->first = NULL;
|
||||
content = last->content;
|
||||
aList->last = aList->last->prev;
|
||||
if (aList->last)
|
||||
aList->last->next = NULL;
|
||||
free(last);
|
||||
--(aList->count);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes but does not free an element in a list by comparing the content.
|
||||
* A callback function is used to define the method of comparison for each element.
|
||||
* @param aList the list in which the search is to be conducted
|
||||
* @param content pointer to the content to look for
|
||||
* @param callback pointer to a function which compares each element
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
int ListDetachItem(List* aList, void* content, int(*callback)(void*, void*))
|
||||
{ /* do not free the content */
|
||||
return ListUnlink(aList, content, callback, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and frees an element in a list by comparing the content.
|
||||
* A callback function is used to define the method of comparison for each element
|
||||
* @param aList the list in which the search is to be conducted
|
||||
* @param content pointer to the content to look for
|
||||
* @param callback pointer to a function which compares each element
|
||||
* @return 1=item removed, 0=item not removed
|
||||
*/
|
||||
int ListRemoveItem(List* aList, void* content, int(*callback)(void*, void*))
|
||||
{ /* remove from list and free the content */
|
||||
return ListUnlink(aList, content, callback, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and frees all items in a list, leaving the list ready for new items.
|
||||
* @param aList the list to which the operation is to be applied
|
||||
*/
|
||||
void ListEmpty(List* aList)
|
||||
{
|
||||
while (aList->first != NULL)
|
||||
{
|
||||
ListElement* first = aList->first;
|
||||
if (first->content != NULL)
|
||||
{
|
||||
free(first->content);
|
||||
first->content = NULL;
|
||||
}
|
||||
aList->first = first->next;
|
||||
free(first);
|
||||
}
|
||||
aList->count = 0;
|
||||
aList->size = 0;
|
||||
aList->current = aList->first = aList->last = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and frees all items in a list, and frees the list itself
|
||||
* @param aList the list to which the operation is to be applied
|
||||
*/
|
||||
void ListFree(List* aList)
|
||||
{
|
||||
ListEmpty(aList);
|
||||
free(aList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes and but does not free all items in a list, and frees the list itself
|
||||
* @param aList the list to which the operation is to be applied
|
||||
*/
|
||||
void ListFreeNoContent(List* aList)
|
||||
{
|
||||
while (aList->first != NULL)
|
||||
{
|
||||
ListElement* first = aList->first;
|
||||
aList->first = first->next;
|
||||
free(first);
|
||||
}
|
||||
free(aList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forward iteration through a list
|
||||
* @param aList the list to which the operation is to be applied
|
||||
* @param pos pointer to the current position in the list. NULL means start from the beginning of the list
|
||||
* This is updated on return to the same value as that returned from this function
|
||||
* @return pointer to the current list element
|
||||
*/
|
||||
ListElement* ListNextElement(List* aList, ListElement** pos)
|
||||
{
|
||||
return *pos = (*pos == NULL) ? aList->first : (*pos)->next;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Backward iteration through a list
|
||||
* @param aList the list to which the operation is to be applied
|
||||
* @param pos pointer to the current position in the list. NULL means start from the end of the list
|
||||
* This is updated on return to the same value as that returned from this function
|
||||
* @return pointer to the current list element
|
||||
*/
|
||||
ListElement* ListPrevElement(List* aList, ListElement** pos)
|
||||
{
|
||||
return *pos = (*pos == NULL) ? aList->last : (*pos)->prev;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing integers
|
||||
* @param a first integer value
|
||||
* @param b second integer value
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
int intcompare(void* a, void* b)
|
||||
{
|
||||
return *((int*)a) == *((int*)b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing C strings
|
||||
* @param a first integer value
|
||||
* @param b second integer value
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
int stringcompare(void* a, void* b)
|
||||
{
|
||||
return strcmp((char*)a, (char*)b) == 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(UNIT_TESTS)
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, *ip, *todelete;
|
||||
ListElement* current = NULL;
|
||||
List* l = ListInitialize();
|
||||
printf("List initialized\n");
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
ip = malloc(sizeof(int));
|
||||
*ip = i;
|
||||
ListAppend(l, (void*)ip, sizeof(int));
|
||||
if (i==5)
|
||||
todelete = ip;
|
||||
printf("List element appended %d\n", *((int*)(l->last->content)));
|
||||
}
|
||||
|
||||
printf("List contents:\n");
|
||||
current = NULL;
|
||||
while (ListNextElement(l, ¤t) != NULL)
|
||||
printf("List element: %d\n", *((int*)(current->content)));
|
||||
|
||||
printf("List contents in reverse order:\n");
|
||||
current = NULL;
|
||||
while (ListPrevElement(l, ¤t) != NULL)
|
||||
printf("List element: %d\n", *((int*)(current->content)));
|
||||
|
||||
/* if ListFindItem(l, *ip, intcompare)->content */
|
||||
|
||||
printf("List contents having deleted element %d:\n", *todelete);
|
||||
ListRemove(l, todelete);
|
||||
current = NULL;
|
||||
while (ListNextElement(l, ¤t) != NULL)
|
||||
printf("List element: %d\n", *((int*)(current->content)));
|
||||
|
||||
i = 9;
|
||||
ListRemoveItem(l, &i, intcompare);
|
||||
printf("List contents having deleted another element, %d, size now %d:\n", i, l->size);
|
||||
current = NULL;
|
||||
while (ListNextElement(l, ¤t) != NULL)
|
||||
printf("List element: %d\n", *((int*)(current->content)));
|
||||
|
||||
ListFree(l);
|
||||
printf("List freed\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
105
src/mqtt/externals/paho-mqtt-c/src/LinkedList.h
vendored
Normal file
105
src/mqtt/externals/paho-mqtt-c/src/LinkedList.h
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - updates for the async client
|
||||
* Ian Craggs - change size types from int to size_t
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(LINKEDLIST_H)
|
||||
#define LINKEDLIST_H
|
||||
|
||||
#include <stdlib.h> /* for size_t definition */
|
||||
|
||||
/*BE
|
||||
defm defList(T)
|
||||
|
||||
def T concat Item
|
||||
{
|
||||
at 4
|
||||
n32 ptr T concat Item suppress "next"
|
||||
at 0
|
||||
n32 ptr T concat Item suppress "prev"
|
||||
at 8
|
||||
n32 ptr T id2str(T)
|
||||
}
|
||||
|
||||
def T concat List
|
||||
{
|
||||
n32 ptr T concat Item suppress "first"
|
||||
n32 ptr T concat Item suppress "last"
|
||||
n32 ptr T concat Item suppress "current"
|
||||
n32 dec "count"
|
||||
n32 suppress "size"
|
||||
}
|
||||
endm
|
||||
|
||||
defList(INT)
|
||||
defList(STRING)
|
||||
defList(TMP)
|
||||
|
||||
BE*/
|
||||
|
||||
/**
|
||||
* Structure to hold all data for one list element
|
||||
*/
|
||||
typedef struct ListElementStruct
|
||||
{
|
||||
struct ListElementStruct *prev, /**< pointer to previous list element */
|
||||
*next; /**< pointer to next list element */
|
||||
void* content; /**< pointer to element content */
|
||||
} ListElement;
|
||||
|
||||
|
||||
/**
|
||||
* Structure to hold all data for one list
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ListElement *first, /**< first element in the list */
|
||||
*last, /**< last element in the list */
|
||||
*current; /**< current element in the list, for iteration */
|
||||
int count; /**< no of items */
|
||||
size_t size; /**< heap storage used */
|
||||
} List;
|
||||
|
||||
void ListZero(List*);
|
||||
List* ListInitialize(void);
|
||||
|
||||
ListElement* ListAppend(List* aList, void* content, size_t size);
|
||||
void ListAppendNoMalloc(List* aList, void* content, ListElement* newel, size_t size);
|
||||
ListElement* ListInsert(List* aList, void* content, size_t size, ListElement* index);
|
||||
|
||||
int ListRemove(List* aList, void* content);
|
||||
int ListRemoveItem(List* aList, void* content, int(*callback)(void*, void*));
|
||||
void* ListDetachHead(List* aList);
|
||||
int ListRemoveHead(List* aList);
|
||||
void* ListPopTail(List* aList);
|
||||
|
||||
int ListDetach(List* aList, void* content);
|
||||
int ListDetachItem(List* aList, void* content, int(*callback)(void*, void*));
|
||||
|
||||
void ListFree(List* aList);
|
||||
void ListEmpty(List* aList);
|
||||
void ListFreeNoContent(List* aList);
|
||||
|
||||
ListElement* ListNextElement(List* aList, ListElement** pos);
|
||||
ListElement* ListPrevElement(List* aList, ListElement** pos);
|
||||
|
||||
ListElement* ListFind(List* aList, void* content);
|
||||
ListElement* ListFindItem(List* aList, void* content, int(*callback)(void*, void*));
|
||||
|
||||
int intcompare(void* a, void* b);
|
||||
int stringcompare(void* a, void* b);
|
||||
|
||||
#endif
|
||||
585
src/mqtt/externals/paho-mqtt-c/src/Log.c
vendored
Normal file
585
src/mqtt/externals/paho-mqtt-c/src/Log.c
vendored
Normal file
@@ -0,0 +1,585 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - updates for the async client
|
||||
* Ian Craggs - fix for bug #427028
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Logging and tracing module
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include "MQTTProtocol.h"
|
||||
#include "MQTTProtocolClient.h"
|
||||
#include "Messages.h"
|
||||
#include "LinkedList.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#define GETTIMEOFDAY 1
|
||||
#else
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#if defined(GETTIMEOFDAY)
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/timeb.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
/**
|
||||
* _unlink mapping for linux
|
||||
*/
|
||||
#define _unlink unlink
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(min)
|
||||
#define min(A,B) ( (A) < (B) ? (A):(B))
|
||||
#endif
|
||||
|
||||
trace_settings_type trace_settings =
|
||||
{
|
||||
#if defined(HIGH_PERFORMANCE)
|
||||
LOG_ERROR,
|
||||
#else
|
||||
TRACE_MINIMUM,
|
||||
#endif
|
||||
400,
|
||||
INVALID_LEVEL
|
||||
};
|
||||
|
||||
#define MAX_FUNCTION_NAME_LENGTH 256
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#if defined(GETTIMEOFDAY)
|
||||
struct timeval ts;
|
||||
#else
|
||||
struct timeb ts;
|
||||
#endif
|
||||
int sametime_count;
|
||||
int number;
|
||||
thread_id_type thread_id;
|
||||
int depth;
|
||||
char name[MAX_FUNCTION_NAME_LENGTH + 1];
|
||||
int line;
|
||||
int has_rc;
|
||||
int rc;
|
||||
enum LOG_LEVELS level;
|
||||
} traceEntry;
|
||||
|
||||
static int start_index = -1,
|
||||
next_index = 0;
|
||||
static traceEntry* trace_queue = NULL;
|
||||
static int trace_queue_size = 0;
|
||||
|
||||
static FILE* trace_destination = NULL; /**< flag to indicate if trace is to be sent to a stream */
|
||||
static char* trace_destination_name = NULL; /**< the name of the trace file */
|
||||
static char* trace_destination_backup_name = NULL; /**< the name of the backup trace file */
|
||||
static int lines_written = 0; /**< number of lines written to the current output file */
|
||||
static int max_lines_per_file = 1000; /**< maximum number of lines to write to one trace file */
|
||||
static enum LOG_LEVELS trace_output_level = INVALID_LEVEL;
|
||||
static Log_traceCallback* trace_callback = NULL;
|
||||
static traceEntry* Log_pretrace(void);
|
||||
static char* Log_formatTraceEntry(traceEntry* cur_entry);
|
||||
static void Log_output(enum LOG_LEVELS log_level, const char *msg);
|
||||
static void Log_posttrace(enum LOG_LEVELS log_level, traceEntry* cur_entry);
|
||||
static void Log_trace(enum LOG_LEVELS log_level, const char *buf);
|
||||
#if 0
|
||||
static FILE* Log_destToFile(const char *dest);
|
||||
static int Log_compareEntries(const char *entry1, const char *entry2);
|
||||
#endif
|
||||
|
||||
static int sametime_count = 0;
|
||||
#if defined(GETTIMEOFDAY)
|
||||
struct timeval now_ts, last_ts;
|
||||
#else
|
||||
struct timeb now_ts, last_ts;
|
||||
#endif
|
||||
static char msg_buf[512];
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mutex_type log_mutex;
|
||||
#else
|
||||
static pthread_mutex_t log_mutex_store = PTHREAD_MUTEX_INITIALIZER;
|
||||
static mutex_type log_mutex = &log_mutex_store;
|
||||
#endif
|
||||
|
||||
|
||||
int Log_initialize(Log_nameValue* info)
|
||||
{
|
||||
int rc = SOCKET_ERROR;
|
||||
char* envval = NULL;
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
struct stat buf;
|
||||
#endif
|
||||
|
||||
if ((trace_queue = malloc(sizeof(traceEntry) * trace_settings.max_trace_entries)) == NULL)
|
||||
goto exit;
|
||||
trace_queue_size = trace_settings.max_trace_entries;
|
||||
|
||||
if ((envval = getenv("MQTT_C_CLIENT_TRACE")) != NULL && strlen(envval) > 0)
|
||||
{
|
||||
if (strcmp(envval, "ON") == 0 || (trace_destination = fopen(envval, "w")) == NULL)
|
||||
trace_destination = stdout;
|
||||
else
|
||||
{
|
||||
size_t namelen = 0;
|
||||
|
||||
if ((trace_destination_name = malloc(strlen(envval) + 1)) == NULL)
|
||||
{
|
||||
free(trace_queue);
|
||||
goto exit;
|
||||
}
|
||||
strcpy(trace_destination_name, envval);
|
||||
namelen = strlen(envval) + 3;
|
||||
if ((trace_destination_backup_name = malloc(namelen)) == NULL)
|
||||
{
|
||||
free(trace_queue);
|
||||
free(trace_destination_name);
|
||||
goto exit;
|
||||
}
|
||||
if (snprintf(trace_destination_backup_name, namelen, "%s.0", trace_destination_name) >= namelen)
|
||||
trace_destination_backup_name[namelen-1] = '\0';
|
||||
}
|
||||
}
|
||||
if ((envval = getenv("MQTT_C_CLIENT_TRACE_MAX_LINES")) != NULL && strlen(envval) > 0)
|
||||
{
|
||||
max_lines_per_file = atoi(envval);
|
||||
if (max_lines_per_file <= 0)
|
||||
max_lines_per_file = 1000;
|
||||
}
|
||||
if ((envval = getenv("MQTT_C_CLIENT_TRACE_LEVEL")) != NULL && strlen(envval) > 0)
|
||||
{
|
||||
if (strcmp(envval, "MAXIMUM") == 0 || strcmp(envval, "TRACE_MAXIMUM") == 0)
|
||||
trace_settings.trace_level = TRACE_MAXIMUM;
|
||||
else if (strcmp(envval, "MEDIUM") == 0 || strcmp(envval, "TRACE_MEDIUM") == 0)
|
||||
trace_settings.trace_level = TRACE_MEDIUM;
|
||||
else if (strcmp(envval, "MINIMUM") == 0 || strcmp(envval, "TRACE_MINIMUM") == 0)
|
||||
trace_settings.trace_level = TRACE_MINIMUM;
|
||||
else if (strcmp(envval, "PROTOCOL") == 0 || strcmp(envval, "TRACE_PROTOCOL") == 0)
|
||||
trace_output_level = TRACE_PROTOCOL;
|
||||
else if (strcmp(envval, "ERROR") == 0 || strcmp(envval, "TRACE_ERROR") == 0)
|
||||
trace_output_level = LOG_ERROR;
|
||||
}
|
||||
Log_output(TRACE_MINIMUM, "=========================================================");
|
||||
Log_output(TRACE_MINIMUM, " Trace Output");
|
||||
if (info)
|
||||
{
|
||||
while (info->name)
|
||||
{
|
||||
snprintf(msg_buf, sizeof(msg_buf), "%s: %s", info->name, info->value);
|
||||
Log_output(TRACE_MINIMUM, msg_buf);
|
||||
info++;
|
||||
}
|
||||
}
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (stat("/proc/version", &buf) != -1)
|
||||
{
|
||||
FILE* vfile;
|
||||
|
||||
if ((vfile = fopen("/proc/version", "r")) != NULL)
|
||||
{
|
||||
int len;
|
||||
|
||||
strcpy(msg_buf, "/proc/version: ");
|
||||
len = strlen(msg_buf);
|
||||
if (fgets(&msg_buf[len], sizeof(msg_buf) - len, vfile))
|
||||
Log_output(TRACE_MINIMUM, msg_buf);
|
||||
fclose(vfile);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Log_output(TRACE_MINIMUM, "=========================================================");
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void Log_setTraceCallback(Log_traceCallback* callback)
|
||||
{
|
||||
trace_callback = callback;
|
||||
}
|
||||
|
||||
|
||||
void Log_setTraceLevel(enum LOG_LEVELS level)
|
||||
{
|
||||
if (level <= LOG_ERROR) /* the lowest we can go is LOG_ERROR */
|
||||
trace_settings.trace_level = level;
|
||||
trace_output_level = level;
|
||||
}
|
||||
|
||||
|
||||
void Log_terminate(void)
|
||||
{
|
||||
free(trace_queue);
|
||||
trace_queue = NULL;
|
||||
trace_queue_size = 0;
|
||||
if (trace_destination)
|
||||
{
|
||||
if (trace_destination != stdout)
|
||||
fclose(trace_destination);
|
||||
trace_destination = NULL;
|
||||
}
|
||||
if (trace_destination_name) {
|
||||
free(trace_destination_name);
|
||||
trace_destination_name = NULL;
|
||||
}
|
||||
if (trace_destination_backup_name) {
|
||||
free(trace_destination_backup_name);
|
||||
trace_destination_backup_name = NULL;
|
||||
}
|
||||
start_index = -1;
|
||||
next_index = 0;
|
||||
trace_output_level = INVALID_LEVEL;
|
||||
sametime_count = 0;
|
||||
}
|
||||
|
||||
|
||||
static traceEntry* Log_pretrace(void)
|
||||
{
|
||||
traceEntry *cur_entry = NULL;
|
||||
|
||||
/* calling ftime/gettimeofday seems to be comparatively expensive, so we need to limit its use */
|
||||
if (++sametime_count % 20 == 0)
|
||||
{
|
||||
#if defined(GETTIMEOFDAY)
|
||||
gettimeofday(&now_ts, NULL);
|
||||
if (now_ts.tv_sec != last_ts.tv_sec || now_ts.tv_usec != last_ts.tv_usec)
|
||||
#else
|
||||
ftime(&now_ts);
|
||||
if (now_ts.time != last_ts.time || now_ts.millitm != last_ts.millitm)
|
||||
#endif
|
||||
{
|
||||
sametime_count = 0;
|
||||
last_ts = now_ts;
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_queue_size != trace_settings.max_trace_entries)
|
||||
{
|
||||
traceEntry* new_trace_queue = malloc(sizeof(traceEntry) * trace_settings.max_trace_entries);
|
||||
|
||||
if (new_trace_queue == NULL)
|
||||
goto exit;
|
||||
memcpy(new_trace_queue, trace_queue, min(trace_queue_size, trace_settings.max_trace_entries) * sizeof(traceEntry));
|
||||
free(trace_queue);
|
||||
trace_queue = new_trace_queue;
|
||||
trace_queue_size = trace_settings.max_trace_entries;
|
||||
|
||||
if (start_index > trace_settings.max_trace_entries + 1 ||
|
||||
next_index > trace_settings.max_trace_entries + 1)
|
||||
{
|
||||
start_index = -1;
|
||||
next_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* add to trace buffer */
|
||||
cur_entry = &trace_queue[next_index];
|
||||
if (next_index == start_index) /* means the buffer is full */
|
||||
{
|
||||
if (++start_index == trace_settings.max_trace_entries)
|
||||
start_index = 0;
|
||||
} else if (start_index == -1)
|
||||
start_index = 0;
|
||||
if (++next_index == trace_settings.max_trace_entries)
|
||||
next_index = 0;
|
||||
exit:
|
||||
return cur_entry;
|
||||
}
|
||||
|
||||
static char* Log_formatTraceEntry(traceEntry* cur_entry)
|
||||
{
|
||||
struct tm *timeinfo;
|
||||
int buf_pos = 31;
|
||||
|
||||
#if defined(GETTIMEOFDAY)
|
||||
timeinfo = localtime((time_t *)&cur_entry->ts.tv_sec);
|
||||
#else
|
||||
timeinfo = localtime(&cur_entry->ts.time);
|
||||
#endif
|
||||
strftime(&msg_buf[7], 80, "%Y%m%d %H%M%S ", timeinfo);
|
||||
#if defined(GETTIMEOFDAY)
|
||||
snprintf(&msg_buf[22], sizeof(msg_buf)-22, ".%.3lu ", cur_entry->ts.tv_usec / 1000L);
|
||||
#else
|
||||
snprintf(&msg_buf[22], sizeof(msg_buf)-22, ".%.3hu ", cur_entry->ts.millitm);
|
||||
#endif
|
||||
buf_pos = 27;
|
||||
|
||||
snprintf(msg_buf, sizeof(msg_buf), "(%.4d)", cur_entry->sametime_count);
|
||||
msg_buf[6] = ' ';
|
||||
|
||||
if (cur_entry->has_rc == 2)
|
||||
strncpy(&msg_buf[buf_pos], cur_entry->name, sizeof(msg_buf)-buf_pos);
|
||||
else
|
||||
{
|
||||
const char *format = Messages_get(cur_entry->number, cur_entry->level);
|
||||
if (cur_entry->has_rc == 1)
|
||||
snprintf(&msg_buf[buf_pos], sizeof(msg_buf)-buf_pos, format, cur_entry->thread_id,
|
||||
cur_entry->depth, "", cur_entry->depth, cur_entry->name, cur_entry->line, cur_entry->rc);
|
||||
else
|
||||
snprintf(&msg_buf[buf_pos], sizeof(msg_buf)-buf_pos, format, cur_entry->thread_id,
|
||||
cur_entry->depth, "", cur_entry->depth, cur_entry->name, cur_entry->line);
|
||||
}
|
||||
return msg_buf;
|
||||
}
|
||||
|
||||
|
||||
static void Log_output(enum LOG_LEVELS log_level, const char *msg)
|
||||
{
|
||||
if (trace_destination)
|
||||
{
|
||||
fprintf(trace_destination, "%s\n", msg);
|
||||
|
||||
if (trace_destination != stdout && ++lines_written >= max_lines_per_file)
|
||||
{
|
||||
|
||||
fclose(trace_destination);
|
||||
_unlink(trace_destination_backup_name); /* remove any old backup trace file */
|
||||
rename(trace_destination_name, trace_destination_backup_name); /* rename recently closed to backup */
|
||||
trace_destination = fopen(trace_destination_name, "w"); /* open new trace file */
|
||||
if (trace_destination == NULL)
|
||||
trace_destination = stdout;
|
||||
lines_written = 0;
|
||||
}
|
||||
else
|
||||
fflush(trace_destination);
|
||||
}
|
||||
|
||||
if (trace_callback)
|
||||
(*trace_callback)(log_level, msg);
|
||||
}
|
||||
|
||||
|
||||
static void Log_posttrace(enum LOG_LEVELS log_level, traceEntry* cur_entry)
|
||||
{
|
||||
if (((trace_output_level == -1) ? log_level >= trace_settings.trace_level : log_level >= trace_output_level))
|
||||
{
|
||||
char* msg = NULL;
|
||||
|
||||
if (trace_destination || trace_callback)
|
||||
msg = &Log_formatTraceEntry(cur_entry)[7];
|
||||
|
||||
Log_output(log_level, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Log_trace(enum LOG_LEVELS log_level, const char *buf)
|
||||
{
|
||||
traceEntry *cur_entry = NULL;
|
||||
|
||||
if (trace_queue == NULL)
|
||||
return;
|
||||
|
||||
cur_entry = Log_pretrace();
|
||||
|
||||
memcpy(&(cur_entry->ts), &now_ts, sizeof(now_ts));
|
||||
cur_entry->sametime_count = sametime_count;
|
||||
|
||||
cur_entry->has_rc = 2;
|
||||
strncpy(cur_entry->name, buf, sizeof(cur_entry->name));
|
||||
cur_entry->name[MAX_FUNCTION_NAME_LENGTH] = '\0';
|
||||
|
||||
Log_posttrace(log_level, cur_entry);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log a message. If possible, all messages should be indexed by message number, and
|
||||
* the use of the format string should be minimized or negated altogether. If format is
|
||||
* provided, the message number is only used as a message label.
|
||||
* @param log_level the log level of the message
|
||||
* @param msgno the id of the message to use if the format string is NULL
|
||||
* @param aFormat the printf format string to be used if the message id does not exist
|
||||
* @param ... the printf inserts
|
||||
*/
|
||||
void Log(enum LOG_LEVELS log_level, int msgno, const char *format, ...)
|
||||
{
|
||||
if (log_level >= trace_settings.trace_level)
|
||||
{
|
||||
const char *temp = NULL;
|
||||
va_list args;
|
||||
|
||||
/* we're using a static character buffer, so we need to make sure only one thread uses it at a time */
|
||||
Paho_thread_lock_mutex(log_mutex);
|
||||
if (format == NULL && (temp = Messages_get(msgno, log_level)) != NULL)
|
||||
format = temp;
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(msg_buf, sizeof(msg_buf), format, args);
|
||||
|
||||
Log_trace(log_level, msg_buf);
|
||||
va_end(args);
|
||||
Paho_thread_unlock_mutex(log_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The reason for this function is to make trace logging as fast as possible so that the
|
||||
* function exit/entry history can be captured by default without unduly impacting
|
||||
* performance. Therefore it must do as little as possible.
|
||||
* @param log_level the log level of the message
|
||||
* @param msgno the id of the message to use if the format string is NULL
|
||||
* @param aFormat the printf format string to be used if the message id does not exist
|
||||
* @param ... the printf inserts
|
||||
*/
|
||||
void Log_stackTrace(enum LOG_LEVELS log_level, int msgno, thread_id_type thread_id, int current_depth, const char* name, int line, int* rc)
|
||||
{
|
||||
traceEntry *cur_entry = NULL;
|
||||
|
||||
if (trace_queue == NULL)
|
||||
return;
|
||||
|
||||
if (log_level < trace_settings.trace_level)
|
||||
return;
|
||||
|
||||
Paho_thread_lock_mutex(log_mutex);
|
||||
cur_entry = Log_pretrace();
|
||||
|
||||
memcpy(&(cur_entry->ts), &now_ts, sizeof(now_ts));
|
||||
cur_entry->sametime_count = sametime_count;
|
||||
cur_entry->number = msgno;
|
||||
cur_entry->thread_id = thread_id;
|
||||
cur_entry->depth = current_depth;
|
||||
strcpy(cur_entry->name, name);
|
||||
cur_entry->level = log_level;
|
||||
cur_entry->line = line;
|
||||
if (rc == NULL)
|
||||
cur_entry->has_rc = 0;
|
||||
else
|
||||
{
|
||||
cur_entry->has_rc = 1;
|
||||
cur_entry->rc = *rc;
|
||||
}
|
||||
|
||||
Log_posttrace(log_level, cur_entry);
|
||||
Paho_thread_unlock_mutex(log_mutex);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static FILE* Log_destToFile(const char *dest)
|
||||
{
|
||||
FILE* file = NULL;
|
||||
|
||||
if (strcmp(dest, "stdout") == 0)
|
||||
file = stdout;
|
||||
else if (strcmp(dest, "stderr") == 0)
|
||||
file = stderr;
|
||||
else
|
||||
{
|
||||
if (strstr(dest, "FFDC"))
|
||||
file = fopen(dest, "ab");
|
||||
else
|
||||
file = fopen(dest, "wb");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
static int Log_compareEntries(const char *entry1, const char *entry2)
|
||||
{
|
||||
int comp = strncmp(&entry1[7], &entry2[7], 19);
|
||||
|
||||
/* if timestamps are equal, use the sequence numbers */
|
||||
if (comp == 0)
|
||||
comp = strncmp(&entry1[1], &entry2[1], 4);
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write the contents of the stored trace to a stream
|
||||
* @param dest string which contains a file name or the special strings stdout or stderr
|
||||
*/
|
||||
int Log_dumpTrace(char* dest)
|
||||
{
|
||||
FILE* file = NULL;
|
||||
ListElement* cur_trace_entry = NULL;
|
||||
const int msgstart = 7;
|
||||
int rc = -1;
|
||||
int trace_queue_index = 0;
|
||||
|
||||
if ((file = Log_destToFile(dest)) == NULL)
|
||||
{
|
||||
Log(LOG_ERROR, 9, NULL, "trace", dest, "trace entries");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fprintf(file, "=========== Start of trace dump ==========\n");
|
||||
/* Interleave the log and trace entries together appropriately */
|
||||
ListNextElement(trace_buffer, &cur_trace_entry);
|
||||
trace_queue_index = start_index;
|
||||
if (trace_queue_index == -1)
|
||||
trace_queue_index = next_index;
|
||||
else
|
||||
{
|
||||
Log_formatTraceEntry(&trace_queue[trace_queue_index++]);
|
||||
if (trace_queue_index == trace_settings.max_trace_entries)
|
||||
trace_queue_index = 0;
|
||||
}
|
||||
while (cur_trace_entry || trace_queue_index != next_index)
|
||||
{
|
||||
if (cur_trace_entry && trace_queue_index != -1)
|
||||
{ /* compare these timestamps */
|
||||
if (Log_compareEntries((char*)cur_trace_entry->content, msg_buf) > 0)
|
||||
cur_trace_entry = NULL;
|
||||
}
|
||||
|
||||
if (cur_trace_entry)
|
||||
{
|
||||
fprintf(file, "%s\n", &((char*)(cur_trace_entry->content))[msgstart]);
|
||||
ListNextElement(trace_buffer, &cur_trace_entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "%s\n", &msg_buf[7]);
|
||||
if (trace_queue_index != next_index)
|
||||
{
|
||||
Log_formatTraceEntry(&trace_queue[trace_queue_index++]);
|
||||
if (trace_queue_index == trace_settings.max_trace_entries)
|
||||
trace_queue_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(file, "========== End of trace dump ==========\n\n");
|
||||
if (file != stdout && file != stderr && file != NULL)
|
||||
fclose(file);
|
||||
rc = 0;
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
93
src/mqtt/externals/paho-mqtt-c/src/Log.h
vendored
Normal file
93
src/mqtt/externals/paho-mqtt-c/src/Log.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - updates for the async client
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(LOG_H)
|
||||
#define LOG_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#define thread_id_type DWORD
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#define thread_id_type pthread_t
|
||||
#endif
|
||||
|
||||
/*BE
|
||||
map LOG_LEVELS
|
||||
{
|
||||
"TRACE_MAXIMUM" 1
|
||||
"TRACE_MEDIUM" 2
|
||||
"TRACE_MINIMUM" 3
|
||||
"TRACE_PROTOCOL" 4
|
||||
|
||||
"ERROR" 5
|
||||
"SEVERE" 6
|
||||
"FATAL" 7
|
||||
}
|
||||
BE*/
|
||||
|
||||
enum LOG_LEVELS {
|
||||
INVALID_LEVEL = -1,
|
||||
TRACE_MAXIMUM = 1,
|
||||
TRACE_MEDIUM,
|
||||
TRACE_MINIMUM,
|
||||
TRACE_PROTOCOL,
|
||||
LOG_ERROR,
|
||||
LOG_SEVERE,
|
||||
LOG_FATAL,
|
||||
};
|
||||
|
||||
|
||||
/*BE
|
||||
def trace_settings_type
|
||||
{
|
||||
n32 map LOG_LEVELS "trace_level"
|
||||
n32 dec "max_trace_entries"
|
||||
n32 dec "trace_output_level"
|
||||
}
|
||||
BE*/
|
||||
typedef struct
|
||||
{
|
||||
enum LOG_LEVELS trace_level; /**< trace level */
|
||||
int max_trace_entries; /**< max no of entries in the trace buffer */
|
||||
enum LOG_LEVELS trace_output_level; /**< trace level to output to destination */
|
||||
} trace_settings_type;
|
||||
|
||||
extern trace_settings_type trace_settings;
|
||||
|
||||
#define LOG_PROTOCOL TRACE_PROTOCOL
|
||||
#define TRACE_MAX TRACE_MAXIMUM
|
||||
#define TRACE_MIN TRACE_MINIMUM
|
||||
#define TRACE_MED TRACE_MEDIUM
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const char* value;
|
||||
} Log_nameValue;
|
||||
|
||||
int Log_initialize(Log_nameValue*);
|
||||
void Log_terminate(void);
|
||||
|
||||
void Log(enum LOG_LEVELS, int, const char *, ...);
|
||||
void Log_stackTrace(enum LOG_LEVELS, int, thread_id_type, int, const char*, int, int*);
|
||||
|
||||
typedef void Log_traceCallback(enum LOG_LEVELS level, const char *message);
|
||||
void Log_setTraceCallback(Log_traceCallback* callback);
|
||||
void Log_setTraceLevel(enum LOG_LEVELS level);
|
||||
|
||||
#endif
|
||||
1861
src/mqtt/externals/paho-mqtt-c/src/MQTTAsync.c
vendored
Normal file
1861
src/mqtt/externals/paho-mqtt-c/src/MQTTAsync.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2383
src/mqtt/externals/paho-mqtt-c/src/MQTTAsync.h
vendored
Normal file
2383
src/mqtt/externals/paho-mqtt-c/src/MQTTAsync.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3184
src/mqtt/externals/paho-mqtt-c/src/MQTTAsyncUtils.c
vendored
Normal file
3184
src/mqtt/externals/paho-mqtt-c/src/MQTTAsyncUtils.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
187
src/mqtt/externals/paho-mqtt-c/src/MQTTAsyncUtils.h
vendored
Normal file
187
src/mqtt/externals/paho-mqtt-c/src/MQTTAsyncUtils.h
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp. and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTASYNCUTILS_H_)
|
||||
#define MQTTASYNCUTILS_H_
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#define URI_TCP "tcp://"
|
||||
#define URI_MQTT "mqtt://"
|
||||
#define URI_WS "ws://"
|
||||
#define URI_WSS "wss://"
|
||||
|
||||
enum MQTTAsync_threadStates
|
||||
{
|
||||
STOPPED, STARTING, RUNNING, STOPPING
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MQTTAsync_message* msg;
|
||||
char* topicName;
|
||||
int topicLen;
|
||||
unsigned int seqno; /* only used on restore */
|
||||
} qEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
MQTTAsync_onSuccess* onSuccess;
|
||||
MQTTAsync_onFailure* onFailure;
|
||||
MQTTAsync_onSuccess5* onSuccess5;
|
||||
MQTTAsync_onFailure5* onFailure5;
|
||||
MQTTAsync_token token;
|
||||
void* context;
|
||||
START_TIME_TYPE start_time;
|
||||
MQTTProperties properties;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int count;
|
||||
char** topics;
|
||||
int* qoss;
|
||||
MQTTSubscribe_options opts;
|
||||
MQTTSubscribe_options* optlist;
|
||||
} sub;
|
||||
struct
|
||||
{
|
||||
int count;
|
||||
char** topics;
|
||||
} unsub;
|
||||
struct
|
||||
{
|
||||
char* destinationName;
|
||||
int payloadlen;
|
||||
void* payload;
|
||||
int qos;
|
||||
int retained;
|
||||
} pub;
|
||||
struct
|
||||
{
|
||||
int internal;
|
||||
int timeout;
|
||||
enum MQTTReasonCodes reasonCode;
|
||||
} dis;
|
||||
struct
|
||||
{
|
||||
int currentURI;
|
||||
int MQTTVersion; /**< current MQTT version being used to connect */
|
||||
} conn;
|
||||
} details;
|
||||
} MQTTAsync_command;
|
||||
|
||||
typedef struct MQTTAsync_struct
|
||||
{
|
||||
char* serverURI;
|
||||
int ssl;
|
||||
int websocket;
|
||||
Clients* c;
|
||||
|
||||
/* "Global", to the client, callback definitions */
|
||||
MQTTAsync_connectionLost* cl;
|
||||
MQTTAsync_messageArrived* ma;
|
||||
MQTTAsync_deliveryComplete* dc;
|
||||
void* clContext; /* the context to be associated with the conn lost callback*/
|
||||
void* maContext; /* the context to be associated with the msg arrived callback*/
|
||||
void* dcContext; /* the context to be associated with the deliv complete callback*/
|
||||
|
||||
MQTTAsync_connected* connected;
|
||||
void* connected_context; /* the context to be associated with the connected callback*/
|
||||
|
||||
MQTTAsync_disconnected* disconnected;
|
||||
void* disconnected_context; /* the context to be associated with the disconnected callback*/
|
||||
|
||||
MQTTAsync_updateConnectOptions* updateConnectOptions;
|
||||
void* updateConnectOptions_context;
|
||||
|
||||
/* Each time connect is called, we store the options that were used. These are reused in
|
||||
any call to reconnect, or an automatic reconnect attempt */
|
||||
MQTTAsync_command connect; /* Connect operation properties */
|
||||
MQTTAsync_command disconnect; /* Disconnect operation properties */
|
||||
MQTTAsync_command* pending_write; /* Is there a socket write pending? */
|
||||
|
||||
List* responses;
|
||||
unsigned int command_seqno;
|
||||
|
||||
MQTTPacket* pack;
|
||||
|
||||
/* added for offline buffering */
|
||||
MQTTAsync_createOptions* createOptions;
|
||||
int shouldBeConnected;
|
||||
int noBufferedMessages; /* the current number of buffered (publish) messages for this client */
|
||||
|
||||
/* added for automatic reconnect */
|
||||
int automaticReconnect;
|
||||
int minRetryInterval;
|
||||
int maxRetryInterval;
|
||||
int serverURIcount;
|
||||
char** serverURIs;
|
||||
int connectTimeout;
|
||||
|
||||
int currentInterval;
|
||||
int currentIntervalBase;
|
||||
START_TIME_TYPE lastConnectionFailedTime;
|
||||
int retrying;
|
||||
int reconnectNow;
|
||||
|
||||
/* MQTT V5 properties */
|
||||
MQTTProperties* connectProps;
|
||||
MQTTProperties* willProps;
|
||||
|
||||
} MQTTAsyncs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MQTTAsync_command command;
|
||||
MQTTAsyncs* client;
|
||||
unsigned int seqno; /* only used on restore */
|
||||
int not_restored;
|
||||
char* key; /* if not_restored, this holds the key */
|
||||
} MQTTAsync_queuedCommand;
|
||||
|
||||
void MQTTAsync_lock_mutex(mutex_type amutex);
|
||||
void MQTTAsync_unlock_mutex(mutex_type amutex);
|
||||
void MQTTAsync_terminate(void);
|
||||
#if !defined(NO_PERSISTENCE)
|
||||
int MQTTAsync_restoreCommands(MQTTAsyncs* client);
|
||||
#endif
|
||||
int MQTTAsync_addCommand(MQTTAsync_queuedCommand* command, int command_size);
|
||||
void MQTTAsync_emptyMessageQueue(Clients* client);
|
||||
void MQTTAsync_freeResponses(MQTTAsyncs* m);
|
||||
void MQTTAsync_freeCommands(MQTTAsyncs* m);
|
||||
int MQTTAsync_unpersistCommandsAndMessages(Clients* c);
|
||||
void MQTTAsync_closeSession(Clients* client, enum MQTTReasonCodes reasonCode, MQTTProperties* props);
|
||||
int MQTTAsync_disconnect1(MQTTAsync handle, const MQTTAsync_disconnectOptions* options, int internal);
|
||||
int MQTTAsync_assignMsgId(MQTTAsyncs* m);
|
||||
int MQTTAsync_getNoBufferedMessages(MQTTAsyncs* m);
|
||||
void MQTTAsync_writeContinue(SOCKET socket);
|
||||
void MQTTAsync_writeComplete(SOCKET socket, int rc);
|
||||
void setRetryLoopInterval(int keepalive);
|
||||
void MQTTAsync_NULLPublishResponses(MQTTAsyncs* m);
|
||||
void MQTTAsync_NULLPublishCommands(MQTTAsyncs* m);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#else
|
||||
#define WINAPI
|
||||
#endif
|
||||
|
||||
thread_return_type WINAPI MQTTAsync_sendThread(void* n);
|
||||
thread_return_type WINAPI MQTTAsync_receiveThread(void* n);
|
||||
|
||||
#endif /* MQTTASYNCUTILS_H_ */
|
||||
3118
src/mqtt/externals/paho-mqtt-c/src/MQTTClient.c
vendored
Normal file
3118
src/mqtt/externals/paho-mqtt-c/src/MQTTClient.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1980
src/mqtt/externals/paho-mqtt-c/src/MQTTClient.h
vendored
Normal file
1980
src/mqtt/externals/paho-mqtt-c/src/MQTTClient.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
277
src/mqtt/externals/paho-mqtt-c/src/MQTTClientPersistence.h
vendored
Normal file
277
src/mqtt/externals/paho-mqtt-c/src/MQTTClientPersistence.h
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief This structure represents a persistent data store, used to store
|
||||
* outbound and inbound messages, in order to achieve reliable messaging.
|
||||
*
|
||||
* The MQTT Client persists QoS1 and QoS2 messages in order to meet the
|
||||
* assurances of delivery associated with these @ref qos levels. The messages
|
||||
* are saved in persistent storage
|
||||
* The type and context of the persistence implementation are specified when
|
||||
* the MQTT client is created (see MQTTClient_create()). The default
|
||||
* persistence type (::MQTTCLIENT_PERSISTENCE_DEFAULT) uses a file system-based
|
||||
* persistence mechanism. The <i>persistence_context</i> argument passed to
|
||||
* MQTTClient_create() when using the default peristence is a string
|
||||
* representing the location of the persistence directory. If the context
|
||||
* argument is NULL, the working directory will be used.
|
||||
*
|
||||
* To use memory-based persistence, an application passes
|
||||
* ::MQTTCLIENT_PERSISTENCE_NONE as the <i>persistence_type</i> to
|
||||
* MQTTClient_create(). This can lead to message loss in certain situations,
|
||||
* but can be appropriate in some cases (see @ref qos).
|
||||
*
|
||||
* Client applications can provide their own persistence mechanism by passing
|
||||
* ::MQTTCLIENT_PERSISTENCE_USER as the <i>persistence_type</i>. To implement a
|
||||
* custom persistence mechanism, the application must pass an initialized
|
||||
* ::MQTTClient_persistence structure as the <i>persistence_context</i>
|
||||
* argument to MQTTClient_create().
|
||||
*
|
||||
* If the functions defined return an ::MQTTCLIENT_PERSISTENCE_ERROR then the
|
||||
* state of the persisted data should remain as it was prior to the function
|
||||
* being called. For example, if Persistence_put() returns
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR, then it is assumed tha tthe persistent store
|
||||
* does not contain the data that was passed to the function. Similarly, if
|
||||
* Persistence_remove() returns ::MQTTCLIENT_PERSISTENCE_ERROR then it is
|
||||
* assumed that the data to be removed is still held in the persistent store.
|
||||
*
|
||||
* It is up to the persistence implementation to log any error information that
|
||||
* may be required to diagnose a persistence mechanism failure.
|
||||
*/
|
||||
|
||||
/*
|
||||
/// @cond EXCLUDE
|
||||
*/
|
||||
#if !defined(MQTTCLIENTPERSISTENCE_H)
|
||||
#define MQTTCLIENTPERSISTENCE_H
|
||||
/*
|
||||
/// @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* This <i>persistence_type</i> value specifies the default file system-based
|
||||
* persistence mechanism (see MQTTClient_create()).
|
||||
*/
|
||||
#define MQTTCLIENT_PERSISTENCE_DEFAULT 0
|
||||
/**
|
||||
* This <i>persistence_type</i> value specifies a memory-based
|
||||
* persistence mechanism (see MQTTClient_create()).
|
||||
*/
|
||||
#define MQTTCLIENT_PERSISTENCE_NONE 1
|
||||
/**
|
||||
* This <i>persistence_type</i> value specifies an application-specific
|
||||
* persistence mechanism (see MQTTClient_create()).
|
||||
*/
|
||||
#define MQTTCLIENT_PERSISTENCE_USER 2
|
||||
|
||||
/**
|
||||
* Application-specific persistence functions must return this error code if
|
||||
* there is a problem executing the function.
|
||||
*/
|
||||
#define MQTTCLIENT_PERSISTENCE_ERROR -2
|
||||
|
||||
/**
|
||||
* @brief Initialize the persistent store.
|
||||
*
|
||||
* Either open the existing persistent store for this client ID or create a new
|
||||
* one if one doesn't exist. If the persistent store is already open, return
|
||||
* without taking any action.
|
||||
*
|
||||
* An application can use the same client identifier to connect to many
|
||||
* different servers. The <i>clientid</i> in conjunction with the
|
||||
* <i>serverURI</i> uniquely identifies the persistence store required.
|
||||
*
|
||||
* @param handle The address of a pointer to a handle for this persistence
|
||||
* implementation. This function must set handle to a valid reference to the
|
||||
* persistence following a successful return.
|
||||
* The handle pointer is passed as an argument to all the other
|
||||
* persistence functions. It may include the context parameter and/or any other
|
||||
* data for use by the persistence functions.
|
||||
* @param clientID The client identifier for which the persistent store should
|
||||
* be opened.
|
||||
* @param serverURI The connection string specified when the MQTT client was
|
||||
* created (see MQTTClient_create()).
|
||||
* @param context A pointer to any data required to initialize the persistent
|
||||
* store (see ::MQTTClient_persistence).
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_open)(void** handle, const char* clientID, const char* serverURI, void* context);
|
||||
|
||||
/**
|
||||
* @brief Close the persistent store referred to by the handle.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_close)(void* handle);
|
||||
|
||||
/**
|
||||
* @brief Put the specified data into the persistent store.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @param key A string used as the key for the data to be put in the store. The
|
||||
* key is later used to retrieve data from the store with Persistence_get().
|
||||
* @param bufcount The number of buffers to write to the persistence store.
|
||||
* @param buffers An array of pointers to the data buffers associated with
|
||||
* this <i>key</i>.
|
||||
* @param buflens An array of lengths of the data buffers. <i>buflen[n]</i>
|
||||
* gives the length of <i>buffer[n]</i>.
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_put)(void* handle, char* key, int bufcount, char* buffers[], int buflens[]);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the specified data from the persistent store.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @param key A string that is the key for the data to be retrieved. This is
|
||||
* the same key used to save the data to the store with Persistence_put().
|
||||
* @param buffer The address of a pointer to a buffer. This function sets the
|
||||
* pointer to point at the retrieved data, if successful.
|
||||
* @param buflen The address of an int that is set to the length of
|
||||
* <i>buffer</i> by this function if successful.
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_get)(void* handle, char* key, char** buffer, int* buflen);
|
||||
|
||||
/**
|
||||
* @brief Remove the data for the specified key from the store.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @param key A string that is the key for the data to be removed from the
|
||||
* store. This is the same key used to save the data to the store with
|
||||
* Persistence_put().
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_remove)(void* handle, char* key);
|
||||
|
||||
/**
|
||||
* @brief Returns the keys in this persistent data store.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @param keys The address of a pointer to pointers to strings. Assuming
|
||||
* successful execution, this function allocates memory to hold the returned
|
||||
* keys (strings used to store the data with Persistence_put()). It also
|
||||
* allocates memory to hold an array of pointers to these strings. <i>keys</i>
|
||||
* is set to point to the array of pointers to strings.
|
||||
* @param nkeys A pointer to the number of keys in this persistent data store.
|
||||
* This function sets the number of keys, if successful.
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_keys)(void* handle, char*** keys, int* nkeys);
|
||||
|
||||
/**
|
||||
* @brief Clears the persistence store, so that it no longer contains any
|
||||
* persisted data.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @return Return 0 if the function completes successfully, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_clear)(void* handle);
|
||||
|
||||
/**
|
||||
* @brief Returns whether any data has been persisted using the specified key.
|
||||
*
|
||||
* @param handle The handle pointer from a successful call to
|
||||
* Persistence_open().
|
||||
* @param key The string to be tested for existence in the store.
|
||||
* @return Return 0 if the key was found in the store, otherwise return
|
||||
* ::MQTTCLIENT_PERSISTENCE_ERROR.
|
||||
*/
|
||||
typedef int (*Persistence_containskey)(void* handle, char* key);
|
||||
|
||||
/**
|
||||
* @brief A structure containing the function pointers to a persistence
|
||||
* implementation and the context or state that will be shared across all
|
||||
* the persistence functions.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* A pointer to any data required to initialize the persistent store.
|
||||
*/
|
||||
void* context;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_open().
|
||||
*/
|
||||
Persistence_open popen;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_close().
|
||||
*/
|
||||
Persistence_close pclose;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_put().
|
||||
*/
|
||||
Persistence_put pput;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_get().
|
||||
*/
|
||||
Persistence_get pget;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_remove().
|
||||
*/
|
||||
Persistence_remove premove;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_keys().
|
||||
*/
|
||||
Persistence_keys pkeys;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_clear().
|
||||
*/
|
||||
Persistence_clear pclear;
|
||||
/**
|
||||
* A function pointer to an implementation of Persistence_containskey().
|
||||
*/
|
||||
Persistence_containskey pcontainskey;
|
||||
} MQTTClient_persistence;
|
||||
|
||||
|
||||
/**
|
||||
* A callback which is invoked just before a write to persistence. This can be
|
||||
* used to transform the data, for instance to encrypt it.
|
||||
* @param context The context as set in ::MQTTAsync_setBeforePersistenceWrite
|
||||
* @param bufcount The number of buffers to write to the persistence store.
|
||||
* @param buffers An array of pointers to the data buffers.
|
||||
* @param buflens An array of lengths of the data buffers.
|
||||
* @return Return 0 if the function completes successfully, otherwise non 0.
|
||||
*/
|
||||
typedef int MQTTPersistence_beforeWrite(void* context, int bufcount, char* buffers[], int buflens[]);
|
||||
|
||||
|
||||
/**
|
||||
* A callback which is invoked just after a read from persistence. This can be
|
||||
* used to transform the data, for instance to decrypt it.
|
||||
* @param context The context as set in ::MQTTAsync_setAfterPersistenceRead
|
||||
* @param buffer The address of a pointer to a buffer.
|
||||
* @param buflen The address of an int that is the length of the buffer.
|
||||
* @return Return 0 if the function completes successfully, otherwise non 0.
|
||||
*/
|
||||
typedef int MQTTPersistence_afterRead(void* context, char** buffer, int* buflen);
|
||||
|
||||
#endif
|
||||
36
src/mqtt/externals/paho-mqtt-c/src/MQTTExportDeclarations.h
vendored
Normal file
36
src/mqtt/externals/paho-mqtt-c/src/MQTTExportDeclarations.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020, 2020 Andreas Walter
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Andreas Walter - initially moved export declarations into separate fle
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(EXPORTDECLARATIONS_H)
|
||||
#define EXPORTDECLARATIONS_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# if defined(PAHO_MQTT_EXPORTS)
|
||||
# define LIBMQTT_API __declspec(dllexport)
|
||||
# elif defined(PAHO_MQTT_IMPORTS)
|
||||
# define LIBMQTT_API __declspec(dllimport)
|
||||
# else
|
||||
# define LIBMQTT_API
|
||||
# endif
|
||||
#else
|
||||
# if defined(PAHO_MQTT_EXPORTS)
|
||||
# define LIBMQTT_API __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define LIBMQTT_API extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1077
src/mqtt/externals/paho-mqtt-c/src/MQTTPacket.c
vendored
Normal file
1077
src/mqtt/externals/paho-mqtt-c/src/MQTTPacket.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
271
src/mqtt/externals/paho-mqtt-c/src/MQTTPacket.h
vendored
Normal file
271
src/mqtt/externals/paho-mqtt-c/src/MQTTPacket.h
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - MQTT 3.1.1 support
|
||||
* Ian Craggs - big endian Linux reversed definition
|
||||
* Ian Craggs - MQTT 5.0 support
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPACKET_H)
|
||||
#define MQTTPACKET_H
|
||||
|
||||
#include "Socket.h"
|
||||
#if defined(OPENSSL)
|
||||
#include "SSLSocket.h"
|
||||
#endif
|
||||
#include "LinkedList.h"
|
||||
#include "Clients.h"
|
||||
|
||||
typedef unsigned int bool;
|
||||
typedef void* (*pf)(int, unsigned char, char*, size_t);
|
||||
|
||||
#include "MQTTProperties.h"
|
||||
#include "MQTTReasonCodes.h"
|
||||
|
||||
enum errors
|
||||
{
|
||||
MQTTPACKET_BAD = -4,
|
||||
MQTTPACKET_BUFFER_TOO_SHORT = -2,
|
||||
MQTTPACKET_READ_ERROR = -1,
|
||||
MQTTPACKET_READ_COMPLETE
|
||||
};
|
||||
|
||||
|
||||
enum msgTypes
|
||||
{
|
||||
CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
|
||||
PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
|
||||
PINGREQ, PINGRESP, DISCONNECT, AUTH
|
||||
};
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define REVERSED 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Bitfields for the MQTT header byte.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
/*unsigned*/ char byte; /**< the whole byte */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int type : 4; /**< message type nibble */
|
||||
bool dup : 1; /**< DUP flag bit */
|
||||
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
|
||||
bool retain : 1; /**< retained flag bit */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
bool retain : 1; /**< retained flag bit */
|
||||
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
|
||||
bool dup : 1; /**< DUP flag bit */
|
||||
unsigned int type : 4; /**< message type nibble */
|
||||
} bits;
|
||||
#endif
|
||||
} Header;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a connect packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
union
|
||||
{
|
||||
unsigned char all; /**< all connect flags */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
bool username : 1; /**< 3.1 user name */
|
||||
bool password : 1; /**< 3.1 password */
|
||||
bool willRetain : 1; /**< will retain setting */
|
||||
unsigned int willQoS : 2; /**< will QoS value */
|
||||
bool will : 1; /**< will flag */
|
||||
bool cleanstart : 1; /**< cleansession flag */
|
||||
int : 1; /**< unused */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
int : 1; /**< unused */
|
||||
bool cleanstart : 1; /**< cleansession flag */
|
||||
bool will : 1; /**< will flag */
|
||||
unsigned int willQoS : 2; /**< will QoS value */
|
||||
bool willRetain : 1; /**< will retain setting */
|
||||
bool password : 1; /**< 3.1 password */
|
||||
bool username : 1; /**< 3.1 user name */
|
||||
} bits;
|
||||
#endif
|
||||
} flags; /**< connect flags byte */
|
||||
|
||||
char *Protocol, /**< MQTT protocol name */
|
||||
*clientID, /**< string client id */
|
||||
*willTopic, /**< will topic */
|
||||
*willMsg; /**< will payload */
|
||||
|
||||
int keepAliveTimer; /**< keepalive timeout value in seconds */
|
||||
unsigned char version; /**< MQTT version number */
|
||||
} Connect;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a connack packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
union
|
||||
{
|
||||
unsigned char all; /**< all connack flags */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int reserved : 7; /**< message type nibble */
|
||||
bool sessionPresent : 1; /**< was a session found on the server? */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
bool sessionPresent : 1; /**< was a session found on the server? */
|
||||
unsigned int reserved : 7; /**< message type nibble */
|
||||
} bits;
|
||||
#endif
|
||||
} flags; /**< connack flags byte */
|
||||
unsigned char rc; /**< connack reason code */
|
||||
unsigned int MQTTVersion; /**< the version of MQTT */
|
||||
MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */
|
||||
} Connack;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a packet with header only.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
} MQTTPacket;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a suback packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
int msgId; /**< MQTT message id */
|
||||
int MQTTVersion; /**< the version of MQTT */
|
||||
MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */
|
||||
List* qoss; /**< list of granted QoSs (MQTT 3/4) / reason codes (MQTT 5) */
|
||||
} Suback;
|
||||
|
||||
|
||||
/**
|
||||
* Data for an MQTT V5 unsuback packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
int msgId; /**< MQTT message id */
|
||||
int MQTTVersion; /**< the version of MQTT */
|
||||
MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */
|
||||
List* reasonCodes; /**< list of reason codes */
|
||||
} Unsuback;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a publish packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
char* topic; /**< topic string */
|
||||
int topiclen;
|
||||
int msgId; /**< MQTT message id */
|
||||
char* payload; /**< binary payload, length delimited */
|
||||
int payloadlen; /**< payload length */
|
||||
int MQTTVersion; /**< the version of MQTT */
|
||||
MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */
|
||||
uint8_t mask[4]; /**< the websockets mask the payload is masked with, if any */
|
||||
} Publish;
|
||||
|
||||
|
||||
/**
|
||||
* Data for one of the ack packets.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
int msgId; /**< MQTT message id */
|
||||
unsigned char rc; /**< MQTT 5 reason code */
|
||||
int MQTTVersion; /**< the version of MQTT */
|
||||
MQTTProperties properties; /**< MQTT 5.0 properties. Not used for MQTT < 5.0 */
|
||||
} Ack;
|
||||
|
||||
typedef Ack Puback;
|
||||
typedef Ack Pubrec;
|
||||
typedef Ack Pubrel;
|
||||
typedef Ack Pubcomp;
|
||||
|
||||
int MQTTPacket_encode(char* buf, size_t length);
|
||||
int MQTTPacket_decode(networkHandles* net, size_t* value);
|
||||
int readInt(char** pptr);
|
||||
char* readUTF(char** pptr, char* enddata);
|
||||
unsigned char readChar(char** pptr);
|
||||
void writeChar(char** pptr, char c);
|
||||
void writeInt(char** pptr, int anInt);
|
||||
void writeUTF(char** pptr, const char* string);
|
||||
void writeData(char** pptr, const void* data, int datalen);
|
||||
|
||||
const char* MQTTPacket_name(int ptype);
|
||||
|
||||
void* MQTTPacket_Factory(int MQTTVersion, networkHandles* net, int* error);
|
||||
int MQTTPacket_send(networkHandles* net, Header header, char* buffer, size_t buflen, int free, int MQTTVersion);
|
||||
int MQTTPacket_sends(networkHandles* net, Header header, PacketBuffers* buffers, int MQTTVersion);
|
||||
|
||||
void* MQTTPacket_header_only(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen);
|
||||
int MQTTPacket_send_disconnect(Clients* client, enum MQTTReasonCodes reason, MQTTProperties* props);
|
||||
|
||||
void* MQTTPacket_publish(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen);
|
||||
void MQTTPacket_freePublish(Publish* pack);
|
||||
int MQTTPacket_send_publish(Publish* pack, int dup, int qos, int retained, networkHandles* net, const char* clientID);
|
||||
int MQTTPacket_send_puback(int MQTTVersion, int msgid, networkHandles* net, const char* clientID);
|
||||
void* MQTTPacket_ack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen);
|
||||
|
||||
void MQTTPacket_freeAck(Ack* pack);
|
||||
void MQTTPacket_freeSuback(Suback* pack);
|
||||
void MQTTPacket_freeUnsuback(Unsuback* pack);
|
||||
int MQTTPacket_send_pubrec(int MQTTVersion, int msgid, networkHandles* net, const char* clientID);
|
||||
int MQTTPacket_send_pubrel(int MQTTVersion, int msgid, int dup, networkHandles* net, const char* clientID);
|
||||
int MQTTPacket_send_pubcomp(int MQTTVersion, int msgid, networkHandles* net, const char* clientID);
|
||||
|
||||
void MQTTPacket_free_packet(MQTTPacket* pack);
|
||||
|
||||
void writeInt4(char** pptr, unsigned int anInt);
|
||||
unsigned int readInt4(char** pptr);
|
||||
void writeMQTTLenString(char** pptr, MQTTLenString lenstring);
|
||||
int MQTTLenStringRead(MQTTLenString* lenstring, char** pptr, char* enddata);
|
||||
int MQTTPacket_VBIlen(int rem_len);
|
||||
int MQTTPacket_decodeBuf(char* buf, unsigned int* value);
|
||||
|
||||
#include "MQTTPacketOut.h"
|
||||
|
||||
#endif /* MQTTPACKET_H */
|
||||
473
src/mqtt/externals/paho-mqtt-c/src/MQTTPacketOut.c
vendored
Normal file
473
src/mqtt/externals/paho-mqtt-c/src/MQTTPacketOut.c
vendored
Normal file
@@ -0,0 +1,473 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2021 IBM Corp. and Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - MQTT 3.1.1 support
|
||||
* Rong Xiang, Ian Craggs - C++ compatibility
|
||||
* Ian Craggs - binary password and will payload
|
||||
* Ian Craggs - MQTT 5.0 support
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief functions to deal with reading and writing of MQTT packets from and to sockets
|
||||
*
|
||||
* Some other related functions are in the MQTTPacket module
|
||||
*/
|
||||
|
||||
|
||||
#include "MQTTPacketOut.h"
|
||||
#include "Log.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Heap.h"
|
||||
|
||||
|
||||
/**
|
||||
* Send an MQTT CONNECT packet down a socket for V5 or later
|
||||
* @param client a structure from which to get all the required values
|
||||
* @param MQTTVersion the MQTT version to connect with
|
||||
* @param connectProperties MQTT V5 properties for the connect packet
|
||||
* @param willProperties MQTT V5 properties for the will message, if any
|
||||
* @return the completion code (e.g. TCPSOCKET_COMPLETE)
|
||||
*/
|
||||
int MQTTPacket_send_connect(Clients* client, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties)
|
||||
{
|
||||
char *buf, *ptr;
|
||||
Connect packet;
|
||||
int rc = SOCKET_ERROR, len;
|
||||
|
||||
FUNC_ENTRY;
|
||||
packet.header.byte = 0;
|
||||
packet.header.bits.type = CONNECT;
|
||||
|
||||
len = ((MQTTVersion == MQTTVERSION_3_1) ? 12 : 10) + (int)strlen(client->clientID)+2;
|
||||
if (client->will)
|
||||
len += (int)strlen(client->will->topic)+2 + client->will->payloadlen+2;
|
||||
if (client->username)
|
||||
len += (int)strlen(client->username)+2;
|
||||
if (client->password)
|
||||
len += client->passwordlen+2;
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
{
|
||||
len += MQTTProperties_len(connectProperties);
|
||||
if (client->will)
|
||||
len += MQTTProperties_len(willProperties);
|
||||
}
|
||||
|
||||
ptr = buf = malloc(len);
|
||||
if (ptr == NULL)
|
||||
goto exit_nofree;
|
||||
if (MQTTVersion == MQTTVERSION_3_1)
|
||||
{
|
||||
writeUTF(&ptr, "MQIsdp");
|
||||
writeChar(&ptr, (char)MQTTVERSION_3_1);
|
||||
}
|
||||
else if (MQTTVersion == MQTTVERSION_3_1_1 || MQTTVersion == MQTTVERSION_5)
|
||||
{
|
||||
writeUTF(&ptr, "MQTT");
|
||||
writeChar(&ptr, (char)MQTTVersion);
|
||||
}
|
||||
else
|
||||
goto exit;
|
||||
|
||||
packet.flags.all = 0;
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
packet.flags.bits.cleanstart = client->cleanstart;
|
||||
else
|
||||
packet.flags.bits.cleanstart = client->cleansession;
|
||||
packet.flags.bits.will = (client->will) ? 1 : 0;
|
||||
if (packet.flags.bits.will)
|
||||
{
|
||||
packet.flags.bits.willQoS = client->will->qos;
|
||||
packet.flags.bits.willRetain = client->will->retained;
|
||||
}
|
||||
if (client->username)
|
||||
packet.flags.bits.username = 1;
|
||||
if (client->password)
|
||||
packet.flags.bits.password = 1;
|
||||
|
||||
writeChar(&ptr, packet.flags.all);
|
||||
writeInt(&ptr, client->keepAliveInterval);
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
MQTTProperties_write(&ptr, connectProperties);
|
||||
writeUTF(&ptr, client->clientID);
|
||||
if (client->will)
|
||||
{
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
MQTTProperties_write(&ptr, willProperties);
|
||||
writeUTF(&ptr, client->will->topic);
|
||||
writeData(&ptr, client->will->payload, client->will->payloadlen);
|
||||
}
|
||||
if (client->username)
|
||||
writeUTF(&ptr, client->username);
|
||||
if (client->password)
|
||||
writeData(&ptr, client->password, client->passwordlen);
|
||||
|
||||
rc = MQTTPacket_send(&client->net, packet.header, buf, len, 1, MQTTVersion);
|
||||
Log(LOG_PROTOCOL, 0, NULL, client->net.socket, client->clientID,
|
||||
MQTTVersion, client->cleansession, rc);
|
||||
exit:
|
||||
if (rc != TCPSOCKET_INTERRUPTED)
|
||||
free(buf);
|
||||
exit_nofree:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function used in the new packets table to create connack packets.
|
||||
* @param MQTTVersion MQTT 5 or less?
|
||||
* @param aHeader the MQTT header byte
|
||||
* @param data the rest of the packet
|
||||
* @param datalen the length of the rest of the packet
|
||||
* @return pointer to the packet structure
|
||||
*/
|
||||
void* MQTTPacket_connack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen)
|
||||
{
|
||||
Connack* pack = NULL;
|
||||
char* curdata = data;
|
||||
char* enddata = &data[datalen];
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((pack = malloc(sizeof(Connack))) == NULL)
|
||||
goto exit;
|
||||
pack->MQTTVersion = MQTTVersion;
|
||||
pack->header.byte = aHeader;
|
||||
if (datalen < 2) /* enough data for connect flags and reason code? */
|
||||
{
|
||||
free(pack);
|
||||
pack = NULL;
|
||||
goto exit;
|
||||
}
|
||||
pack->flags.all = readChar(&curdata); /* connect flags */
|
||||
pack->rc = readChar(&curdata); /* reason code */
|
||||
if (MQTTVersion >= MQTTVERSION_5 && datalen > 2)
|
||||
{
|
||||
MQTTProperties props = MQTTProperties_initializer;
|
||||
pack->properties = props;
|
||||
if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1)
|
||||
{
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
if (pack)
|
||||
free(pack);
|
||||
pack = NULL; /* signal protocol error */
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT;
|
||||
return pack;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free allocated storage for a connack packet.
|
||||
* @param pack pointer to the connack packet structure
|
||||
*/
|
||||
void MQTTPacket_freeConnack(Connack* pack)
|
||||
{
|
||||
FUNC_ENTRY;
|
||||
if (pack->MQTTVersion >= MQTTVERSION_5)
|
||||
MQTTProperties_free(&pack->properties);
|
||||
free(pack);
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an MQTT PINGREQ packet down a socket.
|
||||
* @param socket the open socket to send the data to
|
||||
* @param clientID the string client identifier, only used for tracing
|
||||
* @return the completion code (e.g. TCPSOCKET_COMPLETE)
|
||||
*/
|
||||
int MQTTPacket_send_pingreq(networkHandles* net, const char* clientID)
|
||||
{
|
||||
Header header;
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = 0;
|
||||
header.bits.type = PINGREQ;
|
||||
rc = MQTTPacket_send(net, header, NULL, 0, 0, MQTTVERSION_3_1_1);
|
||||
Log(LOG_PROTOCOL, 20, NULL, net->socket, clientID, rc);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an MQTT subscribe packet down a socket.
|
||||
* @param topics list of topics
|
||||
* @param qoss list of corresponding QoSs
|
||||
* @param msgid the MQTT message id to use
|
||||
* @param dup boolean - whether to set the MQTT DUP flag
|
||||
* @param socket the open socket to send the data to
|
||||
* @param clientID the string client identifier, only used for tracing
|
||||
* @return the completion code (e.g. TCPSOCKET_COMPLETE)
|
||||
*/
|
||||
int MQTTPacket_send_subscribe(List* topics, List* qoss, MQTTSubscribe_options* opts, MQTTProperties* props,
|
||||
int msgid, int dup, Clients* client)
|
||||
{
|
||||
Header header;
|
||||
char *data, *ptr;
|
||||
int rc = -1;
|
||||
ListElement *elem = NULL, *qosElem = NULL;
|
||||
int datalen, i = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.bits.type = SUBSCRIBE;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = 1;
|
||||
header.bits.retain = 0;
|
||||
|
||||
datalen = 2 + topics->count * 3; /* utf length + char qos == 3 */
|
||||
while (ListNextElement(topics, &elem))
|
||||
datalen += (int)strlen((char*)(elem->content));
|
||||
if (client->MQTTVersion >= MQTTVERSION_5)
|
||||
datalen += MQTTProperties_len(props);
|
||||
|
||||
ptr = data = malloc(datalen);
|
||||
if (ptr == NULL)
|
||||
goto exit;
|
||||
writeInt(&ptr, msgid);
|
||||
|
||||
if (client->MQTTVersion >= MQTTVERSION_5)
|
||||
MQTTProperties_write(&ptr, props);
|
||||
|
||||
elem = NULL;
|
||||
while (ListNextElement(topics, &elem))
|
||||
{
|
||||
char subopts = 0;
|
||||
|
||||
ListNextElement(qoss, &qosElem);
|
||||
writeUTF(&ptr, (char*)(elem->content));
|
||||
subopts = *(int*)(qosElem->content);
|
||||
if (client->MQTTVersion >= MQTTVERSION_5 && opts != NULL)
|
||||
{
|
||||
subopts |= (opts[i].noLocal << 2); /* 1 bit */
|
||||
subopts |= (opts[i].retainAsPublished << 3); /* 1 bit */
|
||||
subopts |= (opts[i].retainHandling << 4); /* 2 bits */
|
||||
}
|
||||
writeChar(&ptr, subopts);
|
||||
++i;
|
||||
}
|
||||
rc = MQTTPacket_send(&client->net, header, data, datalen, 1, client->MQTTVersion);
|
||||
Log(LOG_PROTOCOL, 22, NULL, client->net.socket, client->clientID, msgid, rc);
|
||||
if (rc != TCPSOCKET_INTERRUPTED)
|
||||
free(data);
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function used in the new packets table to create suback packets.
|
||||
* @param MQTTVersion the version of MQTT
|
||||
* @param aHeader the MQTT header byte
|
||||
* @param data the rest of the packet
|
||||
* @param datalen the length of the rest of the packet
|
||||
* @return pointer to the packet structure
|
||||
*/
|
||||
void* MQTTPacket_suback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen)
|
||||
{
|
||||
Suback* pack = NULL;
|
||||
char* curdata = data;
|
||||
char* enddata = &data[datalen];
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((pack = malloc(sizeof(Suback))) == NULL)
|
||||
goto exit;
|
||||
pack->MQTTVersion = MQTTVersion;
|
||||
pack->header.byte = aHeader;
|
||||
if (enddata - curdata < 2) /* Is there enough data to read the msgid? */
|
||||
{
|
||||
free(pack);
|
||||
pack = NULL;
|
||||
goto exit;
|
||||
}
|
||||
pack->msgId = readInt(&curdata);
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
{
|
||||
MQTTProperties props = MQTTProperties_initializer;
|
||||
pack->properties = props;
|
||||
if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1)
|
||||
{
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
if (pack)
|
||||
free(pack);
|
||||
pack = NULL; /* signal protocol error */
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
pack->qoss = ListInitialize();
|
||||
while ((size_t)(curdata - data) < datalen)
|
||||
{
|
||||
unsigned int* newint;
|
||||
newint = malloc(sizeof(unsigned int));
|
||||
if (newint == NULL)
|
||||
{
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
if (pack)
|
||||
free(pack);
|
||||
pack = NULL; /* signal protocol error */
|
||||
goto exit;
|
||||
}
|
||||
*newint = (unsigned int)readChar(&curdata);
|
||||
ListAppend(pack->qoss, newint, sizeof(unsigned int));
|
||||
}
|
||||
if (pack->qoss->count == 0)
|
||||
{
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
ListFree(pack->qoss);
|
||||
free(pack);
|
||||
pack = NULL;
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT;
|
||||
return pack;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an MQTT unsubscribe packet down a socket.
|
||||
* @param topics list of topics
|
||||
* @param msgid the MQTT message id to use
|
||||
* @param dup boolean - whether to set the MQTT DUP flag
|
||||
* @param socket the open socket to send the data to
|
||||
* @param clientID the string client identifier, only used for tracing
|
||||
* @return the completion code (e.g. TCPSOCKET_COMPLETE)
|
||||
*/
|
||||
int MQTTPacket_send_unsubscribe(List* topics, MQTTProperties* props, int msgid, int dup, Clients* client)
|
||||
{
|
||||
Header header;
|
||||
char *data, *ptr;
|
||||
int rc = SOCKET_ERROR;
|
||||
ListElement *elem = NULL;
|
||||
int datalen;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.bits.type = UNSUBSCRIBE;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = 1;
|
||||
header.bits.retain = 0;
|
||||
|
||||
datalen = 2 + topics->count * 2; /* utf length == 2 */
|
||||
while (ListNextElement(topics, &elem))
|
||||
datalen += (int)strlen((char*)(elem->content));
|
||||
if (client->MQTTVersion >= MQTTVERSION_5)
|
||||
datalen += MQTTProperties_len(props);
|
||||
ptr = data = malloc(datalen);
|
||||
if (ptr == NULL)
|
||||
goto exit;
|
||||
|
||||
writeInt(&ptr, msgid);
|
||||
|
||||
if (client->MQTTVersion >= MQTTVERSION_5)
|
||||
MQTTProperties_write(&ptr, props);
|
||||
|
||||
elem = NULL;
|
||||
while (ListNextElement(topics, &elem))
|
||||
writeUTF(&ptr, (char*)(elem->content));
|
||||
rc = MQTTPacket_send(&client->net, header, data, datalen, 1, client->MQTTVersion);
|
||||
Log(LOG_PROTOCOL, 25, NULL, client->net.socket, client->clientID, msgid, rc);
|
||||
if (rc != TCPSOCKET_INTERRUPTED)
|
||||
free(data);
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function used in the new packets table to create unsuback packets.
|
||||
* @param MQTTVersion the version of MQTT
|
||||
* @param aHeader the MQTT header byte
|
||||
* @param data the rest of the packet
|
||||
* @param datalen the length of the rest of the packet
|
||||
* @return pointer to the packet structure
|
||||
*/
|
||||
void* MQTTPacket_unsuback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen)
|
||||
{
|
||||
Unsuback* pack = NULL;
|
||||
char* curdata = data;
|
||||
char* enddata = &data[datalen];
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((pack = malloc(sizeof(Unsuback))) == NULL)
|
||||
goto exit;
|
||||
pack->MQTTVersion = MQTTVersion;
|
||||
pack->header.byte = aHeader;
|
||||
if (enddata - curdata < 2) /* Is there enough data? */
|
||||
{
|
||||
free(pack);
|
||||
pack = NULL;
|
||||
goto exit;
|
||||
}
|
||||
pack->msgId = readInt(&curdata);
|
||||
pack->reasonCodes = NULL;
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
{
|
||||
MQTTProperties props = MQTTProperties_initializer;
|
||||
pack->properties = props;
|
||||
if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1)
|
||||
{
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
if (pack)
|
||||
free(pack);
|
||||
pack = NULL; /* signal protocol error */
|
||||
goto exit;
|
||||
}
|
||||
pack->reasonCodes = ListInitialize();
|
||||
while ((size_t)(curdata - data) < datalen)
|
||||
{
|
||||
enum MQTTReasonCodes* newrc;
|
||||
newrc = malloc(sizeof(enum MQTTReasonCodes));
|
||||
if (newrc == NULL)
|
||||
{
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
if (pack)
|
||||
free(pack);
|
||||
pack = NULL; /* signal protocol error */
|
||||
goto exit;
|
||||
}
|
||||
*newrc = (enum MQTTReasonCodes)readChar(&curdata);
|
||||
ListAppend(pack->reasonCodes, newrc, sizeof(enum MQTTReasonCodes));
|
||||
}
|
||||
if (pack->reasonCodes->count == 0)
|
||||
{
|
||||
ListFree(pack->reasonCodes);
|
||||
if (pack->properties.array)
|
||||
free(pack->properties.array);
|
||||
if (pack)
|
||||
free(pack);
|
||||
pack = NULL;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT;
|
||||
return pack;
|
||||
}
|
||||
39
src/mqtt/externals/paho-mqtt-c/src/MQTTPacketOut.h
vendored
Normal file
39
src/mqtt/externals/paho-mqtt-c/src/MQTTPacketOut.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2018 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - MQTT 3.1.1 support
|
||||
* Ian Craggs - MQTT 5.0 support
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPACKETOUT_H)
|
||||
#define MQTTPACKETOUT_H
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
|
||||
int MQTTPacket_send_connect(Clients* client, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties);
|
||||
void* MQTTPacket_connack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen);
|
||||
void MQTTPacket_freeConnack(Connack* pack);
|
||||
|
||||
int MQTTPacket_send_pingreq(networkHandles* net, const char* clientID);
|
||||
|
||||
int MQTTPacket_send_subscribe(List* topics, List* qoss, MQTTSubscribe_options* opts, MQTTProperties* props,
|
||||
int msgid, int dup, Clients* client);
|
||||
void* MQTTPacket_suback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen);
|
||||
|
||||
int MQTTPacket_send_unsubscribe(List* topics, MQTTProperties* props, int msgid, int dup, Clients* client);
|
||||
void* MQTTPacket_unsuback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen);
|
||||
|
||||
#endif
|
||||
921
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistence.c
vendored
Normal file
921
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistence.c
vendored
Normal file
@@ -0,0 +1,921 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - async client updates
|
||||
* Ian Craggs - fix for bug 432903 - queue persistence
|
||||
* Ian Craggs - MQTT V5 updates
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Functions that apply to persistence operations.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MQTTPersistence.h"
|
||||
#include "MQTTPersistenceDefault.h"
|
||||
#include "MQTTProtocolClient.h"
|
||||
#include "Heap.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
static MQTTPersistence_qEntry* MQTTPersistence_restoreQueueEntry(char* buffer, size_t buflen, int MQTTVersion);
|
||||
static void MQTTPersistence_insertInSeqOrder(List* list, MQTTPersistence_qEntry* qEntry, size_t size);
|
||||
|
||||
/**
|
||||
* Creates a ::MQTTClient_persistence structure representing a persistence implementation.
|
||||
* @param persistence the ::MQTTClient_persistence structure.
|
||||
* @param type the type of the persistence implementation. See ::MQTTClient_create.
|
||||
* @param pcontext the context for this persistence implementation. See ::MQTTClient_create.
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
#include "StackTrace.h"
|
||||
|
||||
int MQTTPersistence_create(MQTTClient_persistence** persistence, int type, void* pcontext)
|
||||
{
|
||||
int rc = 0;
|
||||
MQTTClient_persistence* per = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if !defined(NO_PERSISTENCE)
|
||||
switch (type)
|
||||
{
|
||||
case MQTTCLIENT_PERSISTENCE_NONE :
|
||||
per = NULL;
|
||||
break;
|
||||
case MQTTCLIENT_PERSISTENCE_DEFAULT :
|
||||
per = malloc(sizeof(MQTTClient_persistence));
|
||||
if ( per != NULL )
|
||||
{
|
||||
if ( pcontext == NULL )
|
||||
pcontext = "."; /* working directory */
|
||||
if ((per->context = malloc(strlen(pcontext) + 1)) == NULL)
|
||||
{
|
||||
free(per);
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
strcpy(per->context, pcontext);
|
||||
/* file system functions */
|
||||
per->popen = pstopen;
|
||||
per->pclose = pstclose;
|
||||
per->pput = pstput;
|
||||
per->pget = pstget;
|
||||
per->premove = pstremove;
|
||||
per->pkeys = pstkeys;
|
||||
per->pclear = pstclear;
|
||||
per->pcontainskey = pstcontainskey;
|
||||
}
|
||||
else
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
break;
|
||||
case MQTTCLIENT_PERSISTENCE_USER :
|
||||
per = (MQTTClient_persistence *)pcontext;
|
||||
if ( per == NULL || (per != NULL && (per->context == NULL || per->pclear == NULL ||
|
||||
per->pclose == NULL || per->pcontainskey == NULL || per->pget == NULL || per->pkeys == NULL ||
|
||||
per->popen == NULL || per->pput == NULL || per->premove == NULL)) )
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
break;
|
||||
default:
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
*persistence = per;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open persistent store and restore any persisted messages.
|
||||
* @param client the client as ::Clients.
|
||||
* @param serverURI the URI of the remote end.
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
int MQTTPersistence_initialize(Clients *c, const char *serverURI)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ( c->persistence != NULL )
|
||||
{
|
||||
rc = c->persistence->popen(&(c->phandle), c->clientID, serverURI, c->persistence->context);
|
||||
if ( rc == 0 )
|
||||
rc = MQTTPersistence_restorePackets(c);
|
||||
}
|
||||
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close persistent store.
|
||||
* @param client the client as ::Clients.
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
int MQTTPersistence_close(Clients *c)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if !defined(NO_PERSISTENCE)
|
||||
if (c->persistence != NULL)
|
||||
{
|
||||
rc = c->persistence->pclose(c->phandle);
|
||||
|
||||
if (c->persistence->popen == pstopen) {
|
||||
if (c->persistence->context)
|
||||
free(c->persistence->context);
|
||||
free(c->persistence);
|
||||
}
|
||||
|
||||
c->phandle = NULL;
|
||||
c->persistence = NULL;
|
||||
}
|
||||
#endif
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the persistent store.
|
||||
* @param client the client as ::Clients.
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
int MQTTPersistence_clear(Clients *c)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (c->persistence != NULL)
|
||||
rc = c->persistence->pclear(c->phandle);
|
||||
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restores the persisted records to the outbound and inbound message queues of the
|
||||
* client.
|
||||
* @param client the client as ::Clients.
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
int MQTTPersistence_restorePackets(Clients *c)
|
||||
{
|
||||
int rc = 0;
|
||||
char **msgkeys = NULL,
|
||||
*buffer = NULL;
|
||||
int nkeys, buflen;
|
||||
int i = 0;
|
||||
int msgs_sent = 0;
|
||||
int msgs_rcvd = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (c->persistence && (rc = c->persistence->pkeys(c->phandle, &msgkeys, &nkeys)) == 0)
|
||||
{
|
||||
while (rc == 0 && i < nkeys)
|
||||
{
|
||||
if (strncmp(msgkeys[i], PERSISTENCE_COMMAND_KEY, strlen(PERSISTENCE_COMMAND_KEY)) == 0 ||
|
||||
strncmp(msgkeys[i], PERSISTENCE_V5_COMMAND_KEY, strlen(PERSISTENCE_V5_COMMAND_KEY)) == 0)
|
||||
{
|
||||
;
|
||||
}
|
||||
else if (strncmp(msgkeys[i], PERSISTENCE_QUEUE_KEY, strlen(PERSISTENCE_QUEUE_KEY)) == 0 ||
|
||||
strncmp(msgkeys[i], PERSISTENCE_V5_QUEUE_KEY, strlen(PERSISTENCE_V5_QUEUE_KEY)) == 0)
|
||||
{
|
||||
;
|
||||
}
|
||||
else if ((rc = c->persistence->pget(c->phandle, msgkeys[i], &buffer, &buflen)) == 0 &&
|
||||
(c->afterRead == NULL || (rc = c->afterRead(c->afterRead_context, &buffer, &buflen)) == 0))
|
||||
{
|
||||
int data_MQTTVersion = MQTTVERSION_3_1_1;
|
||||
char* cur_key = msgkeys[i];
|
||||
MQTTPacket* pack = NULL;
|
||||
|
||||
if (strncmp(cur_key, PERSISTENCE_V5_PUBLISH_RECEIVED,
|
||||
strlen(PERSISTENCE_V5_PUBLISH_RECEIVED)) == 0)
|
||||
{
|
||||
data_MQTTVersion = MQTTVERSION_5;
|
||||
cur_key = PERSISTENCE_PUBLISH_RECEIVED;
|
||||
}
|
||||
else if (strncmp(cur_key, PERSISTENCE_V5_PUBLISH_SENT,
|
||||
strlen(PERSISTENCE_V5_PUBLISH_SENT)) == 0)
|
||||
{
|
||||
data_MQTTVersion = MQTTVERSION_5;
|
||||
cur_key = PERSISTENCE_PUBLISH_SENT;
|
||||
}
|
||||
else if (strncmp(cur_key, PERSISTENCE_V5_PUBREL,
|
||||
strlen(PERSISTENCE_V5_PUBREL)) == 0)
|
||||
{
|
||||
data_MQTTVersion = MQTTVERSION_5;
|
||||
cur_key = PERSISTENCE_PUBREL;
|
||||
}
|
||||
|
||||
if (data_MQTTVersion == MQTTVERSION_5 && c->MQTTVersion < MQTTVERSION_5)
|
||||
{
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR; /* can't restore version 5 data with a version 3 client */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pack = MQTTPersistence_restorePacket(data_MQTTVersion, buffer, buflen);
|
||||
if ( pack != NULL )
|
||||
{
|
||||
if (strncmp(cur_key, PERSISTENCE_PUBLISH_RECEIVED,
|
||||
strlen(PERSISTENCE_PUBLISH_RECEIVED)) == 0)
|
||||
{
|
||||
Publish* publish = (Publish*)pack;
|
||||
Messages* msg = NULL;
|
||||
publish->MQTTVersion = c->MQTTVersion;
|
||||
msg = MQTTProtocol_createMessage(publish, &msg, publish->header.bits.qos, publish->header.bits.retain, 1);
|
||||
msg->nextMessageType = PUBREL;
|
||||
/* order does not matter for persisted received messages */
|
||||
ListAppend(c->inboundMsgs, msg, msg->len);
|
||||
if (c->MQTTVersion >= MQTTVERSION_5)
|
||||
{
|
||||
free(msg->publish->payload);
|
||||
free(msg->publish->topic);
|
||||
msg->publish->payload = msg->publish->topic = NULL;
|
||||
}
|
||||
publish->topic = NULL;
|
||||
MQTTPacket_freePublish(publish);
|
||||
msgs_rcvd++;
|
||||
}
|
||||
else if (strncmp(cur_key, PERSISTENCE_PUBLISH_SENT,
|
||||
strlen(PERSISTENCE_PUBLISH_SENT)) == 0)
|
||||
{
|
||||
Publish* publish = (Publish*)pack;
|
||||
Messages* msg = NULL;
|
||||
const size_t keysize = PERSISTENCE_MAX_KEY_LENGTH + 1;
|
||||
char *key = malloc(keysize);
|
||||
int chars = 0;
|
||||
|
||||
if (!key)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
publish->MQTTVersion = c->MQTTVersion;
|
||||
if (publish->MQTTVersion >= MQTTVERSION_5)
|
||||
chars = snprintf(key, keysize, "%s%d", PERSISTENCE_V5_PUBREL, publish->msgId);
|
||||
else
|
||||
chars = snprintf(key, keysize, "%s%d", PERSISTENCE_PUBREL, publish->msgId);
|
||||
if (chars >= keysize)
|
||||
{
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
Log(LOG_ERROR, 0, "Error writing %d chars with snprintf", chars);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = MQTTProtocol_createMessage(publish, &msg, publish->header.bits.qos, publish->header.bits.retain, 1);
|
||||
if (c->persistence->pcontainskey(c->phandle, key) == 0)
|
||||
/* PUBLISH Qo2 and PUBREL sent */
|
||||
msg->nextMessageType = PUBCOMP;
|
||||
/* else: PUBLISH QoS1, or PUBLISH QoS2 and PUBREL not sent */
|
||||
/* retry at the first opportunity */
|
||||
memset(&msg->lastTouch, '\0', sizeof(msg->lastTouch));
|
||||
MQTTPersistence_insertInOrder(c->outboundMsgs, msg, msg->len);
|
||||
publish->topic = NULL;
|
||||
MQTTPacket_freePublish(publish);
|
||||
msgs_sent++;
|
||||
}
|
||||
free(key);
|
||||
}
|
||||
else if (strncmp(cur_key, PERSISTENCE_PUBREL, strlen(PERSISTENCE_PUBREL)) == 0)
|
||||
{
|
||||
/* orphaned PUBRELs ? */
|
||||
Pubrel* pubrel = (Pubrel*)pack;
|
||||
const size_t keysize = PERSISTENCE_MAX_KEY_LENGTH + 1;
|
||||
char *key = malloc(keysize);
|
||||
int chars = 0;
|
||||
|
||||
if (!key)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
pubrel->MQTTVersion = c->MQTTVersion;
|
||||
if (pubrel->MQTTVersion >= MQTTVERSION_5)
|
||||
chars = snprintf(key, keysize, "%s%d", PERSISTENCE_V5_PUBLISH_SENT, pubrel->msgId);
|
||||
else
|
||||
chars = snprintf(key, keysize, "%s%d", PERSISTENCE_PUBLISH_SENT, pubrel->msgId);
|
||||
if (chars >= keysize)
|
||||
{
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
Log(LOG_ERROR, 0, "Error writing %d chars with snprintf", chars);
|
||||
}
|
||||
else if (c->persistence->pcontainskey(c->phandle, key) != 0)
|
||||
rc = c->persistence->premove(c->phandle, msgkeys[i]);
|
||||
free(pubrel);
|
||||
free(key);
|
||||
}
|
||||
}
|
||||
else /* pack == NULL -> bad persisted record */
|
||||
rc = c->persistence->premove(c->phandle, msgkeys[i]);
|
||||
}
|
||||
if (buffer)
|
||||
{
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
if (msgkeys[i])
|
||||
{
|
||||
free(msgkeys[i]);
|
||||
msgkeys[i] = NULL;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Log(TRACE_MINIMUM, -1, "%d sent messages and %d received messages restored for client %s\n",
|
||||
msgs_sent, msgs_rcvd, c->clientID);
|
||||
MQTTPersistence_wrapMsgID(c);
|
||||
exit:
|
||||
if (msgkeys)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < nkeys; ++i)
|
||||
{
|
||||
if (msgkeys[i])
|
||||
free(msgkeys[i]);
|
||||
}
|
||||
free(msgkeys);
|
||||
}
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a MQTT packet restored from persisted data.
|
||||
* @param buffer the persisted data.
|
||||
* @param buflen the number of bytes of the data buffer.
|
||||
*/
|
||||
void* MQTTPersistence_restorePacket(int MQTTVersion, char* buffer, size_t buflen)
|
||||
{
|
||||
void* pack = NULL;
|
||||
Header header;
|
||||
int fixed_header_length = 1, ptype, remaining_length = 0;
|
||||
char c;
|
||||
int multiplier = 1;
|
||||
extern pf new_packets[];
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = buffer[0];
|
||||
/* decode the message length according to the MQTT algorithm */
|
||||
do
|
||||
{
|
||||
c = *(++buffer);
|
||||
remaining_length += (c & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
fixed_header_length++;
|
||||
} while ((c & 128) != 0);
|
||||
|
||||
if ( (fixed_header_length + remaining_length) == buflen )
|
||||
{
|
||||
ptype = header.bits.type;
|
||||
if (ptype >= CONNECT && ptype <= DISCONNECT && new_packets[ptype] != NULL)
|
||||
pack = (*new_packets[ptype])(MQTTVersion, header.byte, ++buffer, remaining_length);
|
||||
}
|
||||
|
||||
FUNC_EXIT;
|
||||
return pack;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts the specified message into the list, maintaining message ID order.
|
||||
* @param list the list to insert the message into.
|
||||
* @param content the message to add.
|
||||
* @param size size of the message.
|
||||
*/
|
||||
void MQTTPersistence_insertInOrder(List* list, void* content, size_t size)
|
||||
{
|
||||
ListElement* index = NULL;
|
||||
ListElement* current = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
while(ListNextElement(list, ¤t) != NULL && index == NULL)
|
||||
{
|
||||
if ( ((Messages*)content)->msgid < ((Messages*)current->content)->msgid )
|
||||
index = current;
|
||||
}
|
||||
|
||||
ListInsert(list, content, size, index);
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a record to the persistent store. This function must not be called for QoS0
|
||||
* messages.
|
||||
* @param socket the socket of the client.
|
||||
* @param buf0 fixed header.
|
||||
* @param buf0len length of the fixed header.
|
||||
* @param count number of buffers representing the variable header and/or the payload.
|
||||
* @param buffers the buffers representing the variable header and/or the payload.
|
||||
* @param buflens length of the buffers representing the variable header and/or the payload.
|
||||
* @param htype MQTT packet type - PUBLISH or PUBREL
|
||||
* @param msgId the message ID.
|
||||
* @param scr 0 indicates message in the sending direction; 1 indicates message in the
|
||||
* receiving direction.
|
||||
* @param the MQTT version being used (>= MQTTVERSION_5 means properties included)
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
int MQTTPersistence_putPacket(SOCKET socket, char* buf0, size_t buf0len, int count,
|
||||
char** buffers, size_t* buflens, int htype, int msgId, int scr, int MQTTVersion)
|
||||
{
|
||||
int rc = 0;
|
||||
extern ClientStates* bstate;
|
||||
int nbufs, i;
|
||||
int* lens = NULL;
|
||||
char** bufs = NULL;
|
||||
char *key;
|
||||
Clients* client = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
client = (Clients*)(ListFindItem(bstate->clients, &socket, clientSocketCompare)->content);
|
||||
if (client->persistence != NULL)
|
||||
{
|
||||
const size_t keysize = PERSISTENCE_MAX_KEY_LENGTH + 1;
|
||||
if ((key = malloc(keysize)) == NULL)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
nbufs = 1 + count;
|
||||
if ((lens = (int *)malloc(nbufs * sizeof(int))) == NULL)
|
||||
{
|
||||
free(key);
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
if ((bufs = (char **)malloc(nbufs * sizeof(char *))) == NULL)
|
||||
{
|
||||
free(key);
|
||||
free(lens);
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
lens[0] = (int)buf0len;
|
||||
bufs[0] = buf0;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
lens[i+1] = (int)buflens[i];
|
||||
bufs[i+1] = buffers[i];
|
||||
}
|
||||
|
||||
/* key */
|
||||
if (scr == 0)
|
||||
{ /* sending */
|
||||
char* key_id = PERSISTENCE_PUBLISH_SENT;
|
||||
|
||||
if (htype == PUBLISH) /* PUBLISH QoS1 and QoS2*/
|
||||
{
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
key_id = PERSISTENCE_V5_PUBLISH_SENT;
|
||||
}
|
||||
else if (htype == PUBREL) /* PUBREL */
|
||||
{
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
key_id = PERSISTENCE_V5_PUBREL;
|
||||
else
|
||||
key_id = PERSISTENCE_PUBREL;
|
||||
}
|
||||
if (snprintf(key, keysize, "%s%d", key_id, msgId) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
}
|
||||
else if (scr == 1) /* receiving PUBLISH QoS2 */
|
||||
{
|
||||
char* key_id = PERSISTENCE_PUBLISH_RECEIVED;
|
||||
|
||||
if (MQTTVersion >= MQTTVERSION_5)
|
||||
key_id = PERSISTENCE_V5_PUBLISH_RECEIVED;
|
||||
if (snprintf(key, keysize, "%s%d", key_id, msgId) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
}
|
||||
|
||||
if (rc == 0 && client->beforeWrite)
|
||||
rc = client->beforeWrite(client->beforeWrite_context, nbufs, bufs, lens);
|
||||
|
||||
if (rc == 0)
|
||||
rc = client->persistence->pput(client->phandle, key, nbufs, bufs, lens);
|
||||
|
||||
free(key);
|
||||
free(lens);
|
||||
free(bufs);
|
||||
}
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a record from the persistent store.
|
||||
* @param client the client as ::Clients.
|
||||
* @param type the type of the persisted record: #PERSISTENCE_PUBLISH_SENT, #PERSISTENCE_PUBREL
|
||||
* or #PERSISTENCE_PUBLISH_RECEIVED.
|
||||
* @param qos the qos field of the message.
|
||||
* @param msgId the message ID.
|
||||
* @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise.
|
||||
*/
|
||||
int MQTTPersistence_remove(Clients* c, char *type, int qos, int msgId)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (c->persistence != NULL)
|
||||
{
|
||||
const size_t keysize = PERSISTENCE_MAX_KEY_LENGTH + 1;
|
||||
char *key = malloc(keysize);
|
||||
int chars = 0;
|
||||
|
||||
if (!key)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
if (strcmp(type, PERSISTENCE_PUBLISH_SENT) == 0 ||
|
||||
strcmp(type, PERSISTENCE_V5_PUBLISH_SENT) == 0)
|
||||
{
|
||||
if ((chars = snprintf(key, keysize, "%s%d", PERSISTENCE_V5_PUBLISH_SENT, msgId)) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
{
|
||||
rc = c->persistence->premove(c->phandle, key);
|
||||
if ((chars = snprintf(key, keysize, "%s%d", PERSISTENCE_V5_PUBREL, msgId)) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
{
|
||||
rc += c->persistence->premove(c->phandle, key);
|
||||
if ((chars = snprintf(key, keysize, "%s%d", PERSISTENCE_PUBLISH_SENT, msgId)) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
{
|
||||
rc += c->persistence->premove(c->phandle, key);
|
||||
if ((chars = snprintf(key, keysize, "%s%d", PERSISTENCE_PUBREL, msgId)) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
rc += c->persistence->premove(c->phandle, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* PERSISTENCE_PUBLISH_SENT && qos == 1 */
|
||||
{ /* or PERSISTENCE_PUBLISH_RECEIVED */
|
||||
|
||||
if ((chars = snprintf(key, keysize, "%s%d", PERSISTENCE_V5_PUBLISH_RECEIVED, msgId)) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
{
|
||||
rc = c->persistence->premove(c->phandle, key);
|
||||
if ((chars = snprintf(key, keysize, "%s%d", PERSISTENCE_PUBLISH_RECEIVED, msgId)) >= keysize)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
rc += c->persistence->premove(c->phandle, key);
|
||||
}
|
||||
}
|
||||
if (rc == MQTTCLIENT_PERSISTENCE_ERROR)
|
||||
Log(LOG_ERROR, 0, "Error writing %d chars with snprintf", chars);
|
||||
free(key);
|
||||
}
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the message IDs wrapped by looking for the largest gap between two consecutive
|
||||
* message IDs in the outboundMsgs queue.
|
||||
* @param client the client as ::Clients.
|
||||
*/
|
||||
void MQTTPersistence_wrapMsgID(Clients *client)
|
||||
{
|
||||
ListElement* wrapel = NULL;
|
||||
ListElement* current = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ( client->outboundMsgs->count > 0 )
|
||||
{
|
||||
int firstMsgID = ((Messages*)client->outboundMsgs->first->content)->msgid;
|
||||
int lastMsgID = ((Messages*)client->outboundMsgs->last->content)->msgid;
|
||||
int gap = MAX_MSG_ID - lastMsgID + firstMsgID;
|
||||
current = ListNextElement(client->outboundMsgs, ¤t);
|
||||
|
||||
while(ListNextElement(client->outboundMsgs, ¤t) != NULL)
|
||||
{
|
||||
int curMsgID = ((Messages*)current->content)->msgid;
|
||||
int curPrevMsgID = ((Messages*)current->prev->content)->msgid;
|
||||
int curgap = curMsgID - curPrevMsgID;
|
||||
if ( curgap > gap )
|
||||
{
|
||||
gap = curgap;
|
||||
wrapel = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( wrapel != NULL )
|
||||
{
|
||||
/* put wrapel at the beginning of the queue */
|
||||
client->outboundMsgs->first->prev = client->outboundMsgs->last;
|
||||
client->outboundMsgs->last->next = client->outboundMsgs->first;
|
||||
client->outboundMsgs->first = wrapel;
|
||||
client->outboundMsgs->last = wrapel->prev;
|
||||
client->outboundMsgs->first->prev = NULL;
|
||||
client->outboundMsgs->last->next = NULL;
|
||||
}
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(NO_PERSISTENCE)
|
||||
int MQTTPersistence_unpersistQueueEntry(Clients* client, MQTTPersistence_qEntry* qe)
|
||||
{
|
||||
int rc = 0;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define KEYSIZE PERSISTENCE_MAX_KEY_LENGTH + 1
|
||||
#else
|
||||
const size_t KEYSIZE = PERSISTENCE_MAX_KEY_LENGTH + 1;
|
||||
#endif
|
||||
char key[KEYSIZE];
|
||||
int chars = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (client->MQTTVersion >= MQTTVERSION_5)
|
||||
chars = snprintf(key, KEYSIZE, "%s%u", PERSISTENCE_V5_QUEUE_KEY, qe->seqno);
|
||||
else
|
||||
chars = snprintf(key, KEYSIZE, "%s%u", PERSISTENCE_QUEUE_KEY, qe->seqno);
|
||||
if (chars >= KEYSIZE)
|
||||
{
|
||||
Log(LOG_ERROR, 0, "Error writing %d chars with snprintf", chars);
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
}
|
||||
else if ((rc = client->persistence->premove(client->phandle, key)) != 0)
|
||||
Log(LOG_ERROR, 0, "Error %d removing qEntry from persistence", rc);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_NO_OF_BUFFERS 9
|
||||
int MQTTPersistence_persistQueueEntry(Clients* aclient, MQTTPersistence_qEntry* qe)
|
||||
{
|
||||
int rc = 0;
|
||||
int bufindex = 0;
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
const size_t KEYSIZE = PERSISTENCE_MAX_KEY_LENGTH + 1;
|
||||
#endif
|
||||
char key[KEYSIZE];
|
||||
int chars = 0;
|
||||
int lens[MAX_NO_OF_BUFFERS];
|
||||
void* bufs[MAX_NO_OF_BUFFERS];
|
||||
int props_allocated = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
bufs[bufindex] = &qe->msg->payloadlen;
|
||||
lens[bufindex++] = sizeof(qe->msg->payloadlen);
|
||||
|
||||
bufs[bufindex] = qe->msg->payload;
|
||||
lens[bufindex++] = qe->msg->payloadlen;
|
||||
|
||||
bufs[bufindex] = &qe->msg->qos;
|
||||
lens[bufindex++] = sizeof(qe->msg->qos);
|
||||
|
||||
bufs[bufindex] = &qe->msg->retained;
|
||||
lens[bufindex++] = sizeof(qe->msg->retained);
|
||||
|
||||
bufs[bufindex] = &qe->msg->dup;
|
||||
lens[bufindex++] = sizeof(qe->msg->dup);
|
||||
|
||||
bufs[bufindex] = &qe->msg->msgid;
|
||||
lens[bufindex++] = sizeof(qe->msg->msgid);
|
||||
|
||||
bufs[bufindex] = qe->topicName;
|
||||
lens[bufindex++] = (int)strlen(qe->topicName) + 1;
|
||||
|
||||
bufs[bufindex] = &qe->topicLen;
|
||||
lens[bufindex++] = sizeof(qe->topicLen);
|
||||
|
||||
if (++aclient->qentry_seqno == PERSISTENCE_SEQNO_LIMIT)
|
||||
aclient->qentry_seqno = 0;
|
||||
|
||||
if (aclient->MQTTVersion >= MQTTVERSION_5) /* persist properties */
|
||||
{
|
||||
MQTTProperties no_props = MQTTProperties_initializer;
|
||||
MQTTProperties* props = &no_props;
|
||||
int temp_len = 0;
|
||||
char* ptr = NULL;
|
||||
|
||||
if (qe->msg->struct_version >= 1)
|
||||
props = &qe->msg->properties;
|
||||
|
||||
temp_len = MQTTProperties_len(props);
|
||||
ptr = bufs[bufindex] = malloc(temp_len);
|
||||
if (!ptr)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
props_allocated = bufindex;
|
||||
rc = MQTTProperties_write(&ptr, props);
|
||||
lens[bufindex++] = temp_len;
|
||||
|
||||
chars = snprintf(key, KEYSIZE, "%s%u", PERSISTENCE_V5_QUEUE_KEY, aclient->qentry_seqno);
|
||||
}
|
||||
else
|
||||
chars = snprintf(key, KEYSIZE, "%s%u", PERSISTENCE_QUEUE_KEY, aclient->qentry_seqno);
|
||||
|
||||
if (chars >= KEYSIZE)
|
||||
rc = MQTTCLIENT_PERSISTENCE_ERROR;
|
||||
else
|
||||
{
|
||||
qe->seqno = aclient->qentry_seqno;
|
||||
|
||||
if (aclient->beforeWrite)
|
||||
rc = aclient->beforeWrite(aclient->beforeWrite_context, bufindex, (char**)bufs, lens);
|
||||
|
||||
if (rc == 0 && (rc = aclient->persistence->pput(aclient->phandle, key, bufindex, (char**)bufs, lens)) != 0)
|
||||
Log(LOG_ERROR, 0, "Error persisting queue entry, rc %d", rc);
|
||||
}
|
||||
if (props_allocated != 0)
|
||||
free(bufs[props_allocated]);
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static MQTTPersistence_qEntry* MQTTPersistence_restoreQueueEntry(char* buffer, size_t buflen, int MQTTVersion)
|
||||
{
|
||||
MQTTPersistence_qEntry* qe = NULL;
|
||||
char* ptr = buffer;
|
||||
int data_size;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((qe = malloc(sizeof(MQTTPersistence_qEntry))) == NULL)
|
||||
goto exit;
|
||||
memset(qe, '\0', sizeof(MQTTPersistence_qEntry));
|
||||
|
||||
if ((qe->msg = malloc(sizeof(MQTTPersistence_message))) == NULL)
|
||||
{
|
||||
free(qe);
|
||||
qe = NULL;
|
||||
goto exit;
|
||||
}
|
||||
memset(qe->msg, '\0', sizeof(MQTTPersistence_message));
|
||||
|
||||
qe->msg->struct_version = 1;
|
||||
|
||||
qe->msg->payloadlen = *(int*)ptr;
|
||||
ptr += sizeof(int);
|
||||
|
||||
data_size = qe->msg->payloadlen;
|
||||
if ((qe->msg->payload = malloc(data_size)) == NULL)
|
||||
{
|
||||
free(qe->msg);
|
||||
free(qe);
|
||||
qe = NULL;
|
||||
goto exit;
|
||||
}
|
||||
memcpy(qe->msg->payload, ptr, data_size);
|
||||
ptr += data_size;
|
||||
|
||||
qe->msg->qos = *(int*)ptr;
|
||||
ptr += sizeof(int);
|
||||
|
||||
qe->msg->retained = *(int*)ptr;
|
||||
ptr += sizeof(int);
|
||||
|
||||
qe->msg->dup = *(int*)ptr;
|
||||
ptr += sizeof(int);
|
||||
|
||||
qe->msg->msgid = *(int*)ptr;
|
||||
ptr += sizeof(int);
|
||||
|
||||
data_size = (int)strlen(ptr) + 1;
|
||||
if ((qe->topicName = malloc(data_size)) == NULL)
|
||||
{
|
||||
free(qe->msg->payload);
|
||||
free(qe->msg);
|
||||
free(qe);
|
||||
qe = NULL;
|
||||
goto exit;
|
||||
}
|
||||
strcpy(qe->topicName, ptr);
|
||||
ptr += data_size;
|
||||
|
||||
qe->topicLen = *(int*)ptr;
|
||||
ptr += sizeof(int);
|
||||
|
||||
if (MQTTVersion >= MQTTVERSION_5 &&
|
||||
MQTTProperties_read(&qe->msg->properties, &ptr, buffer + buflen) != 1)
|
||||
Log(LOG_ERROR, -1, "Error restoring properties from persistence");
|
||||
|
||||
exit:
|
||||
FUNC_EXIT;
|
||||
return qe;
|
||||
}
|
||||
|
||||
|
||||
static void MQTTPersistence_insertInSeqOrder(List* list, MQTTPersistence_qEntry* qEntry, size_t size)
|
||||
{
|
||||
ListElement* index = NULL;
|
||||
ListElement* current = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
while (ListNextElement(list, ¤t) != NULL && index == NULL)
|
||||
{
|
||||
if (qEntry->seqno < ((MQTTPersistence_qEntry*)current->content)->seqno)
|
||||
index = current;
|
||||
}
|
||||
ListInsert(list, qEntry, size, index);
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restores a queue of messages from persistence to memory
|
||||
* @param c the client as ::Clients - the client object to restore the messages to
|
||||
* @return return code, 0 if successful
|
||||
*/
|
||||
int MQTTPersistence_restoreMessageQueue(Clients* c)
|
||||
{
|
||||
int rc = 0;
|
||||
char **msgkeys;
|
||||
int nkeys;
|
||||
int i = 0;
|
||||
int entries_restored = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (c->persistence && (rc = c->persistence->pkeys(c->phandle, &msgkeys, &nkeys)) == 0)
|
||||
{
|
||||
while (rc == 0 && i < nkeys)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
int buflen;
|
||||
|
||||
if (strncmp(msgkeys[i], PERSISTENCE_QUEUE_KEY, strlen(PERSISTENCE_QUEUE_KEY)) != 0 &&
|
||||
strncmp(msgkeys[i], PERSISTENCE_V5_QUEUE_KEY, strlen(PERSISTENCE_V5_QUEUE_KEY)) != 0)
|
||||
{
|
||||
; /* ignore if not a queue entry key */
|
||||
}
|
||||
else if ((rc = c->persistence->pget(c->phandle, msgkeys[i], &buffer, &buflen)) == 0 &&
|
||||
(c->afterRead == NULL || (rc = c->afterRead(c->afterRead_context, &buffer, &buflen)) == 0))
|
||||
{
|
||||
int MQTTVersion =
|
||||
(strncmp(msgkeys[i], PERSISTENCE_V5_QUEUE_KEY, strlen(PERSISTENCE_V5_QUEUE_KEY)) == 0)
|
||||
? MQTTVERSION_5 : MQTTVERSION_3_1_1;
|
||||
MQTTPersistence_qEntry* qe = MQTTPersistence_restoreQueueEntry(buffer, buflen, MQTTVersion);
|
||||
|
||||
if (qe)
|
||||
{
|
||||
qe->seqno = atoi(strchr(msgkeys[i], '-')+1); /* key format is tag'-'seqno */
|
||||
MQTTPersistence_insertInSeqOrder(c->messageQueue, qe, sizeof(MQTTPersistence_qEntry));
|
||||
c->qentry_seqno = max(c->qentry_seqno, qe->seqno);
|
||||
entries_restored++;
|
||||
}
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
}
|
||||
if (msgkeys[i])
|
||||
{
|
||||
free(msgkeys[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (msgkeys != NULL)
|
||||
free(msgkeys);
|
||||
}
|
||||
Log(TRACE_MINIMUM, -1, "%d queued messages restored for client %s", entries_restored, c->clientID);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
99
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistence.h
vendored
Normal file
99
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistence.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - async client updates
|
||||
* Ian Craggs - fix for bug 432903 - queue persistence
|
||||
* Ian Craggs - MQTT V5 updates
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPERSISTENCE_H)
|
||||
#define MQTTPERSISTENCE_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "Clients.h"
|
||||
#include "MQTTProperties.h"
|
||||
|
||||
/** Stem of the key for a sent PUBLISH QoS1 or QoS2 */
|
||||
#define PERSISTENCE_PUBLISH_SENT "s-"
|
||||
/** Stem of the key for a sent PUBREL */
|
||||
#define PERSISTENCE_PUBREL "sc-"
|
||||
/** Stem of the key for a received PUBLISH QoS2 */
|
||||
#define PERSISTENCE_PUBLISH_RECEIVED "r-"
|
||||
|
||||
/** Stem of the key for a sent MQTT V5 PUBLISH QoS1 or QoS2 */
|
||||
#define PERSISTENCE_V5_PUBLISH_SENT "s5-"
|
||||
/** Stem of the key for a sent MQTT V5 PUBREL */
|
||||
#define PERSISTENCE_V5_PUBREL "sc5-"
|
||||
/** Stem of the key for a received MQTT V5 PUBLISH QoS2 */
|
||||
#define PERSISTENCE_V5_PUBLISH_RECEIVED "r5-"
|
||||
|
||||
/** Stem of the key for an async client command */
|
||||
#define PERSISTENCE_COMMAND_KEY "c-"
|
||||
/** Stem of the key for an MQTT V5 async client command */
|
||||
#define PERSISTENCE_V5_COMMAND_KEY "c5-"
|
||||
/** Stem of the key for an client incoming message queue */
|
||||
#define PERSISTENCE_QUEUE_KEY "q-"
|
||||
/** Stem of the key for an MQTT V5 incoming message queue */
|
||||
#define PERSISTENCE_V5_QUEUE_KEY "q5-"
|
||||
/** Maximum length of a stem for a persistence key */
|
||||
#define PERSISTENCE_MAX_STEM_LENGTH 4
|
||||
/** Maximum allowed length of a persistence key */
|
||||
#define PERSISTENCE_MAX_KEY_LENGTH 10
|
||||
/** Maximum size of an integer sequence number appended to a persistence key */
|
||||
#define PERSISTENCE_SEQNO_LIMIT 1000000 /*10^(PERSISTENCE_MAX_KEY_LENGTH - PERSISTENCE_MAX_STEM_LENGTH)*/
|
||||
|
||||
int MQTTPersistence_create(MQTTClient_persistence** per, int type, void* pcontext);
|
||||
int MQTTPersistence_initialize(Clients* c, const char* serverURI);
|
||||
int MQTTPersistence_close(Clients* c);
|
||||
int MQTTPersistence_clear(Clients* c);
|
||||
int MQTTPersistence_restorePackets(Clients* c);
|
||||
void* MQTTPersistence_restorePacket(int MQTTVersion, char* buffer, size_t buflen);
|
||||
void MQTTPersistence_insertInOrder(List* list, void* content, size_t size);
|
||||
int MQTTPersistence_putPacket(SOCKET socket, char* buf0, size_t buf0len, int count,
|
||||
char** buffers, size_t* buflens, int htype, int msgId, int scr, int MQTTVersion);
|
||||
int MQTTPersistence_remove(Clients* c, char* type, int qos, int msgId);
|
||||
void MQTTPersistence_wrapMsgID(Clients *c);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char struct_id[4];
|
||||
int struct_version;
|
||||
int payloadlen;
|
||||
void* payload;
|
||||
int qos;
|
||||
int retained;
|
||||
int dup;
|
||||
int msgid;
|
||||
MQTTProperties properties;
|
||||
} MQTTPersistence_message;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MQTTPersistence_message* msg;
|
||||
char* topicName;
|
||||
int topicLen;
|
||||
unsigned int seqno; /* only used on restore */
|
||||
} MQTTPersistence_qEntry;
|
||||
|
||||
int MQTTPersistence_unpersistQueueEntry(Clients* client, MQTTPersistence_qEntry* qe);
|
||||
int MQTTPersistence_persistQueueEntry(Clients* aclient, MQTTPersistence_qEntry* qe);
|
||||
int MQTTPersistence_restoreMessageQueue(Clients* c);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1022
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistenceDefault.c
vendored
Normal file
1022
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistenceDefault.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistenceDefault.h
vendored
Normal file
36
src/mqtt/externals/paho-mqtt-c/src/MQTTPersistenceDefault.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2018 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPERSISTENCEDEFAULT_H)
|
||||
#define MQTTPERSISTENCEDEFAULT_H
|
||||
|
||||
/** Extension of the filename */
|
||||
#define MESSAGE_FILENAME_EXTENSION ".msg"
|
||||
|
||||
/* prototypes of the functions for the default file system persistence */
|
||||
int pstopen(void** handle, const char* clientID, const char* serverURI, void* context);
|
||||
int pstclose(void* handle);
|
||||
int pstput(void* handle, char* key, int bufcount, char* buffers[], int buflens[]);
|
||||
int pstget(void* handle, char* key, char** buffer, int* buflen);
|
||||
int pstremove(void* handle, char* key);
|
||||
int pstkeys(void* handle, char*** keys, int* nkeys);
|
||||
int pstclear(void* handle);
|
||||
int pstcontainskey(void* handle, char* key);
|
||||
|
||||
int pstmkdir(char *pPathname);
|
||||
|
||||
#endif
|
||||
|
||||
552
src/mqtt/externals/paho-mqtt-c/src/MQTTProperties.c
vendored
Normal file
552
src/mqtt/externals/paho-mqtt-c/src/MQTTProperties.c
vendored
Normal file
@@ -0,0 +1,552 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 IBM Corp. and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTProperties.h"
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "MQTTProtocolClient.h"
|
||||
#include "Heap.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
static struct nameToType
|
||||
{
|
||||
enum MQTTPropertyCodes name;
|
||||
enum MQTTPropertyTypes type;
|
||||
} namesToTypes[] =
|
||||
{
|
||||
{MQTTPROPERTY_CODE_PAYLOAD_FORMAT_INDICATOR, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_MESSAGE_EXPIRY_INTERVAL, MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_CONTENT_TYPE, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_RESPONSE_TOPIC, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_CORRELATION_DATA, MQTTPROPERTY_TYPE_BINARY_DATA},
|
||||
{MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIER, MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_SESSION_EXPIRY_INTERVAL, MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_ASSIGNED_CLIENT_IDENTIFER, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_SERVER_KEEP_ALIVE, MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_AUTHENTICATION_METHOD, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_AUTHENTICATION_DATA, MQTTPROPERTY_TYPE_BINARY_DATA},
|
||||
{MQTTPROPERTY_CODE_REQUEST_PROBLEM_INFORMATION, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_WILL_DELAY_INTERVAL, MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_REQUEST_RESPONSE_INFORMATION, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_RESPONSE_INFORMATION, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_SERVER_REFERENCE, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_REASON_STRING, MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING},
|
||||
{MQTTPROPERTY_CODE_RECEIVE_MAXIMUM, MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_TOPIC_ALIAS_MAXIMUM, MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_TOPIC_ALIAS, MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_MAXIMUM_QOS, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_RETAIN_AVAILABLE, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_USER_PROPERTY, MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR},
|
||||
{MQTTPROPERTY_CODE_MAXIMUM_PACKET_SIZE, MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER},
|
||||
{MQTTPROPERTY_CODE_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIERS_AVAILABLE, MQTTPROPERTY_TYPE_BYTE},
|
||||
{MQTTPROPERTY_CODE_SHARED_SUBSCRIPTION_AVAILABLE, MQTTPROPERTY_TYPE_BYTE}
|
||||
};
|
||||
|
||||
|
||||
static char* datadup(const MQTTLenString* str)
|
||||
{
|
||||
char* temp = malloc(str->len);
|
||||
if (temp)
|
||||
memcpy(temp, str->data, str->len);
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperty_getType(enum MQTTPropertyCodes value)
|
||||
{
|
||||
int i, rc = -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(namesToTypes); ++i)
|
||||
{
|
||||
if (namesToTypes[i].name == value)
|
||||
{
|
||||
rc = namesToTypes[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_len(MQTTProperties* props)
|
||||
{
|
||||
/* properties length is an mbi */
|
||||
return (props == NULL) ? 1 : props->length + MQTTPacket_VBIlen(props->length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new property to a property list
|
||||
* @param props the property list
|
||||
* @param prop the new property
|
||||
* @return code 0 is success
|
||||
*/
|
||||
int MQTTProperties_add(MQTTProperties* props, const MQTTProperty* prop)
|
||||
{
|
||||
int rc = 0, type;
|
||||
|
||||
if ((type = MQTTProperty_getType(prop->identifier)) < 0)
|
||||
{
|
||||
/*StackTrace_printStack(stdout);*/
|
||||
rc = MQTT_INVALID_PROPERTY_ID;
|
||||
goto exit;
|
||||
}
|
||||
else if (props->array == NULL)
|
||||
{
|
||||
props->max_count = 10;
|
||||
props->array = malloc(sizeof(MQTTProperty) * props->max_count);
|
||||
}
|
||||
else if (props->count == props->max_count)
|
||||
{
|
||||
props->max_count += 10;
|
||||
props->array = realloc(props->array, sizeof(MQTTProperty) * props->max_count);
|
||||
}
|
||||
|
||||
if (props->array)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
props->array[props->count++] = *prop;
|
||||
/* calculate length */
|
||||
switch (type)
|
||||
{
|
||||
case MQTTPROPERTY_TYPE_BYTE:
|
||||
len = 1;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER:
|
||||
len = 2;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER:
|
||||
len = 4;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER:
|
||||
len = MQTTPacket_VBIlen(prop->value.integer4);
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_BINARY_DATA:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR:
|
||||
len = 2 + prop->value.data.len;
|
||||
props->array[props->count-1].value.data.data = datadup(&prop->value.data);
|
||||
if (type == MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR)
|
||||
{
|
||||
len += 2 + prop->value.value.len;
|
||||
props->array[props->count-1].value.value.data = datadup(&prop->value.value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
props->length += len + 1; /* add identifier byte */
|
||||
}
|
||||
else
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperty_write(char** pptr, MQTTProperty* prop)
|
||||
{
|
||||
int rc = -1,
|
||||
type = -1;
|
||||
|
||||
type = MQTTProperty_getType(prop->identifier);
|
||||
if (type >= MQTTPROPERTY_TYPE_BYTE && type <= MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR)
|
||||
{
|
||||
writeChar(pptr, prop->identifier);
|
||||
switch (type)
|
||||
{
|
||||
case MQTTPROPERTY_TYPE_BYTE:
|
||||
writeChar(pptr, prop->value.byte);
|
||||
rc = 1;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER:
|
||||
writeInt(pptr, prop->value.integer2);
|
||||
rc = 2;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER:
|
||||
writeInt4(pptr, prop->value.integer4);
|
||||
rc = 4;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER:
|
||||
rc = MQTTPacket_encode(*pptr, prop->value.integer4);
|
||||
*pptr += rc;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_BINARY_DATA:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING:
|
||||
writeMQTTLenString(pptr, prop->value.data);
|
||||
rc = prop->value.data.len + 2; /* include length field */
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR:
|
||||
writeMQTTLenString(pptr, prop->value.data);
|
||||
writeMQTTLenString(pptr, prop->value.value);
|
||||
rc = prop->value.data.len + prop->value.value.len + 4; /* include length fields */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc + 1; /* include identifier byte */
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_write(char** pptr, const MQTTProperties* properties)
|
||||
{
|
||||
int rc = -1;
|
||||
int i = 0, len = 0;
|
||||
|
||||
/* write the entire property list length first */
|
||||
if (properties == NULL)
|
||||
{
|
||||
*pptr += MQTTPacket_encode(*pptr, 0);
|
||||
rc = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pptr += MQTTPacket_encode(*pptr, properties->length);
|
||||
len = rc = 1;
|
||||
for (i = 0; i < properties->count; ++i)
|
||||
{
|
||||
rc = MQTTProperty_write(pptr, &properties->array[i]);
|
||||
if (rc < 0)
|
||||
break;
|
||||
else
|
||||
len += rc;
|
||||
}
|
||||
if (rc >= 0)
|
||||
rc = len;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperty_read(MQTTProperty* prop, char** pptr, char* enddata)
|
||||
{
|
||||
int type = -1,
|
||||
len = -1;
|
||||
|
||||
prop->identifier = readChar(pptr);
|
||||
type = MQTTProperty_getType(prop->identifier);
|
||||
if (type >= MQTTPROPERTY_TYPE_BYTE && type <= MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MQTTPROPERTY_TYPE_BYTE:
|
||||
prop->value.byte = readChar(pptr);
|
||||
len = 1;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER:
|
||||
prop->value.integer2 = readInt(pptr);
|
||||
len = 2;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER:
|
||||
prop->value.integer4 = readInt4(pptr);
|
||||
len = 4;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER:
|
||||
len = MQTTPacket_decodeBuf(*pptr, &prop->value.integer4);
|
||||
*pptr += len;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_BINARY_DATA:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR:
|
||||
if ((len = MQTTLenStringRead(&prop->value.data, pptr, enddata)) == -1)
|
||||
break; /* error */
|
||||
if ((prop->value.data.data = datadup(&prop->value.data)) == NULL)
|
||||
{
|
||||
len = -1;
|
||||
break; /* error */
|
||||
}
|
||||
if (type == MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR)
|
||||
{
|
||||
int proplen = MQTTLenStringRead(&prop->value.value, pptr, enddata);
|
||||
|
||||
if (proplen == -1)
|
||||
{
|
||||
len = -1;
|
||||
free(prop->value.data.data);
|
||||
break;
|
||||
}
|
||||
len += proplen;
|
||||
if ((prop->value.value.data = datadup(&prop->value.value)) == NULL)
|
||||
{
|
||||
len = -1;
|
||||
free(prop->value.data.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (len == -1) ? -1 : len + 1; /* 1 byte for identifier */
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_read(MQTTProperties* properties, char** pptr, char* enddata)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int remlength = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
/* we assume an initialized properties structure */
|
||||
if (enddata - (*pptr) > 0) /* enough length to read the VBI? */
|
||||
{
|
||||
int proplen = 0;
|
||||
|
||||
*pptr += MQTTPacket_decodeBuf(*pptr, &remlength);
|
||||
properties->length = remlength;
|
||||
while (remlength > 0)
|
||||
{
|
||||
if (properties->count == properties->max_count)
|
||||
{
|
||||
properties->max_count += 10;
|
||||
if (properties->max_count == 10)
|
||||
properties->array = malloc(sizeof(MQTTProperty) * properties->max_count);
|
||||
else
|
||||
properties->array = realloc(properties->array, sizeof(MQTTProperty) * properties->max_count);
|
||||
}
|
||||
if (properties->array == NULL)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
if ((proplen = MQTTProperty_read(&properties->array[properties->count], pptr, enddata)) > 0)
|
||||
remlength -= proplen;
|
||||
else
|
||||
break;
|
||||
properties->count++;
|
||||
}
|
||||
if (remlength == 0)
|
||||
rc = 1; /* data read successfully */
|
||||
}
|
||||
|
||||
if (rc != 1 && properties->array != NULL)
|
||||
MQTTProperties_free(properties);
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct {
|
||||
enum MQTTPropertyCodes value;
|
||||
const char* name;
|
||||
} nameToString[] =
|
||||
{
|
||||
{MQTTPROPERTY_CODE_PAYLOAD_FORMAT_INDICATOR, "PAYLOAD_FORMAT_INDICATOR"},
|
||||
{MQTTPROPERTY_CODE_MESSAGE_EXPIRY_INTERVAL, "MESSAGE_EXPIRY_INTERVAL"},
|
||||
{MQTTPROPERTY_CODE_CONTENT_TYPE, "CONTENT_TYPE"},
|
||||
{MQTTPROPERTY_CODE_RESPONSE_TOPIC, "RESPONSE_TOPIC"},
|
||||
{MQTTPROPERTY_CODE_CORRELATION_DATA, "CORRELATION_DATA"},
|
||||
{MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIER, "SUBSCRIPTION_IDENTIFIER"},
|
||||
{MQTTPROPERTY_CODE_SESSION_EXPIRY_INTERVAL, "SESSION_EXPIRY_INTERVAL"},
|
||||
{MQTTPROPERTY_CODE_ASSIGNED_CLIENT_IDENTIFER, "ASSIGNED_CLIENT_IDENTIFER"},
|
||||
{MQTTPROPERTY_CODE_SERVER_KEEP_ALIVE, "SERVER_KEEP_ALIVE"},
|
||||
{MQTTPROPERTY_CODE_AUTHENTICATION_METHOD, "AUTHENTICATION_METHOD"},
|
||||
{MQTTPROPERTY_CODE_AUTHENTICATION_DATA, "AUTHENTICATION_DATA"},
|
||||
{MQTTPROPERTY_CODE_REQUEST_PROBLEM_INFORMATION, "REQUEST_PROBLEM_INFORMATION"},
|
||||
{MQTTPROPERTY_CODE_WILL_DELAY_INTERVAL, "WILL_DELAY_INTERVAL"},
|
||||
{MQTTPROPERTY_CODE_REQUEST_RESPONSE_INFORMATION, "REQUEST_RESPONSE_INFORMATION"},
|
||||
{MQTTPROPERTY_CODE_RESPONSE_INFORMATION, "RESPONSE_INFORMATION"},
|
||||
{MQTTPROPERTY_CODE_SERVER_REFERENCE, "SERVER_REFERENCE"},
|
||||
{MQTTPROPERTY_CODE_REASON_STRING, "REASON_STRING"},
|
||||
{MQTTPROPERTY_CODE_RECEIVE_MAXIMUM, "RECEIVE_MAXIMUM"},
|
||||
{MQTTPROPERTY_CODE_TOPIC_ALIAS_MAXIMUM, "TOPIC_ALIAS_MAXIMUM"},
|
||||
{MQTTPROPERTY_CODE_TOPIC_ALIAS, "TOPIC_ALIAS"},
|
||||
{MQTTPROPERTY_CODE_MAXIMUM_QOS, "MAXIMUM_QOS"},
|
||||
{MQTTPROPERTY_CODE_RETAIN_AVAILABLE, "RETAIN_AVAILABLE"},
|
||||
{MQTTPROPERTY_CODE_USER_PROPERTY, "USER_PROPERTY"},
|
||||
{MQTTPROPERTY_CODE_MAXIMUM_PACKET_SIZE, "MAXIMUM_PACKET_SIZE"},
|
||||
{MQTTPROPERTY_CODE_WILDCARD_SUBSCRIPTION_AVAILABLE, "WILDCARD_SUBSCRIPTION_AVAILABLE"},
|
||||
{MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIERS_AVAILABLE, "SUBSCRIPTION_IDENTIFIERS_AVAILABLE"},
|
||||
{MQTTPROPERTY_CODE_SHARED_SUBSCRIPTION_AVAILABLE, "SHARED_SUBSCRIPTION_AVAILABLE"}
|
||||
};
|
||||
|
||||
const char* MQTTPropertyName(enum MQTTPropertyCodes value)
|
||||
{
|
||||
int i = 0;
|
||||
const char* result = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nameToString); ++i)
|
||||
{
|
||||
if (nameToString[i].value == value)
|
||||
{
|
||||
result = nameToString[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void MQTTProperties_free(MQTTProperties* props)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (props == NULL)
|
||||
goto exit;
|
||||
for (i = 0; i < props->count; ++i)
|
||||
{
|
||||
int id = props->array[i].identifier;
|
||||
int type = MQTTProperty_getType(id);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MQTTPROPERTY_TYPE_BINARY_DATA:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING:
|
||||
case MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR:
|
||||
free(props->array[i].value.data.data);
|
||||
if (type == MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR)
|
||||
free(props->array[i].value.value.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (props->array)
|
||||
free(props->array);
|
||||
memset(props, '\0', sizeof(MQTTProperties)); /* zero all fields */
|
||||
exit:
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
MQTTProperties MQTTProperties_copy(const MQTTProperties* props)
|
||||
{
|
||||
int i = 0;
|
||||
MQTTProperties result = MQTTProperties_initializer;
|
||||
|
||||
FUNC_ENTRY;
|
||||
for (i = 0; i < props->count; ++i)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if ((rc = MQTTProperties_add(&result, &props->array[i])) != 0)
|
||||
Log(LOG_ERROR, -1, "Error from MQTTProperties add %d", rc);
|
||||
}
|
||||
|
||||
FUNC_EXIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_hasProperty(MQTTProperties *props, enum MQTTPropertyCodes propid)
|
||||
{
|
||||
int i = 0;
|
||||
int found = 0;
|
||||
|
||||
for (i = 0; i < props->count; ++i)
|
||||
{
|
||||
if (propid == props->array[i].identifier)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_propertyCount(MQTTProperties *props, enum MQTTPropertyCodes propid)
|
||||
{
|
||||
int i = 0;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < props->count; ++i)
|
||||
{
|
||||
if (propid == props->array[i].identifier)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_getNumericValueAt(MQTTProperties *props, enum MQTTPropertyCodes propid, int index)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = -9999999;
|
||||
int cur_index = 0;
|
||||
|
||||
for (i = 0; i < props->count; ++i)
|
||||
{
|
||||
int id = props->array[i].identifier;
|
||||
|
||||
if (id == propid)
|
||||
{
|
||||
if (cur_index < index)
|
||||
{
|
||||
cur_index++;
|
||||
continue;
|
||||
}
|
||||
switch (MQTTProperty_getType(id))
|
||||
{
|
||||
case MQTTPROPERTY_TYPE_BYTE:
|
||||
rc = props->array[i].value.byte;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER:
|
||||
rc = props->array[i].value.integer2;
|
||||
break;
|
||||
case MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER:
|
||||
case MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER:
|
||||
rc = props->array[i].value.integer4;
|
||||
break;
|
||||
default:
|
||||
rc = -999999;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTProperties_getNumericValue(MQTTProperties *props, enum MQTTPropertyCodes propid)
|
||||
{
|
||||
return MQTTProperties_getNumericValueAt(props, propid, 0);
|
||||
}
|
||||
|
||||
|
||||
MQTTProperty* MQTTProperties_getPropertyAt(MQTTProperties *props, enum MQTTPropertyCodes propid, int index)
|
||||
{
|
||||
int i = 0;
|
||||
MQTTProperty* result = NULL;
|
||||
int cur_index = 0;
|
||||
|
||||
for (i = 0; i < props->count; ++i)
|
||||
{
|
||||
int id = props->array[i].identifier;
|
||||
|
||||
if (id == propid)
|
||||
{
|
||||
if (cur_index == index)
|
||||
{
|
||||
result = &props->array[i];
|
||||
break;
|
||||
}
|
||||
else
|
||||
cur_index++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
MQTTProperty* MQTTProperties_getProperty(MQTTProperties *props, enum MQTTPropertyCodes propid)
|
||||
{
|
||||
return MQTTProperties_getPropertyAt(props, propid, 0);
|
||||
}
|
||||
222
src/mqtt/externals/paho-mqtt-c/src/MQTTProperties.h
vendored
Normal file
222
src/mqtt/externals/paho-mqtt-c/src/MQTTProperties.h
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2023 IBM Corp. and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPROPERTIES_H)
|
||||
#define MQTTPROPERTIES_H
|
||||
|
||||
#include "MQTTExportDeclarations.h"
|
||||
|
||||
#define MQTT_INVALID_PROPERTY_ID -2
|
||||
|
||||
/** The one byte MQTT V5 property indicator */
|
||||
enum MQTTPropertyCodes {
|
||||
MQTTPROPERTY_CODE_PAYLOAD_FORMAT_INDICATOR = 1, /**< The value is 1 */
|
||||
MQTTPROPERTY_CODE_MESSAGE_EXPIRY_INTERVAL = 2, /**< The value is 2 */
|
||||
MQTTPROPERTY_CODE_CONTENT_TYPE = 3, /**< The value is 3 */
|
||||
MQTTPROPERTY_CODE_RESPONSE_TOPIC = 8, /**< The value is 8 */
|
||||
MQTTPROPERTY_CODE_CORRELATION_DATA = 9, /**< The value is 9 */
|
||||
MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIER = 11, /**< The value is 11 */
|
||||
MQTTPROPERTY_CODE_SESSION_EXPIRY_INTERVAL = 17, /**< The value is 17 */
|
||||
MQTTPROPERTY_CODE_ASSIGNED_CLIENT_IDENTIFER = 18,/**< The value is 18 */
|
||||
MQTTPROPERTY_CODE_SERVER_KEEP_ALIVE = 19, /**< The value is 19 */
|
||||
MQTTPROPERTY_CODE_AUTHENTICATION_METHOD = 21, /**< The value is 21 */
|
||||
MQTTPROPERTY_CODE_AUTHENTICATION_DATA = 22, /**< The value is 22 */
|
||||
MQTTPROPERTY_CODE_REQUEST_PROBLEM_INFORMATION = 23,/**< The value is 23 */
|
||||
MQTTPROPERTY_CODE_WILL_DELAY_INTERVAL = 24, /**< The value is 24 */
|
||||
MQTTPROPERTY_CODE_REQUEST_RESPONSE_INFORMATION = 25,/**< The value is 25 */
|
||||
MQTTPROPERTY_CODE_RESPONSE_INFORMATION = 26, /**< The value is 26 */
|
||||
MQTTPROPERTY_CODE_SERVER_REFERENCE = 28, /**< The value is 28 */
|
||||
MQTTPROPERTY_CODE_REASON_STRING = 31, /**< The value is 31 */
|
||||
MQTTPROPERTY_CODE_RECEIVE_MAXIMUM = 33, /**< The value is 33*/
|
||||
MQTTPROPERTY_CODE_TOPIC_ALIAS_MAXIMUM = 34, /**< The value is 34 */
|
||||
MQTTPROPERTY_CODE_TOPIC_ALIAS = 35, /**< The value is 35 */
|
||||
MQTTPROPERTY_CODE_MAXIMUM_QOS = 36, /**< The value is 36 */
|
||||
MQTTPROPERTY_CODE_RETAIN_AVAILABLE = 37, /**< The value is 37 */
|
||||
MQTTPROPERTY_CODE_USER_PROPERTY = 38, /**< The value is 38 */
|
||||
MQTTPROPERTY_CODE_MAXIMUM_PACKET_SIZE = 39, /**< The value is 39 */
|
||||
MQTTPROPERTY_CODE_WILDCARD_SUBSCRIPTION_AVAILABLE = 40,/**< The value is 40 */
|
||||
MQTTPROPERTY_CODE_SUBSCRIPTION_IDENTIFIERS_AVAILABLE = 41,/**< The value is 41 */
|
||||
MQTTPROPERTY_CODE_SHARED_SUBSCRIPTION_AVAILABLE = 42/**< The value is 241 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a printable string description of an MQTT V5 property code.
|
||||
* @param value an MQTT V5 property code.
|
||||
* @return the printable string description of the input property code.
|
||||
* NULL if the code was not found.
|
||||
*/
|
||||
LIBMQTT_API const char* MQTTPropertyName(enum MQTTPropertyCodes value);
|
||||
|
||||
/** The one byte MQTT V5 property type */
|
||||
enum MQTTPropertyTypes {
|
||||
MQTTPROPERTY_TYPE_BYTE,
|
||||
MQTTPROPERTY_TYPE_TWO_BYTE_INTEGER,
|
||||
MQTTPROPERTY_TYPE_FOUR_BYTE_INTEGER,
|
||||
MQTTPROPERTY_TYPE_VARIABLE_BYTE_INTEGER,
|
||||
MQTTPROPERTY_TYPE_BINARY_DATA,
|
||||
MQTTPROPERTY_TYPE_UTF_8_ENCODED_STRING,
|
||||
MQTTPROPERTY_TYPE_UTF_8_STRING_PAIR
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the MQTT V5 type code of an MQTT V5 property.
|
||||
* @param value an MQTT V5 property code.
|
||||
* @return the MQTT V5 type code of the input property. -1 if the code was not found.
|
||||
*/
|
||||
LIBMQTT_API int MQTTProperty_getType(enum MQTTPropertyCodes value);
|
||||
|
||||
/**
|
||||
* The data for a length delimited string
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int len; /**< the length of the string */
|
||||
char* data; /**< pointer to the string data */
|
||||
} MQTTLenString;
|
||||
|
||||
|
||||
/**
|
||||
* Structure to hold an MQTT version 5 property of any type
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
enum MQTTPropertyCodes identifier; /**< The MQTT V5 property id. A multi-byte integer. */
|
||||
/** The value of the property, as a union of the different possible types. */
|
||||
union {
|
||||
unsigned char byte; /**< holds the value of a byte property type */
|
||||
unsigned short integer2; /**< holds the value of a 2 byte integer property type */
|
||||
unsigned int integer4; /**< holds the value of a 4 byte integer property type */
|
||||
struct {
|
||||
MQTTLenString data; /**< The value of a string property, or the name of a user property. */
|
||||
MQTTLenString value; /**< The value of a user property. */
|
||||
};
|
||||
} value;
|
||||
} MQTTProperty;
|
||||
|
||||
/**
|
||||
* MQTT version 5 property list
|
||||
*/
|
||||
typedef struct MQTTProperties
|
||||
{
|
||||
int count; /**< number of property entries in the array */
|
||||
int max_count; /**< max number of properties that the currently allocated array can store */
|
||||
int length; /**< mbi: byte length of all properties */
|
||||
MQTTProperty *array; /**< array of properties */
|
||||
} MQTTProperties;
|
||||
|
||||
#define MQTTProperties_initializer {0, 0, 0, NULL}
|
||||
|
||||
/**
|
||||
* Returns the length of the properties structure when serialized ready for network transmission.
|
||||
* @param props an MQTT V5 property structure.
|
||||
* @return the length in bytes of the properties when serialized.
|
||||
*/
|
||||
int MQTTProperties_len(MQTTProperties* props);
|
||||
|
||||
/**
|
||||
* Add a property pointer to the property array. Memory is allocated in this function,
|
||||
* so MQTTClient_create or MQTTAsync_create must be called first to initialize the
|
||||
* internal heap tracking. Alternatively MQTTAsync_global_init() can be called first
|
||||
* or build with the HIGH_PERFORMANCE option which disables the heap tracking.
|
||||
* @param props The property list to add the property to.
|
||||
* @param prop The property to add to the list.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
LIBMQTT_API int MQTTProperties_add(MQTTProperties* props, const MQTTProperty* prop);
|
||||
|
||||
/**
|
||||
* Serialize the given property list to a character buffer, e.g. for writing to the network.
|
||||
* @param pptr pointer to the buffer - move the pointer as we add data
|
||||
* @param properties pointer to the property list, can be NULL
|
||||
* @return whether the write succeeded or not: number of bytes written, or < 0 on failure.
|
||||
*/
|
||||
int MQTTProperties_write(char** pptr, const MQTTProperties* properties);
|
||||
|
||||
/**
|
||||
* Reads a property list from a character buffer into an array.
|
||||
* @param properties pointer to the property list to be filled. Should be initalized but empty.
|
||||
* @param pptr pointer to the character buffer.
|
||||
* @param enddata pointer to the end of the character buffer so we don't read beyond.
|
||||
* @return 1 if the properties were read successfully.
|
||||
*/
|
||||
int MQTTProperties_read(MQTTProperties* properties, char** pptr, char* enddata);
|
||||
|
||||
/**
|
||||
* Free all memory allocated to the property list, including any to individual properties.
|
||||
* @param properties pointer to the property list.
|
||||
*/
|
||||
LIBMQTT_API void MQTTProperties_free(MQTTProperties* properties);
|
||||
|
||||
/**
|
||||
* Copy the contents of a property list, allocating additional memory if needed.
|
||||
* @param props pointer to the property list.
|
||||
* @return the duplicated property list.
|
||||
*/
|
||||
LIBMQTT_API MQTTProperties MQTTProperties_copy(const MQTTProperties* props);
|
||||
|
||||
/**
|
||||
* Checks if property list contains a specific property.
|
||||
* @param props pointer to the property list.
|
||||
* @param propid the property id to check for.
|
||||
* @return 1 if found, 0 if not.
|
||||
*/
|
||||
LIBMQTT_API int MQTTProperties_hasProperty(MQTTProperties *props, enum MQTTPropertyCodes propid);
|
||||
|
||||
/**
|
||||
* Returns the number of instances of a property id. Most properties can exist only once.
|
||||
* User properties and subscription ids can exist more than once.
|
||||
* @param props pointer to the property list.
|
||||
* @param propid the property id to check for.
|
||||
* @return the number of times found. Can be 0.
|
||||
*/
|
||||
LIBMQTT_API int MQTTProperties_propertyCount(MQTTProperties *props, enum MQTTPropertyCodes propid);
|
||||
|
||||
/**
|
||||
* Returns the integer value of a specific property. The property given must be a numeric type.
|
||||
* @param props pointer to the property list.
|
||||
* @param propid the property id to check for.
|
||||
* @return the integer value of the property. -9999999 on failure.
|
||||
*/
|
||||
LIBMQTT_API int MQTTProperties_getNumericValue(MQTTProperties *props, enum MQTTPropertyCodes propid);
|
||||
|
||||
/**
|
||||
* Returns the integer value of a specific property when it's not the only instance.
|
||||
* The property given must be a numeric type.
|
||||
* @param props pointer to the property list.
|
||||
* @param propid the property id to check for.
|
||||
* @param index the instance number, starting at 0.
|
||||
* @return the integer value of the property. -9999999 on failure.
|
||||
*/
|
||||
LIBMQTT_API int MQTTProperties_getNumericValueAt(MQTTProperties *props, enum MQTTPropertyCodes propid, int index);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the property structure for a specific property.
|
||||
* @param props pointer to the property list.
|
||||
* @param propid the property id to check for.
|
||||
* @return the pointer to the property structure if found. NULL if not found.
|
||||
*/
|
||||
LIBMQTT_API MQTTProperty* MQTTProperties_getProperty(MQTTProperties *props, enum MQTTPropertyCodes propid);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the property structure for a specific property when it's not the only instance.
|
||||
* @param props pointer to the property list.
|
||||
* @param propid the property id to check for.
|
||||
* @param index the instance number, starting at 0.
|
||||
* @return the pointer to the property structure if found. NULL if not found.
|
||||
*/
|
||||
LIBMQTT_API MQTTProperty* MQTTProperties_getPropertyAt(MQTTProperties *props, enum MQTTPropertyCodes propid, int index);
|
||||
|
||||
#endif /* MQTTPROPERTIES_H */
|
||||
46
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocol.h
vendored
Normal file
46
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocol.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp., Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - MQTT 3.1.1 updates
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPROTOCOL_H)
|
||||
#define MQTTPROTOCOL_H
|
||||
|
||||
#include "LinkedList.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include "Clients.h"
|
||||
|
||||
#define MAX_MSG_ID 65535
|
||||
#define MAX_CLIENTID_LEN 65535
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOCKET socket;
|
||||
Publications* p;
|
||||
} pending_write;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
List publications;
|
||||
unsigned int msgs_received;
|
||||
unsigned int msgs_sent;
|
||||
List pending_writes; /* for qos 0 writes not complete */
|
||||
} MQTTProtocol;
|
||||
|
||||
|
||||
#include "MQTTProtocolOut.h"
|
||||
|
||||
#endif
|
||||
1114
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolClient.c
vendored
Normal file
1114
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolClient.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
62
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolClient.h
vendored
Normal file
62
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolClient.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - MQTT 3.1.1 updates
|
||||
* Rong Xiang, Ian Craggs - C++ compatibility
|
||||
* Ian Craggs - add debug definition of MQTTStrdup for when needed
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPROTOCOLCLIENT_H)
|
||||
#define MQTTPROTOCOLCLIENT_H
|
||||
|
||||
#include "LinkedList.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include "Log.h"
|
||||
#include "MQTTProtocol.h"
|
||||
#include "Messages.h"
|
||||
#include "MQTTProperties.h"
|
||||
|
||||
#define MAX_MSG_ID 65535
|
||||
#define MAX_CLIENTID_LEN 65535
|
||||
|
||||
int MQTTProtocol_startPublish(Clients* pubclient, Publish* publish, int qos, int retained, Messages** m);
|
||||
Messages* MQTTProtocol_createMessage(Publish* publish, Messages** mm, int qos, int retained, int allocatePayload);
|
||||
Publications* MQTTProtocol_storePublication(Publish* publish, int* len);
|
||||
int messageIDCompare(void* a, void* b);
|
||||
int MQTTProtocol_assignMsgId(Clients* client);
|
||||
void MQTTProtocol_removePublication(Publications* p);
|
||||
void Protocol_processPublication(Publish* publish, Clients* client, int allocatePayload);
|
||||
|
||||
int MQTTProtocol_handlePublishes(void* pack, SOCKET sock);
|
||||
int MQTTProtocol_handlePubacks(void* pack, SOCKET sock, Publications** pubToRemove);
|
||||
int MQTTProtocol_handlePubrecs(void* pack, SOCKET sock, Publications** pubToRemove);
|
||||
int MQTTProtocol_handlePubrels(void* pack, SOCKET sock);
|
||||
int MQTTProtocol_handlePubcomps(void* pack, SOCKET sock, Publications** pubToRemove);
|
||||
|
||||
void MQTTProtocol_closeSession(Clients* c, int sendwill);
|
||||
void MQTTProtocol_keepalive(START_TIME_TYPE);
|
||||
void MQTTProtocol_retry(START_TIME_TYPE, int, int);
|
||||
void MQTTProtocol_freeClient(Clients* client);
|
||||
void MQTTProtocol_emptyMessageList(List* msgList);
|
||||
void MQTTProtocol_freeMessageList(List* msgList);
|
||||
|
||||
char* MQTTStrncpy(char *dest, const char* src, size_t num);
|
||||
char* MQTTStrdup(const char* src);
|
||||
|
||||
void MQTTProtocol_writeAvailable(SOCKET socket);
|
||||
|
||||
//#define MQTTStrdup(src) MQTTStrncpy(malloc(strlen(src)+1), src, strlen(src)+1)
|
||||
|
||||
#endif
|
||||
479
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolOut.c
vendored
Normal file
479
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolOut.c
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp., Ian Craggs and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - fix for buffer overflow in addressPort bug #433290
|
||||
* Ian Craggs - MQTT 3.1.1 support
|
||||
* Rong Xiang, Ian Craggs - C++ compatibility
|
||||
* Ian Craggs - fix for bug 479376
|
||||
* Ian Craggs - SNI support
|
||||
* Ian Craggs - fix for issue #164
|
||||
* Ian Craggs - fix for issue #179
|
||||
* Ian Craggs - MQTT 5.0 support
|
||||
* Sven Gambel - add generic proxy support
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Functions dealing with the MQTT protocol exchanges
|
||||
*
|
||||
* Some other related functions are in the MQTTProtocolClient module
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "MQTTProtocolOut.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Heap.h"
|
||||
#include "WebSocket.h"
|
||||
#include "Proxy.h"
|
||||
#include "Base64.h"
|
||||
|
||||
extern ClientStates* bstate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Separates an address:port into two separate values
|
||||
* @param[in] uri the input string - hostname:port
|
||||
* @param[out] port the returned port integer
|
||||
* @param[out] topic optional topic portion of the address starting with '/'
|
||||
* @return the address string
|
||||
*/
|
||||
size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic, int default_port)
|
||||
{
|
||||
char* buf = (char*)uri;
|
||||
char* colon_pos;
|
||||
size_t len;
|
||||
char* topic_pos;
|
||||
|
||||
FUNC_ENTRY;
|
||||
colon_pos = strrchr(uri, ':'); /* reverse find to allow for ':' in IPv6 addresses */
|
||||
|
||||
if (uri[0] == '[')
|
||||
{ /* ip v6 */
|
||||
if (colon_pos < strrchr(uri, ']'))
|
||||
colon_pos = NULL; /* means it was an IPv6 separator, not for host:port */
|
||||
}
|
||||
|
||||
if (colon_pos) /* have to strip off the port */
|
||||
{
|
||||
len = colon_pos - uri;
|
||||
*port = atoi(colon_pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = strlen(buf);
|
||||
*port = default_port;
|
||||
}
|
||||
|
||||
/* find any topic portion */
|
||||
topic_pos = (char*)uri;
|
||||
if (colon_pos)
|
||||
topic_pos = colon_pos;
|
||||
topic_pos = strchr(topic_pos, '/');
|
||||
if (topic_pos)
|
||||
{
|
||||
if (topic)
|
||||
*topic = topic_pos;
|
||||
if (!colon_pos)
|
||||
len = topic_pos - uri;
|
||||
}
|
||||
|
||||
if (buf[len - 1] == ']')
|
||||
{
|
||||
/* we are stripping off the final ], so length is 1 shorter */
|
||||
--len;
|
||||
}
|
||||
FUNC_EXIT;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allow user or password characters to be expressed in the form of %XX, XX being the
|
||||
* hexadecimal value of the character. This will avoid problems when a user code or a password
|
||||
* contains a '@' or another special character ('%' included)
|
||||
* @param p0 output string
|
||||
* @param p1 input string
|
||||
* @param basic_auth_in_len
|
||||
*/
|
||||
void MQTTProtocol_specialChars(char* p0, char* p1, b64_size_t *basic_auth_in_len)
|
||||
{
|
||||
while (*p1 != '@')
|
||||
{
|
||||
if (*p1 != '%')
|
||||
{
|
||||
*p0++ = *p1++;
|
||||
}
|
||||
else if (isxdigit(*(p1 + 1)) && isxdigit(*(p1 + 2)))
|
||||
{
|
||||
/* next 2 characters are hexa digits */
|
||||
char hex[3];
|
||||
p1++;
|
||||
hex[0] = *p1++;
|
||||
hex[1] = *p1++;
|
||||
hex[2] = '\0';
|
||||
*p0++ = (char)strtol(hex, 0, 16);
|
||||
/* 3 input char => 1 output char */
|
||||
*basic_auth_in_len -= 2;
|
||||
}
|
||||
}
|
||||
*p0 = 0x0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Examples of proxy settings:
|
||||
* http://your.proxy.server:8080/
|
||||
* http://user:pass@my.proxy.server:8080/
|
||||
*/
|
||||
int MQTTProtocol_setHTTPProxy(Clients* aClient, char* source, char** dest, char** auth_dest, char* prefix)
|
||||
{
|
||||
b64_size_t basic_auth_in_len, basic_auth_out_len;
|
||||
b64_data_t *basic_auth;
|
||||
char *p1;
|
||||
int rc = 0;
|
||||
|
||||
if (*auth_dest)
|
||||
{
|
||||
free(*auth_dest);
|
||||
*auth_dest = NULL;
|
||||
}
|
||||
|
||||
if (source)
|
||||
{
|
||||
if ((p1 = strstr(source, prefix)) != NULL) /* skip http:// prefix, if any */
|
||||
source += strlen(prefix);
|
||||
*dest = source;
|
||||
if ((p1 = strchr(source, '@')) != NULL) /* find user.pass separator */
|
||||
*dest = p1 + 1;
|
||||
|
||||
if (p1)
|
||||
{
|
||||
/* basic auth len is string between http:// and @ */
|
||||
basic_auth_in_len = (b64_size_t)(p1 - source);
|
||||
if (basic_auth_in_len > 0)
|
||||
{
|
||||
basic_auth = (b64_data_t *)malloc(sizeof(char)*(basic_auth_in_len+1));
|
||||
if (!basic_auth)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
MQTTProtocol_specialChars((char*)basic_auth, source, &basic_auth_in_len);
|
||||
basic_auth_out_len = Base64_encodeLength(basic_auth, basic_auth_in_len) + 1; /* add 1 for trailing NULL */
|
||||
if ((*auth_dest = (char *)malloc(sizeof(char)*basic_auth_out_len)) == NULL)
|
||||
{
|
||||
free(basic_auth);
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
Base64_encode(*auth_dest, basic_auth_out_len, basic_auth, basic_auth_in_len);
|
||||
free(basic_auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MQTT outgoing connect processing for a client
|
||||
* @param ip_address the TCP address:port to connect to
|
||||
* @param aClient a structure with all MQTT data needed
|
||||
* @param int ssl
|
||||
* @param int MQTTVersion the MQTT version to connect with (3 or 4)
|
||||
* @param long timeout how long to wait for a new socket to be created
|
||||
* @return return code
|
||||
*/
|
||||
#if defined(OPENSSL)
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int ssl, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties, long timeout)
|
||||
#else
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int ssl, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties, long timeout)
|
||||
#else
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
int rc = 0,
|
||||
port;
|
||||
size_t addr_len;
|
||||
char* p0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
aClient->good = 1;
|
||||
|
||||
if (aClient->httpProxy)
|
||||
p0 = aClient->httpProxy;
|
||||
else
|
||||
p0 = getenv("http_proxy");
|
||||
|
||||
if (p0)
|
||||
{
|
||||
if ((rc = MQTTProtocol_setHTTPProxy(aClient, p0, &aClient->net.http_proxy, &aClient->net.http_proxy_auth, "http://")) != 0)
|
||||
goto exit;
|
||||
Log(TRACE_PROTOCOL, -1, "Setting http proxy to %s", aClient->net.http_proxy);
|
||||
if (aClient->net.http_proxy_auth)
|
||||
Log(TRACE_PROTOCOL, -1, "Setting http proxy auth to %s", aClient->net.http_proxy_auth);
|
||||
}
|
||||
|
||||
#if defined(OPENSSL)
|
||||
if (aClient->httpsProxy)
|
||||
p0 = aClient->httpsProxy;
|
||||
else
|
||||
p0 = getenv("https_proxy");
|
||||
|
||||
if (p0)
|
||||
{
|
||||
if ((rc = MQTTProtocol_setHTTPProxy(aClient, p0, &aClient->net.https_proxy, &aClient->net.https_proxy_auth, "https://")) != 0)
|
||||
goto exit;
|
||||
Log(TRACE_PROTOCOL, -1, "Setting https proxy to %s", aClient->net.https_proxy);
|
||||
if (aClient->net.https_proxy_auth)
|
||||
Log(TRACE_PROTOCOL, -1, "Setting https proxy auth to %s", aClient->net.https_proxy_auth);
|
||||
}
|
||||
|
||||
if (!ssl && aClient->net.http_proxy) {
|
||||
#else
|
||||
if (aClient->net.http_proxy) {
|
||||
#endif
|
||||
addr_len = MQTTProtocol_addressPort(aClient->net.http_proxy, &port, NULL, PROXY_DEFAULT_PORT);
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
if (timeout < 0)
|
||||
rc = -1;
|
||||
else
|
||||
rc = Socket_new(aClient->net.http_proxy, addr_len, port, &(aClient->net.socket), timeout);
|
||||
#else
|
||||
rc = Socket_new(aClient->net.http_proxy, addr_len, port, &(aClient->net.socket));
|
||||
#endif
|
||||
}
|
||||
#if defined(OPENSSL)
|
||||
else if (ssl && aClient->net.https_proxy) {
|
||||
addr_len = MQTTProtocol_addressPort(aClient->net.https_proxy, &port, NULL, PROXY_DEFAULT_PORT);
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
if (timeout < 0)
|
||||
rc = -1;
|
||||
else
|
||||
rc = Socket_new(aClient->net.https_proxy, addr_len, port, &(aClient->net.socket), timeout);
|
||||
#else
|
||||
rc = Socket_new(aClient->net.https_proxy, addr_len, port, &(aClient->net.socket));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
#if defined(OPENSSL)
|
||||
addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL, ssl ?
|
||||
(websocket ? WSS_DEFAULT_PORT : SECURE_MQTT_DEFAULT_PORT) :
|
||||
(websocket ? WS_DEFAULT_PORT : MQTT_DEFAULT_PORT) );
|
||||
#else
|
||||
addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL, websocket ? WS_DEFAULT_PORT : MQTT_DEFAULT_PORT);
|
||||
#endif
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
if (timeout < 0)
|
||||
rc = -1;
|
||||
else
|
||||
rc = Socket_new(ip_address, addr_len, port, &(aClient->net.socket), timeout);
|
||||
#else
|
||||
rc = Socket_new(ip_address, addr_len, port, &(aClient->net.socket));
|
||||
#endif
|
||||
}
|
||||
if (rc == EINPROGRESS || rc == EWOULDBLOCK)
|
||||
aClient->connect_state = TCP_IN_PROGRESS; /* TCP connect called - wait for connect completion */
|
||||
else if (rc == 0)
|
||||
{ /* TCP connect completed. If SSL, send SSL connect */
|
||||
#if defined(OPENSSL)
|
||||
if (ssl)
|
||||
{
|
||||
if (aClient->net.https_proxy) {
|
||||
aClient->connect_state = PROXY_CONNECT_IN_PROGRESS;
|
||||
rc = Proxy_connect( &aClient->net, 1, ip_address);
|
||||
}
|
||||
if (rc == 0 && SSLSocket_setSocketForSSL(&aClient->net, aClient->sslopts, ip_address, addr_len) == 1)
|
||||
{
|
||||
rc = aClient->sslopts->struct_version >= 3 ?
|
||||
SSLSocket_connect(aClient->net.ssl, aClient->net.socket, ip_address,
|
||||
aClient->sslopts->verify, aClient->sslopts->ssl_error_cb, aClient->sslopts->ssl_error_context) :
|
||||
SSLSocket_connect(aClient->net.ssl, aClient->net.socket, ip_address,
|
||||
aClient->sslopts->verify, NULL, NULL);
|
||||
if (rc == TCPSOCKET_INTERRUPTED)
|
||||
aClient->connect_state = SSL_IN_PROGRESS; /* SSL connect called - wait for completion */
|
||||
}
|
||||
else
|
||||
rc = SOCKET_ERROR;
|
||||
}
|
||||
else if (aClient->net.http_proxy) {
|
||||
#else
|
||||
if (aClient->net.http_proxy) {
|
||||
#endif
|
||||
aClient->connect_state = PROXY_CONNECT_IN_PROGRESS;
|
||||
rc = Proxy_connect( &aClient->net, 0, ip_address);
|
||||
}
|
||||
if ( websocket )
|
||||
{
|
||||
#if defined(OPENSSL)
|
||||
rc = WebSocket_connect(&aClient->net, ssl, ip_address);
|
||||
#else
|
||||
rc = WebSocket_connect(&aClient->net, 0, ip_address);
|
||||
#endif
|
||||
if ( rc == TCPSOCKET_INTERRUPTED )
|
||||
aClient->connect_state = WEBSOCKET_IN_PROGRESS; /* Websocket connect called - wait for completion */
|
||||
}
|
||||
if (rc == 0)
|
||||
{
|
||||
/* Now send the MQTT connect packet */
|
||||
if ((rc = MQTTPacket_send_connect(aClient, MQTTVersion, connectProperties, willProperties)) == 0)
|
||||
aClient->connect_state = WAIT_FOR_CONNACK; /* MQTT Connect sent - wait for CONNACK */
|
||||
else
|
||||
aClient->connect_state = NOT_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an incoming pingresp packet for a socket
|
||||
* @param pack pointer to the publish packet
|
||||
* @param sock the socket on which the packet was received
|
||||
* @return completion code
|
||||
*/
|
||||
int MQTTProtocol_handlePingresps(void* pack, SOCKET sock)
|
||||
{
|
||||
Clients* client = NULL;
|
||||
int rc = TCPSOCKET_COMPLETE;
|
||||
|
||||
FUNC_ENTRY;
|
||||
client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
|
||||
Log(LOG_PROTOCOL, 21, NULL, sock, client->clientID);
|
||||
client->ping_outstanding = 0;
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MQTT outgoing subscribe processing for a client
|
||||
* @param client the client structure
|
||||
* @param topics list of topics
|
||||
* @param qoss corresponding list of QoSs
|
||||
* @param opts MQTT 5.0 subscribe options
|
||||
* @param props MQTT 5.0 subscribe properties
|
||||
* @return completion code
|
||||
*/
|
||||
int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID,
|
||||
MQTTSubscribe_options* opts, MQTTProperties* props)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
rc = MQTTPacket_send_subscribe(topics, qoss, opts, props, msgID, 0, client);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an incoming suback packet for a socket
|
||||
* @param pack pointer to the publish packet
|
||||
* @param sock the socket on which the packet was received
|
||||
* @return completion code
|
||||
*/
|
||||
int MQTTProtocol_handleSubacks(void* pack, SOCKET sock)
|
||||
{
|
||||
Suback* suback = (Suback*)pack;
|
||||
Clients* client = NULL;
|
||||
int rc = TCPSOCKET_COMPLETE;
|
||||
|
||||
FUNC_ENTRY;
|
||||
client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
|
||||
Log(LOG_PROTOCOL, 23, NULL, sock, client->clientID, suback->msgId);
|
||||
MQTTPacket_freeSuback(suback);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MQTT outgoing unsubscribe processing for a client
|
||||
* @param client the client structure
|
||||
* @param topics list of topics
|
||||
* @return completion code
|
||||
*/
|
||||
int MQTTProtocol_unsubscribe(Clients* client, List* topics, int msgID, MQTTProperties* props)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
rc = MQTTPacket_send_unsubscribe(topics, props, msgID, 0, client);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an incoming unsuback packet for a socket
|
||||
* @param pack pointer to the publish packet
|
||||
* @param sock the socket on which the packet was received
|
||||
* @return completion code
|
||||
*/
|
||||
int MQTTProtocol_handleUnsubacks(void* pack, SOCKET sock)
|
||||
{
|
||||
Unsuback* unsuback = (Unsuback*)pack;
|
||||
Clients* client = NULL;
|
||||
int rc = TCPSOCKET_COMPLETE;
|
||||
|
||||
FUNC_ENTRY;
|
||||
client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
|
||||
Log(LOG_PROTOCOL, 24, NULL, sock, client->clientID, unsuback->msgId);
|
||||
MQTTPacket_freeUnsuback(unsuback);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an incoming disconnect packet for a socket
|
||||
* @param pack pointer to the disconnect packet
|
||||
* @param sock the socket on which the packet was received
|
||||
* @return completion code
|
||||
*/
|
||||
int MQTTProtocol_handleDisconnects(void* pack, SOCKET sock)
|
||||
{
|
||||
Ack* disconnect = (Ack*)pack;
|
||||
Clients* client = NULL;
|
||||
int rc = TCPSOCKET_COMPLETE;
|
||||
|
||||
FUNC_ENTRY;
|
||||
client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
|
||||
Log(LOG_PROTOCOL, 30, NULL, sock, client->clientID, disconnect->rc);
|
||||
MQTTPacket_freeAck(disconnect);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
66
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolOut.h
vendored
Normal file
66
src/mqtt/externals/paho-mqtt-c/src/MQTTProtocolOut.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp., Ian Craggs, and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - MQTT 3.1.1 support
|
||||
* Ian Craggs - SNI support
|
||||
* Ian Craggs - MQTT 5.0 support
|
||||
* Sven Gambel - add generic proxy support
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTPROTOCOLOUT_H)
|
||||
#define MQTTPROTOCOLOUT_H
|
||||
|
||||
#include "LinkedList.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include "Clients.h"
|
||||
#include "Log.h"
|
||||
#include "Messages.h"
|
||||
#include "MQTTProtocol.h"
|
||||
#include "MQTTProtocolClient.h"
|
||||
|
||||
#define MQTT_DEFAULT_PORT 1883
|
||||
#define SECURE_MQTT_DEFAULT_PORT 8883
|
||||
#define WS_DEFAULT_PORT 80
|
||||
#define WSS_DEFAULT_PORT 443
|
||||
#define PROXY_DEFAULT_PORT 8080
|
||||
|
||||
size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic, int default_port);
|
||||
void MQTTProtocol_reconnect(const char* ip_address, Clients* client);
|
||||
#if defined(OPENSSL)
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int ssl, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties, long timeout);
|
||||
#else
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int ssl, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties);
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties, long timeout);
|
||||
#else
|
||||
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int websocket, int MQTTVersion,
|
||||
MQTTProperties* connectProperties, MQTTProperties* willProperties);
|
||||
#endif
|
||||
#endif
|
||||
int MQTTProtocol_handlePingresps(void* pack, SOCKET sock);
|
||||
int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID,
|
||||
MQTTSubscribe_options* opts, MQTTProperties* props);
|
||||
int MQTTProtocol_handleSubacks(void* pack, SOCKET sock);
|
||||
int MQTTProtocol_unsubscribe(Clients* client, List* topics, int msgID, MQTTProperties* props);
|
||||
int MQTTProtocol_handleUnsubacks(void* pack, SOCKET sock);
|
||||
int MQTTProtocol_handleDisconnects(void* pack, SOCKET sock);
|
||||
|
||||
#endif
|
||||
101
src/mqtt/externals/paho-mqtt-c/src/MQTTReasonCodes.c
vendored
Normal file
101
src/mqtt/externals/paho-mqtt-c/src/MQTTReasonCodes.c
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2018 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTReasonCodes.h"
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "Heap.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
static struct {
|
||||
enum MQTTReasonCodes value;
|
||||
const char* name;
|
||||
} nameToString[] =
|
||||
{
|
||||
{MQTTREASONCODE_SUCCESS, "SUCCESS"},
|
||||
{MQTTREASONCODE_NORMAL_DISCONNECTION, "Normal disconnection"},
|
||||
{MQTTREASONCODE_GRANTED_QOS_0, "Granted QoS 0"},
|
||||
{MQTTREASONCODE_GRANTED_QOS_1, "Granted QoS 1"},
|
||||
{MQTTREASONCODE_GRANTED_QOS_2, "Granted QoS 2"},
|
||||
{MQTTREASONCODE_DISCONNECT_WITH_WILL_MESSAGE, "Disconnect with Will Message"},
|
||||
{MQTTREASONCODE_NO_MATCHING_SUBSCRIBERS, "No matching subscribers"},
|
||||
{MQTTREASONCODE_NO_SUBSCRIPTION_FOUND, "No subscription found"},
|
||||
{MQTTREASONCODE_CONTINUE_AUTHENTICATION, "Continue authentication"},
|
||||
{MQTTREASONCODE_RE_AUTHENTICATE, "Re-authenticate"},
|
||||
{MQTTREASONCODE_UNSPECIFIED_ERROR, "Unspecified error"},
|
||||
{MQTTREASONCODE_MALFORMED_PACKET, "Malformed Packet"},
|
||||
{MQTTREASONCODE_PROTOCOL_ERROR, "Protocol error"},
|
||||
{MQTTREASONCODE_IMPLEMENTATION_SPECIFIC_ERROR, "Implementation specific error"},
|
||||
{MQTTREASONCODE_UNSUPPORTED_PROTOCOL_VERSION, "Unsupported Protocol Version"},
|
||||
{MQTTREASONCODE_CLIENT_IDENTIFIER_NOT_VALID, "Client Identifier not valid"},
|
||||
{MQTTREASONCODE_BAD_USER_NAME_OR_PASSWORD, "Bad User Name or Password"},
|
||||
{MQTTREASONCODE_NOT_AUTHORIZED, "Not authorized"},
|
||||
{MQTTREASONCODE_SERVER_UNAVAILABLE, "Server unavailable"},
|
||||
{MQTTREASONCODE_SERVER_BUSY, "Server busy"},
|
||||
{MQTTREASONCODE_BANNED, "Banned"},
|
||||
{MQTTREASONCODE_SERVER_SHUTTING_DOWN, "Server shutting down"},
|
||||
{MQTTREASONCODE_BAD_AUTHENTICATION_METHOD, "Bad authentication method"},
|
||||
{MQTTREASONCODE_KEEP_ALIVE_TIMEOUT, "Keep Alive timeout"},
|
||||
{MQTTREASONCODE_SESSION_TAKEN_OVER, "Session taken over"},
|
||||
{MQTTREASONCODE_TOPIC_FILTER_INVALID, "Topic filter invalid"},
|
||||
{MQTTREASONCODE_TOPIC_NAME_INVALID, "Topic name invalid"},
|
||||
{MQTTREASONCODE_PACKET_IDENTIFIER_IN_USE, "Packet Identifier in use"},
|
||||
{MQTTREASONCODE_PACKET_IDENTIFIER_NOT_FOUND, "Packet Identifier not found"},
|
||||
{MQTTREASONCODE_RECEIVE_MAXIMUM_EXCEEDED, "Receive Maximum exceeded"},
|
||||
{MQTTREASONCODE_TOPIC_ALIAS_INVALID, "Topic Alias invalid"},
|
||||
{MQTTREASONCODE_PACKET_TOO_LARGE, "Packet too large"},
|
||||
{MQTTREASONCODE_MESSAGE_RATE_TOO_HIGH, "Message rate too high"},
|
||||
{MQTTREASONCODE_QUOTA_EXCEEDED, "Quota exceeded"},
|
||||
{MQTTREASONCODE_ADMINISTRATIVE_ACTION, "Administrative action"},
|
||||
{MQTTREASONCODE_PAYLOAD_FORMAT_INVALID, "Payload format invalid"},
|
||||
{MQTTREASONCODE_RETAIN_NOT_SUPPORTED, "Retain not supported"},
|
||||
{MQTTREASONCODE_QOS_NOT_SUPPORTED, "QoS not supported"},
|
||||
{MQTTREASONCODE_USE_ANOTHER_SERVER, "Use another server"},
|
||||
{MQTTREASONCODE_SERVER_MOVED, "Server moved"},
|
||||
{MQTTREASONCODE_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED, "Shared subscriptions not supported"},
|
||||
{MQTTREASONCODE_CONNECTION_RATE_EXCEEDED, "Connection rate exceeded"},
|
||||
{MQTTREASONCODE_MAXIMUM_CONNECT_TIME, "Maximum connect time"},
|
||||
{MQTTREASONCODE_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED, "Subscription Identifiers not supported"},
|
||||
{MQTTREASONCODE_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED, "Wildcard Subscriptions not supported"}
|
||||
};
|
||||
|
||||
const char* MQTTReasonCode_toString(enum MQTTReasonCodes value)
|
||||
{
|
||||
int i = 0;
|
||||
const char* result = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nameToString); ++i)
|
||||
{
|
||||
if (nameToString[i].value == value)
|
||||
{
|
||||
result = nameToString[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
79
src/mqtt/externals/paho-mqtt-c/src/MQTTReasonCodes.h
vendored
Normal file
79
src/mqtt/externals/paho-mqtt-c/src/MQTTReasonCodes.h
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 IBM Corp. and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTREASONCODES_H)
|
||||
#define MQTTREASONCODES_H
|
||||
|
||||
#include "MQTTExportDeclarations.h"
|
||||
|
||||
/** The MQTT V5 one byte reason code */
|
||||
enum MQTTReasonCodes {
|
||||
MQTTREASONCODE_SUCCESS = 0,
|
||||
MQTTREASONCODE_NORMAL_DISCONNECTION = 0,
|
||||
MQTTREASONCODE_GRANTED_QOS_0 = 0,
|
||||
MQTTREASONCODE_GRANTED_QOS_1 = 1,
|
||||
MQTTREASONCODE_GRANTED_QOS_2 = 2,
|
||||
MQTTREASONCODE_DISCONNECT_WITH_WILL_MESSAGE = 4,
|
||||
MQTTREASONCODE_NO_MATCHING_SUBSCRIBERS = 16,
|
||||
MQTTREASONCODE_NO_SUBSCRIPTION_FOUND = 17,
|
||||
MQTTREASONCODE_CONTINUE_AUTHENTICATION = 24,
|
||||
MQTTREASONCODE_RE_AUTHENTICATE = 25,
|
||||
MQTTREASONCODE_UNSPECIFIED_ERROR = 128,
|
||||
MQTTREASONCODE_MALFORMED_PACKET = 129,
|
||||
MQTTREASONCODE_PROTOCOL_ERROR = 130,
|
||||
MQTTREASONCODE_IMPLEMENTATION_SPECIFIC_ERROR = 131,
|
||||
MQTTREASONCODE_UNSUPPORTED_PROTOCOL_VERSION = 132,
|
||||
MQTTREASONCODE_CLIENT_IDENTIFIER_NOT_VALID = 133,
|
||||
MQTTREASONCODE_BAD_USER_NAME_OR_PASSWORD = 134,
|
||||
MQTTREASONCODE_NOT_AUTHORIZED = 135,
|
||||
MQTTREASONCODE_SERVER_UNAVAILABLE = 136,
|
||||
MQTTREASONCODE_SERVER_BUSY = 137,
|
||||
MQTTREASONCODE_BANNED = 138,
|
||||
MQTTREASONCODE_SERVER_SHUTTING_DOWN = 139,
|
||||
MQTTREASONCODE_BAD_AUTHENTICATION_METHOD = 140,
|
||||
MQTTREASONCODE_KEEP_ALIVE_TIMEOUT = 141,
|
||||
MQTTREASONCODE_SESSION_TAKEN_OVER = 142,
|
||||
MQTTREASONCODE_TOPIC_FILTER_INVALID = 143,
|
||||
MQTTREASONCODE_TOPIC_NAME_INVALID = 144,
|
||||
MQTTREASONCODE_PACKET_IDENTIFIER_IN_USE = 145,
|
||||
MQTTREASONCODE_PACKET_IDENTIFIER_NOT_FOUND = 146,
|
||||
MQTTREASONCODE_RECEIVE_MAXIMUM_EXCEEDED = 147,
|
||||
MQTTREASONCODE_TOPIC_ALIAS_INVALID = 148,
|
||||
MQTTREASONCODE_PACKET_TOO_LARGE = 149,
|
||||
MQTTREASONCODE_MESSAGE_RATE_TOO_HIGH = 150,
|
||||
MQTTREASONCODE_QUOTA_EXCEEDED = 151,
|
||||
MQTTREASONCODE_ADMINISTRATIVE_ACTION = 152,
|
||||
MQTTREASONCODE_PAYLOAD_FORMAT_INVALID = 153,
|
||||
MQTTREASONCODE_RETAIN_NOT_SUPPORTED = 154,
|
||||
MQTTREASONCODE_QOS_NOT_SUPPORTED = 155,
|
||||
MQTTREASONCODE_USE_ANOTHER_SERVER = 156,
|
||||
MQTTREASONCODE_SERVER_MOVED = 157,
|
||||
MQTTREASONCODE_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 158,
|
||||
MQTTREASONCODE_CONNECTION_RATE_EXCEEDED = 159,
|
||||
MQTTREASONCODE_MAXIMUM_CONNECT_TIME = 160,
|
||||
MQTTREASONCODE_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 161,
|
||||
MQTTREASONCODE_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a printable string description of an MQTT V5 reason code.
|
||||
* @param value an MQTT V5 reason code.
|
||||
* @return the printable string description of the input reason code.
|
||||
* NULL if the code was not found.
|
||||
*/
|
||||
LIBMQTT_API const char* MQTTReasonCode_toString(enum MQTTReasonCodes value);
|
||||
|
||||
#endif
|
||||
46
src/mqtt/externals/paho-mqtt-c/src/MQTTSubscribeOpts.h
vendored
Normal file
46
src/mqtt/externals/paho-mqtt-c/src/MQTTSubscribeOpts.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(SUBOPTS_H)
|
||||
#define SUBOPTS_H
|
||||
|
||||
/** The MQTT V5 subscribe options, apart from QoS which existed before V5. */
|
||||
typedef struct MQTTSubscribe_options
|
||||
{
|
||||
/** The eyecatcher for this structure. Must be MQSO. */
|
||||
char struct_id[4];
|
||||
/** The version number of this structure. Must be 0.
|
||||
*/
|
||||
int struct_version;
|
||||
/** To not receive our own publications, set to 1.
|
||||
* 0 is the original MQTT behaviour - all messages matching the subscription are received.
|
||||
*/
|
||||
unsigned char noLocal;
|
||||
/** To keep the retain flag as on the original publish message, set to 1.
|
||||
* If 0, defaults to the original MQTT behaviour where the retain flag is only set on
|
||||
* publications sent by a broker if in response to a subscribe request.
|
||||
*/
|
||||
unsigned char retainAsPublished;
|
||||
/** 0 - send retained messages at the time of the subscribe (original MQTT behaviour)
|
||||
* 1 - send retained messages on subscribe only if the subscription is new
|
||||
* 2 - do not send retained messages at all
|
||||
*/
|
||||
unsigned char retainHandling;
|
||||
} MQTTSubscribe_options;
|
||||
|
||||
#define MQTTSubscribe_options_initializer { {'M', 'Q', 'S', 'O'}, 0, 0, 0, 0 }
|
||||
|
||||
#endif
|
||||
112
src/mqtt/externals/paho-mqtt-c/src/MQTTTime.c
vendored
Normal file
112
src/mqtt/externals/paho-mqtt-c/src/MQTTTime.c
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020, 2021 IBM Corp. and Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTTime.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
void MQTTTime_sleep(ELAPSED_TIME_TYPE milliseconds)
|
||||
{
|
||||
FUNC_ENTRY;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
Sleep((DWORD)milliseconds);
|
||||
#else
|
||||
usleep((useconds_t)(milliseconds*1000));
|
||||
#endif
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
START_TIME_TYPE MQTTTime_start_clock(void)
|
||||
{
|
||||
#if WINVER >= _WIN32_WINNT_VISTA
|
||||
return GetTickCount64();
|
||||
#else
|
||||
return GetTickCount();
|
||||
#endif
|
||||
}
|
||||
#elif defined(AIX)
|
||||
START_TIME_TYPE MQTTTime_start_clock(void)
|
||||
{
|
||||
struct timespec start;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
return start;
|
||||
}
|
||||
#else
|
||||
START_TIME_TYPE MQTTTime_start_clock(void)
|
||||
{
|
||||
struct timeval start;
|
||||
struct timespec start_ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_ts);
|
||||
start.tv_sec = start_ts.tv_sec;
|
||||
start.tv_usec = start_ts.tv_nsec / 1000;
|
||||
return start;
|
||||
}
|
||||
#endif
|
||||
START_TIME_TYPE MQTTTime_now(void)
|
||||
{
|
||||
return MQTTTime_start_clock();
|
||||
}
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/*
|
||||
* @param t_new most recent time in milliseconds from GetTickCount()
|
||||
* @param t_old older time in milliseconds from GetTickCount()
|
||||
* @return difference in milliseconds
|
||||
*/
|
||||
DIFF_TIME_TYPE MQTTTime_difftime(START_TIME_TYPE t_new, START_TIME_TYPE t_old)
|
||||
{
|
||||
#if WINVER >= _WIN32_WINNT_VISTA
|
||||
return (DIFF_TIME_TYPE)(t_new - t_old);
|
||||
#else
|
||||
if (t_old < t_new) /* check for wrap around condition in GetTickCount */
|
||||
return (DIFF_TIME_TYPE)(t_new - t_old);
|
||||
else
|
||||
return (DIFF_TIME_TYPE)((0xFFFFFFFFL - t_old) + 1 + t_new);
|
||||
#endif
|
||||
}
|
||||
#elif defined(AIX)
|
||||
#define assert(a)
|
||||
DIFF_TIME_TYPE MQTTTime_difftime(START_TIME_TYPE t_new, START_TIME_TYPE t_old)
|
||||
{
|
||||
struct timespec result;
|
||||
|
||||
ntimersub(t_new, t_old, result);
|
||||
return (DIFF_TIME_TYPE)((result.tv_sec)*1000L + (result.tv_nsec)/1000000L); /* convert to milliseconds */
|
||||
}
|
||||
#else
|
||||
DIFF_TIME_TYPE MQTTTime_difftime(START_TIME_TYPE t_new, START_TIME_TYPE t_old)
|
||||
{
|
||||
struct timeval result;
|
||||
|
||||
timersub(&t_new, &t_old, &result);
|
||||
return (DIFF_TIME_TYPE)(((DIFF_TIME_TYPE)result.tv_sec)*1000 + ((DIFF_TIME_TYPE)result.tv_usec)/1000); /* convert to milliseconds */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ELAPSED_TIME_TYPE MQTTTime_elapsed(START_TIME_TYPE milliseconds)
|
||||
{
|
||||
return (ELAPSED_TIME_TYPE)MQTTTime_difftime(MQTTTime_now(), milliseconds);
|
||||
}
|
||||
49
src/mqtt/externals/paho-mqtt-c/src/MQTTTime.h
vendored
Normal file
49
src/mqtt/externals/paho-mqtt-c/src/MQTTTime.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTTIME_H)
|
||||
#define MQTTTIME_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#if WINVER >= _WIN32_WINNT_VISTA
|
||||
#define START_TIME_TYPE ULONGLONG
|
||||
#define START_TIME_ZERO 0
|
||||
#else
|
||||
#define START_TIME_TYPE DWORD
|
||||
#define START_TIME_ZERO 0
|
||||
#endif
|
||||
#elif defined(AIX)
|
||||
#define START_TIME_TYPE struct timespec
|
||||
#define START_TIME_ZERO {0, 0}
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#define START_TIME_TYPE struct timeval
|
||||
#define START_TIME_ZERO {0, 0}
|
||||
#endif
|
||||
|
||||
#define ELAPSED_TIME_TYPE uint64_t
|
||||
#define DIFF_TIME_TYPE int64_t
|
||||
|
||||
void MQTTTime_sleep(ELAPSED_TIME_TYPE milliseconds);
|
||||
START_TIME_TYPE MQTTTime_start_clock(void);
|
||||
START_TIME_TYPE MQTTTime_now(void);
|
||||
ELAPSED_TIME_TYPE MQTTTime_elapsed(START_TIME_TYPE milliseconds);
|
||||
DIFF_TIME_TYPE MQTTTime_difftime(START_TIME_TYPE t_new, START_TIME_TYPE t_old);
|
||||
|
||||
#endif
|
||||
231
src/mqtt/externals/paho-mqtt-c/src/MQTTVersion.c
vendored
Normal file
231
src/mqtt/externals/paho-mqtt-c/src/MQTTVersion.c
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012, 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(_WRS_KERNEL)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include "MQTTAsync.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @file
|
||||
* \brief MQTTVersion - display the version and build information strings for a library.
|
||||
*
|
||||
* With no arguments, we try to load and call the version string for the libraries we
|
||||
* know about: mqttv3c, mqttv3cs, mqttv3a, mqttv3as.
|
||||
* With an argument:
|
||||
* 1) we try to load the named library, call getVersionInfo and display those values.
|
||||
* 2) If that doesn't work, we look through the binary for eyecatchers, and display those.
|
||||
* This will work if the library is not executable in the current environment.
|
||||
*
|
||||
* */
|
||||
|
||||
|
||||
static const char* libraries[] = {"paho-mqtt3c", "paho-mqtt3cs", "paho-mqtt3a", "paho-mqtt3as"};
|
||||
static const char* eyecatchers[] = {"MQTTAsyncV3_Version", "MQTTAsyncV3_Timestamp",
|
||||
"MQTTClientV3_Version", "MQTTClientV3_Timestamp"};
|
||||
|
||||
|
||||
char* FindString(char* filename, const char* eyecatcher_input);
|
||||
int printVersionInfo(MQTTAsync_nameValue* info);
|
||||
int loadandcall(const char* libname);
|
||||
void printEyecatchers(char* filename);
|
||||
|
||||
|
||||
/**
|
||||
* Finds an eyecatcher in a binary file and returns the following value.
|
||||
* @param filename the name of the file
|
||||
* @param eyecatcher_input the eyecatcher string to look for
|
||||
* @return the value found - "" if not found
|
||||
*/
|
||||
char* FindString(char* filename, const char* eyecatcher_input)
|
||||
{
|
||||
FILE* infile = NULL;
|
||||
static char value[100];
|
||||
const char* eyecatcher = eyecatcher_input;
|
||||
|
||||
memset(value, 0, 100);
|
||||
if ((infile = fopen(filename, "rb")) != NULL)
|
||||
{
|
||||
size_t buflen = strlen(eyecatcher);
|
||||
char* buffer = (char*) malloc(buflen + 1); /* added space for unused null terminator to stop LGTM complaint */
|
||||
|
||||
if (buffer != NULL)
|
||||
{
|
||||
int c = fgetc(infile);
|
||||
|
||||
while (feof(infile) == 0)
|
||||
{
|
||||
int count = 0;
|
||||
buffer[count++] = c;
|
||||
if (memcmp(eyecatcher, buffer, buflen) == 0)
|
||||
{
|
||||
char* ptr = value;
|
||||
c = fgetc(infile); /* skip space */
|
||||
c = fgetc(infile);
|
||||
while (isprint(c))
|
||||
{
|
||||
*ptr++ = c;
|
||||
c = fgetc(infile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (count == buflen)
|
||||
{
|
||||
memmove(buffer, &buffer[1], buflen - 1);
|
||||
count--;
|
||||
}
|
||||
c = fgetc(infile);
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
int printVersionInfo(MQTTAsync_nameValue* info)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
while (info->name)
|
||||
{
|
||||
printf("%s: %s\n", info->name, info->value);
|
||||
info++;
|
||||
rc = 1; /* at least one value printed */
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
typedef MQTTAsync_nameValue* (*func_type)(void);
|
||||
|
||||
int loadandcall(const char* libname)
|
||||
{
|
||||
int rc = 0;
|
||||
MQTTAsync_nameValue* (*func_address)(void) = NULL;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HMODULE APILibrary = LoadLibraryA(libname);
|
||||
if (APILibrary == NULL)
|
||||
printf("Error loading library %s, error code %d\n", libname, GetLastError());
|
||||
else
|
||||
{
|
||||
func_address = (func_type)GetProcAddress(APILibrary, "MQTTAsync_getVersionInfo");
|
||||
if (func_address == NULL)
|
||||
func_address = (func_type)GetProcAddress(APILibrary, "MQTTClient_getVersionInfo");
|
||||
if (func_address)
|
||||
rc = printVersionInfo((*func_address)());
|
||||
FreeLibrary(APILibrary);
|
||||
}
|
||||
#else
|
||||
void* APILibrary = dlopen(libname, RTLD_LAZY); /* Open the Library in question */
|
||||
if (APILibrary == NULL)
|
||||
printf("Error loading library %s, error %s\n", libname, dlerror());
|
||||
else
|
||||
{
|
||||
*(void **) (&func_address) = dlsym(APILibrary, "MQTTAsync_getVersionInfo");
|
||||
if (func_address == NULL)
|
||||
func_address = dlsym(APILibrary, "MQTTClient_getVersionInfo");
|
||||
if (func_address)
|
||||
rc = printVersionInfo((*func_address)());
|
||||
dlclose(APILibrary);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(ARRAY_SIZE)
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
void printEyecatchers(char* filename)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(eyecatchers); ++i)
|
||||
{
|
||||
char* value = FindString(filename, eyecatchers[i]);
|
||||
if (value[0])
|
||||
printf("%s: %s\n", eyecatchers[i], value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
printf("MQTTVersion: print the version strings of an MQTT client library\n");
|
||||
printf("Copyright (c) 2012, 2018 IBM Corp.\n");
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
int i = 0;
|
||||
char namebuf[60];
|
||||
|
||||
printf("Specify a particular library name if it is not in the current directory, or not executable on this platform\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(libraries); ++i)
|
||||
{
|
||||
#if defined(__CYGWIN__)
|
||||
snprintf(namebuf, sizeof(namebuf), "cyg%s-1.dll", libraries[i]);
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
snprintf(namebuf, sizeof(namebuf), "%s.dll", libraries[i]);
|
||||
#elif defined(OSX)
|
||||
snprintf(namebuf, sizeof(namebuf), "lib%s.1.dylib", libraries[i]);
|
||||
#else
|
||||
snprintf(namebuf, sizeof(namebuf), "lib%s.so.1", libraries[i]);
|
||||
#endif
|
||||
printf("--- Trying library %s ---\n", libraries[i]);
|
||||
if (!loadandcall(namebuf))
|
||||
printEyecatchers(namebuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!loadandcall(argv[1]))
|
||||
printEyecatchers(argv[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main(void)
|
||||
{
|
||||
fprintf(stderr, "This tool is not supported on this platform yet.\n");
|
||||
return 1;
|
||||
}
|
||||
#endif /* !defined(_WRS_KERNEL) */
|
||||
105
src/mqtt/externals/paho-mqtt-c/src/Messages.c
vendored
Normal file
105
src/mqtt/externals/paho-mqtt-c/src/Messages.c
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2021 IBM Corp., Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Trace messages
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "Messages.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Heap.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
#define max_msg_len 120
|
||||
|
||||
static const char *protocol_message_list[] =
|
||||
{
|
||||
"%d %s -> CONNECT version %d clean: %d (%d)", /* 0, was 131, 68 and 69 */
|
||||
"%d %s <- CONNACK rc: %d", /* 1, was 132 */
|
||||
"%d %s -> CONNACK rc: %d (%d)", /* 2, was 138 */
|
||||
"%d %s <- PINGREQ", /* 3, was 35 */
|
||||
"%d %s -> PINGRESP (%d)", /* 4 */
|
||||
"%d %s <- DISCONNECT", /* 5 */
|
||||
"%d %s <- SUBSCRIBE msgid: %d", /* 6, was 39 */
|
||||
"%d %s -> SUBACK msgid: %d (%d)", /* 7, was 40 */
|
||||
"%d %s <- UNSUBSCRIBE msgid: %d", /* 8, was 41 */
|
||||
"%d %s -> UNSUBACK msgid: %d (%d)", /* 9 */
|
||||
"%d %s -> PUBLISH msgid: %d qos: %d retained: %d rc %d payload len(%d): %.*s", /* 10, was 42 */
|
||||
"%d %s <- PUBLISH msgid: %d qos: %d retained: %d payload len(%d): %.*s", /* 11, was 46 */
|
||||
"%d %s -> PUBACK msgid: %d (%d)", /* 12, was 47 */
|
||||
"%d %s -> PUBREC msgid: %d (%d)", /* 13, was 48 */
|
||||
"%d %s <- PUBACK msgid: %d", /* 14, was 49 */
|
||||
"%d %s <- PUBREC msgid: %d", /* 15, was 53 */
|
||||
"%d %s -> PUBREL msgid: %d (%d)", /* 16, was 57 */
|
||||
"%d %s <- PUBREL msgid %d", /* 17, was 58 */
|
||||
"%d %s -> PUBCOMP msgid %d (%d)", /* 18, was 62 */
|
||||
"%d %s <- PUBCOMP msgid:%d", /* 19, was 63 */
|
||||
"%d %s -> PINGREQ (%d)", /* 20, was 137 */
|
||||
"%d %s <- PINGRESP", /* 21, was 70 */
|
||||
"%d %s -> SUBSCRIBE msgid: %d (%d)", /* 22, was 72 */
|
||||
"%d %s <- SUBACK msgid: %d", /* 23, was 73 */
|
||||
"%d %s <- UNSUBACK msgid: %d", /* 24, was 74 */
|
||||
"%d %s -> UNSUBSCRIBE msgid: %d (%d)", /* 25, was 106 */
|
||||
"%d %s <- CONNECT", /* 26 */
|
||||
"%d %s -> PUBLISH qos: 0 retained: %d rc: %d payload len(%d): %.*s", /* 27 */
|
||||
"%d %s -> DISCONNECT (%d)", /* 28 */
|
||||
"Socket error for client identifier %s, socket %d, peer address %s; ending connection", /* 29 */
|
||||
"%d %s <- DISCONNECT (%d)", /* 30 */
|
||||
};
|
||||
|
||||
static const char *trace_message_list[] =
|
||||
{
|
||||
"Failed to remove client from bstate->clients", /* 0 */
|
||||
"Removed client %s from bstate->clients, socket %d", /* 1 */
|
||||
"Packet_Factory: unhandled packet type %d", /* 2 */
|
||||
"Packet %s received from client %s for message identifier %d, but no record of that message identifier found", /* 3 */
|
||||
"Packet %s received from client %s for message identifier %d, but message is wrong QoS, %d", /* 4 */
|
||||
"Packet %s received from client %s for message identifier %d, but message is in wrong state", /* 5 */
|
||||
"%s received from client %s for message id %d - removing publication", /* 6 */
|
||||
"Trying %s again for client %s, socket %d, message identifier %d", /* 7 */
|
||||
"", /* 8 */
|
||||
"(%lu) %*s(%d)> %s:%d", /* 9 */
|
||||
"(%lu) %*s(%d)< %s:%d", /* 10 */
|
||||
"(%lu) %*s(%d)< %s:%d (%d)", /* 11 */
|
||||
"Storing unsent QoS 0 message", /* 12 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a log message by its index
|
||||
* @param index the integer index
|
||||
* @param log_level the log level, used to determine which message list to use
|
||||
* @return the message format string
|
||||
*/
|
||||
const char* Messages_get(int index, enum LOG_LEVELS log_level)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
|
||||
if (log_level == TRACE_PROTOCOL)
|
||||
msg = (index >= 0 && index < ARRAY_SIZE(protocol_message_list)) ? protocol_message_list[index] : NULL;
|
||||
else
|
||||
msg = (index >= 0 && index < ARRAY_SIZE(trace_message_list)) ? trace_message_list[index] : NULL;
|
||||
return msg;
|
||||
}
|
||||
|
||||
24
src/mqtt/externals/paho-mqtt-c/src/Messages.h
vendored
Normal file
24
src/mqtt/externals/paho-mqtt-c/src/Messages.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2013 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MESSAGES_H)
|
||||
#define MESSAGES_H
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
const char* Messages_get(int, enum LOG_LEVELS);
|
||||
|
||||
#endif
|
||||
28
src/mqtt/externals/paho-mqtt-c/src/OsWrapper.c
vendored
Normal file
28
src/mqtt/externals/paho-mqtt-c/src/OsWrapper.c
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 logi.cals GmbH
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Gunter Raidl - timer support for VxWorks
|
||||
* Rainer Poisel - reusability
|
||||
*******************************************************************************/
|
||||
|
||||
#include "OsWrapper.h"
|
||||
|
||||
#if defined(_WRS_KERNEL)
|
||||
void usleep(useconds_t useconds)
|
||||
{
|
||||
struct timespec tv;
|
||||
tv.tv_sec = useconds / 1000000;
|
||||
tv.tv_nsec = (useconds % 1000000) * 1000;
|
||||
nanosleep(&tv, NULL);
|
||||
}
|
||||
#endif /* defined(_WRS_KERNEL) */
|
||||
42
src/mqtt/externals/paho-mqtt-c/src/OsWrapper.h
vendored
Normal file
42
src/mqtt/externals/paho-mqtt-c/src/OsWrapper.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 logi.cals GmbH
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Gunter Raidl - timer support for VxWorks
|
||||
* Rainer Poisel - reusability
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(OSWRAPPER_H)
|
||||
#define OSWRAPPER_H
|
||||
|
||||
#if defined(_WRS_KERNEL)
|
||||
#include <time.h>
|
||||
|
||||
#define lstat stat
|
||||
|
||||
typedef unsigned long useconds_t;
|
||||
void usleep(useconds_t useconds);
|
||||
|
||||
#define timersub(a, b, result) \
|
||||
do \
|
||||
{ \
|
||||
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
||||
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
|
||||
if ((result)->tv_usec < 0) \
|
||||
{ \
|
||||
--(result)->tv_sec; \
|
||||
(result)->tv_usec += 1000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* defined(_WRS_KERNEL) */
|
||||
|
||||
#endif /* OSWRAPPER_H */
|
||||
154
src/mqtt/externals/paho-mqtt-c/src/Proxy.c
vendored
Normal file
154
src/mqtt/externals/paho-mqtt-c/src/Proxy.c
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2021 Diehl Metering.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Keith Holman - initial implementation and documentation
|
||||
* Sven Gambel - move WebSocket proxy support to generic proxy support
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
// for timeout process in Proxy_connect()
|
||||
#include <time.h>
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "Log.h"
|
||||
#include "MQTTProtocolOut.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Heap.h"
|
||||
|
||||
#if defined(OPENSSL)
|
||||
#include "SSLSocket.h"
|
||||
#include <openssl/rand.h>
|
||||
#endif /* defined(OPENSSL) */
|
||||
#include "Socket.h"
|
||||
|
||||
/**
|
||||
* Notify the IP address and port of the endpoint to proxy, and wait connection to endpoint.
|
||||
*
|
||||
* @param[in] net network connection to proxy.
|
||||
* @param[in] ssl enable ssl.
|
||||
* @param[in] hostname hostname of endpoint.
|
||||
*
|
||||
* @retval SOCKET_ERROR failed to network connection
|
||||
* @retval 0 connection to endpoint
|
||||
*
|
||||
*/
|
||||
int Proxy_connect(networkHandles *net, int ssl, const char *hostname)
|
||||
{
|
||||
int port, i, rc = 0, buf_len=0;
|
||||
char *buf = NULL;
|
||||
size_t hostname_len, actual_len = 0;
|
||||
time_t current, timeout;
|
||||
PacketBuffers nulbufs = {0, NULL, NULL, NULL, {0, 0, 0, 0}};
|
||||
|
||||
FUNC_ENTRY;
|
||||
hostname_len = MQTTProtocol_addressPort(hostname, &port, NULL, PROXY_DEFAULT_PORT);
|
||||
for ( i = 0; i < 2; ++i ) {
|
||||
#if defined(OPENSSL)
|
||||
if(ssl) {
|
||||
if (net->https_proxy_auth) {
|
||||
buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"Proxy-authorization: Basic %s\r\n"
|
||||
"\r\n",
|
||||
(int)hostname_len, hostname, port,
|
||||
(int)hostname_len, hostname, net->https_proxy_auth);
|
||||
}
|
||||
else {
|
||||
buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"\r\n",
|
||||
(int)hostname_len, hostname, port,
|
||||
(int)hostname_len, hostname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
if (net->http_proxy_auth) {
|
||||
buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"Proxy-authorization: Basic %s\r\n"
|
||||
"\r\n",
|
||||
(int)hostname_len, hostname, port,
|
||||
(int)hostname_len, hostname, net->http_proxy_auth);
|
||||
}
|
||||
else {
|
||||
buf_len = snprintf( buf, (size_t)buf_len, "CONNECT %.*s:%d HTTP/1.1\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"\r\n",
|
||||
(int)hostname_len, hostname, port,
|
||||
(int)hostname_len, hostname);
|
||||
}
|
||||
#if defined(OPENSSL)
|
||||
}
|
||||
#endif
|
||||
if ( i==0 && buf_len > 0 ) {
|
||||
++buf_len;
|
||||
if ((buf = malloc( buf_len )) == NULL)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Log(TRACE_PROTOCOL, -1, "Proxy_connect: \"%s\"", buf);
|
||||
|
||||
Socket_putdatas(net->socket, buf, buf_len, nulbufs);
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
time(&timeout);
|
||||
timeout += (time_t)10;
|
||||
|
||||
while(1) {
|
||||
buf = Socket_getdata(net->socket, (size_t)12, &actual_len, &rc);
|
||||
if(actual_len) {
|
||||
if ( (strncmp( buf, "HTTP/1.0 200", 12 ) != 0) && (strncmp( buf, "HTTP/1.1 200", 12 ) != 0) )
|
||||
rc = SOCKET_ERROR;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
time(¤t);
|
||||
if(current > timeout) {
|
||||
rc = SOCKET_ERROR;
|
||||
break;
|
||||
}
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
Sleep(250);
|
||||
#else
|
||||
usleep(250000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* flush the SocketBuffer */
|
||||
actual_len = 1;
|
||||
while (actual_len)
|
||||
{
|
||||
int rc1;
|
||||
|
||||
buf = Socket_getdata(net->socket, (size_t)1, &actual_len, &rc1);
|
||||
}
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
25
src/mqtt/externals/paho-mqtt-c/src/Proxy.h
vendored
Normal file
25
src/mqtt/externals/paho-mqtt-c/src/Proxy.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2021 Diehl Metering.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Sven Gambel - move WebSocket proxy support to generic proxy support
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(PROXY_H)
|
||||
#define PROXY_H
|
||||
|
||||
#include "Clients.h"
|
||||
|
||||
/* Notify the IP address and port of the endpoint to proxy, and wait connection to endpoint */
|
||||
int Proxy_connect(networkHandles *net, int ssl, const char *hostname );
|
||||
|
||||
#endif /* PROXY_H */
|
||||
249
src/mqtt/externals/paho-mqtt-c/src/SHA1.c
vendored
Normal file
249
src/mqtt/externals/paho-mqtt-c/src/SHA1.c
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Keith Holman - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "SHA1.h"
|
||||
|
||||
#if !defined(OPENSSL)
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
|
||||
int SHA1_Init_mqtt(SHA_CTX *c)
|
||||
{
|
||||
if (!CryptAcquireContext(&c->hProv, NULL, NULL,
|
||||
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
||||
return 0;
|
||||
if (!CryptCreateHash(c->hProv, CALG_SHA1, 0, 0, &c->hHash))
|
||||
{
|
||||
CryptReleaseContext(c->hProv, 0);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SHA1_Update_mqtt(SHA_CTX *c, const void *data, size_t len)
|
||||
{
|
||||
int rv = 1;
|
||||
if (!CryptHashData(c->hHash, data, (DWORD)len, 0))
|
||||
rv = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
int SHA1_Final_mqtt(unsigned char *md, SHA_CTX *c)
|
||||
{
|
||||
int rv = 0;
|
||||
DWORD md_len = SHA1_DIGEST_LENGTH;
|
||||
if (CryptGetHashParam(c->hHash, HP_HASHVAL, md, &md_len, 0))
|
||||
rv = 1;
|
||||
CryptDestroyHash(c->hHash);
|
||||
CryptReleaseContext(c->hProv, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#else /* if defined(_WIN32) || defined(_WIN64) */
|
||||
#if defined(__linux__) || defined(__CYGWIN__)
|
||||
# include <endian.h>
|
||||
#elif defined(__APPLE__)
|
||||
# include <libkern/OSByteOrder.h>
|
||||
# define htobe32(x) OSSwapHostToBigInt32(x)
|
||||
# define be32toh(x) OSSwapBigToHostInt32(x)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
static unsigned char pad[64] = {
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
int SHA1_Init(SHA_CTX *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
if ( ctx )
|
||||
{
|
||||
ctx->h[0] = 0x67452301;
|
||||
ctx->h[1] = 0xEFCDAB89;
|
||||
ctx->h[2] = 0x98BADCFE;
|
||||
ctx->h[3] = 0x10325476;
|
||||
ctx->h[4] = 0xC3D2E1F0;
|
||||
ctx->size = 0u;
|
||||
ctx->total = 0u;
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT32(a, n) (((a) << (n)) | ((a) >> (32 - (n))))
|
||||
static void SHA1_ProcessBlock(SHA_CTX *ctx)
|
||||
{
|
||||
uint32_t blks[5];
|
||||
uint32_t *w;
|
||||
int i;
|
||||
|
||||
/* initialize */
|
||||
for ( i = 0; i < 5; ++i )
|
||||
blks[i] = ctx->h[i];
|
||||
|
||||
w = ctx->w;
|
||||
|
||||
/* perform SHA-1 hash */
|
||||
for ( i = 0; i < 16; ++i )
|
||||
w[i] = be32toh(w[i]);
|
||||
|
||||
for( i = 0; i < 80; ++i )
|
||||
{
|
||||
int tmp;
|
||||
if ( i >= 16 )
|
||||
w[i & 0x0F] = ROTATE_LEFT32( w[(i+13) & 0x0F] ^ w[(i+8) & 0x0F] ^ w[(i+2) & 0x0F] ^ w[i & 0x0F], 1 );
|
||||
|
||||
if ( i < 20 )
|
||||
tmp = ROTATE_LEFT32(blks[0], 5) + ((blks[1] & blks[2]) | (~(blks[1]) & blks[3])) + blks[4] + w[i & 0x0F] + 0x5A827999;
|
||||
else if ( i < 40 )
|
||||
tmp = ROTATE_LEFT32(blks[0], 5) + (blks[1]^blks[2]^blks[3]) + blks[4] + w[i & 0x0F] + 0x6ED9EBA1;
|
||||
else if ( i < 60 )
|
||||
tmp = ROTATE_LEFT32(blks[0], 5) + ((blks[1] & blks[2]) | (blks[1] & blks[3]) | (blks[2] & blks[3])) + blks[4] + w[i & 0x0F] + 0x8F1BBCDC;
|
||||
else
|
||||
tmp = ROTATE_LEFT32(blks[0], 5) + (blks[1]^blks[2]^blks[3]) + blks[4] + w[i & 0x0F] + 0xCA62C1D6;
|
||||
|
||||
/* update registers */
|
||||
blks[4] = blks[3];
|
||||
blks[3] = blks[2];
|
||||
blks[2] = ROTATE_LEFT32(blks[1], 30);
|
||||
blks[1] = blks[0];
|
||||
blks[0] = tmp;
|
||||
}
|
||||
|
||||
/* update of hash */
|
||||
for ( i = 0; i < 5; ++i )
|
||||
ctx->h[i] += blks[i];
|
||||
}
|
||||
|
||||
int SHA1_Final(unsigned char *md, SHA_CTX *ctx)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
size_t pad_amount;
|
||||
uint64_t total;
|
||||
|
||||
/* length before pad */
|
||||
total = ctx->total * 8;
|
||||
|
||||
if ( ctx->size < 56 )
|
||||
pad_amount = 56 - ctx->size;
|
||||
else
|
||||
pad_amount = 64 + 56 - ctx->size;
|
||||
|
||||
SHA1_Update_mqtt(ctx, pad, pad_amount);
|
||||
|
||||
ctx->w[14] = htobe32((uint32_t)(total >> 32));
|
||||
ctx->w[15] = htobe32((uint32_t)total);
|
||||
|
||||
SHA1_ProcessBlock(ctx);
|
||||
|
||||
for ( i = 0; i < 5; ++i )
|
||||
ctx->h[i] = htobe32(ctx->h[i]);
|
||||
|
||||
if ( md )
|
||||
{
|
||||
memcpy( md, &ctx->h[0], SHA1_DIGEST_LENGTH );
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SHA1_Update(SHA_CTX *ctx, const void *data, size_t len)
|
||||
{
|
||||
while ( len > 0 )
|
||||
{
|
||||
unsigned int n = 64 - ctx->size;
|
||||
if ( len < n )
|
||||
n = len;
|
||||
|
||||
memcpy(ctx->buffer + ctx->size, data, n);
|
||||
|
||||
ctx->size += n;
|
||||
ctx->total += n;
|
||||
|
||||
data = (uint8_t *)data + n;
|
||||
len -= n;
|
||||
|
||||
if ( ctx->size == 64 )
|
||||
{
|
||||
SHA1_ProcessBlock(ctx);
|
||||
ctx->size = 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* else if defined(_WIN32) || defined(_WIN64) */
|
||||
#endif /* elif !defined(OPENSSL) */
|
||||
|
||||
#if defined(SHA1_TEST)
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TEST_EXPECT(i,x) if (!(x)) {fprintf( stderr, "failed test: %s (for i == %d)\n", #x, i ); ++fails;}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct _td
|
||||
{
|
||||
const char *in;
|
||||
const char *out;
|
||||
};
|
||||
|
||||
int i;
|
||||
unsigned int fails = 0u;
|
||||
struct _td test_data[] = {
|
||||
{ "", "da39a3ee5e6b4b0d3255bfef95601890afd80709" },
|
||||
{ "this string", "fda4e74bc7489a18b146abdf23346d166663dab8" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* only 1 update */
|
||||
i = 0;
|
||||
while ( test_data[i].in != NULL )
|
||||
{
|
||||
int r[3] = { 1, 1, 1 };
|
||||
unsigned char sha_out[SHA1_DIGEST_LENGTH];
|
||||
char out[SHA1_DIGEST_LENGTH * 2 + 1];
|
||||
SHA_CTX c;
|
||||
int j;
|
||||
r[0] = SHA1_Init_mqtt( &c );
|
||||
r[1] = SHA1_Update_mqtt( &c, test_data[i].in, strlen(test_data[i].in));
|
||||
r[2] = SHA1_Final_mqtt( sha_out, &c );
|
||||
for ( j = 0u; j < SHA1_DIGEST_LENGTH; ++j )
|
||||
snprintf( &out[j*2], 3u, "%02x", sha_out[j] );
|
||||
out[SHA1_DIGEST_LENGTH * 2] = '\0';
|
||||
TEST_EXPECT( i, r[0] == 1 && r[1] == 1 && r[2] == 1 && strncmp(out, test_data[i].out, strlen(test_data[i].out)) == 0 );
|
||||
++i;
|
||||
}
|
||||
|
||||
if ( fails )
|
||||
printf( "%u test failed!\n", fails );
|
||||
else
|
||||
printf( "all tests passed\n" );
|
||||
return fails;
|
||||
}
|
||||
#endif /* if defined(SHA1_TEST) */
|
||||
|
||||
91
src/mqtt/externals/paho-mqtt-c/src/SHA1.h
vendored
Normal file
91
src/mqtt/externals/paho-mqtt-c/src/SHA1.h
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2019 Wind River Systems, Inc. All Rights Reserved.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Keith Holman - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(SHA1_H)
|
||||
#define SHA1_H
|
||||
|
||||
#if defined(OPENSSL)
|
||||
#include <openssl/sha.h>
|
||||
|
||||
/** SHA-1 Digest Length */
|
||||
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
|
||||
|
||||
#else /* if defined(OPENSSL) */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
typedef struct SHA_CTX_S
|
||||
{
|
||||
HCRYPTPROV hProv;
|
||||
HCRYPTHASH hHash;
|
||||
} SHA_CTX;
|
||||
#else /* if defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
#include <stdint.h>
|
||||
typedef struct SHA_CTX_S {
|
||||
uint32_t h[5];
|
||||
union {
|
||||
uint32_t w[16];
|
||||
uint8_t buffer[64];
|
||||
};
|
||||
unsigned int size;
|
||||
unsigned int total;
|
||||
} SHA_CTX;
|
||||
#endif /* else if defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/** SHA-1 Digest Length (number of bytes in SHA1) */
|
||||
#define SHA1_DIGEST_LENGTH (160/8)
|
||||
|
||||
/**
|
||||
* Initializes the SHA1 hashing algorithm
|
||||
*
|
||||
* @param[in,out] ctx hashing context structure
|
||||
*
|
||||
* @see SHA1_Update_mqtt
|
||||
* @see SHA1_Final
|
||||
*/
|
||||
int SHA1_Init_mqtt(SHA_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Updates a block to the SHA1 hash
|
||||
*
|
||||
* @param[in,out] ctx hashing context structure
|
||||
* @param[in] data block of data to hash
|
||||
* @param[in] len length of block to hash
|
||||
*
|
||||
* @see SHA1_Init_mqtt
|
||||
* @see SHA1_Final
|
||||
*/
|
||||
int SHA1_Update_mqtt(SHA_CTX *ctx, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* Produce final SHA1 hash
|
||||
*
|
||||
* @param[out] md SHA1 hash produced (must be atleast
|
||||
* @p SHA1_DIGEST_LENGTH in length)
|
||||
* @param[in,out] ctx hashing context structure
|
||||
*
|
||||
* @see SHA1_Init_mqtt
|
||||
* @see SHA1_Final
|
||||
*/
|
||||
int SHA1_Final_mqtt(unsigned char *md, SHA_CTX *ctx);
|
||||
|
||||
#endif /* if defined(OPENSSL) */
|
||||
#endif /* SHA1_H */
|
||||
|
||||
1118
src/mqtt/externals/paho-mqtt-c/src/SSLSocket.c
vendored
Normal file
1118
src/mqtt/externals/paho-mqtt-c/src/SSLSocket.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
54
src/mqtt/externals/paho-mqtt-c/src/SSLSocket.h
vendored
Normal file
54
src/mqtt/externals/paho-mqtt-c/src/SSLSocket.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp., Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs, Allan Stockdill-Mander - initial implementation
|
||||
* Ian Craggs - SNI support
|
||||
* Ian Craggs - post connect checks and CApath
|
||||
*******************************************************************************/
|
||||
#if !defined(SSLSOCKET_H)
|
||||
#define SSLSOCKET_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define ssl_mutex_type HANDLE
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#define ssl_mutex_type pthread_mutex_t
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include "SocketBuffer.h"
|
||||
#include "Clients.h"
|
||||
|
||||
#define URI_SSL "ssl://"
|
||||
#define URI_MQTTS "mqtts://"
|
||||
|
||||
/** if we should handle openssl initialization (bool_value == 1) or depend on it to be initalized externally (bool_value == 0) */
|
||||
void SSLSocket_handleOpensslInit(int bool_value);
|
||||
|
||||
int SSLSocket_initialize(void);
|
||||
void SSLSocket_terminate(void);
|
||||
int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, const char* hostname, size_t hostname_len);
|
||||
|
||||
int SSLSocket_getch(SSL* ssl, SOCKET socket, char* c);
|
||||
char *SSLSocket_getdata(SSL* ssl, SOCKET socket, size_t bytes, size_t* actual_len, int* rc);
|
||||
|
||||
int SSLSocket_close(networkHandles* net);
|
||||
int SSLSocket_putdatas(SSL* ssl, SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs);
|
||||
int SSLSocket_connect(SSL* ssl, SOCKET sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u);
|
||||
|
||||
SOCKET SSLSocket_getPendingRead(void);
|
||||
int SSLSocket_continueWrite(pending_writes* pw);
|
||||
int SSLSocket_abortWrite(pending_writes* pw);
|
||||
|
||||
#endif
|
||||
1526
src/mqtt/externals/paho-mqtt-c/src/Socket.c
vendored
Normal file
1526
src/mqtt/externals/paho-mqtt-c/src/Socket.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
168
src/mqtt/externals/paho-mqtt-c/src/Socket.h
vendored
Normal file
168
src/mqtt/externals/paho-mqtt-c/src/Socket.h
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation and documentation
|
||||
* Ian Craggs - async client updates
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(SOCKET_H)
|
||||
#define SOCKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <errno.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define MAXHOSTNAMELEN 256
|
||||
#define poll WSAPoll
|
||||
#if !defined(SSLSOCKET_H)
|
||||
#undef EAGAIN
|
||||
#define EAGAIN WSAEWOULDBLOCK
|
||||
#undef EINTR
|
||||
#define EINTR WSAEINTR
|
||||
#undef EINPROGRESS
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#undef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#undef ENOTCONN
|
||||
#define ENOTCONN WSAENOTCONN
|
||||
#undef ECONNRESET
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#undef ETIMEDOUT
|
||||
#define ETIMEDOUT WAIT_TIMEOUT
|
||||
#endif
|
||||
#define ioctl ioctlsocket
|
||||
#define socklen_t int
|
||||
#else
|
||||
#define INVALID_SOCKET SOCKET_ERROR
|
||||
#include <sys/socket.h>
|
||||
#if !defined(_WRS_KERNEL)
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <poll.h>
|
||||
#include <sys/uio.h>
|
||||
#else
|
||||
#include <selectLib.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#define ULONG size_t
|
||||
#define SOCKET int
|
||||
#endif
|
||||
|
||||
#include "mutex_type.h" /* Needed for mutex_type */
|
||||
|
||||
/** socket operation completed successfully */
|
||||
#define TCPSOCKET_COMPLETE 0
|
||||
#if !defined(SOCKET_ERROR)
|
||||
/** error in socket operation */
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
/** must be the same as SOCKETBUFFER_INTERRUPTED */
|
||||
#define TCPSOCKET_INTERRUPTED -22
|
||||
#define SSL_FATAL -3
|
||||
|
||||
#if !defined(INET6_ADDRSTRLEN)
|
||||
#define INET6_ADDRSTRLEN 46 /** only needed for gcc/cygwin on windows */
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(max)
|
||||
#define max(A,B) ( (A) > (B) ? (A):(B))
|
||||
#endif
|
||||
|
||||
#include "LinkedList.h"
|
||||
|
||||
/*
|
||||
* Network write buffers for an MQTT packet
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int count; /**> number of buffers/buflens/frees */
|
||||
char** buffers; /**> array of byte buffers */
|
||||
size_t* buflens; /**> array of lengths of buffers */
|
||||
int* frees; /**> array of flags indicating whether each buffer needs to be freed */
|
||||
uint8_t mask[4]; /**> websocket mask used to mask the buffer data, if any */
|
||||
} PacketBuffers;
|
||||
|
||||
|
||||
/**
|
||||
* Structure to hold all socket data for the module
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
List* connect_pending; /**< list of sockets for which a connect is pending */
|
||||
List* write_pending; /**< list of sockets for which a write is pending */
|
||||
|
||||
#if defined(USE_SELECT)
|
||||
fd_set rset, /**< socket read set (see select doc) */
|
||||
rset_saved; /**< saved socket read set */
|
||||
int maxfdp1; /**< max descriptor used +1 (again see select doc) */
|
||||
List* clientsds; /**< list of client socket descriptors */
|
||||
ListElement* cur_clientsds; /**< current client socket descriptor (iterator) */
|
||||
fd_set pending_wset; /**< socket pending write set for select */
|
||||
#else
|
||||
unsigned int nfds; /**< no of file descriptors for poll */
|
||||
struct pollfd* fds_read; /**< poll read file descriptors */
|
||||
struct pollfd* fds_write;
|
||||
|
||||
struct {
|
||||
int cur_fd; /**< index into the fds_saved array */
|
||||
unsigned int nfds; /**< number of fds in the fds_saved array */
|
||||
struct pollfd* fds_write;
|
||||
struct pollfd* fds_read;
|
||||
} saved;
|
||||
#endif
|
||||
} Sockets;
|
||||
|
||||
|
||||
void Socket_outInitialize(void);
|
||||
void Socket_outTerminate(void);
|
||||
SOCKET Socket_getReadySocket(int more_work, int timeout, mutex_type mutex, int* rc);
|
||||
int Socket_getch(SOCKET socket, char* c);
|
||||
char *Socket_getdata(SOCKET socket, size_t bytes, size_t* actual_len, int* rc);
|
||||
int Socket_putdatas(SOCKET socket, char* buf0, size_t buf0len, PacketBuffers bufs);
|
||||
int Socket_close(SOCKET socket);
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
/* able to use GNU's getaddrinfo_a to make timeouts possible */
|
||||
int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* socket, long timeout);
|
||||
#else
|
||||
int Socket_new(const char* addr, size_t addr_len, int port, SOCKET* socket);
|
||||
#endif
|
||||
|
||||
int Socket_noPendingWrites(SOCKET socket);
|
||||
char* Socket_getpeer(SOCKET sock);
|
||||
|
||||
void Socket_addPendingWrite(SOCKET socket);
|
||||
void Socket_clearPendingWrite(SOCKET socket);
|
||||
|
||||
typedef void Socket_writeContinue(SOCKET socket);
|
||||
void Socket_setWriteContinueCallback(Socket_writeContinue*);
|
||||
|
||||
typedef void Socket_writeComplete(SOCKET socket, int rc);
|
||||
void Socket_setWriteCompleteCallback(Socket_writeComplete*);
|
||||
|
||||
typedef void Socket_writeAvailable(SOCKET socket);
|
||||
void Socket_setWriteAvailableCallback(Socket_writeAvailable*);
|
||||
|
||||
#endif /* SOCKET_H */
|
||||
448
src/mqtt/externals/paho-mqtt-c/src/SocketBuffer.c
vendored
Normal file
448
src/mqtt/externals/paho-mqtt-c/src/SocketBuffer.c
vendored
Normal file
@@ -0,0 +1,448 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - fix for issue #244, issue #20
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Socket buffering related functions
|
||||
*
|
||||
* Some other related functions are in the Socket module
|
||||
*/
|
||||
#include "SocketBuffer.h"
|
||||
#include "LinkedList.h"
|
||||
#include "Log.h"
|
||||
#include "Messages.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Heap.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define iov_len len
|
||||
#define iov_base buf
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Default input queue buffer
|
||||
*/
|
||||
static socket_queue* def_queue;
|
||||
|
||||
/**
|
||||
* List of queued input buffers
|
||||
*/
|
||||
static List* queues;
|
||||
|
||||
/**
|
||||
* List of queued write buffers
|
||||
*/
|
||||
static List writes;
|
||||
|
||||
|
||||
int socketcompare(void* a, void* b);
|
||||
int SocketBuffer_newDefQ(void);
|
||||
void SocketBuffer_freeDefQ(void);
|
||||
int pending_socketcompare(void* a, void* b);
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing socket_queues by socket
|
||||
* @param a first integer value
|
||||
* @param b second integer value
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
int socketcompare(void* a, void* b)
|
||||
{
|
||||
return ((socket_queue*)a)->socket == *(int*)b;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new default queue when one has just been used.
|
||||
*/
|
||||
int SocketBuffer_newDefQ(void)
|
||||
{
|
||||
int rc = PAHO_MEMORY_ERROR;
|
||||
|
||||
def_queue = malloc(sizeof(socket_queue));
|
||||
if (def_queue)
|
||||
{
|
||||
def_queue->buflen = 1000;
|
||||
def_queue->buf = malloc(def_queue->buflen);
|
||||
if (def_queue->buf)
|
||||
{
|
||||
def_queue->socket = def_queue->index = 0;
|
||||
def_queue->buflen = def_queue->datalen = def_queue->headerlen = 0;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the socketBuffer module
|
||||
*/
|
||||
int SocketBuffer_initialize(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
rc = SocketBuffer_newDefQ();
|
||||
if (rc == 0)
|
||||
{
|
||||
if ((queues = ListInitialize()) == NULL)
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
}
|
||||
ListZero(&writes);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the default queue memory
|
||||
*/
|
||||
void SocketBuffer_freeDefQ(void)
|
||||
{
|
||||
free(def_queue->buf);
|
||||
free(def_queue);
|
||||
def_queue = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Terminate the socketBuffer module
|
||||
*/
|
||||
void SocketBuffer_terminate(void)
|
||||
{
|
||||
ListElement* cur = NULL;
|
||||
ListEmpty(&writes);
|
||||
|
||||
FUNC_ENTRY;
|
||||
while (ListNextElement(queues, &cur))
|
||||
free(((socket_queue*)(cur->content))->buf);
|
||||
ListFree(queues);
|
||||
SocketBuffer_freeDefQ();
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup any buffers for a specific socket
|
||||
* @param socket the socket to clean up
|
||||
*/
|
||||
void SocketBuffer_cleanup(SOCKET socket)
|
||||
{
|
||||
FUNC_ENTRY;
|
||||
SocketBuffer_writeComplete(socket); /* clean up write buffers */
|
||||
if (ListFindItem(queues, &socket, socketcompare))
|
||||
{
|
||||
free(((socket_queue*)(queues->current->content))->buf);
|
||||
ListRemove(queues, queues->current->content);
|
||||
}
|
||||
if (def_queue->socket == socket)
|
||||
{
|
||||
def_queue->socket = def_queue->index = 0;
|
||||
def_queue->headerlen = def_queue->datalen = 0;
|
||||
}
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get any queued data for a specific socket
|
||||
* @param socket the socket to get queued data for
|
||||
* @param bytes the number of bytes of data to retrieve
|
||||
* @param actual_len the actual length returned
|
||||
* @return the actual data
|
||||
*/
|
||||
char* SocketBuffer_getQueuedData(SOCKET socket, size_t bytes, size_t* actual_len)
|
||||
{
|
||||
socket_queue* queue = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (ListFindItem(queues, &socket, socketcompare))
|
||||
{ /* if there is queued data for this socket, add any data read to it */
|
||||
queue = (socket_queue*)(queues->current->content);
|
||||
*actual_len = queue->datalen;
|
||||
}
|
||||
else
|
||||
{
|
||||
*actual_len = 0;
|
||||
queue = def_queue;
|
||||
}
|
||||
if (bytes > queue->buflen)
|
||||
{
|
||||
if (queue->datalen > 0)
|
||||
{
|
||||
void* newmem = malloc(bytes);
|
||||
if (newmem)
|
||||
{
|
||||
memcpy(newmem, queue->buf, queue->datalen);
|
||||
free(queue->buf);
|
||||
queue->buf = newmem;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(queue->buf);
|
||||
queue->buf = NULL;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
queue->buf = realloc(queue->buf, bytes);
|
||||
queue->buflen = bytes;
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT;
|
||||
return queue->buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get any queued character for a specific socket
|
||||
* @param socket the socket to get queued data for
|
||||
* @param c the character returned if any
|
||||
* @return completion code
|
||||
*/
|
||||
int SocketBuffer_getQueuedChar(SOCKET socket, char* c)
|
||||
{
|
||||
int rc = SOCKETBUFFER_INTERRUPTED;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (ListFindItem(queues, &socket, socketcompare))
|
||||
{ /* if there is queued data for this socket, read that first */
|
||||
socket_queue* queue = (socket_queue*)(queues->current->content);
|
||||
if (queue->index < queue->headerlen)
|
||||
{
|
||||
*c = queue->fixed_header[(queue->index)++];
|
||||
Log(TRACE_MAX, -1, "index is now %d, headerlen %d", queue->index, (int)queue->headerlen);
|
||||
rc = SOCKETBUFFER_COMPLETE;
|
||||
goto exit;
|
||||
}
|
||||
else if (queue->index > 4)
|
||||
{
|
||||
Log(LOG_FATAL, -1, "header is already at full length");
|
||||
rc = SOCKET_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc; /* there was no queued char if rc is SOCKETBUFFER_INTERRUPTED*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A socket read was interrupted so we need to queue data
|
||||
* @param socket the socket to get queued data for
|
||||
* @param actual_len the actual length of data that was read
|
||||
*/
|
||||
void SocketBuffer_interrupted(SOCKET socket, size_t actual_len)
|
||||
{
|
||||
socket_queue* queue = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (ListFindItem(queues, &socket, socketcompare))
|
||||
queue = (socket_queue*)(queues->current->content);
|
||||
else /* new saved queue */
|
||||
{
|
||||
queue = def_queue;
|
||||
/* if SocketBuffer_queueChar() has not yet been called, then the socket number
|
||||
in def_queue will not have been set. Issue #244.
|
||||
If actual_len == 0 then we may not need to do anything - I'll leave that
|
||||
optimization for another time. */
|
||||
queue->socket = socket;
|
||||
ListAppend(queues, def_queue, sizeof(socket_queue)+def_queue->buflen);
|
||||
SocketBuffer_newDefQ();
|
||||
}
|
||||
queue->index = 0;
|
||||
queue->datalen = actual_len;
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A socket read has now completed so we can get rid of the queue
|
||||
* @param socket the socket for which the operation is now complete
|
||||
* @return pointer to the default queue data
|
||||
*/
|
||||
char* SocketBuffer_complete(SOCKET socket)
|
||||
{
|
||||
FUNC_ENTRY;
|
||||
if (ListFindItem(queues, &socket, socketcompare))
|
||||
{
|
||||
socket_queue* queue = (socket_queue*)(queues->current->content);
|
||||
SocketBuffer_freeDefQ();
|
||||
def_queue = queue;
|
||||
ListDetach(queues, queue);
|
||||
}
|
||||
def_queue->socket = def_queue->index = 0;
|
||||
def_queue->headerlen = def_queue->datalen = 0;
|
||||
FUNC_EXIT;
|
||||
return def_queue->buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queued a Charactor to a specific socket
|
||||
* @param socket the socket for which to queue char for
|
||||
* @param c the character to queue
|
||||
*/
|
||||
void SocketBuffer_queueChar(SOCKET socket, char c)
|
||||
{
|
||||
int error = 0;
|
||||
socket_queue* curq = def_queue;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (ListFindItem(queues, &socket, socketcompare))
|
||||
curq = (socket_queue*)(queues->current->content);
|
||||
else if (def_queue->socket == 0)
|
||||
{
|
||||
def_queue->socket = socket;
|
||||
def_queue->index = 0;
|
||||
def_queue->datalen = 0;
|
||||
}
|
||||
else if (def_queue->socket != socket)
|
||||
{
|
||||
Log(LOG_FATAL, -1, "attempt to reuse socket queue");
|
||||
error = 1;
|
||||
}
|
||||
if (curq->index > 4)
|
||||
{
|
||||
Log(LOG_FATAL, -1, "socket queue fixed_header field full");
|
||||
error = 1;
|
||||
}
|
||||
if (!error)
|
||||
{
|
||||
curq->fixed_header[(curq->index)++] = c;
|
||||
curq->headerlen = curq->index;
|
||||
}
|
||||
Log(TRACE_MAX, -1, "queueChar: index is now %d, headerlen %d", curq->index, (int)curq->headerlen);
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A socket write was interrupted so store the remaining data
|
||||
* @param socket the socket for which the write was interrupted
|
||||
* @param count the number of iovec buffers
|
||||
* @param iovecs buffer array
|
||||
* @param frees a set of flags indicating which of the iovecs array should be freed
|
||||
* @param total total data length to be written
|
||||
* @param bytes actual data length that was written
|
||||
*/
|
||||
#if defined(OPENSSL)
|
||||
int SocketBuffer_pendingWrite(SOCKET socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes)
|
||||
#else
|
||||
int SocketBuffer_pendingWrite(SOCKET socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes)
|
||||
#endif
|
||||
{
|
||||
int i = 0;
|
||||
pending_writes* pw = NULL;
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
/* store the buffers until the whole packet is written */
|
||||
if ((pw = malloc(sizeof(pending_writes))) == NULL)
|
||||
{
|
||||
rc = PAHO_MEMORY_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
pw->socket = socket;
|
||||
#if defined(OPENSSL)
|
||||
pw->ssl = ssl;
|
||||
#endif
|
||||
pw->bytes = bytes;
|
||||
pw->total = total;
|
||||
pw->count = count;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
pw->iovecs[i] = iovecs[i];
|
||||
pw->frees[i] = frees[i];
|
||||
}
|
||||
ListAppend(&writes, pw, sizeof(pw) + total);
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List callback function for comparing pending_writes by socket
|
||||
* @param a first integer value
|
||||
* @param b second integer value
|
||||
* @return boolean indicating whether a and b are equal
|
||||
*/
|
||||
int pending_socketcompare(void* a, void* b)
|
||||
{
|
||||
return ((pending_writes*)a)->socket == *(int*)b;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get any queued write data for a specific socket
|
||||
* @param socket the socket to get queued data for
|
||||
* @return pointer to the queued data or NULL
|
||||
*/
|
||||
pending_writes* SocketBuffer_getWrite(SOCKET socket)
|
||||
{
|
||||
ListElement* le = ListFindItem(&writes, &socket, pending_socketcompare);
|
||||
return (le) ? (pending_writes*)(le->content) : NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A socket write has now completed so we can get rid of the queue
|
||||
* @param socket the socket for which the operation is now complete
|
||||
* @return completion code, boolean - was the queue removed?
|
||||
*/
|
||||
int SocketBuffer_writeComplete(SOCKET socket)
|
||||
{
|
||||
return ListRemoveItem(&writes, &socket, pending_socketcompare);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the queued write data for a socket in the case of QoS 0 messages.
|
||||
* @param socket the socket for which the operation is now complete
|
||||
* @param topic the topic of the QoS 0 write
|
||||
* @param payload the payload of the QoS 0 write
|
||||
* @return pointer to the updated queued data structure, or NULL
|
||||
*/
|
||||
pending_writes* SocketBuffer_updateWrite(SOCKET socket, char* topic, char* payload)
|
||||
{
|
||||
pending_writes* pw = NULL;
|
||||
ListElement* le = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((le = ListFindItem(&writes, &socket, pending_socketcompare)) != NULL)
|
||||
{
|
||||
pw = (pending_writes*)(le->content);
|
||||
if (pw->count == 4)
|
||||
{
|
||||
pw->iovecs[2].iov_base = topic;
|
||||
pw->iovecs[3].iov_base = payload;
|
||||
}
|
||||
}
|
||||
|
||||
FUNC_EXIT;
|
||||
return pw;
|
||||
}
|
||||
81
src/mqtt/externals/paho-mqtt-c/src/SocketBuffer.h
vendored
Normal file
81
src/mqtt/externals/paho-mqtt-c/src/SocketBuffer.h
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2022 IBM Corp., Ian Craggs and others
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(SOCKETBUFFER_H)
|
||||
#define SOCKETBUFFER_H
|
||||
|
||||
#include "Socket.h"
|
||||
|
||||
#if defined(OPENSSL)
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef WSABUF iobuf;
|
||||
#else
|
||||
typedef struct iovec iobuf;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOCKET socket;
|
||||
unsigned int index;
|
||||
size_t headerlen;
|
||||
char fixed_header[5]; /**< header plus up to 4 length bytes */
|
||||
size_t buflen, /**< total length of the buffer */
|
||||
datalen; /**< current length of data in buf */
|
||||
char* buf;
|
||||
} socket_queue;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOCKET socket;
|
||||
int count;
|
||||
size_t total;
|
||||
#if defined(OPENSSL)
|
||||
SSL* ssl;
|
||||
#endif
|
||||
size_t bytes;
|
||||
iobuf iovecs[5];
|
||||
int frees[5];
|
||||
} pending_writes;
|
||||
|
||||
#define SOCKETBUFFER_COMPLETE 0
|
||||
#if !defined(SOCKET_ERROR)
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
#define SOCKETBUFFER_INTERRUPTED -22 /* must be the same value as TCPSOCKET_INTERRUPTED */
|
||||
|
||||
int SocketBuffer_initialize(void);
|
||||
void SocketBuffer_terminate(void);
|
||||
void SocketBuffer_cleanup(SOCKET socket);
|
||||
char* SocketBuffer_getQueuedData(SOCKET socket, size_t bytes, size_t* actual_len);
|
||||
int SocketBuffer_getQueuedChar(SOCKET socket, char* c);
|
||||
void SocketBuffer_interrupted(SOCKET socket, size_t actual_len);
|
||||
char* SocketBuffer_complete(SOCKET socket);
|
||||
void SocketBuffer_queueChar(SOCKET socket, char c);
|
||||
|
||||
#if defined(OPENSSL)
|
||||
int SocketBuffer_pendingWrite(SOCKET socket, SSL* ssl, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes);
|
||||
#else
|
||||
int SocketBuffer_pendingWrite(SOCKET socket, int count, iobuf* iovecs, int* frees, size_t total, size_t bytes);
|
||||
#endif
|
||||
pending_writes* SocketBuffer_getWrite(SOCKET socket);
|
||||
int SocketBuffer_writeComplete(SOCKET socket);
|
||||
pending_writes* SocketBuffer_updateWrite(SOCKET socket, char* topic, char* payload);
|
||||
|
||||
#endif
|
||||
208
src/mqtt/externals/paho-mqtt-c/src/StackTrace.c
vendored
Normal file
208
src/mqtt/externals/paho-mqtt-c/src/StackTrace.c
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "Log.h"
|
||||
#include "LinkedList.h"
|
||||
|
||||
#include "Clients.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/*BE
|
||||
def STACKENTRY
|
||||
{
|
||||
n32 ptr STRING open "name"
|
||||
n32 dec "line"
|
||||
}
|
||||
|
||||
defList(STACKENTRY)
|
||||
BE*/
|
||||
|
||||
#define MAX_STACK_DEPTH 50
|
||||
#define MAX_FUNCTION_NAME_LENGTH 30
|
||||
#define MAX_THREADS 255
|
||||
|
||||
typedef struct
|
||||
{
|
||||
thread_id_type threadid;
|
||||
char name[MAX_FUNCTION_NAME_LENGTH];
|
||||
int line;
|
||||
} stackEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
thread_id_type id;
|
||||
int maxdepth;
|
||||
int current_depth;
|
||||
stackEntry callstack[MAX_STACK_DEPTH];
|
||||
} threadEntry;
|
||||
|
||||
#include "StackTrace.h"
|
||||
|
||||
#if !defined(NOSTACKTRACE)
|
||||
|
||||
static int thread_count = 0;
|
||||
static threadEntry threads[MAX_THREADS];
|
||||
static threadEntry *my_thread = NULL;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mutex_type stack_mutex;
|
||||
#else
|
||||
static pthread_mutex_t stack_mutex_store = PTHREAD_MUTEX_INITIALIZER;
|
||||
static mutex_type stack_mutex = &stack_mutex_store;
|
||||
#endif
|
||||
|
||||
|
||||
int setStack(int create);
|
||||
|
||||
|
||||
int setStack(int create)
|
||||
{
|
||||
int i = -1;
|
||||
thread_id_type curid = Paho_thread_getid();
|
||||
|
||||
my_thread = NULL;
|
||||
for (i = 0; i < MAX_THREADS && i < thread_count; ++i)
|
||||
{
|
||||
if (threads[i].id == curid)
|
||||
{
|
||||
my_thread = &threads[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (my_thread == NULL && create && thread_count < MAX_THREADS)
|
||||
{
|
||||
my_thread = &threads[thread_count];
|
||||
my_thread->id = curid;
|
||||
my_thread->maxdepth = 0;
|
||||
my_thread->current_depth = 0;
|
||||
++thread_count;
|
||||
}
|
||||
return my_thread != NULL; /* good == 1 */
|
||||
}
|
||||
|
||||
void StackTrace_entry(const char* name, int line, enum LOG_LEVELS trace_level)
|
||||
{
|
||||
Paho_thread_lock_mutex(stack_mutex);
|
||||
if (!setStack(1))
|
||||
goto exit;
|
||||
if (trace_level != -1)
|
||||
Log_stackTrace(trace_level, 9, my_thread->id, my_thread->current_depth, name, line, NULL);
|
||||
strncpy(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1);
|
||||
my_thread->callstack[(my_thread->current_depth)++].line = line;
|
||||
if (my_thread->current_depth > my_thread->maxdepth)
|
||||
my_thread->maxdepth = my_thread->current_depth;
|
||||
if (my_thread->current_depth >= MAX_STACK_DEPTH)
|
||||
Log(LOG_FATAL, -1, "Max stack depth exceeded");
|
||||
exit:
|
||||
Paho_thread_unlock_mutex(stack_mutex);
|
||||
}
|
||||
|
||||
|
||||
void StackTrace_exit(const char* name, int line, void* rc, enum LOG_LEVELS trace_level)
|
||||
{
|
||||
Paho_thread_lock_mutex(stack_mutex);
|
||||
if (!setStack(0))
|
||||
goto exit;
|
||||
if (--(my_thread->current_depth) < 0)
|
||||
Log(LOG_FATAL, -1, "Minimum stack depth exceeded for thread %lu", my_thread->id);
|
||||
if (strncmp(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1) != 0)
|
||||
Log(LOG_FATAL, -1, "Stack mismatch. Entry:%s Exit:%s\n", my_thread->callstack[my_thread->current_depth].name, name);
|
||||
if (trace_level != -1)
|
||||
{
|
||||
if (rc == NULL)
|
||||
Log_stackTrace(trace_level, 10, my_thread->id, my_thread->current_depth, name, line, NULL);
|
||||
else
|
||||
Log_stackTrace(trace_level, 11, my_thread->id, my_thread->current_depth, name, line, (int*)rc);
|
||||
}
|
||||
exit:
|
||||
Paho_thread_unlock_mutex(stack_mutex);
|
||||
}
|
||||
|
||||
|
||||
void StackTrace_printStack(FILE* dest)
|
||||
{
|
||||
FILE* file = stdout;
|
||||
int t = 0;
|
||||
|
||||
if (dest)
|
||||
file = dest;
|
||||
for (t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threadEntry *cur_thread = &threads[t];
|
||||
|
||||
if (cur_thread->id > 0)
|
||||
{
|
||||
int i = cur_thread->current_depth - 1;
|
||||
|
||||
fprintf(file, "=========== Start of stack trace for thread %lu ==========\n", (unsigned long)cur_thread->id);
|
||||
if (i >= 0)
|
||||
{
|
||||
fprintf(file, "%s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
|
||||
while (--i >= 0)
|
||||
fprintf(file, " at %s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
|
||||
}
|
||||
fprintf(file, "=========== End of stack trace for thread %lu ==========\n\n", (unsigned long)cur_thread->id);
|
||||
}
|
||||
}
|
||||
if (file != stdout && file != stderr && file != NULL)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
char* StackTrace_get(thread_id_type threadid, char* buf, int bufsize)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
if (bufsize < 100)
|
||||
goto exit;
|
||||
buf[0] = '\0';
|
||||
for (t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threadEntry *cur_thread = &threads[t];
|
||||
|
||||
if (cur_thread->id == threadid)
|
||||
{
|
||||
int i = cur_thread->current_depth - 1;
|
||||
int curpos = 0;
|
||||
|
||||
if (i >= 0)
|
||||
{
|
||||
curpos += snprintf(&buf[curpos], bufsize - curpos -1,
|
||||
"%s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
|
||||
while (--i >= 0)
|
||||
curpos += snprintf(&buf[curpos], bufsize - curpos -1, /* lgtm [cpp/overflowing-snprintf] */
|
||||
" at %s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
|
||||
if (buf[--curpos] == '\n')
|
||||
buf[curpos] = '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
75
src/mqtt/externals/paho-mqtt-c/src/StackTrace.h
vendored
Normal file
75
src/mqtt/externals/paho-mqtt-c/src/StackTrace.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef STACKTRACE_H_
|
||||
#define STACKTRACE_H_
|
||||
|
||||
#if defined(HIGH_PERFORMANCE)
|
||||
#define NOSTACKTRACE 1
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#if defined(NOSTACKTRACE)
|
||||
#define FUNC_ENTRY
|
||||
#define FUNC_ENTRY_NOLOG
|
||||
#define FUNC_ENTRY_MED
|
||||
#define FUNC_ENTRY_MAX
|
||||
#define FUNC_EXIT
|
||||
#define FUNC_EXIT_NOLOG
|
||||
#define FUNC_EXIT_MED
|
||||
#define FUNC_EXIT_MAX
|
||||
#define FUNC_EXIT_RC(x)
|
||||
#define FUNC_EXIT_MED_RC(x)
|
||||
#define FUNC_EXIT_MAX_RC(x)
|
||||
#else
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define inline __inline
|
||||
#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
|
||||
#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
|
||||
#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
|
||||
#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, NULL, -1)
|
||||
#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
|
||||
#else
|
||||
#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
|
||||
#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
|
||||
#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
|
||||
#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
|
||||
#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void StackTrace_entry(const char* name, int line, enum LOG_LEVELS trace);
|
||||
void StackTrace_exit(const char* name, int line, void* return_value, enum LOG_LEVELS trace);
|
||||
|
||||
void StackTrace_printStack(FILE* dest);
|
||||
char* StackTrace_get(thread_id_type, char* buf, int bufsize);
|
||||
|
||||
#endif /* STACKTRACE_H_ */
|
||||
692
src/mqtt/externals/paho-mqtt-c/src/Thread.c
vendored
Normal file
692
src/mqtt/externals/paho-mqtt-c/src/Thread.c
vendored
Normal file
@@ -0,0 +1,692 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp. and Ian Craggs
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation
|
||||
* Ian Craggs, Allan Stockdill-Mander - async client updates
|
||||
* Ian Craggs - bug #415042 - start Linux thread as disconnected
|
||||
* Ian Craggs - fix for bug #420851
|
||||
* Ian Craggs - change MacOS semaphore implementation
|
||||
* Ian Craggs - fix for clock #284
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Threading related functions
|
||||
*
|
||||
* Used to create platform independent threading functions
|
||||
*/
|
||||
|
||||
|
||||
#include "Thread.h"
|
||||
#if defined(THREAD_UNIT_TESTS)
|
||||
#define NOSTACKTRACE
|
||||
#endif
|
||||
#include "Log.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "OsWrapper.h"
|
||||
|
||||
/**
|
||||
* Start a new thread
|
||||
* @param fn the function to run, must be of the correct signature
|
||||
* @param parameter pointer to the function parameter, can be NULL
|
||||
*/
|
||||
void Paho_thread_start(thread_fn fn, void* parameter)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
thread_type thread = NULL;
|
||||
#else
|
||||
thread_type thread = 0;
|
||||
pthread_attr_t attr;
|
||||
#endif
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
thread = CreateThread(NULL, 0, fn, parameter, 0, NULL);
|
||||
CloseHandle(thread);
|
||||
#else
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (pthread_create(&thread, &attr, fn, parameter) != 0)
|
||||
thread = 0;
|
||||
pthread_attr_destroy(&attr);
|
||||
#endif
|
||||
FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
int Thread_set_name(const char* thread_name)
|
||||
{
|
||||
int rc = 0;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MAX_THREAD_NAME_LENGTH 30
|
||||
wchar_t wchars[MAX_THREAD_NAME_LENGTH];
|
||||
#endif
|
||||
FUNC_ENTRY;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* Using NTDDI_VERSION rather than WINVER for more detailed version targeting */
|
||||
/* Can't get this conditional compilation to work so remove it for now */
|
||||
/*#if NTDDI_VERSION >= NTDDI_WIN10_RS1
|
||||
mbstowcs(wchars, thread_name, MAX_THREAD_NAME_LENGTH);
|
||||
rc = (int)SetThreadDescription(GetCurrentThread(), wchars);
|
||||
#endif*/
|
||||
#elif defined(OSX)
|
||||
/* pthread_setname_np __API_AVAILABLE(macos(10.6), ios(3.2)) */
|
||||
#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
|
||||
rc = pthread_setname_np(thread_name);
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 12
|
||||
rc = pthread_setname_np(Paho_thread_getid(), thread_name);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new mutex
|
||||
* @param rc return code: 0 for success, negative otherwise
|
||||
* @return the new mutex
|
||||
*/
|
||||
mutex_type Paho_thread_create_mutex(int* rc)
|
||||
{
|
||||
mutex_type mutex = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
*rc = -1;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mutex = CreateMutex(NULL, 0, NULL);
|
||||
*rc = (mutex == NULL) ? GetLastError() : 0;
|
||||
#else
|
||||
mutex = malloc(sizeof(pthread_mutex_t));
|
||||
if (mutex)
|
||||
*rc = pthread_mutex_init(mutex, NULL);
|
||||
#endif
|
||||
FUNC_EXIT_RC(*rc);
|
||||
return mutex;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lock a mutex which has alrea
|
||||
* @return completion code, 0 is success
|
||||
*/
|
||||
int Paho_thread_lock_mutex(mutex_type mutex)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
/* don't add entry/exit trace points as the stack log uses mutexes - recursion beckons */
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* WaitForSingleObject returns WAIT_OBJECT_0 (0), on success */
|
||||
rc = WaitForSingleObject(mutex, INFINITE);
|
||||
#else
|
||||
rc = pthread_mutex_lock(mutex);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unlock a mutex which has already been locked
|
||||
* @param mutex the mutex
|
||||
* @return completion code, 0 is success
|
||||
*/
|
||||
int Paho_thread_unlock_mutex(mutex_type mutex)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
/* don't add entry/exit trace points as the stack log uses mutexes - recursion beckons */
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* if ReleaseMutex fails, the return value is 0 */
|
||||
if (ReleaseMutex(mutex) == 0)
|
||||
rc = GetLastError();
|
||||
else
|
||||
rc = 0;
|
||||
#else
|
||||
rc = pthread_mutex_unlock(mutex);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a mutex which has already been created
|
||||
* @param mutex the mutex
|
||||
*/
|
||||
int Paho_thread_destroy_mutex(mutex_type mutex)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
rc = CloseHandle(mutex);
|
||||
#else
|
||||
rc = pthread_mutex_destroy(mutex);
|
||||
free(mutex);
|
||||
#endif
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the thread id of the thread from which this function is called
|
||||
* @return thread id, type varying according to OS
|
||||
*/
|
||||
thread_id_type Paho_thread_getid(void)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return GetCurrentThreadId();
|
||||
#else
|
||||
return pthread_self();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new semaphore
|
||||
* @param rc return code: 0 for success, negative otherwise
|
||||
* @return the new condition variable
|
||||
*/
|
||||
sem_type Thread_create_sem(int *rc)
|
||||
{
|
||||
sem_type sem = NULL;
|
||||
|
||||
FUNC_ENTRY;
|
||||
*rc = -1;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
sem = CreateEvent(
|
||||
NULL, /* default security attributes */
|
||||
FALSE, /* manual-reset event? */
|
||||
FALSE, /* initial state is nonsignaled */
|
||||
NULL /* object name */
|
||||
);
|
||||
*rc = (sem == NULL) ? GetLastError() : 0;
|
||||
#elif defined(OSX)
|
||||
sem = dispatch_semaphore_create(0L);
|
||||
*rc = (sem == NULL) ? -1 : 0;
|
||||
#else
|
||||
sem = malloc(sizeof(sem_t));
|
||||
if (sem)
|
||||
*rc = sem_init(sem, 0, 0);
|
||||
#endif
|
||||
FUNC_EXIT_RC(*rc);
|
||||
return sem;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait for a semaphore to be posted, or timeout.
|
||||
* @param sem the semaphore
|
||||
* @param timeout the maximum time to wait, in milliseconds
|
||||
* @return completion code
|
||||
*/
|
||||
int Thread_wait_sem(sem_type sem, int timeout)
|
||||
{
|
||||
/* sem_timedwait is the obvious call to use, but seemed not to work on the Viper,
|
||||
* so I've used trywait in a loop instead. Ian Craggs 23/7/2010
|
||||
*/
|
||||
int rc = -1;
|
||||
#if !defined(_WIN32) && !defined(_WIN64) && !defined(OSX)
|
||||
#define USE_TRYWAIT
|
||||
#if defined(USE_TRYWAIT)
|
||||
int i = 0;
|
||||
useconds_t interval = 10000; /* 10000 microseconds: 10 milliseconds */
|
||||
int count = (1000 * timeout) / interval; /* how many intervals in timeout period */
|
||||
#else
|
||||
struct timespec ts;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* returns 0 (WAIT_OBJECT_0) on success, non-zero (WAIT_TIMEOUT) if timeout occurred */
|
||||
rc = WaitForSingleObject(sem, timeout < 0 ? 0 : timeout);
|
||||
if (rc == WAIT_TIMEOUT)
|
||||
rc = ETIMEDOUT;
|
||||
#elif defined(OSX)
|
||||
/* returns 0 on success, non-zero if timeout occurred */
|
||||
rc = (int)dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeout*1000000L));
|
||||
if (rc != 0)
|
||||
rc = ETIMEDOUT;
|
||||
#elif defined(USE_TRYWAIT)
|
||||
while (++i < count && (rc = sem_trywait(sem)) != 0)
|
||||
{
|
||||
if (rc == -1 && ((rc = errno) != EAGAIN))
|
||||
{
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
usleep(interval); /* microseconds - .1 of a second */
|
||||
}
|
||||
#else
|
||||
/* We have to use CLOCK_REALTIME rather than MONOTONIC for sem_timedwait interval.
|
||||
* Does this make it susceptible to system clock changes?
|
||||
* The intervals are small enough, and repeated, that I think it's not an issue.
|
||||
*/
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) != -1)
|
||||
{
|
||||
ts.tv_sec += timeout;
|
||||
rc = sem_timedwait(sem, &ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if a semaphore has been posted, without waiting
|
||||
* The semaphore will be unchanged, if the return value is false.
|
||||
* The semaphore will have been decremented, if the return value is true.
|
||||
* @param sem the semaphore
|
||||
* @return 0 (false) or 1 (true)
|
||||
*/
|
||||
int Thread_check_sem(sem_type sem)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* if the return value is not 0, the semaphore will not have been decremented */
|
||||
return WaitForSingleObject(sem, 0) == WAIT_OBJECT_0;
|
||||
#elif defined(OSX)
|
||||
/* if the return value is not 0, the semaphore will not have been decremented */
|
||||
return dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0;
|
||||
#else
|
||||
/* If the call was unsuccessful, the state of the semaphore shall be unchanged,
|
||||
* and the function shall return a value of -1 */
|
||||
return sem_trywait(sem) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Post a semaphore
|
||||
* @param sem the semaphore
|
||||
* @return 0 on success
|
||||
*/
|
||||
int Thread_post_sem(sem_type sem)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (SetEvent(sem) == 0)
|
||||
rc = GetLastError();
|
||||
#elif defined(OSX)
|
||||
rc = (int)dispatch_semaphore_signal(sem);
|
||||
#else
|
||||
int val;
|
||||
int rc1 = sem_getvalue(sem, &val);
|
||||
if (rc1 != 0)
|
||||
rc = errno;
|
||||
else if (val == 0 && sem_post(sem) == -1)
|
||||
rc = errno;
|
||||
#endif
|
||||
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a semaphore which has already been created
|
||||
* @param sem the semaphore
|
||||
*/
|
||||
int Thread_destroy_sem(sem_type sem)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
rc = CloseHandle(sem);
|
||||
#elif defined(OSX)
|
||||
dispatch_release(sem);
|
||||
#else
|
||||
rc = sem_destroy(sem);
|
||||
free(sem);
|
||||
#endif
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
|
||||
/**
|
||||
* Create a new condition variable
|
||||
* @return the condition variable struct
|
||||
*/
|
||||
cond_type Thread_create_cond(int *rc)
|
||||
{
|
||||
cond_type condvar = NULL;
|
||||
pthread_condattr_t attr;
|
||||
|
||||
FUNC_ENTRY;
|
||||
*rc = -1;
|
||||
pthread_condattr_init(&attr);
|
||||
|
||||
#if 0
|
||||
/* in theory, a monotonic clock should be able to be used. However on at least
|
||||
* one system reported, even though setclock() reported success, it didn't work.
|
||||
*/
|
||||
if ((rc = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) == 0)
|
||||
use_clock_monotonic = 1;
|
||||
else
|
||||
Log(LOG_ERROR, -1, "Error %d calling pthread_condattr_setclock(CLOCK_MONOTONIC)", rc);
|
||||
#endif
|
||||
|
||||
condvar = malloc(sizeof(cond_type_struct));
|
||||
if (condvar)
|
||||
{
|
||||
*rc = pthread_cond_init(&condvar->cond, &attr);
|
||||
*rc = pthread_mutex_init(&condvar->mutex, NULL);
|
||||
}
|
||||
|
||||
FUNC_EXIT_RC(*rc);
|
||||
return condvar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal a condition variable
|
||||
* @return completion code
|
||||
*/
|
||||
int Thread_signal_cond(cond_type condvar)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
pthread_mutex_lock(&condvar->mutex);
|
||||
rc = pthread_cond_signal(&condvar->cond);
|
||||
pthread_mutex_unlock(&condvar->mutex);
|
||||
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait with a timeout (ms) for condition variable
|
||||
* @return 0 for success, ETIMEDOUT otherwise
|
||||
*/
|
||||
int Thread_wait_cond(cond_type condvar, int timeout_ms)
|
||||
{
|
||||
int rc = 0;
|
||||
struct timespec cond_timeout;
|
||||
struct timespec interval;
|
||||
|
||||
FUNC_ENTRY;
|
||||
interval.tv_sec = timeout_ms / 1000;
|
||||
interval.tv_nsec = (timeout_ms % 1000) * 1000000L;
|
||||
|
||||
#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 /* for older versions of MacOS */
|
||||
struct timeval cur_time;
|
||||
gettimeofday(&cur_time, NULL);
|
||||
cond_timeout.tv_sec = cur_time.tv_sec;
|
||||
cond_timeout.tv_nsec = cur_time.tv_usec * 1000;
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &cond_timeout);
|
||||
#endif
|
||||
|
||||
cond_timeout.tv_sec += interval.tv_sec;
|
||||
cond_timeout.tv_nsec += (timeout_ms % 1000) * 1000000L;
|
||||
|
||||
if (cond_timeout.tv_nsec >= 1000000000L)
|
||||
{
|
||||
cond_timeout.tv_sec++;
|
||||
cond_timeout.tv_nsec += (cond_timeout.tv_nsec - 1000000000L);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&condvar->mutex);
|
||||
rc = pthread_cond_timedwait(&condvar->cond, &condvar->mutex, &cond_timeout);
|
||||
pthread_mutex_unlock(&condvar->mutex);
|
||||
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a condition variable
|
||||
* @return completion code
|
||||
*/
|
||||
int Thread_destroy_cond(cond_type condvar)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = pthread_mutex_destroy(&condvar->mutex);
|
||||
rc = pthread_cond_destroy(&condvar->cond);
|
||||
free(condvar);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(THREAD_UNIT_TESTS)
|
||||
|
||||
#if defined(_WIN32) || defined(_WINDOWS)
|
||||
#define mqsleep(A) Sleep(1000*A)
|
||||
#define START_TIME_TYPE DWORD
|
||||
static DWORD start_time = 0;
|
||||
START_TIME_TYPE start_clock(void)
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
#elif defined(AIX)
|
||||
#define mqsleep sleep
|
||||
#define START_TIME_TYPE struct timespec
|
||||
START_TIME_TYPE start_clock(void)
|
||||
{
|
||||
static struct timespec start;
|
||||
clock_gettime(CLOCK_REALTIME, &start);
|
||||
return start;
|
||||
}
|
||||
#else
|
||||
#define mqsleep sleep
|
||||
#define START_TIME_TYPE struct timeval
|
||||
/* TODO - unused - remove? static struct timeval start_time; */
|
||||
START_TIME_TYPE start_clock(void)
|
||||
{
|
||||
struct timeval start_time;
|
||||
gettimeofday(&start_time, NULL);
|
||||
return start_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
long elapsed(START_TIME_TYPE start_time)
|
||||
{
|
||||
return GetTickCount() - start_time;
|
||||
}
|
||||
#elif defined(AIX)
|
||||
#define assert(a)
|
||||
long elapsed(struct timespec start)
|
||||
{
|
||||
struct timespec now, res;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
ntimersub(now, start, res);
|
||||
return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
|
||||
}
|
||||
#else
|
||||
long elapsed(START_TIME_TYPE start_time)
|
||||
{
|
||||
struct timeval now, res;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&now, &start_time, &res);
|
||||
return (res.tv_sec)*1000 + (res.tv_usec)/1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int tests = 0, failures = 0;
|
||||
|
||||
void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
|
||||
{
|
||||
++tests;
|
||||
if (!value)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
++failures;
|
||||
printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
//cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
|
||||
// description, filename, lineno);
|
||||
}
|
||||
else
|
||||
printf("Assertion succeeded, file %s, line %d, description: %s\n", filename, lineno, description);
|
||||
}
|
||||
|
||||
#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
|
||||
#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
thread_return_type cond_secondary(void* n)
|
||||
{
|
||||
int rc = 0;
|
||||
cond_type cond = n;
|
||||
|
||||
printf("This should return immediately as it was posted already\n");
|
||||
rc = Thread_wait_cond(cond, 99999);
|
||||
assert("rc 1 from wait_cond", rc == 1, "rc was %d", rc);
|
||||
|
||||
printf("This should hang around a few seconds\n");
|
||||
rc = Thread_wait_cond(cond, 99999);
|
||||
assert("rc 1 from wait_cond", rc == 1, "rc was %d", rc);
|
||||
|
||||
printf("Secondary cond thread ending\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cond_test()
|
||||
{
|
||||
int rc = 0;
|
||||
cond_type cond = Thread_create_cond();
|
||||
|
||||
printf("Post secondary so it should return immediately\n");
|
||||
rc = Thread_signal_cond(cond);
|
||||
assert("rc 0 from signal cond", rc == 0, "rc was %d", rc);
|
||||
|
||||
printf("Starting secondary thread\n");
|
||||
Thread_start(cond_secondary, (void*)cond);
|
||||
|
||||
sleep(3);
|
||||
|
||||
printf("post secondary\n");
|
||||
rc = Thread_signal_cond(cond);
|
||||
assert("rc 1 from signal cond", rc == 1, "rc was %d", rc);
|
||||
|
||||
sleep(3);
|
||||
|
||||
printf("Main thread ending\n");
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
thread_return_type sem_secondary(void* n)
|
||||
{
|
||||
int rc = 0;
|
||||
sem_type sem = n;
|
||||
|
||||
printf("Secondary semaphore pointer %p\n", sem);
|
||||
|
||||
rc = Thread_check_sem(sem);
|
||||
assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
|
||||
|
||||
printf("Secondary thread about to wait\n");
|
||||
rc = Thread_wait_sem(sem, 99999);
|
||||
printf("Secondary thread returned from wait %d\n", rc);
|
||||
|
||||
printf("Secondary thread about to wait\n");
|
||||
rc = Thread_wait_sem(sem, 99999);
|
||||
printf("Secondary thread returned from wait %d\n", rc);
|
||||
printf("Secondary check sem %d\n", Thread_check_sem(sem));
|
||||
|
||||
printf("Secondary thread ending\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sem_test()
|
||||
{
|
||||
int rc = 0;
|
||||
sem_type sem = Thread_create_sem();
|
||||
|
||||
printf("Primary semaphore pointer %p\n", sem);
|
||||
|
||||
rc = Thread_check_sem(sem);
|
||||
assert("rc 0 from check_sem", rc == 0, "rc was %d\n", rc);
|
||||
|
||||
printf("post secondary so then check should be 1\n");
|
||||
rc = Thread_post_sem(sem);
|
||||
assert("rc 0 from post_sem", rc == 0, "rc was %d\n", rc);
|
||||
|
||||
rc = Thread_check_sem(sem);
|
||||
assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
|
||||
|
||||
printf("Starting secondary thread\n");
|
||||
Thread_start(sem_secondary, (void*)sem);
|
||||
|
||||
sleep(3);
|
||||
rc = Thread_check_sem(sem);
|
||||
assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
|
||||
|
||||
printf("post secondary\n");
|
||||
rc = Thread_post_sem(sem);
|
||||
assert("rc 1 from post_sem", rc == 1, "rc was %d", rc);
|
||||
|
||||
sleep(3);
|
||||
|
||||
printf("Main thread ending\n");
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
sem_test();
|
||||
//cond_test();
|
||||
}
|
||||
|
||||
#endif
|
||||
88
src/mqtt/externals/paho-mqtt-c/src/Thread.h
vendored
Normal file
88
src/mqtt/externals/paho-mqtt-c/src/Thread.h
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2023 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation
|
||||
* Ian Craggs, Allan Stockdill-Mander - async client updates
|
||||
* Ian Craggs - fix for bug #420851
|
||||
* Ian Craggs - change MacOS semaphore implementation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(THREAD_H)
|
||||
#define THREAD_H
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#if defined(__GNUC__) && defined(__linux__)
|
||||
#if !defined(_GNU_SOURCE)
|
||||
// for pthread_setname
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "MQTTExportDeclarations.h"
|
||||
|
||||
#include "MQTTClient.h"
|
||||
|
||||
#include "mutex_type.h" /* Needed for mutex_type */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#define thread_type HANDLE
|
||||
#define thread_id_type DWORD
|
||||
#define thread_return_type DWORD
|
||||
#define thread_fn LPTHREAD_START_ROUTINE
|
||||
#define cond_type HANDLE
|
||||
#define sem_type HANDLE
|
||||
#undef ETIMEDOUT
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#else
|
||||
#include <pthread.h>
|
||||
|
||||
#define thread_type pthread_t
|
||||
#define thread_id_type pthread_t
|
||||
#define thread_return_type void*
|
||||
typedef thread_return_type (*thread_fn)(void*);
|
||||
typedef struct { pthread_cond_t cond; pthread_mutex_t mutex; } cond_type_struct;
|
||||
typedef cond_type_struct *cond_type;
|
||||
#if defined(OSX)
|
||||
#include <dispatch/dispatch.h>
|
||||
typedef dispatch_semaphore_t sem_type;
|
||||
#else
|
||||
#include <semaphore.h>
|
||||
typedef sem_t *sem_type;
|
||||
#endif
|
||||
|
||||
cond_type Thread_create_cond(int*);
|
||||
int Thread_signal_cond(cond_type);
|
||||
int Thread_wait_cond(cond_type condvar, int timeout);
|
||||
int Thread_destroy_cond(cond_type);
|
||||
#endif
|
||||
|
||||
LIBMQTT_API void Paho_thread_start(thread_fn, void*);
|
||||
int Thread_set_name(const char* thread_name);
|
||||
|
||||
LIBMQTT_API mutex_type Paho_thread_create_mutex(int*);
|
||||
LIBMQTT_API int Paho_thread_lock_mutex(mutex_type);
|
||||
LIBMQTT_API int Paho_thread_unlock_mutex(mutex_type);
|
||||
int Paho_thread_destroy_mutex(mutex_type);
|
||||
|
||||
LIBMQTT_API thread_id_type Paho_thread_getid();
|
||||
|
||||
sem_type Thread_create_sem(int*);
|
||||
int Thread_wait_sem(sem_type sem, int timeout);
|
||||
int Thread_check_sem(sem_type sem);
|
||||
int Thread_post_sem(sem_type sem);
|
||||
int Thread_destroy_sem(sem_type sem);
|
||||
|
||||
|
||||
#endif
|
||||
729
src/mqtt/externals/paho-mqtt-c/src/Tree.c
vendored
Normal file
729
src/mqtt/externals/paho-mqtt-c/src/Tree.c
vendored
Normal file
@@ -0,0 +1,729 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2020 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
/** @file
|
||||
* \brief functions which apply to tree structures.
|
||||
*
|
||||
* These trees can hold data of any sort, pointed to by the content pointer of the
|
||||
* Node structure.
|
||||
* */
|
||||
|
||||
#define TREE_C /* so that malloc/free/realloc aren't redefined by Heap.h */
|
||||
|
||||
#include "Tree.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Heap.h"
|
||||
|
||||
|
||||
int isRed(Node* aNode);
|
||||
int isBlack(Node* aNode);
|
||||
/*int TreeWalk(Node* curnode, int depth);*/
|
||||
/*int TreeMaxDepth(Tree *aTree);*/
|
||||
void TreeRotate(Tree* aTree, Node* curnode, int direction, int index);
|
||||
Node* TreeBAASub(Tree* aTree, Node* curnode, int which, int index);
|
||||
void TreeBalanceAfterAdd(Tree* aTree, Node* curnode, int index);
|
||||
void* TreeAddByIndex(Tree* aTree, void* content, size_t size, int index);
|
||||
Node* TreeFindIndex1(Tree* aTree, void* key, int index, int value);
|
||||
Node* TreeFindContentIndex(Tree* aTree, void* key, int index);
|
||||
Node* TreeMinimum(Node* curnode);
|
||||
Node* TreeSuccessor(Node* curnode);
|
||||
Node* TreeNextElementIndex(Tree* aTree, Node* curnode, int index);
|
||||
Node* TreeBARSub(Tree* aTree, Node* curnode, int which, int index);
|
||||
void TreeBalanceAfterRemove(Tree* aTree, Node* curnode, int index);
|
||||
void* TreeRemoveIndex(Tree* aTree, void* content, int index);
|
||||
|
||||
|
||||
void TreeInitializeNoMalloc(Tree* aTree, int(*compare)(void*, void*, int))
|
||||
{
|
||||
memset(aTree, '\0', sizeof(Tree));
|
||||
aTree->heap_tracking = 1;
|
||||
aTree->index[0].compare = compare;
|
||||
aTree->indexes = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates and initializes a new tree structure.
|
||||
* @return a pointer to the new tree structure
|
||||
*/
|
||||
Tree* TreeInitialize(int(*compare)(void*, void*, int))
|
||||
{
|
||||
#if defined(UNIT_TESTS) || defined(NO_HEAP_TRACKING)
|
||||
Tree* newt = malloc(sizeof(Tree));
|
||||
#else
|
||||
Tree* newt = mymalloc(__FILE__, __LINE__, sizeof(Tree));
|
||||
#endif
|
||||
if (newt)
|
||||
TreeInitializeNoMalloc(newt, compare);
|
||||
return newt;
|
||||
}
|
||||
|
||||
|
||||
void TreeAddIndex(Tree* aTree, int(*compare)(void*, void*, int))
|
||||
{
|
||||
aTree->index[aTree->indexes].compare = compare;
|
||||
++(aTree->indexes);
|
||||
}
|
||||
|
||||
|
||||
void TreeFree(Tree* aTree)
|
||||
{
|
||||
#if defined(UNIT_TESTS) || defined(NO_HEAP_TRACKING)
|
||||
free(aTree);
|
||||
#else
|
||||
(aTree->heap_tracking) ? myfree(__FILE__, __LINE__, aTree) : free(aTree);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define LEFT 0
|
||||
#define RIGHT 1
|
||||
#if !defined(max)
|
||||
#define max(a, b) (a > b) ? a : b;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int isRed(Node* aNode)
|
||||
{
|
||||
return (aNode != NULL) && (aNode->red);
|
||||
}
|
||||
|
||||
|
||||
int isBlack(Node* aNode)
|
||||
{
|
||||
return (aNode == NULL) || (aNode->red == 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int TreeWalk(Node* curnode, int depth)
|
||||
{
|
||||
if (curnode)
|
||||
{
|
||||
int left = TreeWalk(curnode->child[LEFT], depth+1);
|
||||
int right = TreeWalk(curnode->child[RIGHT], depth+1);
|
||||
depth = max(left, right);
|
||||
if (curnode->red)
|
||||
{
|
||||
/*if (isRed(curnode->child[LEFT]) || isRed(curnode->child[RIGHT]))
|
||||
{
|
||||
printf("red/black tree violation %p\n", curnode->content);
|
||||
exit(-99);
|
||||
}*/;
|
||||
}
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
|
||||
int TreeMaxDepth(Tree *aTree)
|
||||
{
|
||||
int rc = TreeWalk(aTree->index[0].root, 0);
|
||||
/*if (aTree->root->red)
|
||||
{
|
||||
printf("root node should not be red %p\n", aTree->root->content);
|
||||
exit(-99);
|
||||
}*/
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
void TreeRotate(Tree* aTree, Node* curnode, int direction, int index)
|
||||
{
|
||||
Node* other = curnode->child[!direction];
|
||||
|
||||
curnode->child[!direction] = other->child[direction];
|
||||
if (other->child[direction] != NULL)
|
||||
other->child[direction]->parent = curnode;
|
||||
other->parent = curnode->parent;
|
||||
if (curnode->parent == NULL)
|
||||
aTree->index[index].root = other;
|
||||
else if (curnode == curnode->parent->child[direction])
|
||||
curnode->parent->child[direction] = other;
|
||||
else
|
||||
curnode->parent->child[!direction] = other;
|
||||
other->child[direction] = curnode;
|
||||
curnode->parent = other;
|
||||
}
|
||||
|
||||
|
||||
Node* TreeBAASub(Tree* aTree, Node* curnode, int which, int index)
|
||||
{
|
||||
Node* uncle = curnode->parent->parent->child[which];
|
||||
|
||||
if (isRed(uncle))
|
||||
{
|
||||
curnode->parent->red = uncle->red = 0;
|
||||
curnode = curnode->parent->parent;
|
||||
curnode->red = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curnode == curnode->parent->child[which])
|
||||
{
|
||||
curnode = curnode->parent;
|
||||
TreeRotate(aTree, curnode, !which, index);
|
||||
}
|
||||
curnode->parent->red = 0;
|
||||
curnode->parent->parent->red = 1;
|
||||
TreeRotate(aTree, curnode->parent->parent, which, index);
|
||||
}
|
||||
return curnode;
|
||||
}
|
||||
|
||||
|
||||
void TreeBalanceAfterAdd(Tree* aTree, Node* curnode, int index)
|
||||
{
|
||||
while (curnode && isRed(curnode->parent) && curnode->parent->parent)
|
||||
{
|
||||
if (curnode->parent == curnode->parent->parent->child[LEFT])
|
||||
curnode = TreeBAASub(aTree, curnode, RIGHT, index);
|
||||
else
|
||||
curnode = TreeBAASub(aTree, curnode, LEFT, index);
|
||||
}
|
||||
aTree->index[index].root->red = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an item to a tree
|
||||
* @param aTree the list to which the item is to be added
|
||||
* @param content the list item content itself
|
||||
* @param size the size of the element
|
||||
*/
|
||||
void* TreeAddByIndex(Tree* aTree, void* content, size_t size, int index)
|
||||
{
|
||||
Node* curparent = NULL;
|
||||
Node* curnode = aTree->index[index].root;
|
||||
Node* newel = NULL;
|
||||
int left = 0;
|
||||
int result = 1;
|
||||
void* rc = NULL;
|
||||
|
||||
while (curnode)
|
||||
{
|
||||
result = aTree->index[index].compare(curnode->content, content, 1);
|
||||
left = (result > 0);
|
||||
if (result == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
curparent = curnode;
|
||||
curnode = curnode->child[left];
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
if (aTree->allow_duplicates)
|
||||
goto exit; /* exit(-99); */
|
||||
else
|
||||
{
|
||||
newel = curnode;
|
||||
if (index == 0)
|
||||
aTree->size += (size - curnode->size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(UNIT_TESTS) || defined(NO_HEAP_TRACKING)
|
||||
newel = malloc(sizeof(Node));
|
||||
#else
|
||||
newel = (aTree->heap_tracking) ? mymalloc(__FILE__, __LINE__, sizeof(Node)) : malloc(sizeof(Node));
|
||||
#endif
|
||||
if (newel == NULL)
|
||||
goto exit;
|
||||
memset(newel, '\0', sizeof(Node));
|
||||
if (curparent)
|
||||
curparent->child[left] = newel;
|
||||
else
|
||||
aTree->index[index].root = newel;
|
||||
newel->parent = curparent;
|
||||
newel->red = 1;
|
||||
if (index == 0)
|
||||
{
|
||||
++(aTree->count);
|
||||
aTree->size += size;
|
||||
}
|
||||
}
|
||||
newel->content = content;
|
||||
newel->size = size;
|
||||
rc = newel->content;
|
||||
TreeBalanceAfterAdd(aTree, newel, index);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void* TreeAdd(Tree* aTree, void* content, size_t size)
|
||||
{
|
||||
void* rc = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < aTree->indexes; ++i)
|
||||
rc = TreeAddByIndex(aTree, content, size, i);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Node* TreeFindIndex1(Tree* aTree, void* key, int index, int value)
|
||||
{
|
||||
int result = 0;
|
||||
Node* curnode = aTree->index[index].root;
|
||||
|
||||
while (curnode)
|
||||
{
|
||||
result = aTree->index[index].compare(curnode->content, key, value);
|
||||
if (result == 0)
|
||||
break;
|
||||
else
|
||||
curnode = curnode->child[result > 0];
|
||||
}
|
||||
return curnode;
|
||||
}
|
||||
|
||||
|
||||
Node* TreeFindIndex(Tree* aTree, void* key, int index)
|
||||
{
|
||||
return TreeFindIndex1(aTree, key, index, 0);
|
||||
}
|
||||
|
||||
|
||||
Node* TreeFindContentIndex(Tree* aTree, void* key, int index)
|
||||
{
|
||||
return TreeFindIndex1(aTree, key, index, 1);
|
||||
}
|
||||
|
||||
|
||||
Node* TreeFind(Tree* aTree, void* key)
|
||||
{
|
||||
return TreeFindIndex(aTree, key, 0);
|
||||
}
|
||||
|
||||
|
||||
Node* TreeMinimum(Node* curnode)
|
||||
{
|
||||
if (curnode)
|
||||
while (curnode->child[LEFT])
|
||||
curnode = curnode->child[LEFT];
|
||||
return curnode;
|
||||
}
|
||||
|
||||
|
||||
Node* TreeSuccessor(Node* curnode)
|
||||
{
|
||||
if (curnode->child[RIGHT])
|
||||
curnode = TreeMinimum(curnode->child[RIGHT]);
|
||||
else
|
||||
{
|
||||
Node* curparent = curnode->parent;
|
||||
while (curparent && curnode == curparent->child[RIGHT])
|
||||
{
|
||||
curnode = curparent;
|
||||
curparent = curparent->parent;
|
||||
}
|
||||
curnode = curparent;
|
||||
}
|
||||
return curnode;
|
||||
}
|
||||
|
||||
|
||||
Node* TreeNextElementIndex(Tree* aTree, Node* curnode, int index)
|
||||
{
|
||||
if (curnode == NULL)
|
||||
curnode = TreeMinimum(aTree->index[index].root);
|
||||
else
|
||||
curnode = TreeSuccessor(curnode);
|
||||
return curnode;
|
||||
}
|
||||
|
||||
|
||||
Node* TreeNextElement(Tree* aTree, Node* curnode)
|
||||
{
|
||||
return TreeNextElementIndex(aTree, curnode, 0);
|
||||
}
|
||||
|
||||
|
||||
Node* TreeBARSub(Tree* aTree, Node* curnode, int which, int index)
|
||||
{
|
||||
Node* sibling = curnode->parent->child[which];
|
||||
|
||||
if (isRed(sibling))
|
||||
{
|
||||
sibling->red = 0;
|
||||
curnode->parent->red = 1;
|
||||
TreeRotate(aTree, curnode->parent, !which, index);
|
||||
sibling = curnode->parent->child[which];
|
||||
}
|
||||
if (!sibling)
|
||||
curnode = curnode->parent;
|
||||
else if (isBlack(sibling->child[!which]) && isBlack(sibling->child[which]))
|
||||
{
|
||||
sibling->red = 1;
|
||||
curnode = curnode->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isBlack(sibling->child[which]))
|
||||
{
|
||||
sibling->child[!which]->red = 0;
|
||||
sibling->red = 1;
|
||||
TreeRotate(aTree, sibling, which, index);
|
||||
sibling = curnode->parent->child[which];
|
||||
}
|
||||
sibling->red = curnode->parent->red;
|
||||
curnode->parent->red = 0;
|
||||
sibling->child[which]->red = 0;
|
||||
TreeRotate(aTree, curnode->parent, !which, index);
|
||||
curnode = aTree->index[index].root;
|
||||
}
|
||||
return curnode;
|
||||
}
|
||||
|
||||
|
||||
void TreeBalanceAfterRemove(Tree* aTree, Node* curnode, int index)
|
||||
{
|
||||
while (curnode != aTree->index[index].root && isBlack(curnode))
|
||||
{
|
||||
/* curnode->content == NULL must equal curnode == NULL */
|
||||
if (((curnode->content) ? curnode : NULL) == curnode->parent->child[LEFT])
|
||||
curnode = TreeBARSub(aTree, curnode, RIGHT, index);
|
||||
else
|
||||
curnode = TreeBARSub(aTree, curnode, LEFT, index);
|
||||
}
|
||||
curnode->red = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an item from a tree
|
||||
* @param aTree the list to which the item is to be added
|
||||
* @param curnode the list item content itself
|
||||
*/
|
||||
void* TreeRemoveNodeIndex(Tree* aTree, Node* curnode, int index)
|
||||
{
|
||||
Node* redundant = curnode;
|
||||
Node* curchild = NULL;
|
||||
size_t size = curnode->size;
|
||||
void* content = curnode->content;
|
||||
|
||||
/* if the node to remove has 0 or 1 children, it can be removed without involving another node */
|
||||
if (curnode->child[LEFT] && curnode->child[RIGHT]) /* 2 children */
|
||||
redundant = TreeSuccessor(curnode); /* now redundant must have at most one child */
|
||||
|
||||
curchild = redundant->child[(redundant->child[LEFT] != NULL) ? LEFT : RIGHT];
|
||||
if (curchild) /* we could have no children at all */
|
||||
curchild->parent = redundant->parent;
|
||||
|
||||
if (redundant->parent == NULL)
|
||||
aTree->index[index].root = curchild;
|
||||
else
|
||||
{
|
||||
if (redundant == redundant->parent->child[LEFT])
|
||||
redundant->parent->child[LEFT] = curchild;
|
||||
else
|
||||
redundant->parent->child[RIGHT] = curchild;
|
||||
}
|
||||
|
||||
if (redundant != curnode)
|
||||
{
|
||||
curnode->content = redundant->content;
|
||||
curnode->size = redundant->size;
|
||||
}
|
||||
|
||||
if (isBlack(redundant))
|
||||
{
|
||||
if (curchild == NULL)
|
||||
{
|
||||
if (redundant->parent)
|
||||
{
|
||||
Node temp;
|
||||
memset(&temp, '\0', sizeof(Node));
|
||||
temp.parent = redundant->parent;
|
||||
temp.red = 0;
|
||||
TreeBalanceAfterRemove(aTree, &temp, index);
|
||||
}
|
||||
}
|
||||
else
|
||||
TreeBalanceAfterRemove(aTree, curchild, index);
|
||||
}
|
||||
|
||||
#if defined(UNIT_TESTS) || defined(NO_HEAP_TRACKING)
|
||||
free(redundant);
|
||||
#else
|
||||
(aTree->heap_tracking) ? myfree(__FILE__, __LINE__, redundant) : free(redundant);
|
||||
#endif
|
||||
if (index == 0)
|
||||
{
|
||||
aTree->size -= size;
|
||||
--(aTree->count);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an item from a tree
|
||||
* @param aTree the list to which the item is to be added
|
||||
* @param curnode the list item content itself
|
||||
*/
|
||||
void* TreeRemoveIndex(Tree* aTree, void* content, int index)
|
||||
{
|
||||
Node* curnode = TreeFindContentIndex(aTree, content, index);
|
||||
|
||||
if (curnode == NULL)
|
||||
return NULL;
|
||||
|
||||
return TreeRemoveNodeIndex(aTree, curnode, index);
|
||||
}
|
||||
|
||||
|
||||
void* TreeRemove(Tree* aTree, void* content)
|
||||
{
|
||||
int i;
|
||||
void* rc = NULL;
|
||||
|
||||
for (i = 0; i < aTree->indexes; ++i)
|
||||
rc = TreeRemoveIndex(aTree, content, i);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void* TreeRemoveKeyIndex(Tree* aTree, void* key, int index)
|
||||
{
|
||||
Node* curnode = TreeFindIndex(aTree, key, index);
|
||||
void* content = NULL;
|
||||
int i;
|
||||
|
||||
if (curnode == NULL)
|
||||
return NULL;
|
||||
|
||||
content = TreeRemoveNodeIndex(aTree, curnode, index);
|
||||
for (i = 0; i < aTree->indexes; ++i)
|
||||
{
|
||||
if (i != index)
|
||||
content = TreeRemoveIndex(aTree, content, i);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
void* TreeRemoveKey(Tree* aTree, void* key)
|
||||
{
|
||||
return TreeRemoveKeyIndex(aTree, key, 0);
|
||||
}
|
||||
|
||||
|
||||
int TreeIntCompare(void* a, void* b, int content)
|
||||
{
|
||||
int i = *((int*)a);
|
||||
int j = *((int*)b);
|
||||
|
||||
/* printf("comparing %d %d\n", *((int*)a), *((int*)b)); */
|
||||
return (i > j) ? -1 : (i == j) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
int TreePtrCompare(void* a, void* b, int content)
|
||||
{
|
||||
return (a > b) ? -1 : (a == b) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
int TreeStringCompare(void* a, void* b, int content)
|
||||
{
|
||||
return strcmp((char*)a, (char*)b);
|
||||
}
|
||||
|
||||
|
||||
#if defined(UNIT_TESTS)
|
||||
|
||||
int check(Tree *t)
|
||||
{
|
||||
Node* curnode = NULL;
|
||||
int rc = 0;
|
||||
|
||||
curnode = TreeNextElement(t, curnode);
|
||||
while (curnode)
|
||||
{
|
||||
Node* prevnode = curnode;
|
||||
|
||||
curnode = TreeNextElement(t, curnode);
|
||||
|
||||
if (prevnode && curnode && (*(int*)(curnode->content) < *(int*)(prevnode->content)))
|
||||
{
|
||||
printf("out of order %d < %d\n", *(int*)(curnode->content), *(int*)(prevnode->content));
|
||||
rc = 99;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int traverse(Tree *t, int lookfor)
|
||||
{
|
||||
Node* curnode = NULL;
|
||||
int rc = 0;
|
||||
|
||||
printf("Traversing\n");
|
||||
curnode = TreeNextElement(t, curnode);
|
||||
/* printf("content int %d\n", *(int*)(curnode->content)); */
|
||||
while (curnode)
|
||||
{
|
||||
Node* prevnode = curnode;
|
||||
|
||||
curnode = TreeNextElement(t, curnode);
|
||||
/* if (curnode)
|
||||
printf("content int %d\n", *(int*)(curnode->content)); */
|
||||
if (prevnode && curnode && (*(int*)(curnode->content) < *(int*)(prevnode->content)))
|
||||
{
|
||||
printf("out of order %d < %d\n", *(int*)(curnode->content), *(int*)(prevnode->content));
|
||||
}
|
||||
if (curnode && (lookfor == *(int*)(curnode->content)))
|
||||
printf("missing item %d actually found\n", lookfor);
|
||||
}
|
||||
printf("End traverse %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int test(int limit)
|
||||
{
|
||||
int i, *ip, *todelete;
|
||||
Node* current = NULL;
|
||||
Tree* t = TreeInitialize(TreeIntCompare);
|
||||
int rc = 0;
|
||||
|
||||
printf("Tree initialized\n");
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
ip = malloc(sizeof(int));
|
||||
*ip = 2;
|
||||
TreeAdd(t, (void*)ip, sizeof(int));
|
||||
|
||||
check(t);
|
||||
|
||||
i = 2;
|
||||
void* result = TreeRemove(t, (void*)&i);
|
||||
if (result)
|
||||
free(result);
|
||||
|
||||
int actual[limit];
|
||||
for (i = 0; i < limit; i++)
|
||||
{
|
||||
void* replaced = NULL;
|
||||
|
||||
ip = malloc(sizeof(int));
|
||||
*ip = rand();
|
||||
replaced = TreeAdd(t, (void*)ip, sizeof(int));
|
||||
if (replaced) /* duplicate */
|
||||
{
|
||||
free(replaced);
|
||||
actual[i] = -1;
|
||||
}
|
||||
else
|
||||
actual[i] = *ip;
|
||||
if (i==5)
|
||||
todelete = ip;
|
||||
printf("Tree element added %d\n", *ip);
|
||||
if (1 % 1000 == 0)
|
||||
{
|
||||
rc = check(t);
|
||||
printf("%d elements, check result %d\n", i+1, rc);
|
||||
if (rc != 0)
|
||||
return 88;
|
||||
}
|
||||
}
|
||||
|
||||
check(t);
|
||||
|
||||
for (i = 0; i < limit; i++)
|
||||
{
|
||||
int parm = actual[i];
|
||||
|
||||
if (parm == -1)
|
||||
continue;
|
||||
|
||||
Node* found = TreeFind(t, (void*)&parm);
|
||||
if (found)
|
||||
printf("Tree find %d %d\n", parm, *(int*)(found->content));
|
||||
else
|
||||
{
|
||||
printf("%d not found\n", parm);
|
||||
traverse(t, parm);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
check(t);
|
||||
|
||||
for (i = limit -1; i >= 0; i--)
|
||||
{
|
||||
int parm = actual[i];
|
||||
void *found;
|
||||
|
||||
if (parm == -1) /* skip duplicate */
|
||||
continue;
|
||||
|
||||
found = TreeRemove(t, (void*)&parm);
|
||||
if (found)
|
||||
{
|
||||
printf("%d Tree remove %d %d\n", i, parm, *(int*)(found));
|
||||
free(found);
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
printf("%d %d not found\n", i, parm);
|
||||
traverse(t, parm);
|
||||
for (i = 0; i < limit; i++)
|
||||
if (actual[i] == parm)
|
||||
++count;
|
||||
printf("%d occurs %d times\n", parm, count);
|
||||
return -2;
|
||||
}
|
||||
if (i % 1000 == 0)
|
||||
{
|
||||
rc = check(t);
|
||||
printf("%d elements, check result %d\n", i+1, rc);
|
||||
if (rc != 0)
|
||||
return 88;
|
||||
}
|
||||
}
|
||||
printf("finished\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
while (rc == 0)
|
||||
rc = test(999999);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
115
src/mqtt/externals/paho-mqtt-c/src/Tree.h
vendored
Normal file
115
src/mqtt/externals/paho-mqtt-c/src/Tree.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2013 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#if !defined(TREE_H)
|
||||
#define TREE_H
|
||||
|
||||
#include <stdlib.h> /* for size_t definition */
|
||||
|
||||
/*BE
|
||||
defm defTree(T) // macro to define a tree
|
||||
|
||||
def T concat Node
|
||||
{
|
||||
n32 ptr T concat Node "parent"
|
||||
n32 ptr T concat Node "left"
|
||||
n32 ptr T concat Node "right"
|
||||
n32 ptr T id2str(T)
|
||||
n32 suppress "size"
|
||||
}
|
||||
|
||||
|
||||
def T concat Tree
|
||||
{
|
||||
struct
|
||||
{
|
||||
n32 ptr T concat Node suppress "root"
|
||||
n32 ptr DATA suppress "compare"
|
||||
}
|
||||
struct
|
||||
{
|
||||
n32 ptr T concat Node suppress "root"
|
||||
n32 ptr DATA suppress "compare"
|
||||
}
|
||||
n32 dec "count"
|
||||
n32 dec suppress "size"
|
||||
}
|
||||
|
||||
endm
|
||||
|
||||
defTree(INT)
|
||||
defTree(STRING)
|
||||
defTree(TMP)
|
||||
|
||||
BE*/
|
||||
|
||||
/**
|
||||
* Structure to hold all data for one list element
|
||||
*/
|
||||
typedef struct NodeStruct
|
||||
{
|
||||
struct NodeStruct *parent, /**< pointer to parent tree node, in case we need it */
|
||||
*child[2]; /**< pointers to child tree nodes 0 = left, 1 = right */
|
||||
void* content; /**< pointer to element content */
|
||||
size_t size; /**< size of content */
|
||||
unsigned int red : 1;
|
||||
} Node;
|
||||
|
||||
|
||||
/**
|
||||
* Structure to hold all data for one tree
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
Node *root; /**< root node pointer */
|
||||
int (*compare)(void*, void*, int); /**< comparison function */
|
||||
} index[2];
|
||||
int indexes, /**< no of indexes into tree */
|
||||
count; /**< no of items */
|
||||
size_t size; /**< heap storage used */
|
||||
unsigned int heap_tracking : 1; /**< switch on heap tracking for this tree? */
|
||||
unsigned int allow_duplicates : 1; /**< switch to allow duplicate entries */
|
||||
} Tree;
|
||||
|
||||
|
||||
Tree* TreeInitialize(int(*compare)(void*, void*, int));
|
||||
void TreeInitializeNoMalloc(Tree* aTree, int(*compare)(void*, void*, int));
|
||||
void TreeAddIndex(Tree* aTree, int(*compare)(void*, void*, int));
|
||||
|
||||
void* TreeAdd(Tree* aTree, void* content, size_t size);
|
||||
|
||||
void* TreeRemove(Tree* aTree, void* content);
|
||||
|
||||
void* TreeRemoveKey(Tree* aTree, void* key);
|
||||
void* TreeRemoveKeyIndex(Tree* aTree, void* key, int index);
|
||||
|
||||
void* TreeRemoveNodeIndex(Tree* aTree, Node* aNode, int index);
|
||||
|
||||
void TreeFree(Tree* aTree);
|
||||
|
||||
Node* TreeFind(Tree* aTree, void* key);
|
||||
Node* TreeFindIndex(Tree* aTree, void* key, int index);
|
||||
|
||||
Node* TreeNextElement(Tree* aTree, Node* curnode);
|
||||
|
||||
int TreeIntCompare(void* a, void* b, int);
|
||||
int TreePtrCompare(void* a, void* b, int);
|
||||
int TreeStringCompare(void* a, void* b, int);
|
||||
|
||||
#endif
|
||||
7
src/mqtt/externals/paho-mqtt-c/src/VersionInfo.h.in
vendored
Normal file
7
src/mqtt/externals/paho-mqtt-c/src/VersionInfo.h.in
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef VERSIONINFO_H
|
||||
#define VERSIONINFO_H
|
||||
|
||||
#define BUILD_TIMESTAMP "@BUILD_TIMESTAMP@"
|
||||
#define CLIENT_VERSION "@CLIENT_VERSION@"
|
||||
|
||||
#endif /* VERSIONINFO_H */
|
||||
1442
src/mqtt/externals/paho-mqtt-c/src/WebSocket.c
vendored
Normal file
1442
src/mqtt/externals/paho-mqtt-c/src/WebSocket.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
75
src/mqtt/externals/paho-mqtt-c/src/WebSocket.h
vendored
Normal file
75
src/mqtt/externals/paho-mqtt-c/src/WebSocket.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2022 Wind River Systems, Inc. and others. All Rights Reserved.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Keith Holman - initial implementation and documentation
|
||||
* Sven Gambel - move WebSocket proxy support to generic proxy support
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(WEBSOCKET_H)
|
||||
#define WEBSOCKET_H
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
|
||||
/**
|
||||
* WebSocket op codes
|
||||
* @{
|
||||
*/
|
||||
#define WebSocket_OP_CONTINUE 0x0 /* 0000 - continue frame */
|
||||
#define WebSocket_OP_TEXT 0x1 /* 0001 - text frame */
|
||||
#define WebSocket_OP_BINARY 0x2 /* 0010 - binary frame */
|
||||
#define WebSocket_OP_CLOSE 0x8 /* 1000 - close frame */
|
||||
#define WebSocket_OP_PING 0x9 /* 1001 - ping frame */
|
||||
#define WebSocket_OP_PONG 0xA /* 1010 - pong frame */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Various close status codes
|
||||
* @{
|
||||
*/
|
||||
#define WebSocket_CLOSE_NORMAL 1000
|
||||
#define WebSocket_CLOSE_GOING_AWAY 1001
|
||||
#define WebSocket_CLOSE_PROTOCOL_ERROR 1002
|
||||
#define WebSocket_CLOSE_UNKNOWN_DATA 1003
|
||||
#define WebSocket_CLOSE_RESERVED 1004
|
||||
#define WebSocket_CLOSE_NO_STATUS_CODE 1005 /* reserved: not to be used */
|
||||
#define WebSocket_CLOSE_ABNORMAL 1006 /* reserved: not to be used */
|
||||
#define WebSocket_CLOSE_BAD_DATA 1007
|
||||
#define WebSocket_CLOSE_POLICY 1008
|
||||
#define WebSocket_CLOSE_MSG_TOO_BIG 1009
|
||||
#define WebSocket_CLOSE_NO_EXTENSION 1010
|
||||
#define WebScoket_CLOSE_UNEXPECTED 1011
|
||||
#define WebSocket_CLOSE_TLS_FAIL 1015 /* reserved: not be used */
|
||||
/** @} */
|
||||
|
||||
/* closes a websocket connection */
|
||||
void WebSocket_close(networkHandles *net, int status_code, const char *reason);
|
||||
|
||||
/* sends upgrade request */
|
||||
int WebSocket_connect(networkHandles *net, int ssl, const char *uri);
|
||||
|
||||
/* obtain data from network socket */
|
||||
int WebSocket_getch(networkHandles *net, char* c);
|
||||
char *WebSocket_getdata(networkHandles *net, size_t bytes, size_t* actual_len);
|
||||
size_t WebSocket_framePos();
|
||||
void WebSocket_framePosSeekTo(size_t);
|
||||
|
||||
/* send data out, in websocket format only if required */
|
||||
int WebSocket_putdatas(networkHandles* net, char** buf0, size_t* buf0len, PacketBuffers* bufs);
|
||||
|
||||
/* releases any resources used by the websocket system */
|
||||
void WebSocket_terminate(void);
|
||||
|
||||
/* handles websocket upgrade request */
|
||||
int WebSocket_upgrade(networkHandles *net);
|
||||
|
||||
#endif /* WEBSOCKET_H */
|
||||
25
src/mqtt/externals/paho-mqtt-c/src/mutex_type.h
vendored
Normal file
25
src/mqtt/externals/paho-mqtt-c/src/mutex_type.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2018 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
*******************************************************************************/
|
||||
#if !defined(_MUTEX_TYPE_H_)
|
||||
#define _MUTEX_TYPE_H_
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#define mutex_type HANDLE
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#define mutex_type pthread_mutex_t*
|
||||
#endif
|
||||
|
||||
#endif /* _MUTEX_TYPE_H_ */
|
||||
239
src/mqtt/externals/paho-mqtt-c/src/utf-8.c
vendored
Normal file
239
src/mqtt/externals/paho-mqtt-c/src/utf-8.c
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2018 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* \brief Functions for checking that strings contain UTF-8 characters only
|
||||
*
|
||||
* See page 104 of the Unicode Standard 5.0 for the list of well formed
|
||||
* UTF-8 byte sequences.
|
||||
*
|
||||
*/
|
||||
#include "utf-8.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "StackTrace.h"
|
||||
|
||||
/**
|
||||
* Macro to determine the number of elements in a single-dimension array
|
||||
*/
|
||||
#if !defined(ARRAY_SIZE)
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Structure to hold the valid ranges of UTF-8 characters, for each byte up to 4
|
||||
*/
|
||||
struct
|
||||
{
|
||||
int len; /**< number of elements in the following array (1 to 4) */
|
||||
struct
|
||||
{
|
||||
char lower; /**< lower limit of valid range */
|
||||
char upper; /**< upper limit of valid range */
|
||||
} bytes[4]; /**< up to 4 bytes can be used per character */
|
||||
}
|
||||
valid_ranges[] =
|
||||
{
|
||||
{1, { {00, 0x7F} } },
|
||||
{2, { {0xC2, 0xDF}, {0x80, 0xBF} } },
|
||||
{3, { {0xE0, 0xE0}, {0xA0, 0xBF}, {0x80, 0xBF} } },
|
||||
{3, { {0xE1, 0xEC}, {0x80, 0xBF}, {0x80, 0xBF} } },
|
||||
{3, { {0xED, 0xED}, {0x80, 0x9F}, {0x80, 0xBF} } },
|
||||
{3, { {0xEE, 0xEF}, {0x80, 0xBF}, {0x80, 0xBF} } },
|
||||
{4, { {0xF0, 0xF0}, {0x90, 0xBF}, {0x80, 0xBF}, {0x80, 0xBF} } },
|
||||
{4, { {0xF1, 0xF3}, {0x80, 0xBF}, {0x80, 0xBF}, {0x80, 0xBF} } },
|
||||
{4, { {0xF4, 0xF4}, {0x80, 0x8F}, {0x80, 0xBF}, {0x80, 0xBF} } },
|
||||
};
|
||||
|
||||
|
||||
static const char* UTF8_char_validate(int len, const char* data);
|
||||
|
||||
|
||||
/**
|
||||
* Validate a single UTF-8 character
|
||||
* @param len the length of the string in "data"
|
||||
* @param data the bytes to check for a valid UTF-8 char
|
||||
* @return pointer to the start of the next UTF-8 character in "data"
|
||||
*/
|
||||
static const char* UTF8_char_validate(int len, const char* data)
|
||||
{
|
||||
int good = 0;
|
||||
int charlen = 2;
|
||||
int i, j;
|
||||
const char *rc = NULL;
|
||||
|
||||
if (data == NULL)
|
||||
goto exit; /* don't have data, can't continue */
|
||||
|
||||
/* first work out how many bytes this char is encoded in */
|
||||
if ((data[0] & 128) == 0)
|
||||
charlen = 1;
|
||||
else if ((data[0] & 0xF0) == 0xF0)
|
||||
charlen = 4;
|
||||
else if ((data[0] & 0xE0) == 0xE0)
|
||||
charlen = 3;
|
||||
|
||||
if (charlen > len)
|
||||
goto exit; /* not enough characters in the string we were given */
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(valid_ranges); ++i)
|
||||
{ /* just has to match one of these rows */
|
||||
if (valid_ranges[i].len == charlen)
|
||||
{
|
||||
good = 1;
|
||||
for (j = 0; j < charlen; ++j)
|
||||
{
|
||||
if (data[j] < valid_ranges[i].bytes[j].lower ||
|
||||
data[j] > valid_ranges[i].bytes[j].upper)
|
||||
{
|
||||
good = 0; /* failed the check */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (good)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (good)
|
||||
rc = data + charlen;
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate a length-delimited string has only UTF-8 characters
|
||||
* @param len the length of the string in "data"
|
||||
* @param data the bytes to check for valid UTF-8 characters
|
||||
* @return 1 (true) if the string has only UTF-8 characters, 0 (false) otherwise
|
||||
*/
|
||||
int UTF8_validate(int len, const char* data)
|
||||
{
|
||||
const char* curdata = NULL;
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (len == 0 || data == NULL)
|
||||
{
|
||||
rc = 1;
|
||||
goto exit;
|
||||
}
|
||||
curdata = UTF8_char_validate(len, data);
|
||||
while (curdata && (curdata < data + len))
|
||||
curdata = UTF8_char_validate((int)(data + len - curdata), curdata);
|
||||
|
||||
rc = curdata != NULL;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate a null-terminated string has only UTF-8 characters
|
||||
* @param string the string to check for valid UTF-8 characters
|
||||
* @return 1 (true) if the string has only UTF-8 characters, 0 (false) otherwise
|
||||
*/
|
||||
int UTF8_validateString(const char* string)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (string != NULL)
|
||||
{
|
||||
rc = UTF8_validate((int)strlen(string), string);
|
||||
}
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(UNIT_TESTS)
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
char data[20];
|
||||
} tests;
|
||||
|
||||
tests valid_strings[] =
|
||||
{
|
||||
{3, "hjk" },
|
||||
{7, {0x41, 0xE2, 0x89, 0xA2, 0xCE, 0x91, 0x2E} },
|
||||
{3, {'f', 0xC9, 0xB1 } },
|
||||
{9, {0xED, 0x95, 0x9C, 0xEA, 0xB5, 0xAD, 0xEC, 0x96, 0xB4} },
|
||||
{9, {0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E} },
|
||||
{4, {0x2F, 0x2E, 0x2E, 0x2F} },
|
||||
{7, {0xEF, 0xBB, 0xBF, 0xF0, 0xA3, 0x8E, 0xB4} },
|
||||
};
|
||||
|
||||
tests invalid_strings[] =
|
||||
{
|
||||
{2, {0xC0, 0x80} },
|
||||
{5, {0x2F, 0xC0, 0xAE, 0x2E, 0x2F} },
|
||||
{6, {0xED, 0xA1, 0x8C, 0xED, 0xBE, 0xB4} },
|
||||
{1, {0xF4} },
|
||||
};
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int i, failed = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(valid_strings); ++i)
|
||||
{
|
||||
if (!UTF8_validate(valid_strings[i].len, valid_strings[i].data))
|
||||
{
|
||||
printf("valid test %d failed\n", i);
|
||||
failed = 1;
|
||||
}
|
||||
else
|
||||
printf("valid test %d passed\n", i);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(invalid_strings); ++i)
|
||||
{
|
||||
if (UTF8_validate(invalid_strings[i].len, invalid_strings[i].data))
|
||||
{
|
||||
printf("invalid test %d failed\n", i);
|
||||
failed = 1;
|
||||
}
|
||||
else
|
||||
printf("invalid test %d passed\n", i);
|
||||
}
|
||||
|
||||
if (failed)
|
||||
printf("Failed\n");
|
||||
else
|
||||
printf("Passed\n");
|
||||
|
||||
//Don't crash on null data
|
||||
UTF8_validateString(NULL);
|
||||
UTF8_validate(1, NULL);
|
||||
UTF8_char_validate(1, NULL);
|
||||
|
||||
return 0;
|
||||
} /* End of main function*/
|
||||
|
||||
#endif
|
||||
|
||||
23
src/mqtt/externals/paho-mqtt-c/src/utf-8.h
vendored
Normal file
23
src/mqtt/externals/paho-mqtt-c/src/utf-8.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2013 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(UTF8_H)
|
||||
#define UTF8_H
|
||||
|
||||
int UTF8_validate(int len, const char *data);
|
||||
int UTF8_validateString(const char* string);
|
||||
|
||||
#endif
|
||||
12
src/mqtt/externals/paho-mqtt-c/test_package/CMakeLists.txt
vendored
Normal file
12
src/mqtt/externals/paho-mqtt-c/test_package/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
project(test_package C)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
|
||||
file(GLOB SOURCE_FILES *.c)
|
||||
|
||||
message("LIBS: ${CONAN_LIBS}")
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
||||
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
|
||||
26
src/mqtt/externals/paho-mqtt-c/test_package/conanfile.py
vendored
Normal file
26
src/mqtt/externals/paho-mqtt-c/test_package/conanfile.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
from conans import ConanFile, CMake, tools, RunEnvironment
|
||||
import os
|
||||
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "cmake"
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def imports(self):
|
||||
self.copy("*paho*.dll", dst="bin", src="bin")
|
||||
self.copy("*paho*.dylib*", dst="bin", src="lib")
|
||||
|
||||
def test(self):
|
||||
with tools.environment_append(RunEnvironment(self).vars):
|
||||
bin_path = os.path.join("bin", "test_package")
|
||||
if self.settings.os == "Windows":
|
||||
self.run(bin_path)
|
||||
elif self.settings.os == "Macos":
|
||||
self.run("DYLD_LIBRARY_PATH=%s %s" % (os.environ.get('DYLD_LIBRARY_PATH', ''), bin_path))
|
||||
else:
|
||||
self.run("LD_LIBRARY_PATH=%s %s" % (os.environ.get('LD_LIBRARY_PATH', ''), bin_path))
|
||||
58
src/mqtt/externals/paho-mqtt-c/test_package/test_package.c
vendored
Normal file
58
src/mqtt/externals/paho-mqtt-c/test_package/test_package.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "MQTTClient.h"
|
||||
|
||||
#define ADDRESS "tcp://localhost:1883"
|
||||
#define CLIENTID "ExampleClientSub"
|
||||
#define TOPIC "MQTT Examples"
|
||||
#define PAYLOAD "Hello World!"
|
||||
#define QOS 1
|
||||
#define TIMEOUT 10000L
|
||||
|
||||
volatile MQTTClient_deliveryToken deliveredtoken;
|
||||
|
||||
void delivered(void *context, MQTTClient_deliveryToken dt)
|
||||
{
|
||||
printf("Message with token value %d delivery confirmed\n", dt);
|
||||
deliveredtoken = dt;
|
||||
}
|
||||
|
||||
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
|
||||
{
|
||||
int i;
|
||||
char *payloadptr;
|
||||
printf("Message arrived\n");
|
||||
printf(" topic: %s\n", topicName);
|
||||
printf(" message: ");
|
||||
payloadptr = message->payload;
|
||||
for (i = 0; i < message->payloadlen; i++)
|
||||
{
|
||||
putchar(*payloadptr++);
|
||||
}
|
||||
putchar('\n');
|
||||
MQTTClient_freeMessage(&message);
|
||||
MQTTClient_free(topicName);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void connlost(void *context, char *cause)
|
||||
{
|
||||
printf("\nConnection lost\n");
|
||||
printf(" cause: %s\n", cause);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("\nCreating MQTTClient\n");
|
||||
MQTTClient client;
|
||||
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
|
||||
MQTTClient_create(&client, ADDRESS, CLIENTID,
|
||||
MQTTCLIENT_PERSISTENCE_NONE, NULL);
|
||||
conn_opts.keepAliveInterval = 20;
|
||||
conn_opts.cleansession = 1;
|
||||
MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
|
||||
MQTTClient_destroy(&client);
|
||||
printf("\nExiting\n");
|
||||
return 0;
|
||||
}
|
||||
1
src/mqtt/externals/paho-mqtt-c/version.major
vendored
Normal file
1
src/mqtt/externals/paho-mqtt-c/version.major
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
1
src/mqtt/externals/paho-mqtt-c/version.minor
vendored
Normal file
1
src/mqtt/externals/paho-mqtt-c/version.minor
vendored
Normal file
@@ -0,0 +1 @@
|
||||
3
|
||||
1
src/mqtt/externals/paho-mqtt-c/version.patch
vendored
Normal file
1
src/mqtt/externals/paho-mqtt-c/version.patch
vendored
Normal file
@@ -0,0 +1 @@
|
||||
13
|
||||
51
src/mqtt/include/mqtt/CMakeLists.txt
Normal file
51
src/mqtt/include/mqtt/CMakeLists.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
#*******************************************************************************
|
||||
# Copyright (c) 2016-2024
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v2.0
|
||||
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at
|
||||
# http://www.eclipse.org/legal/epl-v20.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Guilherme Maciel Ferreira - initial version
|
||||
# Frank Pagliughi
|
||||
#*******************************************************************************/
|
||||
|
||||
install(
|
||||
FILES
|
||||
async_client.h
|
||||
buffer_ref.h
|
||||
buffer_view.h
|
||||
callback.h
|
||||
client.h
|
||||
connect_options.h
|
||||
create_options.h
|
||||
delivery_token.h
|
||||
disconnect_options.h
|
||||
exception.h
|
||||
export.h
|
||||
iaction_listener.h
|
||||
iasync_client.h
|
||||
iclient_persistence.h
|
||||
message.h
|
||||
platform.h
|
||||
properties.h
|
||||
response_options.h
|
||||
server_response.h
|
||||
ssl_options.h
|
||||
string_collection.h
|
||||
subscribe_options.h
|
||||
thread_queue.h
|
||||
token.h
|
||||
topic_matcher.h
|
||||
topic.h
|
||||
types.h
|
||||
will_options.h
|
||||
DESTINATION
|
||||
include/mqtt
|
||||
)
|
||||
|
||||
820
src/mqtt/include/mqtt/async_client.h
Normal file
820
src/mqtt/include/mqtt/async_client.h
Normal file
@@ -0,0 +1,820 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file async_client.h
|
||||
/// Declaration of MQTT async_client class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2024 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
* Frank Pagliughi - MQTT v5 support
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_async_client_h
|
||||
#define __mqtt_async_client_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
#include "mqtt/token.h"
|
||||
#include "mqtt/create_options.h"
|
||||
#include "mqtt/string_collection.h"
|
||||
#include "mqtt/delivery_token.h"
|
||||
#include "mqtt/iclient_persistence.h"
|
||||
#include "mqtt/iaction_listener.h"
|
||||
#include "mqtt/properties.h"
|
||||
#include "mqtt/exception.h"
|
||||
#include "mqtt/message.h"
|
||||
#include "mqtt/callback.h"
|
||||
#include "mqtt/thread_queue.h"
|
||||
#include "mqtt/iasync_client.h"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
// OBSOLETE: The legacy constants that lacked the "PAHO_MQTTPP_" prefix
|
||||
// clashed with #define's from other libraries and will be removed at the
|
||||
// next major version upgrade.
|
||||
|
||||
#if defined(PAHO_MQTTPP_VERSIONS)
|
||||
/** The version number for the client library. */
|
||||
const uint32_t PAHO_MQTTPP_VERSION = 0x01040000;
|
||||
/** The version string for the client library */
|
||||
const string PAHO_MQTTPP_VERSION_STR("Paho MQTT C++ (mqttpp) v. 1.4.0");
|
||||
/** Copyright notice for the client library */
|
||||
const string PAHO_MQTTPP_COPYRIGHT("Copyright (c) 2013-2024 Frank Pagliughi");
|
||||
#else
|
||||
/** The version number for the client library. */
|
||||
const uint32_t VERSION = 0x01040000;
|
||||
/** The version string for the client library */
|
||||
const string VERSION_STR("Paho MQTT C++ (mqttpp) v. 1.4.0");
|
||||
/** Copyright notice for the client library */
|
||||
const string COPYRIGHT("Copyright (c) 2013-2024 Frank Pagliughi");
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Client for talking to an MQTT server using non-blocking
|
||||
* methods that allow an operation to run in the background.
|
||||
*
|
||||
* The location of the server is specified as a URI string with the
|
||||
* following schemas supported to specify the type and security used for the
|
||||
* connection:
|
||||
* @li @em "mqtt://" - A standard (insecure) connection over TCP. (Also,
|
||||
* "tcp://")
|
||||
* @li @em "mqtts://" - A secure connection using SSL/TLS sockets. (Also
|
||||
* "ssl://")
|
||||
* @li @em "ws://" - A standard (insecure) WebSocket connection.
|
||||
* @li @em "wss:// - A secure websocket connection using SSL/TLS.
|
||||
*
|
||||
* The secure connection types assume that the library was built with
|
||||
* OpenSSL support, otherwise requesting a secure connection will result in
|
||||
* an error.
|
||||
*
|
||||
* The communication methods of this class - `connect()`, `publish()`,
|
||||
* `subscribe()`, etc. - are all asynchronous. They create the request for
|
||||
* the server, but return immediately, before a response is received back
|
||||
* from the server.
|
||||
*
|
||||
* These methods return a `Token` to the caller which is akin to a C++
|
||||
* std::future. The caller can keep the Token, then use it later to block
|
||||
* until the asynchronous operation is complete and retrieve the result of
|
||||
* the operation, including any response from the server.
|
||||
*
|
||||
* Alternately, the application can choose to set callbacks to be fired when
|
||||
* each operation completes. This can be used to create an event-driven
|
||||
* architecture, but is more complex in that it forces the user to avoid any
|
||||
* blocking operations and manually handle thread synchronization (since
|
||||
* the callbacks run in a separate thread managed by the library).
|
||||
*/
|
||||
class async_client : public virtual iasync_client
|
||||
{
|
||||
public:
|
||||
/** Smart/shared pointer for an object of this class */
|
||||
using ptr_t = std::shared_ptr<async_client>;
|
||||
/** Type for a thread-safe queue to consume messages synchronously */
|
||||
using consumer_queue_type = std::unique_ptr<thread_queue<const_message_ptr>>;
|
||||
|
||||
/** Handler type for registering an individual message callback */
|
||||
using message_handler = std::function<void(const_message_ptr)>;
|
||||
/** Handler type for when a connection is made or lost */
|
||||
using connection_handler = std::function<void(const string& cause)>;
|
||||
/** Handler type for when a disconnect packet is received */
|
||||
using disconnected_handler = std::function<void(const properties&, ReasonCode)>;
|
||||
/** Handler for updating connection data before an auto-reconnect. */
|
||||
using update_connection_handler = std::function<bool(connect_data&)>;
|
||||
|
||||
private:
|
||||
/** Lock guard type for this class */
|
||||
using guard = std::unique_lock<std::mutex>;
|
||||
/** Unique lock type for this class */
|
||||
using unique_lock = std::unique_lock<std::mutex>;
|
||||
|
||||
/** Object monitor mutex */
|
||||
mutable std::mutex lock_;
|
||||
/** The underlying C-lib client. */
|
||||
MQTTAsync cli_;
|
||||
/** The server URI string. */
|
||||
string serverURI_;
|
||||
/** The client ID string that we provided to the server. */
|
||||
string clientId_;
|
||||
/** The MQTT protocol version we're connected at */
|
||||
int mqttVersion_;
|
||||
/** A user persistence wrapper (if any) */
|
||||
std::unique_ptr<MQTTClient_persistence> persist_;
|
||||
/** Callback supplied by the user (if any) */
|
||||
callback* userCallback_;
|
||||
/** Connection handler */
|
||||
connection_handler connHandler_;
|
||||
/** Connection lost handler */
|
||||
connection_handler connLostHandler_;
|
||||
/** Disconnected handler */
|
||||
disconnected_handler disconnectedHandler_;
|
||||
/** Update connect data/options */
|
||||
update_connection_handler updateConnectionHandler_;
|
||||
/** Message handler */
|
||||
message_handler msgHandler_;
|
||||
/** Cached options from the last connect */
|
||||
connect_options connOpts_;
|
||||
/** Copy of connect token (for re-connects) */
|
||||
token_ptr connTok_;
|
||||
/** A list of tokens that are in play */
|
||||
std::list<token_ptr> pendingTokens_;
|
||||
/** A list of delivery tokens that are in play */
|
||||
std::list<delivery_token_ptr> pendingDeliveryTokens_;
|
||||
/** A queue of messages for consumer API */
|
||||
consumer_queue_type que_;
|
||||
|
||||
/** Callbacks from the C library */
|
||||
static void on_connected(void* context, char* cause);
|
||||
static void on_connection_lost(void *context, char *cause);
|
||||
static void on_disconnected(void* context, MQTTProperties* cprops,
|
||||
MQTTReasonCodes reasonCode);
|
||||
static int on_message_arrived(void* context, char* topicName, int topicLen,
|
||||
MQTTAsync_message* msg);
|
||||
static void on_delivery_complete(void* context, MQTTAsync_token tok);
|
||||
static int on_update_connection(void* context, MQTTAsync_connectData* cdata);
|
||||
|
||||
/** Manage internal list of active tokens */
|
||||
friend class token;
|
||||
virtual void add_token(token_ptr tok);
|
||||
virtual void add_token(delivery_token_ptr tok);
|
||||
virtual void remove_token(token* tok) override;
|
||||
virtual void remove_token(token_ptr tok) { remove_token(tok.get()); }
|
||||
void remove_token(delivery_token_ptr tok) { remove_token(tok.get()); }
|
||||
|
||||
/** Non-copyable */
|
||||
async_client() =delete;
|
||||
async_client(const async_client&) =delete;
|
||||
async_client& operator=(const async_client&) =delete;
|
||||
|
||||
/** Checks a function return code and throws on error. */
|
||||
static void check_ret(int rc) {
|
||||
if (rc != MQTTASYNC_SUCCESS)
|
||||
throw exception(rc);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server.
|
||||
* This uses file-based persistence in the specified directory.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param persistDir The directory to use for persistence data
|
||||
* @throw exception if an argument is invalid
|
||||
*/
|
||||
async_client(const string& serverURI, const string& clientId,
|
||||
const string& persistDir);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server.
|
||||
* This allows the caller to specify a user-defined persistence object,
|
||||
* or use no persistence.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param persistence The user persistence structure. If this is null,
|
||||
* then no persistence is used.
|
||||
* @throw exception if an argument is invalid
|
||||
*/
|
||||
async_client(const string& serverURI, const string& clientId,
|
||||
iclient_persistence* persistence=nullptr);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server, which allows for off-line message buffering.
|
||||
* This uses file-based persistence in the specified directory.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param maxBufferedMessages the maximum number of messages allowed to
|
||||
* be buffered while not connected
|
||||
* @param persistDir The directory to use for persistence data
|
||||
* @throw exception if an argument is invalid
|
||||
*/
|
||||
async_client(const string& serverURI, const string& clientId,
|
||||
int maxBufferedMessages, const string& persistDir);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server, which allows for off-line message buffering.
|
||||
* This allows the caller to specify a user-defined persistence object,
|
||||
* or use no persistence.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param maxBufferedMessages the maximum number of messages allowed to
|
||||
* be buffered while not connected
|
||||
* @param persistence The user persistence structure. If this is null,
|
||||
* then no persistence is used.
|
||||
* @throw exception if an argument is invalid
|
||||
*/
|
||||
async_client(const string& serverURI, const string& clientId,
|
||||
int maxBufferedMessages,
|
||||
iclient_persistence* persistence=nullptr);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server, which allows for off-line message buffering.
|
||||
* This uses file-based persistence in the specified directory.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param opts The create options
|
||||
* @param persistDir The directory to use for persistence data
|
||||
* @throw exception if an argument is invalid
|
||||
*/
|
||||
async_client(const string& serverURI, const string& clientId,
|
||||
const create_options& opts, const string& persistDir);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server, which allows for off-line message buffering.
|
||||
* This allows the caller to specify a user-defined persistence object,
|
||||
* or use no persistence.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param opts The create options
|
||||
* @param persistence The user persistence structure. If this is null,
|
||||
* then no persistence is used.
|
||||
* @throw exception if an argument is invalid
|
||||
*/
|
||||
async_client(const string& serverURI, const string& clientId,
|
||||
const create_options& opts,
|
||||
iclient_persistence* persistence=nullptr);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~async_client() override;
|
||||
/**
|
||||
* Sets a callback listener to use for events that happen
|
||||
* asynchronously.
|
||||
* @param cb callback receiver which will be invoked for certain
|
||||
* asynchronous events
|
||||
*/
|
||||
void set_callback(callback& cb) override;
|
||||
/**
|
||||
* Stops callbacks.
|
||||
* This is not normally called by the application. It should be used
|
||||
* cautiously as it may cause the application to lose messages.
|
||||
*/
|
||||
void disable_callbacks() override;
|
||||
/**
|
||||
* Callback for when a connection is made.
|
||||
* @param cb Callback functor for when the connection is made.
|
||||
*/
|
||||
void set_connected_handler(connection_handler cb) /*override*/;
|
||||
/**
|
||||
* Callback for when a connection is lost.
|
||||
* @param cb Callback functor for when the connection is lost.
|
||||
*/
|
||||
void set_connection_lost_handler(connection_handler cb) /*override*/;
|
||||
/**
|
||||
* Callback for when a disconnect packet is received from the server.
|
||||
* @param cb Callback for when the disconnect packet is received.
|
||||
*/
|
||||
void set_disconnected_handler(disconnected_handler cb) /*override*/;
|
||||
/**
|
||||
* Sets the callback for when a message arrives from the broker.
|
||||
* Note that the application can only have one message handler which can
|
||||
* be installed individually using this method, or installled as a
|
||||
* listener object.
|
||||
* @param cb The callback functor to register with the library.
|
||||
*/
|
||||
void set_message_callback(message_handler cb) /*override*/;
|
||||
/**
|
||||
* Sets a callback to allow the application to update the connection
|
||||
* data on automatic reconnects.
|
||||
* @param cb The callback functor to register with the library.
|
||||
*/
|
||||
void set_update_connection_handler(update_connection_handler cb);
|
||||
/**
|
||||
* Connects to an MQTT server using the default options.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
token_ptr connect() override;
|
||||
/**
|
||||
* Connects to an MQTT server using the provided connect options.
|
||||
* @param options a set of connection parameters that override the
|
||||
* defaults.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
token_ptr connect(connect_options options) override;
|
||||
/**
|
||||
* Connects to an MQTT server using the specified options.
|
||||
* @param options a set of connection parameters that override the
|
||||
* defaults.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback listener that will be notified when the connect
|
||||
* completes.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
token_ptr connect(connect_options options, void* userContext,
|
||||
iaction_listener& cb) override;
|
||||
/**
|
||||
*
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback listener that will be notified when the connect
|
||||
* completes.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
token_ptr connect(void* userContext, iaction_listener& cb) override {
|
||||
return connect(connect_options{}, userContext, cb);
|
||||
}
|
||||
/**
|
||||
* Reconnects the client using options from the previous connect.
|
||||
* The client must have previously called connect() for this to work.
|
||||
* @return token used to track the progress of the reconnect.
|
||||
*/
|
||||
token_ptr reconnect() override;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
token_ptr disconnect() override { return disconnect(disconnect_options()); }
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param opts Options for disconnecting.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
token_ptr disconnect(disconnect_options opts) override;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeout the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
* @return Token used to track and wait for disconnect to complete. The
|
||||
* token will be passed to the callback methods if a callback is
|
||||
* set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
token_ptr disconnect(int timeout) override {
|
||||
return disconnect(disconnect_options(timeout));
|
||||
}
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeout the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
* @return Token used to track and wait for disconnect to complete. The
|
||||
* token will be passed to the callback methods if a callback is
|
||||
* set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
token_ptr disconnect(const std::chrono::duration<Rep, Period>& timeout) {
|
||||
// TODO: check range
|
||||
return disconnect((int) to_milliseconds_count(timeout));
|
||||
}
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeout the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback listener that will be notified when the disconnect
|
||||
* completes.
|
||||
* @return token_ptr Token used to track and wait for disconnect to
|
||||
* complete. The token will be passed to the callback methods if
|
||||
* a callback is set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
token_ptr disconnect(int timeout, void* userContext,
|
||||
iaction_listener& cb) override;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeout the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback listener that will be notified when the disconnect
|
||||
* completes.
|
||||
* @return token_ptr Token used to track and wait for disconnect to
|
||||
* complete. The token will be passed to the callback methods if
|
||||
* a callback is set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
token_ptr disconnect(const std::chrono::duration<Rep, Period>& timeout,
|
||||
void* userContext, iaction_listener& cb) {
|
||||
// TODO: check range
|
||||
return disconnect((int) to_milliseconds_count(timeout), userContext, cb);
|
||||
}
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback listener that will be notified when the disconnect
|
||||
* completes.
|
||||
* @return token_ptr Token used to track and wait for disconnect to
|
||||
* complete. The token will be passed to the callback methods if
|
||||
* a callback is set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
token_ptr disconnect(void* userContext, iaction_listener& cb) override {
|
||||
return disconnect(0L, userContext, cb);
|
||||
}
|
||||
/**
|
||||
* Returns the delivery token for the specified message ID.
|
||||
* @return delivery_token
|
||||
*/
|
||||
delivery_token_ptr get_pending_delivery_token(int msgID) const override;
|
||||
/**
|
||||
* Returns the delivery tokens for any outstanding publish operations.
|
||||
* @return delivery_token[]
|
||||
*/
|
||||
std::vector<delivery_token_ptr> get_pending_delivery_tokens() const override;
|
||||
/**
|
||||
* Returns the client ID used by this client.
|
||||
* @return The client ID used by this client.
|
||||
*/
|
||||
string get_client_id() const override { return clientId_; }
|
||||
/**
|
||||
* Returns the address of the server used by this client.
|
||||
* @return The server's address, as a URI String.
|
||||
*/
|
||||
string get_server_uri() const override { return serverURI_; }
|
||||
/**
|
||||
* Gets the MQTT version used by the client.
|
||||
* @return The MQTT version used by the client
|
||||
* @li MQTTVERSION_DEFAULT (0) = default: start with 3.1.1, and if
|
||||
* that fails, fall back to 3.1
|
||||
* @li MQTTVERSION_3_1 (3) = only try version 3.1
|
||||
* @li MQTTVERSION_3_1_1 (4) = only try version 3.1.1
|
||||
* @li MQTTVERSION_5 (5) = only try version 5
|
||||
*/
|
||||
int mqtt_version() const noexcept { return mqttVersion_; }
|
||||
/**
|
||||
* Gets a copy of the connect options that were last used in a request
|
||||
* to connect to the broker.
|
||||
* @returns The last connect options that were used.
|
||||
*/
|
||||
connect_options get_connect_options() const {
|
||||
guard g(lock_);
|
||||
return connOpts_;
|
||||
}
|
||||
/**
|
||||
* Determines if this client is currently connected to the server.
|
||||
* @return true if connected, false otherwise.
|
||||
*/
|
||||
bool is_connected() const override { return to_bool(MQTTAsync_isConnected(cli_)); }
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
* @param qos the Quality of Service to deliver the message at. Valid
|
||||
* values are 0, 1 or 2.
|
||||
* @param retained whether or not this message should be retained by the
|
||||
* server.
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(string_ref topic, const void* payload, size_t n,
|
||||
int qos, bool retained) override;
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(string_ref topic, const void* payload, size_t n) override {
|
||||
return publish(std::move(topic), payload, n,
|
||||
message::DFLT_QOS, message::DFLT_RETAINED);
|
||||
}
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param qos the Quality of Service to deliver the message at. Valid
|
||||
* values are 0, 1 or 2.
|
||||
* @param retained whether or not this message should be retained by the
|
||||
* server.
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(string_ref topic, binary_ref payload,
|
||||
int qos, bool retained) override;
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(string_ref topic, binary_ref payload) override {
|
||||
return publish(std::move(topic), std::move(payload),
|
||||
message::DFLT_QOS, message::DFLT_RETAINED);
|
||||
}
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
* @param qos the Quality of Service to deliver the message at. Valid
|
||||
* values are 0, 1 or 2.
|
||||
* @param retained whether or not this message should be retained by the
|
||||
* server.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(string_ref topic,
|
||||
const void* payload, size_t n,
|
||||
int qos, bool retained,
|
||||
void* userContext, iaction_listener& cb) override;
|
||||
/**
|
||||
* Publishes a message to a topic on the server Takes an Message
|
||||
* message and delivers it to the server at the requested quality of
|
||||
* service.
|
||||
* @param msg the message to deliver to the server
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(const_message_ptr msg) override;
|
||||
/**
|
||||
* Publishes a message to a topic on the server.
|
||||
* @param msg the message to deliver to the server
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback optional listener that will be notified when message
|
||||
* delivery has completed to the requested quality of
|
||||
* service
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
delivery_token_ptr publish(const_message_ptr msg,
|
||||
void* userContext, iaction_listener& cb) override;
|
||||
/**
|
||||
* Subscribe to a topic, which may include wildcards.
|
||||
* @param topicFilter the topic to subscribe to, which can include
|
||||
* wildcards.
|
||||
* @param qos The quality of service for the subscription
|
||||
* @param opts The MQTT v5 subscribe options for the topic
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr subscribe(const string& topicFilter, int qos,
|
||||
const subscribe_options& opts=subscribe_options(),
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Subscribe to a topic, which may include wildcards.
|
||||
* @param topicFilter the topic to subscribe to, which can include
|
||||
* wildcards.
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when subscribe has completed
|
||||
* @param opts The MQTT v5 subscribe options for the topic
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr subscribe(const string& topicFilter, int qos,
|
||||
void* userContext, iaction_listener& cb,
|
||||
const subscribe_options& opts=subscribe_options(),
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Subscribe to multiple topics, each of which may include wildcards.
|
||||
* @param topicFilters
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param opts The MQTT v5 subscribe options (one for each topic)
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr subscribe(const_string_collection_ptr topicFilters,
|
||||
const qos_collection& qos,
|
||||
const std::vector<subscribe_options>& opts=std::vector<subscribe_options>(),
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Subscribes to multiple topics, each of which may include wildcards.
|
||||
* @param topicFilters
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when subscribe has completed
|
||||
* @param opts The MQTT v5 subscribe options (one for each topic)
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr subscribe(const_string_collection_ptr topicFilters,
|
||||
const qos_collection& qos,
|
||||
void* userContext, iaction_listener& cb,
|
||||
const std::vector<subscribe_options>& opts=std::vector<subscribe_options>(),
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from a topic.
|
||||
* @param topicFilter the topic to unsubscribe from. It must match a
|
||||
* topicFilter specified on an earlier subscribe.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr unsubscribe(const string& topicFilter,
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from one or more topics.
|
||||
* @param topicFilters one or more topics to unsubscribe from. Each
|
||||
* topicFilter must match one specified on an
|
||||
* earlier subscribe.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr unsubscribe(const_string_collection_ptr topicFilters,
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from one or more topics.
|
||||
* @param topicFilters
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when unsubscribe has
|
||||
* completed
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr unsubscribe(const_string_collection_ptr topicFilters,
|
||||
void* userContext, iaction_listener& cb,
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from a topics.
|
||||
* @param topicFilter the topic to unsubscribe from. It must match a
|
||||
* topicFilter specified on an earlier subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when unsubscribe has
|
||||
* completed
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
token_ptr unsubscribe(const string& topicFilter,
|
||||
void* userContext, iaction_listener& cb,
|
||||
const properties& props=properties()) override;
|
||||
/**
|
||||
* Start consuming messages.
|
||||
* This initializes the client to receive messages through a queue that
|
||||
* can be read synchronously.
|
||||
*/
|
||||
void start_consuming() override;
|
||||
/**
|
||||
* Stop consuming messages.
|
||||
* This shuts down the internal callback and discards any unread
|
||||
* messages.
|
||||
*/
|
||||
void stop_consuming() override;
|
||||
/**
|
||||
* Read the next message from the queue.
|
||||
* This blocks until a new message arrives.
|
||||
* @return The message and topic.
|
||||
*/
|
||||
const_message_ptr consume_message() override { return que_->get(); }
|
||||
/**
|
||||
* Try to read the next message from the queue without blocking.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @return @em true is a message was read, @em false if no message was
|
||||
* available.
|
||||
*/
|
||||
bool try_consume_message(const_message_ptr* msg) override {
|
||||
return que_->try_get(msg);
|
||||
}
|
||||
/**
|
||||
* Waits a limited time for a message to arrive.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @param relTime The maximum amount of time to wait for a message.
|
||||
* @return @em true if a message was read, @em false if a timeout
|
||||
* occurred.
|
||||
*/
|
||||
template <typename Rep, class Period>
|
||||
bool try_consume_message_for(const_message_ptr* msg,
|
||||
const std::chrono::duration<Rep, Period>& relTime) {
|
||||
return que_->try_get_for(msg, relTime);
|
||||
}
|
||||
/**
|
||||
* Waits a limited time for a message to arrive.
|
||||
* @param relTime The maximum amount of time to wait for a message.
|
||||
* @return A shared pointer to the message that was received. It will be
|
||||
* empty on timeout.
|
||||
*/
|
||||
template <typename Rep, class Period>
|
||||
const_message_ptr try_consume_message_for(const std::chrono::duration<Rep, Period>& relTime) {
|
||||
const_message_ptr msg;
|
||||
que_->try_get_for(&msg, relTime);
|
||||
return msg;
|
||||
}
|
||||
/**
|
||||
* Waits until a specific time for a message to appear.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @param absTime The time point to wait until, before timing out.
|
||||
* @return @em true if a message was read, @em false if a timeout
|
||||
* occurred.
|
||||
*/
|
||||
template <class Clock, class Duration>
|
||||
bool try_consume_message_until(const_message_ptr* msg,
|
||||
const std::chrono::time_point<Clock,Duration>& absTime) {
|
||||
return que_->try_get_until(msg, absTime);
|
||||
}
|
||||
/**
|
||||
* Waits until a specific time for a message to appear.
|
||||
* @param absTime The time point to wait until, before timing out.
|
||||
* @return The message, if read, an empty pointer if not.
|
||||
*/
|
||||
template <class Clock, class Duration>
|
||||
const_message_ptr try_consume_message_until(const std::chrono::time_point<Clock,Duration>& absTime) {
|
||||
const_message_ptr msg;
|
||||
que_->try_get_until(&msg, absTime);
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to an asynchronous MQTT client object */
|
||||
using async_client_ptr = async_client::ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_async_client_h
|
||||
|
||||
305
src/mqtt/include/mqtt/buffer_ref.h
Normal file
305
src/mqtt/include/mqtt/buffer_ref.h
Normal file
@@ -0,0 +1,305 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file buffer_ref.h
|
||||
/// Buffer reference type for the Paho MQTT C++ library.
|
||||
/// @date April 18, 2017
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017-2024 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_buffer_ref_h
|
||||
#define __mqtt_buffer_ref_h
|
||||
|
||||
#include "mqtt/types.h"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A reference object for holding immutable data buffers, with cheap copy
|
||||
* semantics and lifetime management.
|
||||
*
|
||||
* Each object of this class contains a reference-counted pointer to an
|
||||
* immutable data buffer. Objects can be copied freely and easily, even
|
||||
* across threads, since all instances promise not to modify the contents
|
||||
* of the buffer.
|
||||
*
|
||||
* The buffer is immutable but the reference itself acts like a normal
|
||||
* variable. It can be reassigned to point to a different buffer.
|
||||
*
|
||||
* If no value has been assigned to a reference, then it is in a default
|
||||
* "null" state. It is not safe to call any member functions on a null
|
||||
* reference, other than to check if the object is null or empty.
|
||||
* @verbatim
|
||||
* string_ref sr;
|
||||
* if (!sr)
|
||||
* cout << "null reference" << endl;
|
||||
* else
|
||||
* cout.write(sr.data(), sr.size());
|
||||
* @endverbatim
|
||||
*/
|
||||
template <typename T>
|
||||
class buffer_ref
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The underlying type for the buffer.
|
||||
* Normally byte-wide data (char or uint8_t) for Paho.
|
||||
*/
|
||||
using value_type = T;
|
||||
/**
|
||||
* The type for the buffer.
|
||||
* We use basic_string for compatibility with string data.
|
||||
*/
|
||||
using blob = std::basic_string<value_type>;
|
||||
/**
|
||||
* The pointer we use.
|
||||
* Note that it is a pointer to a _const_ blob.
|
||||
*/
|
||||
using pointer_type = std::shared_ptr<const blob>;
|
||||
|
||||
private:
|
||||
/** Our data is a shared pointer to a const buffer */
|
||||
pointer_type data_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor creates a null reference.
|
||||
*/
|
||||
buffer_ref() =default;
|
||||
/**
|
||||
* Copy constructor only copies a shared pointer.
|
||||
* @param buf Another buffer reference.
|
||||
*/
|
||||
buffer_ref(const buffer_ref& buf) =default;
|
||||
/**
|
||||
* Move constructor only moves a shared pointer.
|
||||
* @param buf Another buffer reference.
|
||||
*/
|
||||
buffer_ref(buffer_ref&& buf) =default;
|
||||
/**
|
||||
* Creates a reference to a new buffer by copying data.
|
||||
* @param b A string from which to create a new buffer.
|
||||
*/
|
||||
buffer_ref(const blob& b) : data_{std::make_shared<blob>(b)} {}
|
||||
/**
|
||||
* Creates a reference to a new buffer by moving a string into the
|
||||
* buffer.
|
||||
* @param b A string from which to create a new buffer.
|
||||
*/
|
||||
buffer_ref(blob&& b) : data_{std::make_shared<blob>(std::move(b))} {}
|
||||
/**
|
||||
* Creates a reference to an existing buffer by copying the shared
|
||||
* pointer.
|
||||
* Note that it is up to the caller to insure that there are no mutable
|
||||
* references to the buffer.
|
||||
* @param p A shared pointer to a string.
|
||||
*/
|
||||
buffer_ref(const pointer_type& p) : data_(p) {}
|
||||
/**
|
||||
* Creates a reference to an existing buffer by moving the shared
|
||||
* pointer.
|
||||
* Note that it is up to the caller to insure that there are no mutable
|
||||
* references to the buffer.
|
||||
* @param p A shared pointer to a string.
|
||||
*/
|
||||
buffer_ref(pointer_type&& p) : data_(std::move(p)) {}
|
||||
/**
|
||||
* Creates a reference to a new buffer containing a copy of the data.
|
||||
* @param buf The memory to copy
|
||||
* @param n The number of bytes to copy.
|
||||
*/
|
||||
buffer_ref(const value_type* buf, size_t n) : data_{std::make_shared<blob>(buf,n)} {}
|
||||
/**
|
||||
* Creates a reference to a new buffer containing a copy of the
|
||||
* NUL-terminated char array.
|
||||
* @param buf A NUL-terminated char array (C string).
|
||||
*/
|
||||
buffer_ref(const char* buf) : buffer_ref(reinterpret_cast<const value_type*>(buf),
|
||||
std::strlen(buf)) {
|
||||
static_assert(sizeof(char) == sizeof(T), "can only use C arr with char or byte buffers");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the reference to the buffer.
|
||||
* @param rhs Another buffer
|
||||
* @return A reference to this object
|
||||
*/
|
||||
buffer_ref& operator=(const buffer_ref& rhs) =default;
|
||||
/**
|
||||
* Move a reference to a buffer.
|
||||
* @param rhs The other reference to move.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
buffer_ref& operator=(buffer_ref&& rhs) =default;
|
||||
/**
|
||||
* Copy a string into this object, creating a new buffer.
|
||||
* Modifies the reference for this object, pointing it to a
|
||||
* newly-created buffer. Other references to the old object remain
|
||||
* unchanges, so this follows copy-on-write semantics.
|
||||
* @param b A new blob/string to copy.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
buffer_ref& operator=(const blob& b) {
|
||||
data_.reset(new blob(b));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Move a string into this object, creating a new buffer.
|
||||
* Modifies the reference for this object, pointing it to a
|
||||
* newly-created buffer. Other references to the old object remain
|
||||
* unchanges, so this follows copy-on-write semantics.
|
||||
* @param b A new blob/string to move.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
buffer_ref& operator=(blob&& b) {
|
||||
data_.reset(new blob(std::move(b)));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Copy a NUL-terminated C char array into a new buffer
|
||||
* @param cstr A NUL-terminated C string.
|
||||
* @return A reference to this object
|
||||
*/
|
||||
buffer_ref& operator=(const char* cstr) {
|
||||
static_assert(sizeof(char) == sizeof(T), "can only use C arr with char or byte buffers");
|
||||
data_.reset(new blob(reinterpret_cast<const value_type*>(cstr), strlen(cstr)));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Copy another type of buffer reference to this one.
|
||||
* This can copy a buffer of different types, provided that the size of
|
||||
* the data elements are the same. This is typically used to convert
|
||||
* from char to byte, where the data is the same, but the interpretation
|
||||
* is different. Note that this copies the underlying buffer.
|
||||
* @param rhs A reference to a different type of buffer.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
template <typename OT>
|
||||
buffer_ref& operator=(const buffer_ref<OT>& rhs) {
|
||||
static_assert(sizeof(OT) == sizeof(T), "Can only assign buffers if values the same size");
|
||||
data_.reset(new blob(reinterpret_cast<const value_type*>(rhs.data()), rhs.size()));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Clears the reference to nil.
|
||||
*/
|
||||
void reset() { data_.reset(); }
|
||||
/**
|
||||
* Determines if the reference is valid.
|
||||
* If the reference is invalid then it is not safe to call @em any
|
||||
* member functions other than @ref is_null() and @ref empty()
|
||||
* @return @em true if referring to a valid buffer, @em false if the
|
||||
* reference (pointer) is null.
|
||||
*/
|
||||
explicit operator bool() const { return bool(data_); }
|
||||
/**
|
||||
* Determines if the reference is invalid.
|
||||
* If the reference is invalid then it is not safe to call @em any
|
||||
* member functions other than @ref is_null() and @ref empty()
|
||||
* @return @em true if the reference is null, @em false if it is
|
||||
* referring to a valid buffer,
|
||||
*/
|
||||
bool is_null() const { return !data_; }
|
||||
/**
|
||||
* Determines if the buffer is empty.
|
||||
* @return @em true if the buffer is empty or the reference is null,
|
||||
* @em false if the buffer contains data.
|
||||
*/
|
||||
bool empty() const { return !data_ || data_->empty(); }
|
||||
/**
|
||||
* Gets a const pointer to the data buffer.
|
||||
* @return A pointer to the data buffer.
|
||||
*/
|
||||
const value_type* data() const { return data_->data(); }
|
||||
/**
|
||||
* Gets the size of the data buffer.
|
||||
* @return The size of the data buffer.
|
||||
*/
|
||||
size_t size() const { return data_->size(); }
|
||||
/**
|
||||
* Gets the size of the data buffer.
|
||||
* @return The size of the data buffer.
|
||||
*/
|
||||
size_t length() const { return data_->length(); }
|
||||
/**
|
||||
* Gets the data buffer as a string.
|
||||
* @return The data buffer as a string.
|
||||
*/
|
||||
const blob& str() const { return *data_; }
|
||||
/**
|
||||
* Gets the data buffer as a string.
|
||||
* @return The data buffer as a string.
|
||||
*/
|
||||
const blob& to_string() const { return str(); }
|
||||
/**
|
||||
* Gets the data buffer as NUL-terminated C string.
|
||||
* Note that the reference must be set to call this function.
|
||||
* @return The data buffer as a string.
|
||||
*/
|
||||
const char* c_str() const { return data_->c_str(); }
|
||||
/**
|
||||
* Gets a shared pointer to the (const) data buffer.
|
||||
* @return A shared pointer to the (const) data buffer.
|
||||
*/
|
||||
const pointer_type& ptr() const { return data_; }
|
||||
/**
|
||||
* Gets elemental access to the data buffer (read only)
|
||||
* @param i The index into the buffer.
|
||||
* @return The value at the specified index.
|
||||
*/
|
||||
const value_type& operator[](size_t i) const { return (*data_)[i]; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Stream inserter for a buffer reference.
|
||||
* This does a binary write of the data in the buffer.
|
||||
* @param os The output stream.
|
||||
* @param buf The buffer reference to write.
|
||||
* @return A reference to the output stream.
|
||||
*/
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& os, const buffer_ref<T>& buf) {
|
||||
if (!buf.empty())
|
||||
os.write(buf.data(), buf.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A reference to a text buffer.
|
||||
*/
|
||||
using string_ref = buffer_ref<char>;
|
||||
|
||||
/**
|
||||
* A reference to a binary buffer.
|
||||
* Note that we're using char for the underlying data type to allow
|
||||
* efficient moves to and from std::string's. Using a separate type
|
||||
* indicates that the data may be arbitrary binary.
|
||||
*/
|
||||
using binary_ref = buffer_ref<char>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_buffer_ref_h
|
||||
|
||||
135
src/mqtt/include/mqtt/buffer_view.h
Normal file
135
src/mqtt/include/mqtt/buffer_view.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file buffer_view.h
|
||||
/// Buffer reference type for the Paho MQTT C++ library.
|
||||
/// @date April 18, 2017
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017-2020 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_buffer_view_h
|
||||
#define __mqtt_buffer_view_h
|
||||
|
||||
#include "mqtt/types.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A reference to a contiguous sequence of items, with no ownership.
|
||||
* This simply contains a pointer to a const array of items, and a size.
|
||||
* This is a similar, but simplified version of the std::string_view
|
||||
* class(es) in the C++17 standard.
|
||||
*/
|
||||
template <typename T>
|
||||
class buffer_view
|
||||
{
|
||||
public:
|
||||
/** The type of items to be held in the queue. */
|
||||
using value_type = T;
|
||||
/** The type used to specify number of items in the container. */
|
||||
using size_type = size_t;
|
||||
|
||||
private:
|
||||
/** Const pointer to the data array */
|
||||
const value_type* data_;
|
||||
/** The size of the array */
|
||||
size_type sz_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a buffer view.
|
||||
* @param data The data pointer
|
||||
* @param n The number of items
|
||||
*/
|
||||
buffer_view(const value_type* data, size_type n)
|
||||
: data_(data), sz_(n) {}
|
||||
/**
|
||||
* Constructs a buffer view to a whole string.
|
||||
* This the starting pointer and length of the whole string.
|
||||
* @param str The string.
|
||||
*/
|
||||
buffer_view(const std::basic_string<value_type>& str)
|
||||
: data_(str.data()), sz_(str.size()) {}
|
||||
/**
|
||||
* Gets a pointer the first item in the view.
|
||||
* @return A const pointer the first item in the view.
|
||||
*/
|
||||
const value_type* data() const { return data_; }
|
||||
/**
|
||||
* Gets the number of items in the view.
|
||||
* @return The number of items in the view.
|
||||
*/
|
||||
size_type size() const { return sz_; }
|
||||
/**
|
||||
* Gets the number of items in the view.
|
||||
* @return The number of items in the view.
|
||||
*/
|
||||
size_type length() const { return sz_; }
|
||||
/**
|
||||
* Access an item in the view.
|
||||
* @param i The index of the item.
|
||||
* @return A const reference to the requested item.
|
||||
*/
|
||||
const value_type& operator[](size_t i) const { return data_[i]; }
|
||||
/**
|
||||
* Gets a copy of the view as a string.
|
||||
* @return A copy of the view as a string.
|
||||
*/
|
||||
std::basic_string<value_type> str() const {
|
||||
return std::basic_string<value_type>(data_, sz_);
|
||||
}
|
||||
/**
|
||||
* Gets a copy of the view as a string.
|
||||
* @return A copy of the view as a string.
|
||||
*/
|
||||
string to_string() const {
|
||||
static_assert(sizeof(char) == sizeof(T), "can only get string for char or byte buffers");
|
||||
return string(reinterpret_cast<const char*>(data_), sz_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stream inserter for a buffer view.
|
||||
* This does a binary write of the data in the buffer.
|
||||
* @param os The output stream.
|
||||
* @param buf The buffer reference to write.
|
||||
* @return A reference to the output stream.
|
||||
*/
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& os, const buffer_view<T>& buf) {
|
||||
if (buf.size() > 0)
|
||||
os.write(buf.data(), sizeof(T)*buf.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
/** A buffer view for character string data. */
|
||||
using string_view = buffer_view<char>;
|
||||
|
||||
/** A buffer view for binary data */
|
||||
using binary_view = buffer_view<char>;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_buffer_view_h
|
||||
|
||||
87
src/mqtt/include/mqtt/callback.h
Normal file
87
src/mqtt/include/mqtt/callback.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file callback.h
|
||||
/// Declaration of MQTT callback class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2019 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_callback_h
|
||||
#define __mqtt_callback_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/delivery_token.h"
|
||||
#include "mqtt/types.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Provides a mechanism for tracking the completion of an asynchronous
|
||||
* action.
|
||||
*/
|
||||
class callback
|
||||
{
|
||||
public:
|
||||
/** Smart/shared pointer to an object of this type */
|
||||
using ptr_t = std::shared_ptr<callback>;
|
||||
/** Smart/shared pointer to a const object of this type */
|
||||
using const_ptr_t = std::shared_ptr<const callback>;
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~callback() {}
|
||||
|
||||
/**
|
||||
* This method is called when the client is connected.
|
||||
* Note that, in response to an initial connect(), the token from the
|
||||
* connect call is also signaled with an on_success(). That occurs just
|
||||
* before this is called.
|
||||
*/
|
||||
virtual void connected(const string& /*cause*/) {}
|
||||
/**
|
||||
* This method is called when the connection to the server is lost.
|
||||
*/
|
||||
virtual void connection_lost(const string& /*cause*/) {}
|
||||
/**
|
||||
* This method is called when a message arrives from the server.
|
||||
*/
|
||||
virtual void message_arrived(const_message_ptr /*msg*/) {}
|
||||
/**
|
||||
* Called when delivery for a message has been completed, and all
|
||||
* acknowledgments have been received.
|
||||
*/
|
||||
virtual void delivery_complete(delivery_token_ptr /*tok*/) {}
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to a callback object */
|
||||
using callback_ptr = callback::ptr_t;
|
||||
|
||||
/** Smart/shared pointer to a const callback object */
|
||||
using const_callback_ptr = callback::const_ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_callback_h
|
||||
|
||||
444
src/mqtt/include/mqtt/client.h
Normal file
444
src/mqtt/include/mqtt/client.h
Normal file
@@ -0,0 +1,444 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file client.h
|
||||
/// Declaration of MQTT client class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2023 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_client_h
|
||||
#define __mqtt_client_h
|
||||
|
||||
#include "mqtt/async_client.h"
|
||||
#include <future>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Lightweight client for talking to an MQTT server using methods that block
|
||||
* until an operation completes.
|
||||
*/
|
||||
class client : private callback
|
||||
{
|
||||
/** An arbitrary, but relatively long timeout */
|
||||
PAHO_MQTTPP_EXPORT static const std::chrono::seconds DFLT_TIMEOUT;
|
||||
/** The default quality of service */
|
||||
PAHO_MQTTPP_EXPORT static const int DFLT_QOS; // =1;
|
||||
|
||||
/** The actual client */
|
||||
async_client cli_;
|
||||
/** The longest time to wait for an operation to complete. */
|
||||
std::chrono::milliseconds timeout_;
|
||||
/** Callback supplied by the user (if any) */
|
||||
callback* userCallback_;
|
||||
|
||||
/**
|
||||
* Creates a shared pointer to an existing non-heap object.
|
||||
* The shared pointer is given a no-op deleter, so it will not try to
|
||||
* destroy the object when it goes out of scope. It is up to the caller
|
||||
* to ensure that the object remains in memory for as long as there may
|
||||
* be pointers to it.
|
||||
* @param val A value which may live anywhere in memory (stack,
|
||||
* file-scope, etc).
|
||||
* @return A shared pointer to the object.
|
||||
*/
|
||||
template <typename T>
|
||||
std::shared_ptr<T> ptr(const T& val) {
|
||||
return std::shared_ptr<T>(const_cast<T*>(&val), [](T*){});
|
||||
}
|
||||
|
||||
// User callbacks
|
||||
// Most are launched in a separate thread, for convenience, except
|
||||
// message_arrived, for performance.
|
||||
void connected(const string& cause) override {
|
||||
std::async(std::launch::async, &callback::connected, userCallback_, cause).wait();
|
||||
}
|
||||
void connection_lost(const string& cause) override {
|
||||
std::async(std::launch::async,
|
||||
&callback::connection_lost, userCallback_, cause).wait();
|
||||
}
|
||||
void message_arrived(const_message_ptr msg) override {
|
||||
userCallback_->message_arrived(msg);
|
||||
}
|
||||
void delivery_complete(delivery_token_ptr tok) override {
|
||||
std::async(std::launch::async, &callback::delivery_complete, userCallback_, tok).wait();
|
||||
}
|
||||
|
||||
/** Non-copyable */
|
||||
client() =delete;
|
||||
client(const async_client&) =delete;
|
||||
client& operator=(const async_client&) =delete;
|
||||
|
||||
public:
|
||||
/** Smart pointer type for this object */
|
||||
using ptr_t = std::shared_ptr<client>;
|
||||
/** Type for a collection of QOS values */
|
||||
using qos_collection = async_client::qos_collection;
|
||||
|
||||
/** Handler for updating connection data before an auto-reconnect. */
|
||||
using update_connection_handler = async_client::update_connection_handler;
|
||||
|
||||
/**
|
||||
* Create a client that can be used to communicate with an MQTT server.
|
||||
* This allows the caller to specify a user-defined persistence object,
|
||||
* or use no persistence.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param persistence The user persistence structure. If this is null,
|
||||
* then no persistence is used.
|
||||
*/
|
||||
client(const string& serverURI, const string& clientId,
|
||||
iclient_persistence* persistence=nullptr);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server.
|
||||
* This uses file-based persistence in the specified directory.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param persistDir The directory to use for persistence data
|
||||
*/
|
||||
client(const string& serverURI, const string& clientId,
|
||||
const string& persistDir);
|
||||
/**
|
||||
* Create a client that can be used to communicate with an MQTT server,
|
||||
* which allows for off-line message buffering.
|
||||
* This allows the caller to specify a user-defined persistence object,
|
||||
* or use no persistence.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param maxBufferedMessages the maximum number of messages allowed to
|
||||
* be buffered while not connected
|
||||
* @param persistence The user persistence structure. If this is null,
|
||||
* then no persistence is used.
|
||||
*/
|
||||
client(const string& serverURI, const string& clientId,
|
||||
int maxBufferedMessages,
|
||||
iclient_persistence* persistence=nullptr);
|
||||
/**
|
||||
* Create a client that can be used to communicate with an MQTT server,
|
||||
* which allows for off-line message buffering.
|
||||
* This uses file-based persistence in the specified directory.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param maxBufferedMessages the maximum number of messages allowed to
|
||||
* be buffered while not connected
|
||||
* @param persistDir The directory to use for persistence data
|
||||
*/
|
||||
client(const string& serverURI, const string& clientId,
|
||||
int maxBufferedMessages, const string& persistDir);
|
||||
/**
|
||||
* Create an async_client that can be used to communicate with an MQTT
|
||||
* server, which allows for off-line message buffering.
|
||||
* This allows the caller to specify a user-defined persistence object,
|
||||
* or use no persistence.
|
||||
* @param serverURI the address of the server to connect to, specified
|
||||
* as a URI.
|
||||
* @param clientId a client identifier that is unique on the server
|
||||
* being connected to
|
||||
* @param opts The create options
|
||||
* @param persistence The user persistence structure. If this is null,
|
||||
* then no persistence is used.
|
||||
*/
|
||||
client(const string& serverURI, const string& clientId,
|
||||
const create_options& opts,
|
||||
iclient_persistence* persistence=nullptr);
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~client() {}
|
||||
/**
|
||||
* Connects to an MQTT server using the default options.
|
||||
*/
|
||||
virtual connect_response connect();
|
||||
/**
|
||||
* Connects to an MQTT server using the specified options.
|
||||
* @param opts
|
||||
*/
|
||||
virtual connect_response connect(connect_options opts);
|
||||
/**
|
||||
* Reconnects the client using options from the previous connect.
|
||||
* The client must have previously called connect() for this to work.
|
||||
*/
|
||||
virtual connect_response reconnect();
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
*/
|
||||
virtual void disconnect();
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeoutMS the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
*/
|
||||
virtual void disconnect(int timeoutMS);
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param to the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
void disconnect(const std::chrono::duration<Rep, Period>& to) {
|
||||
disconnect((int) to_milliseconds_count(to));
|
||||
}
|
||||
/**
|
||||
* Gets the client ID used by this client.
|
||||
* @return The client ID used by this client.
|
||||
*/
|
||||
virtual string get_client_id() const { return cli_.get_client_id(); }
|
||||
/**
|
||||
* Gets the address of the server used by this client.
|
||||
* @return The address of the server used by this client, as a URI.
|
||||
*/
|
||||
virtual string get_server_uri() const { return cli_.get_server_uri(); }
|
||||
/**
|
||||
* Return the maximum time to wait for an action to complete.
|
||||
* @return int
|
||||
*/
|
||||
virtual std::chrono::milliseconds get_timeout() const { return timeout_; }
|
||||
/**
|
||||
* Gets a copy of the connect options that were last used in a request
|
||||
* to connect to the broker.
|
||||
* @returns The last connect options that were used.
|
||||
*/
|
||||
connect_options get_connect_options() const {
|
||||
return cli_.get_connect_options();
|
||||
}
|
||||
/**
|
||||
* Get a topic object which can be used to publish messages on this
|
||||
* client.
|
||||
* @param top The topic name
|
||||
* @param qos The Quality of Service for the topic
|
||||
* @param retained Whether the published messages set the retain flag.
|
||||
* @return A topic attached to this client.
|
||||
*/
|
||||
virtual topic get_topic(const string& top, int qos=message::DFLT_QOS,
|
||||
bool retained=message::DFLT_RETAINED) {
|
||||
return topic(cli_, top, qos, retained);
|
||||
}
|
||||
/**
|
||||
* Determines if this client is currently connected to the server.
|
||||
* @return @em true if the client is currently connected, @em false if
|
||||
* not.
|
||||
*/
|
||||
virtual bool is_connected() const { return cli_.is_connected(); }
|
||||
/**
|
||||
* Sets a callback to allow the application to update the connection
|
||||
* data on automatic reconnects.
|
||||
* @param cb The callback functor to register with the library.
|
||||
*/
|
||||
void set_update_connection_handler(update_connection_handler cb) {
|
||||
cli_.set_update_connection_handler(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a message to a topic on the server and return once it is
|
||||
* delivered.
|
||||
* @param top The topic to publish
|
||||
* @param payload The data to publish
|
||||
* @param n The size in bytes of the data
|
||||
* @param qos The QoS for message delivery
|
||||
* @param retained Whether the broker should retain the message
|
||||
*/
|
||||
virtual void publish(string_ref top, const void* payload, size_t n,
|
||||
int qos, bool retained) {
|
||||
if (!cli_.publish(std::move(top), payload, n, qos, retained)->wait_for(timeout_))
|
||||
throw timeout_error();
|
||||
}
|
||||
/**
|
||||
* Publishes a message to a topic on the server and return once it is
|
||||
* delivered.
|
||||
* @param top The topic to publish
|
||||
* @param payload The data to publish
|
||||
* @param n The size in bytes of the data
|
||||
*/
|
||||
virtual void publish(string_ref top, const void* payload, size_t n) {
|
||||
if (!cli_.publish(std::move(top), payload, n)->wait_for(timeout_))
|
||||
throw timeout_error();
|
||||
}
|
||||
/**
|
||||
* Publishes a message to a topic on the server.
|
||||
* @param msg The message
|
||||
*/
|
||||
virtual void publish(const_message_ptr msg) {
|
||||
if (!cli_.publish(msg)->wait_for(timeout_))
|
||||
throw timeout_error();
|
||||
}
|
||||
/**
|
||||
* Publishes a message to a topic on the server.
|
||||
* This version will not timeout since that could leave the library with
|
||||
* a reference to memory that could disappear while the library is still
|
||||
* using it.
|
||||
* @param msg The message
|
||||
*/
|
||||
virtual void publish(const message& msg) {
|
||||
cli_.publish(ptr(msg))->wait();
|
||||
}
|
||||
/**
|
||||
* Sets the callback listener to use for events that happen
|
||||
* asynchronously.
|
||||
* @param cb The callback functions
|
||||
*/
|
||||
virtual void set_callback(callback& cb);
|
||||
/**
|
||||
* Set the maximum time to wait for an action to complete.
|
||||
* @param timeoutMS The timeout in milliseconds
|
||||
*/
|
||||
virtual void set_timeout(int timeoutMS) {
|
||||
timeout_ = std::chrono::milliseconds(timeoutMS);
|
||||
}
|
||||
/**
|
||||
* Set the maximum time to wait for an action to complete.
|
||||
* @param to The timeout as a std::chrono duration.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
void set_timeout(const std::chrono::duration<Rep, Period>& to) {
|
||||
timeout_ = to_milliseconds(to);
|
||||
}
|
||||
/**
|
||||
* Subscribe to a topic, which may include wildcards using a QoS of 1.
|
||||
* @param topicFilter
|
||||
* @param props The MQTT v5 properties.
|
||||
* @param opts The MQTT v5 subscribe options for the topic
|
||||
* @return The "subscribe" response from the server.
|
||||
*/
|
||||
virtual subscribe_response subscribe(const string& topicFilter,
|
||||
const subscribe_options& opts=subscribe_options(),
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Subscribe to a topic, which may include wildcards.
|
||||
* @param topicFilter A single topic to subscribe
|
||||
* @param qos The QoS of the subscription
|
||||
* @param opts The MQTT v5 subscribe options for the topic
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return The "subscribe" response from the server.
|
||||
*/
|
||||
virtual subscribe_response subscribe(const string& topicFilter, int qos,
|
||||
const subscribe_options& opts=subscribe_options(),
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Subscribes to a one or more topics, which may include wildcards using
|
||||
* a QoS of 1.
|
||||
* @param topicFilters A set of topics to subscribe
|
||||
* @param opts The MQTT v5 subscribe options (one for each topic)
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return The "subscribe" response from the server.
|
||||
*/
|
||||
virtual subscribe_response subscribe(const string_collection& topicFilters,
|
||||
const std::vector<subscribe_options>& opts=std::vector<subscribe_options>(),
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Subscribes to multiple topics, each of which may include wildcards.
|
||||
* @param topicFilters A collection of topics to subscribe
|
||||
* @param qos A collection of QoS for each topic
|
||||
* @param opts The MQTT v5 subscribe options (one for each topic)
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return The "subscribe" response from the server.
|
||||
*/
|
||||
virtual subscribe_response subscribe(const string_collection& topicFilters,
|
||||
const qos_collection& qos,
|
||||
const std::vector<subscribe_options>& opts=std::vector<subscribe_options>(),
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Requests the server unsubscribe the client from a topic.
|
||||
* @param topicFilter A single topic to unsubscribe.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return The "unsubscribe" response from the server.
|
||||
*/
|
||||
virtual unsubscribe_response unsubscribe(const string& topicFilter,
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Requests the server unsubscribe the client from one or more topics.
|
||||
* @param topicFilters A collection of topics to unsubscribe.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return The "unsubscribe" response from the server.
|
||||
*/
|
||||
virtual unsubscribe_response unsubscribe(const string_collection& topicFilters,
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Start consuming messages.
|
||||
* This initializes the client to receive messages through a queue that
|
||||
* can be read synchronously.
|
||||
*/
|
||||
virtual void start_consuming() { cli_.start_consuming(); }
|
||||
/**
|
||||
* Stop consuming messages.
|
||||
* This shuts down the internal callback and discards any unread
|
||||
* messages.
|
||||
*/
|
||||
virtual void stop_consuming() { cli_.stop_consuming(); }
|
||||
/**
|
||||
* Read the next message from the queue.
|
||||
* This blocks until a new message arrives.
|
||||
* @return The message and topic.
|
||||
*/
|
||||
virtual const_message_ptr consume_message() { return cli_.consume_message(); }
|
||||
/**
|
||||
* Try to read the next message from the queue without blocking.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @return @em true is a message was read, @em false if no message was
|
||||
* available.
|
||||
*/
|
||||
virtual bool try_consume_message(const_message_ptr* msg) {
|
||||
return cli_.try_consume_message(msg);
|
||||
}
|
||||
/**
|
||||
* Waits a limited time for a message to arrive.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @param relTime The maximum amount of time to wait for a message.
|
||||
* @return @em true if a message was read, @em false if a timeout
|
||||
* occurred.
|
||||
*/
|
||||
template <typename Rep, class Period>
|
||||
bool try_consume_message_for(const_message_ptr* msg,
|
||||
const std::chrono::duration<Rep, Period>& relTime) {
|
||||
return cli_.try_consume_message_for(msg, relTime);
|
||||
}
|
||||
/**
|
||||
* Waits until a specific time for a message to occur.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @param absTime The time point to wait until, before timing out.
|
||||
* @return @em true if a message was read, @em false if a timeout
|
||||
* occurred.
|
||||
*/
|
||||
template <class Clock, class Duration>
|
||||
bool try_consume_message_until(const_message_ptr* msg,
|
||||
const std::chrono::time_point<Clock,Duration>& absTime) {
|
||||
return cli_.try_consume_message_until(msg, absTime);
|
||||
}
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to an MQTT synchronous client object */
|
||||
using client_ptr = client::ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_client_h
|
||||
|
||||
968
src/mqtt/include/mqtt/connect_options.h
Normal file
968
src/mqtt/include/mqtt/connect_options.h
Normal file
@@ -0,0 +1,968 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file connect_options.h
|
||||
/// Declaration of MQTT connect_options class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2020 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_connect_options_h
|
||||
#define __mqtt_connect_options_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
#include "mqtt/message.h"
|
||||
#include "mqtt/topic.h"
|
||||
#include "mqtt/token.h"
|
||||
#include "mqtt/string_collection.h"
|
||||
#include "mqtt/will_options.h"
|
||||
#include "mqtt/ssl_options.h"
|
||||
#include "mqtt/platform.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Holds the set of options that control how the client connects to a
|
||||
* server.
|
||||
*/
|
||||
class connect_options
|
||||
{
|
||||
/** The default C struct for non-WebSocket connections */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTAsync_connectOptions DFLT_C_STRUCT;
|
||||
|
||||
/** The default C struct for non-Websocket MQTT v5 connections */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTAsync_connectOptions DFLT_C_STRUCT5;
|
||||
|
||||
/** The default C struct for WebSocket connections */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTAsync_connectOptions DFLT_C_STRUCT_WS;
|
||||
|
||||
/** The default C struct for Websocket MQTT v5 connections */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTAsync_connectOptions DFLT_C_STRUCT5_WS;
|
||||
|
||||
/** The underlying C connection options */
|
||||
MQTTAsync_connectOptions opts_;
|
||||
|
||||
/** The LWT options */
|
||||
will_options will_;
|
||||
|
||||
/** The SSL options */
|
||||
ssl_options ssl_;
|
||||
|
||||
/** The user name to use for the connection. */
|
||||
string_ref userName_;
|
||||
|
||||
/** The password to use for the connection. */
|
||||
binary_ref password_;
|
||||
|
||||
/** Shared token pointer for context, if any */
|
||||
token_ptr tok_;
|
||||
|
||||
/** Collection of server URIs, if any */
|
||||
const_string_collection_ptr serverURIs_;
|
||||
|
||||
/** The connect properties */
|
||||
properties props_;
|
||||
|
||||
/** HTTP Headers */
|
||||
name_value_collection httpHeaders_;
|
||||
|
||||
/** HTTP proxy for websockets */
|
||||
string httpProxy_;
|
||||
|
||||
/** Secure HTTPS proxy for websockets */
|
||||
string httpsProxy_;
|
||||
|
||||
/** The client has special access */
|
||||
friend class async_client;
|
||||
|
||||
/**
|
||||
* Gets a pointer to the C-language NUL-terminated strings for the
|
||||
* struct.
|
||||
* @note In the connect options, by default, the Paho C treats
|
||||
* nullptr char arrays as unset values, so we keep that semantic and
|
||||
* only set those char arrays if the string is non-empty.
|
||||
* @param str The C++ string object.
|
||||
* @return Pointer to a NUL terminated string. This is only valid until
|
||||
* the next time the string is updated.
|
||||
*/
|
||||
const char* c_str(const string_ref& sr) {
|
||||
return sr.empty() ? nullptr : sr.c_str();
|
||||
}
|
||||
const char* c_str(const string& s) {
|
||||
return s.empty() ? nullptr : s.c_str();
|
||||
}
|
||||
/**
|
||||
* Updates the underlying C structure to match our strings.
|
||||
*/
|
||||
void update_c_struct();
|
||||
|
||||
/**
|
||||
* Creates the options from a C option struct.
|
||||
* @param copts The C options struct.
|
||||
*/
|
||||
connect_options(const MQTTAsync_connectOptions& copts) : opts_(copts) {}
|
||||
|
||||
public:
|
||||
/** Smart/shared pointer to an object of this class. */
|
||||
using ptr_t = std::shared_ptr<connect_options>;
|
||||
/** Smart/shared pointer to a const object of this class. */
|
||||
using const_ptr_t = std::shared_ptr<const connect_options>;
|
||||
|
||||
/**
|
||||
* Constructs a new object using the default values.
|
||||
*
|
||||
* @param ver The MQTT protocol version.
|
||||
*/
|
||||
explicit connect_options(int ver=MQTTVERSION_DEFAULT);
|
||||
/**
|
||||
* Constructs a new object using the specified user name and password.
|
||||
* @param userName The name of the user for connecting to the server
|
||||
* @param password The password for connecting to the server
|
||||
* @param ver The MQTT protocol version.
|
||||
*/
|
||||
connect_options(
|
||||
string_ref userName, binary_ref password,
|
||||
int ver=MQTTVERSION_DEFAULT
|
||||
);
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param opt Another object to copy.
|
||||
*/
|
||||
connect_options(const connect_options& opt);
|
||||
/**
|
||||
* Move constructor.
|
||||
* @param opt Another object to move into this new one.
|
||||
*/
|
||||
connect_options(connect_options&& opt);
|
||||
/**
|
||||
* Creates default options for an MQTT v3.x connection.
|
||||
* @return Default options for an MQTT v3.x connection.
|
||||
*/
|
||||
static connect_options v3();
|
||||
/**
|
||||
* Creates default options for an MQTT v5 connection.
|
||||
* @return Default options for an MQTT v5 connection.
|
||||
*/
|
||||
static connect_options v5();
|
||||
/**
|
||||
* Creates default options for an MQTT v3.x connection using WebSockets.
|
||||
*
|
||||
* The keepalive interval is set to 45 seconds to avoid webserver 60
|
||||
* second inactivity timeouts.
|
||||
*
|
||||
* @return Default options for an MQTT v3.x connection using websockets.
|
||||
*/
|
||||
static connect_options ws() {
|
||||
return connect_options(DFLT_C_STRUCT_WS);
|
||||
}
|
||||
/**
|
||||
* Creates default options for an MQTT v5 connection using WebSockets.
|
||||
*
|
||||
* The keepalive interval is set to 45 seconds to avoid webserver 60
|
||||
* second inactivity timeouts.
|
||||
*
|
||||
* @return Default options for an MQTT v5 connection using websockets.
|
||||
*/
|
||||
static connect_options v5_ws() {
|
||||
return connect_options(DFLT_C_STRUCT5_WS);
|
||||
}
|
||||
/**
|
||||
* Copy assignment.
|
||||
* @param opt Another object to copy.
|
||||
*/
|
||||
connect_options& operator=(const connect_options& opt);
|
||||
/**
|
||||
* Move assignment.
|
||||
* @param opt Another object to move into this new one.
|
||||
*/
|
||||
connect_options& operator=(connect_options&& opt);
|
||||
/**
|
||||
* Expose the underlying C struct for the unit tests.
|
||||
*/
|
||||
#if defined(UNIT_TESTS)
|
||||
const MQTTAsync_connectOptions& c_struct() const { return opts_; }
|
||||
#endif
|
||||
/**
|
||||
* Gets the "keep alive" interval.
|
||||
* @return The keep alive interval in seconds.
|
||||
*/
|
||||
std::chrono::seconds get_keep_alive_interval() const {
|
||||
return std::chrono::seconds(opts_.keepAliveInterval);
|
||||
}
|
||||
/**
|
||||
* Gets the connection timeout.
|
||||
* This is the amount of time the underlying library will wait for a
|
||||
* timeout before failing.
|
||||
* @return The connect timeout in seconds.
|
||||
*/
|
||||
std::chrono::seconds get_connect_timeout() const {
|
||||
return std::chrono::seconds(opts_.connectTimeout);
|
||||
}
|
||||
/**
|
||||
* Gets the user name to use for the connection.
|
||||
* @return The user name to use for the connection.
|
||||
*/
|
||||
string get_user_name() const { return userName_ ? userName_.to_string() : string(); }
|
||||
/**
|
||||
* Gets the password to use for the connection.
|
||||
* @return The password to use for the connection.
|
||||
*/
|
||||
binary_ref get_password() const { return password_; }
|
||||
/**
|
||||
* Gets the password to use for the connection.
|
||||
* @return The password to use for the connection.
|
||||
*/
|
||||
string get_password_str() const {
|
||||
return password_ ? password_.to_string() : string();
|
||||
}
|
||||
/**
|
||||
* Gets the maximum number of messages that can be in-flight
|
||||
* simultaneously.
|
||||
* @return The maximum number of inflight messages.
|
||||
*/
|
||||
int get_max_inflight() const { return opts_.maxInflight; }
|
||||
/**
|
||||
* Gets the topic to be used for last will and testament (LWT).
|
||||
* @return The topic to be used for last will and testament (LWT).
|
||||
*/
|
||||
string get_will_topic() const {
|
||||
return will_.get_topic();
|
||||
}
|
||||
/**
|
||||
* Gets the message to be sent as last will and testament (LWT).
|
||||
* @return The message to be sent as last will and testament (LWT).
|
||||
*/
|
||||
const_message_ptr get_will_message() const {
|
||||
return will_.get_message();
|
||||
}
|
||||
/**
|
||||
* Get the LWT options to use for the connection.
|
||||
* @return The LWT options to use for the connection.
|
||||
*/
|
||||
const will_options& get_will_options() const { return will_; }
|
||||
/**
|
||||
* Get the SSL options to use for the connection.
|
||||
* @return The SSL options to use for the connection.
|
||||
*/
|
||||
const ssl_options& get_ssl_options() const { return ssl_; }
|
||||
/**
|
||||
* Sets the SSL for the connection.
|
||||
* These will only have an effect if compiled against the SSL version of
|
||||
* the Paho C library, and using a secure connection, "ssl://" or
|
||||
* "wss://".
|
||||
* @param ssl The SSL options.
|
||||
*/
|
||||
void set_ssl(const ssl_options& ssl);
|
||||
/**
|
||||
* Sets the SSL for the connection.
|
||||
* These will only have an effect if compiled against the SSL version of
|
||||
* the Paho C library, and using a secure connection, "ssl://" or
|
||||
* "wss://".
|
||||
* @param ssl The SSL options.
|
||||
*/
|
||||
void set_ssl(ssl_options&& ssl);
|
||||
/**
|
||||
* Returns whether the server should remember state for the client
|
||||
* across reconnects. This only applies to MQTT v3.x connections.
|
||||
* @return @em true if requesting a clean session, @em false if not.
|
||||
*/
|
||||
bool is_clean_session() const { return to_bool(opts_.cleansession); }
|
||||
/**
|
||||
* Returns whether the server should remember state for the client
|
||||
* across reconnects. This only applies to MQTT v5 connections.
|
||||
* @return @em true if requesting a clean start, @em false if not.
|
||||
*/
|
||||
bool is_clean_start() const { return to_bool(opts_.cleanstart); }
|
||||
/**
|
||||
* Gets the token used as the callback context.
|
||||
* @return The delivery token used as the callback context.
|
||||
*/
|
||||
token_ptr get_token() const { return tok_; }
|
||||
/**
|
||||
* Gets the list of servers to which the client will connect.
|
||||
* @return A collection of server URI's. Each entry should be of the
|
||||
* form @em protocol://host:port where @em protocol must be tcp
|
||||
* or @em ssl. For @em host, you can specify either an IP
|
||||
* address or a domain name.
|
||||
*/
|
||||
const_string_collection_ptr get_servers() const { return serverURIs_; }
|
||||
/**
|
||||
* Gets the version of MQTT to be used on the connect.
|
||||
* @return
|
||||
* @li MQTTVERSION_DEFAULT (0) = default: start with 3.1.1, and if that
|
||||
* fails, fall back to 3.1
|
||||
* @li MQTTVERSION_3_1 (3) = only try version 3.1
|
||||
* @li MQTTVERSION_3_1_1 (4) = only try version 3.1.1
|
||||
*/
|
||||
int get_mqtt_version() const { return opts_.MQTTVersion; }
|
||||
/**
|
||||
* Determines if the options have been configured for automatic
|
||||
* reconnect.
|
||||
* @return @em true if configured for automatic reconnect, @em false if
|
||||
* not.
|
||||
*/
|
||||
bool get_automatic_reconnect() const { return to_bool(opts_.automaticReconnect); }
|
||||
/**
|
||||
* Gets the minimum retry interval for automatic reconnect.
|
||||
* @return The minimum retry interval for automatic reconnect, in
|
||||
* seconds.
|
||||
*/
|
||||
std::chrono::seconds get_min_retry_interval() const {
|
||||
return std::chrono::seconds(opts_.minRetryInterval);
|
||||
}
|
||||
/**
|
||||
* Gets the maximum retry interval for automatic reconnect.
|
||||
* @return The maximum retry interval for automatic reconnect, in
|
||||
* seconds.
|
||||
*/
|
||||
std::chrono::seconds get_max_retry_interval() const {
|
||||
return std::chrono::seconds(opts_.maxRetryInterval);
|
||||
}
|
||||
/**
|
||||
* Sets whether the server should remember state for the client across
|
||||
* reconnects. (MQTT v3.x only)
|
||||
*
|
||||
* This will only take effect if the version is _already_ set to v3.x
|
||||
* (not v5).
|
||||
*
|
||||
* @param clean @em true if the server should NOT remember state for the
|
||||
* client across reconnects, @em false otherwise.
|
||||
*/
|
||||
void set_clean_session(bool cleanSession);
|
||||
/**
|
||||
* Sets whether the server should remember state for the client across
|
||||
* reconnects. (MQTT v5 only)
|
||||
*
|
||||
* If a persistent session is desired (turning this off), then the app
|
||||
* should also set the `Session Expiry Interval` property, and add that
|
||||
* to the connect options.
|
||||
*
|
||||
* This will only take effect if the MQTT version is set to v5
|
||||
*
|
||||
* @param clean @em true if the server should NOT remember state for the
|
||||
* client across reconnects, @em false otherwise.
|
||||
*/
|
||||
void set_clean_start(bool cleanStart);
|
||||
/**
|
||||
* Sets the "keep alive" interval.
|
||||
* This is the maximum time that should pass without communications
|
||||
* between client and server. If no messages pass in this time, the
|
||||
* client will ping the broker.
|
||||
* @param keepAliveInterval The keep alive interval in seconds.
|
||||
*/
|
||||
void set_keep_alive_interval(int keepAliveInterval) {
|
||||
opts_.keepAliveInterval = keepAliveInterval;
|
||||
}
|
||||
/**
|
||||
* Sets the "keep alive" interval with a chrono duration.
|
||||
* This is the maximum time that should pass without communications
|
||||
* between client and server. If no messages pass in this time, the
|
||||
* client will ping the broker.
|
||||
* @param interval The keep alive interval.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
void set_keep_alive_interval(const std::chrono::duration<Rep, Period>& interval) {
|
||||
// TODO: Check range
|
||||
set_keep_alive_interval((int) to_seconds_count(interval));
|
||||
}
|
||||
/**
|
||||
* Sets the connect timeout in seconds.
|
||||
* This is the maximum time that the underlying library will wait for a
|
||||
* connection before failing.
|
||||
* @param timeout The connect timeout in seconds.
|
||||
*/
|
||||
void set_connect_timeout(int timeout) {
|
||||
opts_.connectTimeout = timeout;
|
||||
}
|
||||
/**
|
||||
* Sets the connect timeout with a chrono duration.
|
||||
* This is the maximum time that the underlying library will wait for a
|
||||
* connection before failing.
|
||||
* @param timeout The connect timeout in seconds.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
void set_connect_timeout(const std::chrono::duration<Rep, Period>& timeout) {
|
||||
// TODO: check range
|
||||
set_connect_timeout((int) to_seconds_count(timeout));
|
||||
}
|
||||
/**
|
||||
* Sets the user name to use for the connection.
|
||||
* @param userName The user name for connecting to the MQTT broker.
|
||||
*/
|
||||
void set_user_name(string_ref userName);
|
||||
/**
|
||||
* Sets the password to use for the connection.
|
||||
* @param password The password for connecting to the MQTT broker.
|
||||
*/
|
||||
void set_password(binary_ref password);
|
||||
/**
|
||||
* Sets the maximum number of messages that can be in-flight
|
||||
* simultaneously.
|
||||
* @param n The maximum number of inflight messages.
|
||||
*/
|
||||
void set_max_inflight(int n) { opts_.maxInflight = n; }
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) for the connection.
|
||||
* @param will The LWT options.
|
||||
*/
|
||||
void set_will(const will_options& will);
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) for the connection.
|
||||
* @param will The LWT options.
|
||||
*/
|
||||
void set_will(will_options&& will);
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) as a message
|
||||
* @param msg The LWT message
|
||||
*/
|
||||
void set_will_message(const message& msg) {
|
||||
set_will(will_options(msg));
|
||||
}
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) as a message
|
||||
* @param msg Pointer to a LWT message
|
||||
*/
|
||||
void set_will_message(const_message_ptr msg) {
|
||||
if (msg) set_will(will_options(*msg));
|
||||
}
|
||||
/**
|
||||
* Sets the callback context to a delivery token.
|
||||
* @param tok The delivery token to be used as the callback context.
|
||||
*/
|
||||
void set_token(const token_ptr& tok);
|
||||
/**
|
||||
* Sets the list of servers to which the client will connect.
|
||||
* @param serverURIs A pointer to a collection of server URI's. Each
|
||||
* entry should be of the form @em
|
||||
* protocol://host:port where @em protocol must be
|
||||
* @em tcp or @em ssl. For @em host, you can specify
|
||||
* either an IP address or a domain name.
|
||||
*/
|
||||
void set_servers(const_string_collection_ptr serverURIs);
|
||||
/**
|
||||
* Sets the version of MQTT to be used on the connect.
|
||||
*
|
||||
* This will also set other connect options to legal values dependent on
|
||||
* the selected version.
|
||||
*
|
||||
* @param mqttVersion The MQTT version to use for the connection:
|
||||
* @li MQTTVERSION_DEFAULT (0) = default: start with 3.1.1, and if
|
||||
* that fails, fall back to 3.1
|
||||
* @li MQTTVERSION_3_1 (3) = only try version 3.1
|
||||
* @li MQTTVERSION_3_1_1 (4) = only try version 3.1.1
|
||||
* @li MQTTVERSION_5 (5) = only try version 5
|
||||
*
|
||||
* @deprecated It is preferable to create the options for the desired
|
||||
* version rather than using this function to change the version after
|
||||
* some parameters have already been set. If you do use this function,
|
||||
* call it before setting any other version-specific options. @sa
|
||||
* connect_options::v5()
|
||||
*/
|
||||
void set_mqtt_version(int mqttVersion);
|
||||
/**
|
||||
* Enable or disable automatic reconnects.
|
||||
* The retry intervals are not affected.
|
||||
* @param on Whether to turn reconnects on or off
|
||||
*/
|
||||
void set_automatic_reconnect(bool on) {
|
||||
opts_.automaticReconnect = to_int(on);
|
||||
}
|
||||
/**
|
||||
* Enable or disable automatic reconnects.
|
||||
* @param minRetryInterval Minimum retry interval in seconds. Doubled
|
||||
* on each failed retry.
|
||||
* @param maxRetryInterval Maximum retry interval in seconds. The
|
||||
* doubling stops here on failed retries.
|
||||
*/
|
||||
void set_automatic_reconnect(int minRetryInterval, int maxRetryInterval);
|
||||
/**
|
||||
* Enable or disable automatic reconnects.
|
||||
* @param minRetryInterval Minimum retry interval. Doubled on each
|
||||
* failed retry.
|
||||
* @param maxRetryInterval Maximum retry interval. The doubling stops
|
||||
* here on failed retries.
|
||||
*/
|
||||
template <class Rep1, class Period1, class Rep2, class Period2>
|
||||
void set_automatic_reconnect(const std::chrono::duration<Rep1, Period1>& minRetryInterval,
|
||||
const std::chrono::duration<Rep2, Period2>& maxRetryInterval) {
|
||||
set_automatic_reconnect((int) to_seconds_count(minRetryInterval),
|
||||
(int) to_seconds_count(maxRetryInterval));
|
||||
}
|
||||
/**
|
||||
* Gets the connect properties.
|
||||
* @return A const reference to the properties for the connect.
|
||||
*/
|
||||
const properties& get_properties() const { return props_; }
|
||||
/**
|
||||
* Gets a mutable reference to the connect properties.
|
||||
* @return A reference to the properties for the connect.
|
||||
*/
|
||||
properties& get_properties() { return props_; }
|
||||
/**
|
||||
* Sets the properties for the connect.
|
||||
* @param props The properties to place into the message.
|
||||
*/
|
||||
void set_properties(const properties& props);
|
||||
/**
|
||||
* Moves the properties for the connect.
|
||||
* @param props The properties to move into the connect object.
|
||||
*/
|
||||
void set_properties(properties&& props);
|
||||
/**
|
||||
* Gets the HTTP headers
|
||||
* @return A const reference to the HTTP headers name/value collection.
|
||||
*/
|
||||
const name_value_collection& get_http_headers() const {
|
||||
return httpHeaders_;
|
||||
}
|
||||
/**
|
||||
* Sets the HTTP headers for the connection.
|
||||
* @param httpHeaders The header nam/value collection.
|
||||
*/
|
||||
void set_http_headers(const name_value_collection& httpHeaders) {
|
||||
httpHeaders_ = httpHeaders;
|
||||
opts_.httpHeaders = httpHeaders_.empty() ? nullptr : httpHeaders_.c_arr();
|
||||
}
|
||||
/**
|
||||
* Sets the HTTP headers for the connection.
|
||||
* @param httpHeaders The header nam/value collection.
|
||||
*/
|
||||
void set_http_headers(name_value_collection&& httpHeaders) {
|
||||
httpHeaders_ = std::move(httpHeaders);
|
||||
opts_.httpHeaders = httpHeaders_.empty() ? nullptr : httpHeaders_.c_arr();
|
||||
}
|
||||
/**
|
||||
* Gets the HTTP proxy setting.
|
||||
* @return The HTTP proxy setting. An empty string means no proxy.
|
||||
*/
|
||||
string get_http_proxy() const { return httpProxy_; }
|
||||
/**
|
||||
* Sets the HTTP proxy setting.
|
||||
* @param httpProxy The HTTP proxy setting. An empty string means no
|
||||
* proxy.
|
||||
*/
|
||||
void set_http_proxy(const string& httpProxy);
|
||||
/**
|
||||
* Gets the secure HTTPS proxy setting.
|
||||
* @return The HTTPS proxy setting. An empty string means no proxy.
|
||||
*/
|
||||
string get_https_proxy() const { return httpsProxy_; }
|
||||
/**
|
||||
* Sets the secure HTTPS proxy setting.
|
||||
* @param httpsProxy The HTTPS proxy setting. An empty string means no
|
||||
* proxy.
|
||||
*/
|
||||
void set_https_proxy(const string& httpsProxy);
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to a connection options object. */
|
||||
using connect_options_ptr = connect_options::ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The connect options that can be updated before an automatic reconnect.
|
||||
*/
|
||||
class connect_data
|
||||
{
|
||||
/** The default C struct */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTAsync_connectData DFLT_C_STRUCT;
|
||||
|
||||
/** The underlying C connect data */
|
||||
MQTTAsync_connectData data_;
|
||||
|
||||
/** The user name to use for the connection. */
|
||||
string_ref userName_;
|
||||
|
||||
/** The password to use for the connection. (Optional) */
|
||||
binary_ref password_;
|
||||
|
||||
/** The client has special access */
|
||||
friend class async_client;
|
||||
|
||||
/**
|
||||
* Updates the underlying C structure to match our strings.
|
||||
*/
|
||||
void update_c_struct();
|
||||
|
||||
/**
|
||||
* Create data from a C struct
|
||||
* This is a deep copy of the data from the C struct.
|
||||
* @param cdata The C connect data.
|
||||
*/
|
||||
connect_data(const MQTTAsync_connectData& cdata);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an empty set of connection data.
|
||||
*/
|
||||
connect_data();
|
||||
/**
|
||||
* Creates connection data with a user name, but no password.
|
||||
* @param userName The user name for reconnecting to the MQTT broker.
|
||||
*/
|
||||
explicit connect_data(string_ref userName);
|
||||
/**
|
||||
* Creates connection data with a user name and password.
|
||||
* @param userName The user name for reconnecting to the MQTT broker.
|
||||
* @param password The password for connecting to the MQTT broker.
|
||||
*/
|
||||
connect_data(string_ref userName, binary_ref password);
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param other Another data struct to copy into this one.
|
||||
*/
|
||||
connect_data(const connect_data& other);
|
||||
/**
|
||||
* Copy the connection data.
|
||||
* @param rhs Another data struct to copy into this one.
|
||||
* @return A reference to this data
|
||||
*/
|
||||
connect_data& operator=(const connect_data& rhs);
|
||||
/**
|
||||
* Gets the user name to use for the connection.
|
||||
* @return The user name to use for the connection.
|
||||
*/
|
||||
string get_user_name() const { return userName_ ? userName_.to_string() : string(); }
|
||||
/**
|
||||
* Gets the password to use for the connection.
|
||||
* @return The password to use for the connection.
|
||||
*/
|
||||
binary_ref get_password() const { return password_; }
|
||||
/**
|
||||
* Sets the user name to use for the connection.
|
||||
* @param userName The user name for connecting to the MQTT broker.
|
||||
*/
|
||||
void set_user_name(string_ref userName);
|
||||
/**
|
||||
* Sets the password to use for the connection.
|
||||
* @param password The password for connecting to the MQTT broker.
|
||||
*/
|
||||
void set_password(binary_ref password);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Class to build connect options.
|
||||
*/
|
||||
class connect_options_builder
|
||||
{
|
||||
connect_options opts_;
|
||||
|
||||
public:
|
||||
/** This class */
|
||||
using self = connect_options_builder;
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @param ver The MQTT version for the connection. Defaults to the most
|
||||
* recent v3 supported by the server.
|
||||
*/
|
||||
explicit connect_options_builder(int ver=MQTTVERSION_DEFAULT) : opts_(ver) {}
|
||||
/**
|
||||
* Copy constructor from an existing set of options.
|
||||
*/
|
||||
explicit connect_options_builder(const connect_options& opts) : opts_(opts) {}
|
||||
/**
|
||||
* Move constructor from an existing set of options.
|
||||
*/
|
||||
explicit connect_options_builder(const connect_options&& opts) : opts_(std::move(opts)) {}
|
||||
/**
|
||||
* Creates the default options builder for an MQTT v3.x connection.
|
||||
* @return An options builder for an MQTT v3.x connection.
|
||||
*/
|
||||
static connect_options_builder v3() {
|
||||
return connect_options_builder{ connect_options::v3() };
|
||||
}
|
||||
/**
|
||||
* Creates the default options builder for an MQTT v5 connection.
|
||||
* @return An options builder for an MQTT v5 connection.
|
||||
*/
|
||||
static connect_options_builder v5() {
|
||||
return connect_options_builder{ connect_options::v5() };
|
||||
}
|
||||
/**
|
||||
* Creates the default options builder for an MQTT v3.x connection using
|
||||
* WebSockets.
|
||||
*
|
||||
* The keepalive interval is set to 45 seconds to avoid webserver 60
|
||||
* second inactivity timeouts.
|
||||
*
|
||||
* @return An options builder for an MQTT v3.x connection using
|
||||
* websockets.
|
||||
*/
|
||||
static connect_options_builder ws() {
|
||||
return connect_options_builder{ connect_options::ws() };
|
||||
}
|
||||
/**
|
||||
* Creates the default options for an MQTT v5 connection using
|
||||
* WebSockets
|
||||
* .
|
||||
* The keepalive interval is set to 45 seconds to avoid webserver 60
|
||||
* second inactivity timeouts.
|
||||
*
|
||||
* @return An options builder for an MQTT v5 connection using
|
||||
* websockets.
|
||||
*/
|
||||
static connect_options_builder v5_ws() {
|
||||
return connect_options_builder{ connect_options::v5_ws() };
|
||||
}
|
||||
/**
|
||||
* Sets whether the server should remember state for the client across
|
||||
* reconnects. (MQTT v3.x only)
|
||||
* @param on @em true if the server should NOT remember state for the
|
||||
* client across reconnects, @em false otherwise.
|
||||
*/
|
||||
auto clean_session(bool on=true) -> self& {
|
||||
opts_.set_clean_session(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the "keep alive" interval with a chrono duration.
|
||||
* This is the maximum time that should pass without communications
|
||||
* between client and server. If no messages pass in this time, the
|
||||
* client will ping the broker.
|
||||
* @param interval The keep alive interval.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
auto keep_alive_interval(const std::chrono::duration<Rep, Period>& interval) -> self& {
|
||||
opts_.set_keep_alive_interval(interval);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the connect timeout with a chrono duration.
|
||||
* This is the maximum time that the underlying library will wait for a
|
||||
* connection before failing.
|
||||
* @param timeout The connect timeout in seconds.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
auto connect_timeout(const std::chrono::duration<Rep, Period>& timeout) -> self& {
|
||||
opts_.set_connect_timeout(timeout);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the user name to use for the connection.
|
||||
* @param userName
|
||||
*/
|
||||
auto user_name(string_ref userName) -> self& {
|
||||
opts_.set_user_name(userName);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the password to use for the connection.
|
||||
*/
|
||||
auto password(binary_ref password) -> self& {
|
||||
opts_.set_password(password);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the maximum number of messages that can be in-flight
|
||||
* simultaneously.
|
||||
* @param n The maximum number of inflight messages.
|
||||
*/
|
||||
auto max_inflight(int n) -> self& {
|
||||
opts_.set_max_inflight(n);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) for the connection.
|
||||
* @param will The LWT options.
|
||||
*/
|
||||
auto will(const will_options& will) -> self& {
|
||||
opts_.set_will(will);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) for the connection.
|
||||
* @param will The LWT options.
|
||||
*/
|
||||
auto will(will_options&& will) -> self& {
|
||||
opts_.set_will(std::move(will));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the "Last Will and Testament" (LWT) as a message
|
||||
* @param msg The LWT message
|
||||
*/
|
||||
auto will(const message& msg) -> self& {
|
||||
opts_.set_will_message(msg);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the SSL options for the connection.
|
||||
* These will only have an effect if compiled against the SSL version of
|
||||
* the Paho C library, and connecting with a secure URI.
|
||||
* @param ssl The SSL options.
|
||||
*/
|
||||
auto ssl(const ssl_options& ssl) -> self& {
|
||||
opts_.set_ssl(ssl);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the SSL options for the connection.
|
||||
* These will only have an effect if compiled against the SSL version of
|
||||
* the Paho C library, and connecting with a secure URI.
|
||||
* @param ssl The SSL options.
|
||||
*/
|
||||
auto ssl(ssl_options&& ssl) -> self& {
|
||||
opts_.set_ssl(std::move(ssl));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the callback context to a delivery token.
|
||||
* @param tok The delivery token to be used as the callback context.
|
||||
*/
|
||||
auto token(const token_ptr& tok) -> self& {
|
||||
opts_.set_token(tok);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the list of servers to which the client will connect.
|
||||
* @param serverURIs A pointer to a collection of server URI's. Each
|
||||
* entry should be of the form @em
|
||||
* protocol://host:port where @em protocol must be
|
||||
* @em tcp or @em ssl. For @em host, you can specify
|
||||
* either an IP address or a domain name.
|
||||
*/
|
||||
auto servers(const_string_collection_ptr serverURIs) -> self& {
|
||||
opts_.set_servers(serverURIs);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the version of MQTT to be used on the connect.
|
||||
*
|
||||
* This will also set other connect options to legal values dependent on
|
||||
* the selected version.
|
||||
*
|
||||
* @param ver The MQTT protocol version to use for the connection:
|
||||
* @li MQTTVERSION_DEFAULT (0) = default: start with 3.1.1, and if
|
||||
* that fails, fall back to 3.1
|
||||
* @li MQTTVERSION_3_1 (3) = only try version 3.1
|
||||
* @li MQTTVERSION_3_1_1 (4) = only try version 3.1.1
|
||||
* @li MQTTVERSION_5 (5) = only try version 5
|
||||
*
|
||||
* @deprecated It is preferable to create the options builder for the
|
||||
* desired version rather than using this function to change the
|
||||
* version after some parameters have already been set. If you do use
|
||||
* this function, call it before setting any other version-specific
|
||||
* options. @sa connect_options_builder::v5()
|
||||
*/
|
||||
auto mqtt_version(int ver) -> self& {
|
||||
opts_.set_mqtt_version(ver);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Enable or disable automatic reconnects.
|
||||
* The retry intervals are not affected.
|
||||
* @param on Whether to turn reconnects on or off
|
||||
*/
|
||||
auto automatic_reconnect(bool on=true) -> self& {
|
||||
opts_.set_automatic_reconnect(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Enable or disable automatic reconnects.
|
||||
* @param minRetryInterval Minimum retry interval. Doubled on each
|
||||
* failed retry.
|
||||
* @param maxRetryInterval Maximum retry interval. The doubling stops
|
||||
* here on failed retries.
|
||||
*/
|
||||
template <class Rep1, class Period1, class Rep2, class Period2>
|
||||
auto automatic_reconnect(const std::chrono::duration<Rep1, Period1>& minRetryInterval,
|
||||
const std::chrono::duration<Rep2, Period2>& maxRetryInterval) -> self& {
|
||||
opts_.set_automatic_reconnect(minRetryInterval, maxRetryInterval);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the 'clean start' flag for the connection. (MQTT v5 only)
|
||||
* @param on @em true to set the 'clean start' flag for the connect,
|
||||
* @em false otherwise.
|
||||
*/
|
||||
auto clean_start(bool on=true) -> self& {
|
||||
opts_.set_clean_start(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the properties for the connect message.
|
||||
* @param props The properties for the connect message.
|
||||
*/
|
||||
auto properties(const mqtt::properties& props) -> self& {
|
||||
opts_.set_properties(props);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the properties for the connect message.
|
||||
* @param props The properties for the connect message.
|
||||
*/
|
||||
auto properties(mqtt::properties&& props) -> self& {
|
||||
opts_.set_properties(std::move(props));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the HTTP headers for the connection.
|
||||
* @param headers The header nam/value collection.
|
||||
*/
|
||||
auto http_headers(const name_value_collection& headers) -> self& {
|
||||
opts_.set_http_headers(headers);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the HTTP headers for the connection.
|
||||
* @param headers The header nam/value collection.
|
||||
*/
|
||||
auto http_headers(name_value_collection&& headers) -> self& {
|
||||
opts_.set_http_headers(std::move(headers));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the HTTP proxy setting.
|
||||
* @param httpProxy The HTTP proxy setting. An empty string means no
|
||||
* proxy.
|
||||
*/
|
||||
auto http_proxy(const string& httpProxy) -> self& {
|
||||
opts_.set_http_proxy(httpProxy);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the secure HTTPS proxy setting.
|
||||
* @param httpsProxy The HTTPS proxy setting. An empty string means no
|
||||
* proxy.
|
||||
*/
|
||||
auto https_proxy(const string& httpsProxy) -> self& {
|
||||
opts_.set_https_proxy(httpsProxy);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Finish building the options and return them.
|
||||
* @return The option struct as built.
|
||||
*/
|
||||
connect_options finalize() { return opts_; }
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_connect_options_h
|
||||
|
||||
271
src/mqtt/include/mqtt/create_options.h
Normal file
271
src/mqtt/include/mqtt/create_options.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file create_options.h
|
||||
/// Declaration of MQTT create_options class
|
||||
/// @date Oct 17, 2020
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020-2023 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_create_options_h
|
||||
#define __mqtt_create_options_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Options for creating a client object.
|
||||
*/
|
||||
class create_options
|
||||
{
|
||||
/** The default C struct */
|
||||
static const MQTTAsync_createOptions DFLT_C_STRUCT;
|
||||
|
||||
/** The underlying C options */
|
||||
MQTTAsync_createOptions opts_;
|
||||
|
||||
/** The client and tests have special access */
|
||||
friend class async_client;
|
||||
friend class create_options_builder;
|
||||
|
||||
public:
|
||||
/** Smart/shared pointer to an object of this class. */
|
||||
using ptr_t = std::shared_ptr<create_options>;
|
||||
/** Smart/shared pointer to a const object of this class. */
|
||||
using const_ptr_t = std::shared_ptr<const create_options>;
|
||||
|
||||
/**
|
||||
* Default set of client create options.
|
||||
*/
|
||||
create_options();
|
||||
/**
|
||||
* Default create options for the specified version of MQTT.
|
||||
* @param mqttVersion The MQTT version used to create the client.
|
||||
*/
|
||||
explicit create_options(int mqttVersion);
|
||||
/**
|
||||
* Default create options, but with off-line buffering enabled.
|
||||
* @param mqttVersion The MQTT version used to create the client.
|
||||
* @param maxBufferedMessages the maximum number of messages allowed to
|
||||
* be buffered while not connected
|
||||
*/
|
||||
create_options(int mqttVersion, int maxBufferedMessages);
|
||||
/**
|
||||
* Gets whether the client will accept message to publish while
|
||||
* disconnected.
|
||||
*/
|
||||
bool get_send_while_disconnected() const {
|
||||
return to_bool(opts_.sendWhileDisconnected);
|
||||
}
|
||||
/**
|
||||
* Sets whether the client will accept message to publish while
|
||||
* disconnected.
|
||||
*
|
||||
* @param on @em true to allow the application to publish messages while
|
||||
* disconnected, @em false returns an error on publish if
|
||||
* disconnected.
|
||||
* @param anyTime If @em true, allows you to publish messages before the
|
||||
* first successful connection.
|
||||
*/
|
||||
void set_send_while_disconnected(bool on, bool anyTime=false) {
|
||||
opts_.sendWhileDisconnected = to_int(on);
|
||||
opts_.allowDisconnectedSendAtAnyTime = to_int(anyTime);
|
||||
}
|
||||
/**
|
||||
* Gets the maximum number of offline buffered messages.
|
||||
* @return The maximum number of offline buffered messages.
|
||||
*/
|
||||
int get_max_buffered_messages() const {
|
||||
return opts_.maxBufferedMessages;
|
||||
}
|
||||
/**
|
||||
* Sets the maximum number of offline buffered messages.
|
||||
* @param n The maximum number of offline buffered messages.
|
||||
*/
|
||||
void set_max_buffered_messages(int n) {
|
||||
opts_.maxBufferedMessages = n;
|
||||
}
|
||||
/**
|
||||
* Gets the MQTT version used to create the client.
|
||||
* @return The MQTT version used to create the client.
|
||||
*/
|
||||
int mqtt_version() const { return opts_.MQTTVersion; }
|
||||
/**
|
||||
* Sets the MQTT version used to create the client.
|
||||
* @param ver The MQTT version used to create the client.
|
||||
*/
|
||||
void set_mqtt_version(int ver) { opts_.MQTTVersion = ver; }
|
||||
/**
|
||||
* Whether the oldest messages are deleted when the output buffer is
|
||||
* full.
|
||||
*
|
||||
* @return @em true if the oldest messages should be deleted when the
|
||||
* output buffer is full, @em false if the new messages should
|
||||
* be dropped when the buffer is full.
|
||||
*/
|
||||
bool get_delete_oldest_messages() const {
|
||||
return to_bool(opts_.deleteOldestMessages);
|
||||
}
|
||||
/**
|
||||
* Determines what to do when the maximum number of buffered messages is
|
||||
* reached: delete the oldest messages rather than the newest
|
||||
* @param on @em true When the output queue is full, delete the oldest
|
||||
* message, @em false drop the newest message being added.
|
||||
*/
|
||||
void set_delete_oldest_messages(bool on) {
|
||||
opts_.deleteOldestMessages = to_int(on);
|
||||
}
|
||||
/**
|
||||
* Whether the messages will be restored from persistence or the store
|
||||
* will be cleared.
|
||||
* @return @em true if the messages will be restored from persistence,
|
||||
* @em false if the persistence store will be cleared.
|
||||
*/
|
||||
bool get_restore_messages() const {
|
||||
return to_bool(opts_.restoreMessages);
|
||||
}
|
||||
/**
|
||||
* Determine whether to restore messages from persistence or clear the
|
||||
* persistence store.
|
||||
* @param on @em true to restore messages from persistence, @em false to
|
||||
* clear the persistence store.
|
||||
*/
|
||||
void set_restore_messages(bool on) {
|
||||
opts_.restoreMessages = to_int(on);
|
||||
}
|
||||
/**
|
||||
* Whether to persist QoS 0 messages.
|
||||
*
|
||||
* @return @em true if QoS 0 messages are persisted, @em false if not.
|
||||
*/
|
||||
bool get_persist_qos0() const {
|
||||
return to_bool(opts_.persistQoS0);
|
||||
}
|
||||
/**
|
||||
* Determine whether to persist QoS 0 messages.
|
||||
*
|
||||
* @param on @em true if QoS 0 messages are persisted, @em false if not.
|
||||
*/
|
||||
void set_persist_qos0(bool on) {
|
||||
opts_.persistQoS0 = to_int(on);
|
||||
}
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to a connection options object. */
|
||||
using create_options_ptr = create_options::ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Builder class to generate the create options.
|
||||
*/
|
||||
class create_options_builder
|
||||
{
|
||||
/** The underlying options */
|
||||
create_options opts_;
|
||||
|
||||
public:
|
||||
/** This class */
|
||||
using self = create_options_builder;
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
create_options_builder() {}
|
||||
/**
|
||||
*
|
||||
* Sets whether the client will accept message to publish while
|
||||
* disconnected.
|
||||
*
|
||||
* @param on @em true to allow the application to publish messages while
|
||||
* disconnected, @em false returns an error on publish if
|
||||
* disconnected.
|
||||
* @param anyTime If @em true, allows you to publish messages before the
|
||||
* first successful connection.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
auto send_while_disconnected(bool on=true, bool anyTime=false) -> self& {
|
||||
opts_.opts_.sendWhileDisconnected = to_int(on);
|
||||
opts_.opts_.allowDisconnectedSendAtAnyTime = to_int(anyTime);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the maximum number of offline buffered messages.
|
||||
* @param n The maximum number of offline buffered messages.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
auto max_buffered_messages(int n) -> self& {
|
||||
opts_.opts_.maxBufferedMessages = n;
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the MQTT version used to create the client.
|
||||
* @param ver The MQTT version used to create the client.
|
||||
*/
|
||||
auto mqtt_version(int ver) -> self& {
|
||||
opts_.opts_.MQTTVersion = ver;
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Determines what to do when the maximum number of buffered messages is
|
||||
* reached: delete the oldest messages rather than the newest.
|
||||
* @param on @em true When the output queue is full, delete the oldest
|
||||
* message, @em false drop the newest message being added.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
auto delete_oldest_messages(bool on=true) -> self& {
|
||||
opts_.opts_.deleteOldestMessages = to_int(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Determines whether to restore persisted messages or clear the
|
||||
* persistence store. (Defaults true)
|
||||
*
|
||||
* @param on @em true to restore persisted messages, @em false to clear
|
||||
* the persistence store.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
auto restore_messages(bool on=true) -> self& {
|
||||
opts_.opts_.restoreMessages = to_int(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Whether to persist QoS 0 messages. (Defaults true)
|
||||
*
|
||||
* @param on @em true persist QoS 0 messages, @em false, don't.
|
||||
* @return A reference to this object
|
||||
*/
|
||||
auto persist_qos0(bool on=true) -> self& {
|
||||
opts_.opts_.persistQoS0 = to_int(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Finish building the options and return them.
|
||||
* @return The option struct as built.
|
||||
*/
|
||||
create_options finalize() { return opts_; }
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_create_options_h
|
||||
|
||||
135
src/mqtt/include/mqtt/delivery_token.h
Normal file
135
src/mqtt/include/mqtt/delivery_token.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file delivery_token.h
|
||||
/// Declaration of MQTT delivery_token class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2016 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_delivery_token_h
|
||||
#define __mqtt_delivery_token_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/token.h"
|
||||
#include "mqtt/message.h"
|
||||
#include <memory>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Provides a mechanism to track the delivery progress of a message.
|
||||
* Used to track the the delivery progress of a message when a publish is
|
||||
* executed in a non-blocking manner (run in the background) action.
|
||||
*/
|
||||
class delivery_token : public token
|
||||
{
|
||||
/** The message being tracked. */
|
||||
const_message_ptr msg_;
|
||||
|
||||
/** Client has special access. */
|
||||
friend class async_client;
|
||||
|
||||
/**
|
||||
* Sets the message to which this token corresponds.
|
||||
* @param msg
|
||||
*/
|
||||
void set_message(const_message_ptr msg) { msg_ = msg; }
|
||||
|
||||
public:
|
||||
/** Smart/shared pointer to an object of this class */
|
||||
using ptr_t = std::shared_ptr<delivery_token>;
|
||||
/** Smart/shared pointer to a const object of this class */
|
||||
using const_ptr_t = std::shared_ptr<delivery_token>;
|
||||
/** Weak pointer to an object of this class */
|
||||
using weak_ptr_t = std::weak_ptr<delivery_token>;
|
||||
|
||||
/**
|
||||
* Creates an empty delivery token connected to a particular client.
|
||||
* @param cli The asynchronous client object.
|
||||
*/
|
||||
delivery_token(iasync_client& cli) : token(token::Type::PUBLISH, cli) {}
|
||||
/**
|
||||
* Creates a delivery token connected to a particular client.
|
||||
* @param cli The asynchronous client object.
|
||||
* @param msg The message being tracked.
|
||||
*/
|
||||
delivery_token(iasync_client& cli, const_message_ptr msg)
|
||||
: token(token::Type::PUBLISH, cli, msg->get_topic()), msg_(std::move(msg)) {}
|
||||
/**
|
||||
* Creates a delivery token connected to a particular client.
|
||||
* @param cli The asynchronous client object.
|
||||
* @param msg The message data.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback optional listener that will be notified when message
|
||||
* delivery has completed to the requested quality of
|
||||
* service
|
||||
*/
|
||||
delivery_token(iasync_client& cli, const_message_ptr msg,
|
||||
void* userContext, iaction_listener& cb)
|
||||
: token(token::Type::PUBLISH, cli, msg->get_topic(), userContext, cb), msg_(std::move(msg)) {}
|
||||
/**
|
||||
* Creates an empty delivery token connected to a particular client.
|
||||
* @param cli The asynchronous client object.
|
||||
*/
|
||||
static ptr_t create(iasync_client& cli) {
|
||||
return std::make_shared<delivery_token>(cli);
|
||||
}
|
||||
/**
|
||||
* Creates a delivery token connected to a particular client.
|
||||
* @param cli The asynchronous client object.
|
||||
* @param msg The message data.
|
||||
*/
|
||||
static ptr_t create(iasync_client& cli, const_message_ptr msg) {
|
||||
return std::make_shared<delivery_token>(cli, msg);
|
||||
}
|
||||
/**
|
||||
* Creates a delivery token connected to a particular client.
|
||||
* @param cli The asynchronous client object.
|
||||
* @param msg The message data.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback optional listener that will be notified when message
|
||||
* delivery has completed to the requested quality of
|
||||
* service
|
||||
*/
|
||||
static ptr_t create(iasync_client& cli, const_message_ptr msg,
|
||||
void* userContext, iaction_listener& cb) {
|
||||
return std::make_shared<delivery_token>(cli, msg, userContext, cb);
|
||||
}
|
||||
/**
|
||||
* Gets the message associated with this token.
|
||||
* @return The message associated with this token.
|
||||
*/
|
||||
virtual const_message_ptr get_message() const { return msg_; }
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to a delivery_token */
|
||||
using delivery_token_ptr = delivery_token::ptr_t;
|
||||
|
||||
/** Smart/shared pointer to a const delivery_token */
|
||||
using const_delivery_token_ptr = delivery_token::const_ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_delivery_token_h
|
||||
|
||||
281
src/mqtt/include/mqtt/disconnect_options.h
Normal file
281
src/mqtt/include/mqtt/disconnect_options.h
Normal file
@@ -0,0 +1,281 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file disconnect_options.h
|
||||
/// Implementation of the class 'disconnect_options'
|
||||
/// @date 26-Aug-2016
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2016-2017 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __mqtt_disconnect_options_h
|
||||
#define __mqtt_disconnect_options_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
#include "mqtt/token.h"
|
||||
#include "mqtt/properties.h"
|
||||
#include <chrono>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Options for disconnecting from an MQTT broker.
|
||||
*/
|
||||
class disconnect_options
|
||||
{
|
||||
/** The default C struct */
|
||||
static const MQTTAsync_disconnectOptions DFLT_C_STRUCT;
|
||||
|
||||
/** The default C struct */
|
||||
static const MQTTAsync_disconnectOptions DFLT_C_STRUCT5;
|
||||
|
||||
/** The underlying C disconnect options */
|
||||
MQTTAsync_disconnectOptions opts_;
|
||||
|
||||
/** Shared token pointer for context, if any */
|
||||
token_ptr tok_;
|
||||
|
||||
/** Disconnect message properties */
|
||||
properties props_;
|
||||
|
||||
/** The client has special access */
|
||||
friend class async_client;
|
||||
|
||||
/** The options builder has special access */
|
||||
friend class disconnect_options_builder;
|
||||
|
||||
/**
|
||||
* Updates the underlying C structure to match our cached data.
|
||||
*/
|
||||
void update_c_struct();
|
||||
|
||||
/** Construct options from a C struct */
|
||||
disconnect_options(const MQTTAsync_disconnectOptions& copts) : opts_{copts} {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create an empty delivery response object.
|
||||
*/
|
||||
disconnect_options();
|
||||
/**
|
||||
* Creates disconnect options tied to the specific token.
|
||||
* @param timeout The timeout (in milliseconds).
|
||||
*/
|
||||
disconnect_options(int timeout) : disconnect_options() {
|
||||
set_timeout(timeout);
|
||||
}
|
||||
/**
|
||||
* Creates disconnect options tied to the specific token.
|
||||
* @param to The timeout.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
disconnect_options(const std::chrono::duration<Rep, Period>& to)
|
||||
: disconnect_options() {
|
||||
set_timeout(to);
|
||||
}
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param opt Another object to copy.
|
||||
*/
|
||||
disconnect_options(const disconnect_options& opt);
|
||||
/**
|
||||
* Move constructor.
|
||||
* @param opt Another object to move into this new one.
|
||||
*/
|
||||
disconnect_options(disconnect_options&& opt);
|
||||
/**
|
||||
* Creates default options for an MQTT v3.x connection.
|
||||
* @return Default options for an MQTT v3.x connection.
|
||||
*/
|
||||
static disconnect_options v3();
|
||||
/**
|
||||
* Creates default options for an MQTT v5 connection.
|
||||
* @return Default options for an MQTT v5 connection.
|
||||
*/
|
||||
static disconnect_options v5();
|
||||
/**
|
||||
* Copy assignment.
|
||||
* @param opt Another object to copy.
|
||||
*/
|
||||
disconnect_options& operator=(const disconnect_options& opt);
|
||||
/**
|
||||
* Move assignment.
|
||||
* @param opt Another object to move into this new one.
|
||||
*/
|
||||
disconnect_options& operator=(disconnect_options&& opt);
|
||||
/**
|
||||
* Expose the underlying C struct for the unit tests.
|
||||
*/
|
||||
#if defined(UNIT_TESTS)
|
||||
const MQTTAsync_disconnectOptions& c_struct() const { return opts_; }
|
||||
#endif
|
||||
/**
|
||||
* Gets the timeout used for disconnecting.
|
||||
* @return The timeout for disconnecting (in milliseconds).
|
||||
*/
|
||||
std::chrono::milliseconds get_timeout() const {
|
||||
return std::chrono::milliseconds(opts_.timeout);
|
||||
}
|
||||
/**
|
||||
* Sets the disconnect timeout, in milliseconds.
|
||||
* This allows for any remaining in-flight messages to be delivered.
|
||||
* @param timeout The disconnect timeout (in milliseconds).
|
||||
*/
|
||||
void set_timeout(int timeout) { opts_.timeout = timeout; }
|
||||
/**
|
||||
* Sets the disconnect timeout with a duration.
|
||||
* This allows for any remaining in-flight messages to be delivered.
|
||||
* @param to The disconnect connect timeout.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
void set_timeout(const std::chrono::duration<Rep, Period>& to) {
|
||||
// TODO: check range
|
||||
set_timeout((int) to_milliseconds_count(to));
|
||||
}
|
||||
/**
|
||||
* Sets the callback context to a delivery token.
|
||||
* @param tok The delivery token to be used as the callback context.
|
||||
* @param mqttVersion The version of MQTT we're using for the
|
||||
* connection.
|
||||
*/
|
||||
void set_token(const token_ptr& tok, int mqttVersion);
|
||||
/**
|
||||
* Gets the callback context to a delivery token.
|
||||
* @return The delivery token to be used as the callback context.
|
||||
*/
|
||||
token_ptr get_token() const { return tok_; }
|
||||
/**
|
||||
* Gets the disconnect properties.
|
||||
* @return A const reference to the properties for the disconnect.
|
||||
*/
|
||||
const properties& get_properties() const { return props_; }
|
||||
/**
|
||||
* Gets a mutable reference to the disconnect properties.
|
||||
* @return A mutable reference to the properties for the disconnect.
|
||||
*/
|
||||
properties& get_properties() { return props_; }
|
||||
/**
|
||||
* Sets the properties for the connect.
|
||||
* @param props The properties to place into the message.
|
||||
*/
|
||||
void set_properties(const properties& props) {
|
||||
props_ = props;
|
||||
opts_.properties = props_.c_struct();
|
||||
}
|
||||
/**
|
||||
* Moves the properties for the connect.
|
||||
* @param props The properties to move into the connect object.
|
||||
*/
|
||||
void set_properties(properties&& props) {
|
||||
props_ = std::move(props);
|
||||
opts_.properties = props_.c_struct();
|
||||
}
|
||||
/**
|
||||
* Gets the reason code for the disconnect.
|
||||
* @return The reason code for the disconnect.
|
||||
*/
|
||||
ReasonCode get_reason_code() const {
|
||||
return ReasonCode(opts_.reasonCode);
|
||||
}
|
||||
/**
|
||||
* Sets the reason code for the disconnect.
|
||||
* @param code The reason code for the disconnect.
|
||||
*/
|
||||
void set_reason_code(ReasonCode code) {
|
||||
opts_.reasonCode = MQTTReasonCodes(code);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Class to build connect options.
|
||||
*/
|
||||
class disconnect_options_builder
|
||||
{
|
||||
/** The underlying options */
|
||||
disconnect_options opts_;
|
||||
|
||||
/** Construct options builder from a C struct */
|
||||
disconnect_options_builder(const MQTTAsync_disconnectOptions& copts) : opts_{copts} {}
|
||||
|
||||
public:
|
||||
/** This class */
|
||||
using self = disconnect_options_builder;
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
disconnect_options_builder() {}
|
||||
/**
|
||||
* Creates default options builder for an MQTT v3.x connection.
|
||||
* @return Default options builder for an MQTT v3.x connection.
|
||||
*/
|
||||
static disconnect_options_builder v3();
|
||||
/**
|
||||
* Creates default options builder for an MQTT v5 connection.
|
||||
* @return Default options builder for an MQTT v5 connection.
|
||||
*/
|
||||
static disconnect_options_builder v5();
|
||||
/**
|
||||
* Sets the properties for the disconnect message.
|
||||
* @param props The properties for the disconnect message.
|
||||
*/
|
||||
auto properties(mqtt::properties&& props) -> self& {
|
||||
opts_.set_properties(std::move(props));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the properties for the disconnect message.
|
||||
* @param props The properties for the disconnect message.
|
||||
*/
|
||||
auto properties(const mqtt::properties& props) -> self& {
|
||||
opts_.set_properties(props);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the disconnect connect timeout.
|
||||
* This allows for any remaining in-flight messages to be delivered.
|
||||
* @param to The disconnect timeout.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
auto timeout(const std::chrono::duration<Rep, Period>& to) -> self&{
|
||||
opts_.set_timeout(to);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the reason code for the disconnect.
|
||||
* @param code The reason code for the disconnect.
|
||||
*/
|
||||
auto reason_code(ReasonCode code) -> self& {
|
||||
opts_.set_reason_code(code);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Finish building the options and return them.
|
||||
* @return The option struct as built.
|
||||
*/
|
||||
disconnect_options finalize() { return opts_; }
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace 'mqtt'
|
||||
}
|
||||
|
||||
#endif // __mqtt_disconnect_options_h
|
||||
|
||||
261
src/mqtt/include/mqtt/exception.h
Normal file
261
src/mqtt/include/mqtt/exception.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file exception.h
|
||||
/// Declaration of MQTT exception class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2019 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_exception_h
|
||||
#define __mqtt_exception_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/** Bring std::bad_cast into the mqtt namespace */
|
||||
using bad_cast = std::bad_cast;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Base mqtt::exception.
|
||||
* This wraps the error codes which originate from the underlying C library.
|
||||
*/
|
||||
class exception : public std::runtime_error
|
||||
{
|
||||
protected:
|
||||
/** The error return code from the C library */
|
||||
int rc_;
|
||||
/** The reason code from the server */
|
||||
ReasonCode reasonCode_;
|
||||
/** The error message from the C library */
|
||||
string msg_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an MQTT exception.
|
||||
* @param rc The error return code from the C library.
|
||||
*/
|
||||
explicit exception(int rc)
|
||||
: exception(rc, error_str(rc)) {}
|
||||
/**
|
||||
* Creates an MQTT exception.
|
||||
* @param rc The error return code from the C library.
|
||||
* @param reasonCode The reason code from the server response.
|
||||
*/
|
||||
explicit exception(int rc, ReasonCode reasonCode)
|
||||
: exception(rc, reasonCode, error_str(rc)) {}
|
||||
/**
|
||||
* Creates an MQTT exception.
|
||||
* @param rc The error return code from the C library.
|
||||
* @param msg The text message for the error.
|
||||
*/
|
||||
exception(int rc, const string& msg)
|
||||
: std::runtime_error(printable_error(rc, ReasonCode::SUCCESS, msg)),
|
||||
rc_(rc), reasonCode_(ReasonCode::SUCCESS), msg_(msg) {}
|
||||
/**
|
||||
* Creates an MQTT exception.
|
||||
* @param rc The error return code from the C library.
|
||||
* @param reasonCode The reason code from the server
|
||||
* @param msg The text message for the error.
|
||||
*/
|
||||
exception(int rc, ReasonCode reasonCode, const string& msg)
|
||||
: std::runtime_error(printable_error(rc, reasonCode, msg)),
|
||||
rc_(rc), reasonCode_(reasonCode), msg_(msg) {}
|
||||
/**
|
||||
* Gets an error message from an error code.
|
||||
* @param rc The error code from the C lib
|
||||
* @return A string explanation of the error
|
||||
*/
|
||||
static string error_str(int rc) {
|
||||
const char *msg = ::MQTTAsync_strerror(rc);
|
||||
return msg ? string(msg) : string();
|
||||
}
|
||||
/**
|
||||
* Gets a string describing the MQTT v5 reason code.
|
||||
* @param reasonCode The MQTT v5 reason code.
|
||||
* @return A string describing the reason code.
|
||||
*/
|
||||
static string reason_code_str(int reasonCode) {
|
||||
if (reasonCode != MQTTPP_V3_CODE) {
|
||||
auto msg = ::MQTTReasonCode_toString(MQTTReasonCodes(reasonCode));
|
||||
if (msg) return string(msg);
|
||||
}
|
||||
return string();
|
||||
}
|
||||
/**
|
||||
* Gets a detailed error message for an error code.
|
||||
* @param rc The error code from the C lib
|
||||
* @param reasonCode The MQTT v5 reason code
|
||||
* @param msg An optional additional message. If none is provided, the
|
||||
* error_str message is used.
|
||||
* @return A string error message that includes the error code and an
|
||||
* explanation message.
|
||||
*/
|
||||
static string printable_error(int rc, int reasonCode=ReasonCode::SUCCESS,
|
||||
const string& msg=string()) {
|
||||
string s = "MQTT error [" + std::to_string(rc) + "]";
|
||||
if (!msg.empty())
|
||||
s += string(": ") + msg;
|
||||
if (reasonCode != MQTTPP_V3_CODE && reasonCode != ReasonCode::SUCCESS)
|
||||
s += string(". Reason: ") + reason_code_str(reasonCode);
|
||||
return s;
|
||||
}
|
||||
/**
|
||||
* Returns the return code for this exception.
|
||||
*/
|
||||
int get_return_code() const { return rc_; }
|
||||
/**
|
||||
* Gets a string of the error code.
|
||||
* @return A string of the error code.
|
||||
*/
|
||||
string get_error_str() const { return error_str(rc_); }
|
||||
/**
|
||||
* Returns the reason code for this exception.
|
||||
* For MQTT v3 connections, this is actually the return code.
|
||||
*/
|
||||
int get_reason_code() const {
|
||||
return reasonCode_ == MQTTPP_V3_CODE ? rc_ : reasonCode_;
|
||||
}
|
||||
/**
|
||||
* Gets a string for the reason code.
|
||||
* @return A string for the reason code.
|
||||
*/
|
||||
string get_reason_code_str() const {
|
||||
return reason_code_str(reasonCode_);
|
||||
}
|
||||
/**
|
||||
* Returns the error message for this exception.
|
||||
*/
|
||||
string get_message() const { return msg_; }
|
||||
/**
|
||||
* Gets a string representation of this exception.
|
||||
* @return A string representation of this exception.
|
||||
*/
|
||||
string to_string() const { return string(what()); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Stream inserter writes a fairly verbose message
|
||||
* @param os The stream.
|
||||
* @param exc The exception to write.
|
||||
* @return A reference to the stream.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& os, const exception& exc) {
|
||||
os << exc.what();
|
||||
return os;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Exception thrown when an expected server response is missing.
|
||||
*/
|
||||
class missing_response : public exception
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a missing response error.
|
||||
* @param rsp A string for the type of response expected.
|
||||
*/
|
||||
missing_response(const string& rsp)
|
||||
: exception(MQTTASYNC_FAILURE, "Missing "+rsp+" response") {}
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A timeout exception, particularly from the synchronous client.
|
||||
*/
|
||||
class timeout_error : public exception
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a timeout error.
|
||||
*/
|
||||
timeout_error() : exception(MQTTASYNC_FAILURE, "Timeout") {}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* This exception is thrown by the implementor of the persistence interface
|
||||
* if there is a problem reading or writing persistent data.
|
||||
*/
|
||||
class persistence_exception : public exception
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates an MQTT persistence exception.
|
||||
*/
|
||||
persistence_exception() : exception(MQTTCLIENT_PERSISTENCE_ERROR) {}
|
||||
/**
|
||||
* Creates an MQTT persistence exception.
|
||||
* @param code The error code from the C library.
|
||||
*/
|
||||
explicit persistence_exception(int code) : exception(code) {}
|
||||
/**
|
||||
* Creates an MQTT persistence exception.
|
||||
* @param msg The text message for the error.
|
||||
*/
|
||||
explicit persistence_exception(const string& msg)
|
||||
: exception(MQTTCLIENT_PERSISTENCE_ERROR, msg) {}
|
||||
/**
|
||||
* Creates an MQTT persistence exception.
|
||||
* @param code The error code
|
||||
* @param msg The text message for the error.
|
||||
*/
|
||||
persistence_exception(int code, const string& msg)
|
||||
: exception(code, msg) {}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Thrown when a client is not authorized to perform an operation, or if
|
||||
* there is a problem with the security configuration.
|
||||
*/
|
||||
class security_exception : public exception
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates an MQTT security exception
|
||||
* @param code The error code.
|
||||
*/
|
||||
explicit security_exception(int code) : exception(code) {}
|
||||
/**
|
||||
* Creates an MQTT security exception
|
||||
* @param code The error code.
|
||||
* @param msg The text message for the error.
|
||||
*/
|
||||
security_exception(int code, const string& msg) : exception(code, msg) {}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_token_h
|
||||
45
src/mqtt/include/mqtt/export.h
Normal file
45
src/mqtt/include/mqtt/export.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file export.h
|
||||
/// Library symbol export definitions, primarily for Windows MSVC DLL's
|
||||
/// @date November 20, 2023
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
* Frank Pagliughi - MQTT v5 support
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_export_h
|
||||
#define __mqtt_export_h
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
#if defined(PAHO_MQTTPP_EXPORTS)
|
||||
#define PAHO_MQTTPP_EXPORT __declspec(dllexport)
|
||||
#elif defined(PAHO_MQTTPP_IMPORTS)
|
||||
#define PAHO_MQTTPP_EXPORT __declspec(dllimport)
|
||||
#else
|
||||
#define PAHO_MQTTPP_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#if defined(PAHO_MQTTPP_EXPORTS)
|
||||
#define PAHO_MQTTPP_EXPORT __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define PAHO_MQTTPP_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // __mqtt_export_h
|
||||
|
||||
84
src/mqtt/include/mqtt/iaction_listener.h
Normal file
84
src/mqtt/include/mqtt/iaction_listener.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file iaction_listener.h
|
||||
/// Declaration of MQTT iaction_listener class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2016 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_iaction_listener_h
|
||||
#define __mqtt_iaction_listener_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
class token;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Provides a mechanism for tracking the completion of an asynchronous
|
||||
* action.
|
||||
*
|
||||
* A listener is registered on a token and that token is associated with
|
||||
* an action like connect or publish. When used with tokens on the
|
||||
* async_client the listener will be called back on the MQTT client's
|
||||
* thread. The listener will be informed if the action succeeds or fails. It
|
||||
* is important that the listener returns control quickly otherwise the
|
||||
* operation of the MQTT client will be stalled.
|
||||
*/
|
||||
class iaction_listener
|
||||
{
|
||||
public:
|
||||
/** Smart/shared pointer to an object of this class. */
|
||||
using ptr_t = std::shared_ptr<iaction_listener>;
|
||||
/** Smart/shared pointer to a const object of this class. */
|
||||
using const_ptr_t = std::shared_ptr<const iaction_listener>;
|
||||
|
||||
/**
|
||||
* Virtual base destructor.
|
||||
*/
|
||||
virtual ~iaction_listener() {}
|
||||
/**
|
||||
* This method is invoked when an action fails.
|
||||
* @param asyncActionToken
|
||||
*/
|
||||
virtual void on_failure(const token& asyncActionToken) =0;
|
||||
/**
|
||||
* This method is invoked when an action has completed successfully.
|
||||
* @param asyncActionToken
|
||||
*/
|
||||
virtual void on_success(const token& asyncActionToken) =0;
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to an action listener */
|
||||
using iaction_listener_ptr = iaction_listener::ptr_t;
|
||||
|
||||
/** Smart/shared pointer to a const action listener */
|
||||
using const_iaction_listener_ptr = iaction_listener::const_ptr_t;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_iaction_listener_h
|
||||
|
||||
460
src/mqtt/include/mqtt/iasync_client.h
Normal file
460
src/mqtt/include/mqtt/iasync_client.h
Normal file
@@ -0,0 +1,460 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file iasync_client.h
|
||||
/// Implementation of the interface for the asynchronous clients,
|
||||
/// 'iasync_client'
|
||||
/// @date 25-Aug-2016
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2016 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef __mqtt_iasync_client_h
|
||||
#define __mqtt_iasync_client_h
|
||||
|
||||
#include "mqtt/types.h"
|
||||
#include "mqtt/token.h"
|
||||
#include "mqtt/delivery_token.h"
|
||||
#include "mqtt/iclient_persistence.h"
|
||||
#include "mqtt/iaction_listener.h"
|
||||
#include "mqtt/connect_options.h"
|
||||
#include "mqtt/disconnect_options.h"
|
||||
#include "mqtt/subscribe_options.h"
|
||||
#include "mqtt/exception.h"
|
||||
#include "mqtt/message.h"
|
||||
#include "mqtt/callback.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Enables an application to communicate with an MQTT server using
|
||||
* non-blocking methods.
|
||||
*
|
||||
* It provides applications a simple programming interface to all features
|
||||
* of the MQTT version 3.1 specification including:
|
||||
*
|
||||
* @li connect
|
||||
* @li publish
|
||||
* @li subscribe
|
||||
* @li unsubscribe
|
||||
* @li disconnect
|
||||
*/
|
||||
class iasync_client
|
||||
{
|
||||
friend class token;
|
||||
virtual void remove_token(token* tok) =0;
|
||||
|
||||
public:
|
||||
/** Type for a collection of QOS values */
|
||||
using qos_collection = std::vector<int>;
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~iasync_client() {}
|
||||
/**
|
||||
* Connects to an MQTT server using the default options.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
virtual token_ptr connect() =0;
|
||||
/**
|
||||
* Connects to an MQTT server using the provided connect options.
|
||||
* @param options a set of connection parameters that override the
|
||||
* defaults.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
virtual token_ptr connect(connect_options options) =0;
|
||||
/**
|
||||
* Connects to an MQTT server using the specified options.
|
||||
*
|
||||
* @param options a set of connection parameters that override the
|
||||
* defaults.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb callback listener that will be notified when the connect
|
||||
* completes.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
virtual token_ptr connect(connect_options options, void* userContext,
|
||||
iaction_listener& cb) =0;
|
||||
/**
|
||||
*
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when the connect completes.
|
||||
* @return token used to track and wait for the connect to complete. The
|
||||
* token will be passed to any callback that has been set.
|
||||
* @throw exception for non security related problems
|
||||
* @throw security_exception for security related problems
|
||||
*/
|
||||
virtual token_ptr connect(void* userContext, iaction_listener& cb) =0;
|
||||
/**
|
||||
* Reconnects the client using options from the previous connect.
|
||||
* The client must have previously called connect() for this to work.
|
||||
* @return token used to track the progress of the reconnect.
|
||||
*/
|
||||
virtual token_ptr reconnect() =0;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
virtual token_ptr disconnect() =0;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param opts Options for disconnecting.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
virtual token_ptr disconnect(disconnect_options opts) =0;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeout the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
virtual token_ptr disconnect(int timeout) =0;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param timeout the amount of time in milliseconds to allow for
|
||||
* existing work to finish before disconnecting. A value
|
||||
* of zero or less means the client will not quiesce.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when the disconnect
|
||||
* completes.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
virtual token_ptr disconnect(int timeout, void* userContext, iaction_listener& cb) =0;
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when the disconnect
|
||||
* completes.
|
||||
* @return token used to track and wait for the disconnect to complete.
|
||||
* The token will be passed to any callback that has been set.
|
||||
* @throw exception for problems encountered while disconnecting
|
||||
*/
|
||||
virtual token_ptr disconnect(void* userContext, iaction_listener& cb) =0;
|
||||
/**
|
||||
* Returns the delivery token for the specified message ID.
|
||||
* @return delivery_token
|
||||
*/
|
||||
virtual delivery_token_ptr get_pending_delivery_token(int msgID) const =0;
|
||||
/**
|
||||
* Returns the delivery tokens for any outstanding publish operations.
|
||||
* @return delivery_token[]
|
||||
*/
|
||||
virtual std::vector<delivery_token_ptr> get_pending_delivery_tokens() const =0;
|
||||
/**
|
||||
* Returns the client ID used by this client.
|
||||
* @return string
|
||||
*/
|
||||
virtual string get_client_id() const =0;
|
||||
/**
|
||||
* Returns the address of the server used by this client.
|
||||
*/
|
||||
virtual string get_server_uri() const =0;
|
||||
/**
|
||||
* Determines if this client is currently connected to the server.
|
||||
*/
|
||||
virtual bool is_connected() const =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
* @param qos the Quality of Service to deliver the message at. Valid
|
||||
* values are 0, 1 or 2.
|
||||
* @param retained whether or not this message should be retained by the
|
||||
* server.
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(string_ref topic,
|
||||
const void* payload, size_t n,
|
||||
int qos, bool retained) =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(string_ref topic,
|
||||
const void* payload, size_t n) =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
* @param qos the Quality of Service to deliver the message at. Valid
|
||||
* values are 0, 1 or 2.
|
||||
* @param retained whether or not this message should be retained by the
|
||||
* server.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(string_ref topic,
|
||||
const void* payload, size_t n,
|
||||
int qos, bool retained,
|
||||
void* userContext, iaction_listener& cb) =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param qos the Quality of Service to deliver the message at. Valid
|
||||
* values are 0, 1 or 2.
|
||||
* @param retained whether or not this message should be retained by the
|
||||
* server.
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(string_ref topic, binary_ref payload,
|
||||
int qos, bool retained) =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server.
|
||||
* @param topic The topic to deliver the message to
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(string_ref topic, binary_ref payload) =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server Takes an Message
|
||||
* message and delivers it to the server at the requested quality of
|
||||
* service.
|
||||
* @param msg the message to deliver to the server
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(const_message_ptr msg) =0;
|
||||
/**
|
||||
* Publishes a message to a topic on the server.
|
||||
* @param msg the message to deliver to the server
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb optional listener that will be notified when message
|
||||
* delivery has completed to the requested quality of service
|
||||
* @return token used to track and wait for the publish to complete. The
|
||||
* token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual delivery_token_ptr publish(const_message_ptr msg,
|
||||
void* userContext, iaction_listener& cb) =0;
|
||||
/**
|
||||
* Sets a callback listener to use for events that happen
|
||||
* asynchronously.
|
||||
* @param cb callback which will be invoked for certain asynchronous
|
||||
* events
|
||||
*/
|
||||
virtual void set_callback(callback& cb) =0;
|
||||
/**
|
||||
* Stops the callbacks.
|
||||
*/
|
||||
virtual void disable_callbacks() =0;
|
||||
/**
|
||||
* Subscribe to a topic, which may include wildcards.
|
||||
* @param topicFilter the topic to subscribe to, which can include
|
||||
* wildcards.
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param opts The options for the subscription.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr subscribe(const string& topicFilter, int qos,
|
||||
const subscribe_options& opts=subscribe_options(),
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Subscribe to a topic, which may include wildcards.
|
||||
* @param topicFilter the topic to subscribe to, which can include
|
||||
* wildcards.
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param callback listener that will be notified when subscribe has
|
||||
* completed
|
||||
* @param opts The options for the subscription.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr subscribe(const string& topicFilter, int qos,
|
||||
void* userContext, iaction_listener& callback,
|
||||
const subscribe_options& opts=subscribe_options(),
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Subscribe to multiple topics, each of which may include wildcards.
|
||||
* Provides an optimized way to subscribe to multiple topics compared to
|
||||
* subscribing to each one individually.
|
||||
* @param topicFilters one or more topics to subscribe to, which can
|
||||
* include wildcards
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param opts A collection of subscription options (one for each
|
||||
* topic)
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr subscribe(const_string_collection_ptr topicFilters,
|
||||
const qos_collection& qos,
|
||||
const std::vector<subscribe_options>& opts=std::vector<subscribe_options>(),
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Subscribes to multiple topics, each of which may include wildcards.
|
||||
* @param topicFilters one or more topics to subscribe to, which can
|
||||
* include wildcards
|
||||
* @param qos the maximum quality of service at which to subscribe.
|
||||
* Messages published at a lower quality of service will be
|
||||
* received at the published QoS. Messages published at a
|
||||
* higher quality of service will be received using the QoS
|
||||
* specified on the subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param callback listener that will be notified when subscribe has
|
||||
* completed
|
||||
* @param opts A collection of subscription options (one for each
|
||||
* topic)
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the subscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr subscribe(const_string_collection_ptr topicFilters,
|
||||
const qos_collection& qos,
|
||||
void* userContext, iaction_listener& callback,
|
||||
const std::vector<subscribe_options>& opts=std::vector<subscribe_options>(),
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from a topic.
|
||||
* @param topicFilter the topic to unsubscribe from. It must match a
|
||||
* topicFilter specified on an earlier subscribe.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr unsubscribe(const string& topicFilter,
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from one or more topics.
|
||||
* @param topicFilters one or more topics to unsubscribe from. Each
|
||||
* topicFilter must match one specified on an
|
||||
* earlier subscribe.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr unsubscribe(const_string_collection_ptr topicFilters,
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from one or more topics.
|
||||
* @param topicFilters one or more topics to unsubscribe from. Each
|
||||
* topicFilter must match one specified on an
|
||||
* earlier subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when unsubscribe has
|
||||
* completed
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr unsubscribe(const_string_collection_ptr topicFilters,
|
||||
void* userContext, iaction_listener& cb,
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Requests the server unsubscribe the client from a topics.
|
||||
* @param topicFilter the topic to unsubscribe from. It must match a
|
||||
* topicFilter specified on an earlier subscribe.
|
||||
* @param userContext optional object used to pass context to the
|
||||
* callback. Use @em nullptr if not required.
|
||||
* @param cb listener that will be notified when unsubscribe has
|
||||
* completed.
|
||||
* @param props The MQTT v5 properties.
|
||||
* @return Token used to track and wait for the unsubscribe to complete.
|
||||
* The token will be passed to callback methods if set.
|
||||
*/
|
||||
virtual token_ptr unsubscribe(const string& topicFilter,
|
||||
void* userContext, iaction_listener& cb,
|
||||
const properties& props=properties()) =0;
|
||||
/**
|
||||
* Start consuming messages.
|
||||
* This initializes the client to receive messages through a queue that
|
||||
* can be read synchronously.
|
||||
*/
|
||||
virtual void start_consuming() =0;
|
||||
/**
|
||||
* Stop consuming messages.
|
||||
* This shuts down the internal callback and discards any unread
|
||||
* messages.
|
||||
*/
|
||||
virtual void stop_consuming() =0;
|
||||
/**
|
||||
* Read the next message from the queue.
|
||||
* This blocks until a new message arrives.
|
||||
* @return The message and topic.
|
||||
*/
|
||||
virtual const_message_ptr consume_message() =0;
|
||||
/**
|
||||
* Try to read the next message from the queue without blocking.
|
||||
* @param msg Pointer to the value to receive the message
|
||||
* @return @em true is a message was read, @em false if no message was
|
||||
* available.
|
||||
*/
|
||||
virtual bool try_consume_message(const_message_ptr* msg) =0;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace 'mqtt'
|
||||
}
|
||||
|
||||
#endif // __mqtt_iasync_client_h
|
||||
|
||||
154
src/mqtt/include/mqtt/iclient_persistence.h
Normal file
154
src/mqtt/include/mqtt/iclient_persistence.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file iclient_persistence.h
|
||||
/// Declaration of MQTT iclient_persistence interface
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2016 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_iclient_persistence_h
|
||||
#define __mqtt_iclient_persistence_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/types.h"
|
||||
#include "mqtt/buffer_view.h"
|
||||
#include "mqtt/string_collection.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/**
|
||||
* Allocate memory for use with user persistence.
|
||||
*
|
||||
* @param n The number of bytes for the buffer.
|
||||
* @return A pointer to the allocated memory
|
||||
*/
|
||||
inline void* persistence_malloc(size_t n) {
|
||||
return MQTTAsync_malloc(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory allocated with @ref persistence_malloc().
|
||||
* @param p Pointer to a buffer obtained by persistence_malloc.
|
||||
*/
|
||||
inline void persistence_free(void* p) {
|
||||
MQTTAsync_free(p);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Represents a persistent data store, used to store outbound and inbound
|
||||
* messages while they are in flight, enabling delivery to the QoS
|
||||
* specified. You can specify an implementation of this interface using
|
||||
* client::client(string, string, iclient_persistence), which the
|
||||
* client will use to persist QoS 1 and 2 messages.
|
||||
*
|
||||
* If the methods defined throw the MqttPersistenceException then the state
|
||||
* of the data persisted should remain as prior to the method being called.
|
||||
* For example, if put(string, persistable) throws an exception at any
|
||||
* point then the data will be assumed to not be in the persistent store.
|
||||
* Similarly if remove(string) throws an exception then the data will be
|
||||
* assumed to still be held in the persistent store.
|
||||
*
|
||||
* It is up to the persistence interface to log any exceptions or error
|
||||
* information which may be required when diagnosing a persistence failure.
|
||||
*/
|
||||
class iclient_persistence
|
||||
{
|
||||
friend class async_client;
|
||||
friend class mock_persistence;
|
||||
|
||||
/** Callbacks from the C library */
|
||||
static int persistence_open(void** handle, const char* clientID, const char* serverURI, void* context);
|
||||
static int persistence_close(void* handle);
|
||||
static int persistence_put(void* handle, char* key, int bufcount, char* buffers[], int buflens[]);
|
||||
static int persistence_get(void* handle, char* key, char** buffer, int* buflen);
|
||||
static int persistence_remove(void* handle, char* key);
|
||||
static int persistence_keys(void* handle, char*** keys, int* nkeys);
|
||||
static int persistence_clear(void* handle);
|
||||
static int persistence_containskey(void* handle, char* key);
|
||||
|
||||
public:
|
||||
/** Smart/shared pointer to an object of this class. */
|
||||
using ptr_t = std::shared_ptr<iclient_persistence>;
|
||||
/** Smart/shared pointer to a const object of this class. */
|
||||
using const_ptr_t = std::shared_ptr<const iclient_persistence>;
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~iclient_persistence() {}
|
||||
/**
|
||||
* Initialize the persistent store.
|
||||
* This uses the client ID and server name to create a unique location
|
||||
* for the data store.
|
||||
* @param clientId The identifier string for the client.
|
||||
* @param serverURI The server to which the client is connected.
|
||||
*/
|
||||
virtual void open(const string& clientId, const string& serverURI) =0;
|
||||
/**
|
||||
* Close the persistent store that was previously opened.
|
||||
*/
|
||||
virtual void close() =0;
|
||||
/**
|
||||
* Clears persistence, so that it no longer contains any persisted data.
|
||||
*/
|
||||
virtual void clear() =0;
|
||||
/**
|
||||
* Returns whether or not data is persisted using the specified key.
|
||||
* @param key The key to find
|
||||
* @return @em true if the key exists, @em false if not.
|
||||
*/
|
||||
virtual bool contains_key(const string& key) =0;
|
||||
/**
|
||||
* Returns a collection of keys in this persistent data store.
|
||||
* @return A collection of strings representing the keys in the store.
|
||||
*/
|
||||
virtual string_collection keys() const =0;
|
||||
/**
|
||||
* Puts the specified data into the persistent store.
|
||||
* @param key The key.
|
||||
* @param bufs The data to store
|
||||
*/
|
||||
virtual void put(const string& key, const std::vector<string_view>& bufs) =0;
|
||||
/**
|
||||
* Gets the specified data out of the persistent store.
|
||||
* @param key The key
|
||||
* @return A const view of the data associated with the key.
|
||||
*/
|
||||
virtual string get(const string& key) const =0;
|
||||
/**
|
||||
* Remove the data for the specified key.
|
||||
* @param key The key
|
||||
*/
|
||||
virtual void remove(const string& key) =0;
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to a persistence client */
|
||||
using iclient_persistence_ptr = iclient_persistence::ptr_t;
|
||||
|
||||
/** Smart/shared pointer to a persistence client */
|
||||
using const_iclient_persistence_ptr = iclient_persistence::const_ptr_t;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_iclient_persistence_h
|
||||
|
||||
507
src/mqtt/include/mqtt/message.h
Normal file
507
src/mqtt/include/mqtt/message.h
Normal file
@@ -0,0 +1,507 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file message.h
|
||||
/// Declaration of MQTT message class
|
||||
/// @date May 1, 2013
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2023 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
* Frank Pagliughi - MQTT v5 support (properties)
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_message_h
|
||||
#define __mqtt_message_h
|
||||
|
||||
#include "MQTTAsync.h"
|
||||
#include "mqtt/buffer_ref.h"
|
||||
#include "mqtt/properties.h"
|
||||
#include "mqtt/exception.h"
|
||||
#include "mqtt/platform.h"
|
||||
#include <memory>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* An MQTT message holds everything required for an MQTT PUBLISH message.
|
||||
* This holds the binary message payload, topic string, and all the
|
||||
* additional meta-data for an MQTT message.
|
||||
*
|
||||
* The topic and payload buffers are kept as references to const data, so
|
||||
* they can be reassigned as needed, but the buffers can not be updated
|
||||
* in-place. Normally they would be created externally then copied or moved
|
||||
* into the message. The library to transport the messages never touches the
|
||||
* payloads or topics.
|
||||
*
|
||||
* This also means that message objects are fairly cheap to copy, since they
|
||||
* don't copy the payloads. They simply copy the reference to the buffers.
|
||||
* It is safe to pass these buffer references across threads since all
|
||||
* references promise not to update the contents of the buffer.
|
||||
*/
|
||||
class message
|
||||
{
|
||||
public:
|
||||
/** The default QoS for a message */
|
||||
PAHO_MQTTPP_EXPORT static const int DFLT_QOS; // =0
|
||||
/** The default retained flag */
|
||||
PAHO_MQTTPP_EXPORT static const bool DFLT_RETAINED; // =false
|
||||
|
||||
private:
|
||||
/** Initializer for the C struct (from the C library) */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTAsync_message DFLT_C_STRUCT;
|
||||
|
||||
/** The underlying C message struct */
|
||||
MQTTAsync_message msg_;
|
||||
/** The topic that the message was (or should be) sent on. */
|
||||
string_ref topic_;
|
||||
/** The message payload - an arbitrary binary blob. */
|
||||
binary_ref payload_;
|
||||
/** The properties for the message */
|
||||
properties props_;
|
||||
|
||||
/** The client has special access. */
|
||||
friend class async_client;
|
||||
|
||||
/**
|
||||
* Set the dup flag in the underlying message
|
||||
* @param dup
|
||||
*/
|
||||
void set_duplicate(bool dup) { msg_.dup = to_int(dup); }
|
||||
|
||||
public:
|
||||
/** Smart/shared pointer to this class. */
|
||||
using ptr_t = std::shared_ptr<message>;
|
||||
/** Smart/shared pointer to this class. */
|
||||
using const_ptr_t = std::shared_ptr<const message>;
|
||||
|
||||
/**
|
||||
* Constructs a message with an empty payload, and all other values set
|
||||
* to defaults.
|
||||
*/
|
||||
message();
|
||||
/**
|
||||
* Constructs a message with the specified array as a payload, and all
|
||||
* other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param len the number of bytes in the payload
|
||||
* @param qos The quality of service for the message.
|
||||
* @param retained Whether the message should be retained by the broker.
|
||||
* @param props The MQTT v5 properties for the message.
|
||||
*/
|
||||
message(string_ref topic, const void* payload, size_t len,
|
||||
int qos, bool retained,
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Constructs a message with the specified array as a payload, and all
|
||||
* other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param len the number of bytes in the payload
|
||||
*/
|
||||
message(string_ref topic, const void* payload, size_t len)
|
||||
: message(std::move(topic), payload, len, DFLT_QOS, DFLT_RETAINED) {}
|
||||
/**
|
||||
* Constructs a message from a byte buffer.
|
||||
* Note that the payload accepts copy or move semantics.
|
||||
* @param topic The message topic
|
||||
* @param payload A byte buffer to use as the message payload.
|
||||
* @param qos The quality of service for the message.
|
||||
* @param retained Whether the message should be retained by the broker.
|
||||
* @param props The MQTT v5 properties for the message.
|
||||
*/
|
||||
message(string_ref topic, binary_ref payload, int qos, bool retained,
|
||||
const properties& props=properties());
|
||||
/**
|
||||
* Constructs a message from a byte buffer.
|
||||
* Note that the payload accepts copy or move semantics.
|
||||
* @param topic The message topic
|
||||
* @param payload A byte buffer to use as the message payload.
|
||||
*/
|
||||
message(string_ref topic, binary_ref payload)
|
||||
: message(std::move(topic), std::move(payload), DFLT_QOS, DFLT_RETAINED) {}
|
||||
/**
|
||||
* Constructs a message as a copy of the message structure.
|
||||
* @param topic The message topic
|
||||
* @param cmsg A "C" MQTTAsync_message structure.
|
||||
*/
|
||||
message(string_ref topic, const MQTTAsync_message& cmsg);
|
||||
/**
|
||||
* Constructs a message as a copy of the other message.
|
||||
* @param other The message to copy into this one.
|
||||
*/
|
||||
message(const message& other);
|
||||
/**
|
||||
* Moves the other message to this one.
|
||||
* @param other The message to move into this one.
|
||||
*/
|
||||
message(message&& other);
|
||||
/**
|
||||
* Destroys a message and frees all associated resources.
|
||||
*/
|
||||
~message() {}
|
||||
|
||||
/**
|
||||
* Constructs a message with the specified array as a payload, and all
|
||||
* other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param len the number of bytes in the payload
|
||||
* @param qos The quality of service for the message.
|
||||
* @param retained Whether the message should be retained by the broker.
|
||||
* @param props The MQTT v5 properties for the message.
|
||||
*/
|
||||
static ptr_t create(string_ref topic, const void* payload, size_t len,
|
||||
int qos, bool retained, const properties& props=properties()) {
|
||||
return std::make_shared<message>(std::move(topic), payload, len,
|
||||
qos, retained, props);
|
||||
}
|
||||
/**
|
||||
* Constructs a message with the specified array as a payload, and all
|
||||
* other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param len the number of bytes in the payload
|
||||
*/
|
||||
static ptr_t create(string_ref topic, const void* payload, size_t len) {
|
||||
return std::make_shared<message>(std::move(topic), payload, len,
|
||||
DFLT_QOS, DFLT_RETAINED);
|
||||
}
|
||||
/**
|
||||
* Constructs a message from a byte buffer.
|
||||
* Note that the payload accepts copy or move semantics.
|
||||
* @param topic The message topic
|
||||
* @param payload A byte buffer to use as the message payload.
|
||||
* @param qos The quality of service for the message.
|
||||
* @param retained Whether the message should be retained by the broker.
|
||||
* @param props The MQTT v5 properties for the message.
|
||||
*/
|
||||
static ptr_t create(string_ref topic, binary_ref payload, int qos, bool retained,
|
||||
const properties& props=properties()) {
|
||||
return std::make_shared<message>(std::move(topic), std::move(payload),
|
||||
qos, retained, props);
|
||||
}
|
||||
/**
|
||||
* Constructs a message from a byte buffer.
|
||||
* Note that the payload accepts copy or move semantics.
|
||||
* @param topic The message topic
|
||||
* @param payload A byte buffer to use as the message payload.
|
||||
*/
|
||||
static ptr_t create(string_ref topic, binary_ref payload) {
|
||||
return std::make_shared<message>(std::move(topic), std::move(payload),
|
||||
DFLT_QOS, DFLT_RETAINED);
|
||||
}
|
||||
/**
|
||||
* Constructs a message as a copy of the C message struct.
|
||||
* @param topic The message topic
|
||||
* @param msg A "C" MQTTAsync_message structure.
|
||||
*/
|
||||
static ptr_t create(string_ref topic, const MQTTAsync_message& msg) {
|
||||
return std::make_shared<message>(std::move(topic), msg);
|
||||
}
|
||||
/**
|
||||
* Copies another message to this one.
|
||||
* @param rhs The other message.
|
||||
* @return A reference to this message.
|
||||
*/
|
||||
message& operator=(const message& rhs);
|
||||
/**
|
||||
* Moves another message to this one.
|
||||
* @param rhs The other message.
|
||||
* @return A reference to this message.
|
||||
*/
|
||||
message& operator=(message&& rhs);
|
||||
/**
|
||||
* Expose the underlying C struct for the unit tests.
|
||||
*/
|
||||
#if defined(UNIT_TESTS)
|
||||
const MQTTAsync_message& c_struct() const { return msg_; }
|
||||
#endif
|
||||
/**
|
||||
* Sets the topic string.
|
||||
* @param topic The topic on which the message is published.
|
||||
*/
|
||||
void set_topic(string_ref topic) {
|
||||
topic_ = topic ? std::move(topic) : string_ref(string());
|
||||
}
|
||||
/**
|
||||
* Gets the topic reference for the message.
|
||||
* @return The topic reference for the message.
|
||||
*/
|
||||
const string_ref& get_topic_ref() const { return topic_; }
|
||||
/**
|
||||
* Gets the topic for the message.
|
||||
* @return The topic string for the message.
|
||||
*/
|
||||
const string& get_topic() const {
|
||||
static const string EMPTY_STR;
|
||||
return topic_ ? topic_.str() : EMPTY_STR;
|
||||
}
|
||||
/**
|
||||
* Clears the payload, resetting it to be empty.
|
||||
*/
|
||||
void clear_payload();
|
||||
/**
|
||||
* Gets the payload reference.
|
||||
*/
|
||||
const binary_ref& get_payload_ref() const { return payload_; }
|
||||
/**
|
||||
* Gets the payload
|
||||
*/
|
||||
const binary& get_payload() const {
|
||||
static const binary EMPTY_BIN;
|
||||
return payload_ ? payload_.str() : EMPTY_BIN;
|
||||
}
|
||||
/**
|
||||
* Gets the payload as a string
|
||||
*/
|
||||
const string& get_payload_str() const {
|
||||
static const string EMPTY_STR;
|
||||
return payload_ ? payload_.str() : EMPTY_STR;
|
||||
}
|
||||
/**
|
||||
* Returns the quality of service for this message.
|
||||
* @return The quality of service for this message.
|
||||
*/
|
||||
int get_qos() const { return msg_.qos; }
|
||||
/**
|
||||
* Returns whether or not this message might be a duplicate of one which
|
||||
* has already been received.
|
||||
* @return true this message might be a duplicate of one which
|
||||
* has already been received, false otherwise
|
||||
*/
|
||||
bool is_duplicate() const { return to_bool(msg_.dup); }
|
||||
/**
|
||||
* Returns whether or not this message should be/was retained by the
|
||||
* server.
|
||||
* @return true if this message should be/was retained by the
|
||||
* server, false otherwise.
|
||||
*/
|
||||
bool is_retained() const { return to_bool(msg_.retained); }
|
||||
/**
|
||||
* Sets the payload of this message to be the specified buffer.
|
||||
* Note that this accepts copy or move operations:
|
||||
* set_payload(buf);
|
||||
* set_payload(std::move(buf));
|
||||
* @param payload A buffer to use as the message payload.
|
||||
*/
|
||||
void set_payload(binary_ref payload);
|
||||
/**
|
||||
* Sets the payload of this message to be the specified byte array.
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
*/
|
||||
void set_payload(const void* payload, size_t n) {
|
||||
set_payload(binary_ref(static_cast<const binary_ref::value_type*>(payload), n));
|
||||
}
|
||||
/**
|
||||
* Sets the quality of service for this message.
|
||||
* @param qos The integer Quality of Service for the message
|
||||
*/
|
||||
void set_qos(int qos) {
|
||||
validate_qos(qos);
|
||||
msg_.qos = qos;
|
||||
}
|
||||
/**
|
||||
* Determines if the QOS value is a valid one.
|
||||
* @param qos The QOS value.
|
||||
* @throw std::invalid_argument If the qos value is invalid.
|
||||
*/
|
||||
static void validate_qos(int qos) {
|
||||
if (qos < 0 || qos > 2)
|
||||
throw exception(MQTTASYNC_BAD_QOS, "Bad QoS");
|
||||
}
|
||||
/**
|
||||
* Whether or not the publish message should be retained by the broker.
|
||||
* @param retained @em true if the message should be retained by the
|
||||
* broker, @em false if not.
|
||||
*/
|
||||
void set_retained(bool retained) { msg_.retained = to_int(retained); }
|
||||
/**
|
||||
* Gets the properties in the message.
|
||||
* @return A const reference to the properties in the message.
|
||||
*/
|
||||
const properties& get_properties() const {
|
||||
return props_;
|
||||
}
|
||||
/**
|
||||
* Sets the properties in the message.
|
||||
* @param props The properties to place into the message.
|
||||
*/
|
||||
void set_properties(const properties& props) {
|
||||
props_ = props;
|
||||
msg_.properties = props_.c_struct();
|
||||
}
|
||||
/**
|
||||
* Moves the properties into the message.
|
||||
* @param props The properties to move into the message.
|
||||
*/
|
||||
void set_properties(properties&& props) {
|
||||
props_ = std::move(props);
|
||||
msg_.properties = props_.c_struct();
|
||||
}
|
||||
/**
|
||||
* Returns a string representation of this messages payload.
|
||||
* @return A string representation of this messages payload.
|
||||
*/
|
||||
string to_string() const { return get_payload_str(); }
|
||||
};
|
||||
|
||||
/** Smart/shared pointer to a message */
|
||||
using message_ptr = message::ptr_t;
|
||||
|
||||
/** Smart/shared pointer to a const message */
|
||||
using const_message_ptr = message::const_ptr_t;
|
||||
|
||||
/**
|
||||
* Constructs a message with the specified array as a payload, and all
|
||||
* other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param len the number of bytes in the payload
|
||||
*/
|
||||
inline message_ptr make_message(string_ref topic, const void* payload, size_t len) {
|
||||
return mqtt::message::create(std::move(topic), payload, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a message with the specified array as a payload, and all
|
||||
* other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param len the number of bytes in the payload
|
||||
* @param qos The quality of service for the message.
|
||||
* @param retained Whether the message should be retained by the broker.
|
||||
*/
|
||||
inline message_ptr make_message(string_ref topic, const void* payload, size_t len,
|
||||
int qos, bool retained) {
|
||||
return mqtt::message::create(std::move(topic), payload, len, qos, retained);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a message with the specified buffer as a payload, and
|
||||
* all other values set to defaults.
|
||||
* @param topic The message topic
|
||||
* @param payload A string to use as the message payload.
|
||||
*/
|
||||
inline message_ptr make_message(string_ref topic, binary_ref payload) {
|
||||
return mqtt::message::create(std::move(topic), std::move(payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a message with the specified values.
|
||||
* @param topic The message topic
|
||||
* @param payload A buffer to use as the message payload.
|
||||
* @param qos The quality of service for the message.
|
||||
* @param retained Whether the message should be retained by the broker.
|
||||
*/
|
||||
inline message_ptr make_message(string_ref topic, binary_ref payload,
|
||||
int qos, bool retained) {
|
||||
return mqtt::message::create(std::move(topic), std::move(payload), qos, retained);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Class to build messages.
|
||||
*/
|
||||
class message_ptr_builder
|
||||
{
|
||||
/** The underlying message */
|
||||
message_ptr msg_;
|
||||
|
||||
public:
|
||||
/** This class */
|
||||
using self = message_ptr_builder;
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
message_ptr_builder() : msg_{ std::make_shared<message>() } {}
|
||||
/**
|
||||
* Sets the topic string.
|
||||
* @param topic The topic on which the message is published.
|
||||
*/
|
||||
auto topic(string_ref topic) -> self& {
|
||||
msg_->set_topic(topic);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the payload of this message to be the specified buffer.
|
||||
* Note that this accepts copy or move operations:
|
||||
* set_payload(buf);
|
||||
* set_payload(std::move(buf));
|
||||
* @param payload A buffer to use as the message payload.
|
||||
*/
|
||||
auto payload(binary_ref payload) -> self& {
|
||||
msg_->set_payload(payload);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the payload of this message to be the specified byte array.
|
||||
* @param payload the bytes to use as the message payload
|
||||
* @param n the number of bytes in the payload
|
||||
*/
|
||||
auto payload(const void* payload, size_t n) -> self& {
|
||||
msg_->set_payload(payload, n);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the quality of service for this message.
|
||||
* @param qos The integer Quality of Service for the message
|
||||
*/
|
||||
auto qos(int qos) -> self& {
|
||||
msg_->set_qos(qos);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Whether or not the publish message should be retained by the broker.
|
||||
* @param on @em true if the message should be retained by the broker, @em
|
||||
* false if not.
|
||||
*/
|
||||
auto retained(bool on) -> self& {
|
||||
msg_->set_retained(on);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the properties for the disconnect message.
|
||||
* @param props The properties for the disconnect message.
|
||||
*/
|
||||
auto properties(mqtt::properties&& props) -> self& {
|
||||
msg_->set_properties(std::move(props));
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Sets the properties for the disconnect message.
|
||||
* @param props The properties for the disconnect message.
|
||||
*/
|
||||
auto properties(const mqtt::properties& props) -> self& {
|
||||
msg_->set_properties(props);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Finish building the options and return them.
|
||||
* @return The option struct as built.
|
||||
*/
|
||||
message_ptr finalize() { return msg_; }
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_message_h
|
||||
|
||||
30
src/mqtt/include/mqtt/platform.h
Normal file
30
src/mqtt/include/mqtt/platform.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file platform.h
|
||||
/// Paho MQTT platform-specific code
|
||||
/// @date Nov 19, 2023
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_platform_h
|
||||
#define __mqtt_platform_h
|
||||
|
||||
#include "mqtt/export.h"
|
||||
|
||||
#endif // __mqtt_platform_h
|
||||
|
||||
431
src/mqtt/include/mqtt/properties.h
Normal file
431
src/mqtt/include/mqtt/properties.h
Normal file
@@ -0,0 +1,431 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// @file properties.h
|
||||
/// Declaration of MQTT properties class
|
||||
/// @date July 7, 2019
|
||||
/// @author Frank Pagliughi
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019-2024 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v2.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v20.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Frank Pagliughi - initial implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __mqtt_properties_h
|
||||
#define __mqtt_properties_h
|
||||
|
||||
extern "C" {
|
||||
#include "MQTTProperties.h"
|
||||
}
|
||||
|
||||
#include "mqtt/types.h"
|
||||
#include "mqtt/buffer_ref.h"
|
||||
#include "mqtt/exception.h"
|
||||
#include "mqtt/platform.h"
|
||||
#include <tuple>
|
||||
#include <initializer_list>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace mqtt {
|
||||
|
||||
/** A pair of strings as a tuple. */
|
||||
using string_pair = std::tuple<string, string>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A single MQTT v5 property.
|
||||
*/
|
||||
class property
|
||||
{
|
||||
/** The underlying Paho C property struct. */
|
||||
MQTTProperty prop_;
|
||||
|
||||
// Make a deep copy of the property struct into this one.
|
||||
// For string properties, this allocates memory and copied the string(s)
|
||||
void copy(const MQTTProperty& other);
|
||||
|
||||
public:
|
||||
/**
|
||||
* The integer codes for the different v5 properties.
|
||||
*/
|
||||
enum code {
|
||||
PAYLOAD_FORMAT_INDICATOR = 1,
|
||||
MESSAGE_EXPIRY_INTERVAL = 2,
|
||||
CONTENT_TYPE = 3,
|
||||
RESPONSE_TOPIC = 8,
|
||||
CORRELATION_DATA = 9,
|
||||
SUBSCRIPTION_IDENTIFIER = 11,
|
||||
SESSION_EXPIRY_INTERVAL = 17,
|
||||
ASSIGNED_CLIENT_IDENTIFIER = 18,
|
||||
SERVER_KEEP_ALIVE = 19,
|
||||
AUTHENTICATION_METHOD = 21,
|
||||
AUTHENTICATION_DATA = 22,
|
||||
REQUEST_PROBLEM_INFORMATION = 23,
|
||||
WILL_DELAY_INTERVAL = 24,
|
||||
REQUEST_RESPONSE_INFORMATION = 25,
|
||||
RESPONSE_INFORMATION = 26,
|
||||
SERVER_REFERENCE = 28,
|
||||
REASON_STRING = 31,
|
||||
RECEIVE_MAXIMUM = 33,
|
||||
TOPIC_ALIAS_MAXIMUM = 34,
|
||||
TOPIC_ALIAS = 35,
|
||||
MAXIMUM_QOS = 36,
|
||||
RETAIN_AVAILABLE = 37,
|
||||
USER_PROPERTY = 38,
|
||||
MAXIMUM_PACKET_SIZE = 39,
|
||||
WILDCARD_SUBSCRIPTION_AVAILABLE = 40,
|
||||
SUBSCRIPTION_IDENTIFIERS_AVAILABLE = 41,
|
||||
SHARED_SUBSCRIPTION_AVAILABLE = 42
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a numeric property.
|
||||
* This can be a byte, or 2-byte, 4-byte, or variable byte integer.
|
||||
* @param c The property code
|
||||
* @param val The integer value for the property
|
||||
*/
|
||||
property(code c, int32_t val);
|
||||
/**
|
||||
* Create a numeric property.
|
||||
* This can be a byte, or 2-byte, 4-byte, or variable byte integer.
|
||||
* @param c The property code
|
||||
* @param val The integer value for the property
|
||||
*/
|
||||
property(code c, uint32_t val) : property(c, int32_t(val)) {}
|
||||
/**
|
||||
* Create a string or binary property.
|
||||
* @param c The property code
|
||||
* @param val The value for the property
|
||||
*/
|
||||
property(code c, string_ref val);
|
||||
/**
|
||||
* Create a string pair property.
|
||||
* @param c The property code
|
||||
* @param name The string name for the property
|
||||
* @param val The string value for the property
|
||||
*/
|
||||
property(code c, string_ref name, string_ref val);
|
||||
/**
|
||||
* Creates a property list from an C struct.
|
||||
* @param cprop A C struct for a property list.
|
||||
*/
|
||||
explicit property(const MQTTProperty& cprop);
|
||||
/**
|
||||
* Moves a C struct into this property list.
|
||||
* This takes ownership of any memory that the C struct is holding.
|
||||
* @param cprop A C struct for a property list.
|
||||
*/
|
||||
explicit property(MQTTProperty&& cprop);
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param other The other property to copy into this one.
|
||||
*/
|
||||
property(const property& other);
|
||||
/**
|
||||
* Move constructor.
|
||||
* @param other The other property that is moved into this one.
|
||||
*/
|
||||
property(property&& other);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~property();
|
||||
/**
|
||||
* Copy assignment.
|
||||
* @param rhs Another property list to copy into this one.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
property& operator=(const property& rhs);
|
||||
/**
|
||||
* Move assignment.
|
||||
* @param rhs Another property list to move into this one.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
property& operator=(property&& rhs);
|
||||
/**
|
||||
* Gets the underlying C property struct.
|
||||
* @return A const reference to the underlying C property
|
||||
* struct.
|
||||
*/
|
||||
const MQTTProperty& c_struct() const { return prop_; }
|
||||
/**
|
||||
* Gets the property type (identifier).
|
||||
* @return The code for the property type.
|
||||
*/
|
||||
code type() const { return code(prop_.identifier); }
|
||||
/**
|
||||
* Gets a printable name for the property type.
|
||||
* @return A printable name for the property type.
|
||||
*/
|
||||
const char* type_name() const {
|
||||
return ::MQTTPropertyName(prop_.identifier);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as the specified type.
|
||||
* @return The value from the property as the specified type.
|
||||
*/
|
||||
template <typename T>
|
||||
inline T get(const property&) { throw bad_cast(); }
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as an unsigned 8-bit integer.
|
||||
* @return The value from the property as an unsigned 8-bit integer.
|
||||
*/
|
||||
template <>
|
||||
inline uint8_t get<uint8_t>(const property& prop) {
|
||||
return (uint8_t) prop.c_struct().value.byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as an unsigned 16-bit integer.
|
||||
* @return The value from the property as an unsigned 16-bit integer.
|
||||
*/
|
||||
template <>
|
||||
inline uint16_t get<uint16_t>(const property& prop) {
|
||||
return (uint16_t) prop.c_struct().value.integer2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as a signed 16-bit integer.
|
||||
* @return The value from the property as a signed 16-bit integer.
|
||||
* @deprecated All integer properties are unsigned. Use
|
||||
* `get<uint16_t>()`
|
||||
*/
|
||||
template <>
|
||||
inline int16_t get<int16_t>(const property& prop) {
|
||||
return (int16_t) prop.c_struct().value.integer2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as an unsigned 32-bit integer.
|
||||
* @return The value from the property as an unsigned 32-bit integer.
|
||||
*/
|
||||
template <>
|
||||
inline uint32_t get<uint32_t>(const property& prop) {
|
||||
return (uint32_t) prop.c_struct().value.integer4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as a signed 32-bit integer.
|
||||
* @return The value from the property as a signed 32-bit integer.
|
||||
* @deprecated All integer properties are unsigned. Use
|
||||
* `get<uint32_t>()`
|
||||
*/
|
||||
template <>
|
||||
inline int32_t get<int32_t>(const property& prop) {
|
||||
return (int32_t) prop.c_struct().value.integer4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as a string.
|
||||
* @return The value from the property as a string.
|
||||
*/
|
||||
template <>
|
||||
inline string get<string>(const property& prop) {
|
||||
return (!prop.c_struct().value.data.data) ? string()
|
||||
: string(prop.c_struct().value.data.data, prop.c_struct().value.data.len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from the property as a pair of strings.
|
||||
* @return The value from the property as a pair of strings.
|
||||
*/
|
||||
template <>
|
||||
inline string_pair get<string_pair>(const property& prop) {
|
||||
string name = (!prop.c_struct().value.data.data) ? string()
|
||||
: string(prop.c_struct().value.data.data, prop.c_struct().value.data.len);
|
||||
|
||||
string value = (!prop.c_struct().value.value.data) ? string()
|
||||
: string(prop.c_struct().value.value.data, prop.c_struct().value.value.len);
|
||||
|
||||
return std::make_tuple(std::move(name), std::move(value));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* MQTT v5 property list.
|
||||
*
|
||||
* A collection of properties that can be added to outgoing packets or
|
||||
* retrieved from incoming packets.
|
||||
*/
|
||||
class properties
|
||||
{
|
||||
/** The default C struct */
|
||||
PAHO_MQTTPP_EXPORT static const MQTTProperties DFLT_C_STRUCT;
|
||||
|
||||
/** The underlying C properties struct */
|
||||
MQTTProperties props_;
|
||||
|
||||
template<typename T>
|
||||
friend T get(const properties& props, property::code propid, size_t idx);
|
||||
|
||||
template<typename T>
|
||||
friend T get(const properties& props, property::code propid);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
* Creates an empty properties list.
|
||||
*/
|
||||
properties();
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param other The property list to copy.
|
||||
*/
|
||||
properties(const properties& other)
|
||||
: props_(::MQTTProperties_copy(&other.props_)) {}
|
||||
/**
|
||||
* Move constructor.
|
||||
* @param other The property list to move to this one.
|
||||
*/
|
||||
properties(properties&& other) : props_(other.props_) {
|
||||
std::memset(&other.props_, 0, sizeof(MQTTProperties));
|
||||
}
|
||||
/**
|
||||
* Creates a list of properties from a C struct.
|
||||
* @param cprops The c struct of properties
|
||||
*/
|
||||
properties(const MQTTProperties& cprops) {
|
||||
props_ = ::MQTTProperties_copy(&cprops);
|
||||
}
|
||||
/**
|
||||
* Constructs from a list of property objects.
|
||||
* @param props An initializer list of property objects.
|
||||
*/
|
||||
properties(std::initializer_list<property> props);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~properties() { ::MQTTProperties_free(&props_); }
|
||||
/**
|
||||
* Gets a reference to the underlying C properties structure.
|
||||
* @return A const reference to the underlying C properties structure.
|
||||
*/
|
||||
const MQTTProperties& c_struct() const { return props_; }
|
||||
/**
|
||||
* Copy assignment.
|
||||
* @param rhs The other property list to copy into this one
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
properties& operator=(const properties& rhs);
|
||||
/**
|
||||
* Move assignment.
|
||||
* @param rhs The property list to move to this one.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
properties& operator=(properties&& rhs);
|
||||
/**
|
||||
* Determines if the property list is empty.
|
||||
* @return @em true if there are no properties in the list, @em false if
|
||||
* the list contains any items.
|
||||
*/
|
||||
bool empty() const { return props_.count == 0; }
|
||||
/**
|
||||
* Gets the numbers of property items in the list.
|
||||
* @return The number of property items in the list.
|
||||
*/
|
||||
size_t size() const { return size_t(props_.count); }
|
||||
/**
|
||||
* Adds a property to the list.
|
||||
* @param prop The property to add to the list.
|
||||
*/
|
||||
void add(const property& prop) {
|
||||
::MQTTProperties_add(&props_, &prop.c_struct());
|
||||
}
|
||||
/**
|
||||
* Removes all the items from the property list.
|
||||
*/
|
||||
void clear() {
|
||||
::MQTTProperties_free(&props_);
|
||||
}
|
||||
/**
|
||||
* Determines if the list contains a specific property.
|
||||
* @param propid The property ID (code).
|
||||
* @return @em true if the list contains the property, @em false if not.
|
||||
*/
|
||||
bool contains(property::code propid) const {
|
||||
return ::MQTTProperties_hasProperty(const_cast<MQTTProperties*>(&props_),
|
||||
MQTTPropertyCodes(propid)) != 0;
|
||||
}
|
||||
/**
|
||||
* Get the number of properties in the list with the specified property
|
||||
* ID.
|
||||
*
|
||||
* Most properties can exist only once. User properties and subscription
|
||||
* ID's can exist more than once.
|
||||
*
|
||||
* @param propid The property ID (code).
|
||||
* @return The number of properties in the list with the specified ID.
|
||||
*/
|
||||
size_t count(property::code propid) const {
|
||||
return size_t(::MQTTProperties_propertyCount(
|
||||
const_cast<MQTTProperties*>(&props_), MQTTPropertyCodes(propid)));
|
||||
}
|
||||
/**
|
||||
* Gets the property with the specified ID.
|
||||
*
|
||||
* @param propid The property ID (code).
|
||||
* @param idx Which instance of the property to retrieve, if there are
|
||||
* more than one.
|
||||
* @return The requested property
|
||||
*/
|
||||
property get(property::code propid, size_t idx=0);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieves a single value from a property list for when there may be
|
||||
* multiple identical property ID's.
|
||||
* @tparam T The type of the value to retrieve
|
||||
* @param props The property list
|
||||
* @param propid The property ID code for the desired value.
|
||||
* @param idx Index of the desired property ID
|
||||
* @return The requested value of type T
|
||||
*/
|
||||
template<typename T>
|
||||
inline T get(const properties& props, property::code propid, size_t idx)
|
||||
{
|
||||
MQTTProperty* prop = MQTTProperties_getPropertyAt(
|
||||
const_cast<MQTTProperties*>(&props.c_struct()),
|
||||
MQTTPropertyCodes(propid), int(idx));
|
||||
if (!prop)
|
||||
throw bad_cast();
|
||||
|
||||
return get<T>(property(*prop));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a single value from a property list.
|
||||
* @tparam T The type of the value to retrieve
|
||||
* @param props The property list
|
||||
* @param propid The property ID code for the desired value.
|
||||
* @return The requested value of type T
|
||||
*/
|
||||
template<typename T>
|
||||
inline T get(const properties& props, property::code propid)
|
||||
{
|
||||
return get<T>(props, propid, 0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// end namespace mqtt
|
||||
}
|
||||
|
||||
#endif // __mqtt_properties_h
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user