Merge branch 'develop' into installdir

* develop: (32 commits)
  Updates the RPM packaging makefile
  Stop mosquitto at end of Travis build
  Reduce keepalive check interval for low keepalive values #156
  Added RPM spec for Paho C
  Add REVERSED bitfield definition for big endian processors #212
  Some cppcheck complaint fixes #36
  Some CMake cleanup & correction #223
  Remove const from eyecatchers #168
  Fix for issue #244
  Make fix for issue #186 work on Windows too
  Fix for issue #186
  Actual fix for issue #179
  Fix for issue #179
  Update README to refer to Github for bug raising
  Reduce log verbosity for test 2d
  Fix for issue #190
  Non-SSL version of the library report an error if the caller requests an SSL connection. Possible soluiton for Issue #251
  Compile static ssl libraries with OPENSSL=1.
  Extend the 'MQTTAsync_willOptions_initializer' to initialize the new binary payloads fields
  In test5 - 2d the client must not have the valid client certificate!
  ...
parents c1064391 5833994d
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
/build/ /build/
/build.paho/ /build.paho/
*.swp *.swp
/build.paho
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
# #
# Contributors: # Contributors:
# Rainer Poisel - initial version # 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 # Note: on OS X you should install XCode and the associated command-line tools
...@@ -21,6 +22,9 @@ PROJECT("paho" C) ...@@ -21,6 +22,9 @@ PROJECT("paho" C)
MESSAGE(STATUS "CMake version: " ${CMAKE_VERSION}) MESSAGE(STATUS "CMake version: " ${CMAKE_VERSION})
MESSAGE(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME}) 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 ## build settings
SET(PAHO_VERSION_MAJOR 1) SET(PAHO_VERSION_MAJOR 1)
SET(PAHO_VERSION_MINOR 1) SET(PAHO_VERSION_MINOR 1)
...@@ -29,17 +33,7 @@ SET(CLIENT_VERSION ${PAHO_VERSION_MAJOR}.${PAHO_VERSION_MINOR}.${PAHO_VERSION_PA ...@@ -29,17 +33,7 @@ SET(CLIENT_VERSION ${PAHO_VERSION_MAJOR}.${PAHO_VERSION_MINOR}.${PAHO_VERSION_PA
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
EXECUTE_PROCESS(COMMAND date -u OUTPUT_VARIABLE BUILD_TIMESTAMP) STRING(TIMESTAMP BUILD_TIMESTAMP UTC)
IF (BUILD_TIMESTAMP STREQUAL "")
MESSAGE(WARNING "Unable to determine build timestamp via default mechanism.")
IF (WIN32)
EXECUTE_PROCESS(COMMAND "cmd.exe" "/c" echo %DATE% %TIME% OUTPUT_VARIABLE BUILD_TIMESTAMP)
ENDIF()
ENDIF()
STRING(STRIP ${BUILD_TIMESTAMP} BUILD_TIMESTAMP)
MESSAGE(STATUS "Timestamp is ${BUILD_TIMESTAMP}") MESSAGE(STATUS "Timestamp is ${BUILD_TIMESTAMP}")
IF(WIN32) IF(WIN32)
...@@ -53,6 +47,7 @@ SET(PAHO_WITH_SSL FALSE CACHE BOOL "Flag that defines whether to build ssl-enabl ...@@ -53,6 +47,7 @@ SET(PAHO_WITH_SSL FALSE CACHE BOOL "Flag that defines whether to build ssl-enabl
SET(PAHO_BUILD_STATIC FALSE CACHE BOOL "Build static 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_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_SAMPLES FALSE CACHE BOOL "Build sample programs")
SET(PAHO_BUILD_DEB_PACKAGE FALSE CACHE BOOL "Build debian package")
ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(src)
IF(PAHO_BUILD_SAMPLES) IF(PAHO_BUILD_SAMPLES)
...@@ -66,7 +61,13 @@ ENDIF() ...@@ -66,7 +61,13 @@ ENDIF()
### packaging settings ### packaging settings
IF (WIN32) IF (WIN32)
SET(CPACK_GENERATOR "ZIP") SET(CPACK_GENERATOR "ZIP")
ELSEIF(UNIX) 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)
ADD_SUBDIRECTORY(debian)
ELSE()
SET(CPACK_GENERATOR "TGZ") SET(CPACK_GENERATOR "TGZ")
ENDIF() ENDIF()
......
# Eclipse Paho MQTT C client # Eclipse Paho MQTT C client
This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT C client library.
This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT C client library.
This code builds libraries which enable applications to connect to an [MQTT](http://mqtt.org) broker to publish messages, and to subscribe to topics and receive published messages. This code builds libraries which enable applications to connect to an [MQTT](http://mqtt.org) broker to publish messages, and to subscribe to topics and receive published messages.
...@@ -16,7 +15,7 @@ The Paho C client comprises four shared libraries: ...@@ -16,7 +15,7 @@ The Paho C client comprises four shared libraries:
* libmqttv3c.so - "classic" / synchronous * libmqttv3c.so - "classic" / synchronous
* libmqttv3cs.so - "classic" / synchronous with SSL * libmqttv3cs.so - "classic" / synchronous with SSL
Optionally, you can build static version of those libraries. Optionally, using the CMake build, you can build static versions of those libraries.
## Build instructions for GNU Make ## Build instructions for GNU Make
...@@ -63,6 +62,13 @@ On Debian based systems this would mean that the following packages have to be i ...@@ -63,6 +62,13 @@ On Debian based systems this would mean that the following packages have to be i
``` ```
apt-get install build-essential gcc make cmake cmake-gui cmake-curses-gui apt-get install build-essential gcc make cmake cmake-gui cmake-curses-gui
``` ```
Also, in order to build a debian package from the source code, the following packages have to be installed
```
apt-get install fakeroot fakeroot devscripts dh-make lsb-release
```
Ninja can be downloaded from its github project page in the "releases" section. Optionally it is possible to build binaries with SSL support. This requires the OpenSSL libraries and includes to be available. E. g. on Debian: Ninja can be downloaded from its github project page in the "releases" section. Optionally it is possible to build binaries with SSL support. This requires the OpenSSL libraries and includes to be available. E. g. on Debian:
``` ```
...@@ -88,6 +94,7 @@ PAHO_BUILD_SAMPLES | FALSE | Build sample programs ...@@ -88,6 +94,7 @@ PAHO_BUILD_SAMPLES | FALSE | Build sample programs
MQTT_TEST_BROKER | tcp://localhost:1883 | MQTT connection URL for a broker to use during test execution MQTT_TEST_BROKER | tcp://localhost:1883 | MQTT connection URL for a broker to use during test execution
MQTT_TEST_PROXY | tcp://localhost:1883 | Hostname of the test proxy to use MQTT_TEST_PROXY | tcp://localhost:1883 | Hostname of the test proxy to use
MQTT_SSL_HOSTNAME | localhost | Hostname of a test SSL MQTT broker to use MQTT_SSL_HOSTNAME | localhost | Hostname of a test SSL MQTT broker to use
PAHO_BUILD_DEB_PACKAGE | FALSE | Build debian package
Using these variables CMake can be used to generate your Ninja or Make files. Using CMake, building out-of-source is the default. Therefore it is recommended to invoke all build commands inside your chosen build directory but outside of the source tree. Using these variables CMake can be used to generate your Ninja or Make files. Using CMake, building out-of-source is the default. Therefore it is recommended to invoke all build commands inside your chosen build directory but outside of the source tree.
...@@ -105,7 +112,7 @@ Invoking cmake and specifying build options can also be performed using cmake-gu ...@@ -105,7 +112,7 @@ Invoking cmake and specifying build options can also be performed using cmake-gu
ccmake -GNinja ~/git/org.eclipse.paho.mqtt.c ccmake -GNinja ~/git/org.eclipse.paho.mqtt.c
``` ```
To compile/link the binaries and to generate packages, simply invoke `ninja package` or `make -j <number-of-cores-to-use> package` after CMake. To simply compile/link invoke `ninja` or `make -j <number-of-cores-to-use>`. To compile/link the binaries and to generate packages, simply invoke `ninja package` or `make -j <number-of-cores-to-use> package` after CMake. To simply compile/link invoke `ninja` or `make -j <number-of-cores-to-use>`.
### Debug builds ### Debug builds
...@@ -127,10 +134,9 @@ python ../test/mqttsas2.py & ...@@ -127,10 +134,9 @@ python ../test/mqttsas2.py &
ctest -VV ctest -VV
``` ```
### Cross compilation ### Cross compilation
Cross compilation using CMake is performed by using so called "toolchain files" (see: http://www.vtk.org/Wiki/CMake_Cross_Compiling). Cross compilation using CMake is performed by using so called "toolchain files" (see: http://www.vtk.org/Wiki/CMake_Cross_Compiling).
The path to the toolchain file can be specified by using CMake's `-DCMAKE_TOOLCHAIN_FILE` option. In case no toolchain file is specified, the build is performed for the native build platform. The path to the toolchain file can be specified by using CMake's `-DCMAKE_TOOLCHAIN_FILE` option. In case no toolchain file is specified, the build is performed for the native build platform.
...@@ -140,7 +146,7 @@ For your convenience toolchain files for the following platforms can be found in ...@@ -140,7 +146,7 @@ For your convenience toolchain files for the following platforms can be found in
* Windows x86_64 * Windows x86_64
* Windows x86 * Windows x86
The provided toolchain files assume that required compilers/linkers are to be found in the environment, i. e. the PATH-Variable of your user or system. If you prefer, you can also specify the absolute location of your compilers in the toolchain files. The provided toolchain files assume that required compilers/linkers are to be found in the environment, i. e. the PATH-Variable of your user or system. If you prefer, you can also specify the absolute location of your compilers in the toolchain files.
Example invocation for the Raspberry Pi: Example invocation for the Raspberry Pi:
...@@ -163,7 +169,6 @@ In this case the libraries and executable are not linked against OpenSSL Librari ...@@ -163,7 +169,6 @@ In this case the libraries and executable are not linked against OpenSSL Librari
apt-get install gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 apt-get install gcc-mingw-w64-x86-64 gcc-mingw-w64-i686
``` ```
## Usage and API ## Usage and API
Detailed API documentation is available by building the Doxygen docs in the ``doc`` directory. A [snapshot is also available online](http://www.eclipse.org/paho/files/mqttdoc/Cclient/index.html). Detailed API documentation is available by building the Doxygen docs in the ``doc`` directory. A [snapshot is also available online](http://www.eclipse.org/paho/files/mqttdoc/Cclient/index.html).
...@@ -181,9 +186,9 @@ Note that using the C headers from a C++ program requires the following declarat ...@@ -181,9 +186,9 @@ Note that using the C headers from a C++ program requires the following declarat
## Runtime tracing ## Runtime tracing
A number of environment variables control runtime tracing of the C library. A number of environment variables control runtime tracing of the C library.
Tracing is switched on using ``MQTT_C_CLIENT_TRACE`` (a value of ON traces to stdout, any other value should specify a file to trace to). Tracing is switched on using ``MQTT_C_CLIENT_TRACE`` (a value of ON traces to stdout, any other value should specify a file to trace to).
The verbosity of the output is controlled using the ``MQTT_C_CLIENT_TRACE_LEVEL`` environment variable - valid values are ERROR, PROTOCOL, MINIMUM, MEDIUM and MAXIMUM (from least to most verbose). The verbosity of the output is controlled using the ``MQTT_C_CLIENT_TRACE_LEVEL`` environment variable - valid values are ERROR, PROTOCOL, MINIMUM, MEDIUM and MAXIMUM (from least to most verbose).
...@@ -196,7 +201,7 @@ export MQTT_C_CLIENT_TRACE_LEVEL=PROTOCOL ...@@ -196,7 +201,7 @@ export MQTT_C_CLIENT_TRACE_LEVEL=PROTOCOL
## Reporting bugs ## Reporting bugs
Please report bugs under the "MQTT-C" Component in [Eclipse Bugzilla](http://bugs.eclipse.org/bugs/) for the Paho Technology project. Please open issues in the Github project: https://github.com/eclipse/paho.mqtt.c/issues.
## More information ## More information
......
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}")
IF(PAHO_WITH_SSL)
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libssl-dev")
ENDIF()
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()
#=============================================================================
# CMakeDebHelper, Copyright (C) 2013 Sebastian Kienzl
# http://knzl.de/cmake-debhelper/
# Licensed under the GPL v2, see LICENSE
#=============================================================================
# configure() .in-files to the CURRENT_BINARY_DIR
foreach( _F ${DH_INPUT} )
# strip the .in part
string( REGEX REPLACE ".in$" "" _F_WE ${_F} )
configure_file( ${_F} ${_F_WE} @ONLY )
endforeach()
# compat and control is only needed for running the debhelpers,
# CMake is going to make up the one that ends up in the deb.
file( WRITE ${CMAKE_CURRENT_BINARY_DIR}/compat "9" )
if( NOT CPACK_DEBIAN_PACKAGE_NAME )
string( TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME )
endif()
file( WRITE ${CMAKE_CURRENT_BINARY_DIR}/control "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\nArchitecture: any\n" )
# Some debhelpers need fakeroot, we use it for all of them
find_program( FAKEROOT fakeroot )
if( NOT FAKEROOT )
message( SEND_ERROR "fakeroot not found, please install" )
endif()
find_program( DEBHELPER dh_prep )
if( NOT DEBHELPER )
message( SEND_ERROR "debhelper not found, please install" )
endif()
# Compose a string with a semicolon-seperated list of debhelpers
foreach( _DH ${DH_RUN} )
set( _DH_RUN_SC_LIST "${_DH_RUN_SC_LIST} ${_DH} ;" )
endforeach()
# Making sure the debhelpers run each time we change one of ${DH_INPUT}
add_custom_command(
OUTPUT dhtimestamp
# dh_prep is needed to clean up, dh_* aren't idempotent
COMMAND ${FAKEROOT} dh_prep
# I haven't found another way to run a list of commands here
COMMAND ${FAKEROOT} -- sh -c "${_DH_RUN_SC_LIST}"
# needed to create the files we'll use
COMMAND ${FAKEROOT} dh_installdeb
COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/dhtimestamp
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
DEPENDS ${DH_INPUT}
COMMENT "Running debhelpers"
VERBATIM
)
add_custom_target( dhtarget ALL
DEPENDS dhtimestamp
)
# these files are generated by debhelpers from our templates
foreach( _F ${DH_GENERATED_CONTROL_EXTRA} )
set( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
${CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA}
${CMAKE_CURRENT_BINARY_DIR}/${CPACK_DEBIAN_PACKAGE_NAME}/DEBIAN/${_F}
CACHE INTERNAL ""
)
endforeach()
# This will copy the generated dhhelper-files to our to-be-cpacked-directory.
# CPACK_INSTALL_SCRIPT must be set to the value of CPACK_DEBIAN_INSTALL_SCRIPT in the file
# pointed to by CPACK_PROJECT_CONFIG_FILE.
set( CPACK_DEBIAN_INSTALL_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/CMakeDebHelperInstall.cmake CACHE INTERNAL "" )
# This script is used internally by CMakeDebHelper.
# It is run at CPack-Time and copies the files generated by the debhelpers to the right place.
if( NOT CPACK_DEBIAN_PACKAGE_NAME )
string( TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME )
endif()
# Copy all generated files where the packing will happen,
# exclude the DEBIAN-directory.
MESSAGE(STATUS "CPACK_OUTPUT_FILE_PREFIX: " "${CPACK_OUTPUT_FILE_PREFIX}/debian/${CPACK_DEBIAN_PACKAGE_NAME}/")
file( COPY
"${CPACK_OUTPUT_FILE_PREFIX}/debian/${CPACK_DEBIAN_PACKAGE_NAME}/"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}"
PATTERN DEBIAN EXCLUDE
)
# These files (generated by dhelpers) will be copied into the control-part of the deb.
# Files that end up in the filesystem normally (e.g. cron/init-scripts) must not be mentioned here.
# It's a good idea to add "conffiles", as the debhelpers may generate it.
set( DH_GENERATED_CONTROL_EXTRA
preinst
postinst
postrm
prerm
conffiles
)
# At this point, CMakeDebHelper must be included (add .cmake if you have it in this directory)
include( CMakeDebHelper )
# CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA and CPACK_INSTALL_SCRIPT are set now, don't modify them!
VERSION=1.1.0
rpm-prep:
mkdir -p ${HOME}/rpmbuild/SOURCES/
tar --transform="s/\./paho-c-${VERSION}/" -cf ${HOME}/rpmbuild/SOURCES/paho-c-${VERSION}.tar.gz --exclude=./build.paho --exclude=.git --exclude=*.bz ./ --gzip
rpm: rpm-prep
rpmbuild -ba dist/paho-c.spec
%global _enable_debug_package 0
%global debug_package %{nil}
Summary: MQTT C Client
Name: paho-c
Version: 1.1.0
Release: 1%{?dist}
License: Eclipse Distribution License 1.0 and Eclipse Public License 1.0
Group: Development/Tools
Source: paho-c-%{version}.tar.gz
URL: https://eclipse.org/paho/clients/c/
BuildRequires: cmake
BuildRequires: gcc
BuildRequires: graphviz
BuildRequires: doxygen
BuildRequires: openssl-devel
Requires: openssl
%description
The Paho MQTT C Client is a fully fledged MQTT client written in ANSI standard C.
%package devel
Summary: MQTT C Client development kit
Group: Development/Libraries
Requires: paho-c
%description devel
Development files and samples for the the Paho MQTT C Client.
%package devel-docs
Summary: MQTT C Client development kit documentation
Group: Development/Libraries
%description devel-docs
Development documentation files for the the Paho MQTT C Client.
%prep
%autosetup -n paho-c-%{version}
%build
mkdir build.paho && cd build.paho
cmake -DPAHO_WITH_SSL=TRUE -DPAHO_BUILD_DOCUMENTATION=TRUE -DPAHO_BUILD_SAMPLES=TRUE -DCMAKE_INSTALL_PREFIX=%{buildroot}/usr ..
make
%install
cd build.paho
make install
%files
%doc edl-v10 epl-v10
%{_libdir}/*
%files devel
%{_bindir}/*
%{_includedir}/*
%files devel-docs
%{_datadir}/*
%changelog
* Sat Dec 31 2016 Otavio R. Piske <opiske@redhat.com> - 20161231
- Initial packaging
...@@ -93,9 +93,7 @@ IF (PAHO_BUILD_STATIC) ...@@ -93,9 +93,7 @@ IF (PAHO_BUILD_STATIC)
TARGET_LINK_LIBRARIES(paho-mqtt3c-static ${LIBS_SYSTEM}) TARGET_LINK_LIBRARIES(paho-mqtt3c-static ${LIBS_SYSTEM})
TARGET_LINK_LIBRARIES(paho-mqtt3a-static ${LIBS_SYSTEM}) TARGET_LINK_LIBRARIES(paho-mqtt3a-static ${LIBS_SYSTEM})
INSTALL(TARGETS paho-mqtt3c-static INSTALL(TARGETS paho-mqtt3c-static paho-mqtt3a-static
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL(TARGETS paho-mqtt3a-static
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
ENDIF() ENDIF()
...@@ -144,11 +142,7 @@ IF (PAHO_WITH_SSL) ...@@ -144,11 +142,7 @@ IF (PAHO_WITH_SSL)
VERSION ${CLIENT_VERSION} VERSION ${CLIENT_VERSION}
SOVERSION ${PAHO_VERSION_MAJOR} SOVERSION ${PAHO_VERSION_MAJOR}
COMPILE_DEFINITIONS "OPENSSL=1") COMPILE_DEFINITIONS "OPENSSL=1")
INSTALL(TARGETS paho-mqtt3cs INSTALL(TARGETS paho-mqtt3cs paho-mqtt3as
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
INSTALL(TARGETS paho-mqtt3as
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
...@@ -159,10 +153,13 @@ IF (PAHO_WITH_SSL) ...@@ -159,10 +153,13 @@ IF (PAHO_WITH_SSL)
TARGET_LINK_LIBRARIES(paho-mqtt3cs-static ${OPENSSL_LIBRARIES} ${LIBS_SYSTEM}) TARGET_LINK_LIBRARIES(paho-mqtt3cs-static ${OPENSSL_LIBRARIES} ${LIBS_SYSTEM})
TARGET_LINK_LIBRARIES(paho-mqtt3as-static ${OPENSSL_LIBRARIES} ${LIBS_SYSTEM}) TARGET_LINK_LIBRARIES(paho-mqtt3as-static ${OPENSSL_LIBRARIES} ${LIBS_SYSTEM})
SET_TARGET_PROPERTIES(
paho-mqtt3cs-static paho-mqtt3as-static PROPERTIES
VERSION ${CLIENT_VERSION}
SOVERSION ${PAHO_VERSION_MAJOR}
COMPILE_DEFINITIONS "OPENSSL=1")
INSTALL(TARGETS paho-mqtt3cs-static INSTALL(TARGETS paho-mqtt3cs-static paho-mqtt3as-static
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL(TARGETS paho-mqtt3as-static
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
ENDIF() ENDIF()
ENDIF() ENDIF()
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <time.h> #include <time.h>
#if defined(OPENSSL) #if defined(OPENSSL)
#if defined(WIN32) || defined(WIN64) #if defined(WIN32) || defined(WIN64)
#include "winsock2.h" #include <winsock2.h>
#endif #endif
#include <openssl/ssl.h> #include <openssl/ssl.h>
#endif #endif
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
* Ian Craggs - fix for bug 486548 * Ian Craggs - fix for bug 486548
* Ian Craggs - SNI support * Ian Craggs - SNI support
* Ian Craggs - auto reconnect timing fix #218 * Ian Craggs - auto reconnect timing fix #218
* Ian Craggs - fix for issue #190
*******************************************************************************/ *******************************************************************************/
/** /**
...@@ -65,6 +66,13 @@ ...@@ -65,6 +66,13 @@
const char *client_timestamp_eye = "MQTTAsyncV3_Timestamp " BUILD_TIMESTAMP; const char *client_timestamp_eye = "MQTTAsyncV3_Timestamp " BUILD_TIMESTAMP;
const char *client_version_eye = "MQTTAsyncV3_Version " CLIENT_VERSION; const char *client_version_eye = "MQTTAsyncV3_Version " CLIENT_VERSION;
void MQTTAsync_global_init(int handle_openssl_init)
{
#if defined(OPENSSL)
SSLSocket_handleOpensslInit(handle_openssl_init);
#endif
}
#if !defined(min) #if !defined(min)
#define min(a, b) (((a) < (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b))
#endif #endif
...@@ -566,7 +574,7 @@ static int MQTTAsync_unpersistCommand(MQTTAsync_queuedCommand* qcmd) ...@@ -566,7 +574,7 @@ static int MQTTAsync_unpersistCommand(MQTTAsync_queuedCommand* qcmd)
char key[PERSISTENCE_MAX_KEY_LENGTH + 1]; char key[PERSISTENCE_MAX_KEY_LENGTH + 1];
FUNC_ENTRY; FUNC_ENTRY;
sprintf(key, "%s%d", PERSISTENCE_COMMAND_KEY, qcmd->seqno); sprintf(key, "%s%u", PERSISTENCE_COMMAND_KEY, qcmd->seqno);
if ((rc = qcmd->client->c->persistence->premove(qcmd->client->c->phandle, key)) != 0) if ((rc = qcmd->client->c->persistence->premove(qcmd->client->c->phandle, key)) != 0)
Log(LOG_ERROR, 0, "Error %d removing command from persistence", rc); Log(LOG_ERROR, 0, "Error %d removing command from persistence", rc);
FUNC_EXIT_RC(rc); FUNC_EXIT_RC(rc);
...@@ -1337,6 +1345,39 @@ exit: ...@@ -1337,6 +1345,39 @@ exit:
} }
static void nextOrClose(MQTTAsyncs* m, int rc, char* message)
{
if (MQTTAsync_checkConn(&m->connect, m))
{
MQTTAsync_queuedCommand* conn;
MQTTAsync_closeOnly(m->c);
/* put the connect command back to the head of the command queue, using the next serverURI */
conn = malloc(sizeof(MQTTAsync_queuedCommand));
memset(conn, '\0', sizeof(MQTTAsync_queuedCommand));
conn->client = m;
conn->command = m->connect;
Log(TRACE_MIN, -1, "Connect failed, more to try");
MQTTAsync_addCommand(conn, sizeof(m->connect));
}
else
{
MQTTAsync_closeSession(m->c);
if (m->connect.onFailure)
{
MQTTAsync_failureData data;
data.token = 0;
data.code = rc;
data.message = message;
Log(TRACE_MIN, -1, "Calling connect failure for client %s", m->c->clientID);
(*(m->connect.onFailure))(m->connect.context, &data);
}
MQTTAsync_startConnectRetry(m);
}
}
static void MQTTAsync_checkTimeouts(void) static void MQTTAsync_checkTimeouts(void)
{ {
ListElement* current = NULL; ListElement* current = NULL;
...@@ -1361,38 +1402,11 @@ static void MQTTAsync_checkTimeouts(void) ...@@ -1361,38 +1402,11 @@ static void MQTTAsync_checkTimeouts(void)
/* check disconnect timeout */ /* check disconnect timeout */
if (m->c->connect_state == -2) if (m->c->connect_state == -2)
MQTTAsync_checkDisconnect(m, &m->disconnect); MQTTAsync_checkDisconnect(m, &m->disconnect);
/* check connect timeout */ /* check connect timeout */
else if (m->c->connect_state != 0 && MQTTAsync_elapsed(m->connect.start_time) > (m->connectTimeout * 1000)) if (m->c->connect_state != 0 && MQTTAsync_elapsed(m->connect.start_time) > (m->connectTimeout * 1000))
{ {
if (MQTTAsync_checkConn(&m->connect, m)) nextOrClose(m, MQTTASYNC_FAILURE, "TCP connect timeout");
{
MQTTAsync_queuedCommand* conn;
MQTTAsync_closeOnly(m->c);
/* put the connect command back to the head of the command queue, using the next serverURI */
conn = malloc(sizeof(MQTTAsync_queuedCommand));
memset(conn, '\0', sizeof(MQTTAsync_queuedCommand));
conn->client = m;
conn->command = m->connect;
Log(TRACE_MIN, -1, "Connect failed with timeout, more to try");
MQTTAsync_addCommand(conn, sizeof(m->connect));
}
else
{
MQTTAsync_closeSession(m->c);
Log(TRACE_MIN, -1, "Connect failed with timeout, no to try");
if (m->connect.onFailure)
{
MQTTAsync_failureData data;
data.token = 0;
data.code = MQTTASYNC_FAILURE;
data.message = "TCP connect timeout";
Log(TRACE_MIN, -1, "Calling connect failure for client %s", m->c->clientID);
(*(m->connect.onFailure))(m->connect.context, &data);
}
MQTTAsync_startConnectRetry(m);
}
continue; continue;
} }
...@@ -1677,6 +1691,7 @@ static int MQTTAsync_completeConnection(MQTTAsyncs* m, MQTTPacket* pack) ...@@ -1677,6 +1691,7 @@ static int MQTTAsync_completeConnection(MQTTAsyncs* m, MQTTPacket* pack)
return rc; return rc;
} }
/* This is the thread function that handles the calling of callback functions if set */ /* This is the thread function that handles the calling of callback functions if set */
static thread_return_type WINAPI MQTTAsync_receiveThread(void* n) static thread_return_type WINAPI MQTTAsync_receiveThread(void* n)
{ {
...@@ -1725,6 +1740,8 @@ static thread_return_type WINAPI MQTTAsync_receiveThread(void* n) ...@@ -1725,6 +1740,8 @@ static thread_return_type WINAPI MQTTAsync_receiveThread(void* n)
MQTTAsync_disconnect_internal(m, 0); MQTTAsync_disconnect_internal(m, 0);
MQTTAsync_lock_mutex(mqttasync_mutex); MQTTAsync_lock_mutex(mqttasync_mutex);
} }
else if (m->c->connect_state != 0)
nextOrClose(m, rc, "socket error");
else /* calling disconnect_internal won't have any effect if we're already disconnected */ else /* calling disconnect_internal won't have any effect if we're already disconnected */
MQTTAsync_closeOnly(m->c); MQTTAsync_closeOnly(m->c);
} }
...@@ -1791,36 +1808,7 @@ static thread_return_type WINAPI MQTTAsync_receiveThread(void* n) ...@@ -1791,36 +1808,7 @@ static thread_return_type WINAPI MQTTAsync_receiveThread(void* n)
} }
} }
else else
{ nextOrClose(m, rc, "CONNACK return code");
if (MQTTAsync_checkConn(&m->connect, m))
{
MQTTAsync_queuedCommand* conn;
MQTTAsync_closeOnly(m->c);
/* put the connect command back to the head of the command queue, using the next serverURI */
conn = malloc(sizeof(MQTTAsync_queuedCommand));
memset(conn, '\0', sizeof(MQTTAsync_queuedCommand));
conn->client = m;
conn->command = m->connect;
Log(TRACE_MIN, -1, "Connect failed, more to try");
MQTTAsync_addCommand(conn, sizeof(m->connect));
}
else
{
MQTTAsync_closeSession(m->c);
if (m->connect.onFailure)
{
MQTTAsync_failureData data;
data.token = 0;
data.code = rc;
data.message = "CONNACK return code";
Log(TRACE_MIN, -1, "Calling connect failure for client %s", m->c->clientID);
(*(m->connect.onFailure))(m->connect.context, &data);
}
MQTTAsync_startConnectRetry(m);
}
}
} }
else if (pack->header.bits.type == SUBACK) else if (pack->header.bits.type == SUBACK)
{ {
...@@ -2166,6 +2154,21 @@ void Protocol_processPublication(Publish* publish, Clients* client) ...@@ -2166,6 +2154,21 @@ void Protocol_processPublication(Publish* publish, Clients* client)
} }
static int retryLoopInterval = 5;
static void setRetryLoopInterval(int keepalive)
{
int proposed = keepalive / 10;
if (proposed < 1)
proposed = 1;
else if (proposed > 5)
proposed = 5;
if (proposed < retryLoopInterval)
retryLoopInterval = proposed;
}
int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options)
{ {
MQTTAsyncs* m = handle; MQTTAsyncs* m = handle;
...@@ -2234,6 +2237,7 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) ...@@ -2234,6 +2237,7 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options)
} }
m->c->keepAliveInterval = options->keepAliveInterval; m->c->keepAliveInterval = options->keepAliveInterval;
setRetryLoopInterval(options->keepAliveInterval);
m->c->cleansession = options->cleansession; m->c->cleansession = options->cleansession;
m->c->maxInflightMessages = options->maxInflight; m->c->maxInflightMessages = options->maxInflight;
if (options->struct_version >= 3) if (options->struct_version >= 3)
...@@ -2318,6 +2322,12 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) ...@@ -2318,6 +2322,12 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options)
m->c->sslopts->enabledCipherSuites = MQTTStrdup(options->ssl->enabledCipherSuites); m->c->sslopts->enabledCipherSuites = MQTTStrdup(options->ssl->enabledCipherSuites);
m->c->sslopts->enableServerCertAuth = options->ssl->enableServerCertAuth; m->c->sslopts->enableServerCertAuth = options->ssl->enableServerCertAuth;
} }
#else
if (options->struct_version != 0 && options->ssl)
{
rc = MQTTASYNC_SSL_NOT_SUPPORTED;
goto exit;
}
#endif #endif
m->c->username = options->username; m->c->username = options->username;
...@@ -2742,7 +2752,7 @@ static void MQTTAsync_retry(void) ...@@ -2742,7 +2752,7 @@ static void MQTTAsync_retry(void)
FUNC_ENTRY; FUNC_ENTRY;
time(&(now)); time(&(now));
if (difftime(now, last) > 5) if (difftime(now, last) > retryLoopInterval)
{ {
time(&(last)); time(&(last));
MQTTProtocol_keepalive(now); MQTTProtocol_keepalive(now);
...@@ -2845,36 +2855,8 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) ...@@ -2845,36 +2855,8 @@ static int MQTTAsync_connecting(MQTTAsyncs* m)
exit: exit:
if ((rc != 0 && rc != TCPSOCKET_INTERRUPTED && m->c->connect_state != 2) || (rc == SSL_FATAL)) if ((rc != 0 && rc != TCPSOCKET_INTERRUPTED && m->c->connect_state != 2) || (rc == SSL_FATAL))
{ nextOrClose(m, MQTTASYNC_FAILURE, "TCP/TLS connect failure");
if (MQTTAsync_checkConn(&m->connect, m))
{
MQTTAsync_queuedCommand* conn;
MQTTAsync_closeOnly(m->c);
/* put the connect command back to the head of the command queue, using the next serverURI */
conn = malloc(sizeof(MQTTAsync_queuedCommand));
memset(conn, '\0', sizeof(MQTTAsync_queuedCommand));
conn->client = m;
conn->command = m->connect;
Log(TRACE_MIN, -1, "Connect failed, more to try");
MQTTAsync_addCommand(conn, sizeof(m->connect));
}
else
{
MQTTAsync_closeSession(m->c);
if (m->connect.onFailure)
{
MQTTAsync_failureData data;
data.token = 0;
data.code = MQTTASYNC_FAILURE;
data.message = "TCP/TLS connect failure";
Log(TRACE_MIN, -1, "Calling connect failure for client %s", m->c->clientID);
(*(m->connect.onFailure))(m->connect.context, &data);
}
MQTTAsync_startConnectRetry(m);
}
}
FUNC_EXIT_RC(rc); FUNC_EXIT_RC(rc);
return rc; return rc;
} }
...@@ -2922,34 +2904,7 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) ...@@ -2922,34 +2904,7 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc)
if (m->c->connect_state == 3 && *rc == SOCKET_ERROR) if (m->c->connect_state == 3 && *rc == SOCKET_ERROR)
{ {
Log(TRACE_MINIMUM, -1, "CONNECT sent but MQTTPacket_Factory has returned SOCKET_ERROR"); Log(TRACE_MINIMUM, -1, "CONNECT sent but MQTTPacket_Factory has returned SOCKET_ERROR");
if (MQTTAsync_checkConn(&m->connect, m)) nextOrClose(m, MQTTASYNC_FAILURE, "TCP connect completion failure");
{
MQTTAsync_queuedCommand* conn;
MQTTAsync_closeOnly(m->c);
/* put the connect command back to the head of the command queue, using the next serverURI */
conn = malloc(sizeof(MQTTAsync_queuedCommand));
memset(conn, '\0', sizeof(MQTTAsync_queuedCommand));
conn->client = m;
conn->command = m->connect;
Log(TRACE_MIN, -1, "Connect failed, more to try");
MQTTAsync_addCommand(conn, sizeof(m->connect));
}
else
{
MQTTAsync_closeSession(m->c);
if (m->connect.onFailure)
{
MQTTAsync_failureData data;
data.token = 0;
data.code = MQTTASYNC_FAILURE;
data.message = "TCP connect completion failure";
Log(TRACE_MIN, -1, "Calling connect failure for client %s", m->c->clientID);
(*(m->connect.onFailure))(m->connect.context, &data);
}
MQTTAsync_startConnectRetry(m);
}
} }
else else
{ {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* Ian Craggs - automatic reconnect and offline buffering (send while disconnected) * Ian Craggs - automatic reconnect and offline buffering (send while disconnected)
* Ian Craggs - binary will message * Ian Craggs - binary will message
* Ian Craggs - binary password * Ian Craggs - binary password
* Ian Craggs - remove const on eyecatchers #168
*******************************************************************************/ *******************************************************************************/
/********************************************************************/ /********************************************************************/
...@@ -161,6 +162,10 @@ ...@@ -161,6 +162,10 @@
* Return code: no more messages can be buffered * Return code: no more messages can be buffered
*/ */
#define MQTTASYNC_MAX_BUFFERED_MESSAGES -12 #define MQTTASYNC_MAX_BUFFERED_MESSAGES -12
/**
* Return code: Attempting SSL connection using non-SSL version of library
*/
#define MQTTASYNC_SSL_NOT_SUPPORTED -13
/** /**
* Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1 * Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1
...@@ -179,6 +184,13 @@ ...@@ -179,6 +184,13 @@
*/ */
#define MQTT_BAD_SUBSCRIBE 0x80 #define MQTT_BAD_SUBSCRIBE 0x80
/**
* Global init of mqtt library. Call once on program start to set global behaviour.
* handle_openssl_init - if mqtt library should handle openssl init (1) or rely on the caller to init it before using mqtt (0)
*/
void MQTTAsync_global_init(int handle_openssl_init);
/** /**
* A handle representing an MQTT client. A valid client handle is available * A handle representing an MQTT client. A valid client handle is available
* following a successful call to MQTTAsync_create(). * following a successful call to MQTTAsync_create().
...@@ -539,7 +551,7 @@ DLLExport int MQTTAsync_create(MQTTAsync* handle, const char* serverURI, const c ...@@ -539,7 +551,7 @@ DLLExport int MQTTAsync_create(MQTTAsync* handle, const char* serverURI, const c
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. must be MQCO. */ /** The eyecatcher for this structure. must be MQCO. */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0 */ /** The version number of this structure. Must be 0 */
int struct_version; int struct_version;
/** Whether to allow messages to be sent when the client library is not connected. */ /** Whether to allow messages to be sent when the client library is not connected. */
...@@ -569,7 +581,7 @@ DLLExport int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverU ...@@ -569,7 +581,7 @@ DLLExport int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverU
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. must be MQTW. */ /** The eyecatcher for this structure. must be MQTW. */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0 or 1 /** The version number of this structure. Must be 0 or 1
0 indicates no binary will message support 0 indicates no binary will message support
*/ */
...@@ -595,7 +607,7 @@ typedef struct ...@@ -595,7 +607,7 @@ typedef struct
} payload; } payload;
} MQTTAsync_willOptions; } MQTTAsync_willOptions;
#define MQTTAsync_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 1, NULL, NULL, 0, 0 } #define MQTTAsync_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 1, NULL, NULL, 0, 0, { 0, NULL } }
/** /**
* MQTTAsync_sslProperties defines the settings to establish an SSL/TLS connection using the * MQTTAsync_sslProperties defines the settings to establish an SSL/TLS connection using the
...@@ -612,7 +624,7 @@ typedef struct ...@@ -612,7 +624,7 @@ typedef struct
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. Must be MQTS */ /** The eyecatcher for this structure. Must be MQTS */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0 */ /** The version number of this structure. Must be 0 */
int struct_version; int struct_version;
...@@ -656,7 +668,7 @@ typedef struct ...@@ -656,7 +668,7 @@ typedef struct
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. must be MQTC. */ /** The eyecatcher for this structure. must be MQTC. */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0, 1, 2, 3 4 or 5. /** The version number of this structure. Must be 0, 1, 2, 3 4 or 5.
* 0 signifies no SSL options and no serverURIs * 0 signifies no SSL options and no serverURIs
* 1 signifies no serverURIs * 1 signifies no serverURIs
...@@ -822,7 +834,7 @@ DLLExport int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions ...@@ -822,7 +834,7 @@ DLLExport int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. Must be MQTD. */ /** The eyecatcher for this structure. Must be MQTD. */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0 or 1. 0 signifies no SSL options */ /** The version number of this structure. Must be 0 or 1. 0 signifies no SSL options */
int struct_version; int struct_version;
/** /**
...@@ -1224,9 +1236,9 @@ DLLExport MQTTAsync_nameValue* MQTTAsync_getVersionInfo(void); ...@@ -1224,9 +1236,9 @@ DLLExport MQTTAsync_nameValue* MQTTAsync_getVersionInfo(void);
* @page publish Publication example * @page publish Publication example
@code @code
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTAsync.h" #include "MQTTAsync.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
...@@ -1359,9 +1371,9 @@ int main(int argc, char* argv[]) ...@@ -1359,9 +1371,9 @@ int main(int argc, char* argv[])
* @endcode * @endcode
* @page subscribe Subscription example * @page subscribe Subscription example
@code @code
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTAsync.h" #include "MQTTAsync.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
......
...@@ -61,15 +61,25 @@ ...@@ -61,15 +61,25 @@
#if defined(OPENSSL) #if defined(OPENSSL)
#include <openssl/ssl.h> #include <openssl/ssl.h>
#else
#define URI_SSL "ssl://"
#endif #endif
#define URI_TCP "tcp://" #define URI_TCP "tcp://"
#include "VersionInfo.h" #include "VersionInfo.h"
const char *client_timestamp_eye = "MQTTClientV3_Timestamp " BUILD_TIMESTAMP; const char *client_timestamp_eye = "MQTTClientV3_Timestamp " BUILD_TIMESTAMP;
const char *client_version_eye = "MQTTClientV3_Version " CLIENT_VERSION; const char *client_version_eye = "MQTTClientV3_Version " CLIENT_VERSION;
void MQTTClient_global_init(int handle_openssl_init)
{
#if defined(OPENSSL)
SSLSocket_handleOpensslInit(handle_openssl_init);
#endif
}
static ClientStates ClientState = static ClientStates ClientState =
{ {
CLIENT_VERSION, /* version */ CLIENT_VERSION, /* version */
...@@ -157,7 +167,6 @@ void MQTTClient_init(void) ...@@ -157,7 +167,6 @@ void MQTTClient_init(void)
static volatile int initialized = 0; static volatile int initialized = 0;
static List* handles = NULL; static List* handles = NULL;
static time_t last;
static int running = 0; static int running = 0;
static int tostop = 0; static int tostop = 0;
static thread_id_type run_id = 0; static thread_id_type run_id = 0;
...@@ -323,13 +332,16 @@ int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char* cli ...@@ -323,13 +332,16 @@ int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char* cli
memset(m, '\0', sizeof(MQTTClients)); memset(m, '\0', sizeof(MQTTClients));
if (strncmp(URI_TCP, serverURI, strlen(URI_TCP)) == 0) if (strncmp(URI_TCP, serverURI, strlen(URI_TCP)) == 0)
serverURI += strlen(URI_TCP); serverURI += strlen(URI_TCP);
#if defined(OPENSSL)
else if (strncmp(URI_SSL, serverURI, strlen(URI_SSL)) == 0) else if (strncmp(URI_SSL, serverURI, strlen(URI_SSL)) == 0)
{ {
#if defined(OPENSSL)
serverURI += strlen(URI_SSL); serverURI += strlen(URI_SSL);
m->ssl = 1; m->ssl = 1;
} #else
rc = MQTTCLIENT_SSL_NOT_SUPPORTED;
goto exit;
#endif #endif
}
m->serverURI = MQTTStrdup(serverURI); m->serverURI = MQTTStrdup(serverURI);
ListAppend(handles, m, sizeof(MQTTClients)); ListAppend(handles, m, sizeof(MQTTClients));
...@@ -994,6 +1006,20 @@ exit: ...@@ -994,6 +1006,20 @@ exit:
return rc; return rc;
} }
static int retryLoopInterval = 5;
static void setRetryLoopInterval(int keepalive)
{
int proposed = keepalive / 10;
if (proposed < 1)
proposed = 1;
else if (proposed > 5)
proposed = 5;
if (proposed < retryLoopInterval)
retryLoopInterval = proposed;
}
static int MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectOptions* options, const char* serverURI) static int MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectOptions* options, const char* serverURI)
{ {
...@@ -1008,6 +1034,7 @@ static int MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectOptions* o ...@@ -1008,6 +1034,7 @@ static int MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectOptions* o
start = MQTTClient_start_clock(); start = MQTTClient_start_clock();
m->c->keepAliveInterval = options->keepAliveInterval; m->c->keepAliveInterval = options->keepAliveInterval;
setRetryLoopInterval(options->keepAliveInterval);
m->c->cleansession = options->cleansession; m->c->cleansession = options->cleansession;
m->c->maxInflightMessages = (options->reliable) ? 1 : 10; m->c->maxInflightMessages = (options->reliable) ? 1 : 10;
...@@ -1612,11 +1639,12 @@ exit: ...@@ -1612,11 +1639,12 @@ exit:
static void MQTTClient_retry(void) static void MQTTClient_retry(void)
{ {
static time_t last = 0L;
time_t now; time_t now;
FUNC_ENTRY; FUNC_ENTRY;
time(&(now)); time(&(now));
if (difftime(now, last) > 5) if (difftime(now, last) > retryLoopInterval)
{ {
time(&(last)); time(&(last));
MQTTProtocol_keepalive(now); MQTTProtocol_keepalive(now);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
* Ian Craggs, Allan Stockdill-Mander - SSL updates * Ian Craggs, Allan Stockdill-Mander - SSL updates
* Ian Craggs - multiple server connection support * Ian Craggs - multiple server connection support
* Ian Craggs - MQTT 3.1.1 support * Ian Craggs - MQTT 3.1.1 support
* Ian Craggs - remove const from eyecatchers #168
*******************************************************************************/ *******************************************************************************/
/** /**
...@@ -166,6 +167,10 @@ ...@@ -166,6 +167,10 @@
* Return code: A QoS value that falls outside of the acceptable range (0,1,2) * Return code: A QoS value that falls outside of the acceptable range (0,1,2)
*/ */
#define MQTTCLIENT_BAD_QOS -9 #define MQTTCLIENT_BAD_QOS -9
/**
* Return code: Attempting SSL connection using non-SSL version of library
*/
#define MQTTCLIENT_SSL_NOT_SUPPORTED -10
/** /**
* Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1 * Default MQTT version to connect with. Use 3.1.1 then fall back to 3.1
...@@ -184,6 +189,12 @@ ...@@ -184,6 +189,12 @@
*/ */
#define MQTT_BAD_SUBSCRIBE 0x80 #define MQTT_BAD_SUBSCRIBE 0x80
/**
* Global init of mqtt library. Call once on program start to set global behaviour.
* handle_openssl_init - if mqtt library should handle openssl init (1) or rely on the caller to init it before using mqtt (0)
*/
void MQTTClient_global_init(int handle_openssl_init);
/** /**
* A handle representing an MQTT client. A valid client handle is available * A handle representing an MQTT client. A valid client handle is available
* following a successful call to MQTTClient_create(). * following a successful call to MQTTClient_create().
...@@ -424,7 +435,7 @@ DLLExport int MQTTClient_create(MQTTClient* handle, const char* serverURI, const ...@@ -424,7 +435,7 @@ DLLExport int MQTTClient_create(MQTTClient* handle, const char* serverURI, const
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. must be MQTW. */ /** The eyecatcher for this structure. must be MQTW. */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0 or 1 /** The version number of this structure. Must be 0 or 1
0 means there is no binary payload option 0 means there is no binary payload option
*/ */
...@@ -467,7 +478,7 @@ typedef struct ...@@ -467,7 +478,7 @@ typedef struct
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. Must be MQTS */ /** The eyecatcher for this structure. Must be MQTS */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0 */ /** The version number of this structure. Must be 0 */
int struct_version; int struct_version;
...@@ -520,7 +531,7 @@ typedef struct ...@@ -520,7 +531,7 @@ typedef struct
typedef struct typedef struct
{ {
/** The eyecatcher for this structure. must be MQTC. */ /** The eyecatcher for this structure. must be MQTC. */
const char struct_id[4]; char struct_id[4];
/** The version number of this structure. Must be 0, 1, 2, 3, 4 or 5. /** The version number of this structure. Must be 0, 1, 2, 3, 4 or 5.
* 0 signifies no SSL options and no serverURIs * 0 signifies no SSL options and no serverURIs
* 1 signifies no serverURIs * 1 signifies no serverURIs
...@@ -1049,9 +1060,9 @@ DLLExport void MQTTClient_destroy(MQTTClient* handle); ...@@ -1049,9 +1060,9 @@ DLLExport void MQTTClient_destroy(MQTTClient* handle);
* of messages occurs. * of messages occurs.
* @page pubsync Synchronous publication example * @page pubsync Synchronous publication example
@code @code
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTClient.h" #include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
...@@ -1098,9 +1109,9 @@ int main(int argc, char* argv[]) ...@@ -1098,9 +1109,9 @@ int main(int argc, char* argv[])
* *
* @page pubasync Asynchronous publication example * @page pubasync Asynchronous publication example
@code{.c} @code{.c}
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTClient.h" #include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
...@@ -1182,9 +1193,9 @@ int main(int argc, char* argv[]) ...@@ -1182,9 +1193,9 @@ int main(int argc, char* argv[])
* @endcode * @endcode
* @page subasync Asynchronous subscription example * @page subasync Asynchronous subscription example
@code @code
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTClient.h" #include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
......
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009, 2014 IBM Corp. * Copyright (c) 2009, 2017 IBM Corp.
* *
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* Ian Craggs - initial API and implementation and/or initial documentation * Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs, Allan Stockdill-Mander - SSL updates * Ian Craggs, Allan Stockdill-Mander - SSL updates
* Ian Craggs - MQTT 3.1.1 support * Ian Craggs - MQTT 3.1.1 support
* Ian Craggs - big endian Linux reversed definition
*******************************************************************************/ *******************************************************************************/
#if !defined(MQTTPACKET_H) #if !defined(MQTTPACKET_H)
...@@ -44,6 +45,12 @@ enum msgTypes ...@@ -44,6 +45,12 @@ enum msgTypes
PINGREQ, PINGRESP, DISCONNECT PINGREQ, PINGRESP, DISCONNECT
}; };
#if defined(__linux__)
#include <endian.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#define REVERSED 1
#endif
#endif
/** /**
* Bitfields for the MQTT header byte. * Bitfields for the MQTT header byte.
......
...@@ -479,7 +479,7 @@ int MQTTPersistence_unpersistQueueEntry(Clients* client, MQTTPersistence_qEntry* ...@@ -479,7 +479,7 @@ int MQTTPersistence_unpersistQueueEntry(Clients* client, MQTTPersistence_qEntry*
char key[PERSISTENCE_MAX_KEY_LENGTH + 1]; char key[PERSISTENCE_MAX_KEY_LENGTH + 1];
FUNC_ENTRY; FUNC_ENTRY;
sprintf(key, "%s%d", PERSISTENCE_QUEUE_KEY, qe->seqno); sprintf(key, "%s%u", PERSISTENCE_QUEUE_KEY, qe->seqno);
if ((rc = client->persistence->premove(client->phandle, key)) != 0) if ((rc = client->persistence->premove(client->phandle, key)) != 0)
Log(LOG_ERROR, 0, "Error %d removing qEntry from persistence", rc); Log(LOG_ERROR, 0, "Error %d removing qEntry from persistence", rc);
FUNC_EXIT_RC(rc); FUNC_EXIT_RC(rc);
......
...@@ -99,16 +99,17 @@ int pstopen(void **handle, const char* clientID, const char* serverURI, void* co ...@@ -99,16 +99,17 @@ int pstopen(void **handle, const char* clientID, const char* serverURI, void* co
while ( (pToken != NULL) && (rc == 0) ) while ( (pToken != NULL) && (rc == 0) )
{ {
/* Append the next directory level and try to create it */ /* Append the next directory level and try to create it */
sprintf( pCrtDirName, "%s/%s", pCrtDirName, pToken ); strcat( pCrtDirName, "/" );
strcat( pCrtDirName, pToken );
rc = pstmkdir( pCrtDirName ); rc = pstmkdir( pCrtDirName );
pToken = strtok_r( NULL, "\\/", &save_ptr ); pToken = strtok_r( NULL, "\\/", &save_ptr );
} }
*handle = clientDir; *handle = clientDir;
free(perserverURI);
free(pTokDirName); free(pTokDirName);
free(pCrtDirName); free(pCrtDirName);
free(perserverURI);
FUNC_EXIT_RC(rc); FUNC_EXIT_RC(rc);
return rc; return rc;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* Ian Craggs - fix for bug 479376 * Ian Craggs - fix for bug 479376
* Ian Craggs - SNI support * Ian Craggs - SNI support
* Ian Craggs - fix for issue #164 * Ian Craggs - fix for issue #164
* Ian Craggs - fix for issue #179
*******************************************************************************/ *******************************************************************************/
/** /**
...@@ -57,7 +58,7 @@ char* MQTTProtocol_addressPort(const char* uri, int* port) ...@@ -57,7 +58,7 @@ char* MQTTProtocol_addressPort(const char* uri, int* port)
colon_pos = NULL; /* means it was an IPv6 separator, not for host:port */ colon_pos = NULL; /* means it was an IPv6 separator, not for host:port */
} }
if (colon_pos) if (colon_pos) /* have to strip off the port */
{ {
size_t addr_len = colon_pos - uri; size_t addr_len = colon_pos - uri;
buf = malloc(addr_len + 1); buf = malloc(addr_len + 1);
...@@ -69,8 +70,15 @@ char* MQTTProtocol_addressPort(const char* uri, int* port) ...@@ -69,8 +70,15 @@ char* MQTTProtocol_addressPort(const char* uri, int* port)
len = strlen(buf); len = strlen(buf);
if (buf[len - 1] == ']') if (buf[len - 1] == ']')
buf[len - 1] = '\0'; {
if (buf == (char*)uri)
{
buf = malloc(len); /* we are stripping off the final ], so length is 1 shorter */
MQTTStrncpy(buf, uri, len);
}
else
buf[len - 1] = '\0';
}
FUNC_EXIT; FUNC_EXIT;
return buf; return buf;
} }
......
...@@ -51,12 +51,12 @@ ...@@ -51,12 +51,12 @@
* */ * */
char* libraries[] = {"paho-mqtt3c", "paho-mqtt3cs", "paho-mqtt3a", "paho-mqtt3as"}; static const char* libraries[] = {"paho-mqtt3c", "paho-mqtt3cs", "paho-mqtt3a", "paho-mqtt3as"};
char* eyecatchers[] = {"MQTTAsyncV3_Version", "MQTTAsyncV3_Timestamp", static const char* eyecatchers[] = {"MQTTAsyncV3_Version", "MQTTAsyncV3_Timestamp",
"MQTTClientV3_Version", "MQTTClientV3_Timestamp"}; "MQTTClientV3_Version", "MQTTClientV3_Timestamp"};
char* FindString(char* filename, char* eyecatcher_input); char* FindString(char* filename, const char* eyecatcher_input);
int printVersionInfo(MQTTAsync_nameValue* info); int printVersionInfo(MQTTAsync_nameValue* info);
int loadandcall(char* libname); int loadandcall(char* libname);
void printEyecatchers(char* filename); void printEyecatchers(char* filename);
...@@ -68,43 +68,49 @@ void printEyecatchers(char* filename); ...@@ -68,43 +68,49 @@ void printEyecatchers(char* filename);
* @param eyecatcher_input the eyecatcher string to look for * @param eyecatcher_input the eyecatcher string to look for
* @return the value found - "" if not found * @return the value found - "" if not found
*/ */
char* FindString(char* filename, char* eyecatcher_input) char* FindString(char* filename, const char* eyecatcher_input)
{ {
FILE* infile = NULL; FILE* infile = NULL;
static char value[100]; static char value[100];
char* eyecatcher = eyecatcher_input; const char* eyecatcher = eyecatcher_input;
memset(value, 0, 100); memset(value, 0, 100);
if ((infile = fopen(filename, "rb")) != NULL) if ((infile = fopen(filename, "rb")) != NULL)
{ {
size_t buflen = strlen(eyecatcher); size_t buflen = strlen(eyecatcher);
char* buffer = (char*) malloc(buflen); char* buffer = (char*) malloc(buflen);
int count = 0;
int c = fgetc(infile);
while (feof(infile) == 0) if (buffer != NULL)
{ {
buffer[count++] = c; int c = fgetc(infile);
if (memcmp(eyecatcher, buffer, buflen) == 0)
while (feof(infile) == 0)
{ {
char* ptr = value; int count = 0;
c = fgetc(infile); /* skip space */ buffer[count++] = c;
c = fgetc(infile); if (memcmp(eyecatcher, buffer, buflen) == 0)
while (isprint(c))
{ {
*ptr++ = c; char* ptr = value;
c = fgetc(infile); /* skip space */
c = fgetc(infile); c = fgetc(infile);
while (isprint(c))
{
*ptr++ = c;
c = fgetc(infile);
}
break;
} }
break; if (count == buflen)
} {
if (count == buflen) memmove(buffer, &buffer[1], buflen - 1);
{ count--;
memmove(buffer, &buffer[1], buflen - 1); }
count--; c = fgetc(infile);
} }
c = fgetc(infile); free(buffer);
} }
free(buffer);
fclose(infile);
} }
return value; return value;
} }
......
...@@ -68,6 +68,8 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts); ...@@ -68,6 +68,8 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts);
void SSLSocket_destroyContext(networkHandles* net); void SSLSocket_destroyContext(networkHandles* net);
void SSLSocket_addPendingRead(int sock); void SSLSocket_addPendingRead(int sock);
/// 1 ~ we are responsible for initializing openssl; 0 ~ openssl init is done externally
static int handle_openssl_init = 1;
static ssl_mutex_type* sslLocks = NULL; static ssl_mutex_type* sslLocks = NULL;
static ssl_mutex_type sslCoreMutex; static ssl_mutex_type sslCoreMutex;
...@@ -417,6 +419,13 @@ extern void SSLLocks_callback(int mode, int n, const char *file, int line) ...@@ -417,6 +419,13 @@ extern void SSLLocks_callback(int mode, int n, const char *file, int line)
} }
} }
void SSLSocket_handleOpensslInit(int bool_value)
{
handle_openssl_init = bool_value;
}
int SSLSocket_initialize(void) int SSLSocket_initialize(void)
{ {
int rc = 0; int rc = 0;
...@@ -426,41 +435,45 @@ int SSLSocket_initialize(void) ...@@ -426,41 +435,45 @@ int SSLSocket_initialize(void)
FUNC_ENTRY; FUNC_ENTRY;
if ((rc = SSL_library_init()) != 1) if (handle_openssl_init)
rc = -1; {
if ((rc = SSL_library_init()) != 1)
rc = -1;
ERR_load_crypto_strings();
SSL_load_error_strings();
ERR_load_crypto_strings(); /* OpenSSL 0.9.8o and 1.0.0a and later added SHA2 algorithms to SSL_library_init().
SSL_load_error_strings(); Applications which need to use SHA2 in earlier versions of OpenSSL should call
OpenSSL_add_all_algorithms() as well. */
/* OpenSSL 0.9.8o and 1.0.0a and later added SHA2 algorithms to SSL_library_init().
Applications which need to use SHA2 in earlier versions of OpenSSL should call OpenSSL_add_all_algorithms();
OpenSSL_add_all_algorithms() as well. */
lockMemSize = CRYPTO_num_locks() * sizeof(ssl_mutex_type);
OpenSSL_add_all_algorithms();
lockMemSize = CRYPTO_num_locks() * sizeof(ssl_mutex_type);
sslLocks = malloc(lockMemSize); sslLocks = malloc(lockMemSize);
if (!sslLocks) if (!sslLocks)
{ {
rc = -1; rc = -1;
goto exit; goto exit;
} }
else else
memset(sslLocks, 0, lockMemSize); memset(sslLocks, 0, lockMemSize);
for (i = 0; i < CRYPTO_num_locks(); i++) for (i = 0; i < CRYPTO_num_locks(); i++)
{ {
/* prc = */SSL_create_mutex(&sslLocks[i]); /* prc = */SSL_create_mutex(&sslLocks[i]);
} }
#if (OPENSSL_VERSION_NUMBER >= 0x010000000) #if (OPENSSL_VERSION_NUMBER >= 0x010000000)
CRYPTO_THREADID_set_callback(SSLThread_id); CRYPTO_THREADID_set_callback(SSLThread_id);
#else #else
CRYPTO_set_id_callback(SSLThread_id); CRYPTO_set_id_callback(SSLThread_id);
#endif #endif
CRYPTO_set_locking_callback(SSLLocks_callback); CRYPTO_set_locking_callback(SSLLocks_callback);
}
SSL_create_mutex(&sslCoreMutex); SSL_create_mutex(&sslCoreMutex);
exit: exit:
...@@ -471,19 +484,26 @@ exit: ...@@ -471,19 +484,26 @@ exit:
void SSLSocket_terminate(void) void SSLSocket_terminate(void)
{ {
FUNC_ENTRY; FUNC_ENTRY;
EVP_cleanup();
ERR_free_strings(); if (handle_openssl_init)
CRYPTO_set_locking_callback(NULL);
if (sslLocks)
{ {
int i = 0; EVP_cleanup();
ERR_free_strings();
for (i = 0; i < CRYPTO_num_locks(); i++) CRYPTO_set_locking_callback(NULL);
if (sslLocks)
{ {
SSL_destroy_mutex(&sslLocks[i]); int i = 0;
for (i = 0; i < CRYPTO_num_locks(); i++)
{
SSL_destroy_mutex(&sslLocks[i]);
}
free(sslLocks);
} }
free(sslLocks);
} }
SSL_destroy_mutex(&sslCoreMutex);
FUNC_EXIT; FUNC_EXIT;
} }
......
...@@ -31,9 +31,13 @@ ...@@ -31,9 +31,13 @@
#define URI_SSL "ssl://" #define URI_SSL "ssl://"
/** 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); int SSLSocket_initialize(void);
void SSLSocket_terminate(void); void SSLSocket_terminate(void);
int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, char* hostname); int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, char* hostname);
int SSLSocket_getch(SSL* ssl, int socket, char* c); int SSLSocket_getch(SSL* ssl, int socket, char* c);
char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len); char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
* Ian Craggs - fix for bug 484496 * Ian Craggs - fix for bug 484496
* Juergen Kosel, Ian Craggs - fix for issue #135 * Juergen Kosel, Ian Craggs - fix for issue #135
* Ian Craggs - issue #217 * Ian Craggs - issue #217
* Ian Craggs - fix for issue #186
*******************************************************************************/ *******************************************************************************/
/** /**
...@@ -172,12 +173,22 @@ int Socket_addSocket(int newSd) ...@@ -172,12 +173,22 @@ int Socket_addSocket(int newSd)
FUNC_ENTRY; FUNC_ENTRY;
if (ListFindItem(s.clientsds, &newSd, intcompare) == NULL) /* make sure we don't add the same socket twice */ if (ListFindItem(s.clientsds, &newSd, intcompare) == NULL) /* make sure we don't add the same socket twice */
{ {
int* pnewSd = (int*)malloc(sizeof(newSd)); if (s.clientsds->count >= FD_SETSIZE)
*pnewSd = newSd; {
ListAppend(s.clientsds, pnewSd, sizeof(newSd)); Log(LOG_ERROR, -1, "addSocket: exceeded FD_SETSIZE %d", FD_SETSIZE);
FD_SET(newSd, &(s.rset_saved)); rc = SOCKET_ERROR;
s.maxfdp1 = max(s.maxfdp1, newSd + 1); }
rc = Socket_setnonblocking(newSd); else
{
int* pnewSd = (int*)malloc(sizeof(newSd));
*pnewSd = newSd;
ListAppend(s.clientsds, pnewSd, sizeof(newSd));
FD_SET(newSd, &(s.rset_saved));
s.maxfdp1 = max(s.maxfdp1, newSd + 1);
rc = Socket_setnonblocking(newSd);
if (rc == SOCKET_ERROR)
Log(LOG_ERROR, -1, "addSocket: setnonblocking");
}
} }
else else
Log(LOG_ERROR, -1, "addSocket: socket %d already in the list", newSd); Log(LOG_ERROR, -1, "addSocket: socket %d already in the list", newSd);
...@@ -671,7 +682,7 @@ int Socket_new(char* addr, int port, int* sock) ...@@ -671,7 +682,7 @@ int Socket_new(char* addr, int port, int* sock)
Log(TRACE_MIN, -1, "New socket %d for %s, port %d", *sock, addr, port); Log(TRACE_MIN, -1, "New socket %d for %s, port %d", *sock, addr, port);
if (Socket_addSocket(*sock) == SOCKET_ERROR) if (Socket_addSocket(*sock) == SOCKET_ERROR)
rc = Socket_error("setnonblocking", *sock); rc = Socket_error("addSocket", *sock);
else else
{ {
/* this could complete immmediately, even though we are non-blocking */ /* this could complete immmediately, even though we are non-blocking */
......
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009, 2014 IBM Corp. * Copyright (c) 2009, 2017 IBM Corp.
* *
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* Contributors: * Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation * Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs, Allan Stockdill-Mander - SSL updates * Ian Craggs, Allan Stockdill-Mander - SSL updates
* Ian Craggs - fix for issue #244
*******************************************************************************/ *******************************************************************************/
/** /**
...@@ -236,6 +237,11 @@ void SocketBuffer_interrupted(int socket, size_t actual_len) ...@@ -236,6 +237,11 @@ void SocketBuffer_interrupted(int socket, size_t actual_len)
else /* new saved queue */ else /* new saved queue */
{ {
queue = def_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); ListAppend(queues, def_queue, sizeof(socket_queue)+def_queue->buflen);
SocketBuffer_newDefQ(); SocketBuffer_newDefQ();
} }
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* Ian Craggs - initial contribution * Ian Craggs - initial contribution
*******************************************************************************/ *******************************************************************************/
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTAsync.h" #include "MQTTAsync.h"
#if !defined(WIN32) #if !defined(WIN32)
......
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2012, 2013 IBM Corp. * Copyright (c) 2012, 2017 IBM Corp.
* *
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* Ian Craggs - initial contribution * Ian Craggs - initial contribution
*******************************************************************************/ *******************************************************************************/
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTAsync.h" #include "MQTTAsync.h"
#if !defined(WIN32) #if !defined(WIN32)
......
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2012, 2013 IBM Corp. * Copyright (c) 2012, 2017 IBM Corp.
* *
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* Ian Craggs - initial contribution * Ian Craggs - initial contribution
*******************************************************************************/ *******************************************************************************/
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTClient.h" #include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
......
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2012, 2013 IBM Corp. * Copyright (c) 2012, 2017 IBM Corp.
* *
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* Ian Craggs - initial contribution * Ian Craggs - initial contribution
*******************************************************************************/ *******************************************************************************/
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTClient.h" #include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
......
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2012, 2013 IBM Corp. * Copyright (c) 2012, 2017 IBM Corp.
* *
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* Ian Craggs - initial contribution * Ian Craggs - initial contribution
*******************************************************************************/ *******************************************************************************/
#include "stdio.h" #include <stdio.h>
#include "stdlib.h" #include <stdlib.h>
#include "string.h" #include <string.h>
#include "MQTTClient.h" #include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883" #define ADDRESS "tcp://localhost:1883"
......
...@@ -237,7 +237,7 @@ void onSubscribeFailure(void* context, MQTTAsync_failureData* response) ...@@ -237,7 +237,7 @@ void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
void onConnectFailure(void* context, MQTTAsync_failureData* response) void onConnectFailure(void* context, MQTTAsync_failureData* response)
{ {
printf("Connect failed, rc %d\n", response->code); printf("Connect failed, rc %d\n", response ? response->code : -99);
finished = 1; finished = 1;
} }
......
...@@ -290,25 +290,31 @@ ADD_TEST( ...@@ -290,25 +290,31 @@ ADD_TEST(
) )
ADD_TEST( ADD_TEST(
NAME test5-3a-server-auth-server-cert-in-client-store NAME test5-2d-multual-ssl-auth-client-missing-client-cert
COMMAND test5 "--test_no" "5" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" COMMAND test5 "--test_no" "5" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt"
) )
ADD_TEST( ADD_TEST(
NAME test5-3b-server-auth-client-missing-broker-cert NAME test5-3a-server-auth-server-cert-in-client-store
COMMAND test5 "--test_no" "6" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" COMMAND test5 "--test_no" "6" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt"
) )
ADD_TEST( ADD_TEST(
NAME test5-4-accept-invalid-certificates NAME test5-3b-server-auth-client-missing-broker-cert
COMMAND test5 "--test_no" "7" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" COMMAND test5 "--test_no" "7" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt"
) )
ADD_TEST(
NAME test5-4-accept-invalid-certificates
COMMAND test5 "--test_no" "8" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt"
)
SET_TESTS_PROPERTIES( SET_TESTS_PROPERTIES(
test5-1-ssl-connection-to-no-SSL-server test5-1-ssl-connection-to-no-SSL-server
test5-2a-multual-ssl-auth-certificates-in-place test5-2a-multual-ssl-auth-certificates-in-place
test5-2b-multual-ssl-auth-broker-missing-client-cert test5-2b-multual-ssl-auth-broker-missing-client-cert
test5-2c-multual-ssl-auth-client-missing-broker-cert test5-2c-multual-ssl-auth-client-missing-broker-cert
test5-2d-multual-ssl-auth-client-missing-client-cert
test5-3a-server-auth-server-cert-in-client-store test5-3a-server-auth-server-cert-in-client-store
test5-3b-server-auth-client-missing-broker-cert test5-3b-server-auth-client-missing-broker-cert
test5-4-accept-invalid-certificates test5-4-accept-invalid-certificates
......
...@@ -1008,6 +1008,7 @@ int test2d(struct Options options) ...@@ -1008,6 +1008,7 @@ int test2d(struct Options options)
int rc = 0; int rc = 0;
char* test_topic = "C client test2d"; char* test_topic = "C client test2d";
int count = 0; int count = 0;
unsigned int iteration = 0;
failures = 0; failures = 0;
MyLog( MyLog(
...@@ -1016,55 +1017,70 @@ int test2d(struct Options options) ...@@ -1016,55 +1017,70 @@ int test2d(struct Options options)
fprintf(xml, "<testcase classname=\"test2d\" name=\"%s\"", testname); fprintf(xml, "<testcase classname=\"test2d\" name=\"%s\"", testname);
global_start_time = start_clock(); global_start_time = start_clock();
rc = MQTTAsync_create(&c, options.mutual_auth_connection, // As reported in https://github.com/eclipse/paho.mqtt.c/issues/190
"test2d", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL); // there is/was some race condition, which caused _sometimes_ that the library failed to detect,
assert("good rc from create", rc == MQTTASYNC_SUCCESS, "rc was %d\n", rc); // that the connect attempt has already failed.
if (rc != MQTTASYNC_SUCCESS) // Therefore we need to test this several times!
for (iteration = 0; !failures && (iteration < 20) ; iteration++)
{ {
MQTTAsync_destroy(&c); count = 0;
goto exit; MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR);
}
rc = MQTTAsync_create(&c, options.mutual_auth_connection,
"test2d", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
assert("good rc from create", rc == MQTTASYNC_SUCCESS, "rc was %d\n", rc);
opts.keepAliveInterval = 20; if (rc != MQTTASYNC_SUCCESS)
opts.cleansession = 1; {
opts.username = "testuser"; MQTTAsync_destroy(&c);
opts.password = "testpassword"; failures++;
break;
}
opts.will = &wopts; opts.keepAliveInterval = 60;
opts.will->message = "will message"; opts.cleansession = 1;
opts.will->qos = 1;
opts.will->retained = 0;
opts.will->topicName = "will topic";
opts.will = NULL;
opts.onSuccess = test2dOnConnect;
opts.onFailure = test2dOnConnectFailure;
opts.context = c;
opts.ssl = &sslopts; opts.will = &wopts;
//if (options.server_key_file != NULL) opts.ssl->trustStore = options.server_key_file; /*file of certificates trusted by client*/ opts.will->message = "will message";
//opts.ssl->keyStore = options.client_key_file; /*file of certificate for client to present to server*/ opts.will->qos = 1;
//if (options.client_key_pass != NULL) opts.will->retained = 0;
// opts.ssl->privateKeyPassword = options.client_key_pass; opts.will->topicName = "will topic";
//opts.ssl->enabledCipherSuites = "DEFAULT"; opts.will = NULL;
//opts.ssl->enabledServerCertAuth = 0; opts.onSuccess = test2dOnConnect;
opts.onFailure = test2dOnConnectFailure;
opts.context = c;
MyLog(LOGA_DEBUG, "Connecting"); opts.ssl = &sslopts;
rc = MQTTAsync_connect(c, &opts); if (options.server_key_file != NULL) opts.ssl->trustStore = options.server_key_file; /*file of certificates trusted by client*/
assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); opts.ssl->keyStore = NULL; /*file of certificate for client to present to server - In this test the client has no certificate! */
if (rc != MQTTASYNC_SUCCESS)
{
failures++;
goto exit;
}
while (!test2dFinished && ++count < 10000) test2dFinished = 0;
MyLog(LOGA_DEBUG, "Connecting");
rc = MQTTAsync_connect(c, &opts);
assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc);
if (rc != MQTTASYNC_SUCCESS)
{
failures++;
MyLog(LOGA_INFO, "Failed in iteration %d\n",iteration);
MQTTAsync_destroy(&c);
break;
}
#define TEST2D_COUNT 1000
while (!test2dFinished && ++count < TEST2D_COUNT)
{
#if defined(WIN32) #if defined(WIN32)
Sleep(100); Sleep(100);
#else #else
usleep(10000L); usleep(10000L);
#endif #endif
}
exit: MQTTAsync_destroy(&c); if (!test2dFinished && count >= TEST2D_COUNT)
{
MyLog(LOGA_INFO, "Failed in iteration %d\n",iteration);
failures++;
}
MQTTAsync_destroy(&c);
}
MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.", MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.",
(failures == 0) ? "passed" : "failed", testname, tests, failures); (failures == 0) ? "passed" : "failed", testname, tests, failures);
write_test_result(); write_test_result();
...@@ -2122,8 +2138,8 @@ int main(int argc, char** argv) ...@@ -2122,8 +2138,8 @@ int main(int argc, char** argv)
int* numtests = &tests; int* numtests = &tests;
int rc = 0; int rc = 0;
int (*tests[])() = int (*tests[])() =
{ NULL, test1, test2a, test2b, test2c, test3a, test3b, test4, /* test5a, { NULL, test1, test2a, test2b, test2c, test2d, test3a, test3b, test4, /* test5a,
test5b, test5c, */ test6, test7, test2d }; test5b, test5c, */ test6, test7 };
xml = fopen("TEST-test5.xml", "w"); xml = fopen("TEST-test5.xml", "w");
fprintf(xml, "<testsuite name=\"test5\" tests=\"%lu\">\n", ARRAY_SIZE(tests) - 1); fprintf(xml, "<testsuite name=\"test5\" tests=\"%lu\">\n", ARRAY_SIZE(tests) - 1);
...@@ -2157,3 +2173,8 @@ int main(int argc, char** argv) ...@@ -2157,3 +2173,8 @@ int main(int argc, char** argv)
return rc; return rc;
} }
/* Local Variables: */
/* indent-tabs-mode: t */
/* c-basic-offset: 8 */
/* End: */
...@@ -21,6 +21,7 @@ cafile test/tls-testing/keys/all-ca.crt ...@@ -21,6 +21,7 @@ cafile test/tls-testing/keys/all-ca.crt
certfile test/tls-testing/keys/server/server.crt certfile test/tls-testing/keys/server/server.crt
keyfile test/tls-testing/keys/server/server.key keyfile test/tls-testing/keys/server/server.key
require_certificate true require_certificate true
use_identity_as_username false
#tls_version tlsv1 #tls_version tlsv1
# server authentication - no client authentication # server authentication - no client authentication
......
...@@ -10,7 +10,8 @@ if [ "$TRAVIS_OS_NAME" == "osx" ]; then ...@@ -10,7 +10,8 @@ if [ "$TRAVIS_OS_NAME" == "osx" ]; then
make make
python ../test/mqttsas2.py & python ../test/mqttsas2.py &
ctest -VV --timeout 600 ctest -VV --timeout 600
kill %1 %2 kill %1
killall mosquitto
fi fi
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
...@@ -21,5 +22,6 @@ if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ...@@ -21,5 +22,6 @@ if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
make make
python ../test/mqttsas2.py & python ../test/mqttsas2.py &
ctest -VV --timeout 600 ctest -VV --timeout 600
kill %1 %2 kill %1
killall mosquitto
fi fi
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
if [ "$TRAVIS_OS_NAME" == "linux" ]; then if [ "$TRAVIS_OS_NAME" == "linux" ]; then
pwd pwd
sudo service mosquitto stop sudo service mosquitto stop
# Stop any mosquitto instance which may be still running from previous runs
killall mosquitto
mosquitto -h mosquitto -h
mosquitto -c test/tls-testing/mosquitto.conf & mosquitto -c test/tls-testing/mosquitto.conf &
fi fi
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment