Unverified Commit e9946674 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #816

Implement BASP v3
parents 792f39c2 06b57043
doc/png/basp_header.png

219 KB | W: | H:

doc/png/basp_header.png

27.7 KB | W: | H:

doc/png/basp_header.png
doc/png/basp_header.png
doc/png/basp_header.png
doc/png/basp_header.png
  • 2-up
  • Swipe
  • Onion skin
doc/png/client_handshake.png

213 KB | W: | H:

doc/png/client_handshake.png

25.7 KB | W: | H:

doc/png/client_handshake.png
doc/png/client_handshake.png
doc/png/client_handshake.png
doc/png/client_handshake.png
  • 2-up
  • Swipe
  • Onion skin
doc/png/heartbeat.png

198 KB | W: | H:

doc/png/heartbeat.png

22.3 KB | W: | H:

doc/png/heartbeat.png
doc/png/heartbeat.png
doc/png/heartbeat.png
doc/png/heartbeat.png
  • 2-up
  • Swipe
  • Onion skin
doc/png/server_handshake.png

243 KB | W: | H:

doc/png/server_handshake.png

36.2 KB | W: | H:

doc/png/server_handshake.png
doc/png/server_handshake.png
doc/png/server_handshake.png
doc/png/server_handshake.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -339,6 +339,10 @@ private:
static std::string render_pec(uint8_t, atom_value, const message&);
void extract_config_file_path(string_list& args);
/// Adjusts the content of the configuration, e.g., for ensuring backwards
/// compatibility with older options.
error adjust_content();
};
/// @private
......
......@@ -20,6 +20,8 @@
#include <chrono>
#include <cstddef>
#include <string>
#include <vector>
#include "caf/atom.hpp"
#include "caf/string_view.hpp"
......@@ -74,7 +76,7 @@ extern const atom_value file_verbosity;
namespace middleman {
extern string_view app_identifier;
extern std::vector<std::string> app_identifiers;
extern const atom_value network_backend;
extern const size_t max_consecutive_reads;
extern const size_t heartbeat_interval;
......
......@@ -109,7 +109,9 @@ actor_system_config::actor_system_config()
opt_group{custom_options_, "middleman"}
.add<atom_value>("network-backend",
"either 'default' or 'asio' (if available)")
.add<string>("app-identifier", "application identifier of this node")
.add<std::vector<string>>("app-identifiers",
"valid application identifiers of this node")
.add<string>("app-identifier", "DEPRECATED: use app-identifiers instead")
.add<bool>("enable-automatic-connections",
"enables automatic connection management")
.add<size_t>("max-consecutive-reads",
......@@ -275,7 +277,7 @@ error actor_system_config::parse(string_list args, std::istream& ini) {
std::cout << std::flush;
cli_helptext_printed = true;
}
return none;
return adjust_content();
}
error actor_system_config::parse(string_list args, const char* ini_file_cstr) {
......@@ -302,6 +304,11 @@ actor_system_config::add_error_category(atom_value x, error_renderer y) {
actor_system_config& actor_system_config::set_impl(string_view name,
config_value value) {
if (name == "middleman.app-identifier") {
// TODO: Print a warning with 0.18 and remove this code with 0.19.
value.convert_to_list();
return set_impl("middleman.app-identifiers", std::move(value));
}
auto opt = custom_options_.qualified_name_lookup(name);
if (opt != nullptr && opt->check(value) == none) {
opt->store(value);
......@@ -377,6 +384,25 @@ void actor_system_config::extract_config_file_path(string_list& args) {
args.erase(i);
}
error actor_system_config::adjust_content() {
// TODO: Print a warning to STDERR if 'app-identifier' is present with 0.18
// and remove this code with 0.19.
auto i = content.find("middleman");
if (i != content.end()) {
if (auto mm = get_if<settings>(&i->second)) {
auto j = mm->find("app-identifier");
if (j != mm->end()) {
if (!mm->contains("app-identifiers")) {
j->second.convert_to_list();
mm->emplace("app-identifiers", std::move(j->second));
}
mm->container().erase(j);
}
}
}
return none;
}
const settings& content(const actor_system_config& cfg) {
return cfg.content;
}
......
......@@ -86,7 +86,7 @@ const atom_value file_verbosity = atom("trace");
namespace middleman {
string_view app_identifier = "";
std::vector<std::string> app_identifiers{"generic-caf-app"};
const atom_value network_backend = atom("default");
const size_t max_consecutive_reads = 50;
const size_t heartbeat_interval = 0;
......
......@@ -547,19 +547,18 @@ scheduled_actor::categorize(mailbox_element& x) {
case make_type_token<atom_value, atom_value, std::string>():
if (content.get_as<atom_value>(0) == sys_atom::value
&& content.get_as<atom_value>(1) == get_atom::value) {
auto rp = make_response_promise();
if (!rp.pending()) {
CAF_LOG_WARNING("received anonymous ('get', 'sys', $key) message");
return message_category::internal;
}
auto& what = content.get_as<std::string>(2);
if (what == "info") {
CAF_LOG_DEBUG("reply to 'info' message");
x.sender->enqueue(
make_mailbox_element(ctrl(), x.mid.response_id(),
{}, ok_atom::value, std::move(what),
strong_actor_ptr{ctrl()}, name()),
context());
rp.deliver(ok_atom::value, std::move(what), strong_actor_ptr{ctrl()},
name());
} else {
x.sender->enqueue(
make_mailbox_element(ctrl(), x.mid.response_id(),
{}, sec::unsupported_sys_key),
context());
rp.deliver(make_error(sec::unsupported_sys_key));
}
return message_category::internal;
}
......
......@@ -67,7 +67,7 @@
/// Whenever a node learns the address of a remotely running actor, it
/// creates Ma local proxy instance representing this actor and sends an
/// `announce_proxy_instance` to the node hosting the actor. Whenever an actor
/// terminates, the hosting node sends `kill_proxy_instance` messages to all
/// terminates, the hosting node sends `down_message` messages to all
/// nodes that have a proxy for this actor. This enables network-transparent
/// actor monitoring. There are two possible ways addresses can be learned:
///
......
......@@ -46,22 +46,18 @@ struct header {
uint8_t flags;
uint32_t payload_len;
uint64_t operation_data;
node_id source_node;
node_id dest_node;
actor_id source_actor;
actor_id dest_actor;
header(message_type m_operation, uint8_t m_flags, uint32_t m_payload_len,
uint64_t m_operation_data, node_id m_source_node, node_id m_dest_node,
actor_id m_source_actor, actor_id m_dest_actor)
: operation(m_operation),
flags(m_flags),
payload_len(m_payload_len),
operation_data(m_operation_data),
source_node(std::move(m_source_node)),
dest_node(std::move(m_dest_node)),
source_actor(m_source_actor),
dest_actor(m_dest_actor) {
uint64_t m_operation_data, actor_id m_source_actor,
actor_id m_dest_actor)
: operation(m_operation),
flags(m_flags),
payload_len(m_payload_len),
operation_data(m_operation_data),
source_actor(m_source_actor),
dest_actor(m_dest_actor) {
// nop
}
......@@ -85,7 +81,6 @@ typename Inspector::result_type inspect(Inspector& f, header& hdr) {
meta::omittable(), pad,
meta::omittable(), pad,
hdr.flags, hdr.payload_len, hdr.operation_data,
hdr.source_node, hdr.dest_node,
hdr.source_actor, hdr.dest_actor);
}
......@@ -113,8 +108,7 @@ inline bool is_heartbeat(const header& hdr) {
bool valid(const header& hdr);
/// Size of a BASP header in serialized form
constexpr size_t header_size = node_id::serialized_size * 2
+ sizeof(actor_id) * 2
constexpr size_t header_size = sizeof(actor_id) * 2
+ sizeof(uint32_t) * 2
+ sizeof(uint64_t);
......
......@@ -90,7 +90,7 @@ public:
virtual void learned_new_node_indirectly(const node_id& nid) = 0;
/// Called if a heartbeat was received from `nid`
virtual void handle_heartbeat(const node_id& nid) = 0;
virtual void handle_heartbeat() = 0;
/// Returns the actor namespace associated to this BASP protocol instance.
proxy_registry& proxies() {
......@@ -162,7 +162,7 @@ public:
/// Returns `true` if a path to destination existed, `false` otherwise.
bool dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
const std::vector<strong_actor_ptr>& forwarding_stack,
const strong_actor_ptr& receiver,
const node_id& dest_node, uint64_t dest_actor, uint8_t flags,
message_id mid, const message& msg);
/// Returns the actor namespace associated to this BASP protocol instance.
......@@ -200,28 +200,19 @@ public:
buffer_type& out_buf, optional<uint16_t> port);
/// Writes the client handshake to `buf`.
static void write_client_handshake(execution_unit* ctx,
buffer_type& buf,
const node_id& remote_side,
const node_id& this_node,
const std::string& app_identifier);
/// Writes the client handshake to `buf`.
void write_client_handshake(execution_unit* ctx,
buffer_type& buf, const node_id& remote_side);
void write_client_handshake(execution_unit* ctx, buffer_type& buf);
/// Writes an `announce_proxy` to `buf`.
void write_announce_proxy(execution_unit* ctx, buffer_type& buf,
const node_id& dest_node, actor_id aid);
void write_monitor_message(execution_unit* ctx, buffer_type& buf,
const node_id& dest_node, actor_id aid);
/// Writes a `kill_proxy` to `buf`.
void write_kill_proxy(execution_unit* ctx, buffer_type& buf,
const node_id& dest_node, actor_id aid,
const error& rsn);
void write_down_message(execution_unit* ctx, buffer_type& buf,
const node_id& dest_node, actor_id aid,
const error& rsn);
/// Writes a `heartbeat` to `buf`.
void write_heartbeat(execution_unit* ctx, buffer_type& buf,
const node_id& remote_side);
void write_heartbeat(execution_unit* ctx, buffer_type& buf);
const node_id& this_node() const {
return this_node_;
......@@ -241,6 +232,9 @@ public:
std::vector<char>* payload);
private:
void forward(execution_unit* ctx, const node_id& dest_node, const header& hdr,
std::vector<char>& payload);
routing_table tbl_;
published_actor_map published_actors_;
node_id this_node_;
......@@ -252,4 +246,3 @@ private:
} // namespace basp
} // namespace io
} // namespace caf
......@@ -42,31 +42,35 @@ enum class message_type : uint8_t {
/// ![](client_handshake.png)
client_handshake = 0x01,
/// Transmits a direct message from source to destination.
///
/// ![](direct_message.png)
direct_message = 0x02,
/// Transmits a message from `source_node:source_actor` to
/// `dest_node:dest_actor`.
///
/// ![](dispatch_message.png)
dispatch_message = 0x02,
/// ![](routed_message.png)
routed_message = 0x03,
/// Informs the receiving node that the sending node has created a proxy
/// instance for one of its actors. Causes the receiving node to attach
/// a functor to the actor that triggers a kill_proxy_instance
/// message on termination.
/// a functor to the actor that triggers a down_message on termination.
///
/// ![](announce_proxy_instance.png)
announce_proxy = 0x03,
/// ![](monitor_message.png)
monitor_message = 0x04,
/// Informs the receiving node that it has a proxy for an actor
/// that has been terminated.
///
/// ![](kill_proxy_instance.png)
kill_proxy = 0x04,
/// ![](down_message.png)
down_message = 0x05,
/// Used to generate periodic traffic between two nodes
/// in order to detect disconnects.
///
/// ![](heartbeat.png)
heartbeat = 0x05,
heartbeat = 0x06,
};
/// @relates message_type
......@@ -77,5 +81,3 @@ std::string to_string(message_type);
} // namespace basp
} // namespace io
} // namespace caf
......@@ -26,14 +26,11 @@ namespace basp {
/// @addtogroup BASP
/// The current BASP version. Different BASP versions will not
/// be able to exchange messages.
constexpr uint64_t version = 2;
/// The current BASP version. Note: BASP is not backwards compatible.
constexpr uint64_t version = 3;
/// @}
} // namespace basp
} // namespace io
} // namespace caf
......@@ -92,9 +92,8 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
// inherited from basp::instance::callee
void flush(connection_handle hdl) override;
void handle_heartbeat(const node_id&) override {
// nop
}
// inherited from basp::instance::callee
void handle_heartbeat() override;
/// Sets `this_context` by either creating or accessing state for `hdl`.
void set_context(connection_handle hdl);
......@@ -139,10 +138,10 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
// keeps a list of nodes that monitor a particular local actor
monitored_actor_map monitored_actors;
// sends a kill_proxy message to a remote node
void send_kill_proxy_instance(const node_id& nid, actor_id aid, error err);
// sends a basp::down_message message to a remote node
void send_basp_down_message(const node_id& nid, actor_id aid, error err);
// sends kill_proxy_instance message to all nodes monitoring the terminated
// sends basp::down_message to all nodes monitoring the terminated
// actor
void handle_down_msg(down_msg&);
......
......@@ -46,13 +46,7 @@ struct connection_helper_state {
static const char* name;
};
behavior datagram_connection_broker(broker* self,
uint16_t port,
network::address_listing addresses,
actor system_broker);
behavior connection_helper(stateful_actor<connection_helper_state>* self,
actor b);
} // namespace io
} // namespace caf
This diff is collapsed.
......@@ -34,41 +34,6 @@ auto autoconnect_timeout = std::chrono::minutes(10);
const char* connection_helper_state::name = "connection_helper";
behavior datagram_connection_broker(broker* self, uint16_t port,
network::address_listing addresses,
actor system_broker) {
auto& mx = self->system().middleman().backend();
auto& this_node = self->system().node();
auto app_id = get_or(self->config(), "middleman.app-identifier",
defaults::middleman::app_identifier);
for (auto& kvp : addresses) {
for (auto& addr : kvp.second) {
auto eptr = mx.new_remote_udp_endpoint(addr, port);
if (eptr) {
auto hdl = (*eptr)->hdl();
self->add_datagram_servant(std::move(*eptr));
basp::instance::write_client_handshake(self->context(),
self->wr_buf(hdl),
none, this_node,
app_id);
}
}
}
return {
[=](new_datagram_msg& msg) {
auto hdl = msg.handle;
self->send(system_broker, std::move(msg), self->take(hdl), port);
self->quit();
},
after(autoconnect_timeout) >> [=]() {
CAF_LOG_TRACE(CAF_ARG(""));
// nothing heard in about 10 minutes... just a call it a day, then
CAF_LOG_INFO("aborted direct connection attempt after 10min");
self->quit(exit_reason::user_shutdown);
}
};
}
behavior connection_helper(stateful_actor<connection_helper_state>* self,
actor b) {
CAF_LOG_TRACE(CAF_ARG(b));
......@@ -101,17 +66,6 @@ behavior connection_helper(stateful_actor<connection_helper_state>* self,
}
}
CAF_LOG_INFO("could not connect to node directly");
} else if (item == "basp.default-connectivity-udp") {
auto& sys = self->system();
// create new broker to try addresses for communication via UDP
if (get_or(sys.config(), "middleman.attach-utility-actors", false))
self->system().middleman().spawn_broker<hidden>(
datagram_connection_broker, port, std::move(addresses), b
);
else
self->system().middleman().spawn_broker<detached + hidden>(
datagram_connection_broker, port, std::move(addresses), b
);
} else {
CAF_LOG_INFO("aborted direct connection attempt, unknown item: "
<< CAF_ARG(item));
......
......@@ -40,8 +40,6 @@ std::string to_string(const header &hdr) {
<< to_bin(hdr.flags) << ", "
<< hdr.payload_len << ", "
<< hdr.operation_data << ", "
<< to_string(hdr.source_node) << ", "
<< to_string(hdr.dest_node) << ", "
<< hdr.source_actor << ", "
<< hdr.dest_actor
<< "}";
......@@ -53,70 +51,45 @@ bool operator==(const header& lhs, const header& rhs) {
&& lhs.flags == rhs.flags
&& lhs.payload_len == rhs.payload_len
&& lhs.operation_data == rhs.operation_data
&& lhs.source_node == rhs.source_node
&& lhs.dest_node == rhs.dest_node
&& lhs.source_actor == rhs.source_actor
&& lhs.dest_actor == rhs.dest_actor;
}
namespace {
bool valid(const node_id& val) {
return val != none;
}
template <class T>
bool zero(T val) {
return val == 0;
}
bool server_handshake_valid(const header& hdr) {
return valid(hdr.source_node)
&& zero(hdr.dest_actor)
&& !zero(hdr.operation_data);
return !zero(hdr.operation_data);
}
bool client_handshake_valid(const header& hdr) {
return valid(hdr.source_node)
&& hdr.source_node != hdr.dest_node
&& zero(hdr.source_actor)
&& zero(hdr.dest_actor);
return zero(hdr.source_actor) && zero(hdr.dest_actor);
}
bool direct_message_valid(const header& hdr) {
return !zero(hdr.dest_actor) && !zero(hdr.payload_len);
}
bool dispatch_message_valid(const header& hdr) {
return valid(hdr.dest_node)
&& (!zero(hdr.dest_actor) || hdr.has(header::named_receiver_flag))
&& !zero(hdr.payload_len);
bool routed_message_valid(const header& hdr) {
return !zero(hdr.dest_actor) && !zero(hdr.payload_len);
}
bool announce_proxy_instance_valid(const header& hdr) {
return valid(hdr.source_node)
&& valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node
&& zero(hdr.source_actor)
&& !zero(hdr.dest_actor)
&& zero(hdr.payload_len)
&& zero(hdr.operation_data);
bool monitor_message_valid(const header& hdr) {
return !zero(hdr.payload_len) && zero(hdr.operation_data);
}
bool kill_proxy_instance_valid(const header& hdr) {
return valid(hdr.source_node)
&& valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node
&& !zero(hdr.source_actor)
&& zero(hdr.dest_actor)
&& !zero(hdr.payload_len)
&& zero(hdr.operation_data);
bool down_message_valid(const header& hdr) {
return !zero(hdr.source_actor) && zero(hdr.dest_actor)
&& !zero(hdr.payload_len) && zero(hdr.operation_data);
}
bool heartbeat_valid(const header& hdr) {
return valid(hdr.source_node)
&& valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node
&& zero(hdr.source_actor)
&& zero(hdr.dest_actor)
&& zero(hdr.payload_len)
&& zero(hdr.operation_data);
return zero(hdr.source_actor) && zero(hdr.dest_actor) && zero(hdr.payload_len)
&& zero(hdr.operation_data);
}
} // namespace <anonymous>
......@@ -129,12 +102,14 @@ bool valid(const header& hdr) {
return server_handshake_valid(hdr);
case message_type::client_handshake:
return client_handshake_valid(hdr);
case message_type::dispatch_message:
return dispatch_message_valid(hdr);
case message_type::announce_proxy:
return announce_proxy_instance_valid(hdr);
case message_type::kill_proxy:
return kill_proxy_instance_valid(hdr);
case message_type::direct_message:
return direct_message_valid(hdr);
case message_type::routed_message:
return routed_message_valid(hdr);
case message_type::monitor_message:
return monitor_message_valid(hdr);
case message_type::down_message:
return down_message_valid(hdr);
case message_type::heartbeat:
return heartbeat_valid(hdr);
}
......
This diff is collapsed.
......@@ -29,9 +29,10 @@ namespace {
const char* message_type_strings[] = {
"server_handshake",
"client_handshake",
"dispatch_message",
"announce_proxy_instance",
"kill_proxy_instance",
"direct_message",
"routed_message",
"proxy_creation",
"proxy_destruction",
"heartbeat"
};
......
This diff is collapsed.
......@@ -18,7 +18,7 @@
#include "caf/config.hpp"
#define CAF_SUITE io_dynamic_remote_actor_tcp
#define CAF_SUITE io_dynamic_remote_actor
#include "caf/test/dsl.hpp"
#include <vector>
......@@ -142,7 +142,7 @@ behavior linking_actor(event_based_actor* self, const actor& buddy) {
CAF_TEST_FIXTURE_SCOPE(dynamic_remote_actor_tests, fixture)
CAF_TEST(identity_semantics_tcp) {
CAF_TEST(identity_semantics) {
// server side
auto server = server_side.spawn(make_pong_behavior);
auto port1 = unbox(server_side_mm.publish(server, 0, local_host));
......@@ -158,7 +158,7 @@ CAF_TEST(identity_semantics_tcp) {
anon_send_exit(server, exit_reason::user_shutdown);
}
CAF_TEST(ping_pong_tcp) {
CAF_TEST(ping_pong) {
// server side
auto port = unbox(server_side_mm.publish(
server_side.spawn(make_pong_behavior), 0, local_host));
......@@ -167,7 +167,7 @@ CAF_TEST(ping_pong_tcp) {
client_side.spawn(make_ping_behavior, pong);
}
CAF_TEST(custom_message_type_tcp) {
CAF_TEST(custom_message_type) {
// server side
auto port = unbox(server_side_mm.publish(
server_side.spawn(make_sort_behavior), 0, local_host));
......@@ -176,7 +176,7 @@ CAF_TEST(custom_message_type_tcp) {
client_side.spawn(make_sort_requester_behavior, sorter);
}
CAF_TEST(remote_link_tcp) {
CAF_TEST(remote_link) {
// server side
auto port = unbox(
server_side_mm.publish(server_side.spawn(fragile_mirror), 0, local_host));
......
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