diff --git a/include/async_mqtt5/impl/assemble_op.hpp b/include/async_mqtt5/impl/assemble_op.hpp index 018a7c8..5c96930 100644 --- a/include/async_mqtt5/impl/assemble_op.hpp +++ b/include/async_mqtt5/impl/assemble_op.hpp @@ -89,7 +89,7 @@ public: _read_buff.cbegin(), _data_span.first() ); _read_buff.resize( - _svc.connect_prop(prop::maximum_packet_size).value_or(max_recv_size) + _svc.connect_property(prop::maximum_packet_size).value_or(max_recv_size) ); _data_span = { _read_buff.cbegin(), @@ -157,7 +157,7 @@ public: } auto recv_size = static_cast( - _svc.connect_prop(prop::maximum_packet_size).value_or(max_recv_size) + _svc.connect_property(prop::maximum_packet_size).value_or(max_recv_size) ); if (*varlen > recv_size - std::distance(_data_span.first(), first)) return complete(client::error::malformed_packet, 0, {}, {}); diff --git a/include/async_mqtt5/impl/async_sender.hpp b/include/async_mqtt5/impl/async_sender.hpp index c222e4d..3ffe913 100644 --- a/include/async_mqtt5/impl/async_sender.hpp +++ b/include/async_mqtt5/impl/async_sender.hpp @@ -147,7 +147,7 @@ public: // all the packets that require resending. _write_in_progress = true; - auto new_limit = _svc._stream_context.connack_prop(prop::receive_maximum); + auto new_limit = _svc._stream_context.connack_property(prop::receive_maximum); _limit = new_limit.value_or(MAX_LIMIT); _quota = _limit; diff --git a/include/async_mqtt5/impl/client_service.hpp b/include/async_mqtt5/impl/client_service.hpp index ed1121e..df3f811 100644 --- a/include/async_mqtt5/impl/client_service.hpp +++ b/include/async_mqtt5/impl/client_service.hpp @@ -62,20 +62,25 @@ public: } template - const auto& connack_prop(Prop p) const { + const auto& connack_property(Prop p) const { return _mqtt_context.ca_props[p]; } - const auto& connack_props() const { + const auto& connack_properties() const { return _mqtt_context.ca_props; } template - const auto& connect_prop(Prop p) const { + const auto& connect_property(Prop p) const { return _mqtt_context.co_props[p]; } - void connect_props(connect_props props) { + template + auto& connect_property(Prop p) { + return _mqtt_context.co_props[p]; + } + + void connect_propertiess(connect_props props) { _mqtt_context.co_props = std::move(props); } @@ -123,20 +128,25 @@ public: } template - const auto& connack_prop(Prop p) const { + const auto& connack_property(Prop p) const { return _mqtt_context.ca_props[p]; } - const auto& connack_props() const { + const auto& connack_properties() const { return _mqtt_context.ca_props; } template - const auto& connect_prop(Prop p) const { + const auto& connect_property(Prop p) const { return _mqtt_context.co_props[p]; } - void connect_props(connect_props props) { + template + auto& connect_property(Prop p) { + return _mqtt_context.co_props[p]; + } + + void connect_properties(connect_props props) { _mqtt_context.co_props = std::move(props); } @@ -267,22 +277,27 @@ public: } template - const auto& connect_prop(Prop p) const { - return _stream_context.connect_prop(p); - } - - void connect_props(connect_props props) { - if (!is_open()) - _stream_context.connect_props(std::move(props)); + const auto& connect_property(Prop p) const { + return _stream_context.connect_property(p); } template - const auto& connack_prop(Prop p) const { - return _stream_context.connack_prop(p); + auto& connect_property(Prop p) { + return _stream_context.connect_property(p); } - const auto& connack_props() const { - return _stream_context.connack_props(); + void connect_properties(connect_props props) { + if (!is_open()) + _stream_context.connect_properties(std::move(props)); + } + + template + const auto& connack_property(Prop p) const { + return _stream_context.connack_property(p); + } + + const auto& connack_properties() const { + return _stream_context.connack_properties(); } void run() { diff --git a/include/async_mqtt5/impl/disconnect_op.hpp b/include/async_mqtt5/impl/disconnect_op.hpp index 794f149..f15d673 100644 --- a/include/async_mqtt5/impl/disconnect_op.hpp +++ b/include/async_mqtt5/impl/disconnect_op.hpp @@ -72,7 +72,7 @@ public: ); auto max_packet_size = static_cast( - _svc_ptr->connack_prop(prop::maximum_packet_size) + _svc_ptr->connack_property(prop::maximum_packet_size) .value_or(default_max_send_size) ); if (disconnect.size() > max_packet_size) diff --git a/include/async_mqtt5/impl/publish_send_op.hpp b/include/async_mqtt5/impl/publish_send_op.hpp index 8b19c35..bb526bf 100644 --- a/include/async_mqtt5/impl/publish_send_op.hpp +++ b/include/async_mqtt5/impl/publish_send_op.hpp @@ -121,7 +121,7 @@ public: ); auto max_packet_size = static_cast( - _svc_ptr->connack_prop(prop::maximum_packet_size) + _svc_ptr->connack_property(prop::maximum_packet_size) .value_or(default_max_send_size) ); if (publish.size() > max_packet_size) @@ -355,9 +355,9 @@ private: if (validate_topic_name(topic) != validation_result::valid) return client::error::invalid_topic; - auto max_qos = _svc_ptr->connack_prop(prop::maximum_qos) + auto max_qos = _svc_ptr->connack_property(prop::maximum_qos) .value_or(default_maximum_qos); - auto retain_available = _svc_ptr->connack_prop(prop::retain_available) + auto retain_available = _svc_ptr->connack_property(prop::retain_available) .value_or(default_retain_available); if (uint8_t(qos_type) > max_qos) @@ -382,7 +382,7 @@ private: auto topic_alias = props[prop::topic_alias]; if (topic_alias) { - auto topic_alias_max = _svc_ptr->connack_prop(prop::topic_alias_maximum) + auto topic_alias_max = _svc_ptr->connack_property(prop::topic_alias_maximum) .value_or(default_topic_alias_max); if (topic_alias_max == 0 || *topic_alias > topic_alias_max) diff --git a/include/async_mqtt5/impl/subscribe_op.hpp b/include/async_mqtt5/impl/subscribe_op.hpp index 80dc884..3846a33 100644 --- a/include/async_mqtt5/impl/subscribe_op.hpp +++ b/include/async_mqtt5/impl/subscribe_op.hpp @@ -81,7 +81,7 @@ public: ); auto max_packet_size = static_cast( - _svc_ptr->connack_prop(prop::maximum_packet_size) + _svc_ptr->connack_property(prop::maximum_packet_size) .value_or(default_max_send_size) ); if (subscribe.size() > max_packet_size) @@ -169,10 +169,10 @@ private: } error_code validate_topic(const subscribe_topic& topic) const { - auto wildcard_available = _svc_ptr->connack_prop( + auto wildcard_available = _svc_ptr->connack_property( prop::wildcard_subscription_available ).value_or(1); - auto shared_available = _svc_ptr->connack_prop( + auto shared_available = _svc_ptr->connack_property( prop::shared_subscription_available ).value_or(1); @@ -208,7 +208,7 @@ private: if (!sub_id.has_value()) return error_code {}; - auto sub_id_available = _svc_ptr->connack_prop( + auto sub_id_available = _svc_ptr->connack_property( prop::subscription_identifier_available ).value_or(1); diff --git a/include/async_mqtt5/impl/unsubscribe_op.hpp b/include/async_mqtt5/impl/unsubscribe_op.hpp index 8b11f84..e9dd266 100644 --- a/include/async_mqtt5/impl/unsubscribe_op.hpp +++ b/include/async_mqtt5/impl/unsubscribe_op.hpp @@ -76,7 +76,7 @@ public: ); auto max_packet_size = static_cast( - _svc_ptr->connack_prop(prop::maximum_packet_size) + _svc_ptr->connack_property(prop::maximum_packet_size) .value_or(default_max_send_size) ); if (unsubscribe.size() > max_packet_size) diff --git a/include/async_mqtt5/mqtt_client.hpp b/include/async_mqtt5/mqtt_client.hpp index 0120b67..2c08a5a 100644 --- a/include/async_mqtt5/mqtt_client.hpp +++ b/include/async_mqtt5/mqtt_client.hpp @@ -274,8 +274,35 @@ public: return *this; } + /** + * \brief Assign \__CONNECT_PROPS\__ that will be sent in a \__CONNECT\__ packet. + * \param props \__CONNECT_PROPS\__ sent in a \__CONNECT\__ packet. + * \see See \__CONNECT_PROPS\__ for all eligible properties. + */ mqtt_client& connect_properties(connect_props props) { - _svc_ptr->connect_props(std::move(props)); + _svc_ptr->connect_properties(std::move(props)); + return *this; + } + + /** + * \brief Assign a property that will be sent in a \__CONNECT\__ packet. + * \param prop The \__CONNECT_PROPS\__ property to set. + * \param value Value that will be assigned to the property. + * + * \par Example + * \code + * client.connect_property(prop::session_expiry_interval, 40); // ok + * client.connect_property(prop::reason_string, "reason"); // does not compile, not a CONNECT prop! + * \endcode + * + * \see See \__CONNECT_PROPS\__ for all eligible properties. + */ + template + mqtt_client& connect_property( + std::integral_constant prop, + prop::value_type_t

value + ) { + _svc_ptr->connect_property(prop) = value; return *this; } @@ -296,21 +323,30 @@ public: * For all properties, the return type will be `std::optional` of their respective value type. * For `async_mqtt5::prop::user_property`, the return type is `std::vector`. * - * \param prop The \__CONNACK\__ property value to retrieve. + * \param prop The \__CONNACK_PROPS\__ property value to retrieve. * * \par Example * \code - * std::optional auth_method = client.connection_property(async_mqtt5::prop::authentication_method); // ok - * std::optional c_type = client.connection_property(async_mqtt5::prop::content_type); // does not compile! + * std::optional auth_method = client.connack_property(async_mqtt5::prop::authentication_method); // ok + * std::optional c_type = client.connack_property(async_mqtt5::prop::content_type); // does not compile, not a CONNAK prop! * \endcode * * \see See \__CONNACK_PROPS\__ for all eligible properties. */ template - const auto& connection_property( - std::integral_constant prop + const auto& connack_property( + std::integral_constant prop ) const { - return _svc_ptr->connack_prop(prop); + return _svc_ptr->connack_property(prop); + } + + /** + * \brief Retrieves the \__CONNACK_PROPS\__ from the last \__CONNACK\__ packet received. + * + * \see See \__CONNACK_PROPS\__ for all eligible properties. + */ + const connack_props& connack_properties() const { + return _svc_ptr->connack_properties(); } /** diff --git a/test/unit/include/test_common/packet_util.hpp b/test/unit/include/test_common/packet_util.hpp index c57f49c..aa186d3 100644 --- a/test/unit/include/test_common/packet_util.hpp +++ b/test/unit/include/test_common/packet_util.hpp @@ -56,6 +56,7 @@ inline std::string_view code_to_str(control_code_e code) { case control_code_e::disconnect: return "DISCONNECT"; case control_code_e::pingreq: return "PINGREQ"; case control_code_e::pingresp: return "PINGRESP"; + default: return "NO PACKET"; } return "UNKNOWN"; } diff --git a/test/unit/include/test_common/test_service.hpp b/test/unit/include/test_common/test_service.hpp index 1862134..5aa442c 100644 --- a/test/unit/include/test_common/test_service.hpp +++ b/test/unit/include/test_common/test_service.hpp @@ -51,19 +51,11 @@ public: } template - decltype(auto) connack_prop(Prop p) { - return std::as_const(_test_props[p]); + const auto& connack_property(Prop p) const { + return _test_props[p]; } - template - decltype(auto) connack_props(Prop0 p0, Props ...props) { - return std::make_tuple( - std::as_const(_test_props[p0]), - std::as_const(_test_props[props])... - ); - } - - const auto& connack_props() { + const auto& connack_properties() { return _test_props; } diff --git a/test/unit/test/client_broker.cpp b/test/unit/test/client_broker.cpp index e1d6cc7..1595be7 100644 --- a/test/unit/test/client_broker.cpp +++ b/test/unit/test/client_broker.cpp @@ -443,7 +443,6 @@ BOOST_AUTO_TEST_CASE(throttling) { test::msg_exchange broker_side; error_code success {}; - error_code fail = asio::error::not_connected; broker_side .expect(connect) @@ -546,7 +545,6 @@ BOOST_AUTO_TEST_CASE(cancel_multiple_ops) { test::msg_exchange broker_side; error_code success{}; - error_code fail = asio::error::not_connected; broker_side .expect(connect) diff --git a/test/unit/test/compilation_checks.cpp b/test/unit/test/compilation_checks.cpp index 34f167e..46694b2 100644 --- a/test/unit/test/compilation_checks.cpp +++ b/test/unit/test/compilation_checks.cpp @@ -1,11 +1,16 @@ #include +#include +#include + #include #include #include #include +#include + #include #include @@ -43,7 +48,7 @@ class bad_authenticator { public: bad_authenticator() = default; - void async_auth(std::string data) {} + void async_auth(std::string /* data */) {} std::string_view method() const { return "method"; @@ -93,9 +98,28 @@ BOOST_AUTO_TEST_CASE(client_functions) { mqtt_client tcp_client(ioc, ""); tcp_client.authenticator(good_authenticator()); - std::optional data = tcp_client.connection_property( - prop::authentication_data - ); + connack_props ca_props; + ca_props.visit([&tcp_client](const auto& p, auto&) -> bool { + using ptype = boost::remove_cv_ref_t; + prop::value_type_t value = tcp_client.connack_property(p); + return true; + }); + + connack_props ret_ca_props = tcp_client.connack_properties(); + + connect_props co_props; + co_props[prop::maximum_packet_size] = 1234; + tcp_client.connect_properties(std::move(co_props)); + + tcp_client.connect_property(prop::session_expiry_interval, 40); + tcp_client.connect_property(prop::receive_maximum, int16_t(10123)); + tcp_client.connect_property(prop::maximum_packet_size, 103); + tcp_client.connect_property(prop::topic_alias_maximum, uint16_t(12345)); + tcp_client.connect_property(prop::request_response_information, uint8_t(1)); + tcp_client.connect_property(prop::request_problem_information, uint8_t(0)); + tcp_client.connect_property(prop::user_property, std::vector { "prop", "prop" }); + tcp_client.connect_property(prop::authentication_method, "method"); + tcp_client.connect_property(prop::authentication_data, "data"); asio::ssl::context ctx(asio::ssl::context::tls_client); mqtt_client< diff --git a/test/unit/test/subscribe_op.cpp b/test/unit/test/subscribe_op.cpp index ff777da..9edb8cf 100644 --- a/test/unit/test/subscribe_op.cpp +++ b/test/unit/test/subscribe_op.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(test_wildcard_subscriptions_not_supported) { auto svc_ptr = std::make_shared( ioc.get_executor(), std::move(props) ); - BOOST_ASSERT(svc_ptr->connack_prop(prop::wildcard_subscription_available) == 0); + BOOST_ASSERT(svc_ptr->connack_property(prop::wildcard_subscription_available) == 0); for (const auto& topic: wildcard_topics) { auto handler = [&handlers_called](error_code ec, auto, auto) { @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(test_shared_subscriptions_not_supported) { auto svc_ptr = std::make_shared( ioc.get_executor(), std::move(props) ); - BOOST_ASSERT(svc_ptr->connack_prop(prop::shared_subscription_available) == 0); + BOOST_ASSERT(svc_ptr->connack_property(prop::shared_subscription_available) == 0); auto handler = [&handlers_called](error_code ec, auto, auto) { ++handlers_called; @@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(test_large_subscription_id) { auto svc_ptr = std::make_shared( ioc.get_executor(), std::move(props) ); - BOOST_ASSERT(svc_ptr->connack_prop(prop::subscription_identifier_available) == 1); + BOOST_ASSERT(svc_ptr->connack_property(prop::subscription_identifier_available) == 1); auto handler = [&handlers_called](error_code ec, auto, auto) { ++handlers_called; @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(test_subscription_ids_not_supported) { auto svc_ptr = std::make_shared( ioc.get_executor(), std::move(props) ); - BOOST_ASSERT(svc_ptr->connack_prop(prop::subscription_identifier_available) == 0); + BOOST_ASSERT(svc_ptr->connack_property(prop::subscription_identifier_available) == 0); auto handler = [&handlers_called](error_code ec, auto, auto) { ++handlers_called;