Update examples, tests & docs

Summary: related to T13242

Reviewers: ivica

Reviewed By: ivica

Subscribers: miljen, iljazovic

Differential Revision: https://repo.mireo.local/D26889
This commit is contained in:
Korina Šimičević
2023-12-07 15:41:31 +01:00
parent e0a0bafbf1
commit 0d778c6b59
15 changed files with 274 additions and 168 deletions

View File

@ -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 <source-cpp-file> -o example -I<path-to-boost> -Iinclude -pthread
$ clang++ -std=c++17 <source-cpp-file> -o example -I<path-to-boost> -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).

View File

@ -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].

View File

@ -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)

View File

@ -1,10 +1,7 @@
#include <iostream>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/as_tuple.hpp>
#include <boost/asio/ip/tcp.hpp>
@ -14,7 +11,6 @@ namespace asio = boost::asio;
namespace async_mqtt5 {
constexpr auto use_nothrow_awaitable = asio::as_tuple(asio::use_awaitable);
template <typename StreamBase>
struct tls_handshake_type<asio::ssl::stream<StreamBase>> {
@ -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<stream_type, decltype(tls_context)>;
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<stream_type, decltype(tls_context)>;
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<stream_type, decltype(tls_context)>;
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<stream_type, decltype(tls_context)>;
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<void> {
using stream_type = asio::ssl::stream<asio::ip::tcp::socket>;
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<stream_type, decltype(tls_context)>;
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<subscribe_topic> 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();
}

View File

@ -20,7 +20,7 @@ asio::awaitable<void> 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.

View File

@ -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();

View File

@ -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<qos_e::at_most_once>(
"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();

View File

@ -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<stream_type, decltype(tls_context)>;
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<stream_type, decltype(tls_context)>;
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<stream_type, decltype(tls_context)>;
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<stream_type, decltype(tls_context)>;
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();

View File

@ -216,7 +216,7 @@ struct varint_parser : x3::parser<varint_parser> {
template <typename It, typename Ctx, typename RCtx, typename Attr>
bool parse(
It& first, const It last,
const Ctx& ctx, RCtx& rctx, Attr& attr
const Ctx& ctx, RCtx&, Attr& attr
) const {
It iter = first;

View File

@ -10,7 +10,9 @@
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/any_completion_handler.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/http/field.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/beast/websocket/stream_base.hpp>
#include <async_mqtt5/error.hpp>
@ -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<Stream>) {
using namespace boost::beast;

View File

@ -71,7 +71,7 @@ public:
void operator()(
on_read, typename Owner::stream_ptr stream_ptr,
std::array<std::size_t, 2> 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);

View File

@ -11,6 +11,7 @@
#include <boost/asio/recycling_allocator.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/type_traits/remove_cv_ref.hpp>
namespace async_mqtt5::test {
@ -88,7 +89,7 @@ decltype(auto) async_delay(
delayed_op<BoundArgs...>&& op,
CompletionToken&& token
) {
using Signature = void (error_code, std::remove_cvref_t<BoundArgs>...);
using Signature = void (error_code, boost::remove_cv_ref_t<BoundArgs>...);
auto initiation = [](
auto handler, asio::cancellation_slot cancel_slot,

View File

@ -7,6 +7,8 @@
#include <string>
#include <vector>
#include <boost/type_traits/remove_cv_ref.hpp>
#include "test_common/delayed_op.hpp"
namespace async_mqtt5::test {
@ -49,7 +51,6 @@ public:
}
};
} // end namespace detail
@ -81,15 +82,7 @@ public:
template <typename ...Args>
client_message& reply_with(Args&& ...args) {
// just to allow duration to be the last parameter
auto t = std::make_tuple(std::forward<Args>(args)...);
using Tuple = decltype(t);
return[&]<auto... I>(std::index_sequence<I...>) -> client_message& {
return reply_with_impl(
std::get<std::tuple_size_v<Tuple> -1>(t),
std::get<I>(t)...
);
}(std::make_index_sequence<std::tuple_size_v<Tuple> -1>{});
return reply_with_dur(std::make_tuple(std::forward<Args>(args)...));
}
template <typename ...Args>
@ -116,8 +109,25 @@ public:
private:
template <typename ...Args>
requires (std::is_same_v<std::remove_cvref_t<Args>, std::string> && ...)
template<typename Tuple, size_t ...I>
client_message& reply_with_dur(const Tuple& t) {
constexpr auto indices = std::make_index_sequence<
std::tuple_size_v<Tuple> - 1
> {};
return reply_with_impl(
std::get<std::tuple_size_v<Tuple> - 1>(t),
std::get<I>(t)...
);
}
template <
typename ...Args,
std::enable_if_t<
(std::is_same_v<boost::remove_cv_ref_t<Args>, std::string> && ...),
bool
> = true
>
client_message& reply_with_impl(duration af, Args&& ...args) {
_replies.emplace_back(
error_code {}, af, std::forward<Args>(args)...
@ -164,8 +174,13 @@ class msg_exchange {
std::vector<broker_message> _from_broker;
public:
template <typename ...Args>
requires (std::is_same_v<std::remove_cvref_t<Args>, std::string> && ...)
template <
typename ...Args,
std::enable_if_t<
(std::is_same_v<boost::remove_cv_ref_t<Args>, std::string> && ...),
bool
> = true
>
client_message& expect(Args&& ...args) {
_to_broker.emplace_back(this, std::forward<Args>(args)...);
return _to_broker.back();
@ -174,15 +189,7 @@ public:
template <typename ...Args>
broker_message& send(Args&& ...args) {
// just to allow duration to be the last parameter
auto t = std::make_tuple(std::forward<Args>(args)...);
using Tuple = decltype(t);
return[&]<auto... I>(std::index_sequence<I...>) -> broker_message& {
return send_impl(
std::get<std::tuple_size_v<Tuple> -1>(t),
std::get<I>(t)...
);
}(std::make_index_sequence<std::tuple_size_v<Tuple> -1>{});
return send_with_dur(std::make_tuple(std::forward<Args>(args)...));
}
std::optional<client_message> pop_reply_action() {
@ -207,8 +214,25 @@ public:
private:
template <typename ...Args>
requires (std::is_same_v<std::remove_cvref_t<Args>, std::string> && ...)
template<typename Tuple, size_t ...I>
broker_message& send_with_dur(const Tuple& t) {
constexpr auto indices = std::make_index_sequence<
std::tuple_size_v<Tuple> - 1
> {};
return send_impl(
std::get<std::tuple_size_v<Tuple> - 1>(t),
std::get<I>(t)...
);
}
template <
typename ...Args,
std::enable_if_t<
(std::is_same_v<boost::remove_cv_ref_t<Args>, std::string> && ...),
bool
> = true
>
broker_message& send_impl(duration after, Args&& ...args) {
_from_broker.emplace_back(
this, error_code {}, after, std::forward<Args>(args)...

View File

@ -288,7 +288,7 @@ public:
asio::post(get_executor(), asio::prepend(std::move(handler), ec));
};
return async_initiate<ConnectToken, void (error_code)>(
return asio::async_initiate<ConnectToken, void (error_code)>(
std::move(initiation), token, ep
);
}

View File

@ -8,11 +8,68 @@
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <async_mqtt5.hpp>
namespace boost::beast::websocket {
template <typename TeardownHandler>
void async_teardown(
boost::beast::role_type role,
asio::ssl::stream<asio::ip::tcp::socket>& stream,
TeardownHandler&& handler
) {
return stream.async_shutdown(std::forward<TeardownHandler>(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 <typename StreamBase>
struct tls_handshake_type<asio::ssl::stream<StreamBase>> {
static constexpr auto client = asio::ssl::stream_base::client;
static constexpr auto server = asio::ssl::stream_base::server;
};
template <typename StreamBase>
void assign_tls_sni(
const authority_path& ap,
asio::ssl::context& ctx,
asio::ssl::stream<StreamBase>& 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<void> {
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::ip::tcp::socket>;
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<stream_type, decltype(tls_context)>;
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<void> {
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<asio::ip::tcp::socket>
>;
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<stream_type, decltype(tls_context)>;
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