forwarding_actor_proxy::forwarding_actor_proxy(actor_id aid, node_id nid, actor mgr) : actor_proxy(aid, nid), m_manager(mgr) { CAF_ASSERT(mgr != invalid_actor); CAF_LOG_INFO(CAF_ARG(aid) << ", " << CAF_TARG(nid, to_string)); }
void manager::detach(execution_unit*, bool invoke_disconnect_message) { CAF_LOG_TRACE(CAF_ARG(invoke_disconnect_message)); // This function gets called from the multiplexer when an error occurs or // from the broker when closing this manager. In both cases, we need to make // sure this manager does not receive further socket events. remove_from_loop(); // Disconnect from the broker if not already detached. if (!detached()) { CAF_LOG_DEBUG("disconnect servant from broker"); auto raw_ptr = parent(); // Keep a strong reference to our parent until we go out of scope. strong_actor_ptr ptr; ptr.swap(parent_); detach_from(raw_ptr); if (invoke_disconnect_message) { auto mptr = make_mailbox_element(nullptr, invalid_message_id, {}, detach_message()); switch (raw_ptr->consume(*mptr)) { case im_success: raw_ptr->finalize(); break; case im_skipped: raw_ptr->push_to_cache(std::move(mptr)); break; case im_dropped: CAF_LOG_INFO("broker dropped disconnect message"); break; } } } }
void actor_registry::put_impl(actor_id key, strong_actor_ptr val) { CAF_LOG_TRACE(CAF_ARG(key)); if (!val) return; { // lifetime scope of guard exclusive_guard guard(instances_mtx_); if (!entries_.emplace(key, val).second) return; } // attach functor without lock CAF_LOG_INFO("added actor:" << CAF_ARG(key)); actor_registry* reg = this; val->get()->attach_functor([key, reg]() { reg->erase(key); }); }
bool udp::read_datagram(size_t& result, native_socket fd, void* buf, size_t buf_len, ip_endpoint& ep) { CAF_LOG_TRACE(CAF_ARG(fd)); memset(ep.address(), 0, sizeof(sockaddr_storage)); socket_size_type len = sizeof(sockaddr_storage); auto sres = ::recvfrom(fd, static_cast<io::network::socket_recv_ptr>(buf), buf_len, 0, ep.address(), &len); if (is_error(sres, true)) { CAF_LOG_ERROR("recvfrom returned" << CAF_ARG(sres)); return false; } if (sres == 0) CAF_LOG_INFO("Received empty datagram"); else if (sres > static_cast<signed_size_type>(buf_len)) CAF_LOG_WARNING("recvfrom cut of message, only received " << CAF_ARG(buf_len) << " of " << CAF_ARG(sres) << " bytes"); result = (sres > 0) ? static_cast<size_t>(sres) : 0; *ep.length() = static_cast<size_t>(len); return true; }
void basp_broker_state::learned_new_node(const node_id& nid) { CAF_LOG_TRACE(CAF_ARG(nid)); if (spawn_servers.count(nid) > 0) { CAF_LOG_ERROR("learned_new_node called for known node " << CAF_ARG(nid)); return; } auto tmp = system().spawn<hidden>([=](event_based_actor* tself) -> behavior { CAF_LOG_TRACE(""); // terminate when receiving a down message tself->set_down_handler([=](down_msg& dm) { CAF_LOG_TRACE(CAF_ARG(dm)); tself->quit(std::move(dm.reason)); }); // skip messages until we receive the initial ok_atom tself->set_default_handler(skip); return { [=](ok_atom, const std::string& /* key == "info" */, const strong_actor_ptr& config_serv, const std::string& /* name */) { CAF_LOG_TRACE(CAF_ARG(config_serv)); // drop unexpected messages from this point on tself->set_default_handler(print_and_drop); if (!config_serv) return; tself->monitor(config_serv); tself->become( [=](spawn_atom, std::string& type, message& args) -> delegated<strong_actor_ptr, std::set<std::string>> { CAF_LOG_TRACE(CAF_ARG(type) << CAF_ARG(args)); tself->delegate(actor_cast<actor>(std::move(config_serv)), get_atom::value, std::move(type), std::move(args)); return {}; } ); }, after(std::chrono::minutes(5)) >> [=] { CAF_LOG_INFO("no spawn server found:" << CAF_ARG(nid)); tself->quit(); } }; });
void basp_broker_state::proxy_announced(const node_id& nid, actor_id aid) { CAF_LOG_TRACE(CAF_ARG(nid) << CAF_ARG(aid)); // source node has created a proxy for one of our actors auto entry = system().registry().get(aid); auto send_kill_proxy_instance = [=](error rsn) { if (!rsn) rsn = exit_reason::unknown; auto path = instance.tbl().lookup(nid); if (!path) { CAF_LOG_INFO("cannot send exit message for proxy, no route to host:" << CAF_ARG(nid)); return; } instance.write_kill_proxy(self->context(), path->wr_buf, nid, aid, rsn); instance.tbl().flush(*path); }; auto ptr = actor_cast<strong_actor_ptr>(entry); if (!ptr) { CAF_LOG_DEBUG("kill proxy immediately"); // kill immediately if actor has already terminated send_kill_proxy_instance(exit_reason::unknown); } else { strong_actor_ptr tmp{self->ctrl()}; auto mm = &system().middleman(); ptr->get()->attach_functor([=](const error& fail_state) { mm->backend().dispatch([=] { CAF_LOG_TRACE(CAF_ARG(fail_state)); auto bptr = static_cast<basp_broker*>(tmp->get()); // ... to make sure this is safe if (bptr == mm->named_broker<basp_broker>(atom("BASP")) && !bptr->getf(abstract_actor::is_terminated_flag)) send_kill_proxy_instance(fail_state); }); }); } }
remote_actor_proxy::remote_actor_proxy(actor_id aid, node_id nid, actor parent) : super(aid, nid), m_parent(parent) { CAF_REQUIRE(parent != invalid_actor); CAF_LOG_INFO(CAF_ARG(aid) << ", " << CAF_TARG(nid, to_string)); }
resumable::resume_result resume(execution_unit* new_host, size_t max_throughput) override { CAF_REQUIRE(max_throughput > 0); auto d = static_cast<Derived*>(this); CAF_LOG_TRACE("id = " << d->id()); d->host(new_host); auto done_cb = [&]() -> bool { CAF_LOG_TRACE(""); d->bhvr_stack().clear(); d->bhvr_stack().cleanup(); d->on_exit(); if (!d->bhvr_stack().empty()) { CAF_LOG_DEBUG("on_exit did set a new behavior"); d->planned_exit_reason(exit_reason::not_exited); return false; // on_exit did set a new behavior } auto rsn = d->planned_exit_reason(); if (rsn == exit_reason::not_exited) { rsn = exit_reason::normal; d->planned_exit_reason(rsn); } d->cleanup(rsn); return true; }; auto actor_done = [&]() -> bool { if (d->bhvr_stack().empty() || d->planned_exit_reason() != exit_reason::not_exited) { return done_cb(); } return false; }; // actors without behavior or that have already defined // an exit reason must not be resumed CAF_REQUIRE(!d->is_initialized() || (!d->bhvr_stack().empty() && d->planned_exit_reason() == exit_reason::not_exited)); std::exception_ptr eptr = nullptr; try { if (!d->is_initialized()) { CAF_LOG_DEBUG("initialize actor"); d->is_initialized(true); auto bhvr = d->make_behavior(); CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior, " << "bhvr_stack().empty() = " << std::boolalpha << d->bhvr_stack().empty()); if (bhvr) { // make_behavior() did return a behavior instead of using become() CAF_LOG_DEBUG("make_behavior() did return a valid behavior"); d->become(std::move(bhvr)); } if (actor_done()) { CAF_LOG_DEBUG("actor_done() returned true right " << "after make_behavior()"); return resume_result::done; } } // max_throughput = 0 means infinite for (size_t i = 0; i < max_throughput; ++i) { auto ptr = d->next_message(); if (ptr) { if (d->invoke_message(ptr)) { if (actor_done()) { CAF_LOG_DEBUG("actor exited"); return resume_result::done; } // continue from cache if current message was // handled, because the actor might have changed // its behavior to match 'old' messages now while (d->invoke_message_from_cache()) { if (actor_done()) { CAF_LOG_DEBUG("actor exited"); return resume_result::done; } } } // add ptr to cache if invoke_message // did not reset it (i.e. skipped, but not dropped) if (ptr) { CAF_LOG_DEBUG("add message to cache"); d->push_to_cache(std::move(ptr)); } } else { CAF_LOG_DEBUG("no more element in mailbox; going to block"); if (d->mailbox().try_block()) { return resumable::awaiting_message; } CAF_LOG_DEBUG("try_block() interrupted by new message"); } } if (!d->has_next_message() && d->mailbox().try_block()) { return resumable::awaiting_message; } // time's up return resumable::resume_later; } catch (actor_exited& what) { CAF_LOG_INFO("actor died because of exception: actor_exited, " "reason = " << what.reason()); if (d->exit_reason() == exit_reason::not_exited) { d->quit(what.reason()); } } catch (std::exception& e) { CAF_LOG_INFO("actor died because of an exception: " << detail::demangle(typeid(e)) << ", what() = " << e.what()); if (d->exit_reason() == exit_reason::not_exited) { d->quit(exit_reason::unhandled_exception); } eptr = std::current_exception(); } catch (...) { CAF_LOG_INFO("actor died because of an unknown exception"); if (d->exit_reason() == exit_reason::not_exited) { d->quit(exit_reason::unhandled_exception); } eptr = std::current_exception(); } if (eptr) { auto opt_reason = d->handle(eptr); if (opt_reason) { // use exit reason defined by custom handler d->planned_exit_reason(*opt_reason); } } if (!actor_done()) { // actor has been "revived", try running it again later return resumable::resume_later; } return resumable::done; }
void basp_broker_state::deliver(const node_id& src_nid, actor_id src_aid, strong_actor_ptr dest, message_id mid, std::vector<strong_actor_ptr>& stages, message& msg) { CAF_LOG_TRACE(CAF_ARG(src_nid) << CAF_ARG(src_aid) << CAF_ARG(dest) << CAF_ARG(msg) << CAF_ARG(mid)); auto src = src_nid == this_node() ? system().registry().get(src_aid) : proxies().get_or_put(src_nid, src_aid); // Intercept link messages. Forwarding actor proxies signalize linking // by sending link_atom/unlink_atom message with src = dest. if (msg.type_token() == make_type_token<atom_value, strong_actor_ptr>()) { switch (static_cast<uint64_t>(msg.get_as<atom_value>(0))) { default: break; case link_atom::value.uint_value(): { if (src_nid != this_node()) { CAF_LOG_WARNING("received link message for an other node"); return; } auto ptr = msg.get_as<strong_actor_ptr>(1); if (!ptr) { CAF_LOG_WARNING("received link message with invalid target"); return; } if (!src) { CAF_LOG_DEBUG("received link for invalid actor, report error"); anon_send(actor_cast<actor>(ptr), make_error(sec::remote_linking_failed)); return; } static_cast<actor_proxy*>(ptr->get())->local_link_to(src->get()); return; } case unlink_atom::value.uint_value(): { if (src_nid != this_node()) { CAF_LOG_WARNING("received unlink message for an other node"); return; } auto ptr = msg.get_as<strong_actor_ptr>(1); if (!ptr) { CAF_LOG_DEBUG("received unlink message with invalid target"); return; } if (!src) { CAF_LOG_DEBUG("received unlink for invalid actor, report error"); return; } static_cast<actor_proxy*>(ptr->get())->local_unlink_from(src->get()); return; } } } if (!dest) { auto rsn = exit_reason::remote_link_unreachable; CAF_LOG_INFO("cannot deliver message, destination not found"); self->parent().notify<hook::invalid_message_received>(src_nid, src, invalid_actor_id, mid, msg); if (mid.valid() && src) { detail::sync_request_bouncer srb{rsn}; srb(src, mid); } return; } self->parent().notify<hook::message_received>(src_nid, src, dest, mid, msg); dest->enqueue(make_mailbox_element(std::move(src), mid, std::move(stages), std::move(msg)), nullptr); }