Files
cpp-thirdparty/linx64/include/boost/mysql/detail/any_stream_impl.hpp
2023-11-24 12:56:13 -06:00

308 lines
8.6 KiB
C++

//
// 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 BOOST_MYSQL_DETAIL_ANY_STREAM_IMPL_HPP
#define BOOST_MYSQL_DETAIL_ANY_STREAM_IMPL_HPP
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/detail/any_stream.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/socket_stream.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/config.hpp>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Connect and close helpers
template <class Stream>
const typename Stream::lowest_layer_type::endpoint_type cast_endpoint(const void* input) noexcept
{
return *static_cast<const typename Stream::lowest_layer_type::endpoint_type*>(input);
}
template <class Stream>
void do_connect_impl(Stream&, const void*, error_code&, std::false_type)
{
BOOST_ASSERT(false);
}
template <class Stream>
void do_connect_impl(Stream& stream, const void* endpoint, error_code& ec, std::true_type)
{
stream.lowest_layer().connect(cast_endpoint<Stream>(endpoint), ec);
}
template <class Stream>
void do_connect(Stream& stream, const void* endpoint, error_code& ec)
{
do_connect_impl(stream, endpoint, ec, is_socket_stream<Stream>{});
}
template <class Stream>
void do_async_connect_impl(
Stream&,
const void*,
asio::any_completion_handler<void(error_code)>&&,
std::false_type
)
{
BOOST_ASSERT(false);
}
template <class Stream>
void do_async_connect_impl(
Stream& stream,
const void* endpoint,
asio::any_completion_handler<void(error_code)>&& handler,
std::true_type
)
{
stream.lowest_layer().async_connect(cast_endpoint<Stream>(endpoint), std::move(handler));
}
template <class Stream>
void do_async_connect(
Stream& stream,
const void* endpoint,
asio::any_completion_handler<void(error_code)>&& handler
)
{
do_async_connect_impl(stream, endpoint, std::move(handler), is_socket_stream<Stream>{});
}
template <class Stream>
void do_close_impl(Stream&, error_code&, std::false_type)
{
BOOST_ASSERT(false);
}
template <class Stream>
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 <class Stream>
void do_close(Stream& stream, error_code& ec)
{
do_close_impl(stream, ec, is_socket_stream<Stream>{});
}
template <class Stream>
bool do_is_open_impl(const Stream&, std::false_type) noexcept
{
return false;
}
template <class Stream>
bool do_is_open_impl(const Stream& stream, std::true_type) noexcept
{
return stream.lowest_layer().is_open();
}
template <class Stream>
bool do_is_open(const Stream& stream) noexcept
{
return do_is_open_impl(stream, is_socket_stream<Stream>{});
}
template <class Stream>
class any_stream_impl final : public any_stream
{
Stream stream_;
public:
template <class... Args>
any_stream_impl(Args&&... args) : any_stream(false), stream_(std::forward<Args>(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 { BOOST_ASSERT(false); }
void async_handshake(asio::any_completion_handler<void(error_code)>) final override
{
BOOST_ASSERT(false);
}
void shutdown(error_code&) final override { BOOST_ASSERT(false); }
void async_shutdown(asio::any_completion_handler<void(error_code)>) final override
{
BOOST_ASSERT(false);
}
// Reading
std::size_t read_some(boost::asio::mutable_buffer buff, error_code& ec) final override
{
return stream_.read_some(buff, ec);
}
void async_read_some(
boost::asio::mutable_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> handler
) final override
{
return stream_.async_read_some(buff, std::move(handler));
}
// Writing
std::size_t write_some(boost::asio::const_buffer buff, error_code& ec) final override
{
return stream_.write_some(buff, ec);
}
void async_write_some(
boost::asio::const_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> 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<void(error_code)> 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 Stream>
class any_stream_impl<asio::ssl::stream<Stream>> final : public any_stream
{
asio::ssl::stream<Stream> stream_;
public:
template <class... Args>
any_stream_impl(Args&&... args) : any_stream(true), stream_(std::forward<Args>(args)...)
{
}
asio::ssl::stream<Stream>& stream() noexcept { return stream_; }
const asio::ssl::stream<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(boost::asio::ssl::stream_base::client, ec);
}
void async_handshake(asio::any_completion_handler<void(error_code)> handler) override final
{
set_ssl_active();
stream_.async_handshake(boost::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<void(error_code)> handler) override final
{
return stream_.async_shutdown(std::move(handler));
}
// Reading
std::size_t read_some(boost::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(
boost::asio::mutable_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> 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(boost::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(
boost::asio::const_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> 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<void(error_code)> 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 Stream>
const Stream& cast(const any_stream& obj) noexcept
{
return static_cast<const any_stream_impl<Stream>&>(obj).stream();
}
template <class Stream>
Stream& cast(any_stream& obj) noexcept
{
return static_cast<any_stream_impl<Stream>&>(obj).stream();
}
#ifdef BOOST_MYSQL_SEPARATE_COMPILATION
extern template class any_stream_impl<asio::ssl::stream<asio::ip::tcp::socket>>;
extern template class any_stream_impl<asio::ip::tcp::socket>;
#endif
} // namespace detail
} // namespace mysql
} // namespace boost
// any_stream_impl.ipp explicitly instantiates any_stream_impl, so not included here
#endif