diff --git a/README.md b/README.md index d35d8b1..18d1ad3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -Async.MQTT5: A C++20 MQTT client based on Boost.Asio +Async.MQTT5: A ~~C++20~~ C++17 MQTT client based on Boost.Asio =============================== -Async.MQTT5 is a professional, industrial-grade C++20 client built on [Boost.Asio](https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio.html). This client is designed for publishing or receiving messages from an MQTT 5.0 compatible broker. Async.MQTT5 represents a comprehensive implementation of the MQTT 5.0 protocol standard, offering full support for publishing or receiving messages with QoS 0, 1, and 2. +Async.MQTT5 is a professional, industrial-grade C++17 client built on [Boost.Asio](https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio.html). This client is designed for publishing or receiving messages from an MQTT 5.0 compatible broker. Async.MQTT5 represents a comprehensive implementation of the MQTT 5.0 protocol standard, offering full support for publishing or receiving messages with QoS 0, 1, and 2. Our clear intention is to include the Async.MQTT5 library into [Boost](https://www.boost.org/). We are actively working on it. @@ -42,7 +42,7 @@ Using the library You can compile the example below with the following command line on Linux: - $ clang++ -std=c++20 -o example -I -Iinclude -pthread + $ clang++ -std=c++17 -o example -I -Iinclude -pthread Usage and API --------- @@ -101,7 +101,7 @@ It may not be suitable for you if: Requirements --------- Async.MQTT5 is a header-only library. To use Async.MQTT5 it requires the following: -- **C++20 capable compiler** +- **C++17 capable compiler** - **Boost 1.82 or later**. In addition to Asio, we use other header-only libraries such as Beast, Spirit, and more. - **OpenSSL**. Only if you require an SSL connection by using [boost::asio::ssl::stream](https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio/reference/ssl__stream.html). diff --git a/doc/qbk/01_intro.qbk b/doc/qbk/01_intro.qbk index 452e36c..a52fc90 100644 --- a/doc/qbk/01_intro.qbk +++ b/doc/qbk/01_intro.qbk @@ -1,7 +1,7 @@ [section:intro Introduction] [nochunk] -__Self__ is a C++20 client built on __Asio__. +__Self__ is a C++17 client built on __Asio__. This client is designed for publishing or receiving messages from an MQTT 5.0 compatible broker. __Self__ represents a comprehensive implementation of the MQTT 5.0 protocol standard, offering full support for publishing or receiving messages with QoS 0, 1, and 2. @@ -96,7 +96,7 @@ It may not be suitable for you if: __Self__ is a header-only library. To use __Self__ it requires the following: -* [*C++20 capable compiler] +* [*C++17 capable compiler] * [*Boost 1.82 or later]. In addition to Asio, we use other header-only libraries such as Beast, Spirit, and more. * [*OpenSSL]. Only if you require an SSL connection by using [asioreflink ssl__stream ssl::stream]. diff --git a/example/futures.cpp b/example/futures.cpp index 2c14889..216d691 100644 --- a/example/futures.cpp +++ b/example/futures.cpp @@ -95,7 +95,7 @@ int main(int argc, char** argv) { client_type c(ioc.get_executor(), ""); c.credentials("test-client", "", "") - .brokers("mqtt.mireo.local", 1883) + .brokers("mqtt.broker", 1883) .run(); for (int i = 0; i < thread_num - 1; ++i) diff --git a/example/openssl-tls.cpp b/example/openssl_tls.cpp similarity index 60% rename from example/openssl-tls.cpp rename to example/openssl_tls.cpp index 880cc78..feb6826 100644 --- a/example/openssl-tls.cpp +++ b/example/openssl_tls.cpp @@ -1,10 +1,7 @@ #include -#include #include #include -#include -#include #include @@ -14,7 +11,6 @@ namespace asio = boost::asio; namespace async_mqtt5 { -constexpr auto use_nothrow_awaitable = asio::as_tuple(asio::use_awaitable); template struct tls_handshake_type> { @@ -33,27 +29,26 @@ void assign_tls_sni( } // end namespace async_mqtt5 -constexpr char spacetime_ca[] = +constexpr char mireo_ca[] = "-----BEGIN CERTIFICATE-----\n" - "MIIDYDCCAkigAwIBAgIUZZsEKT8m+uGZRNMaTuCiZBchSU4wDQYJKoZIhvcNAQEL\n" - "BQAwHTEbMBkGA1UEAwwSTWlyZW8gU3BhY2VUaW1lIENBMB4XDTIzMDIwNzIwMzU1\n" - "MFoXDTMzMDIwNDIwMzU1MFowHTEbMBkGA1UEAwwSTWlyZW8gU3BhY2VUaW1lIENB\n" - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzZshi2nJNyYZ4aJN+q27\n" - "wA69lUAwRSHiJGBCGzppLue/LFDDC1t8GDicjYLGH5eJOlFwr8TbAr+ZH+/PyBoS\n" - "7g5tsSn5xZhgEaivnq1MJNqYWHqW5KF2KhGxzzyC6m3JFK21H0xiJu9ej2wQs1tD\n" - "ZWG3Y7pKeMFhCezEip5ueIyvmjsenK00TJKr6w1Rkr4BA40euLb5r0srWllKKUyl\n" - "t5AEFghdVU7GeXfC2LPrzzMVngFWTaoL3QRf7VMhvNC0Xq7h2yjwd4wROYiJFZBj\n" - "UgDSi2W50fPlVDliET2hPBR6lQPgCBRoIdQF8NneSBJ5xH+mw9ZZV8btL8ahwWtL\n" - "GwIDAQABo4GXMIGUMB0GA1UdDgQWBBSM9pLZlAekgqt7ZXzPOdTEifMLmzBYBgNV\n" - "HSMEUTBPgBSM9pLZlAekgqt7ZXzPOdTEifMLm6EhpB8wHTEbMBkGA1UEAwwSTWly\n" - "ZW8gU3BhY2VUaW1lIENBghRlmwQpPyb64ZlE0xpO4KJkFyFJTjAMBgNVHRMEBTAD\n" - "AQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAuSe6ZOwc8KnNXs1M\n" - "KoShOUxZGDFBUJFNAtTSsMi0ap6GIo/yJr+6SAkHkVU0HFkl5lzRo9aUHRw4O7Ez\n" - "579JMzUDdEGBxtYqda0Rxnw8N2mq5Fxpv+1b6v4GsWA30k6TdqnrFdNpFVI84W6u\n" - "Fw3HTKA0Ah0jXryc1kC1jU7mYKf66TDI5PSbuZRjHgQzzyUXZmCn1WcLbvunsc4r\n" - "Tk2FrfXHfvag12yPLc9aIOrtfRW2wtlZcxMzX4oE6wfllAIIsSZGx0muydiMe8bw\n" - "Od5S0p1sspsWOthj1t9yhHMwznwV81QLePWzgGmml21uA067ZGG8NHxNbERd/9e+\n" - "Qz9m6w==\n" + "MIIDUTCCAjmgAwIBAgIUAzV59EhZA5MXluHNqRi9cBP0x9swDQYJKoZIhvcNAQEL\n" + "BQAwGDEWMBQGA1UEAwwNTWlyZW8gUm9vdCBDQTAeFw0yMjA0MDcxMzM1MjlaFw0z\n" + "MjA0MDQxMzM1MjlaMBgxFjAUBgNVBAMMDU1pcmVvIFJvb3QgQ0EwggEiMA0GCSqG\n" + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCin/qsHpdxT3iW0SEHhAcTfESyQcfwGtJE\n" + "jcRrGEj36X6eahyY4AF+4Mlz2vWFeW52ayGXpQKn/z4tChdN80txdY77YmEX7XE0\n" + "HHZYY6toNq/+mNX9h2HvB0GW+8+E0YfNN/HloTxDo3RT8+IovY9OSXt44vY4YtQK\n" + "JbvZIm2Q8Iuv3vfNR05uFa4HcNqFhELh10jss0xG/54Y2NvB6xdKOZ8LRQuIX+Fu\n" + "QRzMiqRFQPUJzWxbKF5I/MFiKWmAG0QNPDnlb8XtPmFTFCWY9X96wOpQOczrxT2+\n" + "+vnTxPA3aTAkz7M4yUuocZQqTlbdfdGOSAENXavewdMCyy5bQsSLAgMBAAGjgZIw\n" + "gY8wHQYDVR0OBBYEFLdUGYfJRf9mbM/fTav9U2vFI+TRMFMGA1UdIwRMMEqAFLdU\n" + "GYfJRf9mbM/fTav9U2vFI+TRoRykGjAYMRYwFAYDVQQDDA1NaXJlbyBSb290IENB\n" + "ghQDNXn0SFkDkxeW4c2pGL1wE/TH2zAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB\n" + "BjANBgkqhkiG9w0BAQsFAAOCAQEAHm5d4YUP8BYcks10UCdswLtxbMUN99fNbnYo\n" + "RMxx4EapwhEZFSNbIZvf1INJd5Po+hH5jteBeFVP+4zKqrhg3I8pjdC4josHmrhS\n" + "28OjOFWp6xNJC43BHnLpc84bH0+XIEBbk7YA6H3GjpsZ7aJkhj/JPjjNq7bmyYN7\n" + "1I9RK4PtIrNtUFbSsHZCZhf8Amtl8PrpktITECjfqCq+8uOAqP4McTIQ1JKwYy6f\n" + "O6iu0eybJCFhWYENTUQyPi1VtEwOpWNLzaXBYdj69Xg8wA/J9RZIoqXWvtHv4rPF\n" + "HGudMEIVB3y2vVLmujvQCqYPZWwbgpy5mN3F4uBNuZhTIwWRFg==\n" "-----END CERTIFICATE-----\n" ; @@ -66,14 +61,14 @@ void publish_qos0_openssl_tls() { asio::ssl::context tls_context(asio::ssl::context::tls_client); error_code ec; - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-qos0-openssl-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8883) + .brokers("emqtt.mireo.local", 8883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -99,14 +94,14 @@ void publish_qos1_openssl_tls() { asio::ssl::context tls_context(asio::ssl::context::tls_client); error_code ec; - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-qos1-openssl-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8883) + .brokers("emqtt.mireo.local", 8883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -134,14 +129,14 @@ void publish_qos2_openssl_tls() { asio::ssl::context tls_context(asio::ssl::context::tls_client); error_code ec; - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-qos2-openssl-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8883) + .brokers("emqtt.mireo.local", 8883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -169,14 +164,14 @@ void subscribe_and_receive_openssl_tls(int num_receive) { asio::ssl::context tls_context(asio::ssl::context::tls_client); error_code ec; - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-subscriber-openssl-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8883) + .brokers("emqtt.mireo.local", 8883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -225,61 +220,9 @@ void subscribe_and_receive_openssl_tls(int num_receive) { return; } -void test_coro() { - std::cout << "[Test-coro-openssl-tls]" << std::endl; - using namespace async_mqtt5; - asio::io_context ioc; - - co_spawn(ioc, [&ioc]() -> asio::awaitable { - using stream_type = asio::ssl::stream; - asio::ssl::context tls_context(asio::ssl::context::tls_client); - - error_code ec; - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); - tls_context.set_verify_mode(asio::ssl::verify_peer); - - using client_type = mqtt_client; - client_type c(ioc, "", std::move(tls_context)); - - c.credentials("coro-client", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8883) - .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) - .run(); - - std::vector topics; - topics.push_back(subscribe_topic { - "test/mqtt-test", { - qos_e::exactly_once, - subscribe_options::no_local_e::no, - subscribe_options::retain_as_published_e::retain, - subscribe_options::retain_handling_e::send - } - }); - - auto [ec1, codes, props] = co_await c.async_subscribe( - topics, subscribe_props {}, use_nothrow_awaitable - ); - std::cout << "subscribe reason_code: " << codes[0].message() << std::endl; - - auto [ec2, topic, payload, rec_props] = co_await c.async_receive(use_nothrow_awaitable); - std::cout << "topic: " << topic << std::endl; - std::cout << "payload: " << payload << std::endl; - - asio::steady_timer timer(ioc); - timer.expires_from_now(std::chrono::seconds(1)); - co_await timer.async_wait(use_nothrow_awaitable); - co_await c.async_disconnect(use_nothrow_awaitable); - - co_return; - }, asio::detached); - - ioc.run(); -} - void run_openssl_tls_examples() { publish_qos0_openssl_tls(); publish_qos1_openssl_tls(); publish_qos2_openssl_tls(); subscribe_and_receive_openssl_tls(1); - test_coro(); } diff --git a/example/publisher.cpp b/example/publisher.cpp index 83374b8..fbd626a 100644 --- a/example/publisher.cpp +++ b/example/publisher.cpp @@ -20,7 +20,7 @@ asio::awaitable client_publisher(asio::io_context& ioc) { // Configure the ``__Client__``. // It is mandatory to call brokers() and run() to configure the Brokers to connect to and start the Client. - client.brokers("mqtt.mireo.local", 1883) // Broker that we want to connect to. 1883 is the default TCP port. + client.brokers("mqtt.broker", 1883) // Broker that we want to connect to. 1883 is the default TCP port. .run(); // Start the client. // Publish an Application Message with QoS 1. diff --git a/example/tcp.cpp b/example/tcp.cpp index 9fbc64a..8dff1d4 100644 --- a/example/tcp.cpp +++ b/example/tcp.cpp @@ -18,7 +18,7 @@ void publish_qos0_tcp() { client_type c(ioc, ""); c.credentials("test-qos0-tcp", "", "") - .brokers("mqtt.mireo.local", 1883) + .brokers("emqtt.mireo.local", 1883) .will({ "test/mqtt-test", "Client disconnected!",qos_e::at_least_once }) .run(); @@ -31,6 +31,7 @@ void publish_qos0_tcp() { } ); + ioc.run(); } @@ -45,7 +46,7 @@ void publish_qos1_tcp() { client_type c(ioc, ""); c.credentials("test-qos1-tcp", "", "") - .brokers("mqtt.mireo.local", 1883) + .brokers("emqtt.mireo.local", 1883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -72,7 +73,7 @@ void publish_qos2_tcp() { client_type c(ioc, ""); c.credentials("test-qos2-tcp", "", "") - .brokers("mqtt.mireo.local", 1883) + .brokers("emqtt.mireo.local", 1883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -100,7 +101,7 @@ void subscribe_and_receive_tcp(int num_receive) { client_type c(ioc, ""); c.credentials("test-subscriber-tcp", "", "") - .brokers("mqtt.mireo.local", 1883) + .brokers("emqtt.mireo.local", 1883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); diff --git a/example/websocket-tcp.cpp b/example/websocket_tcp.cpp similarity index 95% rename from example/websocket-tcp.cpp rename to example/websocket_tcp.cpp index 8007e23..f7b41ce 100644 --- a/example/websocket-tcp.cpp +++ b/example/websocket_tcp.cpp @@ -23,12 +23,12 @@ void publish_qos0_websocket_tcp() { client_type c(ioc, ""); c.credentials("test-qos0-websocket-tcp", "", "") - .brokers("fcluster-5/mqtt", 8083) + .brokers("emqtt.mireo.local/mqtt", 8083) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); c.async_publish( - "test/mqtt-test", "hello world with qos0!", + "test/mqtt-test", "hello world with qos0!", retain_e::no, publish_props{}, [&c](error_code ec) { std::cout << "error_code: " << ec.message() << std::endl; @@ -53,7 +53,7 @@ void publish_qos1_websocket_tcp() { client_type c(ioc, ""); c.credentials("test-qos1-websocket-tcp", "", "") - .brokers("fcluster-5/mqtt", 8083) + .brokers("emqtt.mireo.local/mqtt", 8083) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -84,7 +84,7 @@ void publish_qos2_websocket_tcp() { client_type c(ioc, ""); c.credentials("test-qos2-websocket-tcp", "", "") - .brokers("fcluster-5/mqtt", 8083) + .brokers("emqtt.mireo.local/mqtt", 8083) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -116,7 +116,7 @@ void subscribe_and_receive_websocket_tcp(int num_receive) { client_type c(ioc, ""); c.credentials("test-subscriber-websocket-tcp", "", "") - .brokers("fcluster-5/mqtt", 8083) + .brokers("emqtt.mireo.local/mqtt", 8083) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); diff --git a/example/websocket-tls.cpp b/example/websocket_tls.cpp similarity index 77% rename from example/websocket-tls.cpp rename to example/websocket_tls.cpp index 1dda51f..335ad84 100644 --- a/example/websocket-tls.cpp +++ b/example/websocket_tls.cpp @@ -42,28 +42,26 @@ void assign_tls_sni( } } // end namespace async_mqtt5 - -constexpr const char spacetime_ca[] = +constexpr char mireo_ca[] = "-----BEGIN CERTIFICATE-----\n" - "MIIDYDCCAkigAwIBAgIUZZsEKT8m+uGZRNMaTuCiZBchSU4wDQYJKoZIhvcNAQEL\n" - "BQAwHTEbMBkGA1UEAwwSTWlyZW8gU3BhY2VUaW1lIENBMB4XDTIzMDIwNzIwMzU1\n" - "MFoXDTMzMDIwNDIwMzU1MFowHTEbMBkGA1UEAwwSTWlyZW8gU3BhY2VUaW1lIENB\n" - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzZshi2nJNyYZ4aJN+q27\n" - "wA69lUAwRSHiJGBCGzppLue/LFDDC1t8GDicjYLGH5eJOlFwr8TbAr+ZH+/PyBoS\n" - "7g5tsSn5xZhgEaivnq1MJNqYWHqW5KF2KhGxzzyC6m3JFK21H0xiJu9ej2wQs1tD\n" - "ZWG3Y7pKeMFhCezEip5ueIyvmjsenK00TJKr6w1Rkr4BA40euLb5r0srWllKKUyl\n" - "t5AEFghdVU7GeXfC2LPrzzMVngFWTaoL3QRf7VMhvNC0Xq7h2yjwd4wROYiJFZBj\n" - "UgDSi2W50fPlVDliET2hPBR6lQPgCBRoIdQF8NneSBJ5xH+mw9ZZV8btL8ahwWtL\n" - "GwIDAQABo4GXMIGUMB0GA1UdDgQWBBSM9pLZlAekgqt7ZXzPOdTEifMLmzBYBgNV\n" - "HSMEUTBPgBSM9pLZlAekgqt7ZXzPOdTEifMLm6EhpB8wHTEbMBkGA1UEAwwSTWly\n" - "ZW8gU3BhY2VUaW1lIENBghRlmwQpPyb64ZlE0xpO4KJkFyFJTjAMBgNVHRMEBTAD\n" - "AQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAuSe6ZOwc8KnNXs1M\n" - "KoShOUxZGDFBUJFNAtTSsMi0ap6GIo/yJr+6SAkHkVU0HFkl5lzRo9aUHRw4O7Ez\n" - "579JMzUDdEGBxtYqda0Rxnw8N2mq5Fxpv+1b6v4GsWA30k6TdqnrFdNpFVI84W6u\n" - "Fw3HTKA0Ah0jXryc1kC1jU7mYKf66TDI5PSbuZRjHgQzzyUXZmCn1WcLbvunsc4r\n" - "Tk2FrfXHfvag12yPLc9aIOrtfRW2wtlZcxMzX4oE6wfllAIIsSZGx0muydiMe8bw\n" - "Od5S0p1sspsWOthj1t9yhHMwznwV81QLePWzgGmml21uA067ZGG8NHxNbERd/9e+\n" - "Qz9m6w==\n" + "MIIDUTCCAjmgAwIBAgIUAzV59EhZA5MXluHNqRi9cBP0x9swDQYJKoZIhvcNAQEL\n" + "BQAwGDEWMBQGA1UEAwwNTWlyZW8gUm9vdCBDQTAeFw0yMjA0MDcxMzM1MjlaFw0z\n" + "MjA0MDQxMzM1MjlaMBgxFjAUBgNVBAMMDU1pcmVvIFJvb3QgQ0EwggEiMA0GCSqG\n" + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCin/qsHpdxT3iW0SEHhAcTfESyQcfwGtJE\n" + "jcRrGEj36X6eahyY4AF+4Mlz2vWFeW52ayGXpQKn/z4tChdN80txdY77YmEX7XE0\n" + "HHZYY6toNq/+mNX9h2HvB0GW+8+E0YfNN/HloTxDo3RT8+IovY9OSXt44vY4YtQK\n" + "JbvZIm2Q8Iuv3vfNR05uFa4HcNqFhELh10jss0xG/54Y2NvB6xdKOZ8LRQuIX+Fu\n" + "QRzMiqRFQPUJzWxbKF5I/MFiKWmAG0QNPDnlb8XtPmFTFCWY9X96wOpQOczrxT2+\n" + "+vnTxPA3aTAkz7M4yUuocZQqTlbdfdGOSAENXavewdMCyy5bQsSLAgMBAAGjgZIw\n" + "gY8wHQYDVR0OBBYEFLdUGYfJRf9mbM/fTav9U2vFI+TRMFMGA1UdIwRMMEqAFLdU\n" + "GYfJRf9mbM/fTav9U2vFI+TRoRykGjAYMRYwFAYDVQQDDA1NaXJlbyBSb290IENB\n" + "ghQDNXn0SFkDkxeW4c2pGL1wE/TH2zAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB\n" + "BjANBgkqhkiG9w0BAQsFAAOCAQEAHm5d4YUP8BYcks10UCdswLtxbMUN99fNbnYo\n" + "RMxx4EapwhEZFSNbIZvf1INJd5Po+hH5jteBeFVP+4zKqrhg3I8pjdC4josHmrhS\n" + "28OjOFWp6xNJC43BHnLpc84bH0+XIEBbk7YA6H3GjpsZ7aJkhj/JPjjNq7bmyYN7\n" + "1I9RK4PtIrNtUFbSsHZCZhf8Amtl8PrpktITECjfqCq+8uOAqP4McTIQ1JKwYy6f\n" + "O6iu0eybJCFhWYENTUQyPi1VtEwOpWNLzaXBYdj69Xg8wA/J9RZIoqXWvtHv4rPF\n" + "HGudMEIVB3y2vVLmujvQCqYPZWwbgpy5mN3F4uBNuZhTIwWRFg==\n" "-----END CERTIFICATE-----\n" ; @@ -78,14 +76,14 @@ void publish_qos0_websocket_tls() { error_code ec; asio::ssl::context tls_context(asio::ssl::context::tls_client); - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-qos0-websocket-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8884) + .brokers("emqtt.mireo.local/mqtt", 8884) .will({ "test/mqtt-test", "Client disconnected!", async_mqtt5::qos_e::at_least_once }) .run(); @@ -113,14 +111,14 @@ void publish_qos1_websocket_tls() { error_code ec; asio::ssl::context tls_context(asio::ssl::context::tls_client); - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-qos1-websocket-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8884) + .brokers("emqtt.mireo.local/mqtt", 8884) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -149,14 +147,14 @@ void publish_qos2_websocket_tls() { error_code ec; asio::ssl::context tls_context(asio::ssl::context::tls_client); - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-qos2-websocket-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8884) + .brokers("emqtt.mireo.local/mqtt", 8884) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); @@ -186,14 +184,14 @@ void subscribe_and_receive_websocket_tls(int num_receive) { error_code ec; asio::ssl::context tls_context(asio::ssl::context::tls_client); - tls_context.add_certificate_authority(asio::buffer(spacetime_ca), ec); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); tls_context.set_verify_mode(asio::ssl::verify_peer); using client_type = mqtt_client; client_type c(ioc, "", std::move(tls_context)); c.credentials("test-subscriber-websocket-tls", "", "") - .brokers("iot.fcluster.mireo.hr/mqtt", 8884) + .brokers("emqtt.mireo.local/mqtt", 8884) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); diff --git a/include/async_mqtt5/impl/codecs/base_decoders.hpp b/include/async_mqtt5/impl/codecs/base_decoders.hpp index 9ed0f76..f55f36d 100644 --- a/include/async_mqtt5/impl/codecs/base_decoders.hpp +++ b/include/async_mqtt5/impl/codecs/base_decoders.hpp @@ -216,7 +216,7 @@ struct varint_parser : x3::parser { template bool parse( It& first, const It last, - const Ctx& ctx, RCtx& rctx, Attr& attr + const Ctx& ctx, RCtx&, Attr& attr ) const { It iter = first; diff --git a/include/async_mqtt5/impl/connect_op.hpp b/include/async_mqtt5/impl/connect_op.hpp index b79c5cf..224d705 100644 --- a/include/async_mqtt5/impl/connect_op.hpp +++ b/include/async_mqtt5/impl/connect_op.hpp @@ -10,7 +10,9 @@ #include #include -#include +#include +#include +#include #include @@ -133,7 +135,7 @@ public: do_ws_handshake(std::move(ep), std::move(ap)); } - void do_ws_handshake(endpoint ep, authority_path ap) { + void do_ws_handshake(endpoint, authority_path ap) { if constexpr (has_ws_handshake) { using namespace boost::beast; diff --git a/include/async_mqtt5/impl/read_op.hpp b/include/async_mqtt5/impl/read_op.hpp index 255b282..6ee4594 100644 --- a/include/async_mqtt5/impl/read_op.hpp +++ b/include/async_mqtt5/impl/read_op.hpp @@ -71,7 +71,7 @@ public: void operator()( on_read, typename Owner::stream_ptr stream_ptr, std::array ord, error_code read_ec, size_t bytes_read, - error_code timer_ec + error_code ) { if (!_owner.is_open()) return complete(asio::error::operation_aborted, bytes_read); diff --git a/test/unit/include/test_common/delayed_op.hpp b/test/unit/include/test_common/delayed_op.hpp index cbe46e5..65e18d7 100644 --- a/test/unit/include/test_common/delayed_op.hpp +++ b/test/unit/include/test_common/delayed_op.hpp @@ -11,6 +11,7 @@ #include #include +#include namespace async_mqtt5::test { @@ -88,7 +89,7 @@ decltype(auto) async_delay( delayed_op&& op, CompletionToken&& token ) { - using Signature = void (error_code, std::remove_cvref_t...); + using Signature = void (error_code, boost::remove_cv_ref_t...); auto initiation = []( auto handler, asio::cancellation_slot cancel_slot, diff --git a/test/unit/include/test_common/message_exchange.hpp b/test/unit/include/test_common/message_exchange.hpp index 375bdf2..6ad68d4 100644 --- a/test/unit/include/test_common/message_exchange.hpp +++ b/test/unit/include/test_common/message_exchange.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include "test_common/delayed_op.hpp" namespace async_mqtt5::test { @@ -49,7 +51,6 @@ public: } }; - } // end namespace detail @@ -81,15 +82,7 @@ public: template client_message& reply_with(Args&& ...args) { // just to allow duration to be the last parameter - auto t = std::make_tuple(std::forward(args)...); - using Tuple = decltype(t); - - return[&](std::index_sequence) -> client_message& { - return reply_with_impl( - std::get -1>(t), - std::get(t)... - ); - }(std::make_index_sequence -1>{}); + return reply_with_dur(std::make_tuple(std::forward(args)...)); } template @@ -116,8 +109,25 @@ public: private: - template - requires (std::is_same_v, std::string> && ...) + template + client_message& reply_with_dur(const Tuple& t) { + constexpr auto indices = std::make_index_sequence< + std::tuple_size_v - 1 + > {}; + + return reply_with_impl( + std::get - 1>(t), + std::get(t)... + ); + } + + template < + typename ...Args, + std::enable_if_t< + (std::is_same_v, std::string> && ...), + bool + > = true + > client_message& reply_with_impl(duration af, Args&& ...args) { _replies.emplace_back( error_code {}, af, std::forward(args)... @@ -164,8 +174,13 @@ class msg_exchange { std::vector _from_broker; public: - template - requires (std::is_same_v, std::string> && ...) + template < + typename ...Args, + std::enable_if_t< + (std::is_same_v, std::string> && ...), + bool + > = true + > client_message& expect(Args&& ...args) { _to_broker.emplace_back(this, std::forward(args)...); return _to_broker.back(); @@ -174,15 +189,7 @@ public: template broker_message& send(Args&& ...args) { // just to allow duration to be the last parameter - auto t = std::make_tuple(std::forward(args)...); - using Tuple = decltype(t); - - return[&](std::index_sequence) -> broker_message& { - return send_impl( - std::get -1>(t), - std::get(t)... - ); - }(std::make_index_sequence -1>{}); + return send_with_dur(std::make_tuple(std::forward(args)...)); } std::optional pop_reply_action() { @@ -207,8 +214,25 @@ public: private: - template - requires (std::is_same_v, std::string> && ...) + template + broker_message& send_with_dur(const Tuple& t) { + constexpr auto indices = std::make_index_sequence< + std::tuple_size_v - 1 + > {}; + + return send_impl( + std::get - 1>(t), + std::get(t)... + ); + } + + template < + typename ...Args, + std::enable_if_t< + (std::is_same_v, std::string> && ...), + bool + > = true + > broker_message& send_impl(duration after, Args&& ...args) { _from_broker.emplace_back( this, error_code {}, after, std::forward(args)... diff --git a/test/unit/include/test_common/test_stream.hpp b/test/unit/include/test_common/test_stream.hpp index 83effef..55dd3da 100644 --- a/test/unit/include/test_common/test_stream.hpp +++ b/test/unit/include/test_common/test_stream.hpp @@ -288,7 +288,7 @@ public: asio::post(get_executor(), asio::prepend(std::move(handler), ec)); }; - return async_initiate( + return asio::async_initiate( std::move(initiation), token, ep ); } diff --git a/test/unit/test/coroutine.cpp b/test/unit/test/coroutine.cpp index fa76ccd..1d560ef 100644 --- a/test/unit/test/coroutine.cpp +++ b/test/unit/test/coroutine.cpp @@ -8,11 +8,68 @@ #include #include #include +#include #include #include +namespace boost::beast::websocket { + +template +void async_teardown( + boost::beast::role_type role, + asio::ssl::stream& stream, + TeardownHandler&& handler +) { + return stream.async_shutdown(std::forward(handler)); +} + +} // end namespace boost::beast::websocket + +constexpr char mireo_ca[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIDUTCCAjmgAwIBAgIUAzV59EhZA5MXluHNqRi9cBP0x9swDQYJKoZIhvcNAQEL\n" + "BQAwGDEWMBQGA1UEAwwNTWlyZW8gUm9vdCBDQTAeFw0yMjA0MDcxMzM1MjlaFw0z\n" + "MjA0MDQxMzM1MjlaMBgxFjAUBgNVBAMMDU1pcmVvIFJvb3QgQ0EwggEiMA0GCSqG\n" + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCin/qsHpdxT3iW0SEHhAcTfESyQcfwGtJE\n" + "jcRrGEj36X6eahyY4AF+4Mlz2vWFeW52ayGXpQKn/z4tChdN80txdY77YmEX7XE0\n" + "HHZYY6toNq/+mNX9h2HvB0GW+8+E0YfNN/HloTxDo3RT8+IovY9OSXt44vY4YtQK\n" + "JbvZIm2Q8Iuv3vfNR05uFa4HcNqFhELh10jss0xG/54Y2NvB6xdKOZ8LRQuIX+Fu\n" + "QRzMiqRFQPUJzWxbKF5I/MFiKWmAG0QNPDnlb8XtPmFTFCWY9X96wOpQOczrxT2+\n" + "+vnTxPA3aTAkz7M4yUuocZQqTlbdfdGOSAENXavewdMCyy5bQsSLAgMBAAGjgZIw\n" + "gY8wHQYDVR0OBBYEFLdUGYfJRf9mbM/fTav9U2vFI+TRMFMGA1UdIwRMMEqAFLdU\n" + "GYfJRf9mbM/fTav9U2vFI+TRoRykGjAYMRYwFAYDVQQDDA1NaXJlbyBSb290IENB\n" + "ghQDNXn0SFkDkxeW4c2pGL1wE/TH2zAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB\n" + "BjANBgkqhkiG9w0BAQsFAAOCAQEAHm5d4YUP8BYcks10UCdswLtxbMUN99fNbnYo\n" + "RMxx4EapwhEZFSNbIZvf1INJd5Po+hH5jteBeFVP+4zKqrhg3I8pjdC4josHmrhS\n" + "28OjOFWp6xNJC43BHnLpc84bH0+XIEBbk7YA6H3GjpsZ7aJkhj/JPjjNq7bmyYN7\n" + "1I9RK4PtIrNtUFbSsHZCZhf8Amtl8PrpktITECjfqCq+8uOAqP4McTIQ1JKwYy6f\n" + "O6iu0eybJCFhWYENTUQyPi1VtEwOpWNLzaXBYdj69Xg8wA/J9RZIoqXWvtHv4rPF\n" + "HGudMEIVB3y2vVLmujvQCqYPZWwbgpy5mN3F4uBNuZhTIwWRFg==\n" + "-----END CERTIFICATE-----\n" +; + + +namespace async_mqtt5 { + +template +struct tls_handshake_type> { + static constexpr auto client = asio::ssl::stream_base::client; + static constexpr auto server = asio::ssl::stream_base::server; +}; + +template +void assign_tls_sni( + const authority_path& ap, + asio::ssl::context& ctx, + asio::ssl::stream& stream +) { + SSL_set_tlsext_host_name(stream.native_handle(), ap.host.c_str()); +} + +} // end namespace async_mqtt5 + BOOST_AUTO_TEST_SUITE(coroutine/*, *boost::unit_test::disabled()*/) using namespace async_mqtt5; @@ -81,12 +138,12 @@ BOOST_AUTO_TEST_CASE(tcp_client_check) { client_type c(ioc, ""); c.credentials("tcp-tester", "", "") - .brokers("mqtt.mireo.local", 1883) + .brokers("emqtt.mireo.local", 1883) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); asio::steady_timer timer(ioc); - timer.expires_after(std::chrono::seconds(10)); + timer.expires_after(std::chrono::seconds(5)); timer.async_wait( [&](boost::system::error_code ec) { @@ -107,8 +164,6 @@ BOOST_AUTO_TEST_CASE(tcp_client_check) { ioc.run(); } -// TODO: SSL - BOOST_AUTO_TEST_CASE(websocket_tcp_client_check) { asio::io_context ioc; @@ -120,12 +175,95 @@ BOOST_AUTO_TEST_CASE(websocket_tcp_client_check) { client_type c(ioc, ""); c.credentials("websocket-tcp-tester", "", "") - .brokers("fcluster-5/mqtt", 8083) + .brokers("emqtt.mireo.local/mqtt", 8083) .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .run(); asio::steady_timer timer(ioc); - timer.expires_after(std::chrono::seconds(10)); + timer.expires_after(std::chrono::seconds(5)); + + timer.async_wait( + [&](boost::system::error_code ec) { + BOOST_CHECK_MESSAGE(ec, "Failed to receive all the expected replies!"); + c.cancel(); + ioc.stop(); + } + ); + + co_spawn(ioc, + [&]() -> asio::awaitable { + co_await sanity_check(c); + timer.cancel(); + }, + asio::detached + ); + + ioc.run(); +} + + +BOOST_AUTO_TEST_CASE(openssl_tls_client_check) { + asio::io_context ioc; + + using stream_type = asio::ssl::stream; + asio::ssl::context tls_context(asio::ssl::context::tls_client); + + error_code ec; + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); + tls_context.set_verify_mode(asio::ssl::verify_peer); + + using client_type = mqtt_client; + client_type c(ioc, "", std::move(tls_context)); + + c.credentials("openssl-tls-tester", "", "") + .brokers("emqtt.mireo.local", 8883) + .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) + .run(); + + asio::steady_timer timer(ioc); + timer.expires_after(std::chrono::seconds(5)); + + timer.async_wait( + [&](boost::system::error_code ec) { + BOOST_CHECK_MESSAGE(ec, "Failed to receive all the expected replies!"); + c.cancel(); + ioc.stop(); + } + ); + + co_spawn(ioc, + [&]() -> asio::awaitable { + co_await sanity_check(c); + timer.cancel(); + }, + asio::detached + ); + + ioc.run(); +} + +BOOST_AUTO_TEST_CASE(websocket_tls_client_check) { + asio::io_context ioc; + + using stream_type = boost::beast::websocket::stream< + asio::ssl::stream + >; + + error_code ec; + asio::ssl::context tls_context(asio::ssl::context::tls_client); + tls_context.add_certificate_authority(asio::buffer(mireo_ca), ec); + tls_context.set_verify_mode(asio::ssl::verify_peer); + + using client_type = mqtt_client; + client_type c(ioc, "", std::move(tls_context)); + + c.credentials("websocket-tls-tester", "", "") + .brokers("emqtt.mireo.local/mqtt", 8884) + .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) + .run(); + + asio::steady_timer timer(ioc); + timer.expires_after(std::chrono::seconds(5)); timer.async_wait( [&](boost::system::error_code ec) { @@ -148,5 +286,4 @@ BOOST_AUTO_TEST_CASE(websocket_tcp_client_check) { BOOST_AUTO_TEST_SUITE_END() - #endif