File indexing completed on 2025-09-17 08:38:19
0001
0002
0003
0004
0005
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
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
0036
0037 template <typename Stream>
0038 struct ws_handshake_traits {};
0039
0040 namespace detail {
0041
0042
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
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
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
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
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
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
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
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
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 }
0235
0236 }
0237
0238 #endif