Commit 84a7596b authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #553

Add SSL/TLS support via OpenSSL
parents 2fcea6ab fc619263
...@@ -19,6 +19,7 @@ flags = [ ...@@ -19,6 +19,7 @@ flags = [
'-I./libcaf_test/', '-I./libcaf_test/',
'-I./libcaf_python/', '-I./libcaf_python/',
'-I./libcaf_opencl/', '-I./libcaf_opencl/',
'-I./libcaf_openssl/'
] ]
# Set this to the absolute path to the folder (NOT the file!) containing the # Set this to the absolute path to the folder (NOT the file!) containing the
......
...@@ -77,6 +77,10 @@ if(NOT CAF_NO_OPENCL) ...@@ -77,6 +77,10 @@ if(NOT CAF_NO_OPENCL)
set(CAF_NO_OPENCL no) set(CAF_NO_OPENCL no)
endif() endif()
if(NOT CAF_NO_OPENSSL)
set(CAF_NO_OPENSSL no)
endif()
if(NOT CAF_NO_PYTHON) if(NOT CAF_NO_PYTHON)
set(CAF_NO_PYTHON no) set(CAF_NO_PYTHON no)
endif() endif()
...@@ -494,12 +498,25 @@ endmacro() ...@@ -494,12 +498,25 @@ endmacro()
add_caf_lib(core) add_caf_lib(core)
add_optional_caf_lib(io) add_optional_caf_lib(io)
# build SSL module if OpenSSL library is available
if(NOT CAF_NO_OPENSSL)
find_package(OpenSSL)
if(OPENSSL_FOUND)
include_directories(BEFORE ${OPENSSL_INCLUDE_DIR})
add_optional_caf_lib(openssl)
else(OPENSSL_FOUND)
set(CAF_NO_OPENSSL yes)
endif(OPENSSL_FOUND)
endif()
# build opencl library if not told otherwise and OpenCL package was found # build opencl library if not told otherwise and OpenCL package was found
if(NOT CAF_NO_OPENCL) if(NOT CAF_NO_OPENCL)
find_package(OpenCL) find_package(OpenCL)
if(OpenCL_FOUND) if(OpenCL_FOUND)
add_optional_caf_lib(opencl) add_optional_caf_lib(opencl)
add_optional_caf_binaries(libcaf_opencl/examples) add_optional_caf_binaries(libcaf_opencl/examples)
else()
set(CAF_NO_OPENCL yes)
endif() endif()
endif() endif()
...@@ -682,6 +699,7 @@ invertYesNo(CAF_NO_EXCEPTIONS CAF_BUILD_WITH_EXCEPTIONS) ...@@ -682,6 +699,7 @@ invertYesNo(CAF_NO_EXCEPTIONS CAF_BUILD_WITH_EXCEPTIONS)
invertYesNo(CAF_NO_MEM_MANAGEMENT CAF_BUILD_MEM_MANAGEMENT) invertYesNo(CAF_NO_MEM_MANAGEMENT CAF_BUILD_MEM_MANAGEMENT)
invertYesNo(CAF_NO_BENCHMARKS CAF_BUILD_BENCHMARKS) invertYesNo(CAF_NO_BENCHMARKS CAF_BUILD_BENCHMARKS)
invertYesNo(CAF_NO_OPENCL CAF_BUILD_OPENCL) invertYesNo(CAF_NO_OPENCL CAF_BUILD_OPENCL)
invertYesNo(CAF_NO_OPENSSL CAF_BUILD_OPENSSL)
invertYesNo(CAF_NO_PYTHON CAF_BUILD_PYTHON) invertYesNo(CAF_NO_PYTHON CAF_BUILD_PYTHON)
# collect all compiler flags # collect all compiler flags
string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE) string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE)
...@@ -706,7 +724,8 @@ if(NOT CAF_NO_SUMMARY) ...@@ -706,7 +724,8 @@ if(NOT CAF_NO_SUMMARY)
"\nBuild examples: ${CAF_BUILD_EXAMPLES}" "\nBuild examples: ${CAF_BUILD_EXAMPLES}"
"\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}" "\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}"
"\nBuild benchmarks: ${CAF_BUILD_BENCHMARKS}" "\nBuild benchmarks: ${CAF_BUILD_BENCHMARKS}"
"\nBuild opencl: ${CAF_BUILD_OPENCL}" "\nBuild OpenCL: ${CAF_BUILD_OPENCL}"
"\nBuild OpenSSL: ${CAF_BUILD_OPENSSL}"
"\nBuild Python: ${CAF_BUILD_PYTHON}" "\nBuild Python: ${CAF_BUILD_PYTHON}"
"\n" "\n"
"\nCXX: ${CMAKE_CXX_COMPILER}" "\nCXX: ${CMAKE_CXX_COMPILER}"
......
...@@ -65,6 +65,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]... ...@@ -65,6 +65,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--no-curl-examples build without libcurl examples --no-curl-examples build without libcurl examples
--no-unit-tests build without unit tests --no-unit-tests build without unit tests
--no-opencl build without OpenCL module --no-opencl build without OpenCL module
--no-openssl build without OpenSSL module
--no-benchmarks build without benchmarks --no-benchmarks build without benchmarks
--no-tools build without CAF tools such as caf-run --no-tools build without CAF tools such as caf-run
--no-io build without I/O module --no-io build without I/O module
...@@ -339,6 +340,9 @@ while [ $# -ne 0 ]; do ...@@ -339,6 +340,9 @@ while [ $# -ne 0 ]; do
--no-opencl) --no-opencl)
append_cache_entry CAF_NO_OPENCL BOOL yes append_cache_entry CAF_NO_OPENCL BOOL yes
;; ;;
--no-openssl)
append_cache_entry CAF_NO_OPENSSL BOOL yes
;;
--build-static) --build-static)
append_cache_entry CAF_BUILD_STATIC BOOL yes append_cache_entry CAF_BUILD_STATIC BOOL yes
;; ;;
......
...@@ -293,6 +293,14 @@ public: ...@@ -293,6 +293,14 @@ public:
std::string opencl_device_ids; std::string opencl_device_ids;
// -- config parameters of the OpenSSL module ---------------------------------
std::string openssl_certificate;
std::string openssl_key;
std::string openssl_passphrase;
std::string openssl_capath;
std::string openssl_cafile;
// -- factories -------------------------------------------------------------- // -- factories --------------------------------------------------------------
value_factory_string_map value_factories_by_name; value_factory_string_map value_factories_by_name;
......
...@@ -200,6 +200,17 @@ actor_system_config::actor_system_config() ...@@ -200,6 +200,17 @@ actor_system_config::actor_system_config()
opt_group(options_, "opencl") opt_group(options_, "opencl")
.add(opencl_device_ids, "device-ids", .add(opencl_device_ids, "device-ids",
"restricts which OpenCL devices are accessed by CAF"); "restricts which OpenCL devices are accessed by CAF");
opt_group(options_, "openssl")
.add(openssl_certificate, "certificate",
"sets the path to the file containining the certificate for this node PEM format")
.add(openssl_key, "key",
"sets the path to the file containting the private key for this node")
.add(openssl_passphrase, "passphrase",
"sets the passphrase to decrypt the private key, if needed")
.add(openssl_capath, "capath",
"sets the path to an OpenSSL-style directory of trusted certificates")
.add(openssl_cafile, "cafile",
"sets the path to a file containing trusted certificates concatenated together in PEM format");
// add renderers for default error categories // add renderers for default error categories
error_renderers.emplace(atom("system"), render_sec); error_renderers.emplace(atom("system"), render_sec);
error_renderers.emplace(atom("exit"), render_exit_reason); error_renderers.emplace(atom("exit"), render_exit_reason);
......
cmake_minimum_required(VERSION 2.8)
project(caf_openssl C CXX)
# get header files; only needed by CMake generators,
# e.g., for creating proper Xcode projects
file(GLOB_RECURSE LIBCAF_OPENSSL_HDRS "caf/*.hpp")
# list cpp files excluding platform-dependent files
set (LIBCAF_OPENSSL_SRCS
src/manager.cpp
src/middleman_actor.cpp
src/publish.cpp
src/remote_actor.cpp
src/session.cpp)
add_custom_target(libcaf_openssl)
# build shared library if not compiling static only
if (NOT CAF_BUILD_STATIC_ONLY)
add_library(libcaf_openssl_shared SHARED
${LIBCAF_OPENSSL_SRCS} ${LIBCAF_OPENSSL_HDRS})
target_link_libraries(libcaf_openssl_shared ${LD_FLAGS}
${CAF_LIBRARY_CORE} ${CAF_LIBRARY_IO} ${OPENSSL_LIBRARIES})
if(NOT APPLE AND NOT WIN32)
target_link_libraries(libcaf_openssl_shared "-pthread")
endif()
set_target_properties(libcaf_openssl_shared
PROPERTIES
SOVERSION ${CAF_VERSION}
VERSION ${CAF_VERSION}
OUTPUT_NAME caf_openssl)
if (CYGWIN)
install(TARGETS libcaf_openssl_shared RUNTIME DESTINATION bin)
elseif (NOT WIN32)
install(TARGETS libcaf_openssl_shared LIBRARY DESTINATION lib)
endif()
add_dependencies(libcaf_openssl_shared libcaf_openssl)
endif ()
# build static library only if --build-static or --build-static-only was set
if (CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC)
add_library(libcaf_openssl_static STATIC
${LIBCAF_OPENSSL_HDRS} ${LIBCAF_OPENSSL_SRCS})
target_link_libraries(libcaf_openssl_static ${LD_FLAGS}
${CAF_LIBRARY_CORE_STATIC} ${CAF_LIBRARY_IO_STATIC} ${OPENSSL_LIBRARIES})
set_target_properties(libcaf_openssl_static PROPERTIES
OUTPUT_NAME caf_openssl_static)
if(NOT WIN32)
install(TARGETS libcaf_openssl_static ARCHIVE DESTINATION lib)
endif()
add_dependencies(libcaf_openssl_static libcaf_openssl)
endif ()
link_directories(${LD_DIRS})
include_directories(. ${INCLUDE_DIRS})
# install includes
if(NOT WIN32)
install(DIRECTORY caf/ DESTINATION include/caf FILES_MATCHING PATTERN "*.hpp")
endif()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENSSL_ALL_HPP
#define CAF_OPENSSL_ALL_HPP
#include "caf/openssl/manager.hpp"
#include "caf/openssl/publish.hpp"
#include "caf/openssl/remote_actor.hpp"
#endif // CAF_OPENSSL_ALL_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENSSL_MANAGER_HPP
#define CAF_OPENSSL_MANAGER_HPP
#include <set>
#include <string>
#include "caf/actor_system.hpp"
#include "caf/io/middleman_actor.hpp"
namespace caf {
namespace openssl {
/// Stores OpenSSL context information and provides access to necessary
/// credentials for establishing connections.
class manager : public actor_system::module {
public:
~manager() override;
void start() override;
void stop() override;
void init(actor_system_config&) override;
id_t id() const override;
void* subtype_ptr() override;
/// Returns an SSL-aware implementation of the middleman actor interface.
inline const io::middleman_actor& actor_handle() const {
return manager_;
}
/// Returns the enclosing actor system.
inline actor_system& system() {
return system_;
}
/// Returns true if configured to require certificate-based authentication
/// of peers.
bool authentication_enabled();
/// Returns an OpenSSL manager using the default network backend.
/// @warning Creating an OpenSSL manager will fail when using the ASIO
/// network backend or any other custom implementation.
/// @throws `logic_error` if the middleman is not loaded or is not using the
/// default network backend.
static actor_system::module* make(actor_system&, detail::type_list<>);
private:
/// Private since instantiation is only allowed via `make`.
manager(actor_system& sys);
/// Reference to the parent.
actor_system& system_;
/// OpenSSL-aware connection manager.
io::middleman_actor manager_;
};
} // namespace openssl
} // namespace caf
#endif // CAF_OPENSSL_MANAGER_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENSSL_MIDDLEMAN_ACTOR_HPP
#define CAF_OPENSSL_MIDDLEMAN_ACTOR_HPP
#include "caf/io/middleman_actor.hpp"
namespace caf {
namespace openssl {
io::middleman_actor make_middleman_actor(actor_system& sys, actor db);
} // namespace openssl
} // namespace caf
#endif // CAF_OPENSSL_MIDDLEMAN_ACTOR_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENSSL_PUBLISH_HPP
#define CAF_OPENSSL_PUBLISH_HPP
#include <set>
#include <string>
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/sec.hpp"
#include "caf/error.hpp"
#include "caf/actor_cast.hpp"
#include "caf/typed_actor.hpp"
#include "caf/actor_control_block.hpp"
namespace caf {
namespace openssl {
/// @private
expected<uint16_t> publish(actor_system& sys, const strong_actor_ptr& whom,
std::set<std::string>&& sigs, uint16_t port,
const char* cstr, bool ru);
/// Tries to publish `whom` at `port` and returns either an `error` or the
/// bound port.
/// @param whom Actor that should be published at `port`.
/// @param port Unused TCP port.
/// @param in The IP address to listen to or `INADDR_ANY` if `in == nullptr`.
/// @param reuse Create socket using `SO_REUSEADDR`.
/// @returns The actual port the OS uses after `bind()`. If `port == 0`
/// the OS chooses a random high-level port.
template <class Handle>
expected<uint16_t> publish(const Handle& whom, uint16_t port,
const char* in = nullptr, bool reuse = false) {
if (!whom)
return sec::cannot_publish_invalid_actor;
auto& sys = whom.home_system();
return publish(sys, actor_cast<strong_actor_ptr>(whom),
sys.message_types(whom), port, in, reuse);
}
} // namespace openssl
} // namespace caf
#endif // CAF_OPENSSL_PUBLISH_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENSSL_REMOTE_ACTOR_HPP
#define CAF_OPENSSL_REMOTE_ACTOR_HPP
#include <set>
#include <string>
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_control_block.hpp"
namespace caf {
namespace openssl {
/// @private
expected<strong_actor_ptr> remote_actor(actor_system& sys,
const std::set<std::string>& mpi,
std::string host, uint16_t port);
/// Establish a new connection to the actor at `host` on given `port`.
/// @param host Valid hostname or IP address.
/// @param port TCP port.
/// @returns An `actor` to the proxy instance representing
/// a remote actor or an `error`.
template <class ActorHandle = actor>
expected<ActorHandle> remote_actor(actor_system& sys, std::string host,
uint16_t port) {
detail::type_list<ActorHandle> tk;
auto res = remote_actor(sys, sys.message_types(tk), std::move(host), port);
if (res)
return actor_cast<ActorHandle>(std::move(*res));
return std::move(res.error());
}
} // namespace openssl
} // namespace caf
#endif // CAF_OPENSSL_REMOTE_ACTOR_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_OPENSSL_SESSION_HPP
#define CAF_OPENSSL_SESSION_HPP
#include "caf/config.hpp"
CAF_PUSH_WARNINGS
#include <openssl/ssl.h>
CAF_POP_WARNINGS
#include "caf/actor_system.hpp"
#include "caf/io/network/native_socket.hpp"
#include "caf/io/network/default_multiplexer.hpp"
namespace caf {
namespace openssl {
using native_socket = io::network::native_socket;
using rw_state = io::network::rw_state;
class session : public ref_counted {
public:
session(actor_system& sys);
~session();
bool init();
rw_state read_some(size_t& result, native_socket fd, void* buf, size_t len);
rw_state write_some(size_t& result, native_socket fd, const void* buf,
size_t len);
bool try_connect(native_socket fd);
bool try_accept(native_socket fd);
const char* openssl_passphrase();
private:
rw_state do_some(int (*f)(SSL*, void*, int), size_t& result, void* buf,
size_t len, const char* debug_name);
SSL_CTX* create_ssl_context();
std::string get_ssl_error();
void raise_ssl_error(std::string msg);
bool handle_ssl_result(int ret);
actor_system& sys_;
SSL_CTX* ctx_;
SSL* ssl_;
std::string openssl_passphrase_;
bool connecting_;
bool accepting_;
};
/// @relates session
using session_ptr = intrusive_ptr<session>;
/// @relates session
session_ptr make_session(actor_system& sys, native_socket fd,
bool from_accepted_socket);
} // namespace openssl
} // namespace caf
#endif // CAF_OPENSSL_SESSION_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/openssl/manager.hpp"
CAF_PUSH_WARNINGS
#include <openssl/err.h>
#include <openssl/ssl.h>
CAF_POP_WARNINGS
#include "caf/expected.hpp"
#include "caf/actor_system.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/io/middleman.hpp"
#include "caf/io/basp_broker.hpp"
#include "caf/io/network/default_multiplexer.hpp"
#include "caf/openssl/middleman_actor.hpp"
namespace caf {
namespace openssl {
manager::~manager() {
// nop
}
void manager::start() {
CAF_LOG_TRACE("");
manager_ = make_middleman_actor(
system(), system().middleman().named_broker<io::basp_broker>(atom("BASP")));
}
void manager::stop() {
CAF_LOG_TRACE("");
scoped_actor self{system(), true};
self->send_exit(manager_, exit_reason::kill);
if (system().config().middleman_detach_utility_actors)
self->wait_for(manager_);
manager_ = nullptr;
}
void manager::init(actor_system_config&) {
CAF_LOG_TRACE("");
ERR_load_crypto_strings();
OPENSSL_add_all_algorithms_conf();
SSL_library_init();
SSL_load_error_strings();
if (authentication_enabled()) {
if (system().config().openssl_certificate.size() == 0)
CAF_RAISE_ERROR("No certificate configured for SSL endpoint");
if (system().config().openssl_key.size() == 0)
CAF_RAISE_ERROR("No private key configured for SSL endpoint");
}
}
actor_system::module::id_t manager::id() const {
return openssl_manager;
}
void* manager::subtype_ptr() {
return this;
}
bool manager::authentication_enabled() {
auto& cfg = system().config();
return cfg.openssl_certificate.size() > 0 || cfg.openssl_key.size() > 0
|| cfg.openssl_passphrase.size() > 0 || cfg.openssl_capath.size() > 0
|| cfg.openssl_cafile.size() > 0;
}
actor_system::module* manager::make(actor_system& sys, detail::type_list<>) {
if (!sys.has_middleman())
CAF_RAISE_ERROR("Cannot start OpenSSL module without middleman.");
auto ptr = &sys.middleman().backend();
if (dynamic_cast<io::network::default_multiplexer*>(ptr) == nullptr)
CAF_RAISE_ERROR("Cannot start OpenSSL module without default backend.");
return new manager(sys);
}
manager::manager(actor_system& sys) : system_(sys) {
// nop
}
} // namespace openssl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/io/middleman_actor.hpp"
#include <tuple>
#include <stdexcept>
#include <utility>
#include "caf/sec.hpp"
#include "caf/send.hpp"
#include "caf/actor.hpp"
#include "caf/logger.hpp"
#include "caf/node_id.hpp"
#include "caf/actor_proxy.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/typed_event_based_actor.hpp"
#include "caf/io/basp_broker.hpp"
#include "caf/io/system_messages.hpp"
#include "caf/io/middleman_actor_impl.hpp"
#include "caf/io/network/interfaces.hpp"
#include "caf/io/network/default_multiplexer.hpp"
#include "caf/openssl/session.hpp"
namespace caf {
namespace openssl {
namespace {
using native_socket = io::network::native_socket;
using default_mpx = io::network::default_multiplexer;
struct ssl_policy {
ssl_policy(intrusive_ptr<session> session) : session_(std::move(session)) {
// nop
}
rw_state read_some(size_t& result, native_socket fd, void* buf, size_t len) {
CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(len));
return session_->read_some(result, fd, buf, len);
}
rw_state write_some(size_t& result, native_socket fd, const void* buf,
size_t len) {
CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(len));
return session_->write_some(result, fd, buf, len);
}
bool try_accept(native_socket& result, native_socket fd) {
CAF_LOG_TRACE(CAF_ARG(fd));
sockaddr_storage addr;
memset(&addr, 0, sizeof(addr));
socklen_t addrlen = sizeof(addr);
result = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
CAF_LOG_DEBUG(CAF_ARG(fd) << CAF_ARG(result));
if (result == io::network::invalid_native_socket) {
auto err = io::network::last_socket_error();
if (!io::network::would_block_or_temporarily_unavailable(err))
return false;
}
return session_->try_accept(result);
}
private:
intrusive_ptr<session> session_;
};
class scribe_impl : public io::scribe {
public:
scribe_impl(default_mpx& mpx, native_socket sockfd,
session_ptr sptr)
: scribe(io::network::conn_hdl_from_socket(sockfd)),
launched_(false),
stream_(mpx, sockfd, std::move(sptr)) {
// nop
}
~scribe_impl() {
CAF_LOG_TRACE("");
}
void configure_read(io::receive_policy::config config) override {
CAF_LOG_TRACE(CAF_ARG(config));
stream_.configure_read(config);
if (!launched_)
launch();
}
void ack_writes(bool enable) override {
CAF_LOG_TRACE(CAF_ARG(enable));
stream_.ack_writes(enable);
}
std::vector<char>& wr_buf() override {
return stream_.wr_buf();
}
std::vector<char>& rd_buf() override {
return stream_.rd_buf();
}
void stop_reading() override {
CAF_LOG_TRACE("");
stream_.stop_reading();
detach(&stream_.backend(), false);
}
void flush() override {
CAF_LOG_TRACE("");
stream_.flush(this);
}
std::string addr() const override {
auto x = io::network::remote_addr_of_fd(stream_.fd());
if (!x)
return "";
return *x;
}
uint16_t port() const override {
auto x = io::network::remote_port_of_fd(stream_.fd());
if (!x)
return 0;
return *x;
}
void launch() {
CAF_LOG_TRACE("");
CAF_ASSERT(!launched_);
launched_ = true;
stream_.start(this);
// This schedules the scribe in case SSL still needs to call SSL_connect
// or SSL_accept. Otherwise, the backend simply removes the socket for
// write operations after the first "nop write".
stream_.force_empty_write(this);
}
void add_to_loop() override {
CAF_LOG_TRACE("");
stream_.activate(this);
}
void remove_from_loop() override {
CAF_LOG_TRACE("");
stream_.passivate();
}
private:
bool launched_;
io::network::stream_impl<ssl_policy> stream_;
};
class doorman_impl : public io::network::doorman_impl {
public:
doorman_impl(default_mpx& mx, native_socket sockfd)
: io::network::doorman_impl(mx, sockfd) {
// nop
}
bool new_connection() override {
CAF_LOG_TRACE("");
if (detached())
// we are already disconnected from the broker while the multiplexer
// did not yet remove the socket, this can happen if an I/O event causes
// the broker to call close_all() while the pollset contained
// further activities for the broker
return false;
auto& dm = acceptor_.backend();
auto fd = acceptor_.accepted_socket();
auto sssn = make_session(parent()->system(), fd, true);
if (sssn == nullptr) {
CAF_LOG_ERROR("Unable to create SSL session for accepted socket");
return false;
}
auto scrb = make_counted<scribe_impl>(dm, fd, std::move(sssn));
auto hdl = scrb->hdl();
parent()->add_scribe(std::move(scrb));
return doorman::new_connection(&dm, hdl);
}
};
class middleman_actor_impl : public io::middleman_actor_impl {
public:
middleman_actor_impl(actor_config& cfg, actor default_broker)
: io::middleman_actor_impl(cfg, std::move(default_broker)) {
// nop
}
const char* name() const override {
return "openssl::middleman_actor";
}
protected:
expected<io::scribe_ptr> connect(const std::string& host,
uint16_t port) override {
CAF_LOG_TRACE(CAF_ARG(host) << CAF_ARG(port));
auto fd = io::network::new_tcp_connection(host, port);
if (fd == io::network::invalid_native_socket)
return std::move(fd.error());
io::network::nonblocking(*fd, true);
auto sssn = make_session(system(), *fd, false);
if (!sssn) {
CAF_LOG_ERROR("Unable to create SSL session for connection");
return sec::cannot_connect_to_node;
}
CAF_LOG_DEBUG("successfully created an SSL session for:"
<< CAF_ARG(host) << CAF_ARG(port));
return make_counted<scribe_impl>(mpx(), *fd, std::move(sssn));
}
expected<io::doorman_ptr> open(uint16_t port, const char* addr,
bool reuse) override {
CAF_LOG_TRACE(CAF_ARG(port) << CAF_ARG(reuse));
auto fd = io::network::new_tcp_acceptor_impl(port, addr, reuse);
if (fd == io::network::invalid_native_socket)
return std::move(fd.error());
return make_counted<doorman_impl>(mpx(), *fd);
}
private:
default_mpx& mpx() {
return static_cast<default_mpx&>(system().middleman().backend());
}
};
} // namespace <anonymous>
io::middleman_actor make_middleman_actor(actor_system& sys, actor db) {
return sys.config().middleman_detach_utility_actors
? sys.spawn<middleman_actor_impl, detached + hidden>(std::move(db))
: sys.spawn<middleman_actor_impl, hidden>(std::move(db));
}
} // namespace openssl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/openssl/publish.hpp"
#include <set>
#include "caf/atom.hpp"
#include "caf/expected.hpp"
#include "caf/actor_system.hpp"
#include "caf/function_view.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/openssl/manager.hpp"
namespace caf {
namespace openssl {
expected<uint16_t> publish(actor_system& sys, const strong_actor_ptr& whom,
std::set<std::string>&& sigs, uint16_t port,
const char* cstr, bool ru) {
CAF_LOG_TRACE(CAF_ARG(whom) << CAF_ARG(sigs) << CAF_ARG(port));
CAF_ASSERT(whom != nullptr);
std::string in;
if (cstr != nullptr)
in = cstr;
auto f = make_function_view(sys.openssl_manager().actor_handle());
return f(publish_atom::value, port, std::move(whom), std::move(sigs),
std::move(in), ru);
}
} // namespace openssl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/openssl/remote_actor.hpp"
#include "caf/sec.hpp"
#include "caf/atom.hpp"
#include "caf/expected.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/openssl/manager.hpp"
namespace caf {
namespace openssl {
/// Establish a new connection to the actor at `host` on given `port`.
/// @param host Valid hostname or IP address.
/// @param port TCP port.
/// @returns An `actor` to the proxy instance representing
/// a remote actor or an `error`.
expected<strong_actor_ptr> remote_actor(actor_system& sys,
const std::set<std::string>& mpi,
std::string host, uint16_t port) {
CAF_LOG_TRACE(CAF_ARG(mpi) << CAF_ARG(host) << CAF_ARG(port));
expected<strong_actor_ptr> res{strong_actor_ptr{nullptr}};
scoped_actor self{sys};
auto mm = sys.openssl_manager().actor_handle();
CAF_ASSERT(mm != nullptr);
self->request(sys.openssl_manager().actor_handle(), infinite,
connect_atom::value, std::move(host), port)
.receive(
[&](const node_id&, strong_actor_ptr& ptr, std::set<std::string>& found) {
if (ptr) {
if (sys.assignable(found, mpi))
res = std::move(ptr);
else
res = sec::unexpected_actor_messaging_interface;
} else {
res = sec::no_actor_published_at_port;
}
},
[&](error& err) {
res = std::move(err);
}
);
return res;
}
} // namespace openssl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/openssl/session.hpp"
CAF_PUSH_WARNINGS
#include <sys/socket.h>
#include <openssl/err.h>
CAF_POP_WARNINGS
#include "caf/actor_system_config.hpp"
#include "caf/io/network/default_multiplexer.hpp"
#include "caf/openssl/manager.hpp"
namespace caf {
namespace openssl {
namespace {
int pem_passwd_cb(char* buf, int size, int, void* ptr) {
auto passphrase = reinterpret_cast<session*>(ptr)->openssl_passphrase();
strncpy(buf, passphrase, static_cast<size_t>(size));
buf[size - 1] = '\0';
return strlen(buf);
}
} // namespace <anonymous>
session::session(actor_system& sys)
: sys_(sys),
ctx_(nullptr),
ssl_(nullptr),
connecting_(false),
accepting_(false) {
// nop
}
bool session::init() {
CAF_LOG_TRACE("");
ctx_ = create_ssl_context();
ssl_ = SSL_new(ctx_);
if (ssl_ == nullptr) {
CAF_LOG_ERROR("cannot create SSL session");
return false;
}
return true;
}
session::~session() {
SSL_free(ssl_);
SSL_CTX_free(ctx_);
}
rw_state session::do_some(int (*f)(SSL*, void*, int), size_t& result, void* buf,
size_t len, const char* debug_name) {
auto check_ssl_res = [&](int res) -> rw_state {
result = 0;
switch (SSL_get_error(ssl_, res)) {
default:
CAF_LOG_INFO("SSL error:" << get_ssl_error());
return rw_state::failure;
case SSL_ERROR_WANT_READ:
CAF_LOG_DEBUG("SSL_ERROR_WANT_READ reported");
// Report success to poll on this socket.
if (len == 0 && strcmp(debug_name, "write_some") == 0)
return rw_state::indeterminate;
return rw_state::success;
case SSL_ERROR_WANT_WRITE:
CAF_LOG_DEBUG("SSL_ERROR_WANT_WRITE reported");
// Report success to poll on this socket.
return rw_state::success;
}
};
CAF_LOG_TRACE(CAF_ARG(len) << CAF_ARG(debug_name));
CAF_IGNORE_UNUSED(debug_name);
if (connecting_) {
CAF_LOG_DEBUG(debug_name << ": connecting");
auto res = SSL_connect(ssl_);
if (res == 1) {
CAF_LOG_DEBUG("SSL connection established");
connecting_ = false;
} else {
result = 0;
return check_ssl_res(res);
}
}
if (accepting_) {
CAF_LOG_DEBUG(debug_name << ": accepting");
auto res = SSL_accept(ssl_);
if (res == 1) {
CAF_LOG_DEBUG("SSL connection accepted");
accepting_ = false;
} else {
result = 0;
return check_ssl_res(res);
}
}
CAF_LOG_DEBUG(debug_name << ": calling SSL_write or SSL_read");
if (len == 0) {
result = 0;
return rw_state::indeterminate;
}
auto ret = f(ssl_, buf, static_cast<int>(len));
if (ret > 0) {
result = static_cast<size_t>(ret);
return rw_state::success;
}
result = 0;
return handle_ssl_result(ret) ? rw_state::success : rw_state::failure;
}
rw_state session::read_some(size_t& result, native_socket, void* buf,
size_t len) {
CAF_LOG_TRACE(CAF_ARG(len));
return do_some(SSL_read, result, buf, len, "read_some");
}
rw_state session::write_some(size_t& result, native_socket, const void* buf,
size_t len) {
CAF_LOG_TRACE(CAF_ARG(len));
auto wr_fun = [](SSL* sptr, void* vptr, int ptr_size) {
return SSL_write(sptr, vptr, ptr_size);
};
return do_some(wr_fun, result, const_cast<void*>(buf), len, "write_some");
}
bool session::try_connect(native_socket fd) {
CAF_LOG_TRACE(CAF_ARG(fd));
SSL_set_fd(ssl_, fd);
SSL_set_connect_state(ssl_);
auto ret = SSL_connect(ssl_);
if (ret == 1)
return true;
connecting_ = true;
return handle_ssl_result(ret);
}
bool session::try_accept(native_socket fd) {
CAF_LOG_TRACE(CAF_ARG(fd));
SSL_set_fd(ssl_, fd);
SSL_set_accept_state(ssl_);
auto ret = SSL_accept(ssl_);
if (ret == 1)
return true;
accepting_ = true;
return handle_ssl_result(ret);
}
const char* session::openssl_passphrase() {
return openssl_passphrase_.c_str();
}
SSL_CTX* session::create_ssl_context() {
auto ctx = SSL_CTX_new(TLSv1_2_method());
if (!ctx)
raise_ssl_error("cannot create OpenSSL context");
if (sys_.openssl_manager().authentication_enabled()) {
// Require valid certificates on both sides.
auto& cfg = sys_.config();
if (cfg.openssl_certificate.size() > 0
&& SSL_CTX_use_certificate_chain_file(ctx,
cfg.openssl_certificate.c_str())
!= 1)
raise_ssl_error("cannot load certificate");
if (cfg.openssl_passphrase.size() > 0) {
openssl_passphrase_ = cfg.openssl_passphrase;
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ctx, this);
}
if (cfg.openssl_key.size() > 0
&& SSL_CTX_use_PrivateKey_file(ctx, cfg.openssl_key.c_str(),
SSL_FILETYPE_PEM)
!= 1)
raise_ssl_error("cannot load private key");
auto cafile =
(cfg.openssl_cafile.size() > 0 ? cfg.openssl_cafile.c_str() : nullptr);
auto capath =
(cfg.openssl_capath.size() > 0 ? cfg.openssl_capath.c_str() : nullptr);
if (cafile || capath) {
if (SSL_CTX_load_verify_locations(ctx, cafile, capath) != 1)
raise_ssl_error("cannot load trusted CA certificates");
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
nullptr);
if (SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!MD5") != 1)
raise_ssl_error("cannot set cipher list");
} else {
// No authentication.
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr);
auto ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
if (!ecdh)
raise_ssl_error("cannot get ECDH curve");
CAF_PUSH_WARNINGS
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
CAF_POP_WARNINGS
if (SSL_CTX_set_cipher_list(ctx, "AECDH-AES256-SHA") != 1)
raise_ssl_error("cannot set anonymous cipher");
}
return ctx;
}
std::string session::get_ssl_error() {
std::string msg = "";
while (auto err = ERR_get_error()) {
if (msg.size() > 0)
msg += " ";
char buf[256];
ERR_error_string_n(err, buf, sizeof(buf));
msg += buf;
}
return msg;
}
void session::raise_ssl_error(std::string msg) {
CAF_RAISE_ERROR(std::string("[OpenSSL] ") + msg + ": " + get_ssl_error());
}
bool session::handle_ssl_result(int ret) {
auto err = SSL_get_error(ssl_, ret);
switch (err) {
case SSL_ERROR_WANT_READ:
CAF_LOG_DEBUG("Nonblocking call to SSL returned want_read");
return true;
case SSL_ERROR_WANT_WRITE:
CAF_LOG_DEBUG("Nonblocking call to SSL returned want_write");
return true;
case SSL_ERROR_ZERO_RETURN: // Regular remote connection shutdown.
case SSL_ERROR_SYSCALL: // Socket connection closed.
return false;
default: // Other error
CAF_LOG_INFO("SSL call failed:" << get_ssl_error());
return false;
}
}
session_ptr make_session(actor_system& sys, native_socket fd,
bool from_accepted_socket) {
auto ptr = make_counted<session>(sys);
if (!ptr->init())
return nullptr;
if (from_accepted_socket) {
if (!ptr->try_accept(fd))
return nullptr;
} else {
if (!ptr->try_connect(fd))
return nullptr;
}
return ptr;
}
} // namespace openssl
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE openssl_authentication
#include "caf/test/unit_test.hpp"
#include <unistd.h>
#include <vector>
#include <sstream>
#include <utility>
#include <algorithm>
#include <limits.h>
#include <stdlib.h>
#include "caf/all.hpp"
#include "caf/io/all.hpp"
#include "caf/openssl/all.hpp"
using namespace caf;
namespace {
constexpr char local_host[] = "127.0.0.1";
class config : public actor_system_config {
public:
config() {
load<io::middleman>();
load<openssl::manager>();
add_message_type<std::vector<int>>("std::vector<int>");
actor_system_config::parse(test::engine::argc(), test::engine::argv());
middleman_detach_multiplexer = false;
middleman_detach_utility_actors = false;
scheduler_policy = atom("testing");
}
static std::string data_dir() {
std::string path{::caf::test::engine::path()};
path = path.substr(0, path.find_last_of("/"));
// TODO: https://github.com/actor-framework/actor-framework/issues/555
path += "/../../libcaf_openssl/test";
char rpath[PATH_MAX];
auto rp = realpath(path.c_str(), rpath);
std::string result;
if (rp)
result = rp;
return result;
}
};
behavior make_pong_behavior() {
return {
[](int val) -> int {
++val;
CAF_MESSAGE("pong " << val);
return val;
}
};
}
behavior make_ping_behavior(event_based_actor* self, const actor& pong) {
CAF_MESSAGE("ping " << 0);
self->send(pong, 0);
return {
[=](int val) -> int {
CAF_MESSAGE("ping " << val);
if (val >= 3) {
CAF_MESSAGE("terminate ping");
self->quit();
}
return val;
}
};
}
struct fixture {
using sched_t = scheduler::test_coordinator;
config server_side_config;
config client_side_config;
bool initialized;
union { actor_system server_side; };
union { actor_system client_side; };
sched_t* ssched;
sched_t* csched;
fixture() : initialized(false) {
// nop
}
~fixture() {
if (initialized) {
server_side.~actor_system();
client_side.~actor_system();
}
}
bool init(bool skip_client_side_ca) {
auto cd = config::data_dir();
cd += '/';
server_side_config.openssl_passphrase = "12345";
// check whether all files exist before setting config parameters
std::string dummy;
std::pair<const char*, std::string*> cfg[] {
{"ca.pem", &server_side_config.openssl_cafile},
{"cert.1.pem", &server_side_config.openssl_certificate},
{"key.1.enc.pem", &server_side_config.openssl_key},
{"ca.pem", skip_client_side_ca ? &dummy
: &client_side_config.openssl_cafile},
{"cert.2.pem", &client_side_config.openssl_certificate},
{"key.2.pem", &client_side_config.openssl_key}
};
// return if any file is unreadable or non-existend
for (auto& x : cfg) {
auto path = cd + x.first;
if (access(path.c_str(), F_OK) == -1) {
CAF_MESSAGE("pem files missing, skip test");
return false;
}
*x.second = std::move(path);
}
CAF_MESSAGE("initialize server side");
new (&server_side) actor_system(server_side_config);
CAF_MESSAGE("initialize client side");
new (&client_side) actor_system(client_side_config);
ssched = &dynamic_cast<sched_t&>(server_side.scheduler());
csched = &dynamic_cast<sched_t&>(client_side.scheduler());
initialized = true;
return true;
}
sched_t& sched_by_sys(actor_system& sys) {
return &sys == &server_side ? *ssched : *csched;
}
bool exec_one(actor_system& sys) {
CAF_ASSERT(initialized);
CAF_PUSH_AID(0);
CAF_SET_LOGGER_SYS(&sys);
return sched_by_sys(sys).try_run_once()
|| sys.middleman().backend().try_run_once();
}
void exec_loop(actor_system& sys) {
while (exec_one(sys))
; // nop
}
void exec_loop() {
while (exec_one(client_side) | exec_one(server_side))
; // nop
}
void loop_after_next_enqueue(actor_system& sys) {
auto s = &sys == &server_side ? ssched : csched;
s->after_next_enqueue([=] { exec_loop(); });
}
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(authentication, fixture)
using openssl::remote_actor;
using openssl::publish;
CAF_TEST(authentication_succes) {
if (!init(false))
return;
// server side
CAF_MESSAGE("spawn pong on server");
auto spong = server_side.spawn(make_pong_behavior);
exec_loop();
loop_after_next_enqueue(server_side);
CAF_MESSAGE("publish pong");
CAF_EXP_THROW(port, publish(spong, 0, local_host));
exec_loop();
// client side
CAF_MESSAGE("connect to pong via port " << port);
loop_after_next_enqueue(client_side);
CAF_EXP_THROW(pong, remote_actor(client_side, local_host, port));
CAF_MESSAGE("spawn ping and exchange messages");
client_side.spawn(make_ping_behavior, pong);
exec_loop();
CAF_MESSAGE("terminate pong");
anon_send_exit(spong, exit_reason::user_shutdown);
exec_loop();
}
CAF_TEST(authentication_failure) {
if (!init(true))
return;
// server side
CAF_MESSAGE("spawn pong on server");
auto spong = server_side.spawn(make_pong_behavior);
exec_loop();
loop_after_next_enqueue(server_side);
CAF_MESSAGE("publish pong");
CAF_EXP_THROW(port, publish(spong, 0, local_host));
exec_loop();
// client side
CAF_MESSAGE("connect to pong via port " << port);
loop_after_next_enqueue(client_side);
auto remote_pong = remote_actor(client_side, local_host, port);
CAF_CHECK(!remote_pong);
CAF_MESSAGE("terminate pong");
anon_send_exit(spong, exit_reason::user_shutdown);
exec_loop();
}
CAF_TEST_FIXTURE_SCOPE_END()
-----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-----
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-----
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-----
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-----
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE openssl_dynamic_remote_actor
#include "caf/test/unit_test.hpp"
#include <vector>
#include <sstream>
#include <utility>
#include <algorithm>
#include "caf/all.hpp"
#include "caf/io/all.hpp"
#include "caf/openssl/all.hpp"
using namespace caf;
namespace {
constexpr char local_host[] = "127.0.0.1";
class config : public actor_system_config {
public:
config() {
load<io::middleman>();
load<openssl::manager>();
add_message_type<std::vector<int>>("std::vector<int>");
actor_system_config::parse(test::engine::argc(),
test::engine::argv());
}
};
struct fixture {
config server_side_config;
actor_system server_side{server_side_config};
config client_side_config;
actor_system client_side{client_side_config};
};
behavior make_pong_behavior() {
return {
[](int val) -> int {
++val;
CAF_MESSAGE("pong with " << val);
return val;
}
};
}
behavior make_ping_behavior(event_based_actor* self, const actor& pong) {
CAF_MESSAGE("ping with " << 0);
self->send(pong, 0);
return {
[=](int val) -> int {
if (val == 3) {
CAF_MESSAGE("ping with exit");
self->send_exit(self->current_sender(),
exit_reason::user_shutdown);
CAF_MESSAGE("ping quits");
self->quit();
}
CAF_MESSAGE("ping with " << val);
return val;
}
};
}
std::string to_string(const std::vector<int>& vec) {
std::ostringstream os;
for (size_t i = 0; i + 1 < vec.size(); ++i)
os << vec[i] << ", ";
os << vec.back();
return os.str();
}
behavior make_sort_behavior() {
return {
[](std::vector<int>& vec) -> std::vector<int> {
CAF_MESSAGE("sorter received: " << to_string(vec));
std::sort(vec.begin(), vec.end());
CAF_MESSAGE("sorter sent: " << to_string(vec));
return std::move(vec);
}
};
}
behavior make_sort_requester_behavior(event_based_actor* self, const actor& sorter) {
self->send(sorter, std::vector<int>{5, 4, 3, 2, 1});
return {
[=](const std::vector<int>& vec) {
CAF_MESSAGE("sort requester received: " << to_string(vec));
for (size_t i = 1; i < vec.size(); ++i)
CAF_CHECK_EQUAL(static_cast<int>(i), vec[i - 1]);
self->send_exit(sorter, exit_reason::user_shutdown);
self->quit();
}
};
}
behavior fragile_mirror(event_based_actor* self) {
return {
[=](int i) {
self->quit(exit_reason::user_shutdown);
return i;
}
};
}
behavior linking_actor(event_based_actor* self, const actor& buddy) {
CAF_MESSAGE("link to mirror and send dummy message");
self->link_to(buddy);
self->send(buddy, 42);
return {
[](int i) {
CAF_CHECK_EQUAL(i, 42);
}
};
}
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(dynamic_remote_actor_tests, fixture)
using openssl::remote_actor;
using openssl::publish;
CAF_TEST(identity_semantics) {
// server side
auto server = server_side.spawn(make_pong_behavior);
CAF_EXP_THROW(port1, publish(server, 0, local_host));
CAF_EXP_THROW(port2, publish(server, 0, local_host));
CAF_REQUIRE_NOT_EQUAL(port1, port2);
CAF_EXP_THROW(same_server, remote_actor(server_side, local_host, port2));
CAF_REQUIRE_EQUAL(same_server, server);
CAF_CHECK_EQUAL(same_server->node(), server_side.node());
CAF_EXP_THROW(server1, remote_actor(client_side, local_host, port1));
CAF_EXP_THROW(server2, remote_actor(client_side, local_host, port2));
CAF_CHECK_EQUAL(server1, remote_actor(client_side, local_host, port1));
CAF_CHECK_EQUAL(server2, remote_actor(client_side, local_host, port2));
anon_send_exit(server, exit_reason::user_shutdown);
}
CAF_TEST(ping_pong) {
// server side
CAF_EXP_THROW(port,
publish(server_side.spawn(make_pong_behavior), 0, local_host));
// client side
CAF_EXP_THROW(pong, remote_actor(client_side, local_host, port));
client_side.spawn(make_ping_behavior, pong);
}
CAF_TEST(custom_message_type) {
// server side
CAF_EXP_THROW(port,
publish(server_side.spawn(make_sort_behavior), 0, local_host));
// client side
CAF_EXP_THROW(sorter, remote_actor(client_side, local_host, port));
client_side.spawn(make_sort_requester_behavior, sorter);
}
CAF_TEST(remote_link) {
// server side
CAF_EXP_THROW(port,
publish(server_side.spawn(fragile_mirror), 0, local_host));
// client side
CAF_EXP_THROW(mirror, remote_actor(client_side, local_host, port));
auto linker = client_side.spawn(linking_actor, mirror);
scoped_actor self{client_side};
self->wait_for(linker);
CAF_MESSAGE("linker exited");
self->wait_for(mirror);
CAF_MESSAGE("mirror exited");
}
CAF_TEST_FIXTURE_SCOPE_END()
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