boost_redis 1.4.2
A redis client library
handshaker.hpp
1/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
2 *
3 * Distributed under the Boost Software License, Version 1.0. (See
4 * accompanying file LICENSE.txt)
5 */
6
7#ifndef BOOST_REDIS_SSL_CONNECTOR_HPP
8#define BOOST_REDIS_SSL_CONNECTOR_HPP
9
10#include <boost/redis/detail/helper.hpp>
11#include <boost/redis/error.hpp>
12#include <boost/asio/compose.hpp>
13#include <boost/asio/connect.hpp>
14#include <boost/asio/coroutine.hpp>
15#include <boost/asio/experimental/parallel_group.hpp>
16#include <boost/asio/ip/tcp.hpp>
17#include <boost/asio/steady_timer.hpp>
18#include <boost/asio/ssl.hpp>
19#include <string>
20#include <chrono>
21
22namespace boost::redis::detail
23{
24
25template <class Handshaker, class Stream>
26struct handshake_op {
27 Handshaker* hsher_ = nullptr;
28 Stream* stream_ = nullptr;
29 asio::coroutine coro{};
30
31 template <class Self>
32 void operator()( Self& self
33 , std::array<std::size_t, 2> const& order = {}
34 , system::error_code const& ec1 = {}
35 , system::error_code const& ec2 = {})
36 {
37 BOOST_ASIO_CORO_REENTER (coro)
38 {
39 hsher_->timer_.expires_after(hsher_->timeout_);
40
41 BOOST_ASIO_CORO_YIELD
42 asio::experimental::make_parallel_group(
43 [this](auto token) { return stream_->async_handshake(asio::ssl::stream_base::client, token); },
44 [this](auto token) { return hsher_->timer_.async_wait(token);}
45 ).async_wait(
46 asio::experimental::wait_for_one(),
47 std::move(self));
48
49 if (is_cancelled(self)) {
50 self.complete(asio::error::operation_aborted);
51 return;
52 }
53
54 switch (order[0]) {
55 case 0: {
56 self.complete(ec1);
57 } break;
58 case 1:
59 {
60 if (ec2) {
61 self.complete(ec2);
62 } else {
63 self.complete(error::ssl_handshake_timeout);
64 }
65 } break;
66
67 default: BOOST_ASSERT(false);
68 }
69 }
70 }
71};
72
73template <class Executor>
74class handshaker {
75public:
76 using timer_type =
77 asio::basic_waitable_timer<
78 std::chrono::steady_clock,
79 asio::wait_traits<std::chrono::steady_clock>,
80 Executor>;
81
82 handshaker(Executor ex)
83 : timer_{ex}
84 {}
85
86 template <class Stream, class CompletionToken>
87 auto
88 async_handshake(Stream& stream, CompletionToken&& token)
89 {
90 return asio::async_compose
91 < CompletionToken
92 , void(system::error_code)
93 >(handshake_op<handshaker, Stream>{this, &stream}, token, timer_);
94 }
95
96 std::size_t cancel(operation op)
97 {
98 switch (op) {
100 case operation::all:
101 timer_.cancel();
102 break;
103 default: /* ignore */;
104 }
105
106 return 0;
107 }
108
109 constexpr bool is_dummy() const noexcept
110 {return false;}
111
112 void set_config(config const& cfg)
113 { timeout_ = cfg.ssl_handshake_timeout; }
114
115private:
116 template <class, class> friend struct handshake_op;
117
118 timer_type timer_;
119 std::chrono::steady_clock::duration timeout_;
120};
121
122} // boost::redis::detail
123
124#endif // BOOST_REDIS_SSL_CONNECTOR_HPP
operation
Connection operations that can be cancelled.
Definition: operation.hpp:18
@ ssl_handshake_timeout
SSL handshake timeout.
@ ssl_handshake
SSL handshake operation.
@ all
Refers to all operations.