Commit b45136ea authored by Dominik Charousset's avatar Dominik Charousset

Merge pull request #299 from actor-framework/topic/asio

Add boost asio as an optional multiplexer backend
parents 53e67b5d e3bea9a2
...@@ -28,6 +28,10 @@ endif() ...@@ -28,6 +28,10 @@ endif()
if(NOT CAF_NO_SUMMARY) if(NOT CAF_NO_SUMMARY)
set(CAF_NO_SUMMARY no) set(CAF_NO_SUMMARY no)
endif() endif()
if(NOT CAF_USE_ASIO)
set(CAF_USE_ASIO no)
endif()
################################################################################ ################################################################################
# get version of CAF # # get version of CAF #
...@@ -243,6 +247,10 @@ if(CAF_NO_MEM_MANAGEMENT) ...@@ -243,6 +247,10 @@ if(CAF_NO_MEM_MANAGEMENT)
add_definitions(-DCAF_NO_MEM_MANAGEMENT) add_definitions(-DCAF_NO_MEM_MANAGEMENT)
endif() endif()
if (CAF_USE_ASIO)
add_definitions(-DCAF_USE_ASIO)
endif()
################################################################################ ################################################################################
# check for biicode build pipeline # # check for biicode build pipeline #
################################################################################ ################################################################################
...@@ -320,6 +328,20 @@ endif() ...@@ -320,6 +328,20 @@ endif()
# all projects need the headers of the core components # all projects need the headers of the core components
include_directories("${LIBCAF_INCLUDE_DIRS}") include_directories("${LIBCAF_INCLUDE_DIRS}")
# Find boost asio if the asio multiplexer should be used
if (CAF_USE_ASIO)
if (CAF_BUILD_STATIC_ONLY)
set(Boost_USE_STATIC_LIBS ON) # only find static libs
endif()
set(Boost_USE_MULTITHREADED ON)
find_package(Boost REQUIRED COMPONENTS system)
if (Boost_FOUND)
set(INCLUDE_DIRS "${INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}")
set(LD_DIRS ${LD_DIRS} ${Boost_LIBRARIES})
set(LD_FLAGS ${LD_FLAGS} ${Boost_SYSTEM_LIBRARY})
endif()
endif()
################################################################################ ################################################################################
# add subprojects # # add subprojects #
...@@ -563,6 +585,7 @@ if(NOT CAF_NO_SUMMARY) ...@@ -563,6 +585,7 @@ if(NOT CAF_NO_SUMMARY)
"\nRuntime checks: ${CAF_ENABLE_RUNTIME_CHECKS}" "\nRuntime checks: ${CAF_ENABLE_RUNTIME_CHECKS}"
"\nLog level: ${LOG_LEVEL_STR}" "\nLog level: ${LOG_LEVEL_STR}"
"\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}" "\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}"
"\nUse Boost ASIO: ${CAF_USE_ASIO}"
"\n" "\n"
"\nBuild examples: ${CAF_BUILD_EXAMPLES}" "\nBuild examples: ${CAF_BUILD_EXAMPLES}"
"\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}" "\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}"
......
...@@ -49,6 +49,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]... ...@@ -49,6 +49,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--no-compiler-check disable compiler version check --no-compiler-check disable compiler version check
--no-auto-libc++ do not automatically enable libc++ for Clang --no-auto-libc++ do not automatically enable libc++ for Clang
--warnings-as-errors enables -Werror --warnings-as-errors enables -Werror
--with-asio enable ASIO multiplexer
Installation Directories: Installation Directories:
--prefix=PREFIX installation directory [/usr/local] --prefix=PREFIX installation directory [/usr/local]
...@@ -241,6 +242,9 @@ while [ $# -ne 0 ]; do ...@@ -241,6 +242,9 @@ while [ $# -ne 0 ]; do
append_cache_entry CMAKE_OSX_ARCHITECTURES STRING "\$(ARCHS_STANDARD_32_64_BIT)" append_cache_entry CMAKE_OSX_ARCHITECTURES STRING "\$(ARCHS_STANDARD_32_64_BIT)"
append_cache_entry CAF_IOS_DEPLOYMENT_TARGET STRING "$optarg" append_cache_entry CAF_IOS_DEPLOYMENT_TARGET STRING "$optarg"
;; ;;
--with-asio)
append_cache_entry CAF_USE_ASIO BOOL yes
;;
--with-log-level=*) --with-log-level=*)
level=`echo "$optarg" | tr '[:lower:]' '[:upper:]'` level=`echo "$optarg" | tr '[:lower:]' '[:upper:]'`
case $level in case $level in
......
...@@ -13,7 +13,6 @@ set (LIBCAF_IO_SRCS ...@@ -13,7 +13,6 @@ set (LIBCAF_IO_SRCS
src/middleman.cpp src/middleman.cpp
src/hook.cpp src/hook.cpp
src/interfaces.cpp src/interfaces.cpp
src/default_multiplexer.cpp
src/publish.cpp src/publish.cpp
src/publish_local_groups.cpp src/publish_local_groups.cpp
src/remote_actor.cpp src/remote_actor.cpp
...@@ -26,6 +25,12 @@ set (LIBCAF_IO_SRCS ...@@ -26,6 +25,12 @@ set (LIBCAF_IO_SRCS
add_custom_target(libcaf_io) add_custom_target(libcaf_io)
if (CAF_USE_ASIO)
set(LIBCAF_IO_SRCS ${LIBCAF_IO_SRCS} src/asio_multiplexer.cpp)
else()
set(LIBCAF_IO_SRCS ${LIBCAF_IO_SRCS} src/default_multiplexer.cpp)
endif()
# build shared library if not compiling static only # build shared library if not compiling static only
if (NOT CAF_BUILD_STATIC_ONLY) if (NOT CAF_BUILD_STATIC_ONLY)
add_library(libcaf_io_shared SHARED ${LIBCAF_IO_SRCS} ${LIBCAF_IO_HDRS}) add_library(libcaf_io_shared SHARED ${LIBCAF_IO_SRCS} ${LIBCAF_IO_HDRS})
......
This diff is collapsed.
This diff is collapsed.
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <cstddef> #include <cstddef>
#include <utility> #include <utility>
#include "caf/config.hpp"
namespace caf { namespace caf {
namespace io { namespace io {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen (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/exception.hpp"
#include "caf/io/broker.hpp"
#include "caf/io/middleman.hpp"
#include "caf/io/network/asio_multiplexer.hpp"
namespace caf {
namespace io {
namespace network {
default_socket new_tcp_connection(io_backend& backend, const std::string& host,
uint16_t port) {
default_socket fd{backend};
using boost::asio::ip::tcp;
try {
tcp::resolver r(fd.get_io_service());
tcp::resolver::query q(host, std::to_string(port));
auto i = r.resolve(q);
boost::asio::connect(fd, i);
} catch (boost::system::system_error& se) {
throw network_error(se.code().message());
}
return fd;
}
void ip_bind(default_socket_acceptor& fd, uint16_t port,
const char* addr = nullptr, bool reuse_addr = true) {
CAF_LOGF_TRACE(CAF_ARG(port));
using boost::asio::ip::tcp;
try {
auto bind_and_listen = [&](tcp::endpoint& ep) {
fd.open(ep.protocol());
fd.set_option(tcp::acceptor::reuse_address(reuse_addr));
fd.bind(ep);
fd.listen();
};
if (addr) {
tcp::endpoint ep(boost::asio::ip::address::from_string(addr), port);
bind_and_listen(ep);
CAF_LOGF_DEBUG("created IPv6 endpoint: " << ep.address() << ":"
<< fd.local_endpoint().port());
} else {
tcp::endpoint ep(tcp::v6(), port);
bind_and_listen(ep);
CAF_LOGF_DEBUG("created IPv6 endpoint: " << ep.address() << ":"
<< fd.local_endpoint().port());
}
} catch (boost::system::system_error& se) {
if (se.code() == boost::system::errc::address_in_use) {
throw bind_failure(se.code().message());
}
throw network_error(se.code().message());
}
}
connection_handle asio_multiplexer::new_tcp_scribe(const std::string& host,
uint16_t port) {
default_socket fd{new_tcp_connection(backend(), host, port)};
auto id = int64_from_native_socket(fd.native_handle());
std::lock_guard<std::mutex> lock(m_mtx_sockets);
m_unassigned_sockets.insert(std::make_pair(id, std::move(fd)));
return connection_handle::from_int(id);
}
void asio_multiplexer::assign_tcp_scribe(broker* self, connection_handle hdl) {
std::lock_guard<std::mutex> lock(m_mtx_sockets);
auto itr = m_unassigned_sockets.find(hdl.id());
if (itr != m_unassigned_sockets.end()) {
add_tcp_scribe(self, std::move(itr->second));
m_unassigned_sockets.erase(itr);
}
}
template <class Socket>
connection_handle asio_multiplexer::add_tcp_scribe(broker* self,
Socket&& sock) {
CAF_LOG_TRACE("");
class impl : public broker::scribe {
public:
impl(broker* ptr, Socket&& s)
: scribe(ptr, network::conn_hdl_from_socket(s)),
m_launched(false),
m_stream(s.get_io_service()) {
m_stream.init(std::move(s));
}
void configure_read(receive_policy::config config) override {
CAF_LOG_TRACE("");
m_stream.configure_read(config);
if (!m_launched) {
launch();
}
}
broker::buffer_type& wr_buf() override { return m_stream.wr_buf(); }
broker::buffer_type& rd_buf() override { return m_stream.rd_buf(); }
void stop_reading() override {
CAF_LOG_TRACE("");
m_stream.stop_reading();
disconnect(false);
}
void flush() override {
CAF_LOG_TRACE("");
m_stream.flush(this);
}
void launch() {
CAF_LOG_TRACE("");
CAF_ASSERT(!m_launched);
m_launched = true;
m_stream.start(this);
}
private:
bool m_launched;
stream<Socket> m_stream;
};
broker::scribe_pointer ptr = make_counted<impl>(self, std::move(sock));
self->add_scribe(ptr);
return ptr->hdl();
}
connection_handle asio_multiplexer::add_tcp_scribe(broker* self,
native_socket fd) {
CAF_LOG_TRACE(CAF_ARG(self) << ", " << CAF_ARG(fd));
boost::system::error_code ec;
default_socket sock{backend()};
sock.assign(boost::asio::ip::tcp::v6(), fd, ec);
if (ec) {
sock.assign(boost::asio::ip::tcp::v4(), fd, ec);
}
if (ec) {
throw network_error(ec.message());
}
return add_tcp_scribe(self, std::move(sock));
}
connection_handle asio_multiplexer::add_tcp_scribe(broker* self,
const std::string& host,
uint16_t port) {
CAF_LOG_TRACE(CAF_ARG(self) << ", " << CAF_ARG(host) << ":" << CAF_ARG(port));
return add_tcp_scribe(self, new_tcp_connection(backend(), host, port));
}
std::pair<accept_handle, uint16_t>
asio_multiplexer::new_tcp_doorman(uint16_t port, const char* in, bool rflag) {
CAF_LOG_TRACE(CAF_ARG(port) << ", addr = " << (in ? in : "nullptr"));
default_socket_acceptor fd{backend()};
ip_bind(fd, port, in, rflag);
auto id = int64_from_native_socket(fd.native_handle());
auto assigned_port = fd.local_endpoint().port();
std::lock_guard<std::mutex> lock(m_mtx_acceptors);
m_unassigned_acceptors.insert(std::make_pair(id, std::move(fd)));
return {accept_handle::from_int(id), assigned_port};
}
void asio_multiplexer::assign_tcp_doorman(broker* self, accept_handle hdl) {
CAF_LOG_TRACE("");
std::lock_guard<std::mutex> lock(m_mtx_acceptors);
auto itr = m_unassigned_acceptors.find(hdl.id());
if (itr != m_unassigned_acceptors.end()) {
add_tcp_doorman(self, std::move(itr->second));
m_unassigned_acceptors.erase(itr);
}
}
accept_handle
asio_multiplexer::add_tcp_doorman(broker* self,
default_socket_acceptor&& sock) {
CAF_LOG_TRACE("sock.fd = " << sock.native_handle());
CAF_ASSERT(sock.native_handle() != network::invalid_native_socket);
class impl : public broker::doorman {
public:
impl(broker* ptr, default_socket_acceptor&& s,
network::asio_multiplexer& am)
: doorman(ptr, network::accept_hdl_from_socket(s)),
m_acceptor(am, s.get_io_service()) {
m_acceptor.init(std::move(s));
}
void new_connection() override {
CAF_LOG_TRACE("");
auto& am = m_acceptor.backend();
accept_msg().handle
= am.add_tcp_scribe(parent(), std::move(m_acceptor.accepted_socket()));
parent()->invoke_message(invalid_actor_addr, invalid_message_id,
m_accept_msg);
}
void stop_reading() override {
CAF_LOG_TRACE("");
m_acceptor.stop();
disconnect(false);
}
void launch() override {
CAF_LOG_TRACE("");
m_acceptor.start(this);
}
private:
network::acceptor<default_socket_acceptor> m_acceptor;
};
broker::doorman_pointer ptr
= make_counted<impl>(self, std::move(sock), *this);
self->add_doorman(ptr);
return ptr->hdl();
}
accept_handle asio_multiplexer::add_tcp_doorman(broker* self,
native_socket fd) {
default_socket_acceptor sock{backend()};
boost::system::error_code ec;
sock.assign(boost::asio::ip::tcp::v6(), fd, ec);
if (ec) {
sock.assign(boost::asio::ip::tcp::v4(), fd, ec);
}
if (ec) {
throw network_error(ec.message());
}
return add_tcp_doorman(self, std::move(sock));
}
std::pair<accept_handle, uint16_t>
asio_multiplexer::add_tcp_doorman(broker* self, uint16_t port, const char* in,
bool rflag) {
default_socket_acceptor fd{backend()};
ip_bind(fd, port, in, rflag);
auto p = fd.local_endpoint().port();
return {add_tcp_doorman(self, std::move(fd)), p};
}
void asio_multiplexer::dispatch_runnable(runnable_ptr ptr) {
auto r = ptr.release();
backend().post([=]() {
r->run();
r->request_deletion(false);
});
}
asio_multiplexer::asio_multiplexer() {
// nop
}
asio_multiplexer::~asio_multiplexer() {
//nop
}
multiplexer::supervisor_ptr asio_multiplexer::make_supervisor() {
return std::unique_ptr<asio_supervisor>(new asio_supervisor(backend()));
}
void asio_multiplexer::run() {
CAF_LOG_TRACE("asio-based multiplexer");
boost::system::error_code ec;
backend().run(ec);
if (ec) {
throw std::runtime_error(ec.message());
}
}
asio_multiplexer& get_multiplexer_singleton() {
return static_cast<asio_multiplexer&>(middleman::instance()->backend());
}
} // namesapce network
} // namespace io
} // namespace caf
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