mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Fixes TLS reconnection.
This commit is contained in:
@@ -693,6 +693,11 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php.
|
||||
apps need only one connection for their entire application, which
|
||||
makes the overhead of one ssl-context per connection negligible.
|
||||
|
||||
* ([Issue 169](https://github.com/boostorg/redis/issues/169)).
|
||||
Allows setting a callback that is called before every attempt to
|
||||
stablish a connection or reconnection. See `cpp20_intro_tls.cpp` for
|
||||
an example.
|
||||
|
||||
### Boost 1.84 (First release in Boost)
|
||||
|
||||
* Deprecates the `async_receive` overload that takes a response. Users
|
||||
|
||||
@@ -22,10 +22,16 @@ using boost::redis::connection;
|
||||
|
||||
auto verify_certificate(bool, asio::ssl::verify_context&) -> bool
|
||||
{
|
||||
std::cout << "set_verify_callback" << std::endl;
|
||||
std::cout << "verify_certificate called" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto prepare_callback = [](connection::next_layer_type& stream)
|
||||
{
|
||||
stream.set_verify_mode(asio::ssl::verify_peer);
|
||||
stream.set_verify_callback(verify_certificate);
|
||||
};
|
||||
|
||||
auto co_main(config cfg) -> asio::awaitable<void>
|
||||
{
|
||||
cfg.use_ssl = true;
|
||||
@@ -35,6 +41,7 @@ auto co_main(config cfg) -> asio::awaitable<void>
|
||||
cfg.addr.port = "6380";
|
||||
|
||||
auto conn = std::make_shared<connection>(co_await asio::this_coro::executor);
|
||||
conn->set_prepare_callback(prepare_callback);
|
||||
conn->async_run(cfg, {}, asio::consign(asio::detached, conn));
|
||||
|
||||
request req;
|
||||
@@ -42,9 +49,6 @@ auto co_main(config cfg) -> asio::awaitable<void>
|
||||
|
||||
response<std::string> resp;
|
||||
|
||||
conn->next_layer().set_verify_mode(asio::ssl::verify_peer);
|
||||
conn->next_layer().set_verify_callback(verify_certificate);
|
||||
|
||||
co_await conn->async_exec(req, resp, asio::deferred);
|
||||
conn->cancel();
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ struct reconnection_op {
|
||||
{
|
||||
BOOST_ASIO_CORO_REENTER (coro_) for (;;)
|
||||
{
|
||||
conn_->m_prepare_callback(conn_->next_layer());
|
||||
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
conn_->impl_.async_run(conn_->cfg_, logger_, std::move(self));
|
||||
conn_->cancel(operation::receive);
|
||||
@@ -78,6 +80,15 @@ public:
|
||||
executor_type get_executor() noexcept
|
||||
{ return impl_.get_executor(); }
|
||||
|
||||
/// Next layer type.
|
||||
using next_layer_type = asio::ssl::stream<asio::basic_stream_socket<asio::ip::tcp, Executor>>;
|
||||
|
||||
/** Prepare callback type
|
||||
*
|
||||
* See set_prepare_callback for more information.
|
||||
*/
|
||||
using prepare_callback_type = std::function<void(next_layer_type&)>;
|
||||
|
||||
/// Rebinds the socket type to another executor.
|
||||
template <class Executor1>
|
||||
struct rebind_executor
|
||||
@@ -313,6 +324,30 @@ public:
|
||||
usage get_usage() const noexcept
|
||||
{ return impl_.get_usage(); }
|
||||
|
||||
/** @brief Set the prepare callback
|
||||
*
|
||||
* This callback is called before every new connect or reconnect
|
||||
* attempt. It is specially useful for SSL connections, for example
|
||||
*
|
||||
* @code
|
||||
* auto verify_certificate(bool, asio::ssl::verify_context&) -> bool
|
||||
* {
|
||||
* std::cout << "verify_certificate called" << std::endl;
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* auto prepare_callback = [](connection::next_layer_type& stream)
|
||||
* {
|
||||
* stream.set_verify_mode(asio::ssl::verify_peer);
|
||||
* stream.set_verify_callback(verify_certificate);
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
void set_prepare_callback(prepare_callback_type callback)
|
||||
{
|
||||
m_prepare_callback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
using timer_type =
|
||||
asio::basic_waitable_timer<
|
||||
@@ -325,6 +360,7 @@ private:
|
||||
config cfg_;
|
||||
detail::connection_base<executor_type> impl_;
|
||||
timer_type timer_;
|
||||
prepare_callback_type m_prepare_callback = [](next_layer_type&){ };
|
||||
};
|
||||
|
||||
/** \brief A basic_connection that type erases the executor.
|
||||
@@ -341,6 +377,15 @@ public:
|
||||
/// Executor type.
|
||||
using executor_type = asio::any_io_executor;
|
||||
|
||||
/// Underlying connection type.
|
||||
using underlying_type = basic_connection<executor_type>;
|
||||
|
||||
/// Next layer type.
|
||||
using next_layer_type = underlying_type::next_layer_type;
|
||||
|
||||
/// Prepare callback type
|
||||
using prepare_callback_type = underlying_type::prepare_callback_type;
|
||||
|
||||
/// Contructs from an executor.
|
||||
explicit
|
||||
connection(
|
||||
@@ -429,6 +474,10 @@ public:
|
||||
auto const& get_ssl_context() const noexcept
|
||||
{ return impl_.get_ssl_context();}
|
||||
|
||||
/// Calls `boost::redis::basic_connection::set_prepare_callback`.
|
||||
void set_prepare_callback(prepare_callback_type callback)
|
||||
{ impl_.set_prepare_callback(std::move(callback)); }
|
||||
|
||||
private:
|
||||
void
|
||||
async_run_impl(
|
||||
@@ -436,7 +485,7 @@ private:
|
||||
logger l,
|
||||
asio::any_completion_handler<void(boost::system::error_code)> token);
|
||||
|
||||
basic_connection<executor_type> impl_;
|
||||
underlying_type impl_;
|
||||
};
|
||||
|
||||
} // boost::redis
|
||||
|
||||
@@ -17,6 +17,7 @@ using boost::redis::request;
|
||||
using boost::redis::response;
|
||||
using boost::redis::config;
|
||||
using boost::redis::operation;
|
||||
using boost::redis::ignore;
|
||||
using boost::system::error_code;
|
||||
|
||||
bool verify_certificate(bool, net::ssl::verify_context&)
|
||||
@@ -25,6 +26,12 @@ bool verify_certificate(bool, net::ssl::verify_context&)
|
||||
return true;
|
||||
}
|
||||
|
||||
auto prepare_callback = [](connection::next_layer_type& stream)
|
||||
{
|
||||
stream.set_verify_mode(net::ssl::verify_peer);
|
||||
stream.set_verify_callback(verify_certificate);
|
||||
};
|
||||
|
||||
config make_tls_config()
|
||||
{
|
||||
config cfg;
|
||||
@@ -49,8 +56,7 @@ BOOST_AUTO_TEST_CASE(ping_internal_ssl_context)
|
||||
|
||||
net::io_context ioc;
|
||||
connection conn{ioc};
|
||||
conn.next_layer().set_verify_mode(net::ssl::verify_peer);
|
||||
conn.next_layer().set_verify_callback(verify_certificate);
|
||||
conn.set_prepare_callback(prepare_callback);
|
||||
|
||||
conn.async_exec(req, resp, [&](auto ec, auto) {
|
||||
BOOST_TEST(!ec);
|
||||
@@ -77,8 +83,7 @@ BOOST_AUTO_TEST_CASE(ping_custom_ssl_context)
|
||||
net::io_context ioc;
|
||||
net::ssl::context ctx{boost::asio::ssl::context::tls_client};
|
||||
connection conn{ioc, std::move(ctx)};
|
||||
conn.next_layer().set_verify_mode(net::ssl::verify_peer);
|
||||
conn.next_layer().set_verify_callback(verify_certificate);
|
||||
conn.set_prepare_callback(prepare_callback);
|
||||
|
||||
conn.async_exec(req, resp, [&](auto ec, auto) {
|
||||
BOOST_TEST(!ec);
|
||||
@@ -107,8 +112,7 @@ BOOST_AUTO_TEST_CASE(acl_does_not_allow_select)
|
||||
|
||||
net::io_context ioc;
|
||||
connection conn{ioc};
|
||||
conn.next_layer().set_verify_mode(net::ssl::verify_peer);
|
||||
conn.next_layer().set_verify_callback(verify_certificate);
|
||||
conn.set_prepare_callback(prepare_callback);
|
||||
|
||||
conn.async_exec(req, resp, [&](auto, auto) {
|
||||
// TODO: We should not need this cancel here because
|
||||
@@ -126,3 +130,44 @@ BOOST_AUTO_TEST_CASE(acl_does_not_allow_select)
|
||||
|
||||
BOOST_TEST(!!ec2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(tls_and_reconnection)
|
||||
{
|
||||
net::io_context ioc;
|
||||
connection conn{ioc};
|
||||
|
||||
int counter = 0;
|
||||
auto prepare_callback = [&](auto& stream)
|
||||
{
|
||||
++counter;
|
||||
};
|
||||
|
||||
conn.set_prepare_callback(prepare_callback);
|
||||
|
||||
request req;
|
||||
req.get_config().cancel_on_connection_lost = false;
|
||||
req.push("PING", "str1");
|
||||
req.push("QUIT");
|
||||
|
||||
conn.async_exec(req, ignore, [&](auto ec, auto) {
|
||||
std::cout << "First: " << ec.message() << std::endl;
|
||||
BOOST_TEST(!ec);
|
||||
conn.async_exec(req, ignore, [&](auto ec, auto) {
|
||||
std::cout << "Second: " << ec.message() << std::endl;
|
||||
BOOST_TEST(!ec);
|
||||
conn.async_exec(req, ignore, [&](auto ec, auto) {
|
||||
std::cout << "Third: " << ec.message() << std::endl;
|
||||
BOOST_TEST(!ec);
|
||||
conn.cancel();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
auto const cfg = make_tls_config();
|
||||
conn.async_run(cfg, {}, [](auto) { });
|
||||
|
||||
ioc.run();
|
||||
|
||||
BOOST_CHECK_EQUAL(counter, 3);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user