├── .github └── workflows │ ├── ci-posix.yml │ ├── ci-windows.yml │ ├── coverage.yml │ └── docs.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build.jam ├── cmake └── project-is-top-level.cmake ├── codecov.yml ├── doc ├── Jamfile ├── config.json └── qbk │ ├── 00_main.qbk │ ├── 01_intro.qbk │ ├── 02_getting_started.qbk │ ├── 03_auto_reconnect.qbk │ ├── 04_maintaining_a_stable_connection.qbk │ ├── 05_optimising_communication.qbk │ ├── 06_disconnecting_the_client.qbk │ ├── 07_asio_compliance.qbk │ ├── 08_allocators.qbk │ ├── 09_per_op_cancellation.qbk │ ├── 10_executors.qbk │ ├── 11_multithreading.qbk │ ├── 12_examples.qbk │ ├── examples │ └── Examples.qbk │ └── reference │ ├── Error_handling.qbk │ ├── concepts │ ├── Authenticator.qbk │ ├── LoggerType.qbk │ ├── StreamType.qbk │ └── TlsContext.qbk │ ├── properties │ ├── auth_props.qbk │ ├── connack_props.qbk │ ├── connect_props.qbk │ ├── disconnect_props.qbk │ ├── puback_props.qbk │ ├── pubcomp_props.qbk │ ├── publish_props.qbk │ ├── pubrec_props.qbk │ ├── pubrel_props.qbk │ ├── suback_props.qbk │ ├── subscribe_props.qbk │ ├── unsuback_props.qbk │ ├── unsubscribe_props.qbk │ └── will_props.qbk │ ├── quickref.xml │ └── reason_codes │ ├── Reason_codes.qbk │ └── rcref.xml ├── example ├── CMakeLists.txt ├── hello_world_in_coro_multithreaded_env.cpp ├── hello_world_in_multithreaded_env.cpp ├── hello_world_over_tcp.cpp ├── hello_world_over_tls.cpp ├── hello_world_over_websocket_tcp.cpp ├── hello_world_over_websocket_tls.cpp ├── multiflight_client.cpp ├── publisher.cpp ├── receiver.cpp ├── timeout_with_awaitable_operators.cpp └── timeout_with_parallel_group.cpp ├── include └── boost │ ├── mqtt5.hpp │ └── mqtt5 │ ├── detail │ ├── any_authenticator.hpp │ ├── async_mutex.hpp │ ├── async_traits.hpp │ ├── cancellable_handler.hpp │ ├── channel_traits.hpp │ ├── control_packet.hpp │ ├── internal_types.hpp │ ├── log_invoke.hpp │ ├── rebind_executor.hpp │ ├── shutdown.hpp │ ├── topic_validation.hpp │ ├── traits.hpp │ └── utf8_mqtt.hpp │ ├── error.hpp │ ├── impl │ ├── assemble_op.hpp │ ├── async_sender.hpp │ ├── autoconnect_stream.hpp │ ├── client_service.hpp │ ├── codecs │ │ ├── base_decoders.hpp │ │ ├── base_encoders.hpp │ │ ├── message_decoders.hpp │ │ └── message_encoders.hpp │ ├── connect_op.hpp │ ├── disconnect_op.hpp │ ├── endpoints.hpp │ ├── ping_op.hpp │ ├── publish_rec_op.hpp │ ├── publish_send_op.hpp │ ├── re_auth_op.hpp │ ├── read_message_op.hpp │ ├── read_op.hpp │ ├── reconnect_op.hpp │ ├── replies.hpp │ ├── run_op.hpp │ ├── sentry_op.hpp │ ├── shutdown_op.hpp │ ├── subscribe_op.hpp │ ├── unsubscribe_op.hpp │ └── write_op.hpp │ ├── logger.hpp │ ├── logger_traits.hpp │ ├── mqtt_client.hpp │ ├── property_types.hpp │ ├── reason_codes.hpp │ ├── ssl.hpp │ ├── types.hpp │ ├── websocket.hpp │ └── websocket_ssl.hpp ├── index.html ├── meta └── libraries.json ├── test ├── CMakeLists.txt ├── Jamfile ├── cmake_b2_test │ └── CMakeLists.txt ├── cmake_install_test │ └── CMakeLists.txt ├── cmake_subdir_test │ └── CMakeLists.txt ├── include │ └── test_common │ │ ├── delayed_op.hpp │ │ ├── extra_deps.hpp │ │ ├── message_exchange.hpp │ │ ├── packet_util.hpp │ │ ├── preconditions.hpp │ │ ├── test_authenticators.hpp │ │ ├── test_autoconnect_stream.hpp │ │ ├── test_broker.hpp │ │ ├── test_service.hpp │ │ └── test_stream.hpp ├── integration │ ├── async_sender.cpp │ ├── cancellation.cpp │ ├── client.cpp │ ├── client_functions.cpp │ ├── disconnect.cpp │ ├── executors.cpp │ ├── mqtt_features.cpp │ ├── ping.cpp │ ├── re_authentication.cpp │ ├── read_message.cpp │ ├── receive_publish.cpp │ ├── send_publish.cpp │ └── sub_unsub.cpp ├── src │ ├── quick.cpp │ └── run_tests.cpp └── unit │ ├── async_mutex.cpp │ ├── connect_op.cpp │ ├── default_completion_tokens.cpp │ ├── disconnect_op.cpp │ ├── endpoints.cpp │ ├── error.cpp │ ├── logger.cpp │ ├── publish_send_op.cpp │ ├── reconnect_op.cpp │ ├── serialization.cpp │ ├── session.cpp │ ├── string_validation.cpp │ ├── subscribe_op.cpp │ ├── traits.cpp │ └── unsubscribe_op.cpp ├── tools └── ci.py └── vcpkg.json /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | name: coverage 9 | 10 | on: [push, pull_request] 11 | 12 | jobs: 13 | posix: 14 | name: "coverage ${{ matrix.toolset }} -std=c++${{ matrix.cxxstd }} ${{ matrix.container }}" 15 | defaults: 16 | run: 17 | shell: bash 18 | 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | include: 23 | - toolset: gcc-11 24 | install: g++-11 25 | os: ubuntu-latest 26 | container: ubuntu:22.04 27 | build-type: 'Coverage' 28 | cxxstd: 20 29 | cxxflags: '-g -O0 -std=c++20 --coverage -fkeep-inline-functions -fkeep-static-functions' 30 | ldflags: '--coverage' 31 | 32 | runs-on: ${{ matrix.os }} 33 | container: ${{ matrix.container }} 34 | env: 35 | CXXFLAGS: ${{ matrix.cxxflags }} 36 | LDFLAGS: ${{ matrix.ldflags }} 37 | CMAKE_BUILD_PARALLEL_LEVEL: 4 38 | 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v4 42 | 43 | - name: Setup container environment 44 | if: matrix.container 45 | run: | 46 | apt-get update 47 | apt-get -y install --no-install-recommends \ 48 | sudo git g++ cmake make openssl libssl-dev ca-certificates pkg-config \ 49 | python3 lcov gpg gpg-agent curl 50 | 51 | - name: Install compiler 52 | run: sudo apt-get install -y ${{ matrix.install }} 53 | 54 | - name: Setup Boost 55 | run: | 56 | python3 tools/ci.py setup-boost \ 57 | --source-dir=$(pwd) 58 | 59 | - name: Build standalone tests using CMake 60 | run: | 61 | python3 tools/ci.py build-cmake-standalone-tests \ 62 | --build-type ${{ matrix.build-type }} \ 63 | --cxxstd ${{ matrix.cxxstd }} \ 64 | --toolset ${{ matrix.toolset }} 65 | 66 | - name: Run standalone tests 67 | run: | 68 | python3 tools/ci.py run-cmake-standalone-tests \ 69 | --build-type ${{ matrix.build-type }} 70 | 71 | - name: Generate Coverage Report 72 | run: | 73 | lcov --capture --output-file coverage.info \ 74 | --directory ~/boost-root/libs/mqtt5/__build_standalone_tests__/test 75 | lcov --extract coverage.info '**/boost/mqtt5/*' --output-file coverage.info 76 | 77 | - name: Upload coverage reports to Codecov 78 | uses: codecov/codecov-action@v5 79 | with: 80 | verbose: true 81 | files: coverage.info 82 | disable_search: true 83 | fail_ci_if_error: true 84 | plugins: noop 85 | token: ${{ secrets.CODECOV_TOKEN }} 86 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | name: docs 9 | 10 | on: [push] 11 | 12 | jobs: 13 | 14 | posix: 15 | name: "Docs ${{ matrix.container }}" 16 | 17 | runs-on: ubuntu-latest 18 | container: ubuntu:24.04 19 | defaults: 20 | run: 21 | shell: bash 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | 27 | - name: Setup container environment 28 | run: | 29 | apt-get update 30 | export DEBIAN_FRONTEND=noninteractive # for tzdata 31 | apt-get -y install --no-install-recommends \ 32 | docbook docbook-xml docbook-xsl docutils-doc docutils-common \ 33 | doxygen xsltproc \ 34 | wget ca-certificates g++ rsync git unzip \ 35 | python3 python-is-python3 python3-jinja2 36 | 37 | - name: Setup Boost 38 | run: | 39 | python3 tools/ci.py setup-boost \ 40 | --source-dir=$(pwd) \ 41 | --docs-install=1 42 | 43 | - name: Build docs 44 | run: | 45 | python3 tools/ci.py build-docs 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | build/ 3 | prefix/ 4 | CMakeUserPresets.json 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | cmake_minimum_required(VERSION 3.8...3.20) 9 | 10 | project(boost_mqtt5 VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) 11 | 12 | include(cmake/project-is-top-level.cmake) 13 | 14 | # Determine if this is the superproject or called from add_subdirectory. 15 | if(NOT DEFINED BOOST_MQTT5_MAIN_PROJECT) 16 | set(BOOST_MQTT5_MAIN_PROJECT OFF) 17 | if(PROJECT_IS_TOP_LEVEL) 18 | set(BOOST_MQTT5_MAIN_PROJECT ON) 19 | endif() 20 | endif() 21 | 22 | add_library(boost_mqtt5 INTERFACE) 23 | add_library(Boost::mqtt5 ALIAS boost_mqtt5) 24 | 25 | # If non-Boost dependencies are not found, we just bail out. 26 | find_package(Threads) 27 | if(NOT Threads_FOUND) 28 | message(STATUS "Boost.MQTT5 has been disabled, because the required package Threads hasn't been found") 29 | return() 30 | endif() 31 | 32 | target_include_directories(boost_mqtt5 INTERFACE include) 33 | target_compile_features(boost_mqtt5 INTERFACE cxx_std_17) 34 | 35 | if(BOOST_MQTT5_MAIN_PROJECT) 36 | find_package(Boost 1.82 REQUIRED) 37 | if (NOT Boost_FOUND) 38 | message(STATUS "Cannot find Boost!") 39 | return() 40 | endif() 41 | target_link_libraries(boost_mqtt5 INTERFACE Boost::headers Threads::Threads) 42 | else() 43 | target_link_libraries( 44 | boost_mqtt5 45 | INTERFACE 46 | Boost::asio 47 | Boost::assert 48 | # Boost::beast # Optional, only used for MQTT connections over WebSocket. 49 | Boost::container 50 | Boost::core 51 | Boost::endian 52 | Boost::fusion 53 | Boost::optional 54 | Boost::random 55 | Boost::range 56 | Boost::smart_ptr 57 | Boost::spirit 58 | Boost::system 59 | Boost::type_traits 60 | Threads::Threads 61 | ) 62 | endif() 63 | 64 | option(BOOST_MQTT5_PUBLIC_BROKER_TESTS OFF "Whether to run tests requiring a public MQTT broker") 65 | mark_as_advanced(BOOST_MQTT5_PUBLIC_BROKER_TESTS) 66 | 67 | if(BUILD_TESTING) 68 | # Custom target tests; required by the Boost superproject 69 | if(NOT TARGET tests) 70 | add_custom_target(tests) 71 | endif() 72 | add_subdirectory(test) 73 | endif() 74 | 75 | if(BOOST_MQTT5_MAIN_PROJECT) 76 | option(BUILD_EXAMPLES "Whether to build examples") 77 | if(BUILD_EXAMPLES) 78 | add_subdirectory(example) 79 | endif() 80 | endif() 81 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /build.jam: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | require-b2 5.2 ; 9 | 10 | constant boost_dependencies : 11 | /boost/asio//boost_asio 12 | /boost/assert//boost_assert 13 | /boost/container//boost_container 14 | /boost/core//boost_core 15 | /boost/endian//boost_endian 16 | /boost/fusion//boost_fusion 17 | /boost/optional//boost_optional 18 | /boost/random//boost_random 19 | /boost/range//boost_range 20 | /boost/smart_ptr//boost_smart_ptr 21 | /boost/spirit//boost_spirit 22 | /boost/system//boost_system 23 | /boost/type_traits//boost_type_traits 24 | ; 25 | 26 | project /boost/mqtt5 27 | : common-requirements 28 | include 29 | ; 30 | 31 | explicit 32 | [ alias boost_mqtt5 : : : : $(boost_dependencies) ] 33 | [ alias all : boost_mqtt5 test ] 34 | ; 35 | 36 | call-if : boost-library mqtt5 37 | ; 38 | -------------------------------------------------------------------------------- /cmake/project-is-top-level.cmake: -------------------------------------------------------------------------------- 1 | # This variable is set by project() in CMake 3.21+ 2 | string( 3 | COMPARE EQUAL 4 | "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" 5 | PROJECT_IS_TOP_LEVEL 6 | ) 7 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | codecov: 9 | require_ci_to_pass: true 10 | 11 | comment: 12 | behavior: default 13 | layout: reach,diff,flags,tree,reach 14 | show_carryforward_flags: false 15 | 16 | coverage: 17 | precision: 2 18 | round: down 19 | status: 20 | changes: false 21 | default_rules: 22 | flag_coverage_not_uploaded_behavior: include 23 | patch: 24 | default: 25 | informational: true 26 | project: 27 | default: 28 | informational: true 29 | 30 | github_checks: 31 | annotations: true 32 | 33 | fixes: 34 | - ".*/boost/mqtt5/::include/boost/mqtt5/" 35 | -------------------------------------------------------------------------------- /doc/Jamfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | project mqtt5/doc ; 9 | 10 | import boostbook ; 11 | import os ; 12 | import path ; 13 | import-search /boost/docca ; 14 | import docca ; 15 | 16 | local include-prefix = [ path.root $(__file__:D) [ path.pwd ] ] ; 17 | include-prefix = [ path.native $(include-prefix:D)/include ] ; 18 | 19 | local doxygen_include = 20 | error.hpp 21 | logger.hpp 22 | property_types.hpp 23 | reason_codes.hpp 24 | types.hpp 25 | mqtt_client.hpp 26 | ; 27 | 28 | docca.pyreference reference.qbk 29 | : 30 | [ glob-tree-ex ../include/boost/mqtt5 : $(doxygen_include) : detail impl ] 31 | : 32 | PROJECT_NAME=MQTT5 33 | PROJECT_BRIEF="C++ MQTT5 Client Library" 34 | DISTRIBUTE_GROUP_DOC=YES 35 | ENABLE_PREPROCESSING=YES 36 | MACRO_EXPANSION=YES 37 | EXPAND_ONLY_PREDEF=YES 38 | SEARCH_INCLUDES=NO 39 | STRIP_FROM_PATH=$(include-prefix) 40 | 41 | SKIP_FUNCTION_MACROS=NO 42 | OUTPUT_LANGUAGE=English 43 | ABBREVIATE_BRIEF= 44 | AUTOLINK_SUPPORT=NO 45 | EXTRACT_ALL=YES 46 | HIDE_UNDOC_MEMBERS=YES 47 | HIDE_UNDOC_CLASSES=YES 48 | HIDE_FRIEND_COMPOUNDS=YES 49 | CASE_SENSE_NAMES=YES 50 | SHOW_INCLUDE_FILES=NO 51 | INLINE_INFO=NO 52 | SORT_MEMBER_DOCS=NO 53 | SORT_MEMBERS_CTORS_1ST=YES 54 | SHOW_USED_FILES=NO 55 | SHOW_FILES=NO 56 | SHOW_NAMESPACES=NO 57 | 58 | config.json 59 | ; 60 | 61 | install images 62 | : 63 | [ glob images/*.png ] 64 | : 65 | html/mqtt5/images 66 | ; 67 | 68 | explicit images ; 69 | 70 | xml mqtt5_doc 71 | : 72 | qbk/00_main.qbk 73 | : 74 | reference.qbk 75 | images 76 | ; 77 | 78 | explicit mqtt5_doc ; 79 | 80 | 81 | boostbook mqtt5 82 | : 83 | mqtt5_doc 84 | : 85 | boost.root=../../../.. 86 | chapter.autolabel=1 87 | chunk.section.depth=8 88 | chunk.first.sections=1 89 | toc.max.depth=2 90 | generate.toc="chapter toc,title section nop reference nop part toc" 91 | ../../../tools/boostbook/dtd 92 | : 93 | images 94 | ; 95 | 96 | # These are used to inform the build system of the 97 | # means to build the integrated and stand-alone docs. 98 | 99 | alias boostdoc ; 100 | explicit boostdoc ; 101 | 102 | alias boostrelease : mqtt5 ; 103 | explicit boostrelease ; 104 | -------------------------------------------------------------------------------- /doc/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "include_private": false, 3 | "legacy_behavior": false, 4 | "external_marker": "!EXTERNAL!", 5 | "link_prefix": "mqtt5.ref.", 6 | "convenience_header": "boost/mqtt5.hpp", 7 | "replace_strings": { 8 | "__see_below__": "``['see-below]``", 9 | "\\btypename CompletionToken\\b": "typename __CompletionToken__", 10 | "\\btypename Executor\\b": "typename __Executor__", 11 | "\\btypename ExecutionContext\\b": "typename __ExecutionContext__", 12 | "\\btypename TlsContext\\b": "typename __TlsContext__", 13 | "\\btypename StreamType\\b": "typename __StreamType__", 14 | "\\btypename LoggerType\\b": "typename __LoggerType__" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /doc/qbk/07_asio_compliance.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:asio_compliance Compliance With Boost.Asio] 8 | 9 | Every asynchronous operation in __Asio__ has associated characteristics that specify their behaviour. 10 | 11 | * An *allocator* determines how the asynchronous operations allocate memory resources. 12 | * A *cancellation slot* determines how the asynchronous operations support cancellation. 13 | * An *executor* determines the queuing and execution strategy for completion handlers. 14 | 15 | This section expands further into the roles of allocators, 16 | cancellation slots, and executors, highlighting their integration and usage within the __Client__. 17 | 18 | * See [link mqtt5.asio_compliance.allocators Allocators] for more information about how the 19 | __Client__ supports and uses associated allocators. 20 | * See [link mqtt5.asio_compliance.per_op_cancellation Per-Operation Cancellation] for more information about how 21 | asynchronous operations within the __Client__ support cancellation. 22 | * See [link mqtt5.asio_compliance.executors Executors] for more information about executors. 23 | 24 | [include 08_allocators.qbk] 25 | [include 09_per_op_cancellation.qbk] 26 | [include 10_executors.qbk] 27 | 28 | [endsect] [/asio_compliance] 29 | -------------------------------------------------------------------------------- /doc/qbk/08_allocators.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:allocators Allocators] 8 | 9 | Every asynchronous operation has an associated allocator 10 | designed to provide the operation with a consistent and stable memory source for the duration of its execution. 11 | This allocated memory, referred to as per-operation stable memory resources (POSMs), 12 | remains retained for the lifetime of the operation, ensuring its availability whenever needed. 13 | Asynchronous operations may utilise POSMs in numerous ways. 14 | See __ASIO_ALLOCATORS__ and __ASIO_CUSTOM_MEMORY_ALLOCATION__ for more information. 15 | 16 | The __Client__ supports and utilises allocators associated with `async_xxx`'s handlers 17 | to store the state associated with the operation. 18 | Specifically, the allocator is used to reserve memory for MQTT Control Packet bytes 19 | (__PUBLISH__, __SUBSCRIBE__,...) created by each `async_xxx` operation request. 20 | Moreover, the __Client__'s internal packet queue 21 | (described in the section ['Efficient bandwidth usage with packet queuing] in [link mqtt5.optimising_communication Optimising communication]) 22 | associates the allocator of the first packet in the queue to the low-level __Asio__ function 23 | `async_write` on the transport layer. 24 | 25 | Lastly, the __Client__ uses [@boost:doc/html/boost_asio/reference/recycling_allocator.html `boost::asio::recycling_allocator`] 26 | to allocate memory for its internal operations and components. 27 | 28 | [endsect][/allocators] 29 | -------------------------------------------------------------------------------- /doc/qbk/10_executors.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:executors Executors] 8 | 9 | Every asynchronous operation has an associated executor that determines how the completion handlers are queued and run. 10 | Asynchronous operations use the associated executor to track the existence of the work of asynchronous tasks, 11 | schedule the completion handlers for execution, 12 | and prevent re-entrant execution of the completion handlers to avoid recursion and potential stack overflow issues. 13 | 14 | Every asynchronous operation within the __Client__ is defined as a composed operation. 15 | This implies that each `async_xxx` operation is a sequence consisting of an initiating function, 16 | a series of intermediate asynchronous operations, and a final completion handler. 17 | 18 | Upon creating an instance of the __Client__, it is necessary to provide an executor or an __ExecutionContext__. 19 | The specified executor (or __ExecutionContext__'s executor) will become the default executor associated with the __Client__ 20 | and will be used for the execution of all the intermediate operations and a final completion handler for all asynchronous operations 21 | that have not bound an executor. 22 | If an executor is bound to an asynchronous operation, that executor will be used for the final completion handler instead. 23 | 24 | The following examples will demonstrate the previously described interactions. 25 | 26 | [heading Example: using the constructor's executor as the default associated executor] 27 | 28 | In this code snippet, the __Client__ is constructed with a strand. 29 | Consequently, the __Client__ adopts the strand as its new default executor, 30 | which is used to execute the [refmem mqtt_client async_publish] operation. 31 | 32 | ``` 33 | int main() { 34 | boost::asio::io_context ioc; 35 | 36 | // Construct the Client with a strand. 37 | auto strand = boost::asio::make_strand(ioc.get_executor()); 38 | boost::mqtt5::mqtt_client client(strand); 39 | 40 | client.brokers("", 1883) 41 | .async_run(boost::asio::detached); 42 | 43 | // This asynchronous operation will use the default associated executor, 44 | // which is the strand with which the Client is constructed. 45 | client.async_publish( 46 | "", "Hello world!", 47 | boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, 48 | [&client, &strand](boost::mqtt5::error_code /* ec */) { 49 | assert(strand.running_in_this_thread()); 50 | client.cancel(); 51 | } 52 | ); 53 | 54 | ioc.run(); 55 | } 56 | 57 | ``` 58 | 59 | [endsect] [/executors] 60 | -------------------------------------------------------------------------------- /doc/qbk/12_examples.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:examples Examples] 8 | [nochunk] 9 | 10 | The following list contains all the examples that showcase how to use the __Client__: 11 | 12 | [variablelist 13 | [ 14 | [[link mqtt5.publisher publisher.cpp]] 15 | [Shows how to use the __Client__ as a publisher. The __Client__ publishes sensor readings every `5 seconds`.] 16 | ] 17 | [ 18 | [[link mqtt5.receiver receiver.cpp]] 19 | [Shows how to use the __Client__ as a receiver. The __Client__ subscribes and indefinitely receives Application Messages from the Broker.] 20 | ] 21 | [ 22 | [[link mqtt5.hello_world_over_tcp hello_world_over_tcp.cpp]] 23 | [Publishes a "Hello World" message via TCP/IP.] 24 | ] 25 | [ 26 | [[link mqtt5.hello_world_over_tls hello_world_over_tls.cpp]] 27 | [Publishes a "Hello World" message via TLS/SSL.] 28 | ] 29 | [ 30 | [[link mqtt5.hello_world_over_websocket_tcp hello_world_over_websocket_tcp.cpp]] 31 | [Publishes a "Hello World" message via Websocket/TLS.] 32 | ] 33 | [ 34 | [[link mqtt5.hello_world_over_websocket_tls hello_world_over_websocket_tls.cpp]] 35 | [Publishes a "Hello World" message via Websocket/TLS.] 36 | ] 37 | [ 38 | [[link mqtt5.multiflight_client multiflight_client.cpp]] 39 | [Shows how to use the __Client__ to simultaneously dispatch multiple requests.] 40 | ] 41 | [ 42 | [[link mqtt5.timeout_with_parallel_group timeout_with_parallel_group.cpp]] 43 | [ 44 | Shows how to use the __Client__ with its support for per-operation cancellation to perform operations under a time constraint 45 | using a parallel group. 46 | ] 47 | ] 48 | [ 49 | [[link mqtt5.timeout_with_awaitable_operators timeout_with_awaitable_operators.cpp]] 50 | [ 51 | Shows how to use the __Client__ with its support for per-operation cancellation to perform operations under a time constraint 52 | using awaitable operators. 53 | ] 54 | ] 55 | [ 56 | [[link mqtt5.hello_world_in_multithreaded_env hello_world_in_multithreaded_env.cpp]] 57 | [Shows how to publish a "Hello World" message in a multithreaded environment using callbacks (`post`/`dispatch`).] 58 | ] 59 | [ 60 | [[link mqtt5.hello_world_in_coro_multithreaded_env hello_world_in_coro_multithreaded_env.cpp]] 61 | [Shows how to publish a "Hello World" message in a multithreaded environment using coroutines (`co_spawn`).] 62 | ] 63 | ] 64 | 65 | [endsect][/examples] 66 | -------------------------------------------------------------------------------- /doc/qbk/examples/Examples.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [block''''''] 8 | 9 | [section:hello_world_over_tcp Hello World over TCP/IP] 10 | This example illustrates the process of setting up the Client to connect to the Broker via TCP/IP and publish a "Hello World!" message. 11 | [hello_world_over_tcp] 12 | [endsect] [/hello_world_over_tcp] 13 | 14 | [section:hello_world_over_tls Hello World over TLS/SSL] 15 | This example illustrates the process of setting up the Client to connect to the Broker via TLS/SSL and publish a "Hello World!" message. 16 | [hello_world_over_tls] 17 | [endsect] [/hello_world_over_tls] 18 | 19 | [section:hello_world_over_websocket_tcp Hello World over Websocket/TCP] 20 | This example illustrates the process of setting up the Client to connect to the Broker via Websocket/TCP and publish a "Hello World!" message. 21 | [hello_world_over_websocket_tcp] 22 | [endsect] [/hello_world_over_websocket_tcp] 23 | 24 | [section:hello_world_over_websocket_tls Hello World over Websocket/TLS] 25 | This example illustrates the process of setting up the Client to connect to the Broker via Websocket/TLS and publish a "Hello World!" message. 26 | [hello_world_over_websocket_tls] 27 | [endsect] [/hello_world_over_websocket_tls] 28 | 29 | [section:publisher The publisher] 30 | This example shows how to use __Client__ as a publisher that publishes sensor readings every `5` seconds. 31 | 32 | [publisher] 33 | [endsect] 34 | 35 | [section:receiver The receiver] 36 | This example shows how to use __Client__ as a receiver. 37 | The __Client__ subscribes and indefinitely receives Application Messages from the Broker. 38 | 39 | [receiver] 40 | [endsect] 41 | 42 | [section:multiflight_client The multiflight Client] 43 | This example shows how to use __Client__ to simultaneously dispatch multiple requests. 44 | 45 | [multiflight_client] 46 | [endsect] 47 | 48 | [section:timeout_with_parallel_group Timed MQTT operations with parallel group] 49 | This example demonstrates how to use the __Client__ with its support for per-operation cancellation to perform operations under a time constraint 50 | using parallel group. 51 | Specifically, in this example, the __Client__ will subscribe to a Topic and try to receive a message from the Topic within `5 seconds`. 52 | 53 | [timeout_with_parallel_group] 54 | [endsect] 55 | 56 | [section:timeout_with_awaitable_operators Timed MQTT operations with awaitable operators] 57 | This example demonstrates how to use the __Client__ with its support for per-operation cancellation to perform operations under a time constraint 58 | using awaitable operators. 59 | Specifically, in this example, a call to [refmem mqtt_client async_publish] and [refmem mqtt_client async_disconnect] must complete 60 | within `5 seconds`. Otherwise, they will be cancelled. 61 | 62 | [timeout_with_awaitable_operators] 63 | [endsect] 64 | 65 | [section:hello_world_in_multithreaded_env Hello World in a multithreaded environment using callbacks] 66 | This example demonstrates how to publish a "Hello World" message in a multithreaded environment using callbacks (`post`/`dispatch`). 67 | 68 | [hello_world_in_multithreaded_env] 69 | [endsect] 70 | 71 | [section:hello_world_in_coro_multithreaded_env Hello World in a multithreaded environment using coroutines] 72 | This example demonstrates how to publish a "Hello World" message in a multithreaded environment using coroutines (`co_spawn`). 73 | 74 | [hello_world_in_coro_multithreaded_env] 75 | [endsect] 76 | 77 | [block''''''] 78 | -------------------------------------------------------------------------------- /doc/qbk/reference/concepts/Authenticator.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:Authenticator Authenticator concept] 8 | 9 | A type `T` satisfies `Authenticator` concept if it satisifes the requirements listed below. 10 | 11 | [table 12 | [[operation] [type] [arguments]] 13 | [ 14 | [```a.async_auth(step, data, h)```] 15 | [`void`] 16 | [ 17 | [*`step`] is [reflink2 auth_step_e boost::mqtt5::auth_step_e] that specifies current authentication stage. 18 | 19 | [*`data`] is `std::string`, server's authentication data. 20 | 21 | [*`h`] is [asioreflink any_completion_handler any_completion_handler] with signature `void(__ERROR_CODE__ ec, std::string client_data)`. If `ec` is non-trivial, authentication is aborted. 22 | ] 23 | ] 24 | [ 25 | [```a.method()```] 26 | [`std::string_view`, authentication method] 27 | [] 28 | ] 29 | ] 30 | 31 | [endsect] 32 | -------------------------------------------------------------------------------- /doc/qbk/reference/concepts/LoggerType.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:LoggerType LoggerType concept] 8 | 9 | `LoggerType` represents an object type that will be used by the __Client__ to log events. 10 | 11 | A type satisfies the `LoggerType` concept if it defines [*any number (including zero)] of the following functions: 12 | 13 | [table:log_functions 14 | [[Function signature] [Arguments] [Description]] 15 | [ 16 | [`void at_resolve(error_code ec, std::string_view host, std::string_view port, const asio::ip::tcp::resolver::results_type& eps);`] 17 | [ 18 | [*`ec`] is the `error_code` returned by the resolve operation. 19 | 20 | [*`host`] is the hostname used in the resolve. 21 | 22 | [*`port`] is the port used in the resolve. 23 | 24 | [*`eps`] is a list of endpoints returned by the resolve operation. 25 | ] 26 | [Invoked when the resolve operation is complete.] 27 | ] 28 | [ 29 | [`void at_tcp_connect(error_code ec, asio::ip::tcp::endpoint ep);`] 30 | [ 31 | [*`ec`] is the `error_code` returned by the TCP connect operation. 32 | 33 | [*`ep`] is a TCP endpoint used to establish the TCP connection. 34 | ] 35 | [Invoked when the TCP connect operation is complete.] 36 | ] 37 | [ 38 | [`void at_tls_handshake(error_code ec, asio::ip::tcp::endpoint ep);`] 39 | [ 40 | [*`ec`] is the `error_code` returned by the the TLS handshake operation. 41 | 42 | [*`ep`] is a TCP endpoint used to establish the TLS handshake. 43 | ] 44 | [Invoked when the TLS handshake operation is complete.] 45 | ] 46 | [ 47 | [`void at_ws_handshake(error_code ec, asio::ip::tcp::endpoint ep);`] 48 | [ 49 | [*`ec`] is the `error_code` returned by the the WebSocket handshake operation. 50 | 51 | [*`ep`] is a TCP endpoint used to establish the WebSocket handshake. 52 | ] 53 | [Invoked when the WebSocket handshake operation is complete.] 54 | ] 55 | [ 56 | [`void at_connack(reason_code rc, bool session_present, const connack_props& ca_props);`] 57 | [ 58 | [*`rc`] is the `reason_code` received in the __CONNACK__ packet indicating the result of the MQTT handshake. 59 | 60 | [*`session_present`] A flag indicating whether the Broker already has a session associated with this connection. 61 | 62 | [*`ca_props`] __CONNACK_PROPS__ received in the __CONNACK__ packet. 63 | ] 64 | [Invoked when the __CONNACK__ packet is received, marking the completion of the MQTT handshake. ] 65 | ] 66 | [ 67 | [`void at_disconnect(reason_code rc, const disconnect_props& dc_props);`] 68 | [ 69 | [*`rc`] is the `reason_code` received in the __DISCONNECT__ packet specifying the reason behind the disconnection. 70 | 71 | [*`dc_props`] __DISCONNECT_PROPS__ received in the __DISCONNECT__ packet. 72 | ] 73 | [Invoked when the __DISCONNECT__ packet is received, indicating that the Broker wants to close this connection. ] 74 | ] 75 | ] 76 | 77 | For example, a type `T` that defines `at_connack` and `at_disconnect` functions with their respective arguments is considered a valid `LoggerType`. 78 | This allows you to create your own `LoggerType` classes with functions of interest. 79 | 80 | All defined functions are invoked directly within the __Client__ using its default executor. 81 | If the __Client__ is initialized with an explicit or implicit strand, none of the functions will be invoked concurrently. 82 | 83 | [warning Defined functions should not block and stop the __Client__ from doing work. ] 84 | 85 | A class that satifies this concept is [ghreflink include/boost/mqtt5/logger.hpp logger]. 86 | 87 | [endsect] 88 | -------------------------------------------------------------------------------- /doc/qbk/reference/concepts/StreamType.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:StreamType StreamType concept] 8 | 9 | `StreamType` represents the transport protocol type used to transfer stream of bytes. 10 | 11 | `StreamType` should meet the [beastconceptslink streams AsyncStream] concept. 12 | 13 | It should follow Asio's layered stream model by having a `lowest_layer_type` member type, 14 | and a `lowest_layer` member function, returing a `lowest_layer_type&`. 15 | The `lowest_layer_type` should inherit from __TCP_SOCKET__. 16 | 17 | Additionally, it should have an overload of [ghreflink include/boost/mqtt5/detail/shutdown.hpp async_shutdown] 18 | function that is discoverable via argument-dependent lookup (ADL). 19 | 20 | The types __TCP_SOCKET__, __SSL_STREAM__ and __WEBSOCKET_STREAM__ meet these requirements. 21 | 22 | [endsect] 23 | -------------------------------------------------------------------------------- /doc/qbk/reference/concepts/TlsContext.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:TlsContext TlsContext concept] 8 | 9 | `TlsContext` represents an object that defines the user's configuration for establishing TLS/SSL connections. 10 | If TLS/SSL is not required, this parameter defaults to `std::monostate`. 11 | 12 | The __Client__ treats the `TlsContext` object as an opaque entity. 13 | It is primarily utilized when creating the underlying transport stream and is not directly manipulated by the __Client__. 14 | 15 | For instance, establishing a secure connection using using __SSL_STREAM__ requires __SSL_CONTEXT__ as the `TlsContext` type. 16 | An example of this can be found in the [link mqtt5.hello_world_over_tls hello_world_over_tls.cpp] example. 17 | 18 | [endsect] 19 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/auth_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:auth_props AUTH properties] 8 | The last field in the Variable header of __AUTH__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __AUTH__ Properties, along with descriptions of their usage: 14 | 15 | [table:auth_props AUTH properties 16 | [[Identifier] [Value type] [Description]] 17 | [[authentication_method] [`std::string`] [A UTF-8 Encoded String containing the name of the authentication method used for extended authentication.]] 18 | [[authentication_data] [`std::string`] [Binary Data containing authentication data. The contents of the data are defined by the authentication method.]] 19 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 20 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 21 | This property may be used to provide additional diagnostic or other information. ]] 22 | ] 23 | 24 | [h4 Usage] 25 | After obtaining an instance of `boost::mqtt5::auth_props`, the subscript operator can be used to access a Property. 26 | 27 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 28 | 29 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 30 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 31 | 32 | [h4 Example] 33 | 34 | The following example shows how to set a Property value: 35 | 36 | [!c++] 37 | boost::mqtt5::auth_props props; 38 | props[boost::mqtt5::prop::authentication_method] = "SCRAM-SHA-1"; 39 | props[boost::mqtt5::prop::authentication_data] = "data"; 40 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 41 | 42 | The following example shows how to retrieve a Property value: 43 | 44 | [!c++] 45 | std::optional auth_data = props[boost::mqtt5::prop::authentication_data]; 46 | if (auth_data.has_value()) 47 | // authentication data property was previously set 48 | else 49 | // authentication data property was not set 50 | 51 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 52 | if (!user_props.empty()) 53 | // user property was previously set 54 | else 55 | // user property was not set 56 | 57 | [endsect] 58 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/connack_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:connack_props CONNACK properties] 8 | The last field in the Variable header of __CONNACK__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __CONNACK__ Properties, along with descriptions of their usage: 14 | 15 | [table:connack_props CONNACK properties 16 | [[Identifier] [Value type] [Description]] 17 | [[session_expiry_interval] [`uint32_t`] [Represents the Session Expiry Internal in seconds.]] 18 | [[receive_maximum] [`uint16_t`] [The maximum number of QoS 1 and QoS 2 publications that the Server is willing to process concurrently.]] 19 | [[maximum_qos] [`uint8_t`] [The highest QoS the Server supports.]] 20 | [[retain_available] [`uint8_t`] [A value of 0 means that retained message are not supported. A value of 1 means they are supported.]] 21 | [[maximum_packet_size] [`uint32_t`] [The maximum __PACKET_SIZE__ in bytes as defined by the specification that the Server is willing to accept.]] 22 | [[assigned_client_identifier] [`std::string`] [The Client Identifier which was assigned by the Server because a zero length Client Identifier was found in the __CONNECT__ packet]] 23 | [[topic_alias_maximum] [`uint16_t`] [The highest value that the Server will accept as a Topic Alias sent by the Client.]] 24 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 25 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 26 | The meaning of these properties is not defined by the specification.]] 27 | [[wildcard_subscription_available] [`uint8_t`] [A value of 0 means that Wildcard Subscriptions are not supported. 28 | A value of 1 means they are supported. If not present, they are supported.]] 29 | [[subscription_identifier_available] [`uint8_t`] [A value of 0 means that Subscriptions Identifiers are not supported. 30 | A value of 1 means they are supported. If not present, they are supported.]] 31 | [[shared_subscription_available] [`uint8_t`] [A value of 0 means that Shared Subscriptions are not supported. 32 | A value of 1 means they are supported. If not present, they are supported.]] 33 | [[server_keep_alive] [`uint16_t`] [The Keep Alive time assigned by the Server.]] 34 | [[response_information] [`std::string`] [A UTF-8 Encoded String which is used as the basis for creating a Response Topic.]] 35 | [[server_reference] [`std::string`] [A UTF-8 Encoded String which can be used by the Client to identfy another Server to use.]] 36 | [[authentication_method] [`std::string`] [A UTF-8 Encoded String containing the name of the authentication method used for extended authentication.]] 37 | [[authentication_data] [`std::string`] [Binary Data containing authentication data. The contents of the data are defined by the authentication method.]] 38 | ] 39 | 40 | [h4 Usage] 41 | After obtaining an instance of `boost::mqtt5::connack_props`, the subscript operator can be used to access a Property. 42 | 43 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 44 | 45 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 46 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 47 | 48 | [h4 Example] 49 | 50 | The following example shows how to set a Property value: 51 | 52 | [!c++] 53 | boost::mqtt5::connack_props props; 54 | props[boost::mqtt5::prop::maximum_packet_size] = 65535; 55 | props[boost::mqtt5::prop::assigned_client_identifier] = "ClientID"; 56 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 57 | 58 | The following example shows how to retrieve a Property value: 59 | 60 | [!c++] 61 | std::optional auth_method = props[boost::mqtt5::prop::authentication_method]; 62 | if (auth_method.has_value()) 63 | // authentication method property was previously set 64 | else 65 | // authentication method property was not set 66 | 67 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 68 | if (!user_props.empty()) 69 | // user property was previously set 70 | else 71 | // user property was not set 72 | 73 | [endsect] 74 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/connect_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:connect_props CONNECT properties] 8 | The last field in the Variable header of __CONNECT__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __CONNECT__ Properties, along with descriptions of their usage: 14 | 15 | [table:connect_props CONNECT properties 16 | [[Identifier] [Value type] [Description]] 17 | [[session_expiry_interval] [`uint32_t`] [Represents the Session Expiry Internal in seconds.]] 18 | [[receive_maximum] [`uint16_t`] [The maximum number of QoS 1 and QoS 2 publications that the Client is willing to process concurrently.]] 19 | [[maximum_packet_size] [`uint32_t`] [The maximum __PACKET_SIZE__ in bytes as defined by the specification that the Client is willing to process.]] 20 | [[topic_alias_maximum] [`uint16_t`] [The highest value that the Client will accept as a Topic Alias sent by the Server.]] 21 | [[request_response_information] [`uint8_t`] [The value of 0 signals that the Server MUST NOT return Response Information in __CONNACK__. If the value if 1, it MAY return it.]] 22 | [[request_problem_information] [`uint8_t`] [The value of 0 signals that the Server MAY return a Reason String or User Properties on a __CONNACK__ or __DISCONNECT__ packet, 23 | but MUST NOT send them on any packet other than __PUBLISH__, __CONNACK__, or __DISCONNECT__. 24 | If the value is 1, the Server MAY return a Reason String or User Properties where it is allowed.]] 25 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 26 | The meaning of these properties is not defined by the specification.]] 27 | [[authentication_method] [`std::string`] [A UTF-8 Encoded String containing the name of the authentication method used for extended authentication.]] 28 | [[authentication_data] [`std::string`] [Binary Data containing authentication data. The contents of the data are defined by the authentication method.]] 29 | ] 30 | 31 | [h4 Usage] 32 | After obtaining an instance of `boost::mqtt5::connect_props`, the subscript operator can be used to access a Property. 33 | 34 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 35 | 36 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 37 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 38 | 39 | [h4 Example] 40 | 41 | The following example shows how to set a Property value: 42 | 43 | [!c++] 44 | boost::mqtt5::connect_props props; 45 | props[boost::mqtt5::prop::session_expiry_interval] = 1200; 46 | props[boost::mqtt5::prop::receive_maximum] = uint16_t(100); 47 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 48 | 49 | The following example shows how to retrieve a Property value: 50 | 51 | [!c++] 52 | std::optional auth_method = props[boost::mqtt5::prop::authentication_method]; 53 | if (auth_method.has_value()) 54 | // authentication method property was previously set 55 | else 56 | // authentication method property was not set 57 | 58 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 59 | if (!user_props.empty()) 60 | // user property was previously set 61 | else 62 | // user property was not set 63 | 64 | [endsect] 65 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/disconnect_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:disconnect_props DISCONNECT properties] 8 | The last field in the Variable header of __DISCONNECT__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __DISCONNECT__ Properties, along with descriptions of their usage: 14 | 15 | [table:disconnect_props DISCONNECT properties 16 | [[Identifier] [Value type] [Description]] 17 | [[session_expiry_interval] [`uint32_t`] [Represents the Session Expiry Internal in seconds. Can only be sent by the Client.]] 18 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 19 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 20 | This property may be used to provide additional diagnostic or other information. ]] 21 | [[server_reference] [`std::string`] [A UTF-8 Encoded String which can be used by the Client to identfy another Server to use.]] 22 | ] 23 | 24 | [h4 Usage] 25 | After obtaining an instance of `boost::mqtt5::disconnect_props`, the subscript operator can be used to access a Property. 26 | 27 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 28 | 29 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 30 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 31 | 32 | [h4 Example] 33 | 34 | The following example shows how to set a Property value: 35 | 36 | [!c++] 37 | boost::mqtt5::disconnect_props props; 38 | props[boost::mqtt5::prop::reason_string] = "Lost connection!"; 39 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 40 | 41 | The following example shows how to retrieve a Property value: 42 | 43 | [!c++] 44 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 45 | if (reason_string.has_value()) 46 | // reason string property was previously set 47 | else 48 | // reason string property was not set 49 | 50 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 51 | if (!user_props.empty()) 52 | // user property was previously set 53 | else 54 | // user property was not set 55 | 56 | [endsect] 57 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/puback_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:puback_props PUBACK properties] 8 | The last field in the Variable header of __PUBACK__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __PUBACK__ Properties, along with descriptions of their usage: 14 | 15 | [table:puback_props PUBACK properties 16 | [[Identifier] [Value type] [Description]] 17 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property may be used to provide additional diagnostic or other information. ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::puback_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | 32 | The following example shows how to set a Property value: 33 | 34 | [!c++] 35 | boost::mqtt5::puback_props props; 36 | props[boost::mqtt5::prop::reason_string] = "Some reason..."; 37 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 38 | 39 | The following example shows how to retrieve a Property value: 40 | 41 | [!c++] 42 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 43 | if (reason_string.has_value()) 44 | // reason string property was previously set 45 | else 46 | // reason string property was not set 47 | 48 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 49 | if (!user_props.empty()) 50 | // user property was previously set 51 | else 52 | // user property was not set 53 | 54 | [endsect] 55 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/pubcomp_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:pubcomp_props PUBCOMP properties] 8 | The last field in the Variable header of __PUBCOMP__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __PUBCOMP__ Properties, along with descriptions of their usage: 14 | 15 | [table:pubcomp_props PUBCOMP properties 16 | [[Identifier] [Value type] [Description]] 17 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property may be used to provide additional diagnostic or other information. ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::pubcomp_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | 32 | The following example shows how to set a Property value: 33 | 34 | [!c++] 35 | boost::mqtt5::pubcomp_props props; 36 | props[boost::mqtt5::prop::reason_string] = "Some reason..."; 37 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 38 | 39 | The following example shows how to retrieve a Property value: 40 | 41 | [!c++] 42 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 43 | if (reason_string.has_value()) 44 | // reason string property was previously set 45 | else 46 | // reason string property was not set 47 | 48 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 49 | if (!user_props.empty()) 50 | // user property was previously set 51 | else 52 | // user property was not set 53 | 54 | [endsect] 55 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/publish_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:publish_props PUBLISH properties] 8 | The last field in the Variable header of __PUBLISH__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __PUBLISH__ Properties, along with descriptions of their usage: 14 | 15 | [table:publish_props PUBLISH properties 16 | [[Identifier] [Value type] [Description]] 17 | [[payload_format_indicator] [`uint8_t`] [Value of 0 indicates that the Payload is in unspecified bytes. Value of 1 indicates that the Payload is UTF-8 Encoded Character Data.]] 18 | [[message_expiry_interval] [`uint32_t`] [The lifetime of the Application Message in seconds.]] 19 | [[topic_alias] [`uint16_t`] [Two Byte integer representing the Topic Alias, an integer value that is used to identify the Topic instead of using the Topic Name.]] 20 | [[response_topic] [`std::string`] [A UTF-8 Encoded String which is used as the Topic Name for a response message.]] 21 | [[correlation_data] [`std::string`] [Binary Data used by the sender of the Request Message to identify which request the Response Message is for when it is received.]] 22 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 23 | The meaning of these properties is not defined by the specification.]] 24 | [[subscription_identifier] [`boost::mqtt5::prop::subscription_identifiers`] [Identifier of the matching subscription. If there are multiple matching subscriptions, multiple identifiers may be included.]] 25 | [[content_type] [`std::string`] [A UTF-8 Encoded String describing the content of the Application Message.]] 26 | ] 27 | 28 | [h4 Usage] 29 | After obtaining an instance of `boost::mqtt5::publish_props`, the subscript operator can be used to access a Property. 30 | 31 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 32 | 33 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 34 | except for `boost::mqtt5::prop::user_property` and `boost::mqtt5::prop::subscription_identifier`, where it will return an instance of 35 | `std::vector>` and [reflink2 prop__subscription_identifiers prop::subscription_identifiers] respectively. 36 | [reflink2 prop__subscription_identifiers prop::subscription_identifiers] has the interface of `boost::container::small_vector`.] 37 | 38 | [h4 Example] 39 | 40 | The following example shows how to set a Property value: 41 | 42 | [!c++] 43 | boost::mqtt5::publish_props props; 44 | props[boost::mqtt5::prop::payload_format_indicator] = uint8_t(1); 45 | props[boost::mqtt5::prop::topic_alias] = uint16_t(12); 46 | props[boost::mqtt5::prop::response_topic] = "response_topic"; 47 | props[boost::mqtt5::prop::subscription_identifier].push_back(40); 48 | 49 | The following example shows how to retrieve a Property value: 50 | 51 | [!c++] 52 | std::optional topic_alias = props[boost::mqtt5::prop::topic_alias]; 53 | if (topic_alias.has_value()) 54 | // topic alias property was previously set 55 | else 56 | // topic alias property was not set 57 | 58 | boost::mqtt5::prop::subscription_identifiers& sub_ids = props[boost::mqtt5::prop::subscription_identifier]; 59 | if (!sub_ids.empty()) 60 | // subscription identifier property was previously set 61 | else 62 | // subscription identifier property was not set 63 | 64 | [endsect] 65 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/pubrec_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:pubrec_props PUBREC properties] 8 | The last field in the Variable header of __PUBREC__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __PUBREC__ Properties, along with descriptions of their usage: 14 | 15 | [table:pubrec_props PUBREC properties 16 | [[Identifier] [Value type] [Description]] 17 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property may be used to provide additional diagnostic or other information. ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::pubrec_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | 32 | The following example shows how to set a Property value: 33 | 34 | [!c++] 35 | boost::mqtt5::pubrec_props props; 36 | props[boost::mqtt5::prop::reason_string] = "Some reason..."; 37 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 38 | 39 | The following example shows how to retrieve a Property value: 40 | 41 | [!c++] 42 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 43 | if (reason_string.has_value()) 44 | // reason string property was previously set 45 | else 46 | // reason string property was not set 47 | 48 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 49 | if (!user_props.empty()) 50 | // user property was previously set 51 | else 52 | // user property was not set 53 | 54 | [endsect] 55 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/pubrel_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:pubrel_props PUBREL properties] 8 | The last field in the Variable header of __PUBREL__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __PUBREL__ Properties, along with descriptions of their usage: 14 | 15 | [table:pubrel_props PUBREL properties 16 | [[Identifier] [Value type] [Description]] 17 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property may be used to provide additional diagnostic or other information. ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::pubrel_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | The following example shows how to set a Property value: 32 | 33 | [!c++] 34 | boost::mqtt5::pubrel_props props; 35 | props[boost::mqtt5::prop::reason_string] = "Some reason..."; 36 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 37 | 38 | The following example shows how to retrieve a Property value: 39 | 40 | [!c++] 41 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 42 | if (reason_string.has_value()) 43 | // reason string property was previously set 44 | else 45 | // reason string property was not set 46 | 47 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 48 | if (!user_props.empty()) 49 | // user property was previously set 50 | else 51 | // user property was not set 52 | 53 | [endsect] 54 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/suback_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:suback_props SUBACK properties] 8 | The last field in the Variable header of __SUBACK__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __SUBACK__ Properties, along with descriptions of their usage: 14 | 15 | [table:suback_props SUBACK properties 16 | [[Identifier] [Value type] [Description]] 17 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property may be used to provide additional diagnostic or other information. ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::suback_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | 32 | The following example shows how to set a Property value: 33 | 34 | [!c++] 35 | boost::mqtt5::suback_props props; 36 | props[boost::mqtt5::prop::reason_string] = "Some reason..."; 37 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 38 | 39 | The following example shows how to retrieve a Property value: 40 | 41 | [!c++] 42 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 43 | if (reason_string.has_value()) 44 | // reason string property was previously set 45 | else 46 | // reason string property was not set 47 | 48 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 49 | if (!user_props.empty()) 50 | // user property was previously set 51 | else 52 | // user property was not set 53 | 54 | [endsect] 55 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/subscribe_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:subscribe_props SUBSCRIBE properties] 8 | The last field in the Variable header of __SUBSCRIBE__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __SUBSCRIBE__ Properties, along with descriptions of their usage: 14 | 15 | [table:subscribe_props SUBSCRIBE properties 16 | [[Identifier] [Value type] [Description]] 17 | [[subscription_identifier] [`boost::mqtt5::prop::subscription_identifiers`] [Identifier of the Subscription in range of 1 to 268,435,455.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property can be used to send subscription related properties from the Client to the Server. 20 | The meaning of these properties is not defined by the specification ]] 21 | ] 22 | 23 | [h4 Usage] 24 | After obtaining an instance of `boost::mqtt5::subscribe_props`, the subscript operator can be used to access a Property. 25 | 26 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 27 | 28 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 29 | except for `boost::mqtt5::prop::user_property` and `boost::mqtt5::prop::subscription_identifier`, where it will return an instance of 30 | `std::vector>` and [reflink2 prop__subscription_identifiers prop::subscription_identifiers] respectively. 31 | [reflink2 prop__subscription_identifiers prop::subscription_identifiers] has the interface of `std::optional`.] 32 | 33 | [h4 Example] 34 | 35 | The following example shows how to set a Property value: 36 | 37 | [!c++] 38 | boost::mqtt5::subscribe_props props; 39 | props[boost::mqtt5::prop::subscription_identifier] = 1234; 40 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 41 | 42 | The following example shows how to retrieve a Property value: 43 | 44 | [!c++] 45 | boost::mqtt5::prop::subscription_identifiers sub_id = props[boost::mqtt5::prop::subscription_identifier]; 46 | if (sub_id.has_value()) 47 | // subscription identifier property was previously set 48 | else 49 | // subscription identifier property was not set 50 | 51 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 52 | if (!user_props.empty()) 53 | // user property was previously set 54 | else 55 | // user property was not set 56 | 57 | [endsect] 58 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/unsuback_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:unsuback_props UNSUBACK properties] 8 | The last field in the Variable header of __UNSUBACK__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __UNSUBACK__ Properties, along with descriptions of their usage: 14 | 15 | [table:unsuback_props UNSUBACK properties 16 | [[Identifier] [Value type] [Description]] 17 | [[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]] 18 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 19 | This property may be used to provide additional diagnostic or other information. ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::unsuback_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | 32 | The following example shows how to set a Property value: 33 | 34 | [!c++] 35 | boost::mqtt5::unsuback_props props; 36 | props[boost::mqtt5::prop::reason_string] = "Some reason..."; 37 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 38 | 39 | The following example shows how to retrieve a Property value: 40 | 41 | [!c++] 42 | std::optional reason_string = props[boost::mqtt5::prop::reason_string]; 43 | if (reason_string.has_value()) 44 | // reason string property was previously set 45 | else 46 | // reason string property was not set 47 | 48 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 49 | if (!user_props.empty()) 50 | // user property was previously set 51 | else 52 | // user property was not set 53 | 54 | [endsect] 55 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/unsubscribe_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:unsubscribe_props UNSUBSCRIBE properties] 8 | The last field in the Variable header of __UNSUBSCRIBE__ packet is a set of Properties. 9 | A set contains a Property Length followed by the Properties. 10 | A Property consists of an Identifier and a value. 11 | 12 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 13 | Below is a list of possible __UNSUBSCRIBE__ Properties, along with descriptions of their usage: 14 | 15 | [table:unsubscribe_props UNSUBSCRIBE properties 16 | [[Identifier] [Value type] [Description]] 17 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 18 | This property can be used to send subscription related properties from the Client to the Server. 19 | The meaning of these properties is not defined by the specification ]] 20 | ] 21 | 22 | [h4 Usage] 23 | After obtaining an instance of `boost::mqtt5::unsubscribe_props`, the subscript operator can be used to access a Property. 24 | 25 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 26 | 27 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 28 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 29 | 30 | [h4 Example] 31 | 32 | The following example shows how to set a Property value: 33 | 34 | [!c++] 35 | boost::mqtt5::unsubscribe_props props; 36 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 37 | 38 | The following example shows how to retrieve a Property value: 39 | 40 | [!c++] 41 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 42 | if (!user_props.empty()) 43 | // user property was previously set 44 | else 45 | // user property was not set 46 | 47 | 48 | [endsect] 49 | -------------------------------------------------------------------------------- /doc/qbk/reference/properties/will_props.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:will_props Will properties] 8 | The Will Properties consist of the properties that determine when to publish the [reflink2 will Will] Message 9 | and the Application Message properties to be sent with the [reflink2 will Will] Message. 10 | The Will Properties consists of a Property Length and the Properties. 11 | A Property consists of an Identifier and a value. 12 | 13 | This class extends [reflink2 prop__properties prop::properties], which provides common functionalities for all property classes. 14 | Below is a list of possible [reflink2 will Will] Properties, along with descriptions of their usage: 15 | 16 | [table:will_props Will properties 17 | [[Identifier] [Value type] [Description]] 18 | [[will_delay_interval] [`uint32_t`] [The delay in seconds that need to pass before Server publishes the Client's Will Message.]] 19 | [[payload_format_indicator] [`uint8_t`] [Value of 0 indicates that the Will Message is in unspecified bytes. Value of 1 indicates that the Will Message is UTF-8 Encoded Character Data.]] 20 | [[message_expiry_interval] [`uint32_t`] [The lifetime of the Will Message in seconds. It is send as Publication Expiry Interval when it is published.]] 21 | [[content_type] [`std::string`] [A UTF-8 Encoded String describing the content of the Will Message.]] 22 | [[response_topic] [`std::string`] [A UTF-8 Encoded String which is used as the Topic Name for a response message.]] 23 | [[correlation_data] [`std::string`] [Binary Data used by the sender of the Request Message to identify which request the Response Message is for when it is received.]] 24 | [[user_property] [`std::vector>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet. 25 | The meaning of these properties is not defined by the specification.]] 26 | ] 27 | 28 | [h4 Usage] 29 | After creating an instance of [reflink2 will `boost::mqtt5::will`], the subscript operator can be used to access a Property. 30 | 31 | The Identifiers listed in the table above are available within the `boost::mqtt5::prop` namespace for Property access. 32 | 33 | [note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties, 34 | except for `boost::mqtt5::prop::user_property`, where it will return an instance of `std::vector>`.] 35 | 36 | [h4 Example] 37 | 38 | The following example shows how to set a Property value: 39 | 40 | [!c++] 41 | boost::mqtt5::will will; 42 | will[boost::mqtt5::prop::message_expiry_interval] = 90; 43 | will[boost::mqtt5::prop::content_type] = "Notification"; 44 | props[boost::mqtt5::prop::user_property].emplace_back("name", "value"); 45 | 46 | The following example shows how to retrieve a Property value: 47 | 48 | [!c++] 49 | std::optional c_type = will[boost::mqtt5::prop::content_type]; 50 | if (c_type.has_value()) 51 | // content type property was previously set 52 | else 53 | // content type property was not set 54 | 55 | std::vector>& user_props = props[boost::mqtt5::prop::user_property]; 56 | if (!user_props.empty()) 57 | // user property was previously set 58 | else 59 | // user property was not set 60 | 61 | [endsect] 62 | -------------------------------------------------------------------------------- /doc/qbk/reference/reason_codes/Reason_codes.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | ] 6 | 7 | [section:Reason_codes Reason codes] 8 | 9 | This section lists all possible __REASON_CODE__ instances representing 10 | Reason Codes that can be found in MQTT Control Packets. 11 | 12 | [xinclude rcref.xml] 13 | 14 | [endsect] 15 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | cmake_minimum_required(VERSION 3.8...3.20) 9 | 10 | project(boost-mqtt5-examples LANGUAGES CXX) 11 | 12 | function(add_example name) 13 | add_executable("${name}" ${ARGN}) 14 | target_link_libraries("${name}" PRIVATE Boost::mqtt5) 15 | string(FIND "${example_name}" "tls" found_tls) 16 | if(found_tls GREATER -1) 17 | target_link_libraries("${name}" PRIVATE OpenSSL::SSL) 18 | endif() 19 | endfunction() 20 | 21 | file(GLOB examples "*.cpp") 22 | 23 | foreach(file_path ${examples}) 24 | get_filename_component(example_name "${file_path}" NAME_WE) 25 | add_example("${example_name}" "${file_path}") 26 | endforeach() 27 | 28 | find_package(OpenSSL REQUIRED) 29 | -------------------------------------------------------------------------------- /example/hello_world_in_coro_multithreaded_env.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #include 9 | #ifdef BOOST_ASIO_HAS_CO_AWAIT 10 | 11 | //[hello_world_in_coro_multithreaded_env 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | struct config { 31 | std::string brokers = "broker.hivemq.com"; 32 | uint16_t port = 1883; 33 | std::string client_id = "boost_mqtt5_tester"; 34 | }; 35 | 36 | // client_type with logging enabled 37 | using client_type = boost::mqtt5::mqtt_client< 38 | boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger 39 | >; 40 | 41 | // client_type without logging 42 | //using client_type = boost::mqtt5::mqtt_client; 43 | 44 | // Modified completion token that will prevent co_await from throwing exceptions. 45 | constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::deferred); 46 | 47 | boost::asio::awaitable publish_hello_world( 48 | const config& cfg, client_type& client, 49 | const boost::asio::strand& strand 50 | ) { 51 | // Confirmation that the coroutine running in the strand. 52 | assert(strand.running_in_this_thread()); 53 | 54 | // All these function calls will be executed by the strand that is executing the coroutine. 55 | // All the completion handler's associated executors will be that same strand 56 | // because the Client was constructed with it as the default associated executor. 57 | client.brokers(cfg.brokers, cfg.port) // Set the Broker to connect to. 58 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 59 | .async_run(boost::asio::detached); // Start the Client. 60 | 61 | auto&& [ec, rc, puback_props] = co_await client.async_publish( 62 | "boost-mqtt5/test" /* topic */, "Hello world!" /* payload*/, boost::mqtt5::retain_e::no, 63 | boost::mqtt5::publish_props {}, use_nothrow_awaitable); 64 | 65 | co_await client.async_disconnect(use_nothrow_awaitable); 66 | co_return; 67 | } 68 | 69 | int main(int argc, char** argv) { 70 | config cfg; 71 | 72 | if (argc == 4) { 73 | cfg.brokers = argv[1]; 74 | cfg.port = uint16_t(std::stoi(argv[2])); 75 | cfg.client_id = argv[3]; 76 | } 77 | 78 | // Create a thread pool with 4 threads. 79 | boost::asio::thread_pool tp(4); 80 | 81 | // Create an explicit strand from io_context's executor. 82 | // The strand guarantees a serialised handler execution regardless of the 83 | // number of threads running in the io_context. 84 | boost::asio::strand strand = boost::asio::make_strand(tp.get_executor()); 85 | 86 | // Create the Client with the explicit strand as the default associated executor. 87 | client_type client(strand, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); 88 | 89 | // Spawn the coroutine. 90 | // The executor that executes the coroutine must be the same executor 91 | // that is the Client's default associated executor. 92 | co_spawn( 93 | strand, 94 | publish_hello_world(cfg, client, strand), 95 | [](std::exception_ptr e) { 96 | if (e) 97 | std::rethrow_exception(e); 98 | } 99 | ); 100 | 101 | tp.join(); 102 | 103 | return 0; 104 | } 105 | 106 | //] 107 | 108 | #else 109 | 110 | #include 111 | 112 | int main() { 113 | std::cout << "This example requires C++20 standard to compile and run" << std::endl; 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /example/hello_world_in_multithreaded_env.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[hello_world_in_multithreaded_env 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | struct config { 28 | std::string brokers = "broker.hivemq.com"; 29 | uint16_t port = 1883; 30 | std::string client_id = "boost_mqtt5_tester"; 31 | }; 32 | 33 | int main(int argc, char** argv) { 34 | config cfg; 35 | 36 | if (argc == 4) { 37 | cfg.brokers = argv[1]; 38 | cfg.port = uint16_t(std::stoi(argv[2])); 39 | cfg.client_id = argv[3]; 40 | } 41 | 42 | // Create a thread pool with 4 threads. 43 | boost::asio::thread_pool tp(4); 44 | 45 | // Create an explicit strand from thread_pool's executor. 46 | // The strand guarantees a serialised handler execution regardless of the 47 | // number of threads running in the thread_pool. 48 | boost::asio::strand strand = boost::asio::make_strand(tp.get_executor()); 49 | 50 | // Create the Client with the explicit strand as the default associated executor. 51 | boost::mqtt5::mqtt_client< 52 | boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger 53 | > client(strand, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); 54 | 55 | // Configure the client. 56 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 57 | .credentials(cfg.client_id); // Set the Client Identifier. (optional) 58 | 59 | // Start the Client. 60 | // The async_run function call must be posted/dispatched to the strand. 61 | boost::asio::dispatch( 62 | boost::asio::bind_executor( 63 | strand, 64 | [&client, &strand, &cfg] { 65 | // Considering that the default associated executor of all completion handlers is the strand, 66 | // it is not necessary to explicitly bind it to async_run or other async_xxx's handlers. 67 | client.async_run(boost::asio::detached); // Start the Client. 68 | } 69 | ) 70 | ); 71 | 72 | // The async_publish function call must be posted/dispatched to the strand. 73 | // The associated executor of async_publish's completion handler must be the same strand. 74 | boost::asio::dispatch( 75 | boost::asio::bind_executor( 76 | strand, 77 | [&client, &strand, &cfg] { 78 | assert(strand.running_in_this_thread()); 79 | 80 | client.async_publish( 81 | "boost-mqtt5/test", "Hello World!", boost::mqtt5::retain_e::no, 82 | boost::mqtt5::publish_props {}, 83 | // You may bind the strand to this handler, but it is not necessary 84 | // as the strand is already the default associated handler. 85 | [&client, &strand]( 86 | boost::mqtt5::error_code ec, boost::mqtt5::reason_code rc, 87 | boost::mqtt5::puback_props props 88 | ) { 89 | assert(strand.running_in_this_thread()); 90 | 91 | std::cout << ec.message() << std::endl; 92 | std::cout << rc.message() << std::endl; 93 | 94 | // Stop the Client. 95 | client.cancel(); 96 | } 97 | ); 98 | } 99 | ) 100 | ); 101 | 102 | tp.join(); 103 | 104 | return 0; 105 | } 106 | 107 | //] 108 | -------------------------------------------------------------------------------- /example/hello_world_over_tcp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[hello_world_over_tcp 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | struct config { 21 | std::string brokers = "broker.hivemq.com"; 22 | uint16_t port = 1883; // 1883 is the default TCP MQTT port. 23 | std::string client_id = "boost_mqtt5_tester"; 24 | }; 25 | 26 | int main(int argc, char** argv) { 27 | config cfg; 28 | 29 | if (argc == 4) { 30 | cfg.brokers = argv[1]; 31 | cfg.port = uint16_t(std::stoi(argv[2])); 32 | cfg.client_id = argv[3]; 33 | } 34 | 35 | boost::asio::io_context ioc; 36 | 37 | //[init_tcp_client_with_logger 38 | // Construct the Client with ``__TCP_SOCKET__`` as the underlying stream and enabled logging. 39 | // Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate. 40 | boost::mqtt5::mqtt_client< 41 | boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger 42 | > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); 43 | //] 44 | 45 | // If you want to use the Client without logging, initialise it with the following line instead. 46 | //boost::mqtt5::mqtt_client client(ioc); 47 | 48 | //[configure_tcp_client 49 | client.brokers(cfg.brokers, cfg.port) // Set the Broker to connect to. 50 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 51 | .async_run(boost::asio::detached); // Start the Client. 52 | //] 53 | 54 | //[publish_hello_world 55 | client.async_publish( 56 | "boost-mqtt5/test", "Hello world!", 57 | boost::mqtt5::retain_e::yes, boost::mqtt5::publish_props {}, 58 | [&client](boost::mqtt5::error_code ec) { 59 | std::cout << ec.message() << std::endl; 60 | 61 | // Disconnnect the Client. 62 | client.async_disconnect(boost::asio::detached); 63 | } 64 | ); 65 | //] 66 | 67 | ioc.run(); 68 | } 69 | //] 70 | -------------------------------------------------------------------------------- /example/hello_world_over_tls.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[hello_world_over_tls 9 | #include 10 | #include 11 | #include 12 | #include // OpenSSL traits 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | struct config { 23 | std::string brokers = "broker.hivemq.com"; 24 | uint16_t port = 8883; // 8883 is the default TLS MQTT port. 25 | std::string client_id = "boost_mqtt5_tester"; 26 | }; 27 | 28 | // External customization point. 29 | namespace boost::mqtt5 { 30 | 31 | // Specify that the TLS handshake will be performed as a client. 32 | template 33 | struct tls_handshake_type> { 34 | static constexpr auto client = boost::asio::ssl::stream_base::client; 35 | }; 36 | 37 | // This client uses this function to indicate which hostname it is 38 | // attempting to connect to at the start of the handshaking process. 39 | template 40 | void assign_tls_sni( 41 | const authority_path& ap, 42 | boost::asio::ssl::context& /* ctx */, 43 | boost::asio::ssl::stream& stream 44 | ) { 45 | SSL_set_tlsext_host_name(stream.native_handle(), ap.host.c_str()); 46 | } 47 | 48 | } // end namespace boost::mqtt5 49 | 50 | int main(int argc, char** argv) { 51 | config cfg; 52 | 53 | if (argc == 4) { 54 | cfg.brokers = argv[1]; 55 | cfg.port = uint16_t(std::stoi(argv[2])); 56 | cfg.client_id = argv[3]; 57 | } 58 | 59 | boost::asio::io_context ioc; 60 | 61 | // TLS context that the underlying SSL stream will use. 62 | // The purpose of the context is to allow us to set up TLS/SSL-related options. 63 | // See ``__SSL__`` for more information and options. 64 | boost::asio::ssl::context context(boost::asio::ssl::context::tls_client); 65 | 66 | // Set up the TLS context. 67 | // This step is highly dependent on the specific requirements of the Broker you are connecting to. 68 | // Each broker may have its own standards and expectations for establishing a secure TLS/SSL connection. 69 | // This can include verifying certificates, setting up private keys, PSK authentication, and others. 70 | 71 | // Construct the Client with ``__SSL_STREAM__`` as the underlying stream 72 | // with ``__SSL_CONTEXT__`` as the ``__TlsContext__`` type 73 | // and logging enabled. 74 | boost::mqtt5::mqtt_client< 75 | boost::asio::ssl::stream, 76 | boost::asio::ssl::context, 77 | boost::mqtt5::logger 78 | > client(ioc, std::move(context), boost::mqtt5::logger(boost::mqtt5::log_level::info)); 79 | 80 | 81 | // If you want to use the Client without logging, initialise it with the following line instead. 82 | //boost::mqtt5::mqtt_client< 83 | // boost::asio::ssl::stream, 84 | // boost::asio::ssl::context 85 | //> client(ioc, std::move(context)); 86 | 87 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 88 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 89 | .async_run(boost::asio::detached); // Start the Client. 90 | 91 | client.async_publish( 92 | "boost-mqtt5/test", "Hello world!", 93 | boost::mqtt5::retain_e::no, boost::mqtt5::publish_props{}, 94 | [&client](boost::mqtt5::error_code ec) { 95 | std::cout << ec.message() << std::endl; 96 | client.async_disconnect(boost::asio::detached); 97 | } 98 | ); 99 | 100 | ioc.run(); 101 | } 102 | //] 103 | -------------------------------------------------------------------------------- /example/hello_world_over_websocket_tcp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[hello_world_over_websocket_tcp 9 | #include 10 | #include 11 | #include 12 | #include // WebSocket traits 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | struct config { 23 | std::string brokers = "broker.hivemq.com/mqtt"; // Path example: localhost/mqtt 24 | uint16_t port = 8000; // 8083 is the default Webscoket/TCP MQTT port. However, HiveMQ's public broker uses 8000 instead. 25 | std::string client_id = "boost_mqtt5_tester"; 26 | }; 27 | 28 | int main(int argc, char** argv) { 29 | config cfg; 30 | 31 | if (argc == 4) { 32 | cfg.brokers = argv[1]; 33 | cfg.port = uint16_t(std::stoi(argv[2])); 34 | cfg.client_id = argv[3]; 35 | } 36 | 37 | boost::asio::io_context ioc; 38 | 39 | // Construct the Client with WebSocket/TCP as the underlying stream and enabled logging. 40 | // Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate. 41 | boost::mqtt5::mqtt_client< 42 | boost::beast::websocket::stream, 43 | std::monostate, 44 | boost::mqtt5::logger 45 | > client(ioc, {}, boost::mqtt5::logger(boost::mqtt5::log_level::info)); 46 | 47 | // If you want to use the Client without logging, initialise it with the following line instead. 48 | //boost::mqtt5::mqtt_client> client(ioc); 49 | 50 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 51 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 52 | .async_run(boost::asio::detached); // Start the Client. 53 | 54 | client.async_publish( 55 | "boost-mqtt5/test", "Hello world!", 56 | boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, 57 | [&client](boost::mqtt5::error_code ec) { 58 | std::cout << ec.message() << std::endl; 59 | client.async_disconnect(boost::asio::detached); 60 | } 61 | ); 62 | 63 | ioc.run(); 64 | } 65 | //] 66 | -------------------------------------------------------------------------------- /example/hello_world_over_websocket_tls.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[hello_world_over_websocket_tls 9 | #include 10 | #include 11 | #include 12 | #include // WebSocket and OpenSSL traits 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | struct config { 24 | std::string brokers = "broker.hivemq.com/mqtt"; // Path example: localhost/mqtt 25 | uint16_t port = 8884; // 8884 is the default Websocket/TLS MQTT port. 26 | std::string client_id = "boost_mqtt5_tester"; 27 | }; 28 | 29 | // External customization point. 30 | namespace boost::mqtt5 { 31 | 32 | // Specify that the TLS handshake will be performed as a client. 33 | template 34 | struct tls_handshake_type> { 35 | static constexpr auto client = boost::asio::ssl::stream_base::client; 36 | }; 37 | 38 | // This client uses this function to indicate which hostname it is 39 | // attempting to connect to at the start of the handshaking process. 40 | template 41 | void assign_tls_sni( 42 | const authority_path& ap, 43 | boost::asio::ssl::context& /*ctx*/, 44 | boost::asio::ssl::stream& stream 45 | ) { 46 | SSL_set_tlsext_host_name(stream.native_handle(), ap.host.c_str()); 47 | } 48 | 49 | } // end namespace boost::mqtt5 50 | 51 | int main(int argc, char** argv) { 52 | config cfg; 53 | 54 | if (argc == 4) { 55 | cfg.brokers = argv[1]; 56 | cfg.port = uint16_t(std::stoi(argv[2])); 57 | cfg.client_id = argv[3]; 58 | } 59 | 60 | boost::asio::io_context ioc; 61 | 62 | // TLS context that the underlying SSL stream will use. 63 | // The purpose of the context is to allow us to set up TLS/SSL-related options. 64 | // See ``__SSL__`` for more information and options. 65 | boost::asio::ssl::context context(boost::asio::ssl::context::tls_client); 66 | 67 | // Set up the TLS context. 68 | // This step is highly dependent on the specific requirements of the Broker you are connecting to. 69 | // Each broker may have its own standards and expectations for establishing a secure TLS/SSL connection. 70 | // This can include verifying certificates, setting up private keys, PSK authentication, and others. 71 | 72 | // Construct the Client with WebSocket/SSL as the underlying stream 73 | // with ``__SSL_CONTEXT__`` as the ``__TlsContext__`` type and enabled logging. 74 | boost::mqtt5::mqtt_client< 75 | boost::beast::websocket::stream>, 76 | boost::asio::ssl::context, 77 | boost::mqtt5::logger 78 | > client(ioc, std::move(context), boost::mqtt5::logger(boost::mqtt5::log_level::info)); 79 | 80 | // If you want to use the Client without logging, initialise it with the following line instead. 81 | //boost::mqtt5::mqtt_client< 82 | // boost::beast::websocket::stream>, 83 | // boost::asio::ssl::context 84 | //> client(ioc, std::move(context)); 85 | 86 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 87 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 88 | .async_run(boost::asio::detached); // Start the Client. 89 | 90 | client.async_publish( 91 | "boost-mqtt5/test", "Hello world!", 92 | boost::mqtt5::retain_e::no, boost::mqtt5::publish_props{}, 93 | [&client](boost::mqtt5::error_code ec) { 94 | std::cout << ec.message() << std::endl; 95 | client.async_disconnect(boost::asio::detached); 96 | } 97 | ); 98 | 99 | ioc.run(); 100 | } 101 | //] 102 | -------------------------------------------------------------------------------- /example/multiflight_client.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[multiflight_client 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | struct config { 23 | std::string brokers = "broker.hivemq.com"; 24 | uint16_t port = 1883; 25 | std::string client_id = "boost_mqtt5_tester"; 26 | }; 27 | 28 | int main(int argc, char** argv) { 29 | config cfg; 30 | 31 | if (argc == 4) { 32 | cfg.brokers = argv[1]; 33 | cfg.port = uint16_t(std::stoi(argv[2])); 34 | cfg.client_id = argv[3]; 35 | } 36 | 37 | boost::asio::io_context ioc; 38 | 39 | // Construct the Client with ``__TCP_SOCKET__`` as the underlying stream and enabled logging. 40 | // Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate. 41 | boost::mqtt5::mqtt_client< 42 | boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger 43 | > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); 44 | 45 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 46 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 47 | .async_run(boost::asio::detached); // Start the client. 48 | 49 | // Publish with QoS 2 five times in a row without waiting for the handler 50 | // of the previous async_publish call to be invoked. 51 | for (auto i = 1; i <= 5; ++i) 52 | client.async_publish( 53 | "boost-mqtt5/test", "Hello world!", 54 | boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, 55 | [i](boost::mqtt5::error_code ec, boost::mqtt5::reason_code rc, boost::mqtt5::pubcomp_props) { 56 | std::cout << "Publish number " << i << " completed with: " << std::endl; 57 | std::cout << "\t ec: " << ec.message() << std::endl; 58 | std::cout << "\t rc: " << rc.message() << std::endl; 59 | } 60 | ); 61 | 62 | // We can stop the Client by using signals. 63 | boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); 64 | signals.async_wait([&client](boost::mqtt5::error_code, int) { 65 | client.async_disconnect(boost::asio::detached); 66 | }); 67 | 68 | ioc.run(); 69 | } 70 | //] 71 | -------------------------------------------------------------------------------- /example/timeout_with_awaitable_operators.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #include 9 | #ifdef BOOST_ASIO_HAS_CO_AWAIT 10 | 11 | //[timeout_with_awaitable_operators 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | struct config { 33 | std::string brokers = "broker.hivemq.com"; 34 | uint16_t port = 1883; 35 | std::string client_id = "boost_mqtt5_tester"; 36 | }; 37 | 38 | // Modified completion token that will prevent co_await from throwing exceptions. 39 | constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::deferred); 40 | 41 | // client_type with logging enabled 42 | using client_type = boost::mqtt5::mqtt_client< 43 | boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger 44 | >; 45 | 46 | // client_type without logging 47 | //using client_type = boost::mqtt5::mqtt_client; 48 | 49 | boost::asio::awaitable send_over_mqtt( 50 | const config& cfg, client_type& client 51 | ) { 52 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 53 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 54 | .async_run(boost::asio::detached); // Start the Client. 55 | 56 | auto&& [pec, prc, puback_props] = co_await client.async_publish( 57 | "boost-mqtt5/test", "Hello World!", 58 | boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, 59 | use_nothrow_awaitable 60 | ); 61 | 62 | co_await client.async_disconnect(use_nothrow_awaitable); 63 | co_return; 64 | } 65 | 66 | int main(int argc, char** argv) { 67 | config cfg; 68 | 69 | if (argc == 4) { 70 | cfg.brokers = argv[1]; 71 | cfg.port = uint16_t(std::stoi(argv[2])); 72 | cfg.client_id = argv[3]; 73 | } 74 | 75 | boost::asio::io_context ioc; 76 | 77 | co_spawn( 78 | ioc, 79 | [&ioc, &cfg]() -> boost::asio::awaitable { 80 | // Initialise the Client to connect to the Broker over TCP. 81 | client_type client(ioc); 82 | 83 | // You can also initialise the Client and its logger with a specific log_level (default log_level::info). 84 | //client_type client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::debug)); 85 | 86 | // Construct the timer. 87 | boost::asio::steady_timer timer(ioc, std::chrono::seconds(5)); 88 | 89 | using namespace boost::asio::experimental::awaitable_operators; 90 | auto res = co_await ( 91 | send_over_mqtt(cfg, client) || 92 | timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable)) 93 | ); 94 | 95 | // The timer expired first. The client is cancelled. 96 | if (res.index() == 1) 97 | std::cout << "Send over MQTT timed out!" << std::endl; 98 | // send_over_mqtt completed first. The timer is cancelled. 99 | else 100 | std::cout << "Send over MQTT completed!" << std::endl; 101 | 102 | }, 103 | [](std::exception_ptr e) { 104 | if (e) 105 | std::rethrow_exception(e); 106 | } 107 | ); 108 | 109 | ioc.run(); 110 | } 111 | 112 | //] 113 | 114 | #else 115 | 116 | #include 117 | 118 | int main() { 119 | std::cout << "This example requires C++20 standard to compile and run" << std::endl; 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /example/timeout_with_parallel_group.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | //[timeout_with_parallel_group 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | struct config { 28 | std::string brokers = "broker.hivemq.com"; 29 | uint16_t port = 1883; 30 | std::string client_id = "boost_mqtt5_tester"; 31 | }; 32 | 33 | int main(int argc, char** argv) { 34 | config cfg; 35 | 36 | if (argc == 4) { 37 | cfg.brokers = argv[1]; 38 | cfg.port = uint16_t(std::stoi(argv[2])); 39 | cfg.client_id = argv[3]; 40 | } 41 | 42 | boost::asio::io_context ioc; 43 | 44 | // Construct the Client with ``__TCP_SOCKET__`` as the underlying stream and enabled logging. 45 | // Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate. 46 | boost::mqtt5::mqtt_client< 47 | boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger 48 | > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); 49 | 50 | // If you want to use the Client without logging, initialise it with the following line instead. 51 | //boost::mqtt5::mqtt_client client(ioc); 52 | 53 | // Construct the timer. 54 | boost::asio::steady_timer timer(ioc, std::chrono::seconds(5)); 55 | 56 | client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. 57 | .credentials(cfg.client_id) // Set the Client Identifier. (optional) 58 | .async_run(boost::asio::detached); // Start the Client. 59 | 60 | // Subscribe to a Topic. 61 | client.async_subscribe( 62 | { "test" /* Topic */}, boost::mqtt5::subscribe_props {}, 63 | [](boost::mqtt5::error_code ec, std::vector rcs, boost::mqtt5::suback_props) { 64 | std::cout << "[subscribe ec]: " << ec.message() << std::endl; 65 | std::cout << "[subscribe rc]: " << rcs[0].message() << std::endl; 66 | } 67 | ); 68 | 69 | // Create a parallel group to wait up to 5 seconds to receive a message 70 | // using client.async_receive(...). 71 | boost::asio::experimental::make_parallel_group( 72 | timer.async_wait(boost::asio::deferred), 73 | client.async_receive(boost::asio::deferred) 74 | ).async_wait( 75 | boost::asio::experimental::wait_for_one(), 76 | [&client]( 77 | std::array ord, // Completion order 78 | boost::mqtt5::error_code /* timer_ec */, // timer.async_wait(...) handler signature 79 | // client.async_receive(...) handler signature 80 | boost::mqtt5::error_code receive_ec, 81 | std::string topic, std::string payload, boost::mqtt5::publish_props /* props */ 82 | ) { 83 | if (ord[0] == 1) { 84 | std::cout << "Received a message!" << std::endl; 85 | std::cout << "[receive ec]: " << receive_ec.message() << std::endl; 86 | std::cout << "[receive topic]: " << topic << std::endl; 87 | std::cout << "[receive payload]: " << payload << std::endl; 88 | } 89 | else 90 | std::cout << "Timed out! Did not receive a message within 5 seconds." << std::endl; 91 | 92 | client.cancel(); 93 | } 94 | ); 95 | 96 | ioc.run(); 97 | } 98 | 99 | //] 100 | -------------------------------------------------------------------------------- /include/boost/mqtt5.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_HPP 9 | #define BOOST_MQTT5_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #endif // !BOOST_MQTT5_HPP 20 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/any_authenticator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_ANY_AUTHENTICATOR 9 | #define BOOST_MQTT5_ANY_AUTHENTICATOR 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace boost::mqtt5::detail { 25 | 26 | namespace asio = boost::asio; 27 | using error_code = boost::system::error_code; 28 | 29 | using auth_handler_type = asio::any_completion_handler< 30 | void (error_code, std::string) 31 | >; 32 | 33 | template 34 | using async_auth_sig = decltype( 35 | std::declval().async_auth(std::declval()...) 36 | ); 37 | 38 | template 39 | using method_sig = decltype( 40 | std::declval().method() 41 | ); 42 | 43 | template 44 | constexpr bool is_authenticator = 45 | boost::is_detected< 46 | async_auth_sig, T, 47 | auth_step_e, std::string, auth_handler_type 48 | >::value && 49 | boost::is_detected_convertible_v; 50 | 51 | class auth_fun_base { 52 | using auth_func = void(*)( 53 | auth_step_e, std::string, auth_handler_type, auth_fun_base* 54 | ); 55 | auth_func _auth_func; 56 | 57 | public: 58 | auth_fun_base(auth_func f) : _auth_func(f) {} 59 | ~auth_fun_base() = default; 60 | 61 | void async_auth( 62 | auth_step_e step, std::string data, 63 | auth_handler_type auth_handler 64 | ) { 65 | _auth_func(step, std::move(data), std::move(auth_handler), this); 66 | } 67 | }; 68 | 69 | template < 70 | typename Authenticator, 71 | typename = std::enable_if_t> 72 | > 73 | class auth_fun : public auth_fun_base { 74 | Authenticator _authenticator; 75 | 76 | public: 77 | auth_fun(Authenticator authenticator) : 78 | auth_fun_base(&async_auth), 79 | _authenticator(std::forward(authenticator)) 80 | {} 81 | 82 | static void async_auth( 83 | auth_step_e step, std::string data, auth_handler_type auth_handler, 84 | auth_fun_base* base_ptr 85 | ) { 86 | auto auth_fun_ptr = static_cast(base_ptr); 87 | auth_fun_ptr->_authenticator.async_auth( 88 | step, std::move(data), std::move(auth_handler) 89 | ); 90 | } 91 | }; 92 | 93 | class any_authenticator { 94 | std::string _method; 95 | std::shared_ptr _auth_fun; 96 | 97 | public: 98 | any_authenticator() = default; 99 | 100 | template < 101 | typename Authenticator, 102 | std::enable_if_t, bool> = true 103 | > 104 | any_authenticator(Authenticator&& a) : 105 | _method(a.method()), 106 | _auth_fun( 107 | new detail::auth_fun( 108 | std::forward(a) 109 | ) 110 | ) 111 | {} 112 | 113 | std::string_view method() const { 114 | return _method; 115 | } 116 | 117 | template 118 | decltype(auto) async_auth( 119 | auth_step_e step, std::string data, 120 | CompletionToken&& token 121 | ) { 122 | using Signature = void (error_code, std::string); 123 | 124 | auto initiation = []( 125 | auto handler, any_authenticator& self, 126 | auth_step_e step, std::string data 127 | ) { 128 | self._auth_fun->async_auth( 129 | step, std::move(data), std::move(handler) 130 | ); 131 | }; 132 | 133 | return asio::async_initiate( 134 | initiation, token, std::ref(*this), step, std::move(data) 135 | ); 136 | } 137 | }; 138 | 139 | } // end namespace boost::mqtt5::detail 140 | 141 | 142 | #endif // !BOOST_MQTT5_ANY_AUTHENTICATOR 143 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/cancellable_handler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_CANCELLABLE_HANDLER_HPP 9 | #define BOOST_MQTT5_CANCELLABLE_HANDLER_HPP 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace boost::mqtt5::detail { 22 | 23 | template 24 | class cancellable_handler { 25 | Executor _executor; 26 | Handler _handler; 27 | tracking_type _handler_ex; 28 | asio::cancellation_state _cancellation_state; 29 | 30 | public: 31 | cancellable_handler(Handler&& handler, const Executor& ex) : 32 | _executor(ex), 33 | _handler(std::move(handler)), 34 | _handler_ex(tracking_executor(_handler, ex)), 35 | _cancellation_state( 36 | asio::get_associated_cancellation_slot(_handler), 37 | asio::enable_total_cancellation {}, 38 | asio::enable_terminal_cancellation {} 39 | ) 40 | {} 41 | 42 | cancellable_handler(cancellable_handler&&) = default; 43 | cancellable_handler(const cancellable_handler&) = delete; 44 | 45 | cancellable_handler& operator=(cancellable_handler&&) = default; 46 | cancellable_handler& operator=(const cancellable_handler&) = delete; 47 | 48 | using allocator_type = asio::associated_allocator_t; 49 | allocator_type get_allocator() const noexcept { 50 | return asio::get_associated_allocator(_handler); 51 | } 52 | 53 | using cancellation_slot_type = asio::associated_cancellation_slot_t; 54 | cancellation_slot_type get_cancellation_slot() const noexcept { 55 | return _cancellation_state.slot(); 56 | } 57 | 58 | using executor_type = tracking_type; 59 | executor_type get_executor() const noexcept { 60 | return _handler_ex; 61 | } 62 | 63 | using immediate_executor_type = 64 | asio::associated_immediate_executor_t; 65 | immediate_executor_type get_immediate_executor() const noexcept { 66 | // get_associated_immediate_executor will require asio::execution::blocking.never 67 | // on the default executor. 68 | return asio::get_associated_immediate_executor(_handler, _executor); 69 | } 70 | 71 | asio::cancellation_type_t cancelled() const { 72 | return _cancellation_state.cancelled(); 73 | } 74 | 75 | template 76 | void complete(Args&&... args) { 77 | asio::get_associated_cancellation_slot(_handler).clear(); 78 | asio::dispatch( 79 | _handler_ex, 80 | asio::prepend(std::move(_handler), std::forward(args)...) 81 | ); 82 | } 83 | 84 | template 85 | void complete_immediate(Args&&... args) { 86 | asio::get_associated_cancellation_slot(_handler).clear(); 87 | auto ex = get_immediate_executor(); 88 | asio::dispatch( 89 | ex, 90 | asio::prepend(std::move(_handler), std::forward(args)...) 91 | ); 92 | } 93 | 94 | }; 95 | 96 | } // end boost::mqtt5::detail 97 | 98 | #endif // !BOOST_MQTT5_CANCELLABLE_HANDLER_HPP 99 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/channel_traits.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_CHANNEL_TRAITS_HPP 9 | #define BOOST_MQTT5_CHANNEL_TRAITS_HPP 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace boost::mqtt5::detail { 17 | 18 | namespace asio = boost::asio; 19 | using error_code = boost::system::error_code; 20 | 21 | template 22 | class bounded_deque { 23 | std::deque _buffer; 24 | static constexpr size_t MAX_SIZE = 65535; 25 | 26 | public: 27 | bounded_deque() = default; 28 | bounded_deque(size_t n) : _buffer(n) {} 29 | 30 | size_t size() const { 31 | return _buffer.size(); 32 | } 33 | 34 | template 35 | void push_back(E&& e) { 36 | if (_buffer.size() == MAX_SIZE) 37 | _buffer.pop_front(); 38 | _buffer.push_back(std::forward(e)); 39 | } 40 | 41 | void pop_front() { 42 | _buffer.pop_front(); 43 | } 44 | 45 | void clear() { 46 | _buffer.clear(); 47 | } 48 | 49 | const auto& front() const noexcept { 50 | return _buffer.front(); 51 | } 52 | 53 | auto& front() noexcept { 54 | return _buffer.front(); 55 | } 56 | }; 57 | 58 | template 59 | struct channel_traits { 60 | template 61 | struct rebind { 62 | using other = channel_traits; 63 | }; 64 | }; 65 | 66 | template 67 | struct channel_traits { 68 | static_assert(sizeof...(Args) > 0); 69 | 70 | template 71 | struct rebind { 72 | using other = channel_traits; 73 | }; 74 | 75 | template 76 | struct container { 77 | using type = bounded_deque; 78 | }; 79 | 80 | using receive_cancelled_signature = R(error_code, Args...); 81 | 82 | template 83 | static void invoke_receive_cancelled(F f) { 84 | std::forward(f)( 85 | asio::error::operation_aborted, 86 | typename std::decay_t()... 87 | ); 88 | } 89 | 90 | using receive_closed_signature = R(error_code, Args...); 91 | 92 | template 93 | static void invoke_receive_closed(F f) { 94 | std::forward(f)( 95 | asio::error::operation_aborted, 96 | typename std::decay_t()... 97 | ); 98 | } 99 | }; 100 | 101 | } // namespace boost::mqtt5::detail 102 | 103 | #endif // !BOOST_MQTT5_CHANNEL_TRAITS_HPP 104 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/internal_types.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_INTERNAL_TYPES_HPP 9 | #define BOOST_MQTT5_INTERNAL_TYPES_HPP 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace boost::mqtt5::detail { 22 | 23 | using byte_citer = std::string::const_iterator; 24 | 25 | using time_stamp = std::chrono::time_point; 26 | using duration = time_stamp::duration; 27 | 28 | struct credentials { 29 | std::string client_id; 30 | std::optional username; 31 | std::optional password; 32 | 33 | credentials() = default; 34 | credentials( 35 | std::string client_id, 36 | std::string username, std::string password 37 | ) : 38 | client_id(std::move(client_id)) 39 | { 40 | if (!username.empty()) 41 | this->username = std::move(username); 42 | if (!password.empty()) 43 | this->password = std::move(password); 44 | } 45 | }; 46 | 47 | class session_state { 48 | uint8_t _flags = 0b00; 49 | 50 | static constexpr uint8_t session_present_flag = 0b01; 51 | static constexpr uint8_t subscriptions_present_flag = 0b10; 52 | public: 53 | void session_present(bool present) { 54 | return update_flag(present, session_present_flag); 55 | } 56 | 57 | bool session_present() const { 58 | return _flags & session_present_flag; 59 | } 60 | 61 | void subscriptions_present(bool present) { 62 | return update_flag(present, subscriptions_present_flag); 63 | } 64 | 65 | bool subscriptions_present() const { 66 | return _flags & subscriptions_present_flag; 67 | } 68 | 69 | private: 70 | void update_flag(bool set, uint8_t flag) { 71 | if (set) 72 | _flags |= flag; 73 | else 74 | _flags &= ~flag; 75 | } 76 | }; 77 | 78 | struct mqtt_ctx { 79 | credentials creds; 80 | std::optional will_msg; 81 | uint16_t keep_alive = 60; 82 | connect_props co_props; 83 | connack_props ca_props; 84 | session_state state; 85 | any_authenticator authenticator; 86 | 87 | mqtt_ctx() = default; 88 | 89 | mqtt_ctx(const mqtt_ctx& other) : 90 | creds(other.creds), will_msg(other.will_msg), 91 | keep_alive(other.keep_alive), co_props(other.co_props), 92 | ca_props {}, state {}, 93 | authenticator(other.authenticator) 94 | {} 95 | }; 96 | 97 | struct disconnect_ctx { 98 | disconnect_rc_e reason_code = disconnect_rc_e::normal_disconnection; 99 | disconnect_props props = {}; 100 | bool terminal = false; 101 | }; 102 | 103 | using serial_num_t = uint32_t; 104 | constexpr serial_num_t no_serial = 0; 105 | 106 | namespace send_flag { 107 | 108 | constexpr unsigned none = 0b000; 109 | constexpr unsigned throttled = 0b001; 110 | constexpr unsigned prioritized = 0b010; 111 | constexpr unsigned terminal = 0b100; 112 | 113 | }; 114 | 115 | } // end namespace boost::mqtt5::detail 116 | 117 | #endif // !BOOST_MQTT5_INTERNAL_TYPES_HPP 118 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/log_invoke.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_LOG_INVOKE_HPP 9 | #define BOOST_MQTT5_LOG_INVOKE_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | namespace boost::mqtt5::detail { 23 | 24 | namespace asio = boost::asio; 25 | using boost::system::error_code; 26 | 27 | template 28 | class log_invoke { 29 | LoggerType _logger; 30 | public: 31 | explicit log_invoke(LoggerType logger = {}) : 32 | _logger(std::move(logger)) 33 | {} 34 | 35 | void at_resolve( 36 | error_code ec, std::string_view host, std::string_view port, 37 | const asio::ip::tcp::resolver::results_type& eps 38 | ) { 39 | if constexpr (has_at_resolve) 40 | _logger.at_resolve(ec, host, port, eps); 41 | } 42 | 43 | void at_tcp_connect(error_code ec, asio::ip::tcp::endpoint ep) { 44 | if constexpr (has_at_tcp_connect) 45 | _logger.at_tcp_connect(ec, ep); 46 | } 47 | 48 | void at_tls_handshake(error_code ec, asio::ip::tcp::endpoint ep) { 49 | if constexpr (has_at_tls_handshake) 50 | _logger.at_tls_handshake(ec, ep); 51 | } 52 | 53 | void at_ws_handshake(error_code ec, asio::ip::tcp::endpoint ep) { 54 | if constexpr (has_at_ws_handshake) 55 | _logger.at_ws_handshake(ec, ep); 56 | } 57 | 58 | void at_connack( 59 | reason_code rc, 60 | bool session_present, const connack_props& ca_props 61 | ) { 62 | if constexpr (has_at_connack) 63 | _logger.at_connack(rc, session_present, ca_props); 64 | } 65 | 66 | void at_disconnect(reason_code rc, const disconnect_props& dc_props) { 67 | if constexpr (has_at_disconnect) 68 | _logger.at_disconnect(rc, dc_props); 69 | } 70 | 71 | }; 72 | 73 | } // end namespace boost::mqtt5::detail 74 | 75 | 76 | #endif // !BOOST_MQTT5_LOG_INVOKE_HPP 77 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/rebind_executor.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_REBIND_EXECUTOR_HPP 9 | #define BOOST_MQTT5_REBIND_EXECUTOR_HPP 10 | 11 | namespace boost::asio::ssl { 12 | 13 | // forward declare to preserve optional OpenSSL dependency 14 | template 15 | class stream; 16 | 17 | } // end namespace boost::asio::ssl 18 | 19 | // forward declare to avoid Beast dependency 20 | 21 | namespace boost::beast::websocket { 22 | 23 | template 24 | class stream; 25 | 26 | }// end namespace boost::beast::websocket 27 | 28 | namespace boost::mqtt5::detail { 29 | 30 | namespace asio = boost::asio; 31 | 32 | template 33 | struct rebind_executor { 34 | using other = typename Stream::template rebind_executor::other; 35 | }; 36 | 37 | // asio::ssl::stream does not define a rebind_executor member type 38 | template 39 | struct rebind_executor, Executor> { 40 | using other = typename asio::ssl::stream< 41 | typename rebind_executor::other 42 | >; 43 | }; 44 | 45 | template 46 | struct rebind_executor< 47 | boost::beast::websocket::stream, deflate_supported>, 48 | Executor 49 | > { 50 | using other = typename boost::beast::websocket::stream< 51 | asio::ssl::stream::other>, 52 | deflate_supported 53 | >; 54 | }; 55 | 56 | } // end namespace boost::mqtt5::detail 57 | 58 | #endif // !BOOST_MQTT5_REBIND_EXECUTOR_HPP 59 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/shutdown.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_SHUTDOWN_HPP 9 | #define BOOST_MQTT5_SHUTDOWN_HPP 10 | 11 | #include 12 | 13 | namespace boost::mqtt5::detail { 14 | 15 | template 16 | void async_shutdown(Stream& /* stream */, ShutdownHandler&& /* handler */) { 17 | /* 18 | If you are trying to use beast::websocket::stream and/or OpenSSL 19 | and this goes off, you need to add an include for one of these 20 | * 21 | * 22 | * 23 | 24 | If you are trying to use mqtt_client with user-defined stream type, you must 25 | provide an overload of async_shutdown that is discoverable via 26 | argument-dependent lookup (ADL). 27 | */ 28 | static_assert(sizeof(Stream) == -1, 29 | "Unknown Stream type in async_shutdown."); 30 | } 31 | 32 | template 33 | void async_shutdown( 34 | asio::basic_stream_socket& socket, ShutdownHandler&& handler 35 | ) { 36 | boost::system::error_code ec; 37 | socket.shutdown(asio::socket_base::shutdown_both, ec); 38 | return std::move(handler)(ec); 39 | } 40 | 41 | } // end namespace boost::mqtt5::detail 42 | 43 | #endif // !BOOST_MQTT5_SHUTDOWN_HPP 44 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/topic_validation.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_TOPIC_VALIDATION_HPP 9 | #define BOOST_MQTT5_TOPIC_VALIDATION_HPP 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace boost::mqtt5::detail { 17 | 18 | static constexpr int32_t min_subscription_identifier = 1; 19 | static constexpr int32_t max_subscription_identifier = 268'435'455; 20 | 21 | static constexpr std::string_view shared_sub_prefix = "$share/"; 22 | 23 | inline bool is_utf8_no_wildcard(validation_result result) { 24 | return result == validation_result::valid; 25 | } 26 | 27 | inline bool is_not_empty(size_t sz) { 28 | return sz != 0; 29 | } 30 | 31 | inline bool is_valid_topic_size(size_t sz) { 32 | return is_not_empty(sz) && is_valid_string_size(sz); 33 | } 34 | 35 | inline validation_result validate_topic_name(std::string_view str) { 36 | return validate_impl(str, is_valid_topic_size, is_utf8_no_wildcard); 37 | } 38 | 39 | inline validation_result validate_topic_alias_name(std::string_view str) { 40 | return validate_impl(str, is_valid_string_size, is_utf8_no_wildcard); 41 | } 42 | 43 | inline validation_result validate_shared_topic_name(std::string_view str) { 44 | return validate_impl(str, is_not_empty, is_utf8_no_wildcard); 45 | } 46 | 47 | inline validation_result validate_topic_filter(std::string_view str) { 48 | if (!is_valid_topic_size(str.size())) 49 | return validation_result::invalid; 50 | 51 | constexpr int multi_lvl_wildcard = '#'; 52 | constexpr int single_lvl_wildcard = '+'; 53 | 54 | // must be the last character preceded by '/' or stand alone 55 | // #, .../# 56 | if (str.back() == multi_lvl_wildcard) { 57 | str.remove_suffix(1); 58 | 59 | if (!str.empty() && str.back() != '/') 60 | return validation_result::invalid; 61 | } 62 | 63 | int last_c = -1; 64 | validation_result result; 65 | while (!str.empty()) { 66 | int c = pop_front_unichar(str); 67 | 68 | // can be used at any level, but must occupy an entire level 69 | // +, +/..., .../+/..., .../+ 70 | bool is_valid_single_lvl = (c == single_lvl_wildcard) && 71 | (str.empty() || str.front() == '/') && 72 | (last_c == -1 || last_c == '/'); 73 | 74 | result = validate_mqtt_utf8_char(c); 75 | if ( 76 | result == validation_result::valid || 77 | is_valid_single_lvl 78 | ) { 79 | last_c = c; 80 | continue; 81 | } 82 | 83 | return validation_result::invalid; 84 | } 85 | 86 | return validation_result::valid; 87 | } 88 | 89 | inline validation_result validate_shared_topic_filter( 90 | std::string_view str, bool wildcard_allowed = true 91 | ) { 92 | if (!is_valid_topic_size(str.size())) 93 | return validation_result::invalid; 94 | 95 | if (str.compare(0, shared_sub_prefix.size(), shared_sub_prefix) != 0) 96 | return validation_result::invalid; 97 | 98 | str.remove_prefix(shared_sub_prefix.size()); 99 | 100 | size_t share_name_end = str.find_first_of('/'); 101 | if (share_name_end == std::string::npos) 102 | return validation_result::invalid; 103 | 104 | validation_result result; 105 | result = validate_shared_topic_name(str.substr(0, share_name_end)); 106 | 107 | if (result != validation_result::valid) 108 | return validation_result::invalid; 109 | 110 | auto topic_filter = str.substr(share_name_end + 1); 111 | return wildcard_allowed ? 112 | validate_topic_filter(topic_filter) : 113 | validate_topic_name(topic_filter) 114 | ; 115 | } 116 | 117 | } // end namespace boost::mqtt5::detail 118 | 119 | #endif //BOOST_MQTT5_TOPIC_VALIDATION_HPP 120 | -------------------------------------------------------------------------------- /include/boost/mqtt5/detail/traits.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | #ifndef BOOST_MQTT5_TRAITS_HPP 9 | #define BOOST_MQTT5_TRAITS_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace boost::mqtt5::detail { 20 | 21 | template 22 | constexpr bool is_optional_impl = false; 23 | 24 | template 25 | constexpr bool is_optional_impl> = true; 26 | 27 | template 28 | constexpr bool is_optional = is_optional_impl>; 29 | 30 | template typename> 31 | constexpr bool is_specialization = false; 32 | 33 | template