Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-09 08:28:00

0001 //
0002 // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // Adapts a regular Asio Stream to meet the EngineStream requirements
0027 // We only use callbacks with the async functions in this file, so no need to support arbitrary return types
0028 
0029 namespace boost {
0030 namespace mysql {
0031 namespace detail {
0032 
0033 // Connect and close helpers
0034 template <class Stream, class = void>
0035 struct endpoint_storage  // prevent build errors for non socket streams
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     // SSL
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     // Reading
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     // Writing
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     // Connect and close
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     // SSL
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     // Reading
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     // Writing
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     // Connect and close
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 // Use these only for engines created using make_engine
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 }  // namespace detail
0322 }  // namespace mysql
0323 }  // namespace boost
0324 
0325 #endif