engine_stream_adaptor.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //
  2. // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_DETAIL_ENGINE_STREAM_ADAPTOR_HPP
  8. #define BOOST_MYSQL_DETAIL_ENGINE_STREAM_ADAPTOR_HPP
  9. #include <boost/mysql/error_code.hpp>
  10. #include <boost/mysql/detail/config.hpp>
  11. #include <boost/mysql/detail/engine_impl.hpp>
  12. #include <boost/mysql/detail/socket_stream.hpp>
  13. #include <boost/mysql/detail/void_t.hpp>
  14. #include <boost/asio/any_io_executor.hpp>
  15. #include <boost/asio/ip/tcp.hpp>
  16. #include <boost/asio/ssl/stream.hpp>
  17. #include <boost/config.hpp>
  18. #include <boost/core/ignore_unused.hpp>
  19. #include <type_traits>
  20. // Adapts a regular Asio Stream to meet the EngineStream requirements
  21. // We only use callbacks with the async functions in this file, so no need to support arbitrary return types
  22. namespace boost {
  23. namespace mysql {
  24. namespace detail {
  25. // Connect and close helpers
  26. // LCOV_EXCL_START
  27. template <class Stream>
  28. void do_connect_impl(Stream&, const void*, error_code&, std::false_type)
  29. {
  30. BOOST_ASSERT(false);
  31. }
  32. // LCOV_EXCL_STOP
  33. template <class Stream>
  34. void do_connect_impl(Stream& stream, const void* ep, error_code& ec, std::true_type)
  35. {
  36. stream.lowest_layer().connect(
  37. *static_cast<const typename Stream::lowest_layer_type::endpoint_type*>(ep),
  38. ec
  39. );
  40. }
  41. template <class Stream>
  42. void do_connect(Stream& stream, const void* ep, error_code& ec)
  43. {
  44. do_connect_impl(stream, ep, ec, is_socket_stream<Stream>{});
  45. }
  46. // LCOV_EXCL_START
  47. template <class Stream, class CompletionToken>
  48. void do_async_connect_impl(Stream&, const void*, CompletionToken&&, std::false_type)
  49. {
  50. BOOST_ASSERT(false);
  51. }
  52. // LCOV_EXCL_STOP
  53. template <class Stream, class CompletionToken>
  54. void do_async_connect_impl(Stream& stream, const void* ep, CompletionToken&& token, std::true_type)
  55. {
  56. stream.lowest_layer().async_connect(
  57. *static_cast<const typename Stream::lowest_layer_type::endpoint_type*>(ep),
  58. std::forward<CompletionToken>(token)
  59. );
  60. }
  61. template <class Stream, class CompletionToken>
  62. void do_async_connect(Stream& stream, const void* ep, CompletionToken&& token)
  63. {
  64. do_async_connect_impl(stream, ep, std::forward<CompletionToken>(token), is_socket_stream<Stream>{});
  65. }
  66. // LCOV_EXCL_START
  67. template <class Stream>
  68. void do_close_impl(Stream&, error_code&, std::false_type)
  69. {
  70. BOOST_ASSERT(false);
  71. }
  72. // LCOV_EXCL_STOP
  73. template <class Stream>
  74. void do_close_impl(Stream& stream, error_code& ec, std::true_type)
  75. {
  76. stream.lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);
  77. stream.lowest_layer().close(ec);
  78. }
  79. template <class Stream>
  80. void do_close(Stream& stream, error_code& ec)
  81. {
  82. do_close_impl(stream, ec, is_socket_stream<Stream>{});
  83. }
  84. template <class Stream>
  85. class engine_stream_adaptor
  86. {
  87. Stream stream_;
  88. public:
  89. template <class... Args>
  90. engine_stream_adaptor(Args&&... args) : stream_(std::forward<Args>(args)...)
  91. {
  92. }
  93. Stream& stream() { return stream_; }
  94. const Stream& stream() const { return stream_; }
  95. bool supports_ssl() const { return false; }
  96. using executor_type = asio::any_io_executor;
  97. executor_type get_executor() { return stream_.get_executor(); }
  98. // SSL
  99. // LCOV_EXCL_START
  100. void ssl_handshake(error_code&) { BOOST_ASSERT(false); }
  101. template <class CompletinToken>
  102. void async_ssl_handshake(CompletinToken&&)
  103. {
  104. BOOST_ASSERT(false);
  105. }
  106. void ssl_shutdown(error_code&) { BOOST_ASSERT(false); }
  107. template <class CompletionToken>
  108. void async_ssl_shutdown(CompletionToken&&)
  109. {
  110. BOOST_ASSERT(false);
  111. }
  112. // LCOV_EXCL_STOP
  113. // Reading
  114. std::size_t read_some(boost::asio::mutable_buffer buff, bool use_ssl, error_code& ec)
  115. {
  116. BOOST_ASSERT(!use_ssl);
  117. boost::ignore_unused(use_ssl);
  118. return stream_.read_some(buff, ec);
  119. }
  120. template <class CompletionToken>
  121. void async_read_some(boost::asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)
  122. {
  123. BOOST_ASSERT(!use_ssl);
  124. boost::ignore_unused(use_ssl);
  125. stream_.async_read_some(buff, std::forward<CompletionToken>(token));
  126. }
  127. // Writing
  128. std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)
  129. {
  130. BOOST_ASSERT(!use_ssl);
  131. boost::ignore_unused(use_ssl);
  132. return stream_.write_some(buff, ec);
  133. }
  134. template <class CompletionToken>
  135. void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)
  136. {
  137. BOOST_ASSERT(!use_ssl);
  138. boost::ignore_unused(use_ssl);
  139. stream_.async_write_some(buff, std::forward<CompletionToken>(token));
  140. }
  141. // Connect and close
  142. void connect(const void* endpoint, error_code& ec) { do_connect(stream_, endpoint, ec); }
  143. template <class CompletionToken>
  144. void async_connect(const void* endpoint, CompletionToken&& token)
  145. {
  146. do_async_connect(stream_, endpoint, std::forward<CompletionToken>(token));
  147. }
  148. void close(error_code& ec) { do_close(stream_, ec); }
  149. };
  150. template <class Stream>
  151. class engine_stream_adaptor<asio::ssl::stream<Stream>>
  152. {
  153. asio::ssl::stream<Stream> stream_;
  154. public:
  155. template <class... Args>
  156. engine_stream_adaptor(Args&&... args) : stream_(std::forward<Args>(args)...)
  157. {
  158. }
  159. asio::ssl::stream<Stream>& stream() { return stream_; }
  160. const asio::ssl::stream<Stream>& stream() const { return stream_; }
  161. bool supports_ssl() const { return true; }
  162. using executor_type = asio::any_io_executor;
  163. executor_type get_executor() { return stream_.get_executor(); }
  164. // SSL
  165. void ssl_handshake(error_code& ec) { stream_.handshake(asio::ssl::stream_base::client, ec); }
  166. template <class CompletionToken>
  167. void async_ssl_handshake(CompletionToken&& token)
  168. {
  169. stream_.async_handshake(asio::ssl::stream_base::client, std::forward<CompletionToken>(token));
  170. }
  171. void ssl_shutdown(error_code& ec) { stream_.shutdown(ec); }
  172. template <class CompletionToken>
  173. void async_ssl_shutdown(CompletionToken&& token)
  174. {
  175. stream_.async_shutdown(std::forward<CompletionToken>(token));
  176. }
  177. // Reading
  178. std::size_t read_some(boost::asio::mutable_buffer buff, bool use_ssl, error_code& ec)
  179. {
  180. if (use_ssl)
  181. {
  182. return stream_.read_some(buff, ec);
  183. }
  184. else
  185. {
  186. return stream_.next_layer().read_some(buff, ec);
  187. }
  188. }
  189. template <class CompletionToken>
  190. void async_read_some(boost::asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)
  191. {
  192. if (use_ssl)
  193. {
  194. stream_.async_read_some(buff, std::forward<CompletionToken>(token));
  195. }
  196. else
  197. {
  198. stream_.next_layer().async_read_some(buff, std::forward<CompletionToken>(token));
  199. }
  200. }
  201. // Writing
  202. std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)
  203. {
  204. if (use_ssl)
  205. {
  206. return stream_.write_some(buff, ec);
  207. }
  208. else
  209. {
  210. return stream_.next_layer().write_some(buff, ec);
  211. }
  212. }
  213. template <class CompletionToken>
  214. void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)
  215. {
  216. if (use_ssl)
  217. {
  218. stream_.async_write_some(buff, std::forward<CompletionToken>(token));
  219. }
  220. else
  221. {
  222. stream_.next_layer().async_write_some(buff, std::forward<CompletionToken>(token));
  223. }
  224. }
  225. // Connect and close
  226. void connect(const void* endpoint, error_code& ec) { do_connect(stream_, endpoint, ec); }
  227. template <class CompletionToken>
  228. void async_connect(const void* endpoint, CompletionToken&& token)
  229. {
  230. do_async_connect(stream_, endpoint, std::forward<CompletionToken>(token));
  231. }
  232. void close(error_code& ec) { do_close(stream_, ec); }
  233. };
  234. #ifdef BOOST_MYSQL_SEPARATE_COMPILATION
  235. extern template class engine_impl<engine_stream_adaptor<asio::ssl::stream<asio::ip::tcp::socket>>>;
  236. extern template class engine_impl<engine_stream_adaptor<asio::ip::tcp::socket>>;
  237. #endif
  238. template <class Stream, class... Args>
  239. std::unique_ptr<engine> make_engine(Args&&... args)
  240. {
  241. return std::unique_ptr<engine>(new engine_impl<engine_stream_adaptor<Stream>>(std::forward<Args>(args)...)
  242. );
  243. }
  244. // Use these only for engines created using make_engine
  245. template <class Stream>
  246. Stream& stream_from_engine(engine& eng)
  247. {
  248. using derived_t = engine_impl<engine_stream_adaptor<Stream>>;
  249. return static_cast<derived_t&>(eng).stream().stream();
  250. }
  251. template <class Stream>
  252. const Stream& stream_from_engine(const engine& eng)
  253. {
  254. using derived_t = engine_impl<engine_stream_adaptor<Stream>>;
  255. return static_cast<const derived_t&>(eng).stream().stream();
  256. }
  257. } // namespace detail
  258. } // namespace mysql
  259. } // namespace boost
  260. #endif