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