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); }
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"); }