File indexing completed on 2025-04-09 08:28:00
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_DETAIL_ENGINE_STREAM_ADAPTOR_HPP
0009 #define BOOST_MYSQL_DETAIL_ENGINE_STREAM_ADAPTOR_HPP
0010
0011 #include <boost/mysql/error_code.hpp>
0012
0013 #include <boost/mysql/detail/config.hpp>
0014 #include <boost/mysql/detail/engine_impl.hpp>
0015 #include <boost/mysql/detail/socket_stream.hpp>
0016 #include <boost/mysql/detail/void_t.hpp>
0017
0018 #include <boost/asio/any_io_executor.hpp>
0019 #include <boost/asio/ip/tcp.hpp>
0020 #include <boost/asio/ssl/stream.hpp>
0021 #include <boost/config.hpp>
0022 #include <boost/core/ignore_unused.hpp>
0023
0024 #include <type_traits>
0025
0026
0027
0028
0029 namespace boost {
0030 namespace mysql {
0031 namespace detail {
0032
0033
0034 template <class Stream, class = void>
0035 struct endpoint_storage
0036 {
0037 void store(const void*) {}
0038 };
0039
0040 template <class Stream>
0041 struct endpoint_storage<Stream, void_t<typename Stream::lowest_layer_type::endpoint_type>>
0042 {
0043 using endpoint_type = typename Stream::lowest_layer_type::endpoint_type;
0044 endpoint_type value;
0045 void store(const void* v) { value = *static_cast<const endpoint_type*>(v); }
0046 };
0047
0048 template <class Stream>
0049 void do_connect_impl(Stream&, const endpoint_storage<Stream>&, error_code&, std::false_type)
0050 {
0051 BOOST_ASSERT(false);
0052 }
0053
0054 template <class Stream>
0055 void do_connect_impl(Stream& stream, const endpoint_storage<Stream>& ep, error_code& ec, std::true_type)
0056 {
0057 stream.lowest_layer().connect(ep.value, ec);
0058 }
0059
0060 template <class Stream>
0061 void do_connect(Stream& stream, const endpoint_storage<Stream>& ep, error_code& ec)
0062 {
0063 do_connect_impl(stream, ep, ec, is_socket_stream<Stream>{});
0064 }
0065
0066 template <class Stream, class CompletionToken>
0067 void do_async_connect_impl(Stream&, const endpoint_storage<Stream>&, CompletionToken&&, std::false_type)
0068 {
0069 BOOST_ASSERT(false);
0070 }
0071
0072 template <class Stream, class CompletionToken>
0073 void do_async_connect_impl(
0074 Stream& stream,
0075 const endpoint_storage<Stream>& ep,
0076 CompletionToken&& token,
0077 std::true_type
0078 )
0079 {
0080 stream.lowest_layer().async_connect(ep.value, std::forward<CompletionToken>(token));
0081 }
0082
0083 template <class Stream, class CompletionToken>
0084 void do_async_connect(Stream& stream, const endpoint_storage<Stream>& ep, CompletionToken&& token)
0085 {
0086 do_async_connect_impl(stream, ep, std::forward<CompletionToken>(token), is_socket_stream<Stream>{});
0087 }
0088
0089 template <class Stream>
0090 void do_close_impl(Stream&, error_code&, std::false_type)
0091 {
0092 BOOST_ASSERT(false);
0093 }
0094
0095 template <class Stream>
0096 void do_close_impl(Stream& stream, error_code& ec, std::true_type)
0097 {
0098 stream.lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);
0099 stream.lowest_layer().close(ec);
0100 }
0101
0102 template <class Stream>
0103 void do_close(Stream& stream, error_code& ec)
0104 {
0105 do_close_impl(stream, ec, is_socket_stream<Stream>{});
0106 }
0107
0108 template <class Stream>
0109 class engine_stream_adaptor
0110 {
0111 Stream stream_;
0112 endpoint_storage<Stream> endpoint_;
0113
0114 public:
0115 template <class... Args>
0116 engine_stream_adaptor(Args&&... args) : stream_(std::forward<Args>(args)...)
0117 {
0118 }
0119
0120 Stream& stream() { return stream_; }
0121 const Stream& stream() const { return stream_; }
0122
0123 bool supports_ssl() const { return false; }
0124
0125 void set_endpoint(const void* val) { endpoint_.store(val); }
0126
0127 using executor_type = asio::any_io_executor;
0128 executor_type get_executor() { return stream_.get_executor(); }
0129
0130
0131 void ssl_handshake(error_code&) { BOOST_ASSERT(false); }
0132
0133 template <class CompletinToken>
0134 void async_ssl_handshake(CompletinToken&&)
0135 {
0136 BOOST_ASSERT(false);
0137 }
0138
0139 void ssl_shutdown(error_code&) { BOOST_ASSERT(false); }
0140
0141 template <class CompletionToken>
0142 void async_ssl_shutdown(CompletionToken&&)
0143 {
0144 BOOST_ASSERT(false);
0145 }
0146
0147
0148 std::size_t read_some(boost::asio::mutable_buffer buff, bool use_ssl, error_code& ec)
0149 {
0150 BOOST_ASSERT(!use_ssl);
0151 boost::ignore_unused(use_ssl);
0152 return stream_.read_some(buff, ec);
0153 }
0154
0155 template <class CompletionToken>
0156 void async_read_some(boost::asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)
0157 {
0158 BOOST_ASSERT(!use_ssl);
0159 boost::ignore_unused(use_ssl);
0160 stream_.async_read_some(buff, std::forward<CompletionToken>(token));
0161 }
0162
0163
0164 std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)
0165 {
0166 BOOST_ASSERT(!use_ssl);
0167 boost::ignore_unused(use_ssl);
0168 return stream_.write_some(buff, ec);
0169 }
0170
0171 template <class CompletionToken>
0172 void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)
0173 {
0174 BOOST_ASSERT(!use_ssl);
0175 boost::ignore_unused(use_ssl);
0176 stream_.async_write_some(buff, std::forward<CompletionToken>(token));
0177 }
0178
0179
0180 void connect(error_code& ec) { do_connect(stream_, endpoint_, ec); }
0181
0182 template <class CompletionToken>
0183 void async_connect(CompletionToken&& token)
0184 {
0185 do_async_connect(stream_, endpoint_, std::forward<CompletionToken>(token));
0186 }
0187
0188 void close(error_code& ec) { do_close(stream_, ec); }
0189 };
0190
0191 template <class Stream>
0192 class engine_stream_adaptor<asio::ssl::stream<Stream>>
0193 {
0194 asio::ssl::stream<Stream> stream_;
0195 endpoint_storage<asio::ssl::stream<Stream>> endpoint_;
0196
0197 public:
0198 template <class... Args>
0199 engine_stream_adaptor(Args&&... args) : stream_(std::forward<Args>(args)...)
0200 {
0201 }
0202
0203 asio::ssl::stream<Stream>& stream() { return stream_; }
0204 const asio::ssl::stream<Stream>& stream() const { return stream_; }
0205
0206 bool supports_ssl() const { return true; }
0207
0208 void set_endpoint(const void* val) { endpoint_.store(val); }
0209
0210 using executor_type = asio::any_io_executor;
0211 executor_type get_executor() { return stream_.get_executor(); }
0212
0213
0214 void ssl_handshake(error_code& ec) { stream_.handshake(asio::ssl::stream_base::client, ec); }
0215
0216 template <class CompletionToken>
0217 void async_ssl_handshake(CompletionToken&& token)
0218 {
0219 stream_.async_handshake(asio::ssl::stream_base::client, std::forward<CompletionToken>(token));
0220 }
0221
0222 void ssl_shutdown(error_code& ec) { stream_.shutdown(ec); }
0223
0224 template <class CompletionToken>
0225 void async_ssl_shutdown(CompletionToken&& token)
0226 {
0227 stream_.async_shutdown(std::forward<CompletionToken>(token));
0228 }
0229
0230
0231 std::size_t read_some(boost::asio::mutable_buffer buff, bool use_ssl, error_code& ec)
0232 {
0233 if (use_ssl)
0234 {
0235 return stream_.read_some(buff, ec);
0236 }
0237 else
0238 {
0239 return stream_.next_layer().read_some(buff, ec);
0240 }
0241 }
0242
0243 template <class CompletionToken>
0244 void async_read_some(boost::asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)
0245 {
0246 if (use_ssl)
0247 {
0248 stream_.async_read_some(buff, std::forward<CompletionToken>(token));
0249 }
0250 else
0251 {
0252 stream_.next_layer().async_read_some(buff, std::forward<CompletionToken>(token));
0253 }
0254 }
0255
0256
0257 std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)
0258 {
0259 if (use_ssl)
0260 {
0261 return stream_.write_some(buff, ec);
0262 }
0263 else
0264 {
0265 return stream_.next_layer().write_some(buff, ec);
0266 }
0267 }
0268
0269 template <class CompletionToken>
0270 void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)
0271 {
0272 if (use_ssl)
0273 {
0274 stream_.async_write_some(buff, std::forward<CompletionToken>(token));
0275 }
0276 else
0277 {
0278 stream_.next_layer().async_write_some(buff, std::forward<CompletionToken>(token));
0279 }
0280 }
0281
0282
0283 void connect(error_code& ec) { do_connect(stream_, endpoint_, ec); }
0284
0285 template <class CompletionToken>
0286 void async_connect(CompletionToken&& token)
0287 {
0288 do_async_connect(stream_, endpoint_, std::forward<CompletionToken>(token));
0289 }
0290
0291 void close(error_code& ec) { do_close(stream_, ec); }
0292 };
0293
0294 #ifdef BOOST_MYSQL_SEPARATE_COMPILATION
0295 extern template class engine_impl<engine_stream_adaptor<asio::ssl::stream<asio::ip::tcp::socket>>>;
0296 extern template class engine_impl<engine_stream_adaptor<asio::ip::tcp::socket>>;
0297 #endif
0298
0299 template <class Stream, class... Args>
0300 std::unique_ptr<engine> make_engine(Args&&... args)
0301 {
0302 return std::unique_ptr<engine>(new engine_impl<engine_stream_adaptor<Stream>>(std::forward<Args>(args)...)
0303 );
0304 }
0305
0306
0307 template <class Stream>
0308 Stream& stream_from_engine(engine& eng)
0309 {
0310 using derived_t = engine_impl<engine_stream_adaptor<Stream>>;
0311 return static_cast<derived_t&>(eng).stream().stream();
0312 }
0313
0314 template <class Stream>
0315 const Stream& stream_from_engine(const engine& eng)
0316 {
0317 using derived_t = engine_impl<engine_stream_adaptor<Stream>>;
0318 return static_cast<const derived_t&>(eng).stream().stream();
0319 }
0320
0321 }
0322 }
0323 }
0324
0325 #endif