Commit 3d232106 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/neverlord/caf-net-additions'

parents a0c97282 617955aa
...@@ -19,8 +19,12 @@ ...@@ -19,8 +19,12 @@
// -- convenience type aliases ------------------------------------------------- // -- convenience type aliases -------------------------------------------------
// The trait for translating between bytes on the wire and flow items. The
// binary default trait operates on binary::frame items.
using trait = caf::net::binary::default_trait;
// Takes care converting a byte stream into a sequence of messages on the wire. // Takes care converting a byte stream into a sequence of messages on the wire.
using lpf = caf::net::length_prefix_framing; using lpf = caf::net::length_prefix_framing::bind<trait>;
// An implicitly shared type for storing a binary frame. // An implicitly shared type for storing a binary frame.
using bin_frame = caf::net::binary::frame; using bin_frame = caf::net::binary::frame;
......
...@@ -17,8 +17,12 @@ ...@@ -17,8 +17,12 @@
// -- convenience type aliases ------------------------------------------------- // -- convenience type aliases -------------------------------------------------
// The trait for translating between bytes on the wire and flow items. The
// binary default trait operates on binary::frame items.
using trait = caf::net::binary::default_trait;
// Takes care converting a byte stream into a sequence of messages on the wire. // Takes care converting a byte stream into a sequence of messages on the wire.
using lpf = caf::net::length_prefix_framing; using lpf = caf::net::length_prefix_framing::bind<trait>;
// An implicitly shared type for storing a binary frame. // An implicitly shared type for storing a binary frame.
using bin_frame = caf::net::binary::frame; using bin_frame = caf::net::binary::frame;
......
...@@ -75,7 +75,8 @@ int caf_main(actor_system& sys, const config& cfg) { ...@@ -75,7 +75,8 @@ int caf_main(actor_system& sys, const config& cfg) {
auto [lpf_pull, app_push] = make_spsc_buffer_resource<bin_frame>(); auto [lpf_pull, app_push] = make_spsc_buffer_resource<bin_frame>();
auto [app_pull, lpf_push] = make_spsc_buffer_resource<bin_frame>(); auto [app_pull, lpf_push] = make_spsc_buffer_resource<bin_frame>();
// Spin up the network backend. // Spin up the network backend.
using lpf = caf::net::length_prefix_framing; using trait = caf::net::binary::default_trait;
using lpf = caf::net::length_prefix_framing::bind<trait>;
auto conn = lpf::run(sys, *fd, std::move(lpf_pull), std::move(lpf_push)); auto conn = lpf::run(sys, *fd, std::move(lpf_pull), std::move(lpf_push));
// Spin up Qt. // Spin up Qt.
auto [argc, argv] = cfg.c_args_remainder(); auto [argc, argv] = cfg.c_args_remainder();
......
...@@ -140,6 +140,11 @@ public: ...@@ -140,6 +140,11 @@ public:
impl_->cancel(); impl_->cancel();
} }
consumer_adapter& operator=(std::nullptr_t) {
impl_ = nullptr;
return *this;
}
template <class Policy> template <class Policy>
read_result pull(Policy policy, T& result) { read_result pull(Policy policy, T& result) {
if (impl_) if (impl_)
......
...@@ -107,6 +107,11 @@ public: ...@@ -107,6 +107,11 @@ public:
// nop // nop
} }
producer_adapter& operator=(std::nullptr_t) {
impl_ = nullptr;
return *this;
}
~producer_adapter() { ~producer_adapter() {
if (impl_) if (impl_)
impl_->close(); impl_->close();
......
...@@ -607,6 +607,9 @@ auto observable<T>::merge(Inputs&&... xs) { ...@@ -607,6 +607,9 @@ auto observable<T>::merge(Inputs&&... xs) {
static_assert( static_assert(
sizeof...(Inputs) > 0, sizeof...(Inputs) > 0,
"merge without arguments expects this observable to emit observables"); "merge without arguments expects this observable to emit observables");
static_assert(
(std::is_same_v<Out, output_type_t<std::decay_t<Inputs>>> && ...),
"can only merge observables with the same observed type");
using impl_t = op::merge<Out>; using impl_t = op::merge<Out>;
return make_observable<impl_t>(ctx(), *this, std::forward<Inputs>(xs)...); return make_observable<impl_t>(ctx(), *this, std::forward<Inputs>(xs)...);
} }
...@@ -622,7 +625,10 @@ auto observable<T>::concat(Inputs&&... xs) { ...@@ -622,7 +625,10 @@ auto observable<T>::concat(Inputs&&... xs) {
} else { } else {
static_assert( static_assert(
sizeof...(Inputs) > 0, sizeof...(Inputs) > 0,
"merge without arguments expects this observable to emit observables"); "concat without arguments expects this observable to emit observables");
static_assert(
(std::is_same_v<Out, output_type_t<std::decay_t<Inputs>>> && ...),
"can only concatenate observables with the same observed type");
using impl_t = op::concat<Out>; using impl_t = op::concat<Out>;
return make_observable<impl_t>(ctx(), *this, std::forward<Inputs>(xs)...); return make_observable<impl_t>(ctx(), *this, std::forward<Inputs>(xs)...);
} }
......
...@@ -67,9 +67,11 @@ caf_add_component( ...@@ -67,9 +67,11 @@ caf_add_component(
src/net/ssl/context.cpp src/net/ssl/context.cpp
src/net/ssl/dtls.cpp src/net/ssl/dtls.cpp
src/net/ssl/format.cpp src/net/ssl/format.cpp
src/net/ssl/password.cpp
src/net/ssl/startup.cpp src/net/ssl/startup.cpp
src/net/ssl/tls.cpp src/net/ssl/tls.cpp
src/net/ssl/transport.cpp src/net/ssl/transport.cpp
src/net/ssl/verify.cpp
src/net/stream_oriented.cpp src/net/stream_oriented.cpp
src/net/stream_socket.cpp src/net/stream_socket.cpp
src/net/stream_transport.cpp src/net/stream_transport.cpp
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/async/consumer_adapter.hpp"
#include "caf/async/producer_adapter.hpp"
#include "caf/async/spsc_buffer.hpp"
#include "caf/fwd.hpp"
#include "caf/net/flow_connector.hpp"
#include "caf/sec.hpp"
#include <utility>
namespace caf::detail {
/// Translates between a message-oriented transport and data flows.
template <class UpperLayer, class LowerLayer, class Trait>
class flow_bridge_base : public UpperLayer {
public:
using input_type = typename Trait::input_type;
using output_type = typename Trait::output_type;
/// Type for the consumer adapter. We consume the output of the application.
using consumer_type = async::consumer_adapter<output_type>;
/// Type for the producer adapter. We produce the input of the application.
using producer_type = async::producer_adapter<input_type>;
using connector_pointer = net::flow_connector_ptr<Trait>;
flow_bridge_base(async::execution_context_ptr loop, connector_pointer conn)
: loop_(std::move(loop)), conn_(std::move(conn)) {
// nop
}
virtual bool write(const output_type& item) = 0;
bool running() const noexcept {
return in_ || out_;
}
void self_ref(disposable ref) {
self_ref_ = std::move(ref);
}
// -- implementation of the lower_layer --------------------------------------
error start(LowerLayer* down, const settings& cfg) override {
CAF_ASSERT(down != nullptr);
down_ = down;
auto [err, pull, push] = conn_->on_request(cfg);
if (!err) {
auto do_wakeup = make_action([this] {
if (running())
prepare_send();
});
auto do_resume = make_action([this] { down_->request_messages(); });
auto do_cancel = make_action([this] {
if (!running()) {
down_->shutdown();
}
});
in_ = consumer_type::make(pull.try_open(), loop_, std::move(do_wakeup));
out_ = producer_type::make(push.try_open(), loop_, std::move(do_resume),
std::move(do_cancel));
conn_ = nullptr;
if (running())
return none;
else
return make_error(sec::runtime_error,
"cannot init flow bridge: no buffers");
} else {
conn_ = nullptr;
return err;
}
}
void prepare_send() override {
input_type tmp;
while (down_->can_send_more()) {
switch (in_.pull(async::delay_errors, tmp)) {
case async::read_result::ok:
if (!write(tmp)) {
abort(trait_.last_error());
down_->shutdown(trait_.last_error());
return;
}
break;
case async::read_result::stop:
in_ = nullptr;
abort(error{});
down_->shutdown();
return;
case async::read_result::abort:
in_ = nullptr;
abort(in_.abort_reason());
down_->shutdown(in_.abort_reason());
return;
default: // try later
return;
}
}
}
bool done_sending() override {
return !in_.has_consumer_event();
}
void abort(const error& reason) override {
CAF_LOG_TRACE(CAF_ARG(reason));
if (out_) {
if (!reason || reason == sec::connection_closed
|| reason == sec::socket_disconnected || reason == sec::disposed)
out_.close();
else
out_.abort(reason);
out_ = nullptr;
}
if (in_) {
in_.cancel();
in_ = nullptr;
}
self_ref_ = nullptr;
}
protected:
LowerLayer* down_;
/// The output of the application. Serialized to the socket.
consumer_type in_;
/// The input to the application. Deserialized from the socket.
producer_type out_;
/// Converts between raw bytes and native C++ objects.
Trait trait_;
/// Our event loop.
async::execution_context_ptr loop_;
/// Initializes the bridge. Disposed (set to null) after initializing.
connector_pointer conn_;
/// Type-erased handle to the @ref socket_manager. This reference is important
/// to keep the bridge alive while the manager is not registered for writing
/// or reading.
disposable self_ref_;
};
} // namespace caf::detail
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "caf/async/consumer_adapter.hpp" #include "caf/async/consumer_adapter.hpp"
#include "caf/async/producer_adapter.hpp" #include "caf/async/producer_adapter.hpp"
#include "caf/async/spsc_buffer.hpp" #include "caf/async/spsc_buffer.hpp"
#include "caf/detail/flow_bridge_base.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/net/binary/lower_layer.hpp" #include "caf/net/binary/lower_layer.hpp"
#include "caf/net/binary/upper_layer.hpp" #include "caf/net/binary/upper_layer.hpp"
...@@ -17,153 +18,48 @@ ...@@ -17,153 +18,48 @@
namespace caf::net::binary { namespace caf::net::binary {
/// Convenience alias for referring to the base type of @ref flow_bridge.
template <class Trait>
using flow_bridge_base_t
= detail::flow_bridge_base<upper_layer, lower_layer, Trait>;
/// Translates between a message-oriented transport and data flows. /// Translates between a message-oriented transport and data flows.
template <class Trait> template <class Trait>
class flow_bridge : public upper_layer { class flow_bridge : public flow_bridge_base_t<Trait> {
public: public:
using super = flow_bridge_base_t<Trait>;
using input_type = typename Trait::input_type; using input_type = typename Trait::input_type;
using output_type = typename Trait::output_type; using output_type = typename Trait::output_type;
/// Type for the consumer adapter. We consume the output of the application.
using consumer_type = async::consumer_adapter<output_type>;
/// Type for the producer adapter. We produce the input of the application.
using producer_type = async::producer_adapter<input_type>;
using connector_pointer = flow_connector_ptr<Trait>; using connector_pointer = flow_connector_ptr<Trait>;
explicit flow_bridge(async::execution_context_ptr loop, using super::super;
connector_pointer conn)
: loop_(std::move(loop)), conn_(std::move(conn)) {
// nop
}
static std::unique_ptr<flow_bridge> make(async::execution_context_ptr loop, static std::unique_ptr<flow_bridge> make(async::execution_context_ptr loop,
connector_pointer conn) { connector_pointer conn) {
return std::make_unique<flow_bridge>(std::move(loop), std::move(conn)); return std::make_unique<flow_bridge>(std::move(loop), std::move(conn));
} }
bool write(const output_type& item) { bool write(const output_type& item) override {
down_->begin_message(); super::down_->begin_message();
auto& bytes = down_->message_buffer(); auto& bytes = super::down_->message_buffer();
return trait_.convert(item, bytes) && down_->end_message(); return super::trait_.convert(item, bytes) && super::down_->end_message();
}
bool running() const noexcept {
return in_ || out_;
}
void self_ref(disposable ref) {
self_ref_ = std::move(ref);
} }
// -- implementation of binary::lower_layer ---------------------------------- // -- implementation of binary::lower_layer ----------------------------------
error start(binary::lower_layer* down, const settings& cfg) override {
CAF_ASSERT(down != nullptr);
down_ = down;
auto [err, pull, push] = conn_->on_request(cfg);
if (!err) {
auto do_wakeup = make_action([this] {
prepare_send();
if (!running())
down_->shutdown();
});
auto do_resume = make_action([this] { down_->request_messages(); });
auto do_cancel = make_action([this] {
if (!running()) {
down_->shutdown();
}
});
in_ = consumer_type::make(pull.try_open(), loop_, std::move(do_wakeup));
out_ = producer_type::make(push.try_open(), loop_, std::move(do_resume),
std::move(do_cancel));
conn_ = nullptr;
if (in_ && out_) {
return none;
} else {
return make_error(sec::runtime_error,
"cannot init flow bridge: no buffers");
}
} else {
conn_ = nullptr;
return err;
}
}
void prepare_send() override {
input_type tmp;
while (down_->can_send_more()) {
switch (in_.pull(async::delay_errors, tmp)) {
case async::read_result::ok:
if (!write(tmp)) {
down_->shutdown(trait_.last_error());
return;
}
break;
case async::read_result::stop:
down_->shutdown();
break;
case async::read_result::abort:
down_->shutdown(in_.abort_reason());
break;
default: // try later
return;
}
}
}
bool done_sending() override {
return !in_.has_consumer_event();
}
void abort(const error& reason) override {
CAF_LOG_TRACE(CAF_ARG(reason));
if (out_) {
if (reason == sec::connection_closed || reason == sec::socket_disconnected
|| reason == sec::disposed)
out_.close();
else
out_.abort(reason);
}
in_.cancel();
self_ref_ = nullptr;
}
ptrdiff_t consume(byte_span buf) override { ptrdiff_t consume(byte_span buf) override {
if (!out_) if (!super::out_)
return -1; return -1;
input_type val; input_type val;
if (!trait_.convert(buf, val)) if (!super::trait_.convert(buf, val))
return -1; return -1;
if (out_.push(std::move(val)) == 0) if (super::out_.push(std::move(val)) == 0)
down_->suspend_reading(); super::down_->suspend_reading();
return static_cast<ptrdiff_t>(buf.size()); return static_cast<ptrdiff_t>(buf.size());
} }
private:
lower_layer* down_;
/// The output of the application. Serialized to the socket.
consumer_type in_;
/// The input to the application. Deserialized from the socket.
producer_type out_;
/// Converts between raw bytes and native C++ objects.
Trait trait_;
/// Our event loop.
async::execution_context_ptr loop_;
/// Initializes the bridge. Disposed (set to null) after initializing.
connector_pointer conn_;
/// Type-erased handle to the @ref socket_manager. This reference is important
/// to keep the bridge alive while the manager is not registered for writing
/// or reading.
disposable self_ref_;
}; };
} // namespace caf::net::binary } // namespace caf::net::binary
...@@ -56,27 +56,32 @@ public: ...@@ -56,27 +56,32 @@ public:
// -- high-level factory functions ------------------------------------------- // -- high-level factory functions -------------------------------------------
/// Binds a trait class to the framing protocol to enable a high-level API for
/// operating on flows.
template <class Trait>
struct bind {
/// Describes the one-time connection event. /// Describes the one-time connection event.
using connect_event_t using connect_event_t
= cow_tuple<async::consumer_resource<binary::frame>, // Socket to App. = cow_tuple<async::consumer_resource<typename Trait::input_type>,
async::producer_resource<binary::frame>>; // App to Socket. async::producer_resource<typename Trait::output_type>>;
/// Runs length-prefix framing on given connection. /// Runs length-prefix framing on given connection.
/// @param sys The host system. /// @param sys The host system.
/// @param conn A connected stream socket or SSL connection, depending on the /// @param conn A connected stream socket or SSL connection, depending on
/// the
/// `Transport`. /// `Transport`.
/// @param pull Source for pulling data to send. /// @param pull Source for pulling data to send.
/// @param push Source for pushing received data. /// @param push Source for pushing received data.
template <class Connection> template <class Connection>
static disposable run(actor_system& sys, Connection conn, static disposable
async::consumer_resource<binary::frame> pull, run(actor_system& sys, Connection conn,
async::producer_resource<binary::frame> push) { async::consumer_resource<typename Trait::output_type> pull,
using trait_t = binary::default_trait; async::producer_resource<typename Trait::input_type> push) {
using transport_t = typename Connection::transport_type; using transport_t = typename Connection::transport_type;
auto mpx = sys.network_manager().mpx_ptr(); auto mpx = sys.network_manager().mpx_ptr();
auto fc = flow_connector<trait_t>::make_trivial(std::move(pull), auto fc = flow_connector<Trait>::make_trivial(std::move(pull),
std::move(push)); std::move(push));
auto bridge = binary::flow_bridge<trait_t>::make(mpx, std::move(fc)); auto bridge = binary::flow_bridge<Trait>::make(mpx, std::move(fc));
auto bridge_ptr = bridge.get(); auto bridge_ptr = bridge.get();
auto impl = length_prefix_framing::make(std::move(bridge)); auto impl = length_prefix_framing::make(std::move(bridge));
auto transport = transport_t::make(std::move(conn), std::move(impl)); auto transport = transport_t::make(std::move(conn), std::move(impl));
...@@ -88,16 +93,18 @@ public: ...@@ -88,16 +93,18 @@ public:
/// Runs length-prefix framing on given connection. /// Runs length-prefix framing on given connection.
/// @param sys The host system. /// @param sys The host system.
/// @param conn A connected stream socket or SSL connection, depending on the /// @param conn A connected stream socket or SSL connection, depending on
/// the
/// `Transport`. /// `Transport`.
/// @param init Function object for setting up the created flows. /// @param init Function object for setting up the created flows.
template <class Connection, class Init> template <class Connection, class Init>
static disposable run(actor_system& sys, Connection conn, Init init) { static disposable run(actor_system& sys, Connection conn, Init init) {
using app_in_t = typename Trait::input_type;
using app_out_t = typename Trait::output_type;
static_assert(std::is_invocable_v<Init, connect_event_t&&>, static_assert(std::is_invocable_v<Init, connect_event_t&&>,
"invalid signature found for init"); "invalid signature found for init");
using frame_t = binary::frame; auto [app_pull, fd_push] = async::make_spsc_buffer_resource<app_in_t>();
auto [fd_pull, app_push] = async::make_spsc_buffer_resource<frame_t>(); auto [fd_pull, app_push] = async::make_spsc_buffer_resource<app_out_t>();
auto [app_pull, fd_push] = async::make_spsc_buffer_resource<frame_t>();
auto result = run(sys, std::move(conn), std::move(fd_pull), auto result = run(sys, std::move(conn), std::move(fd_pull),
std::move(fd_push)); std::move(fd_push));
init(connect_event_t{std::move(app_pull), std::move(app_push)}); init(connect_event_t{std::move(app_pull), std::move(app_push)});
...@@ -113,12 +120,11 @@ public: ...@@ -113,12 +120,11 @@ public:
/// Describes the per-connection event. /// Describes the per-connection event.
using accept_event_t using accept_event_t
= cow_tuple<async::consumer_resource<binary::frame>, // Socket to App. = cow_tuple<async::consumer_resource<typename Trait::input_type>,
async::producer_resource<binary::frame>>; // App to Socket. async::producer_resource<typename Trait::output_type>>;
/// Convenience function for creating an event listener resource and an /// Convenience function for creating an event listener resource and an
/// @ref acceptor_resource_t via @ref async::make_spsc_buffer_resource. /// @ref acceptor_resource_t via @ref async::make_spsc_buffer_resource.
template <class... Ts>
static auto make_accept_event_resources() { static auto make_accept_event_resources() {
return async::make_spsc_buffer_resource<accept_event_t>(); return async::make_spsc_buffer_resource<accept_event_t>();
} }
...@@ -131,7 +137,8 @@ public: ...@@ -131,7 +137,8 @@ public:
/// configuration parameter is `max-connections`. /// configuration parameter is `max-connections`.
template <class Acceptor> template <class Acceptor>
static disposable accept(actor_system& sys, Acceptor acc, static disposable accept(actor_system& sys, Acceptor acc,
acceptor_resource_t out, const settings& cfg = {}) { acceptor_resource_t out,
const settings& cfg = {}) {
using transport_t = typename Acceptor::transport_type; using transport_t = typename Acceptor::transport_type;
using trait_t = binary::default_trait; using trait_t = binary::default_trait;
using factory_t = cf_impl<transport_t>; using factory_t = cf_impl<transport_t>;
...@@ -153,6 +160,7 @@ public: ...@@ -153,6 +160,7 @@ public:
return {}; return {};
} }
} }
};
// -- implementation of stream_oriented::upper_layer ------------------------- // -- implementation of stream_oriented::upper_layer -------------------------
......
...@@ -4,10 +4,6 @@ ...@@ -4,10 +4,6 @@
#pragma once #pragma once
#include <memory>
#include <mutex>
#include <thread>
#include "caf/action.hpp" #include "caf/action.hpp"
#include "caf/async/execution_context.hpp" #include "caf/async/execution_context.hpp"
#include "caf/detail/atomic_ref_counted.hpp" #include "caf/detail/atomic_ref_counted.hpp"
...@@ -19,6 +15,11 @@ ...@@ -19,6 +15,11 @@
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
#include "caf/unordered_flat_map.hpp" #include "caf/unordered_flat_map.hpp"
#include <deque>
#include <memory>
#include <mutex>
#include <thread>
extern "C" { extern "C" {
struct pollfd; struct pollfd;
...@@ -150,6 +151,9 @@ public: ...@@ -150,6 +151,9 @@ public:
/// Applies all pending updates. /// Applies all pending updates.
void apply_updates(); void apply_updates();
/// Runs all pending actions.
void run_actions();
/// Sets the thread ID to `std::this_thread::id()`. /// Sets the thread ID to `std::this_thread::id()`.
void set_thread_id(); void set_thread_id();
...@@ -213,6 +217,9 @@ protected: ...@@ -213,6 +217,9 @@ protected:
/// Signals whether shutdown has been requested. /// Signals whether shutdown has been requested.
bool shutting_down_ = false; bool shutting_down_ = false;
/// Pending actions via `schedule`.
std::deque<action> pending_actions_;
/// Keeps track of watched disposables. /// Keeps track of watched disposables.
std::vector<disposable> watched_; std::vector<disposable> watched_;
......
...@@ -69,7 +69,7 @@ public: ...@@ -69,7 +69,7 @@ public:
/// from a client. /// from a client.
[[nodiscard]] ptrdiff_t accept(); [[nodiscard]] ptrdiff_t accept();
/// Gracefully closes the SSL connection. /// Gracefully closes the SSL connection without closing the socket.
ptrdiff_t close(); ptrdiff_t close();
// -- reading and writing ---------------------------------------------------- // -- reading and writing ----------------------------------------------------
......
...@@ -8,9 +8,12 @@ ...@@ -8,9 +8,12 @@
#include "caf/net/ssl/dtls.hpp" #include "caf/net/ssl/dtls.hpp"
#include "caf/net/ssl/format.hpp" #include "caf/net/ssl/format.hpp"
#include "caf/net/ssl/fwd.hpp" #include "caf/net/ssl/fwd.hpp"
#include "caf/net/ssl/password.hpp"
#include "caf/net/ssl/tls.hpp" #include "caf/net/ssl/tls.hpp"
#include "caf/net/ssl/verify.hpp"
#include "caf/net/stream_socket.hpp" #include "caf/net/stream_socket.hpp"
#include <cstring>
#include <string> #include <string>
namespace caf::net::ssl { namespace caf::net::ssl {
...@@ -27,6 +30,9 @@ public: ...@@ -27,6 +30,9 @@ public:
/// The opaque implementation type. /// The opaque implementation type.
struct impl; struct impl;
/// Stores additional data provided by the user.
struct user_data;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
context() = delete; context() = delete;
...@@ -65,6 +71,30 @@ public: ...@@ -65,6 +71,30 @@ public:
return pimpl_ == nullptr; return pimpl_ == nullptr;
} }
/// Overrides the verification mode for this context.
/// @note calls @c SSL_CTX_set_verify
void set_verify_mode(verify_t flags);
/// Overrides the callback to obtain the password for encrypted PEM files.
/// @note calls @c SSL_CTX_set_default_passwd_cb
template <typename PasswordCallback>
void set_password_callback(PasswordCallback callback) {
set_password_callback_impl(password::make_callback(std::move(callback)));
}
/// Overrides the callback to obtain the password for encrypted PEM files with
/// a function that always returns @p password.
/// @note calls @c SSL_CTX_set_default_passwd_cb
void set_password(std::string password) {
auto cb = [pw = std::move(password)](char* buf, int len,
password::purpose) {
strncpy(buf, pw.c_str(), static_cast<size_t>(len));
buf[len - 1] = '\0';
return static_cast<int>(pw.size());
};
set_password_callback(std::move(cb));
}
// -- native handles --------------------------------------------------------- // -- native handles ---------------------------------------------------------
/// Reinterprets `native_handle` as the native implementation type and takes /// Reinterprets `native_handle` as the native implementation type and takes
...@@ -111,29 +141,57 @@ public: ...@@ -111,29 +141,57 @@ public:
/// e.g., `9d66eef0.0` and `9d66eef0.1`. /// e.g., `9d66eef0.0` and `9d66eef0.1`.
/// @returns `true` on success, `false` otherwise and `last_error` can be used /// @returns `true` on success, `false` otherwise and `last_error` can be used
/// to retrieve a human-readable error representation. /// to retrieve a human-readable error representation.
[[nodiscard]] bool load_verify_dir(const char* path); /// @note Calls @c SSL_CTX_load_verify_locations
[[nodiscard]] bool add_verify_path(const char* path);
/// @copydoc add_verify_path
[[nodiscard]] bool add_verify_path(const std::string& path) {
return add_verify_path(path.c_str());
}
/// Loads a CA certificate file. /// Loads a CA certificate file.
/// @param path Null-terminated string with a path to a single PEM file. /// @param path Null-terminated string with a path to a single PEM file.
/// @returns `true` on success, `false` otherwise and `last_error` can be used /// @returns `true` on success, `false` otherwise and `last_error` can be used
/// to retrieve a human-readable error representation. /// to retrieve a human-readable error representation.
/// @note Calls @c SSL_CTX_load_verify_locations
[[nodiscard]] bool load_verify_file(const char* path); [[nodiscard]] bool load_verify_file(const char* path);
/// @copydoc load_verify_file
[[nodiscard]] bool load_verify_file(const std::string& path) {
return load_verify_file(path.c_str());
}
/// Loads the first certificate found in given file. /// Loads the first certificate found in given file.
/// @param path Null-terminated string with a path to a single PEM file. /// @param path Null-terminated string with a path to a single PEM file.
[[nodiscard]] bool use_certificate_from_file(const char* path, [[nodiscard]] bool use_certificate_file(const char* path, format file_format);
format file_format);
/// Loads a certificate chain from a PEM-formatted file.
/// @note calls @c SSL_CTX_use_certificate_chain_file
[[nodiscard]] bool use_certificate_chain_file(const char* path);
/// @copydoc use_certificate_chain_file
[[nodiscard]] bool use_certificate_chain_file(const std::string& path) {
return use_certificate_chain_file(path.c_str());
}
/// Loads the first private key found in given file. /// Loads the first private key found in given file.
[[nodiscard]] bool use_private_key_from_file(const char* path, [[nodiscard]] bool use_private_key_file(const char* path, format file_format);
format file_format);
/// @copydoc use_private_key_file
[[nodiscard]] bool use_private_key_file(const std::string& path,
format file_format) {
return use_private_key_file(path.c_str(), file_format);
}
private: private:
constexpr explicit context(impl* ptr) : pimpl_(ptr) { constexpr explicit context(impl* ptr) : pimpl_(ptr) {
// nop // nop
} }
void set_password_callback_impl(password::callback_ptr callback);
impl* pimpl_; impl* pimpl_;
user_data* data_ = nullptr;
}; };
} // namespace caf::net::ssl } // namespace caf::net::ssl
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/default_enum_inspect.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/fwd.hpp"
#include <memory>
namespace caf::net::ssl::password {
/// Purpose of PEM password.
enum class purpose {
/// SSL asks the password is reading/decryption.
reading,
/// SSL asks the password is for writing/encryption.
writing
};
class CAF_NET_EXPORT callback {
public:
virtual ~callback();
/// Reads the password into the buffer @p buf of size @p len.
/// @returns Written characters on success, -1 otherwise.
virtual int operator()(char* buf, int len, purpose flag) = 0;
};
using callback_ptr = std::unique_ptr<callback>;
template <class PasswordCallback>
callback_ptr make_callback(PasswordCallback callback) {
struct impl : callback {
explicit impl(PasswordCallback&& cb) : cb_(std::move(cb)) {
// nop
}
int operator()(char* buf, int len, purpose flag) override {
return cb_(buf, len, flag);
}
PasswordCallback cb_;
};
return std::make_unique<impl>(std::move(callback));
}
} // namespace caf::net::ssl::password
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/default_enum_inspect.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/fwd.hpp"
#include <string>
namespace caf::net::ssl {
/// Bitmask type for the SSL verification mode.
enum class verify_t {};
namespace verify {
CAF_NET_EXPORT extern const verify_t none;
CAF_NET_EXPORT extern const verify_t peer;
CAF_NET_EXPORT extern const verify_t fail_if_no_peer_cert;
CAF_NET_EXPORT extern const verify_t client_once;
} // namespace verify
constexpr int to_integer(verify_t x) {
return static_cast<int>(x);
}
inline verify_t& operator|=(verify_t& x, verify_t y) noexcept {
return x = static_cast<verify_t>(to_integer(x) | to_integer(y));
}
constexpr verify_t operator|(verify_t x, verify_t y) noexcept {
return static_cast<verify_t>(to_integer(x) | to_integer(y));
}
} // namespace caf::net::ssl
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "caf/detail/accept_handler.hpp" #include "caf/detail/accept_handler.hpp"
#include "caf/detail/connection_factory.hpp" #include "caf/detail/connection_factory.hpp"
#include "caf/net/flow_connector.hpp" #include "caf/net/flow_connector.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/ssl/acceptor.hpp" #include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/transport.hpp" #include "caf/net/ssl/transport.hpp"
#include "caf/net/web_socket/default_trait.hpp" #include "caf/net/web_socket/default_trait.hpp"
...@@ -36,6 +37,10 @@ using accept_event_t ...@@ -36,6 +37,10 @@ using accept_event_t
template <class... Ts> template <class... Ts>
using acceptor_resource_t = async::producer_resource<accept_event_t<Ts...>>; using acceptor_resource_t = async::producer_resource<accept_event_t<Ts...>>;
/// A consumer resource for processing accepted connections.
template <class... Ts>
using listener_resource_t = async::consumer_resource<accept_event_t<Ts...>>;
/// Convenience function for creating an event listener resource and an /// Convenience function for creating an event listener resource and an
/// @ref acceptor_resource_t via @ref async::make_spsc_buffer_resource. /// @ref acceptor_resource_t via @ref async::make_spsc_buffer_resource.
template <class... Ts> template <class... Ts>
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "caf/async/consumer_adapter.hpp" #include "caf/async/consumer_adapter.hpp"
#include "caf/async/producer_adapter.hpp" #include "caf/async/producer_adapter.hpp"
#include "caf/async/spsc_buffer.hpp" #include "caf/async/spsc_buffer.hpp"
#include "caf/detail/flow_bridge_base.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/net/flow_connector.hpp" #include "caf/net/flow_connector.hpp"
#include "caf/net/web_socket/lower_layer.hpp" #include "caf/net/web_socket/lower_layer.hpp"
...@@ -18,170 +19,67 @@ ...@@ -18,170 +19,67 @@
namespace caf::net::web_socket { namespace caf::net::web_socket {
/// Convenience alias for referring to the base type of @ref flow_bridge.
template <class Trait>
using flow_bridge_base_t
= detail::flow_bridge_base<upper_layer, lower_layer, Trait>;
/// Translates between a message-oriented transport and data flows. /// Translates between a message-oriented transport and data flows.
template <class Trait> template <class Trait>
class flow_bridge : public web_socket::upper_layer { class flow_bridge : public flow_bridge_base_t<Trait> {
public: public:
using super = flow_bridge_base_t<Trait>;
using input_type = typename Trait::input_type; using input_type = typename Trait::input_type;
using output_type = typename Trait::output_type; using output_type = typename Trait::output_type;
/// Type for the consumer adapter. We consume the output of the application.
using consumer_type = async::consumer_adapter<output_type>;
/// Type for the producer adapter. We produce the input of the application.
using producer_type = async::producer_adapter<input_type>;
using request_type = request<Trait>;
using connector_pointer = flow_connector_ptr<Trait>; using connector_pointer = flow_connector_ptr<Trait>;
explicit flow_bridge(async::execution_context_ptr loop, using super::super;
connector_pointer conn)
: loop_(std::move(loop)), conn_(std::move(conn)) {
// nop
}
static std::unique_ptr<flow_bridge> make(async::execution_context_ptr loop, static std::unique_ptr<flow_bridge> make(async::execution_context_ptr loop,
connector_pointer conn) { connector_pointer conn) {
return std::make_unique<flow_bridge>(std::move(loop), std::move(conn)); return std::make_unique<flow_bridge>(std::move(loop), std::move(conn));
} }
bool write(const output_type& item) { bool write(const output_type& item) override {
if (trait_.converts_to_binary(item)) { if (super::trait_.converts_to_binary(item)) {
down_->begin_binary_message(); super::down_->begin_binary_message();
auto& bytes = down_->binary_message_buffer(); auto& bytes = super::down_->binary_message_buffer();
return trait_.convert(item, bytes) && down_->end_binary_message(); return super::trait_.convert(item, bytes)
&& super::down_->end_binary_message();
} else { } else {
down_->begin_text_message(); super::down_->begin_text_message();
auto& text = down_->text_message_buffer(); auto& text = super::down_->text_message_buffer();
return trait_.convert(item, text) && down_->end_text_message(); return super::trait_.convert(item, text)
&& super::down_->end_text_message();
} }
} }
bool running() const noexcept {
return in_ || out_;
}
void self_ref(disposable ref) {
self_ref_ = std::move(ref);
}
// -- implementation of web_socket::lower_layer ------------------------------ // -- implementation of web_socket::lower_layer ------------------------------
error start(web_socket::lower_layer* down, const settings& cfg) override {
down_ = down;
auto [err, pull, push] = conn_->on_request(cfg);
if (!err) {
auto do_wakeup = make_action([this] {
prepare_send();
if (!running())
down_->shutdown();
});
auto do_resume = make_action([this] { down_->request_messages(); });
auto do_cancel = make_action([this] {
if (!running())
down_->shutdown();
});
in_ = consumer_type::make(pull.try_open(), loop_, std::move(do_wakeup));
out_ = producer_type::make(push.try_open(), loop_, std::move(do_resume),
std::move(do_cancel));
conn_ = nullptr;
if (running())
return none;
else
return make_error(sec::runtime_error,
"cannot init flow bridge: no buffers");
} else {
conn_ = nullptr;
return err;
}
}
void prepare_send() override {
input_type tmp;
while (down_->can_send_more()) {
switch (in_.pull(async::delay_errors, tmp)) {
case async::read_result::ok:
if (!write(tmp)) {
down_->shutdown(trait_.last_error());
return;
}
break;
case async::read_result::stop:
down_->shutdown();
break;
case async::read_result::abort:
down_->shutdown(in_.abort_reason());
break;
default: // try later
return;
}
}
}
bool done_sending() override {
return !in_.has_consumer_event();
}
void abort(const error& reason) override {
CAF_LOG_TRACE(CAF_ARG(reason));
if (out_) {
if (reason == sec::connection_closed || reason == sec::socket_disconnected
|| reason == sec::disposed) {
out_.close();
} else {
out_.abort(reason);
}
}
in_.cancel();
self_ref_ = nullptr;
}
ptrdiff_t consume_binary(byte_span buf) override { ptrdiff_t consume_binary(byte_span buf) override {
if (!out_) if (!super::out_)
return -1; return -1;
input_type val; input_type val;
if (!trait_.convert(buf, val)) if (!super::trait_.convert(buf, val))
return -1; return -1;
if (out_.push(std::move(val)) == 0) if (super::out_.push(std::move(val)) == 0)
down_->suspend_reading(); super::down_->suspend_reading();
return static_cast<ptrdiff_t>(buf.size()); return static_cast<ptrdiff_t>(buf.size());
} }
ptrdiff_t consume_text(std::string_view buf) override { ptrdiff_t consume_text(std::string_view buf) override {
if (!out_) if (!super::out_)
return -1; return -1;
input_type val; input_type val;
if (!trait_.convert(buf, val)) if (!super::trait_.convert(buf, val))
return -1; return -1;
if (out_.push(std::move(val)) == 0) if (super::out_.push(std::move(val)) == 0)
down_->suspend_reading(); super::down_->suspend_reading();
return static_cast<ptrdiff_t>(buf.size()); return static_cast<ptrdiff_t>(buf.size());
} }
private:
web_socket::lower_layer* down_;
/// The output of the application. Serialized to the socket.
consumer_type in_;
/// The input to the application. Deserialized from the socket.
producer_type out_;
/// Converts between raw bytes and native C++ objects.
Trait trait_;
/// Runs callbacks in the I/O event loop.
async::execution_context_ptr loop_;
/// Initializes the bridge. Disposed (set to null) after initializing.
connector_pointer conn_;
/// Type-erased handle to the @ref socket_manager. This reference is important
/// to keep the bridge alive while the manager is not registered for writing
/// or reading.
disposable self_ref_;
}; };
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -171,8 +171,12 @@ void multiplexer::deref_execution_context() const noexcept { ...@@ -171,8 +171,12 @@ void multiplexer::deref_execution_context() const noexcept {
void multiplexer::schedule(action what) { void multiplexer::schedule(action what) {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
if (std::this_thread::get_id() == tid_) {
pending_actions_.push_back(what);
} else {
auto ptr = std::move(what).as_intrusive_ptr().release(); auto ptr = std::move(what).as_intrusive_ptr().release();
write_to_pipe(pollset_updater::code::run_action, ptr); write_to_pipe(pollset_updater::code::run_action, ptr);
}
} }
void multiplexer::watch(disposable what) { void multiplexer::watch(disposable what) {
...@@ -309,6 +313,7 @@ void multiplexer::poll() { ...@@ -309,6 +313,7 @@ void multiplexer::poll() {
void multiplexer::apply_updates() { void multiplexer::apply_updates() {
CAF_LOG_DEBUG("apply" << updates_.size() << "updates"); CAF_LOG_DEBUG("apply" << updates_.size() << "updates");
for (;;) {
if (!updates_.empty()) { if (!updates_.empty()) {
for (auto& [fd, update] : updates_) { for (auto& [fd, update] : updates_) {
if (auto index = index_of(fd); index == -1) { if (auto index = index_of(fd); index == -1) {
...@@ -327,6 +332,14 @@ void multiplexer::apply_updates() { ...@@ -327,6 +332,14 @@ void multiplexer::apply_updates() {
} }
updates_.clear(); updates_.clear();
} }
while (!pending_actions_.empty()) {
auto next = std::move(pending_actions_.front());
pending_actions_.pop_front();
next.run();
}
if (updates_.empty())
return;
}
} }
void multiplexer::set_thread_id() { void multiplexer::set_thread_id() {
......
...@@ -45,9 +45,9 @@ void pollset_updater::handle_read_event() { ...@@ -45,9 +45,9 @@ void pollset_updater::handle_read_event() {
auto as_mgr = [](intptr_t ptr) { auto as_mgr = [](intptr_t ptr) {
return intrusive_ptr{reinterpret_cast<socket_manager*>(ptr), false}; return intrusive_ptr{reinterpret_cast<socket_manager*>(ptr), false};
}; };
auto run_action = [](intptr_t ptr) { auto add_action = [this](intptr_t ptr) {
auto f = action{intrusive_ptr{reinterpret_cast<action::impl*>(ptr), false}}; auto f = action{intrusive_ptr{reinterpret_cast<action::impl*>(ptr), false}};
f.run(); mpx_->pending_actions_.push_back(std::move(f));
}; };
for (;;) { for (;;) {
CAF_ASSERT((buf_.size() - buf_size_) > 0); CAF_ASSERT((buf_.size() - buf_size_) > 0);
...@@ -65,7 +65,7 @@ void pollset_updater::handle_read_event() { ...@@ -65,7 +65,7 @@ void pollset_updater::handle_read_event() {
mpx_->do_start(as_mgr(ptr)); mpx_->do_start(as_mgr(ptr));
break; break;
case code::run_action: case code::run_action:
run_action(ptr); add_action(ptr);
break; break;
case code::shutdown: case code::shutdown:
CAF_ASSERT(ptr == 0); CAF_ASSERT(ptr == 0);
......
...@@ -33,11 +33,11 @@ acceptor::make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path, ...@@ -33,11 +33,11 @@ acceptor::make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path,
if (!ctx) { if (!ctx) {
return {make_error(sec::runtime_error, "unable to create SSL context")}; return {make_error(sec::runtime_error, "unable to create SSL context")};
} }
if (!ctx->use_certificate_from_file(cert_file_path, file_format)) { if (!ctx->use_certificate_file(cert_file_path, file_format)) {
return {make_error(sec::runtime_error, "unable to load certificate file", return {make_error(sec::runtime_error, "unable to load certificate file",
ctx->last_error_string())}; ctx->last_error_string())};
} }
if (!ctx->use_private_key_from_file(key_file_path, file_format)) { if (!ctx->use_private_key_file(key_file_path, file_format)) {
return {make_error(sec::runtime_error, "unable to load private key file", return {make_error(sec::runtime_error, "unable to load private key file",
ctx->last_error_string())}; ctx->last_error_string())};
} }
......
...@@ -23,22 +23,34 @@ auto native(context::impl* ptr) { ...@@ -23,22 +23,34 @@ auto native(context::impl* ptr) {
} // namespace } // namespace
// -- member types -------------------------------------------------------------
struct context::user_data {
password::callback_ptr pw_callback;
};
// -- constructors, destructors, and assignment operators ---------------------- // -- constructors, destructors, and assignment operators ----------------------
context::context(context&& other) { context::context(context&& other) {
pimpl_ = other.pimpl_; pimpl_ = other.pimpl_;
other.pimpl_ = nullptr; other.pimpl_ = nullptr;
data_ = other.data_;
other.data_ = nullptr;
} }
context& context::operator=(context&& other) { context& context::operator=(context&& other) {
SSL_CTX_free(native(pimpl_)); SSL_CTX_free(native(pimpl_));
pimpl_ = other.pimpl_; pimpl_ = other.pimpl_;
other.pimpl_ = nullptr; other.pimpl_ = nullptr;
delete data_;
data_ = other.data_;
other.data_ = nullptr;
return *this; return *this;
} }
context::~context() { context::~context() {
SSL_CTX_free(native(pimpl_)); // Already checks for NULL. SSL_CTX_free(native(pimpl_)); // Already checks for NULL.
delete data_;
} }
// -- factories ---------------------------------------------------------------- // -- factories ----------------------------------------------------------------
...@@ -147,6 +159,34 @@ expected<context> context::make_client(dtls vmin, dtls vmax) { ...@@ -147,6 +159,34 @@ expected<context> context::make_client(dtls vmin, dtls vmax) {
return {make_error(sec::logic_error, errstr)}; return {make_error(sec::logic_error, errstr)};
} }
// -- properties ---------------------------------------------------------------
void context::set_verify_mode(verify_t flags) {
auto ptr = native(pimpl_);
SSL_CTX_set_verify(ptr, to_integer(flags), SSL_CTX_get_verify_callback(ptr));
}
namespace {
int c_password_callback(char* buf, int size, int rwflag, void* ptr) {
if (ptr == nullptr)
return -1;
auto flag = static_cast<password::purpose>(rwflag);
auto fn = static_cast<password::callback*>(ptr);
return (*fn)(buf, size, flag);
}
} // namespace
void context::set_password_callback_impl(password::callback_ptr callback) {
if (data_ == nullptr)
data_ = new user_data;
auto ptr = native(pimpl_);
data_->pw_callback = std::move(callback);
SSL_CTX_set_default_passwd_cb(ptr, c_password_callback);
SSL_CTX_set_default_passwd_cb_userdata(ptr, data_->pw_callback.get());
}
// -- native handles ----------------------------------------------------------- // -- native handles -----------------------------------------------------------
context context::from_native(void* native_handle) { context context::from_native(void* native_handle) {
...@@ -217,7 +257,7 @@ bool context::set_default_verify_paths() { ...@@ -217,7 +257,7 @@ bool context::set_default_verify_paths() {
return SSL_CTX_set_default_verify_paths(native(pimpl_)) == 1; return SSL_CTX_set_default_verify_paths(native(pimpl_)) == 1;
} }
bool context::load_verify_dir(const char* path) { bool context::add_verify_path(const char* path) {
ERR_clear_error(); ERR_clear_error();
return SSL_CTX_load_verify_locations(native(pimpl_), nullptr, path) == 1; return SSL_CTX_load_verify_locations(native(pimpl_), nullptr, path) == 1;
} }
...@@ -227,16 +267,21 @@ bool context::load_verify_file(const char* path) { ...@@ -227,16 +267,21 @@ bool context::load_verify_file(const char* path) {
return SSL_CTX_load_verify_locations(native(pimpl_), path, nullptr) == 1; return SSL_CTX_load_verify_locations(native(pimpl_), path, nullptr) == 1;
} }
bool context::use_certificate_from_file(const char* path, format file_format) { bool context::use_certificate_file(const char* path, format file_format) {
ERR_clear_error();
auto nff = native(file_format);
return SSL_CTX_use_certificate_file(native(pimpl_), path, nff) == 1;
}
bool context::use_certificate_chain_file(const char* path) {
ERR_clear_error(); ERR_clear_error();
return SSL_CTX_use_certificate_file(native(pimpl_), path, native(file_format)) return SSL_CTX_use_certificate_chain_file(native(pimpl_), path) == 1;
== 1;
} }
bool context::use_private_key_from_file(const char* path, format file_format) { bool context::use_private_key_file(const char* path, format file_format) {
ERR_clear_error(); ERR_clear_error();
return SSL_CTX_use_PrivateKey_file(native(pimpl_), path, native(file_format)) auto nff = native(file_format);
== 1; return SSL_CTX_use_PrivateKey_file(native(pimpl_), path, nff) == 1;
} }
} // namespace caf::net::ssl } // namespace caf::net::ssl
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/net/ssl/password.hpp"
namespace caf::net::ssl::password {
callback::~callback() {
// nop
}
} // namespace caf::net::ssl::password
...@@ -62,6 +62,8 @@ void startup() { ...@@ -62,6 +62,8 @@ void startup() {
CRYPTO_set_dynlock_create_callback(dynlock_create); CRYPTO_set_dynlock_create_callback(dynlock_create);
CRYPTO_set_dynlock_lock_callback(dynlock_lock); CRYPTO_set_dynlock_lock_callback(dynlock_lock);
CRYPTO_set_dynlock_destroy_callback(dynlock_destroy); CRYPTO_set_dynlock_destroy_callback(dynlock_destroy);
#else
OPENSSL_init_ssl(0, nullptr);
#endif #endif
} }
...@@ -72,6 +74,10 @@ void cleanup() { ...@@ -72,6 +74,10 @@ void cleanup() {
CRYPTO_set_dynlock_lock_callback(nullptr); CRYPTO_set_dynlock_lock_callback(nullptr);
CRYPTO_set_dynlock_destroy_callback(nullptr); CRYPTO_set_dynlock_destroy_callback(nullptr);
mutexes.clear(); mutexes.clear();
#else
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif #endif
} }
......
#include "caf/net/ssl/verify.hpp"
#include <openssl/ssl.h>
namespace caf::net::ssl::verify {
namespace {
constexpr verify_t i2v(int x) {
return static_cast<verify_t>(x);
}
} // namespace
const verify_t none = i2v(SSL_VERIFY_NONE);
const verify_t peer = i2v(SSL_VERIFY_PEER);
const verify_t fail_if_no_peer_cert = i2v(SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
const verify_t client_once = i2v(SSL_VERIFY_CLIENT_ONCE);
} // namespace caf::net::ssl::verify
...@@ -215,7 +215,6 @@ SCENARIO("calling suspend_reading temporarily halts receiving of messages") { ...@@ -215,7 +215,6 @@ SCENARIO("calling suspend_reading temporarily halts receiving of messages") {
app_ptr->continue_reading(); app_ptr->continue_reading();
mpx->apply_updates(); mpx->apply_updates();
mpx->poll_once(true); mpx->poll_once(true);
CHECK_EQ(mpx->mask_of(mgr), net::operation::read);
while (mpx->num_socket_managers() > 1u) while (mpx->num_socket_managers() > 1u)
mpx->poll_once(true); mpx->poll_once(true);
if (CHECK_EQ(buf->size(), 5u)) { if (CHECK_EQ(buf->size(), 5u)) {
...@@ -248,7 +247,9 @@ SCENARIO("length_prefix_framing::run translates between flows and socket I/O") { ...@@ -248,7 +247,9 @@ SCENARIO("length_prefix_framing::run translates between flows and socket I/O") {
caf::actor_system sys{cfg}; caf::actor_system sys{cfg};
auto buf = std::make_shared<std::vector<std::string>>(); auto buf = std::make_shared<std::vector<std::string>>();
caf::actor hdl; caf::actor hdl;
net::length_prefix_framing::run(sys, fd2, [&](auto event) { using trait = net::binary::default_trait;
using lpf = net::length_prefix_framing::bind<trait>;
lpf::run(sys, fd2, [&](auto event) {
hdl = sys.spawn([event, buf](event_based_actor* self) { hdl = sys.spawn([event, buf](event_based_actor* self) {
auto [pull, push] = event.data(); auto [pull, push] = event.data();
pull.observe_on(self) pull.observe_on(self)
......
...@@ -112,12 +112,12 @@ void dummy_tls_server(stream_socket fd, const char* cert_file, ...@@ -112,12 +112,12 @@ void dummy_tls_server(stream_socket fd, const char* cert_file,
auto guard = detail::make_scope_guard([fd] { close(fd); }); auto guard = detail::make_scope_guard([fd] { close(fd); });
// Get and configure our SSL context. // Get and configure our SSL context.
auto ctx = unbox(ssl::context::make_server(ssl::tls::any)); auto ctx = unbox(ssl::context::make_server(ssl::tls::any));
if (!ctx.use_certificate_from_file(cert_file, ssl::format::pem)) { if (!ctx.use_certificate_file(cert_file, ssl::format::pem)) {
std::cerr << "*** failed to load certificate_file: " std::cerr << "*** failed to load certificate_file: "
<< ctx.last_error_string() << '\n'; << ctx.last_error_string() << '\n';
return; return;
} }
if (!ctx.use_private_key_from_file(key_file, ssl::format::pem)) { if (!ctx.use_private_key_file(key_file, ssl::format::pem)) {
std::cerr << "*** failed to load private key file: " std::cerr << "*** failed to load private key file: "
<< ctx.last_error_string() << '\n'; << ctx.last_error_string() << '\n';
return; return;
...@@ -231,9 +231,9 @@ SCENARIO("ssl::transport::make_server performs the server handshake") { ...@@ -231,9 +231,9 @@ SCENARIO("ssl::transport::make_server performs the server handshake") {
mpx->set_thread_id(); mpx->set_thread_id();
std::ignore = mpx->init(); std::ignore = mpx->init();
auto ctx = unbox(ssl::context::make_server(ssl::tls::any)); auto ctx = unbox(ssl::context::make_server(ssl::tls::any));
REQUIRE(ctx.use_certificate_from_file(cert_1_pem_path, // REQUIRE(ctx.use_certificate_file(cert_1_pem_path, //
ssl::format::pem)); ssl::format::pem));
REQUIRE(ctx.use_private_key_from_file(key_1_pem_path, // REQUIRE(ctx.use_private_key_file(key_1_pem_path, //
ssl::format::pem)); ssl::format::pem));
auto conn = unbox(ctx.new_connection(server_fd)); auto conn = unbox(ctx.new_connection(server_fd));
auto done = std::make_shared<bool>(false); auto done = std::make_shared<bool>(false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment