Commit 18b5a995 authored by Dominik Charousset's avatar Dominik Charousset

Add scaffold for OpenSSL module

parent 2fcea6ab
...@@ -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
......
...@@ -494,6 +494,12 @@ endmacro() ...@@ -494,6 +494,12 @@ 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
find_package(OpenSSL)
if(OPENSSL_FOUND)
add_optional_caf_lib(openssl)
endif(OPENSSL_FOUND)
# 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)
......
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)
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})
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})
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 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. *
******************************************************************************/
#include "caf/openssl/manager.hpp"
#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("");
// TODO: initialize OpenSSL state
}
actor_system::module::id_t manager::id() const {
return openssl_manager;
}
void* manager::subtype_ptr() {
return this;
}
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"
namespace caf {
namespace openssl {
namespace {
using native_socket = io::network::native_socket;
using default_mpx = io::network::default_multiplexer;
struct ssl_policy {
/// Reads up to `len` bytes from an OpenSSL socket.
static bool read_some(size_t& result, native_socket fd, void* buf,
size_t len) {
CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(len));
// TODO: implement me
CAF_RAISE_ERROR("unimplemented function: openssl::read_some");
}
static bool write_some(size_t& result, native_socket fd, const void* buf,
size_t len) {
CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(len));
// TODO: implement me
CAF_RAISE_ERROR("unimplemented function: openssl::write_some");
}
static bool try_accept(native_socket& result, native_socket fd) {
CAF_LOG_TRACE(CAF_ARG(fd));
// TODO: implement me
CAF_RAISE_ERROR("unimplemented function: openssl::try_accept");
}
};
class scribe_impl : public io::scribe {
public:
scribe_impl(default_mpx& mpx, native_socket sockfd)
: scribe(io::network::conn_hdl_from_socket(sockfd)),
launched_(false),
stream_(mpx, sockfd) {
// nop
}
void configure_read(io::receive_policy::config config) override {
CAF_LOG_TRACE("");
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);
}
void add_to_loop() override {
stream_.activate(this);
}
void remove_from_loop() override {
stream_.passivate();
}
private:
bool launched_;
io::network::stream_impl<ssl_policy> stream_;
};
class doorman_impl : public io::doorman {
public:
doorman_impl(default_mpx& mx, native_socket sockfd)
: doorman(io::network::accept_hdl_from_socket(sockfd)),
acceptor_(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 sptr = dm.new_scribe(acceptor_.accepted_socket());
auto hdl = sptr->hdl();
parent()->add_scribe(std::move(sptr));
return doorman::new_connection(&dm, hdl);
}
void stop_reading() override {
CAF_LOG_TRACE("");
acceptor_.stop_reading();
detach(&acceptor_.backend(), false);
}
void launch() override {
CAF_LOG_TRACE("");
acceptor_.start(this);
}
std::string addr() const override {
auto x = io::network::local_addr_of_fd(acceptor_.fd());
if (!x)
return "";
return std::move(*x);
}
uint16_t port() const override {
auto x = io::network::local_port_of_fd(acceptor_.fd());
if (!x)
return 0;
return *x;
}
void add_to_loop() override {
acceptor_.activate(this);
}
void remove_from_loop() override {
acceptor_.passivate();
}
private:
io::network::acceptor_impl<ssl_policy> acceptor_;
};
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
}
protected:
expected<io::scribe_ptr> connect(const std::string& host,
uint16_t port) override {
native_socket fd;
// TODO: implement me
return make_counted<scribe_impl>(mpx(), fd);
}
expected<io::doorman_ptr> open(uint16_t port, const char* addr,
bool reuse) override {
native_socket fd;
// TODO: implement me
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(expected) << CAF_ARG(host) << CAF_ARG(port));
expected<strong_actor_ptr> res{strong_actor_ptr{nullptr}};
scoped_actor self{sys};
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 (res) {
if (sys.assignable(found, mpi))
res = std::move(ptr);
else
res = sec::unexpected_actor_messaging_interface;
}
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/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 {
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