Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:19

0001 //
0002 // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MQTT5_ASYNC_TRAITS_HPP
0009 #define BOOST_MQTT5_ASYNC_TRAITS_HPP
0010 
0011 #include <boost/mqtt5/types.hpp>
0012 
0013 #include <boost/asio/associated_executor.hpp>
0014 #include <boost/asio/execution.hpp>
0015 #include <boost/asio/prefer.hpp>
0016 #include <boost/asio/write.hpp>
0017 #include <boost/type_traits/detected_or.hpp>
0018 #include <boost/type_traits/is_detected.hpp>
0019 #include <boost/type_traits/remove_cv_ref.hpp>
0020 
0021 #include <type_traits>
0022 
0023 namespace boost::mqtt5 {
0024 
0025 namespace asio = boost::asio;
0026 
0027 // TLS
0028 
0029 template <typename StreamType>
0030 struct tls_handshake_type {};
0031 
0032 template <typename TlsContext, typename TlsStream>
0033 void assign_tls_sni(const authority_path& ap, TlsContext& ctx, TlsStream& s);
0034 
0035 // WebSocket
0036 
0037 template <typename Stream>
0038 struct ws_handshake_traits {};
0039 
0040 namespace detail {
0041 
0042 // tracking executor
0043 
0044 template <typename Handler, typename DfltExecutor>
0045 using tracking_type = std::decay_t<
0046     typename asio::prefer_result<
0047         asio::associated_executor_t<Handler, DfltExecutor>,
0048         asio::execution::outstanding_work_t::tracked_t
0049     >::type
0050 >;
0051 
0052 template <typename Handler, typename DfltExecutor>
0053 tracking_type<Handler, DfltExecutor>
0054 tracking_executor(const Handler& handler, const DfltExecutor& ex) {
0055     return asio::prefer(
0056         asio::get_associated_executor(handler, ex),
0057         asio::execution::outstanding_work.tracked
0058     );
0059 }
0060 
0061 
0062 // tls handshake
0063 
0064 constexpr auto handshake_handler_t = [](error_code) {};
0065 
0066 template <typename T>
0067 using tls_handshake_t = typename T::handshake_type;
0068 
0069 template <typename T>
0070 using tls_handshake_type_of = boost::detected_or_t<void, tls_handshake_t, T>;
0071 
0072 template <typename T, typename ...Ts>
0073 using async_tls_handshake_sig = decltype(
0074     std::declval<T&>().async_handshake(std::declval<Ts>()...)
0075 );
0076 
0077 template <typename T>
0078 constexpr bool has_tls_handshake = boost::is_detected<
0079     async_tls_handshake_sig, T, tls_handshake_type_of<T>,
0080     decltype(handshake_handler_t)
0081 >::value;
0082 
0083 // websocket handshake
0084 
0085 template <typename T, typename ...Ts>
0086 using async_ws_handshake_sig = decltype(
0087     std::declval<T&>().async_handshake(std::declval<Ts>()...)
0088 );
0089 
0090 template <typename T>
0091 constexpr bool has_ws_handshake = boost::is_detected<
0092     async_ws_handshake_sig, T,
0093     std::string_view, std::string_view,
0094     decltype(handshake_handler_t)
0095 >::value;
0096 
0097 // next layer
0098 
0099 template <typename T>
0100 using next_layer_sig = decltype(std::declval<T&>().next_layer());
0101 
0102 template <typename T>
0103 constexpr bool has_next_layer = boost::is_detected<
0104     next_layer_sig, boost::remove_cv_ref_t<T>
0105 >::value;
0106 
0107 template <typename T, typename Enable = void>
0108 struct next_layer_type_impl {
0109     using type = T;
0110 };
0111 
0112 template <typename T>
0113 struct next_layer_type_impl<T, std::enable_if_t<has_next_layer<T>>> {
0114     using type = typename T::next_layer_type;
0115 };
0116 
0117 template <typename T>
0118 using next_layer_type = typename next_layer_type_impl<
0119     boost::remove_cv_ref_t<T>
0120 >::type;
0121 
0122 template <typename T>
0123 next_layer_type<T>& next_layer(T&& a) {
0124     if constexpr (has_next_layer<T>)
0125         return a.next_layer();
0126     else
0127         return std::forward<T>(a);
0128 }
0129 
0130 // lowest layer
0131 
0132 template <typename T, typename Enable = void>
0133 struct lowest_layer_type_impl {
0134     using type = T;
0135 };
0136 
0137 template <typename T>
0138 struct lowest_layer_type_impl<T, std::enable_if_t<has_next_layer<T>>> {
0139     using type = typename lowest_layer_type_impl<
0140         next_layer_type<T>
0141     >::type;
0142 };
0143 
0144 template <typename T>
0145 using lowest_layer_type = typename lowest_layer_type_impl<
0146     boost::remove_cv_ref_t<T>
0147 >::type;
0148 
0149 template <typename T>
0150 lowest_layer_type<T>& lowest_layer(T&& a) {
0151     if constexpr (has_next_layer<T>)
0152         return lowest_layer(a.next_layer());
0153     else
0154         return std::forward<T>(a);
0155 }
0156 
0157 // tls layer
0158 
0159 template <typename T, typename Enable = void>
0160 struct has_tls_layer_impl : std::false_type {};
0161 
0162 template <typename T>
0163 struct has_tls_layer_impl<
0164     T, std::enable_if_t<has_tls_handshake<T>>
0165 > : std::true_type {};
0166 
0167 template <typename T>
0168 struct has_tls_layer_impl<
0169     T, std::enable_if_t<!has_tls_handshake<T> && has_next_layer<T>>
0170 > : has_tls_layer_impl<
0171     boost::remove_cv_ref_t<decltype(std::declval<T&>().next_layer())>
0172 > {};
0173 
0174 template <typename T>
0175 constexpr bool has_tls_layer = has_tls_layer_impl<
0176     boost::remove_cv_ref_t<T>
0177 >::value;
0178 
0179 // tls context
0180 
0181 template <typename T>
0182 using tls_context_sig = decltype(
0183     std::declval<T&>().tls_context()
0184 );
0185 
0186 template <typename T>
0187 constexpr bool has_tls_context = boost::is_detected<
0188     tls_context_sig, T
0189 >::value;
0190 
0191 // setup_tls_sni
0192 
0193 template <typename TlsContext, typename Stream>
0194 void setup_tls_sni(const authority_path& ap, TlsContext& ctx, Stream& s) {
0195     if constexpr (has_tls_handshake<Stream>)
0196         assign_tls_sni(ap, ctx, s);
0197     else if constexpr (has_next_layer<Stream>)
0198         setup_tls_sni(ap, ctx, next_layer(s));
0199 }
0200 
0201 // async_write
0202 
0203 template <typename T, typename ...Ts>
0204 using async_write_sig = decltype(
0205     std::declval<T&>().async_write(std::declval<Ts>()...)
0206 );
0207 
0208 constexpr auto write_handler_t = [](error_code, size_t) {};
0209 
0210 template <typename T, typename B>
0211 constexpr bool has_async_write = boost::is_detected<
0212     async_write_sig, T, B, decltype(write_handler_t)
0213 >::value;
0214 
0215 template <
0216     typename Stream,
0217     typename ConstBufferSequence,
0218     typename CompletionToken
0219 >
0220 decltype(auto) async_write(
0221     Stream& stream, const ConstBufferSequence& buff, CompletionToken&& token
0222 ) {
0223     if constexpr (has_async_write<Stream, ConstBufferSequence>)
0224         return stream.async_write(
0225             buff, std::forward<CompletionToken>(token)
0226         );
0227     else
0228         return asio::async_write(
0229             stream, buff, std::forward<CompletionToken>(token)
0230         );
0231 }
0232 
0233 
0234 } // end namespace detail
0235 
0236 } // end namespace boost::mqtt5
0237 
0238 #endif // !BOOST_MQTT5_ASYNC_TRAITS_HPP