Commit ac91378e authored by Dominik Charousset's avatar Dominik Charousset

Restructure SSL code

parent d0d73a0f
......@@ -112,6 +112,9 @@ public:
/// Returns an observer that ignores any of its inputs.
static observer ignore();
/// Returns an observer that disposes its subscription immediately.
static observer cancel();
private:
intrusive_ptr<impl> pimpl_;
};
......@@ -170,6 +173,26 @@ private:
flow::subscription sub_;
};
template <class T>
class canceling_observer : public flow::observer_impl_base<T> {
public:
void on_next(const T&) override {
// nop
}
void on_error(const error&) override {
// nop
}
void on_complete() override {
// nop
}
void on_subscribe(flow::subscription sub) override {
sub.dispose();
}
};
template <class OnNextSignature>
struct on_next_trait;
......@@ -262,6 +285,11 @@ observer<T> observer<T>::ignore() {
return observer<T>{make_counted<detail::ignoring_observer<T>>()};
}
template <class T>
observer<T> observer<T>::cancel() {
return observer<T>{make_counted<detail::canceling_observer<T>>()};
}
/// Creates an observer from given callbacks.
/// @param on_next Callback for handling incoming elements.
/// @param on_error Callback for handling an error.
......
......@@ -4,6 +4,8 @@ file(GLOB_RECURSE CAF_NET_HEADERS "caf/*.hpp")
# -- add targets ---------------------------------------------------------------
configure_file(test/pem.cpp.in test/pem.cpp @ONLY)
caf_add_component(
net
DEPENDENCIES
......@@ -18,6 +20,10 @@ caf_add_component(
net.http.method
net.http.status
net.operation
net.ssl.dtls
net.ssl.errc
net.ssl.format
net.ssl.tls
net.stream_transport_error
net.web_socket.status
HEADERS
......@@ -49,6 +55,12 @@ caf_add_component(
src/net/socket.cpp
src/net/socket_event_layer.cpp
src/net/socket_manager.cpp
src/net/ssl/connection.cpp
src/net/ssl/context.cpp
src/net/ssl/dtls.cpp
src/net/ssl/format.cpp
src/net/ssl/tls.cpp
src/net/ssl/transport.cpp
src/net/stream_oriented.cpp
src/net/stream_socket.cpp
src/net/stream_transport.cpp
......@@ -64,8 +76,8 @@ caf_add_component(
src/net/web_socket/server.cpp
src/net/web_socket/upper_layer.cpp
TEST_SOURCES
${CMAKE_CURRENT_BINARY_DIR}/test/pem.cpp
test/net-test.cpp
test/pem.cpp
TEST_SUITES
detail.convert_ip_endpoint
detail.rfc6455
......@@ -83,6 +95,7 @@ caf_add_component(
net.producer_adapter
net.socket
net.socket_guard
net.ssl.transport
net.stream_socket
net.stream_transport
net.tcp_socket
......@@ -91,21 +104,3 @@ caf_add_component(
net.web_socket.client
net.web_socket.handshake
net.web_socket.server)
# Our OpenSSL test currently depends on <filesystem>.
check_cxx_source_compiles("
#include <cstdlib>
#include <filesystem>
int main(int, char**) {
auto cwd = std::filesystem::current_path();
auto str = cwd.string();
return str.empty() ? EXIT_FAILURE : EXIT_SUCCESS;
}
"
CAF_NET_HAS_STD_FILESYSTEM)
if(CAF_NET_HAS_STD_FILESYSTEM)
caf_add_test_suites(caf-net-test net.openssl_transport)
else()
message(STATUS "<filesystem> not working, skip OpenSSL test in CAF::net")
endif()
......@@ -90,11 +90,6 @@ public:
return write_result::stop;
}
write_result handle_continue_writing() override {
CAF_LOG_ERROR("connection_acceptor received continue writing event");
return write_result::stop;
}
void abort(const error& reason) override {
CAF_LOG_ERROR("connection_acceptor aborts due to an error: " << reason);
factory_.abort(reason);
......
// 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/net/socket_manager.hpp"
#include "caf/net/stream_transport_error.hpp"
namespace caf::net {
template <class OnSuccess, class OnError>
struct default_handshake_worker_factory {
OnSuccess make;
OnError abort;
};
/// An connect worker calls an asynchronous `connect` callback until it
/// succeeds. On success, the worker calls a factory object to transfer
/// ownership of socket and communication policy to the create the socket
/// manager that takes care of the established connection.
template <bool IsServer, class Socket, class Policy, class Factory>
class handshake_worker : public socket_manager {
public:
// -- member types -----------------------------------------------------------
using super = socket_manager;
using read_result = typename super::read_result;
using write_result = typename super::write_result;
handshake_worker(Socket handle, multiplexer* parent, Policy policy,
Factory factory)
: super(handle, parent),
policy_(std::move(policy)),
factory_(std::move(factory)) {
// nop
}
// -- interface functions ----------------------------------------------------
error init(const settings& config) override {
cfg_ = config;
register_writing();
return caf::none;
}
read_result handle_read_event() override {
auto fd = socket_cast<Socket>(this->handle());
if (auto res = advance_handshake(fd); res > 0) {
return read_result::handover;
} else if (res == 0) {
factory_.abort(make_error(sec::connection_closed));
return read_result::stop;
} else {
auto err = policy_.last_error(fd, res);
switch (err) {
case stream_transport_error::want_read:
case stream_transport_error::temporary:
return read_result::again;
case stream_transport_error::want_write:
return read_result::want_write;
default:
auto err = make_error(sec::cannot_connect_to_node,
policy_.fetch_error_str());
factory_.abort(std::move(err));
return read_result::stop;
}
}
}
read_result handle_buffered_data() override {
return read_result::again;
}
read_result handle_continue_reading() override {
return read_result::again;
}
write_result handle_write_event() override {
auto fd = socket_cast<Socket>(this->handle());
if (auto res = advance_handshake(fd); res > 0) {
return write_result::handover;
} else if (res == 0) {
factory_.abort(make_error(sec::connection_closed));
return write_result::stop;
} else {
switch (policy_.last_error(fd, res)) {
case stream_transport_error::want_write:
case stream_transport_error::temporary:
return write_result::again;
case stream_transport_error::want_read:
return write_result::want_read;
default:
auto err = make_error(sec::cannot_connect_to_node,
policy_.fetch_error_str());
factory_.abort(std::move(err));
return write_result::stop;
}
}
}
write_result handle_continue_writing() override {
return write_result::again;
}
void handle_error(sec code) override {
factory_.abort(make_error(code));
}
socket_manager_ptr make_next_manager(socket hdl) override {
auto ptr = factory_.make(socket_cast<Socket>(hdl), this->mpx_ptr(),
std::move(policy_));
if (ptr) {
if (auto err = ptr->init(cfg_)) {
factory_.abort(err);
return nullptr;
} else {
return ptr;
}
} else {
factory_.abort(make_error(sec::runtime_error, "factory_.make failed"));
return nullptr;
}
}
private:
ptrdiff_t advance_handshake(Socket fd) {
if constexpr (IsServer)
return policy_.accept(fd);
else
return policy_.connect(fd);
}
settings cfg_;
Policy policy_;
Factory factory_;
};
} // namespace caf::net
......@@ -57,8 +57,6 @@ public:
write_result handle_write_event() override;
write_result handle_continue_writing() override;
void abort(const error& reason) override;
private:
......
......@@ -54,18 +54,25 @@ public:
handover,
};
/// Initializes the layer.
virtual error init(socket_manager* owner, const settings& cfg) = 0;
/// Handles a read event on the managed socket.
virtual read_result handle_read_event() = 0;
/// Handles internally buffered data.
virtual read_result handle_buffered_data() = 0;
/// Handles a request to continue reading on the socket.
virtual read_result handle_continue_reading() = 0;
/// Handles a write event on the managed socket.
virtual write_result handle_write_event() = 0;
virtual write_result handle_continue_writing() = 0;
/// Called after returning `handover` from a read or write handler.
virtual bool do_handover(std::unique_ptr<socket_event_layer>& next);
/// Called on hard errors on the managed socket.
virtual void abort(const error& reason) = 0;
};
......
......@@ -156,10 +156,6 @@ public:
/// Closes the write channel of the socket.
void close_write() noexcept;
/// Performs a handover to another manager after `handle_read_event` or
/// `handle_read_event` returned `handover`.
socket_manager_ptr do_handover();
/// Initializes the manager and its all of its sub-components.
error init(const settings& cfg);
......@@ -179,20 +175,13 @@ public:
/// Called whenever the socket is allowed to send data.
write_result handle_write_event();
/// Restarts a socket manager that suspended writes. Calling this member
/// function on active managers is a no-op.
write_result handle_continue_writing();
/// Called when the remote side becomes unreachable due to an error.
/// @param code The error code as reported by the operating system.
void handle_error(sec code);
/// Returns the new manager for the socket after `handle_read_event` or
/// Performs a handover to another transport after `handle_read_event` or
/// `handle_read_event` returned `handover`.
/// @note Called from `do_handover`.
/// @note When returning a non-null pointer, the new manager *must* be
/// initialized.
socket_manager_ptr make_next_manager(socket handle);
[[nodiscard]] bool do_handover();
private:
// -- member variables -------------------------------------------------------
......
......@@ -14,14 +14,11 @@
#include "caf/net/handshake_worker.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/receive_policy.hpp"
#include "caf/net/stream_oriented_layer_ptr.hpp"
#include "caf/net/stream_socket.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/sec.hpp"
#include "caf/settings.hpp"
#include "caf/span.hpp"
#include "caf/tag/io_event_oriented.hpp"
#include "caf/tag/stream_oriented.hpp"
CAF_PUSH_WARNINGS
#include <openssl/err.h>
......@@ -32,31 +29,37 @@ CAF_POP_WARNINGS
#include <string>
#include <string_view>
// -- small wrappers to help working with OpenSSL ------------------------------
namespace caf::net::ssl {
namespace caf::net::openssl {
/// State shared by multiple connections.
class context {
public:
struct impl;
context() = delete;
context(context&& other);
context& operator=(context&& other);
private:
};
/// State per connection.
struct connection;
/// Deletes an SSL object.
struct deleter {
void operator()(SSL_CTX* ptr) const noexcept {
SSL_CTX_free(ptr);
}
void operator()(context* ptr) const noexcept;
void operator()(SSL* ptr) const noexcept {
SSL_free(ptr);
}
void operator()(connection* ptr) const noexcept;
};
/// A smart pointer to an `SSL_CTX` structure.
/// @note technically, SSL structures are reference counted and we could use
/// `intrusive_ptr` instead. However, we have no need for shared ownership
/// semantics here and use `unique_ptr` for simplicity.
using ctx_ptr = std::unique_ptr<SSL_CTX, deleter>;
/// An owning smart pointer for a @ref context.
using ctx_ptr = std::unique_ptr<context, deleter>;
/// A smart pointer to an `SSL` structure.
/// @note technically, SSL structures are reference counted and we could use
/// `intrusive_ptr` instead. However, we have no need for shared ownership
/// semantics here and use `unique_ptr` for simplicity.
using conn_ptr = std::unique_ptr<SSL, deleter>;
/// An owning smart pointer for a @ref connection.
using conn_ptr = std::unique_ptr<connection, deleter>;
/// Convenience function for creating an OpenSSL context for given method.
inline ctx_ptr make_ctx(const SSL_METHOD* method) {
......@@ -204,84 +207,50 @@ public:
ptrdiff_t accept(stream_socket) override;
size_t buffered() override;
size_t buffered() const noexcept override;
private:
/// Our SSL connection data.
openssl::conn_ptr conn_;
};
/// Asynchronously starts the TLS/SSL client handshake.
/// @param fd A connected stream socket.
/// @param mpx Pointer to the multiplexer for managing the asynchronous events.
/// @param pol The OpenSSL policy with properly configured SSL/TSL method.
/// @param on_success The callback for creating a @ref socket_manager after
/// successfully connecting to the server.
/// @param on_error The callback for unexpected errors.
/// @pre `fd != invalid_socket`
/// @pre `mpx != nullptr`
template <class Socket, class OnSuccess, class OnError>
void async_connect(Socket fd, multiplexer* mpx, policy pol,
OnSuccess on_success, OnError on_error) {
using res_t = decltype(on_success(fd, mpx, std::move(pol)));
using err_t = decltype(on_error(error{}));
static_assert(std::is_convertible_v<res_t, socket_manager_ptr>,
"on_success must return a socket_manager_ptr");
static_assert(std::is_same_v<err_t, void>,
"on_error may not return anything");
using factory_t = default_handshake_worker_factory<OnSuccess, OnError>;
using worker_t = handshake_worker<false, Socket, policy, factory_t>;
auto factory = factory_t{std::move(on_success), std::move(on_error)};
auto mgr = make_counted<worker_t>(fd, mpx, std::move(pol),
std::move(factory));
mpx->init(mgr);
}
/// Asynchronously starts the TLS/SSL server handshake.
/// @param fd A connected stream socket.
/// @param mpx Pointer to the multiplexer for managing the asynchronous events.
/// @param pol The OpenSSL policy with properly configured SSL/TSL method.
/// @param on_success The callback for creating a @ref socket_manager after
/// successfully connecting to the client.
/// @param on_error The callback for unexpected errors.
/// @pre `fd != invalid_socket`
/// @pre `mpx != nullptr`
template <class Socket, class OnSuccess, class OnError>
void async_accept(Socket fd, multiplexer* mpx, policy pol, OnSuccess on_success,
OnError on_error) {
using res_t = decltype(on_success(fd, mpx, std::move(pol)));
using err_t = decltype(on_error(error{}));
static_assert(std::is_convertible_v<res_t, socket_manager_ptr>,
"on_success must return a socket_manager_ptr");
static_assert(std::is_same_v<err_t, void>,
"on_error may not return anything");
using factory_t = default_handshake_worker_factory<OnSuccess, OnError>;
using worker_t = handshake_worker<true, Socket, policy, factory_t>;
auto factory = factory_t{std::move(on_success), std::move(on_error)};
auto mgr = make_counted<worker_t>(fd, mpx, std::move(pol),
std::move(factory));
mpx->init(mgr);
}
} // namespace caf::net::openssl
namespace caf::net {
/// Implements a stream_transport that manages a stream socket with encrypted
/// communication over OpenSSL.
class CAF_NET_EXPORT openssl_transport : public stream_transport {
class CAF_NET_EXPORT transport : public stream_transport {
public:
// -- member types -----------------------------------------------------------
using super = stream_transport;
// -- constructors, destructors, and assignment operators --------------------
using openssl_transport_ptr = std::unique_ptr<openssl_transport>;
using worker_ptr = std::unique_ptr<socket_event_layer>;
// -- factories --------------------------------------------------------------
/// Creates a new instance of the SSL transport for a socket that has already
/// performed the SSL handshake.
static openssl_transport_ptr make(stream_socket fd, openssl::policy policy,
upper_layer_ptr up);
/// Returns a worker that performs the OpenSSL server handshake on the socket.
/// On success, the worker performs a handover to an `openssl_transport` that
/// runs `up`.
static worker_ptr make_server(stream_socket fd, openssl::policy policy,
upper_layer_ptr up);
openssl_transport(stream_socket fd, openssl::conn_ptr conn,
upper_layer_ptr up);
/// Returns a worker that performs the OpenSSL client handshake on the socket.
/// On success, the worker performs a handover to an `openssl_transport` that
/// runs `up`.
static worker_ptr make_client(stream_socket fd, openssl::policy policy,
upper_layer_ptr up);
private:
// -- constructors, destructors, and assignment operators --------------------
openssl_transport(stream_socket fd, openssl::policy pol, upper_layer_ptr up);
openssl::policy ssl_policy_;
};
} // namespace caf::net
} // 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.
#pragma once
#include "caf/byte_span.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/net/ssl/errc.hpp"
#include "caf/net/stream_socket.hpp"
#include <cstddef>
namespace caf::net::ssl {
/// SSL state for a single connections.
class CAF_NET_EXPORT connection {
public:
// -- member types -----------------------------------------------------------
/// The opaque implementation type.
struct impl;
// -- constructors, destructors, and assignment operators --------------------
connection() = delete;
connection(connection&& other);
connection& operator=(connection&& other);
~connection();
// -- factories --------------------------------------------------------------
expected<connection> make(stream_socket fd);
// -- native handles ---------------------------------------------------------
/// Reinterprets `native_handle` as the native implementation type and takes
/// ownership of the handle.
static connection from_native(void* native_handle);
/// Retrieves the native handle from the connection.
void* native_handle() const noexcept;
// -- error handling ---------------------------------------------------------
/// Returns the error code for a preceding call to `connect`, `accept`,
/// `read`, `write` or `close.
/// @param ret The (negative) result from the preceding call.
errc last_error(ptrdiff_t ret) const;
/// Returns a human-readable representation of the error for a preceding call
/// to `connect`, `accept`, `read`, `write` or `close.
/// @param ret The (negative) result from the preceding call.
std::string last_error_string(ptrdiff_t ret) const;
// -- connecting and teardown ------------------------------------------------
/// Performs the client-side TLS/SSL handshake after connection to the server.
[[nodiscard]] ptrdiff_t connect();
/// Performs the server-side TLS/SSL handshake after accepting a connection
/// from a client.
[[nodiscard]] ptrdiff_t accept();
/// Gracefully closes the SSL connection.
ptrdiff_t close();
// -- reading and writing ----------------------------------------------------
/// Tries to fill @p buf with data from the managed socket.
[[nodiscard]] ptrdiff_t read(byte_span buf);
/// Tries to write bytes from @p buf to the managed socket.
[[nodiscard]] ptrdiff_t write(const_byte_span buf);
// -- properties -------------------------------------------------------------
/// Returns the number of bytes that are currently buffered outside of the
/// managed socket.
size_t buffered() const noexcept;
/// Returns the file descriptor for this connection.
stream_socket fd() const noexcept;
private:
constexpr explicit connection(impl* ptr) : pimpl_(ptr) {
// nop
}
impl* pimpl_;
};
} // 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.
#pragma once
#include "caf/detail/net_export.hpp"
#include "caf/net/ssl/dtls.hpp"
#include "caf/net/ssl/format.hpp"
#include "caf/net/ssl/fwd.hpp"
#include "caf/net/ssl/tls.hpp"
#include "caf/net/stream_socket.hpp"
namespace caf::net::ssl {
/// SSL state, shared by multiple connections.
class CAF_NET_EXPORT context {
public:
// -- member types -----------------------------------------------------------
/// The opaque implementation type.
struct impl;
// -- constructors, destructors, and assignment operators --------------------
context() = delete;
context(context&& other);
context& operator=(context&& other);
~context();
// -- factories --------------------------------------------------------------
static expected<context> make(tls min_version, tls max_version = tls::any);
static expected<context> make_server(tls min_version,
tls max_version = tls::any);
static expected<context> make_client(tls min_version,
tls max_version = tls::any);
static expected<context> make(dtls min_version, dtls max_version = dtls::any);
static expected<context> make_server(dtls min_version,
dtls max_version = dtls::any);
static expected<context> make_client(dtls min_version,
dtls max_version = dtls::any);
// -- native handles ---------------------------------------------------------
/// Reinterprets `native_handle` as the native implementation type and takes
/// ownership of the handle.
static context from_native(void* native_handle);
/// Retrieves the native handle from the context.
void* native_handle() const noexcept;
// -- error handling ---------------------------------------------------------
/// Retrieves a human-readable error description for a preceding call to
/// another member functions and removes that error from the error queue. Call
/// repeatedly until @ref has_last_error returns `false` to retrieve all
/// errors from the queue.
static std::string last_error_string();
/// Queries whether the error stack has at least one entry.
static bool has_last_error() noexcept;
// -- connections ------------------------------------------------------------
expected<connection> new_connection(stream_socket fd);
// -- certificates and keys --------------------------------------------------
/// Configure the context to use the default locations for loading CA
/// certificates.
/// @returns `true` on success, `false` otherwise and `last_error` can be used
/// to retrieve a human-readable error representation.
[[nodiscard]] bool set_default_verify_paths();
/// Configures the context to load CA certificate from a directory.
/// @param path Null-terminated string with a path to a directory. Files in
/// the directory must use the CA subject name hash value as file
/// name with a suffix to disambiguate multiple certificates,
/// e.g., `9d66eef0.0` and `9d66eef0.1`.
/// @returns `true` on success, `false` otherwise and `last_error` can be used
/// to retrieve a human-readable error representation.
[[nodiscard]] bool load_verify_dir(const char* path);
/// Loads a CA certificate 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
/// to retrieve a human-readable error representation.
[[nodiscard]] bool load_verify_file(const char* path);
/// Loads the first certificate found in given file.
/// @param path Null-terminated string with a path to a single PEM file.
[[nodiscard]] bool use_certificate_from_file(const char* path,
format file_format);
/// Loads the first private key found in given file.
[[nodiscard]] bool use_private_key_from_file(const char* path,
format file_format);
private:
constexpr explicit context(impl* ptr) : pimpl_(ptr) {
// nop
}
impl* pimpl_;
};
} // 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 "caf/is_error_code_enum.hpp"
namespace caf::net::ssl {
/// Configures the allowed DTLS versions on a @ref context.
enum class dtls {
any,
v1_0,
v1_2,
};
/// @relates dtls
CAF_NET_EXPORT std::string to_string(dtls);
/// @relates dtls
CAF_NET_EXPORT bool from_string(std::string_view, dtls&);
/// @relates dtls
CAF_NET_EXPORT bool from_integer(std::underlying_type_t<dtls>, dtls&);
/// @relates dtls
template <class Inspector>
bool inspect(Inspector& f, dtls& x) {
return default_enum_inspect(f, x);
}
/// @relates dtls
CAF_NET_EXPORT int native(dtls);
} // 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 "caf/is_error_code_enum.hpp"
namespace caf::net::ssl {
/// SSL error code for I/O operations on a @ref connection.
enum class errc : uint8_t {
/// Not-an-error.
none = 0,
/// SSL has closed the connection. The underlying transport may remain open.
closed,
/// Temporary error. SSL failed to write to a socket because it needs to read
/// first.
want_read,
/// Temporary error. SSL failed to read from a socket because it needs to
/// write first.
want_write,
/// Temporary error. The SSL client handshake did not complete yet.
want_connect,
/// Temporary error. The SSL server handshake did not complete yet.
want_accept,
/// Temporary error. An application callback has asked to be called again.
want_x509_lookup,
/// Temporary error. An asynchronous is still processing data and the user
/// must call the preceding function again from the same thread.
want_async,
/// The pool for starting asynchronous jobs is exhausted.
want_async_job,
/// Temporary error. An application callback has asked to be called again.
want_client_hello,
/// The operating system reported a non-recoverable, fatal I/O error. Users
/// may consult OS-specific means to retrieve the underlying error, e.g.,
/// `errno` on UNIX or `WSAGetLastError` on Windows.
syscall_failed,
/// SSL encountered a fatal error, usually a protocol violation.
fatal,
/// An unexpected error occurred with no further explanation available.
unspecified,
};
/// @relates errc
CAF_NET_EXPORT std::string to_string(errc);
/// @relates errc
CAF_NET_EXPORT bool from_string(std::string_view, errc&);
/// @relates errc
CAF_NET_EXPORT bool from_integer(std::underlying_type_t<errc>, errc&);
/// @relates errc
template <class Inspector>
bool inspect(Inspector& f, errc& x) {
return default_enum_inspect(f, x);
}
} // namespace caf::net::ssl
CAF_ERROR_CODE_ENUM(caf::net::ssl::errc)
// 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 {
/// Format of keys and certificates.
enum class format {
/// Privacy Enhanced Mail format.
pem,
/// Binary ASN1 format.
asn1,
};
/// @relates format
CAF_NET_EXPORT std::string to_string(format);
/// @relates format
CAF_NET_EXPORT bool from_string(std::string_view, format&);
/// @relates format
CAF_NET_EXPORT bool from_integer(std::underlying_type_t<format>, format&);
/// @relates format
template <class Inspector>
bool inspect(Inspector& f, format& x) {
return default_enum_inspect(f, x);
}
/// @relates dtls
CAF_NET_EXPORT int native(format);
} // 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.
#pragma once
namespace caf::net::ssl {
class connection;
class context;
class transport;
enum class dtls;
enum class errc : uint8_t;
enum class format;
enum class tls;
} // 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 "caf/is_error_code_enum.hpp"
namespace caf::net::ssl {
/// Configures the allowed DTLS versions on a @ref context.
enum class tls {
any,
v1_0,
v1_1,
v1_2,
v1_3,
};
/// @relates tls
CAF_NET_EXPORT std::string to_string(tls);
/// @relates tls
CAF_NET_EXPORT bool from_string(std::string_view, tls&);
/// @relates tls
CAF_NET_EXPORT bool from_integer(std::underlying_type_t<tls>, tls&);
/// @relates tls
template <class Inspector>
bool inspect(Inspector& f, tls& x) {
return default_enum_inspect(f, x);
}
/// @relates tls
CAF_NET_EXPORT int native(tls);
} // 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.
#pragma once
#include "caf/detail/net_export.hpp"
#include "caf/net/ssl/connection.hpp"
#include "caf/net/stream_transport.hpp"
namespace caf::net::ssl {
/// Implements a stream_transport that manages a stream socket with encrypted
/// communication over OpenSSL.
class CAF_NET_EXPORT transport : public stream_transport {
public:
// -- member types -----------------------------------------------------------
using super = stream_transport;
using worker_ptr = std::unique_ptr<socket_event_layer>;
class policy_impl : public stream_transport::policy {
public:
explicit policy_impl(connection conn);
ptrdiff_t read(stream_socket, byte_span) override;
ptrdiff_t write(stream_socket, const_byte_span) override;
stream_transport_error last_error(stream_socket, ptrdiff_t) override;
ptrdiff_t connect(stream_socket) override;
ptrdiff_t accept(stream_socket) override;
size_t buffered() const noexcept override;
connection conn;
};
// -- factories --------------------------------------------------------------
/// Creates a new instance of the SSL transport for a socket that has already
/// performed the SSL handshake.
/// @param conn The connection object for managing @p fd.
/// @param up The layer operating on top of this transport.
static std::unique_ptr<transport> make(connection conn, upper_layer_ptr up);
/// Returns a worker that performs the OpenSSL server handshake on the socket.
/// On success, the worker performs a handover to an `openssl_transport` that
/// runs `up`.
/// @param conn The connection object for managing @p fd.
/// @param up The layer operating on top of this transport.
static worker_ptr make_server(connection conn, upper_layer_ptr up);
/// Returns a worker that performs the OpenSSL client handshake on the socket.
/// On success, the worker performs a handover to an `openssl_transport` that
/// runs `up`.
/// @param conn The connection object for managing @p fd.
/// @param up The layer operating on top of this transport.
static worker_ptr make_client(connection conn, upper_layer_ptr up);
private:
// -- constructors, destructors, and assignment operators --------------------
transport(stream_socket fd, connection conn, upper_layer_ptr up);
policy_impl policy_impl_;
};
} // namespace caf::net::ssl
......@@ -160,11 +160,9 @@ public:
read_result handle_continue_reading() override;
write_result handle_continue_writing() override;
void abort(const error& reason) override;
private:
protected:
/// The socket file descriptor.
stream_socket fd_;
......
......@@ -5,6 +5,7 @@
#pragma once
#include "caf/byte_span.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/error.hpp"
#include "caf/logger.hpp"
#include "caf/net/connection_acceptor.hpp"
......@@ -35,7 +36,7 @@ namespace caf::net::web_socket {
/// 6455. Initially, the layer performs the WebSocket handshake. Once completed,
/// this layer decodes RFC 6455 frames and forwards binary and text messages to
/// `UpperLayer`.
class server : public stream_oriented::upper_layer {
class CAF_NET_EXPORT server : public stream_oriented::upper_layer {
public:
// -- member types -----------------------------------------------------------
......
......@@ -6,22 +6,19 @@
#include "caf/detail/net_export.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/generic_upper_layer.hpp"
#include "caf/net/web_socket/fwd.hpp"
namespace caf::net::web_socket {
/// Consumes text and binary messages from the lower layer.
class CAF_NET_EXPORT upper_layer {
class CAF_NET_EXPORT upper_layer : public generic_upper_layer {
public:
virtual ~upper_layer();
virtual error
init(net::socket_manager* mgr, lower_layer* down, const settings& cfg)
= 0;
virtual bool prepare_send() = 0;
virtual bool done_sending() = 0;
virtual void continue_reading() = 0;
virtual void abort(const error& reason) = 0;
virtual ptrdiff_t consume_binary(byte_span buf) = 0;
virtual ptrdiff_t consume_text(std::string_view buf) = 0;
};
......
......@@ -431,9 +431,7 @@ void multiplexer::do_handover(const socket_manager_ptr& mgr) {
// again. Hence, it *must not* point to the old manager.
auto& update = update_for(mgr);
update.events = 0;
auto new_mgr = mgr->do_handover(); // May alter the events mask.
if (new_mgr != nullptr) {
update.mgr = new_mgr;
if (mgr->do_handover()) {
// If the new manager registered itself for reading, make sure it processes
// whatever data is available in buffers outside of the socket that may not
// trigger read events.
......@@ -451,7 +449,7 @@ void multiplexer::do_handover(const socket_manager_ptr& mgr) {
break;
case socket_manager::read_result::handover: {
// Down the rabbit hole we go!
do_handover(new_mgr);
do_handover(mgr);
}
}
}
......@@ -579,20 +577,7 @@ void multiplexer::do_continue_reading(const socket_manager_ptr& mgr) {
void multiplexer::do_continue_writing(const socket_manager_ptr& mgr) {
if (!is_writing(mgr)) {
switch (mgr->handle_continue_writing()) {
default: // socket_manager::read_result::(stop | abort)
update_for(mgr).events &= ~output_mask;
break;
case socket_manager::write_result::again:
update_for(mgr).events |= output_mask;
break;
case socket_manager::write_result::want_read:
update_for(mgr).events = input_mask;
break;
case socket_manager::write_result::handover: {
do_handover(mgr);
}
}
update_for(mgr).events |= output_mask;
}
}
......
// 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/stream_transport.hpp"
namespace caf::net::openssl {
ptrdiff_t policy::read(stream_socket, byte_span buf) {
return SSL_read(conn_.get(), buf.data(), static_cast<int>(buf.size()));
}
ptrdiff_t policy::write(stream_socket, const_byte_span buf) {
return SSL_write(conn_.get(), buf.data(), static_cast<int>(buf.size()));
}
stream_transport_error policy::last_error(stream_socket fd, ptrdiff_t ret) {
switch (SSL_get_error(conn_.get(), static_cast<int>(ret))) {
case SSL_ERROR_NONE:
case SSL_ERROR_WANT_ACCEPT:
case SSL_ERROR_WANT_CONNECT:
// For all of these, OpenSSL docs say to do the operation again later.
return stream_transport_error::temporary;
case SSL_ERROR_SYSCALL:
// Need to consult errno, which we just leave to the default policy.
return default_stream_transport_policy::last_error(fd, ret);
case SSL_ERROR_WANT_READ:
return stream_transport_error::want_read;
case SSL_ERROR_WANT_WRITE:
return stream_transport_error::want_write;
default:
// Errors like SSL_ERROR_WANT_X509_LOOKUP are technically temporary, but
// we do not configure any callbacks. So seeing this is a red flag.
return stream_transport_error::permanent;
}
}
ptrdiff_t stream_transport::default_policy::connect(stream_socket x) {
return SSL_connect(conn_.get());
}
ptrdiff_t stream_transport::default_policy::accept(stream_socket) {
return SSL_accept(conn_.get());
}
size_t stream_transport::default_policy::buffered() const noexcept {
return static_cast<size_t>(SSL_pending(conn_.get()));
}
} // namespace caf::net::openssl
namespace caf::net {
openssl_transport::openssl_transport(stream_socket fd, openssl::conn_ptr conn,
upper_layer_ptr up)
: super(fd, std::move(up), &ssl_policy_), ssl_policy_(std::move(conn)) {
// nop
}
} // namespace caf::net
......@@ -115,10 +115,6 @@ pollset_updater::write_result pollset_updater::handle_write_event() {
return write_result::stop;
}
pollset_updater::write_result pollset_updater::handle_continue_writing() {
return write_result::stop;
}
void pollset_updater::abort(const error&) {
// nop
}
......
......@@ -10,4 +10,8 @@ socket_event_layer::~socket_event_layer() {
// nop
}
bool socket_event_layer::do_handover(std::unique_ptr<socket_event_layer>&) {
return false;
}
} // namespace caf::net
......@@ -70,16 +70,13 @@ void socket_manager::close_write() noexcept {
flags_.write_closed = true;
}
socket_manager_ptr socket_manager::do_handover() {
flags_.read_closed = true;
flags_.write_closed = true;
auto fd = fd_;
fd_ = invalid_socket;
if (auto ptr = make_next_manager(fd)) {
return ptr;
bool socket_manager::do_handover() {
event_handler_ptr next;
if (handler_->do_handover(next)) {
handler_.swap(next);
return true;
} else {
close(fd);
return nullptr;
return false;
}
}
......@@ -103,6 +100,7 @@ socket_manager::read_result socket_manager::handle_read_event() {
case read_result::abort:
flags_.read_closed = true;
flags_.write_closed = true;
break;
}
return result;
}
......@@ -119,10 +117,6 @@ socket_manager::write_result socket_manager::handle_write_event() {
return handler_->handle_write_event();
}
socket_manager::write_result socket_manager::handle_continue_writing() {
return handler_->handle_continue_writing();
}
void socket_manager::handle_error(sec code) {
if (handler_) {
handler_->abort(make_error(code));
......@@ -130,8 +124,4 @@ void socket_manager::handle_error(sec code) {
}
}
socket_manager_ptr socket_manager::make_next_manager(socket) {
return {};
}
} // namespace caf::net
// 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/connection.hpp"
#include "caf/config.hpp"
#include "caf/net/ssl/context.hpp"
CAF_PUSH_WARNINGS
#include <openssl/err.h>
#include <openssl/ssl.h>
CAF_POP_WARNINGS
namespace caf::net::ssl {
namespace {
auto native(connection::impl* ptr) {
return reinterpret_cast<SSL*>(ptr);
}
} // namespace
// -- constructors, destructors, and assignment operators ----------------------
connection::connection(connection&& other) {
pimpl_ = other.pimpl_;
other.pimpl_ = nullptr;
}
connection& connection::operator=(connection&& other) {
SSL_free(native(pimpl_));
pimpl_ = other.pimpl_;
other.pimpl_ = nullptr;
return *this;
}
connection::~connection() {
SSL_free(native(pimpl_)); // Already checks for NULL.
}
// -- native handles -----------------------------------------------------------
connection connection::from_native(void* native_handle) {
return connection{static_cast<impl*>(native_handle)};
}
void* connection::native_handle() const noexcept {
return static_cast<void*>(pimpl_);
}
// -- error handling -----------------------------------------------------------
std::string connection::last_error_string(ptrdiff_t ret) const {
auto code = last_error(ret);
switch (code) {
default:
return to_string(code);
case errc::fatal:
return context::last_error_string();
case errc::syscall_failed:
return last_socket_error_as_string();
}
}
errc connection::last_error(ptrdiff_t ret) const {
switch (SSL_get_error(native(pimpl_), static_cast<int>(ret))) {
case SSL_ERROR_NONE:
return errc::none;
case SSL_ERROR_ZERO_RETURN:
return errc::closed;
case SSL_ERROR_WANT_READ:
return errc::want_read;
case SSL_ERROR_WANT_WRITE:
return errc::want_write;
case SSL_ERROR_WANT_CONNECT:
return errc::want_connect;
case SSL_ERROR_WANT_ACCEPT:
return errc::want_accept;
case SSL_ERROR_WANT_X509_LOOKUP:
return errc::want_x509_lookup;
case SSL_ERROR_WANT_ASYNC:
return errc::want_async;
case SSL_ERROR_WANT_ASYNC_JOB:
return errc::want_async_job;
case SSL_ERROR_WANT_CLIENT_HELLO_CB:
return errc::want_client_hello;
case SSL_ERROR_SYSCALL:
return errc::syscall_failed;
case SSL_ERROR_SSL:
return errc::fatal;
default:
return errc::unspecified;
}
}
// -- connecting and teardown --------------------------------------------------
ptrdiff_t connection::connect() {
return SSL_connect(native(pimpl_));
}
ptrdiff_t connection::accept() {
return SSL_accept(native(pimpl_));
}
ptrdiff_t connection::close() {
return SSL_shutdown(native(pimpl_));
}
// -- reading and writing ------------------------------------------------------
ptrdiff_t connection::read(byte_span buf) {
return SSL_read(native(pimpl_), buf.data(), static_cast<int>(buf.size()));
}
ptrdiff_t connection::write(const_byte_span buf) {
return SSL_write(native(pimpl_), buf.data(), static_cast<int>(buf.size()));
}
// -- properties ---------------------------------------------------------------
size_t connection::buffered() const noexcept {
return static_cast<size_t>(SSL_pending(native(pimpl_)));
}
stream_socket connection::fd() const noexcept {
if (auto id = SSL_get_fd(native(pimpl_)))
return stream_socket{static_cast<socket_id>(id)};
else
return stream_socket{invalid_socket_id};
}
} // 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/context.hpp"
#include "caf/config.hpp"
#include "caf/expected.hpp"
#include "caf/net/ssl/connection.hpp"
CAF_PUSH_WARNINGS
#include <openssl/err.h>
#include <openssl/ssl.h>
CAF_POP_WARNINGS
namespace caf::net::ssl {
namespace {
auto native(context::impl* ptr) {
return reinterpret_cast<SSL_CTX*>(ptr);
}
} // namespace
// -- constructors, destructors, and assignment operators ----------------------
context::context(context&& other) {
pimpl_ = other.pimpl_;
other.pimpl_ = nullptr;
}
context& context::operator=(context&& other) {
SSL_CTX_free(native(pimpl_));
pimpl_ = other.pimpl_;
other.pimpl_ = nullptr;
return *this;
}
context::~context() {
SSL_CTX_free(native(pimpl_)); // Already checks for NULL.
}
// -- factories ----------------------------------------------------------------
namespace {
std::pair<SSL_CTX*, const char*> make_ctx(const SSL_METHOD* method, int vmin,
int vmax) {
auto ctx = SSL_CTX_new(method);
if (!ctx)
return {nullptr, "SSL_CTX_new returned null"};
if (vmin != 0 && SSL_CTX_set_min_proto_version(ctx, vmin) != 1)
return {ctx, "SSL_CTX_set_min_proto_version returned an error"};
if (vmax != 0 && SSL_CTX_set_max_proto_version(ctx, vmax) != 1)
return {ctx, "SSL_CTX_set_max_proto_version returned an error"};
return {ctx, nullptr};
}
} // namespace
expected<context> context::make(tls min_version, tls max_version) {
auto [raw, errstr] = make_ctx(TLS_method(), native(min_version),
native(max_version));
context ctx{reinterpret_cast<impl*>(raw)};
if (errstr == nullptr)
return {std::move(ctx)};
else
return {make_error(sec::logic_error, errstr)};
}
expected<context> context::make_server(tls min_version, tls max_version) {
auto [raw, errstr] = make_ctx(TLS_server_method(), native(min_version),
native(max_version));
context ctx{reinterpret_cast<impl*>(raw)};
if (errstr == nullptr)
return {std::move(ctx)};
else
return {make_error(sec::logic_error, errstr)};
}
expected<context> context::make_client(tls min_version, tls max_version) {
auto [raw, errstr] = make_ctx(TLS_client_method(), native(min_version),
native(max_version));
context ctx{reinterpret_cast<impl*>(raw)};
if (errstr == nullptr)
return {std::move(ctx)};
else
return {make_error(sec::logic_error, errstr)};
}
expected<context> context::make(dtls min_version, dtls max_version) {
auto [raw, errstr] = make_ctx(TLS_method(), native(min_version),
native(max_version));
context ctx{reinterpret_cast<impl*>(raw)};
if (errstr == nullptr)
return {std::move(ctx)};
else
return {make_error(sec::logic_error, errstr)};
}
expected<context> context::make_server(dtls min_version, dtls max_version) {
auto [raw, errstr] = make_ctx(DTLS_server_method(), native(min_version),
native(max_version));
context ctx{reinterpret_cast<impl*>(raw)};
if (errstr == nullptr)
return {std::move(ctx)};
else
return {make_error(sec::logic_error, errstr)};
}
expected<context> context::make_client(dtls min_version, dtls max_version) {
auto [raw, errstr] = make_ctx(DTLS_client_method(), native(min_version),
native(max_version));
context ctx{reinterpret_cast<impl*>(raw)};
if (errstr == nullptr)
return {std::move(ctx)};
else
return {make_error(sec::logic_error, errstr)};
}
// -- native handles -----------------------------------------------------------
context context::from_native(void* native_handle) {
return context{static_cast<impl*>(native_handle)};
}
void* context::native_handle() const noexcept {
return static_cast<void*>(pimpl_);
}
// -- error handling -----------------------------------------------------------
std::string context::last_error_string() {
auto save_cstr = [](const char* cstr) { return cstr ? cstr : "NULL"; };
if (auto code = ERR_get_error(); code != 0) {
std::string result;
result.reserve(256);
result = "error:";
result += std::to_string(code);
result += ':';
result += save_cstr(ERR_lib_error_string(code));
result += "::";
result += save_cstr(ERR_reason_error_string(code));
return result;
} else {
return "no-error";
}
}
bool context::has_last_error() noexcept {
return ERR_peek_error() != 0;
}
// -- connections --------------------------------------------------------------
expected<connection> context::new_connection(stream_socket fd) {
if (auto ptr = SSL_new(native(pimpl_))) {
auto conn = connection::from_native(ptr);
if (SSL_set_fd(ptr, fd.id) == 1)
return {std::move(conn)};
else
return {make_error(sec::logic_error, "SSL_set_fd failed")};
} else {
return {make_error(sec::logic_error, "SSL_new returned null")};
}
}
// -- certificates and keys ----------------------------------------------------
bool context::set_default_verify_paths() {
ERR_clear_error();
return SSL_CTX_set_default_verify_paths(native(pimpl_)) == 1;
}
bool context::load_verify_dir(const char* path) {
ERR_clear_error();
return SSL_CTX_load_verify_locations(native(pimpl_), nullptr, path) == 1;
}
bool context::load_verify_file(const char* path) {
ERR_clear_error();
return SSL_CTX_load_verify_locations(native(pimpl_), path, nullptr) == 1;
}
bool context::use_certificate_from_file(const char* path, format file_format) {
ERR_clear_error();
return SSL_CTX_use_certificate_file(native(pimpl_), path, native(file_format))
== 1;
}
bool context::use_private_key_from_file(const char* path, format file_format) {
ERR_clear_error();
return SSL_CTX_use_PrivateKey_file(native(pimpl_), path, native(file_format))
== 1;
}
} // 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/dtls.hpp"
#include "caf/config.hpp"
CAF_PUSH_WARNINGS
#include <openssl/ssl.h>
CAF_POP_WARNINGS
namespace caf::net::ssl {
int native(dtls x) {
switch (x) {
default:
return 0;
case dtls::v1_0:
return DTLS1_VERSION;
case dtls::v1_2:
return DTLS1_2_VERSION;
}
}
} // 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/format.hpp"
#include "caf/config.hpp"
CAF_PUSH_WARNINGS
#include <openssl/ssl.h>
CAF_POP_WARNINGS
namespace caf::net::ssl {
int native(format x) {
switch (x) {
default:
CAF_ASSERT(x == format::pem);
return SSL_FILETYPE_PEM;
case format::asn1:
return SSL_FILETYPE_ASN1;
}
}
} // 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/tls.hpp"
#include "caf/config.hpp"
CAF_PUSH_WARNINGS
#include <openssl/ssl.h>
CAF_POP_WARNINGS
namespace caf::net::ssl {
int native(tls x) {
switch (x) {
default:
return 0;
case tls::v1_0:
return TLS1_VERSION;
case tls::v1_1:
return TLS1_1_VERSION;
case tls::v1_2:
return TLS1_2_VERSION;
case tls::v1_3:
return TLS1_3_VERSION;
}
}
} // 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/transport.hpp"
#include "caf/net/socket_manager.hpp"
#include "caf/net/ssl/connection.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/settings.hpp"
CAF_PUSH_WARNINGS
#include <openssl/err.h>
#include <openssl/ssl.h>
CAF_POP_WARNINGS
namespace caf::net::ssl {
namespace {
/// Calls `connect` or `accept` until it succeeds or fails. On success, the
/// worker creates a new SSL transport and performs a handover.
class handshake_worker : public socket_event_layer {
public:
// -- member types -----------------------------------------------------------
using super = socket_event_layer;
using read_result = typename super::read_result;
using write_result = typename super::write_result;
using upper_layer_ptr = transport::upper_layer_ptr;
handshake_worker(connection conn, bool is_server, upper_layer_ptr up)
: is_server_(is_server), policy_(std::move(conn)), up_(std::move(up)) {
// nop
}
// -- interface functions ----------------------------------------------------
error init(socket_manager* owner, const settings& cfg) override {
owner_ = owner;
cfg_ = cfg;
owner->register_writing();
return caf::none;
}
read_result handle_read_event() override {
if (auto res = advance_handshake(); res > 0) {
return read_result::handover;
} else if (res == 0) {
up_->abort(make_error(sec::connection_closed));
return read_result::stop;
} else {
auto err = policy_.last_error(policy_.conn.fd(), res);
switch (err) {
case stream_transport_error::want_read:
case stream_transport_error::temporary:
return read_result::again;
case stream_transport_error::want_write:
return read_result::want_write;
default:
auto err = make_error(sec::cannot_connect_to_node,
policy_.conn.last_error_string(res));
up_->abort(std::move(err));
return read_result::stop;
}
}
}
read_result handle_buffered_data() override {
return read_result::again;
}
read_result handle_continue_reading() override {
return read_result::again;
}
write_result handle_write_event() override {
if (auto res = advance_handshake(); res > 0) {
return write_result::handover;
} else if (res == 0) {
up_->abort(make_error(sec::connection_closed));
return write_result::stop;
} else {
switch (policy_.last_error(policy_.conn.fd(), res)) {
case stream_transport_error::want_write:
case stream_transport_error::temporary:
return write_result::again;
case stream_transport_error::want_read:
return write_result::want_read;
default:
auto err = make_error(sec::cannot_connect_to_node,
policy_.conn.last_error_string(res));
up_->abort(std::move(err));
return write_result::stop;
}
}
}
bool do_handover(std::unique_ptr<socket_event_layer>& next) override {
next = transport::make(std::move(policy_.conn), std::move(up_));
if (auto err = next->init(owner_, cfg_))
return false;
else
return true;
}
void abort(const error& reason) override {
up_->abort(reason);
}
private:
ptrdiff_t advance_handshake() {
if (is_server_)
return policy_.conn.accept();
else
return policy_.conn.connect();
}
bool is_server_ = false;
socket_manager* owner_ = nullptr;
settings cfg_;
transport::policy_impl policy_;
upper_layer_ptr up_;
};
} // namespace
// -- member types -------------------------------------------------------------
transport::policy_impl::policy_impl(connection conn) : conn(std::move(conn)) {
// nop
}
ptrdiff_t transport::policy_impl::read(stream_socket, byte_span buf) {
return conn.read(buf);
}
ptrdiff_t transport::policy_impl::write(stream_socket, const_byte_span buf) {
return conn.write(buf);
}
stream_transport_error transport::policy_impl::last_error(stream_socket fd,
ptrdiff_t ret) {
switch (conn.last_error(ret)) {
case errc::none:
case errc::want_accept:
case errc::want_connect:
// For all of these, OpenSSL docs say to do the operation again later.
return stream_transport_error::temporary;
case errc::syscall_failed:
// Need to consult errno, which we just leave to the default policy.
return stream_transport::default_policy{}.last_error(fd, ret);
case errc::want_read:
return stream_transport_error::want_read;
case errc::want_write:
return stream_transport_error::want_write;
default:
// Errors like SSL_ERROR_WANT_X509_LOOKUP are technically temporary, but
// we do not configure any callbacks. So seeing this is a red flag.
return stream_transport_error::permanent;
}
}
ptrdiff_t transport::policy_impl::connect(stream_socket) {
return conn.connect();
}
ptrdiff_t transport::policy_impl::accept(stream_socket) {
return conn.accept();
}
size_t transport::policy_impl::buffered() const noexcept {
return conn.buffered();
}
// -- factories ----------------------------------------------------------------
std::unique_ptr<transport> transport::make(connection conn,
upper_layer_ptr up) {
// Note: can't use make_unique because the constructor is private.
auto fd = conn.fd();
auto ptr = new transport(fd, std::move(conn), std::move(up));
return std::unique_ptr<transport>{ptr};
}
transport::worker_ptr transport::make_server(connection conn,
upper_layer_ptr up) {
return std::make_unique<handshake_worker>(std::move(conn), true,
std::move(up));
}
transport::worker_ptr transport::make_client(connection conn,
upper_layer_ptr up) {
return std::make_unique<handshake_worker>(std::move(conn), false,
std::move(up));
}
// -- constructors, destructors, and assignment operators ----------------------
transport::transport(stream_socket fd, connection conn, upper_layer_ptr up)
: super(fd, std::move(up), &policy_impl_), policy_impl_(std::move(conn)) {
// nop
}
} // namespace caf::net::ssl
......@@ -317,13 +317,6 @@ stream_transport::read_result stream_transport::handle_continue_reading() {
}
}
stream_transport::write_result stream_transport::handle_continue_writing() {
// TODO: consider whether we need another callback for the upper layer.
// For now, we always return `again`, which triggers the write
// handler later.
return write_result::again;
}
void stream_transport::abort(const error& reason) {
up_->abort(reason);
}
......
......@@ -112,10 +112,6 @@ public:
: write_result::stop;
}
write_result handle_continue_writing() override {
return write_result::again;
}
void abort(const error& reason) override {
FAIL("abort called: " << reason);
}
......
-----BEGIN CERTIFICATE-----
MIIDmzCCAoOgAwIBAgIJAPLZ3e3WR0LLMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIQmVya2VsZXkxIzAhBgNVBAoM
GkFDTUUgU2lnbmluZyBBdXRob3JpdHkgSW5jMRAwDgYDVQQDDAdmb28uYmFyMB4X
DTE3MDQyMTIzMjM0OFoXDTQyMDQyMTIzMjM0OFowZDELMAkGA1UEBhMCVVMxCzAJ
BgNVBAgMAkNBMREwDwYDVQQHDAhCZXJrZWxleTEjMCEGA1UECgwaQUNNRSBTaWdu
aW5nIEF1dGhvcml0eSBJbmMxEDAOBgNVBAMMB2Zvby5iYXIwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC6ah79JvrN3LtcPzc9bX5THdzfidWncSmowotG
SZA3gcIhlsYD3P3RCaUR9g+f2Z/l0l7ciKgWetpNtN9hRBbg5/9tFzSpCb/Y0SSG
mwtHHovEqN2MWV+Od/MUcYSlL6MmPjSDc8Ls5NSniTr9OBE9J1jm72AsuzHasjPQ
D84TlWeTSs0HW3H5VxDb15xWYFnmgBo0JylDWj0+VWI+G41Xr7Ubu9699lWSFYF9
FCtdjzM5e1CGZOMvqUbUBus38BhUAdQ4fE7Dwnn8seKh+7HpJ70omIgqG87e4DBo
HbnMAkZaekk8+LBl0Hfu8c66Utw9mNoMIlFf/AMlJyLDIpNxAgMBAAGjUDBOMB0G
A1UdDgQWBBRc6Cbyshtny6jFWZtd/cEUUfMQ3DAfBgNVHSMEGDAWgBRc6Cbyshtn
y6jFWZtd/cEUUfMQ3DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCY
numHau9XYH5h4R2CoMdnKPMGk6V7UZZdbidLLcE4roQrYhnBdyhT69b/ySJK2Ee4
mt8T+E0wcg3k8Pr3aJEJA8eYYaJTqZvvv+TwuMBPjmE2rYSIpgMZv2tRD3XWMaQu
duLbwkclfejQHDD26xNXsxuU+WNB5kuvtNAg0oKFyFdNKElLQEcjyYzfxmCF4YX5
WmElijr1Tzuzd59rWPqC/tVIsh42vQ+P6g8Y1PDmo8eTUFveZ+wcr/eEPW6IOMrg
OW7tATcrgzNuXZ1umiuGgAPuIVqPfr9ssZHBqi9UOK9L/8MQrnOxecNUpPohcTFR
vq+Zqu15QV9T4BVWKHv0
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDOjCCAiICCQDz7oMOR7Wm7jANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCEJlcmtlbGV5MSMwIQYDVQQKDBpBQ01F
IFNpZ25pbmcgQXV0aG9yaXR5IEluYzEQMA4GA1UEAwwHZm9vLmJhcjAgFw0xNzA0
MjEyMzI2MzhaGA80NzU1MDMxOTIzMjYzOFowWDELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMREwDwYDVQQHDAhCZXJrZWxleTEVMBMGA1UECgwMQUNNRSBTZXJ2aWNl
MRIwEAYDVQQDDAkxLmZvby5iYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDHobccAQQqbZANdOdx852W/nUzGcwpurOi8zbh9yCxMwnFMogW9AsqKEnd
sypV6Ah/cIz45PAgCdEg+1pc2DG7+E0+QlV4ChNwCDuk+FSWB6pqMTCdZcLeIwlA
GPp6Ow9v40dW7IFpDetFKXEo6kqEzR5P58Q0a6KpCtpsSMqhk57Py83wB9gPA1vp
s77kN7D5CI3oay86TA5j5nfFMT1X/77Hs24csW6CLnW/OD4f1RK79UgPd/kpPKQ1
jNq+hsR7NZTcfrAF1hcfScxnKaznO7WopSt1k75NqLdnSN1GIci2GpiXYKtXZ9l5
TErv2Oucpw/u+a/wjKlXjrgLL9lfAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKuW
yKA2uuiNc9MKU+yVbNaP8kPaMb/wMvVaFG8FFFpCTZ0MFMLsqRpeqtj7gMK/gaJC
CQm4EyadjzfWFYDLkHzm6b7gI8digvvhjr/C2RJ5Qxr2P0iFP1buGq0CqnF20XgQ
Q+ecS43CZ77CfKfS6ZLPmAZMAwgFLImVyo5mkaTECo3+9oCnjDYBapvXLJqCJRhk
NosoTmGCV0HecWN4l38ojnXd44aSktQIND9iCLus3S6++nFnX5DHGZiv6/SnSO/6
+Op7nV0A6zKVcMOYQ0SGZPD8UQs5wDJgrR9LY29Ox5QBwu/5NqyvNSrMQaTop5vb
wkMInaq5lLxEYQDSLBc=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDOjCCAiICCQDz7oMOR7Wm7TANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCEJlcmtlbGV5MSMwIQYDVQQKDBpBQ01F
IFNpZ25pbmcgQXV0aG9yaXR5IEluYzEQMA4GA1UEAwwHZm9vLmJhcjAgFw0xNzA0
MjEyMzI2MzNaGA80NzU1MDMxOTIzMjYzM1owWDELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMREwDwYDVQQHDAhCZXJrZWxleTEVMBMGA1UECgwMQUNNRSBTZXJ2aWNl
MRIwEAYDVQQDDAkyLmZvby5iYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDG9fAvW9qnhjGRmLpA++RvOHaesu7NiUQvxf2F6gF2rLJV0/+DSA/PztEv
1WJaGhgJSaEqUjaHk3HY2EKlbGXEPh1mxqgPZD5plGlu4ddTwutxCxxQiFIBH+3N
MYRjJvDN7ozJoi4uRiK0QQdDWAqWJs5hMOJqeWd6MCgmVXSP6pj5/omGROktbHzD
9jJhAW9fnYFg6k+7cGN5kLmjqqnGhJkNtgom6uW9j73S9OpU/9Er2aZme6/PrujI
qYFBV81TJK2vmonWUITxfQjk9JVJYhBdHamGTxUqVBbuRcbAqdImV9yx4LoGh55u
L6xnsW4i0n1o1k+bh03NgwPz12O3AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJmN
yCdInFIeEwomE6m+Su82BWBzkztOfMG9iRE+1aGuC8EQ8kju5NNMmWQcuKetNh0s
hJVdY6LXh27O0ZUllhQ/ig9c+dYFh6AHoZU7WjiNKIyWuyl4IAOkQ4IEdsBvst+l
0rafcdJjUpqNOMWeyg6x1s+gUD5o+ZLCZGCdkCW3fZbKgF52L+vmsSRiJg2JkYZW
8BPNNsroHZw2UXnLvRqUXCMf1hnOrlx/B0a0Q46hD4NQvl+OzlKaxfR2L2USmJ8M
XZvT6+i8fWvkGv18iunm23Yu+8Zf08wTXnbqXvmMda5upAYLmwD0YKIVYC3ycihh
mkYCYI6PVeH63a2/zxw=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAx6G3HAEEKm2QDXTncfOdlv51MxnMKbqzovM24fcgsTMJxTKI
FvQLKihJ3bMqVegIf3CM+OTwIAnRIPtaXNgxu/hNPkJVeAoTcAg7pPhUlgeqajEw
nWXC3iMJQBj6ejsPb+NHVuyBaQ3rRSlxKOpKhM0eT+fENGuiqQrabEjKoZOez8vN
8AfYDwNb6bO+5Dew+QiN6GsvOkwOY+Z3xTE9V/++x7NuHLFugi51vzg+H9USu/VI
D3f5KTykNYzavobEezWU3H6wBdYXH0nMZyms5zu1qKUrdZO+Tai3Z0jdRiHIthqY
l2CrV2fZeUxK79jrnKcP7vmv8IypV464Cy/ZXwIDAQABAoIBAC0Y7jmoTR2clJ9F
modWhnI215kMqd9/atdT5EEVx8/f/MQMj0vII8GJSm6H6/duLIVFksMjTM+gCBtQ
TPCOcmXJSQHYkGBGvm9fnMG+y7T81FWa+SWFeIkgFxXgzqzQLMOU72fGk9F8sHp2
Szb3/o+TmtZoQB2rdxqC9ibiJsxrG5IBVKkzlSPv3POkPXwSb1HcETqrTwefuioj
WMuMrqtm5Y3HddJ5l4JEF5VA3KrsfXWl3JLHH0UViemVahiNjXQAVTKAXIL1PHAV
J2MCEvlpA7sIgXREbmvPvZUTkt3pIqhVjZVJ7tHiSnSecqNTbuxcocnhKhZrHNtC
v2zYKHkCgYEA6cAIhz0qOGDycZ1lf9RSWw0RO1hO8frATMQNVoFVuJJCVL22u96u
0FvJ0JGyYbjthULnlOKyRe7DUL5HRLVS4D7vvKCrgwDmsJp1VFxMdASUdaBfq6aX
oKLUW4q7kC2lQcmK/PVRYwp2GQSx8bodWe+DtXUY/GcN03znY8mhSB0CgYEA2qJK
1GSZsm6kFbDek3BiMMHfO+X819owB2FmXiH+GQckyIZu9xA3HWrkOWTqwglEvzfO
qzFF96E9iEEtseAxhcM8gPvfFuXiUj9t2nH/7SzMnVGikhtYi0p6jrgHmscc4NBx
AOUA15kYEFOGqpZfl2uuKqgHidrHdGkJzzSUBqsCgYAVCjb6TVQejQNlnKBFOExN
a8iwScuZVlO21TLKJYwct/WGgSkQkgO0N37b6jFfQHEIvLPxn9IiH1KvUuFBWvzh
uGiF1wR5HzykitKizEgJbVwbllrmLXGagO2Sa9NkL+efG1AKYt53hrqIl/aYZoM7
1CZL0AV2uqPw9F4zijOdNQKBgH1WmvWGMsKjQTgaLI9z1ybCjjqlj70jHXOtt+Tx
Md2hRcobn5PN3PrlY68vlpHkhF/nG3jzB3x+GGt7ijm2IE3h7la3jl5vLb8fE9gu
kJykmSz7Nurx+GHqMbaN8/Ycfga4GIB9yGzRHIWHjOVQzb5eAfv8Vk4GeV/YM8Jx
Dwd/AoGAILn8pVC9dIFac2BDOFU5y9ZvMmZAvwRxh9vEWewNvkzg27vdYc+rCHNm
I7H0S/RqfqVeo0ApE5PQ8Sll6RvxN/mbSQo9YeCDGQ1r1rNe4Vs12GAYXAbE4ipf
BTdqMbieumB/zL97iK5baHUFEJ4VRtLQhh/SOXgew/BF8ccpilI=
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,4FEF2D042C3D3463
S3uHh5KH2Vsxzhw+B8zKsZNUG7CjMAvYfZwUptDnCms2dqxdfyzioxiRVNTN2MBb
nFxMKZayl5Xjr+04LhUpCAKdmvTfqGmWRFVSa8ol1hvqN/Vmg3a11B+3MD9pHXKu
ipgHMDTmE34DsDun6cXZ8W2k9ZSSJ20Y7qhcb4lTYUZuWq+94+Bup684COZytbyG
Eb6tOvVs/N6KeFhvd4vBL4YgTR3aY/vu1cHQQJeHvSYFtGKTKr7qpsfFfDFB7ExM
bqt2qbiUq1s+uZ0hlDjs+/TCZpC9Wuqpl9m05FrZhboubBRK9pw3wRVNvrpfwunH
2/E4Ta8/YaxypUwtk4saiPofKcJwvYx3Te38OHKKXgVKlein1p1e6eJNZt3qJaPd
BEBAR11iWstE+ghPS2WmrwT17cDqNA8wG5CRM9unYVWRMtO8Nl98OYars0vAXOgd
TI8bHDx6OHm2sJnkc56HAfu6hMdTbKzZXsWyOqLXUU79ioNmTvbMQUO0F+0VKDrv
3LikXewv69aOhhk+M96ng8KpWUW4z2kbDReiFuWQfjtiFNyEdS9wQIElpq5gU98r
EAeZoT6s8O0fkE/tt374ZJREEe9YEkMFcv06c96GPkMKnScncOFKRa1w0AblGxOM
vjICMLIk3CesFNWNzJk4MQu5ZVerJsz27UFocjNUvT6iM10rDCeU55W71bIPWRSb
SZL3JUi1gOeORrv3jAEamOd6YRlvPRYQjpDENg/qnx+bdXp5S3qHeHFSkRRHBCfy
UcYUba5hZJVDyBJXC4dkc2Ftcna149PZP1aKe9r//ZGa25PVZl1Mg6HhLROSJrEN
D2lqPMYcBDuSiZ6QK5ZHh2gsXJPktDgMhw4ZNIfIIqIpMDJ7rV4tQXXwB3d+iZte
/Ib/y1Mn8fZOo448nBqagpNFvU70eg7WkA4rzgiS3VzFYosP3g48PlZ07bEZ0awy
9lMGE0OKJv6x8EkVY0xHDxujzD5WVFEkanpGo8bWl1ofBrsnnDsFrvvRkDRsQbrG
WZkRqn7zLaGKOUirfKjfktajvPOAKMsvbl9KXAfp88sOtTZuYppCivZ/2qnzQ8xg
9/fuGfpAPXYfUu44+7dhrbvxJzrPp+GQRLUb1e3KA2MLgVak+yV1TIKdDGYek5vM
xDEmLLgOQqsE/OAcdXD2b/qIVYEmFPdut6N9K0m65AoqrN5nY6r0BzuC7usCgxnu
K6Z7Y2L6Ax4DjnKt21RRcjIVLLpea7KXnMiTogCYJ7+zmD82fE3i1xCDQs7R9b4T
tZhnkGfQS2RjOp3WaiV5rcmOKXDK3kYE+ezD0wbiVFDgB2jNdR7duOFqzW/WuPac
hsIPYn7VmjLB3W4p7PBf7OQ1fIiQ6IofeMvu8I8IOVRfC7eYDCJ0QKsHI8uA6j9T
vOCfjsZcpjygtN1Xy3uXIEZUVJJq/DF5t2Lxn95wDG9VfstJQR3KuDbPwYAWOYCh
W6gYu6HftIr3OlIYKurtSUFM4+iargMUaBVOUQ4XWLN8LzoyHNL3fsiGKn1afBV/
J3Qaqrn/YBGCAc2SOUCRl3F8yfWjmidXy6rQIzrjpF8aX2QSflB+fw==
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAxvXwL1vap4YxkZi6QPvkbzh2nrLuzYlEL8X9heoBdqyyVdP/
g0gPz87RL9ViWhoYCUmhKlI2h5Nx2NhCpWxlxD4dZsaoD2Q+aZRpbuHXU8LrcQsc
UIhSAR/tzTGEYybwze6MyaIuLkYitEEHQ1gKlibOYTDianlnejAoJlV0j+qY+f6J
hkTpLWx8w/YyYQFvX52BYOpPu3BjeZC5o6qpxoSZDbYKJurlvY+90vTqVP/RK9mm
Znuvz67oyKmBQVfNUyStr5qJ1lCE8X0I5PSVSWIQXR2phk8VKlQW7kXGwKnSJlfc
seC6Boeebi+sZ7FuItJ9aNZPm4dNzYMD89djtwIDAQABAoIBAQDDaWquGRl40GR/
C/JjQQPr+RkIZdYGKXu/MEcA8ATf+l5tzfp3hp+BCzCKOpqOxHI3LQoN9xF3t2lq
AX3z27NYO2nFN/h4pYxnRk0Hiulia1+zd6YnsrxYPnPhxXCxsd1xZYsBvzh8WoZb
ZEMt8Zr0PskUzF6VFQh9Ci9k9ym07ooo/KqP4wjXsm/JK1ueOCTpRtabrBI1icrV
iTaw1JEGqlTAQ92vg3pXqSG5yy69Krt7miZZtiOA5mJ90VrHtlNSgp31AOcVv/Ve
/LMIwJp9EzTN+4ipT7AKPeJAoeVqpFjQk+2cW44zJ7xyzw73pTs5ErxkEIhQOp4M
ak2iMg4BAoGBAOivDZSaOcTxEB3oKxYvN/jL9eU2Io9wdZwAZdYQpkgc8lkM9elW
2rbHIwifkDxQnZbl3rXM8xmjA4c5PSCUYdPnLvx6nsUJrWTG0RjakHRliSLthNEC
LpL9MR1aQblyz1D/ulWTFOCNvHU7m3XI3RVJEQWu3qQ5pCndzT56wXjnAoGBANrl
zKvR9o2SONU8SDIcMzXrO2647Z8yXn4Kz1WhWojhRQQ1V3VOLm8gBwv8bPtc7LmE
MSX5MIcxRoHu7D98d53hd+K/ZGYV2h/638qaIEgZDf2oa8QylBgvoGljoy1DH8nN
KKOgksqWK0AAEkP0+S4IFugTxHVanw8JUkV0gVSxAoGBANIRUGJrxmHt/M3zUArs
QE0G3o28DQGQ1y0rEsVrLKQINid9UvoBpt3C9PcRD2fUpCGakDFzwbnQeRv46h3i
uFtV6Q6aKYLcFMXZ1ObqU+Yx0NhOtUz4+lFL8q58UL/7Tf3jkjc13XBJpe31DYoN
+MMBvzNxR6HeRD5j96tDqi3bAoGAT57SqZS/l5MeNQGuSPvU7MHZZlbBp+xMTpBk
BgOgyLUXw4Ybf8GmRiliJsv0YCHWwUwCDIvtSN91hAGB0T3WzIiccM+pFzDPnF5G
VI1nPJJQcnl2aXD0SS/ZqzvguK/3uhFzvMDFZAbnSGo+OpW6pTGwE05NYVpLDM8Z
K8ZK3KECgYEApNoI5Mr5tmtjq4sbZrgQq6cMlfkIj9gUubOzFCryUb6NaB38Xqkp
2N3/jqdkR+5ZiKOYhsYj+Iy6U3jyqiEl9VySYTfEIfP/ky1CD0a8/EVC9HR4iG8J
im6G7/osaSBYAZctryLqVJXObTelgEy/EFwW9jW8HVph/G+ljmHOmuQ=
-----END RSA PRIVATE KEY-----
This diff is collapsed.
#include <string_view>
// clang-format off
const char* ca_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/ca.pem";
const char* cert_1_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/cert_1.pem";
const char* cert_2_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/cert_2.pem";
const char* key_1_enc_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/key_1_enc.pem";
const char* key_1_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/key_1.pem";
const char* key_2_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/key_2.pem";
// clang-format on
......@@ -2,9 +2,9 @@
#include <string_view>
extern std::string_view ca_pem;
extern std::string_view cert_1_pem;
extern std::string_view cert_2_pem;
extern std::string_view key_1_enc_pem;
extern std::string_view key_1_pem;
extern std::string_view key_2_pem;
extern const char* ca_pem_path;
extern const char* cert_1_pem_path;
extern const char* cert_2_pem_path;
extern const char* key_1_enc_pem_path;
extern const char* key_1_pem_path;
extern const char* key_2_pem_path;
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