Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:19

0001 /* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
0002  *
0003  * Distributed under the Boost Software License, Version 1.0. (See
0004  * accompanying file LICENSE.txt)
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: /* ignore */;
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 } // boost::redis::detail
0123 
0124 #endif // BOOST_REDIS_SSL_CONNECTOR_HPP