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));
}
예제 #2
0
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;
      }
    }
  }
}
예제 #3
0
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);
  });
}
예제 #4
0
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;
}
예제 #5
0
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();
      }
    };
  });
예제 #6
0
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);
      });
    });
  }
}
예제 #7
0
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;
 }
예제 #9
0
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);
}