File indexing completed on 2026-08-17 09:00:18
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/redis/config.hpp>
0010 #include <boost/redis/detail/connect_fsm.hpp>
0011 #include <boost/redis/detail/coroutine.hpp>
0012 #include <boost/redis/error.hpp>
0013 #include <boost/redis/impl/log_utils.hpp>
0014
0015 #include <boost/asio/cancellation_type.hpp>
0016 #include <boost/asio/error.hpp>
0017 #include <boost/asio/ip/tcp.hpp>
0018 #include <boost/assert.hpp>
0019
0020 #include <string>
0021
0022 namespace boost::redis::detail {
0023
0024
0025 inline void format_tcp_endpoint(const asio::ip::tcp::endpoint& ep, std::string& to)
0026 {
0027
0028 const auto& addr = ep.address();
0029 if (addr.is_v6())
0030 to += '[';
0031 to += addr.to_string();
0032 if (addr.is_v6())
0033 to += ']';
0034 to += ':';
0035 to += std::to_string(ep.port());
0036 }
0037
0038 template <>
0039 struct log_traits<asio::ip::tcp::endpoint> {
0040 static inline void log(std::string& to, const asio::ip::tcp::endpoint& value)
0041 {
0042 format_tcp_endpoint(value, to);
0043 }
0044 };
0045
0046 template <>
0047 struct log_traits<asio::ip::tcp::resolver::results_type> {
0048 static inline void log(std::string& to, const asio::ip::tcp::resolver::results_type& value)
0049 {
0050 auto iter = value.cbegin();
0051 auto end = value.cend();
0052
0053 if (iter != end) {
0054 format_tcp_endpoint(iter->endpoint(), to);
0055 ++iter;
0056 for (; iter != end; ++iter) {
0057 to += ", ";
0058 format_tcp_endpoint(iter->endpoint(), to);
0059 }
0060 }
0061 }
0062 };
0063
0064 inline transport_type transport_from_config(const config& cfg)
0065 {
0066 if (cfg.unix_socket.empty()) {
0067 if (cfg.use_ssl) {
0068 return transport_type::tcp_tls;
0069 } else {
0070 return transport_type::tcp;
0071 }
0072 } else {
0073 BOOST_ASSERT(!cfg.use_ssl);
0074 return transport_type::unix_socket;
0075 }
0076 }
0077
0078 inline system::error_code translate_timeout_error(
0079 system::error_code io_ec,
0080 asio::cancellation_type_t cancel_state,
0081 error code_if_cancelled)
0082 {
0083
0084
0085
0086
0087
0088
0089
0090
0091 if ((cancel_state & asio::cancellation_type_t::terminal) != asio::cancellation_type_t::none) {
0092 return io_ec ? io_ec : asio::error::operation_aborted;
0093 }
0094 return io_ec == asio::error::operation_aborted ? code_if_cancelled : io_ec;
0095 }
0096
0097 connect_action connect_fsm::resume(
0098 system::error_code ec,
0099 const asio::ip::tcp::resolver::results_type& resolver_results,
0100 redis_stream_state& st,
0101 asio::cancellation_type_t cancel_state)
0102 {
0103
0104 ec = translate_timeout_error(ec, cancel_state, error::resolve_timeout);
0105
0106
0107 if (ec) {
0108 log_info(*lgr_, "Error resolving the server hostname: ", ec);
0109 } else {
0110 log_info(*lgr_, "Resolve results: ", resolver_results);
0111 }
0112
0113
0114 return resume(ec, st, cancel_state);
0115 }
0116
0117 connect_action connect_fsm::resume(
0118 system::error_code ec,
0119 const asio::ip::tcp::endpoint& selected_endpoint,
0120 redis_stream_state& st,
0121 asio::cancellation_type_t cancel_state)
0122 {
0123
0124 ec = translate_timeout_error(ec, cancel_state, error::connect_timeout);
0125
0126
0127 if (ec) {
0128 log_info(*lgr_, "Failed to connect to the server: ", ec);
0129 } else {
0130 log_info(*lgr_, "Connected to ", selected_endpoint);
0131 }
0132
0133
0134 return resume(ec, st, cancel_state);
0135 }
0136
0137 connect_action connect_fsm::resume(
0138 system::error_code ec,
0139 redis_stream_state& st,
0140 asio::cancellation_type_t cancel_state)
0141 {
0142 switch (resume_point_) {
0143 BOOST_REDIS_CORO_INITIAL
0144
0145
0146 st.type = transport_from_config(*cfg_);
0147
0148 if (st.type == transport_type::unix_socket) {
0149
0150 BOOST_REDIS_YIELD(resume_point_, 1, connect_action_type::unix_socket_close)
0151
0152
0153 BOOST_REDIS_YIELD(resume_point_, 2, connect_action_type::unix_socket_connect)
0154
0155
0156
0157
0158
0159 ec = translate_timeout_error(ec, cancel_state, error::connect_timeout);
0160
0161
0162 if (ec) {
0163 log_info(*lgr_, "Failed to connect to the server: ", ec);
0164 } else {
0165 log_info(*lgr_, "Connected to ", cfg_->unix_socket);
0166 }
0167
0168
0169 if (ec) {
0170 return ec;
0171 }
0172
0173
0174 return system::error_code();
0175 } else {
0176
0177
0178
0179
0180
0181 if (cfg_->use_ssl && st.ssl_stream_used) {
0182 BOOST_REDIS_YIELD(resume_point_, 3, connect_action_type::ssl_stream_reset)
0183 }
0184
0185
0186
0187 BOOST_REDIS_YIELD(resume_point_, 4, connect_action_type::tcp_resolve)
0188
0189
0190 if (ec) {
0191 return ec;
0192 }
0193
0194
0195
0196 BOOST_REDIS_YIELD(resume_point_, 5, connect_action_type::tcp_connect)
0197
0198
0199 if (ec) {
0200 return ec;
0201 }
0202
0203 if (cfg_->use_ssl) {
0204
0205 st.ssl_stream_used = true;
0206
0207
0208 BOOST_REDIS_YIELD(resume_point_, 6, connect_action_type::ssl_handshake)
0209
0210
0211 ec = translate_timeout_error(ec, cancel_state, error::ssl_handshake_timeout);
0212
0213
0214 if (ec) {
0215 log_info(*lgr_, "Failed to perform SSL handshake: ", ec);
0216 } else {
0217 log_info(*lgr_, "Successfully performed SSL handshake");
0218 }
0219
0220
0221 if (ec) {
0222 return ec;
0223 }
0224 }
0225
0226
0227 return system::error_code();
0228 }
0229 }
0230
0231 BOOST_ASSERT(false);
0232 return system::error_code();
0233 }
0234
0235 }