// // 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 #include #include #include #include #include #include #include #include namespace boost::mqtt5 { namespace asio = boost::asio; // TLS template struct tls_handshake_type {}; template void assign_tls_sni(const authority_path& ap, TlsContext& ctx, TlsStream& s); // WebSocket template struct ws_handshake_traits {}; namespace detail { // tracking executor template using tracking_type = std::decay_t< typename asio::prefer_result< asio::associated_executor_t, asio::execution::outstanding_work_t::tracked_t >::type >; template tracking_type 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 using tls_handshake_t = typename T::handshake_type; template using tls_handshake_type_of = boost::detected_or_t; template using async_tls_handshake_sig = decltype( std::declval().async_handshake(std::declval()...) ); template constexpr bool has_tls_handshake = boost::is_detected< async_tls_handshake_sig, T, tls_handshake_type_of, decltype(handshake_handler_t) >::value; // websocket handshake template using async_ws_handshake_sig = decltype( std::declval().async_handshake(std::declval()...) ); template 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 using next_layer_sig = decltype(std::declval().next_layer()); template constexpr bool has_next_layer = boost::is_detected< next_layer_sig, boost::remove_cv_ref_t >::value; template struct next_layer_type_impl { using type = T; }; template struct next_layer_type_impl>> { using type = typename T::next_layer_type; }; template using next_layer_type = typename next_layer_type_impl< boost::remove_cv_ref_t >::type; template next_layer_type& next_layer(T&& a) { if constexpr (has_next_layer) return a.next_layer(); else return std::forward(a); } // lowest layer template struct lowest_layer_type_impl { using type = T; }; template struct lowest_layer_type_impl>> { using type = typename lowest_layer_type_impl< next_layer_type >::type; }; template using lowest_layer_type = typename lowest_layer_type_impl< boost::remove_cv_ref_t >::type; template lowest_layer_type& lowest_layer(T&& a) { if constexpr (has_next_layer) return lowest_layer(a.next_layer()); else return std::forward(a); } // tls layer template struct has_tls_layer_impl : std::false_type {}; template struct has_tls_layer_impl< T, std::enable_if_t> > : std::true_type {}; template struct has_tls_layer_impl< T, std::enable_if_t && has_next_layer> > : has_tls_layer_impl< boost::remove_cv_ref_t().next_layer())> > {}; template constexpr bool has_tls_layer = has_tls_layer_impl< boost::remove_cv_ref_t >::value; // tls context template using tls_context_sig = decltype( std::declval().tls_context() ); template constexpr bool has_tls_context = boost::is_detected< tls_context_sig, T >::value; // setup_tls_sni template void setup_tls_sni(const authority_path& ap, TlsContext& ctx, Stream& s) { if constexpr (has_tls_handshake) assign_tls_sni(ap, ctx, s); else if constexpr (has_next_layer) setup_tls_sni(ap, ctx, next_layer(s)); } // async_write template using async_write_sig = decltype( std::declval().async_write(std::declval()...) ); constexpr auto write_handler_t = [](error_code, size_t) {}; template 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) return stream.async_write( buff, std::forward(token) ); else return asio::async_write( stream, buff, std::forward(token) ); } } // end namespace detail } // end namespace boost::mqtt5 #endif // !BOOST_MQTT5_ASYNC_TRAITS_HPP