| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- //
- // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- #ifndef BOOST_MQTT5_ASYNC_TRAITS_HPP
- #define BOOST_MQTT5_ASYNC_TRAITS_HPP
- #include <boost/mqtt5/types.hpp>
- #include <boost/asio/associated_executor.hpp>
- #include <boost/asio/execution.hpp>
- #include <boost/asio/prefer.hpp>
- #include <boost/asio/write.hpp>
- #include <boost/type_traits/detected_or.hpp>
- #include <boost/type_traits/is_detected.hpp>
- #include <boost/type_traits/remove_cv_ref.hpp>
- #include <type_traits>
- namespace boost::mqtt5 {
- namespace asio = boost::asio;
- // TLS
- template <typename StreamType>
- struct tls_handshake_type {};
- template <typename TlsContext, typename TlsStream>
- void assign_tls_sni(const authority_path& ap, TlsContext& ctx, TlsStream& s);
- // WebSocket
- template <typename Stream>
- struct ws_handshake_traits {};
- namespace detail {
- // tracking executor
- template <typename Handler, typename DfltExecutor>
- using tracking_type = std::decay_t<
- typename asio::prefer_result<
- asio::associated_executor_t<Handler, DfltExecutor>,
- asio::execution::outstanding_work_t::tracked_t
- >::type
- >;
- template <typename Handler, typename DfltExecutor>
- tracking_type<Handler, DfltExecutor>
- tracking_executor(const Handler& handler, const DfltExecutor& ex) {
- return asio::prefer(
- asio::get_associated_executor(handler, ex),
- asio::execution::outstanding_work.tracked
- );
- }
- // tls handshake
- constexpr auto handshake_handler_t = [](error_code) {};
- template <typename T>
- using tls_handshake_t = typename T::handshake_type;
- template <typename T>
- using tls_handshake_type_of = boost::detected_or_t<void, tls_handshake_t, T>;
- template <typename T, typename ...Ts>
- using async_tls_handshake_sig = decltype(
- std::declval<T&>().async_handshake(std::declval<Ts>()...)
- );
- template <typename T>
- constexpr bool has_tls_handshake = boost::is_detected<
- async_tls_handshake_sig, T, tls_handshake_type_of<T>,
- decltype(handshake_handler_t)
- >::value;
- // websocket handshake
- template <typename T, typename ...Ts>
- using async_ws_handshake_sig = decltype(
- std::declval<T&>().async_handshake(std::declval<Ts>()...)
- );
- template <typename T>
- constexpr bool has_ws_handshake = boost::is_detected<
- async_ws_handshake_sig, T,
- std::string_view, std::string_view,
- decltype(handshake_handler_t)
- >::value;
- // next layer
- template <typename T>
- using next_layer_sig = decltype(std::declval<T&>().next_layer());
- template <typename T>
- constexpr bool has_next_layer = boost::is_detected<
- next_layer_sig, boost::remove_cv_ref_t<T>
- >::value;
- template <typename T, typename Enable = void>
- struct next_layer_type_impl {
- using type = T;
- };
- template <typename T>
- struct next_layer_type_impl<T, std::enable_if_t<has_next_layer<T>>> {
- using type = typename T::next_layer_type;
- };
- template <typename T>
- using next_layer_type = typename next_layer_type_impl<
- boost::remove_cv_ref_t<T>
- >::type;
- template <typename T>
- next_layer_type<T>& next_layer(T&& a) {
- if constexpr (has_next_layer<T>)
- return a.next_layer();
- else
- return std::forward<T>(a);
- }
- // lowest layer
- template <typename T, typename Enable = void>
- struct lowest_layer_type_impl {
- using type = T;
- };
- template <typename T>
- struct lowest_layer_type_impl<T, std::enable_if_t<has_next_layer<T>>> {
- using type = typename lowest_layer_type_impl<
- next_layer_type<T>
- >::type;
- };
- template <typename T>
- using lowest_layer_type = typename lowest_layer_type_impl<
- boost::remove_cv_ref_t<T>
- >::type;
- template <typename T>
- lowest_layer_type<T>& lowest_layer(T&& a) {
- if constexpr (has_next_layer<T>)
- return lowest_layer(a.next_layer());
- else
- return std::forward<T>(a);
- }
- // tls layer
- template <typename T, typename Enable = void>
- struct has_tls_layer_impl : std::false_type {};
- template <typename T>
- struct has_tls_layer_impl<
- T, std::enable_if_t<has_tls_handshake<T>>
- > : std::true_type {};
- template <typename T>
- struct has_tls_layer_impl<
- T, std::enable_if_t<!has_tls_handshake<T> && has_next_layer<T>>
- > : has_tls_layer_impl<
- boost::remove_cv_ref_t<decltype(std::declval<T&>().next_layer())>
- > {};
- template <typename T>
- constexpr bool has_tls_layer = has_tls_layer_impl<
- boost::remove_cv_ref_t<T>
- >::value;
- // tls context
- template <typename T>
- using tls_context_sig = decltype(
- std::declval<T&>().tls_context()
- );
- template <typename T>
- constexpr bool has_tls_context = boost::is_detected<
- tls_context_sig, T
- >::value;
- // setup_tls_sni
- template <typename TlsContext, typename Stream>
- void setup_tls_sni(const authority_path& ap, TlsContext& ctx, Stream& s) {
- if constexpr (has_tls_handshake<Stream>)
- assign_tls_sni(ap, ctx, s);
- else if constexpr (has_next_layer<Stream>)
- setup_tls_sni(ap, ctx, next_layer(s));
- }
- // async_write
- template <typename T, typename ...Ts>
- using async_write_sig = decltype(
- std::declval<T&>().async_write(std::declval<Ts>()...)
- );
- constexpr auto write_handler_t = [](error_code, size_t) {};
- template <typename T, typename B>
- constexpr bool has_async_write = boost::is_detected<
- async_write_sig, T, B, decltype(write_handler_t)
- >::value;
- template <
- typename Stream,
- typename ConstBufferSequence,
- typename CompletionToken
- >
- decltype(auto) async_write(
- Stream& stream, const ConstBufferSequence& buff, CompletionToken&& token
- ) {
- if constexpr (has_async_write<Stream, ConstBufferSequence>)
- return stream.async_write(
- buff, std::forward<CompletionToken>(token)
- );
- else
- return asio::async_write(
- stream, buff, std::forward<CompletionToken>(token)
- );
- }
- } // end namespace detail
- } // end namespace boost::mqtt5
- #endif // !BOOST_MQTT5_ASYNC_TRAITS_HPP
|