Beispiel #1
0
pool_ptr pool(context_t& context, const std::string& name) {
    auto pool = context.config().component_group("postgres").get(name);
    if(!pool) {
        throw error_t(std::errc::argument_out_of_domain, "postgres component with name '{}' not found", name);
    }
    return context.repository().get<pool_t>("postgres", context, name, pool->args());
}
Beispiel #2
0
// I2C Slave mode
void i2c_interrupt(void) {
    //  Test if there is really an interrupt
    switch (status_reg) {
    // SLAVE TRANSMITTER MODE
        case DATA_TX:
            // Slave TX callback
            ctx.data_cb(TX, &data_reg);
            break;

    // SLAVE RECEIVER MODE
        case ADDR_MATCH:
        break;

        // Data has been received on SLA+W; ACK has been returned.
        case DATA_RX:
            // Slave RX callback
            ctx.data_cb(RX, &data_reg);
        break;

        // Data has been received on general call;ACK has been returned.
        case DATA_RXGC:
            // Slave RX general call callback
            ctx.data_cb(RXGC, &data_reg);
        break;

    // OTHER
        case STOP_CATCHED:
            ctx.data_cb = idle;
            ctx.data_cb(END, &data_reg);
        default:
        break;
    }
}
Beispiel #3
0
/* compute the current binary context */
void ContextTree::getContext(const history_t &h, context_t &context) const {

    context.clear();
    for (size_t i=0; i < m_depth; ++i) {
        context.push_back(h[h.size()-i-1]);
    }
}
Beispiel #4
0
/**
 * Unicorn trait for service creation.
 * Trait to create unicorn service by name. All instances are cached by name as it is done in storage.
 */
unicorn_ptr
unicorn(context_t& context, const std::string& name) {
    auto unicorn = context.config().unicorns().get(name);
    if(!unicorn) {
        throw error_t(error::component_not_found, "unicorn component \"{}\" not found in the config", name);
    }
    return context.repository().get<unicorn_t>(unicorn->type(), context, name, unicorn->args());
}
Beispiel #5
0
actor_base<Protocol>::actor_base(context_t& context, io::dispatch_ptr_t prototype) :
    m_context(context),
    m_log(context.log("core/asio", {{"service", prototype->name()}})),
    metrics(new metrics_t{
        context.metrics_hub().counter<std::int64_t>(cocaine::format("{}.connections.accepted", prototype->name())),
        context.metrics_hub().counter<std::int64_t>(cocaine::format("{}.connections.rejected", prototype->name()))
    }),
    m_prototype(std::move(prototype))
{}
Beispiel #6
0
multicast_t::multicast_t(context_t& context, interface& locator, const std::string& name, const dynamic_t& args):
    category_type(context, locator, name, args),
    m_context(context),
    m_log(context.log(name)),
    m_locator(locator),
    m_cfg(args.to<multicast_cfg_t>()),
    m_socket(locator.asio()),
    m_timer(locator.asio())
{
    m_socket.open(m_cfg.endpoint.protocol());
    m_socket.set_option(socket_base::reuse_address(true));

    if(m_cfg.endpoint.address().is_v4()) {
        m_socket.bind(udp::endpoint(address_v4::any(), m_cfg.endpoint.port()));
    } else {
        m_socket.bind(udp::endpoint(address_v6::any(), m_cfg.endpoint.port()));
    }

    if(args.as_object().count("interface")) {
        auto interface = args.as_object().at("interface");

        if(m_cfg.endpoint.address().is_v4()) {
            m_socket.set_option(multicast::outbound_interface(interface.to<ip::address>().to_v4()));
        } else {
            m_socket.set_option(multicast::outbound_interface(interface.as_uint()));
        }
    }

    m_socket.set_option(multicast::enable_loopback(args.as_object().at("loopback", false).as_bool()));
    m_socket.set_option(multicast::hops(args.as_object().at("hops", 1u).as_uint()));

    COCAINE_LOG_INFO(m_log, "joining multicast group '%s'", m_cfg.endpoint)(
        "uuid", m_locator.uuid()
    );

    m_socket.set_option(multicast::join_group(m_cfg.endpoint.address()));

    const auto announce = std::make_shared<announce_t>();

    m_socket.async_receive_from(buffer(announce->buffer.data(), announce->buffer.size()),
        announce->endpoint,
        std::bind(&multicast_t::on_receive, this, ph::_1, ph::_2, announce)
    );

    m_signals = std::make_shared<dispatch<context_tag>>(name);
    m_signals->on<context::prepared>(std::bind(&multicast_t::on_publish, this, std::error_code()));

    context.listen(m_signals, m_locator.asio());
}
Beispiel #7
0
    app_dispatch_t(context_t& context, const std::string& name, std::shared_ptr<overseer_t> overseer_) :
        dispatch<io::app_tag>(name),
        log(context.log(format("%s/dispatch", name))),
        overseer(std::move(overseer_))
    {
        on<io::app::enqueue>(std::make_shared<slot_type>(
            std::bind(&app_dispatch_t::on_enqueue, this, ph::_1, ph::_2, ph::_3)
        ));

        on<io::app::info>(std::bind(&app_dispatch_t::on_info, this));

        // TODO: Temporary here to test graceful app terminating.
        on<io::app::test>([&](const std::string& v) {
            COCAINE_LOG_DEBUG(log, "processing test '%s' event", v);

            if (v == "0") {
                overseer.lock()->terminate();
            } else {
                std::vector<std::string> slaves;
                {
                    auto pool = overseer.lock()->get_pool();
                    for (const auto& p : *pool) {
                        slaves.push_back(p.first);
                    }
                }

                for (auto& s : slaves) {
                    overseer.lock()->despawn(s, overseer_t::despawn_policy_t::graceful);
                }
            }
        });
    }
Beispiel #8
0
adhoc_t::adhoc_t(context_t& context, const std::string& _local_uuid, const std::string& name, const dynamic_t& args):
    category_type(context, _local_uuid, name, args),
    m_log(context.log(name))
{
    std::random_device rd;
    m_random_generator.seed(rd());
}
Beispiel #9
0
logging_t::logging_t(context_t& context, io::reactor_t& reactor, const std::string& name, const Json::Value& args):
    category_type(context, reactor, name, args)
{
    auto logger = std::ref(context.logger());

    using cocaine::logging::logger_concept_t;

    on<io::logging::emit>("emit", std::bind(&logger_concept_t::emit, logger, _1, _2, _3));
    on<io::logging::verbosity>("verbosity", std::bind(&logger_concept_t::verbosity, logger));
}
Beispiel #10
0
logging_t::logging_t(context_t& context, io::reactor_t& reactor, const std::string& name, const Json::Value& args):
    api::service_t(context, reactor, name, args),
    implementation<io::logging_tag>(context, name)
{
    auto logger = std::ref(context.logger());

    using cocaine::logging::logger_concept_t;

    on<io::logging::emit>(std::bind(&logger_concept_t::emit, logger, _1, _2, _3));
    on<io::logging::verbosity>(std::bind(&logger_concept_t::verbosity, logger));
}
void msg_complete(msg_dir_t dir) {
    switch (ctx.msg.reg) {
        case WRITE_ID:
            // Get and save a new given ID
            id_update(ctx.msg.data[0]);
        break;
        case GET_ID:
        case GET_MODULE_TYPE:
        case GET_STATUS:
        case GET_FIRM_REVISION:
            // ERROR
            ctx.status.rx_error = TRUE;
        break;
        default:
            if (dir == RX)
                ctx.rx_cb(dir, &ctx.msg);
            else
                ctx.rxgc_cb(dir, &ctx.msg);
        break;
    }
}
agent_t::agent_t(
	context_t ctx )
	:	m_current_state_ptr( &st_default )
	,	m_was_defined( false )
	,	m_state_listener_controller( new impl::state_listener_controller_t )
	,	m_handler_finder{
			// Actual handler finder is dependent on msg_tracing status.
			impl::internal_env_iface_t{ ctx.env() }.is_msg_tracing_enabled() ?
				&agent_t::handler_finder_msg_tracing_enabled :
				&agent_t::handler_finder_msg_tracing_disabled }
	,	m_subscriptions(
			ctx.options().query_subscription_storage_factory()( self_ptr() ) )
	,	m_message_limits(
			message_limit::impl::info_storage_t::create_if_necessary(
				ctx.options().giveout_message_limits() ) )
	,	m_env( ctx.env() )
	,	m_event_queue( nullptr )
	,	m_direct_mbox(
			impl::internal_env_iface_t{ ctx.env() }.create_mpsc_mbox(
				self_ptr(),
				m_message_limits.get() ) )
		// It is necessary to enable agent subscription in the
		// constructor of derived class.
	,	m_working_thread_id( so_5::query_current_thread_id() )
	,	m_agent_coop( 0 )
	,	m_priority( ctx.options().query_priority() )
{
}
Beispiel #13
0
actor_t::actor_t(context_t& context, std::shared_ptr<io::reactor_t> reactor, std::unique_ptr<api::service_t> service):
    m_context(context),
    m_log(context.log(service->prototype().name())),
    m_reactor(reactor)
{
    const io::basic_dispatch_t* prototype = &service->prototype();

    // Aliasing the pointer to the service to point to the dispatch (sub-)object.
    m_prototype = std::shared_ptr<const io::basic_dispatch_t>(
        std::shared_ptr<api::service_t>(std::move(service)),
        prototype
    );
}
Beispiel #14
0
/* create (if necessary) all of the nodes in the current context */
void ContextTree::createNodesInCurrentContext(const context_t &context) {

    CTNode **ctn = &m_root;

    for (size_t i = 0; i < context.size(); i++) {
        ctn = &((*ctn)->m_child[context[i]]);
        if (*ctn == NULL) {
            void *p = m_ctnode_pool.malloc();
            assert(p != NULL);  // TODO: make more robust
            *ctn = new (p) CTNode();
        }
    }
}
Beispiel #15
0
auth_t::auth_t(context_t& context):
    m_context(context),
    m_log(context.log("crypto")),
    m_evp_md_context(EVP_MD_CTX_create())
{
    ERR_load_crypto_strings();

    // NOTE: Allowing the exception to propagate here, as this is a fatal error.
    std::vector<std::string> keys(
        context.get<api::storage_t>("storage/core")->list("keys")
    );

    for(std::vector<std::string>::const_iterator it = keys.begin();
        it != keys.end();
        ++it)
    {
        std::string identity(*it);

        std::string object(
            context.get<api::storage_t>("storage/core")->get<std::string>("keys", identity)
        );

        if(object.empty()) {
            COCAINE_LOG_ERROR(m_log, "key for user '%s' is malformed", identity);
            continue;
        }

        // Read the key into the BIO object.
        BIO * bio = BIO_new_mem_buf(const_cast<char*>(object.data()), object.size());
        EVP_PKEY * pkey = NULL;
        
        pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
            
        if(pkey != NULL) {
            m_keys.emplace(identity, pkey);
        } else { 
            COCAINE_LOG_ERROR(
                m_log,
                "key for user '%s' is invalid - %s",
                identity, 
                ERR_reason_error_string(ERR_get_error())
            );
        }

        BIO_free(bio);
    }
    
    COCAINE_LOG_INFO(m_log, "loaded %llu public key(s)", m_keys.size());
}
Beispiel #16
0
execution_unit_t::execution_unit_t(context_t& context):
    m_asio(new io_service()),
    m_chamber(new io::chamber_t("core:asio", m_asio)),
    m_cron(*m_asio)
{
    m_log = context.log("core:asio", {
        attribute::make("engine", boost::lexical_cast<std::string>(m_chamber->thread_id()))
    });

    m_asio->post(std::bind(&gc_action_t::operator(),
                           std::make_shared<gc_action_t>(this, boost::posix_time::seconds(kCollectionInterval))
                          ));

    COCAINE_LOG_DEBUG(m_log, "engine started");
}
Beispiel #17
0
process_t::process_t(context_t& context, const std::string& name, const dynamic_t& args):
    category_type(context, name, args),
    m_context(context),
    m_log(context.log(name)),
    m_name(name),
    m_working_directory(fs::path(args.as_object().at("spool", "/var/spool/cocaine").as_string()) / name)
{
#ifdef COCAINE_ALLOW_CGROUPS
    int rv = 0;

    if((rv = cgroup_init()) != 0) {
        throw std::system_error(rv, cgroup_category(), "unable to initialize cgroups");
    }

    m_cgroup = cgroup_new_cgroup(m_name.c_str());

    // NOTE: Looks like if this is not done, then libcgroup will chown everything as root.
    cgroup_set_uid_gid(m_cgroup, getuid(), getgid(), getuid(), getgid());

    for(auto type = args.as_object().begin(); type != args.as_object().end(); ++type) {
        if(!type->second.is_object() || type->second.as_object().empty()) {
            continue;
        }

        cgroup_controller* ptr = cgroup_add_controller(m_cgroup, type->first.c_str());

        for(auto it = type->second.as_object().begin(); it != type->second.as_object().end(); ++it) {
            COCAINE_LOG_INFO(m_log, "setting cgroup controller '%s' parameter '%s' to '%s'",
                type->first, it->first, boost::lexical_cast<std::string>(it->second)
            );

            try {
                it->second.apply(cgroup_configurator_t(ptr, it->first.c_str()));
            } catch(const cocaine::error_t& e) {
                COCAINE_LOG_ERROR(m_log, "unable to set cgroup controller '%s' parameter '%s' - %s",
                    type->first, it->first, e.what()
                );
            }
        }
    }

    if((rv = cgroup_create_cgroup(m_cgroup, false)) != 0) {
        cgroup_free(&m_cgroup);

        throw std::system_error(rv, cgroup_category(), "unable to create cgroup");
    }
#endif
}
Beispiel #18
0
node_service_t::node_service_t(context_t& context, io::reactor_t& reactor, const std::string& name):
    api::service_t(context, reactor, name, dynamic_t::empty_object),
    dispatch<io::raft_node_tag<msgpack::object, msgpack::object>>(name),
    m_context(context),
    m_log(context.log(name))
{
    using namespace std::placeholders;

    typedef io::raft_node<msgpack::object, msgpack::object> protocol;

    on<protocol::append>(std::bind(&node_service_t::append, this, _1, _2, _3, _4, _5, _6));
    on<protocol::apply>(std::bind(&node_service_t::apply, this, _1, _2, _3, _4, _5, _6));
    on<protocol::request_vote>(std::bind(&node_service_t::request_vote, this, _1, _2, _3, _4));
    on<protocol::insert>(std::bind(&node_service_t::insert, this, _1, _2));
    on<protocol::erase>(std::bind(&node_service_t::erase, this, _1, _2));
}
Beispiel #19
0
darkmetrics_t::darkmetrics_t(context_t& context, peers_t& peers, const dynamic_t& args)
    : unicorn_name_(args.as_object().at("unicorn", dynamic_t::empty_string).as_string())
    , unicorn_prefix_(args.as_object().at("unicorn_prefix", dynamic_t::empty_string).as_string())
    , unicorn_retry_after_(args.as_object().at("unicorn_retry_after_s", 20U).as_uint())
    , enabled_(args.as_object().at("enabled", false).as_bool())
    , ttl_(args.as_object().at("ttl_s", 300U).as_uint())
    , logger_(context.log("vicodyn/darkmetrics"))
    , peers_(peers) {

    if (enabled_) {
        if (unicorn_name_.empty() || unicorn_prefix_.empty()) {
            throw error_t("invalid configuration of darkmetrics: `unicorn` and `unicorn_prefix` are required");
        }
        unicorn_ = api::unicorn(context, unicorn_name_);
    }
    COCAINE_LOG_INFO(logger_, "balancing by system weights is {}", enabled_ ? "on" : "off");
}
Beispiel #20
0
bool ParseContextMap(const string &str, context_t &context) {
    istringstream iss(str);
    string element;

    while (getline(iss, element, ',')) {
        istringstream ess(element);

        string tok;
        getline(ess, tok, ':');
        domain_t id = (domain_t) stoi(tok);
        getline(ess, tok, ':');
        float w = stof(tok);

        context.push_back(cscore_t(id, w));
    }

    return true;
}
Beispiel #21
0
master_t::master_t(context_t& context, engine_t& engine):
    m_context(context),
    m_log(context.log(
              (boost::format("app/%1%")
               % engine.manifest().name
              ).str()
          )),
    m_engine(engine),
    m_heartbeat_timer(m_engine.loop())
{
    initiate();

    // NOTE: Initialization heartbeat can be different.
    m_heartbeat_timer.set<master_t, &master_t::on_timeout>(this);
    m_heartbeat_timer.start(m_engine.manifest().policy.startup_timeout);

    spawn();
}
Beispiel #22
0
manifest_t::manifest_t(context_t& context, const std::string& name_):
    cached<dynamic_t>(context, "manifests", name_),
    name(name_)
{
    endpoint = cocaine::format("{}/{}.{}", context.config().path().runtime(), name, ::getpid());

    try {
        environment = as_object().at("environment", dynamic_t::empty_object)
            .to<std::map<std::string, std::string>>();
    } catch (const boost::bad_get&) {
        throw cocaine::error_t("environment should be a map of string -> string");
    }

    if(as_object().find("slave") != as_object().end()) {
        executable = as_object().at("slave").as_string();
    } else {
        throw cocaine::error_t("runnable object has not been specified");
    }
}
Beispiel #23
0
    app_state_t(context_t& context,
                manifest_t manifest_,
                profile_t profile_,
                cocaine::deferred<void> deferred_):
        log(context.log(format("%s/app", manifest_.name))),
        context(context),
        state(new state::stopped_t),
        deferred(std::move(deferred_)),
        manifest_(std::move(manifest_)),
        profile(std::move(profile_)),
        loop(std::make_shared<asio::io_service>()),
        work(std::make_unique<asio::io_service::work>(*loop))
    {
        COCAINE_LOG_TRACE(log, "application has initialized its internal state");

        thread = boost::thread([=] {
            loop->run();
        });
    }
Beispiel #24
0
slave_t::slave_t(context_t& context, slave_config_t config):
    unique_id_t(config.uuid),
    m_context(context),
    m_log(context.log(
        (boost::format("app/%1%")
            % config.app
        ).str()
    )),
    m_app(config.app),
    m_bus(m_context.io(), config.uuid),
    m_bus_timeout(m_bus, defaults::bus_timeout)
{
    int linger = 0;

    m_bus.setsockopt(ZMQ_LINGER, &linger, sizeof(linger));

#ifdef ZMQ_ROUTER_BEHAVIOR
    int mode = 1;
    
    m_bus.setsockopt(ZMQ_ROUTER_BEHAVIOR, &mode, sizeof(mode));
#endif

    m_bus.connect(
        (boost::format("ipc://%1%/%2%")
            % m_context.config.ipc_path
            % config.app
        ).str()
    );
    
    m_watcher.set<slave_t, &slave_t::message>(this);
    m_watcher.start(m_bus.fd(), ev::READ);
    m_processor.set<slave_t, &slave_t::process>(this);
    m_check.set<slave_t, &slave_t::check>(this);
    m_check.start();

    m_heartbeat_timer.set<slave_t, &slave_t::heartbeat>(this);
    m_heartbeat_timer.start(0.0f, 5.0f);

    configure();
}
Beispiel #25
0
app_t::app_t(context_t& context,
             const std::string& name,
             const std::string& profile):
    m_context(context),
    m_log(context.log(
        cocaine::format("app/%1%", name)
    )),
    m_manifest(new manifest_t(context, name)),
    m_profile(new profile_t(context, profile))
{
    fs::path path(fs::path(m_context.config.spool_path) / name);
    
    if(!fs::exists(path)) {
        deploy(name, path.string());
    }

    m_control.reset(new control_channel_t(context, ZMQ_PAIR));

    std::string endpoint = cocaine::format(
        "inproc://%s",
        m_manifest->name
    );

    try { 
        m_control->bind(endpoint);
    } catch(const zmq::error_t& e) {
        throw configuration_error_t("unable to bind the engine control channel - %s", e.what());
    }

    // NOTE: The event loop is not started here yet.
    m_engine.reset(
        new engine_t(
            m_context,
            *m_manifest,
            *m_profile
        )
    );
}
Beispiel #26
0
archive_t::archive_t(context_t& context, const std::string& archive):
    m_log(context.log("packaging")),
    m_archive(archive_read_new())
{
#if ARCHIVE_VERSION_NUMBER < 3000000
    archive_read_support_compression_all(m_archive);
#else
    archive_read_support_filter_all(m_archive);
#endif

    archive_read_support_format_all(m_archive);

    const int rv = archive_read_open_memory(
        m_archive,
        const_cast<char*>(archive.data()),
        archive.size()
    );

    if(rv != ARCHIVE_OK) {
        throw archive_error_t(m_archive);
    }

    COCAINE_LOG_INFO(m_log, "compression: %s, size: %llu bytes", type(), archive.size());
}
Beispiel #27
0
    running_t(context_t& context,
              const manifest_t& manifest,
              const profile_t& profile,
              const logging::log_t* log,
              std::shared_ptr<asio::io_service> loop):
        log(log)
    {
        // Create the Overseer - slave spawner/despawner plus the event queue dispatcher.
        overseer.reset(new overseer_t(context, manifest, profile, loop));

        // Create the event balancer.
        // TODO: Rename method.
        overseer->balance(std::make_unique<load_balancer_t>(overseer));

        // Create a TCP server and publish it.
        COCAINE_LOG_TRACE(log, "publishing application service with the context");
        context.insert(manifest.name, std::make_unique<actor_t>(
            context,
            std::make_shared<asio::io_service>(),
            std::make_unique<app_dispatch_t>(context, manifest.name, overseer)
        ));

        // Create an unix actor and bind to {manifest->name}.{pid} unix-socket.
        COCAINE_LOG_TRACE(log, "publishing worker service with the context");
        engine.reset(new unix_actor_t(
            context,
            manifest.endpoint,
            std::bind(&overseer_t::prototype, overseer),
            [](io::dispatch_ptr_t handshaker, std::shared_ptr<session_t> session) {
                std::static_pointer_cast<const handshaker_t>(handshaker)->bind(session);
            },
            std::make_shared<asio::io_service>(),
            std::make_unique<hostess_t>(manifest.name)
        ));
        engine->run();
    }
Beispiel #28
0
node_t::node_t(context_t& context, asio::io_service& asio, const std::string& name, const dynamic_t& args):
    category_type(context, asio, name, args),
    dispatch<io::node_tag>(name),
    context(context),
    log(context.log(name))
{
    on<io::node::start_app>(std::bind(&node_t::start_app, this, ph::_1, ph::_2));
    on<io::node::pause_app>(std::bind(&node_t::pause_app, this, ph::_1));
    on<io::node::list>     (std::bind(&node_t::list, this));
    on<io::node::info>     (std::bind(&node_t::info, this, ph::_1, ph::_2));

    // Context signal/slot.
    signal = std::make_shared<dispatch<io::context_tag>>(name);
    signal->on<io::context::shutdown>(std::bind(&node_t::on_context_shutdown, this));

    const auto runname = args.as_object().at("runlist", "").as_string();

    if(runname.empty()) {
        context.listen(signal, asio);
        return;
    }

    COCAINE_LOG_INFO(log, "reading '%s' runlist", runname);

    typedef std::map<std::string, std::string> runlist_t;
    runlist_t runlist;

    const auto storage = api::storage(context, "core");

    try {
        // TODO: Perform request to a special service, like "storage->runlist(runname)".
        runlist = storage->get<runlist_t>("runlists", runname);
    } catch(const std::system_error& err) {
        COCAINE_LOG_WARNING(log, "unable to read '%s' runlist: %s", runname, err.what());
    }

    if(runlist.empty()) {
        context.listen(signal, asio);
        return;
    }

    COCAINE_LOG_INFO(log, "starting %d app(s)", runlist.size());

    std::vector<std::string> errored;

    for(auto it = runlist.begin(); it != runlist.end(); ++it) {
        blackhole::scoped_attributes_t scope(*log, {{ "app", it->first }});

        try {
            start_app(it->first, it->second);
        } catch(const std::exception& e) {
            COCAINE_LOG_WARNING(log, "unable to initialize app: %s", e.what());
            errored.push_back(it->first);
        }
    }

    if(!errored.empty()) {
        std::ostringstream stream;
        std::ostream_iterator<char> builder(stream);

        boost::spirit::karma::generate(builder, boost::spirit::karma::string % ", ", errored);

        COCAINE_LOG_WARNING(log, "couldn't start %d app(s): %s", errored.size(), stream.str());
    }

    context.listen(signal, asio);
}
Beispiel #29
0
engine_t::engine_t(context_t& context, const manifest_t& manifest):
    m_context(context),
    m_log(context.log(
        (boost::format("app/%1%")
            % manifest.name
        ).str()
    )),
    m_manifest(manifest),
    m_state(stopped),
    m_thread(NULL),
    m_bus(new io::channel_t(context.io(), m_manifest.name)),
    m_watcher(m_loop),
    m_processor(m_loop),
    m_check(m_loop),
    m_gc_timer(m_loop),
    m_termination_timer(m_loop),
    m_notification(m_loop)
#ifdef HAVE_CGROUPS
    , m_cgroup(NULL)
#endif
{
    int linger = 0;

    m_bus->setsockopt(ZMQ_LINGER, &linger, sizeof(linger));

    std::string endpoint(
        (boost::format("ipc://%1%/%2%")
            % m_context.config.ipc_path
            % m_manifest.name
        ).str()
    );

    try {
        m_bus->bind(endpoint);
    } catch(const zmq::error_t& e) {
        throw configuration_error_t(std::string("invalid rpc endpoint - ") + e.what());
    }
    
    m_watcher.set<engine_t, &engine_t::message>(this);
    m_watcher.start(m_bus->fd(), ev::READ);
    m_processor.set<engine_t, &engine_t::process>(this);
    m_check.set<engine_t, &engine_t::check>(this);
    m_check.start();

    m_gc_timer.set<engine_t, &engine_t::cleanup>(this);
    m_gc_timer.start(5.0f, 5.0f);

    m_notification.set<engine_t, &engine_t::notify>(this);
    m_notification.start();

#ifdef HAVE_CGROUPS
    Json::Value limits(m_manifest.root["resource-limits"]);

    if(!(cgroup_init() == 0) || !limits.isObject() || limits.empty()) {
        return;
    }
    
    m_cgroup = cgroup_new_cgroup(m_manifest.name.c_str());

    // XXX: Not sure if it changes anything.
    cgroup_set_uid_gid(m_cgroup, getuid(), getgid(), getuid(), getgid());
    
    Json::Value::Members controllers(limits.getMemberNames());

    for(Json::Value::Members::iterator c = controllers.begin();
        c != controllers.end();
        ++c)
    {
        Json::Value cfg(limits[*c]);

        if(!cfg.isObject() || cfg.empty()) {
            continue;
        }
        
        cgroup_controller * ctl = cgroup_add_controller(m_cgroup, c->c_str());
        
        Json::Value::Members parameters(cfg.getMemberNames());

        for(Json::Value::Members::iterator p = parameters.begin();
            p != parameters.end();
            ++p)
        {
            switch(cfg[*p].type()) {
                case Json::stringValue: {
                    cgroup_add_value_string(ctl, p->c_str(), cfg[*p].asCString());
                    break;
                } case Json::intValue: {
                    cgroup_add_value_int64(ctl, p->c_str(), cfg[*p].asInt());
                    break;
                } case Json::uintValue: {
                    cgroup_add_value_uint64(ctl, p->c_str(), cfg[*p].asUInt());
                    break;
                } case Json::booleanValue: {
                    cgroup_add_value_bool(ctl, p->c_str(), cfg[*p].asBool());
                    break;
                } default: {
                    m_log->error(
                        "controller '%s' parameter '%s' type is not supported",
                        c->c_str(),
                        p->c_str()
                    );

                    continue;
                }
            }
            
            m_log->debug(
                "setting controller '%s' parameter '%s' to '%s'", 
                c->c_str(),
                p->c_str(),
                boost::lexical_cast<std::string>(cfg[*p]).c_str()
            );
        }
    }

    int rv = 0;

    if((rv = cgroup_create_cgroup(m_cgroup, false)) != 0) {
        m_log->error(
            "unable to create the control group - %s", 
            cgroup_strerror(rv)
        );

        cgroup_free(&m_cgroup);
        m_cgroup = NULL;
    }
#endif
}
/*
 * idle function is called when we are ready to receive or send a new message.
 */
void idle(msg_dir_t dir, volatile unsigned char *data) {
    static unsigned char *data_to_send;
    static unsigned char msg_size = 0;
    static unsigned char RX_count = 0;
    switch (dir) {
        case TX:
            /*
             * At this point we should have something ready to send.
             */
            if (msg_size) {
                /*
                 *This case is dedicated to protocol messages
                 */
                msg_size--;
                *data = *data_to_send++;
            } else {
                ctx.tx_cb(&ctx.msg);
            }
        break;
        case RX:
        case RXGC:
            /*
             * That should be a new message to receive.
             */
             RX_count++;
             ctx.msg.reg = *data;
            switch (ctx.msg.reg) {
                case GET_ID:
                    // Reply with ID
                    msg_size = 1;
                    data_to_send = &ctx.id;
                break;
                case WRITE_ID:
                    // Get and save a new given ID
                    ctx.msg.size = 1;
                    ctx.data_cb = get_data;
                break;
                case GET_MODULE_TYPE:
                    // Reply with module_type number
                    msg_size = 1;
                    data_to_send = &ctx.type;
                break;
                case GET_STATUS:
                    // Reply with a status register
                    msg_size = 1;
                    data_to_send = (unsigned char*)&ctx.status;
                    // TODO(NR) ca devrais reset le status...
                break;
                case GET_FIRM_REVISION:
                    // Reply with the actual firmware revision number
                    // TODO(NR)
                break;
                default:
                    ctx.data_cb = get_size;
                break;
            }
        break;
        case END:
            if (msg_size > 0)
                ctx.status.rx_error = TRUE;
            msg_size = 0;
        break;
    }
}