File indexing completed on 2025-01-18 09:51:19
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_REDIS_SSL_CONNECTOR_HPP
0008 #define BOOST_REDIS_SSL_CONNECTOR_HPP
0009
0010 #include <boost/redis/detail/helper.hpp>
0011 #include <boost/redis/error.hpp>
0012 #include <boost/asio/compose.hpp>
0013 #include <boost/asio/connect.hpp>
0014 #include <boost/asio/coroutine.hpp>
0015 #include <boost/asio/experimental/parallel_group.hpp>
0016 #include <boost/asio/ip/tcp.hpp>
0017 #include <boost/asio/steady_timer.hpp>
0018 #include <boost/asio/ssl.hpp>
0019 #include <string>
0020 #include <chrono>
0021
0022 namespace boost::redis::detail
0023 {
0024
0025 template <class Handshaker, class Stream>
0026 struct handshake_op {
0027 Handshaker* hsher_ = nullptr;
0028 Stream* stream_ = nullptr;
0029 asio::coroutine coro{};
0030
0031 template <class Self>
0032 void operator()( Self& self
0033 , std::array<std::size_t, 2> const& order = {}
0034 , system::error_code const& ec1 = {}
0035 , system::error_code const& ec2 = {})
0036 {
0037 BOOST_ASIO_CORO_REENTER (coro)
0038 {
0039 hsher_->timer_.expires_after(hsher_->timeout_);
0040
0041 BOOST_ASIO_CORO_YIELD
0042 asio::experimental::make_parallel_group(
0043 [this](auto token) { return stream_->async_handshake(asio::ssl::stream_base::client, token); },
0044 [this](auto token) { return hsher_->timer_.async_wait(token);}
0045 ).async_wait(
0046 asio::experimental::wait_for_one(),
0047 std::move(self));
0048
0049 if (is_cancelled(self)) {
0050 self.complete(asio::error::operation_aborted);
0051 return;
0052 }
0053
0054 switch (order[0]) {
0055 case 0: {
0056 self.complete(ec1);
0057 } break;
0058 case 1:
0059 {
0060 if (ec2) {
0061 self.complete(ec2);
0062 } else {
0063 self.complete(error::ssl_handshake_timeout);
0064 }
0065 } break;
0066
0067 default: BOOST_ASSERT(false);
0068 }
0069 }
0070 }
0071 };
0072
0073 template <class Executor>
0074 class handshaker {
0075 public:
0076 using timer_type =
0077 asio::basic_waitable_timer<
0078 std::chrono::steady_clock,
0079 asio::wait_traits<std::chrono::steady_clock>,
0080 Executor>;
0081
0082 handshaker(Executor ex)
0083 : timer_{ex}
0084 {}
0085
0086 template <class Stream, class CompletionToken>
0087 auto
0088 async_handshake(Stream& stream, CompletionToken&& token)
0089 {
0090 return asio::async_compose
0091 < CompletionToken
0092 , void(system::error_code)
0093 >(handshake_op<handshaker, Stream>{this, &stream}, token, timer_);
0094 }
0095
0096 std::size_t cancel(operation op)
0097 {
0098 switch (op) {
0099 case operation::ssl_handshake:
0100 case operation::all:
0101 timer_.cancel();
0102 break;
0103 default: ;
0104 }
0105
0106 return 0;
0107 }
0108
0109 constexpr bool is_dummy() const noexcept
0110 {return false;}
0111
0112 void set_config(config const& cfg)
0113 { timeout_ = cfg.ssl_handshake_timeout; }
0114
0115 private:
0116 template <class, class> friend struct handshake_op;
0117
0118 timer_type timer_;
0119 std::chrono::steady_clock::duration timeout_;
0120 };
0121
0122 }
0123
0124 #endif