Beispiel #1
0
void
locator_t::connect() {
    using namespace boost::asio::ip;

    io::udp::endpoint endpoint = {
        address::from_string(m_context.config.network.group.get()),
        0
    };

    if(m_context.config.network.gateway) {
        const io::udp::endpoint bindpoint = { address::from_string("0.0.0.0"), 10054 };

        m_sink.reset(new io::socket<io::udp>());

        if(::bind(m_sink->fd(), bindpoint.data(), bindpoint.size()) != 0) {
            throw std::system_error(errno, std::system_category(), "unable to bind an announce socket");
        }

        COCAINE_LOG_INFO(m_log, "joining multicast group '%s' on '%s'", endpoint.address(), bindpoint);

        group_req request;

        std::memset(&request, 0, sizeof(request));

        request.gr_interface = 0;

        std::memcpy(&request.gr_group, endpoint.data(), endpoint.size());

        if(::setsockopt(m_sink->fd(), IPPROTO_IP, MCAST_JOIN_GROUP, &request, sizeof(request)) != 0) {
            throw std::system_error(errno, std::system_category(), "unable to join a multicast group");
        }

        m_sink_watcher.reset(new ev::io(m_reactor.native()));
        m_sink_watcher->set<locator_t, &locator_t::on_announce_event>(this);
        m_sink_watcher->start(m_sink->fd(), ev::READ);

        m_gateway = m_context.get<api::gateway_t>(
            m_context.config.network.gateway.get().type,
            m_context,
            "service/locator",
            m_context.config.network.gateway.get().args
        );
    }

    endpoint.port(10054);

    COCAINE_LOG_INFO(m_log, "announcing the node on '%s'", endpoint);

    // NOTE: Connect this UDP socket so that we could send announces via write() instead of sendto().
    m_announce.reset(new io::socket<io::udp>(endpoint));

    const int loop = 0;
    const int life = IP_DEFAULT_MULTICAST_TTL;

    // NOTE: I don't think these calls might fail at all.
    ::setsockopt(m_announce->fd(), IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
    ::setsockopt(m_announce->fd(), IPPROTO_IP, IP_MULTICAST_TTL,  &life, sizeof(life));

    m_announce_timer.reset(new ev::timer(m_reactor.native()));
    m_announce_timer->set<locator_t, &locator_t::on_announce_timer>(this);
    m_announce_timer->start(0.0f, 5.0f);

    m_synchronizer = std::make_shared<synchronize_slot_t>(*this);

    on<io::locator::synchronize>(m_synchronizer);
}
Beispiel #2
0
void
locator_t::run() {
    typedef implementation<io::locator_tag> locator_service_t;

    auto dispatch = std::make_unique<locator_service_t>(m_context, "service/locator");

    dispatch->on<io::locator::resolve>(std::bind(&locator_t::resolve, this, _1));
    dispatch->on<io::locator::reports>(std::bind(&locator_t::reports, this));
    dispatch->on<io::locator::refresh>(std::bind(&locator_t::refresh, this, _1));

    if(m_context.config.network.group) {
        using namespace boost::asio::ip;

        io::udp::endpoint endpoint = {
            address::from_string(m_context.config.network.group.get()),
            0
        };

        if(m_context.config.network.gateway) {
            const io::udp::endpoint bindpoint = { address::from_string("0.0.0.0"), 10054 };

            m_sink.reset(new io::socket<io::udp>());

            if(::bind(m_sink->fd(), bindpoint.data(), bindpoint.size()) != 0) {
                throw std::system_error(errno, std::system_category(), "unable to bind an announce socket");
            }

            COCAINE_LOG_INFO(m_log, "joining multicast group '%s' on '%s'", endpoint.address(), bindpoint);

            group_req request;

            std::memset(&request, 0, sizeof(request));

            request.gr_interface = 0;

            std::memcpy(&request.gr_group, endpoint.data(), endpoint.size());

            if(::setsockopt(m_sink->fd(), IPPROTO_IP, MCAST_JOIN_GROUP, &request, sizeof(request)) != 0) {
                throw std::system_error(errno, std::system_category(), "unable to join a multicast group");
            }

            m_sink_watcher.reset(new ev::io(m_reactor->native()));
            m_sink_watcher->set<locator_t, &locator_t::on_announce_event>(this);
            m_sink_watcher->start(m_sink->fd(), ev::READ);

            m_gateway = m_context.get<api::gateway_t>(
                m_context.config.network.gateway.get().type,
                m_context,
                "service/locator",
                m_context.config.network.gateway.get().args
            );
        }

        endpoint.port(10054);

        COCAINE_LOG_INFO(m_log, "announcing the node on '%s'", endpoint);

        // NOTE: Connect this UDP socket so that we could send announces via write() instead of sendto().
        m_announce.reset(new io::socket<io::udp>(endpoint));

        const int loop = 0;
        const int life = IP_DEFAULT_MULTICAST_TTL;

        // NOTE: I don't think these calls might fail at all.
        ::setsockopt(m_announce->fd(), IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
        ::setsockopt(m_announce->fd(), IPPROTO_IP, IP_MULTICAST_TTL,  &life, sizeof(life));

        m_announce_timer.reset(new ev::timer(m_reactor->native()));
        m_announce_timer->set<locator_t, &locator_t::on_announce_timer>(this);
        m_announce_timer->start(0.0f, 5.0f);

        m_synchronizer = std::make_shared<synchronize_slot_t>(*this);

        dispatch->on<io::locator::synchronize>(m_synchronizer);
    }

    // NOTE: Start the locator thread last, so that we won't needlessly send node updates to
    // the peers which managed to connect during the bootstrap.

    const std::vector<io::tcp::endpoint> endpoints = {{
        boost::asio::ip::address::from_string(m_context.config.network.endpoint),
        m_context.config.network.locator
    }};

    COCAINE_LOG_INFO(m_log, "starting the locator service on %s", endpoints.front());

    m_services.emplace_front("locator", std::make_unique<actor_t>(
        m_context,
        m_reactor,
        std::move(dispatch)
    ));

    m_services.front().second->run(endpoints);

    // TODO: Check if this is really needed.
    m_router->add_local("locator");
}