// // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BHO_MYSQL_DETAIL_ANY_STREAM_IMPL_HPP #define BHO_MYSQL_DETAIL_ANY_STREAM_IMPL_HPP #include #include #include #include #include #include #include #include namespace bho { namespace mysql { namespace detail { // Connect and close helpers template const typename Stream::lowest_layer_type::endpoint_type cast_endpoint(const void* input) noexcept { return *static_cast(input); } template void do_connect_impl(Stream&, const void*, error_code&, std::false_type) { BHO_ASSERT(false); } template void do_connect_impl(Stream& stream, const void* endpoint, error_code& ec, std::true_type) { stream.lowest_layer().connect(cast_endpoint(endpoint), ec); } template void do_connect(Stream& stream, const void* endpoint, error_code& ec) { do_connect_impl(stream, endpoint, ec, is_socket_stream{}); } template void do_async_connect_impl( Stream&, const void*, asio::any_completion_handler&&, std::false_type ) { BHO_ASSERT(false); } template void do_async_connect_impl( Stream& stream, const void* endpoint, asio::any_completion_handler&& handler, std::true_type ) { stream.lowest_layer().async_connect(cast_endpoint(endpoint), std::move(handler)); } template void do_async_connect( Stream& stream, const void* endpoint, asio::any_completion_handler&& handler ) { do_async_connect_impl(stream, endpoint, std::move(handler), is_socket_stream{}); } template void do_close_impl(Stream&, error_code&, std::false_type) { BHO_ASSERT(false); } template void do_close_impl(Stream& stream, error_code& ec, std::true_type) { stream.lowest_layer().shutdown(asio::socket_base::shutdown_both, ec); stream.lowest_layer().close(ec); } template void do_close(Stream& stream, error_code& ec) { do_close_impl(stream, ec, is_socket_stream{}); } template bool do_is_open_impl(const Stream&, std::false_type) noexcept { return false; } template bool do_is_open_impl(const Stream& stream, std::true_type) noexcept { return stream.lowest_layer().is_open(); } template bool do_is_open(const Stream& stream) noexcept { return do_is_open_impl(stream, is_socket_stream{}); } template class any_stream_impl final : public any_stream { Stream stream_; public: template any_stream_impl(Args&&... args) : any_stream(false), stream_(std::forward(args)...) { } Stream& stream() noexcept { return stream_; } const Stream& stream() const noexcept { return stream_; } executor_type get_executor() override final { return stream_.get_executor(); } // SSL void handshake(error_code&) final override { BHO_ASSERT(false); } void async_handshake(asio::any_completion_handler) final override { BHO_ASSERT(false); } void shutdown(error_code&) final override { BHO_ASSERT(false); } void async_shutdown(asio::any_completion_handler) final override { BHO_ASSERT(false); } // Reading std::size_t read_some(asio::mutable_buffer buff, error_code& ec) final override { return stream_.read_some(buff, ec); } void async_read_some( asio::mutable_buffer buff, asio::any_completion_handler handler ) final override { return stream_.async_read_some(buff, std::move(handler)); } // Writing std::size_t write_some(asio::const_buffer buff, error_code& ec) final override { return stream_.write_some(buff, ec); } void async_write_some( asio::const_buffer buff, asio::any_completion_handler handler ) final override { return stream_.async_write_some(buff, std::move(handler)); } // Connect and close void connect(const void* endpoint, error_code& ec) override final { do_connect(stream_, endpoint, ec); } void async_connect(const void* endpoint, asio::any_completion_handler handler) override final { do_async_connect(stream_, endpoint, std::move(handler)); } void close(error_code& ec) override final { do_close(stream_, ec); } bool is_open() const noexcept override { return do_is_open(stream_); } }; template class any_stream_impl> final : public any_stream { asio::ssl::stream stream_; public: template any_stream_impl(Args&&... args) : any_stream(true), stream_(std::forward(args)...) { } asio::ssl::stream& stream() noexcept { return stream_; } const asio::ssl::stream& stream() const noexcept { return stream_; } executor_type get_executor() override final { return stream_.get_executor(); } // SSL void handshake(error_code& ec) override final { set_ssl_active(); stream_.handshake(asio::ssl::stream_base::client, ec); } void async_handshake(asio::any_completion_handler handler) override final { set_ssl_active(); stream_.async_handshake(asio::ssl::stream_base::client, std::move(handler)); } void shutdown(error_code& ec) override final { stream_.shutdown(ec); } void async_shutdown(asio::any_completion_handler handler) override final { return stream_.async_shutdown(std::move(handler)); } // Reading std::size_t read_some(asio::mutable_buffer buff, error_code& ec) override final { if (ssl_active()) { return stream_.read_some(buff, ec); } else { return stream_.next_layer().read_some(buff, ec); } } void async_read_some( asio::mutable_buffer buff, asio::any_completion_handler handler ) override final { if (ssl_active()) { return stream_.async_read_some(buff, std::move(handler)); } else { return stream_.next_layer().async_read_some(buff, std::move(handler)); } } // Writing std::size_t write_some(asio::const_buffer buff, error_code& ec) override final { if (ssl_active()) { return stream_.write_some(buff, ec); } else { return stream_.next_layer().write_some(buff, ec); } } void async_write_some( asio::const_buffer buff, asio::any_completion_handler handler ) override final { if (ssl_active()) { stream_.async_write_some(buff, std::move(handler)); } else { return stream_.next_layer().async_write_some(buff, std::move(handler)); } } // Connect and close void connect(const void* endpoint, error_code& ec) override final { do_connect(stream_, endpoint, ec); } void async_connect(const void* endpoint, asio::any_completion_handler handler) override final { do_async_connect(stream_, endpoint, std::move(handler)); } void close(error_code& ec) override final { do_close(stream_, ec); } bool is_open() const noexcept override { return do_is_open(stream_); } }; template const Stream& cast(const any_stream& obj) noexcept { return static_cast&>(obj).stream(); } template Stream& cast(any_stream& obj) noexcept { return static_cast&>(obj).stream(); } #ifdef BHO_MYSQL_SEPARATE_COMPILATION extern template class any_stream_impl>; extern template class any_stream_impl; #endif } // namespace detail } // namespace mysql } // namespace bho // any_stream_impl.ipp explicitly instantiates any_stream_impl, so not included here #endif