diff options
Diffstat (limited to 'osp/impl/discovery/mdns/mdns_demo.cc')
-rw-r--r-- | osp/impl/discovery/mdns/mdns_demo.cc | 374 |
1 files changed, 0 insertions, 374 deletions
diff --git a/osp/impl/discovery/mdns/mdns_demo.cc b/osp/impl/discovery/mdns/mdns_demo.cc deleted file mode 100644 index 1fc1513e..00000000 --- a/osp/impl/discovery/mdns/mdns_demo.cc +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <signal.h> -#include <unistd.h> - -#include <algorithm> -#include <map> -#include <memory> -#include <vector> - -// TODO(rwkeane): Remove references to platform/impl -#include "osp/impl/discovery/mdns/mdns_responder_adapter_impl.h" -#include "platform/api/network_interface.h" -#include "platform/api/time.h" -#include "platform/base/error.h" -#include "platform/impl/logging.h" -#include "platform/impl/platform_client_posix.h" -#include "platform/impl/task_runner.h" -#include "platform/impl/udp_socket_reader_posix.h" - -// This file contains a demo of our mDNSResponder wrapper code. It can both -// listen for mDNS services and advertise an mDNS service. The command-line -// usage is: -// mdns_demo [service_type] [service_instance_name] -// service_type defaults to '_openscreen._udp' and service_instance_name -// defaults to ''. service_type determines services the program listens for and -// when service_instance_name is not empty, a service of -// 'service_instance_name.service_type' is also advertised. -// -// The program will print a list of discovered services when it receives a USR1 -// or INT signal. The pid is printed at the beginning of the program to -// facilitate this. -// -// There are a few known bugs around the handling of record events, so this -// shouldn't be expected to be a source of truth, nor should it be expected to -// be correct after running for a long time. - -namespace openscreen { -namespace osp { -namespace { - -bool g_done = false; -bool g_dump_services = false; - -struct Service { - explicit Service(DomainName service_instance) - : service_instance(std::move(service_instance)) {} - ~Service() = default; - - DomainName service_instance; - DomainName domain_name; - IPAddress address; - uint16_t port; - std::vector<std::string> txt; -}; - -class DemoSocketClient : public UdpSocket::Client { - public: - explicit DemoSocketClient(MdnsResponderAdapterImpl* mdns) : mdns_(mdns) {} - - void OnError(UdpSocket* socket, Error error) override { - // TODO(crbug.com/openscreen/66): Change to OSP_LOG_FATAL. - OSP_LOG_ERROR << "configuration failed for interface " << error.message(); - OSP_CHECK(false); - } - - void OnSendError(UdpSocket* socket, Error error) override { - OSP_UNIMPLEMENTED(); - } - - void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) override { - mdns_->OnRead(socket, std::move(packet)); - } - - private: - MdnsResponderAdapterImpl* mdns_; -}; - -using ServiceMap = std::map<DomainName, Service, DomainNameComparator>; -ServiceMap* g_services = nullptr; - -void sigusr1_dump_services(int) { - g_dump_services = true; -} - -void sigint_stop(int) { - OSP_LOG_INFO << "caught SIGINT, exiting..."; - g_done = true; -} - -std::vector<std::string> SplitByDot(const std::string& domain_part) { - std::vector<std::string> result; - auto copy_it = domain_part.begin(); - for (auto it = domain_part.begin(); it != domain_part.end(); ++it) { - if (*it == '.') { - result.emplace_back(copy_it, it); - copy_it = it + 1; - } - } - if (copy_it != domain_part.end()) - result.emplace_back(copy_it, domain_part.end()); - - return result; -} - -void SignalThings() { - struct sigaction usr1_sa; - struct sigaction int_sa; - struct sigaction unused; - - usr1_sa.sa_handler = &sigusr1_dump_services; - sigemptyset(&usr1_sa.sa_mask); - usr1_sa.sa_flags = 0; - - int_sa.sa_handler = &sigint_stop; - sigemptyset(&int_sa.sa_mask); - int_sa.sa_flags = 0; - - sigaction(SIGUSR1, &usr1_sa, &unused); - sigaction(SIGINT, &int_sa, &unused); - - OSP_LOG_INFO << "signal handlers setup" << std::endl << "pid: " << getpid(); -} - -std::vector<std::unique_ptr<UdpSocket>> SetUpMulticastSockets( - TaskRunner* task_runner, - const std::vector<NetworkInterfaceIndex>& index_list, - UdpSocket::Client* client) { - std::vector<std::unique_ptr<UdpSocket>> sockets; - for (const auto ifindex : index_list) { - auto create_result = - UdpSocket::Create(task_runner, client, IPEndpoint{{}, 5353}); - if (!create_result) { - OSP_LOG_ERROR << "failed to create IPv4 socket for interface " << ifindex - << ": " << create_result.error().message(); - continue; - } - std::unique_ptr<UdpSocket> socket = std::move(create_result.value()); - - socket->JoinMulticastGroup(IPAddress{224, 0, 0, 251}, ifindex); - socket->SetMulticastOutboundInterface(ifindex); - socket->Bind(); - - OSP_LOG_INFO << "listening on interface " << ifindex; - sockets.emplace_back(std::move(socket)); - } - return sockets; -} - -void LogService(const Service& s) { - OSP_LOG_INFO << "PTR: (" << s.service_instance << ")" << std::endl - << "SRV: " << s.domain_name << ":" << s.port << std::endl - << "TXT:"; - - for (const auto& l : s.txt) { - OSP_LOG_INFO << " | " << l; - } - OSP_LOG_INFO << "A: " << s.address; -} - -void HandleEvents(MdnsResponderAdapterImpl* mdns_adapter) { - for (auto& ptr_event : mdns_adapter->TakePtrResponses()) { - auto it = g_services->find(ptr_event.service_instance); - switch (ptr_event.header.response_type) { - case QueryEventHeader::Type::kAdded: - case QueryEventHeader::Type::kAddedNoCache: - mdns_adapter->StartSrvQuery(ptr_event.header.socket, - ptr_event.service_instance); - mdns_adapter->StartTxtQuery(ptr_event.header.socket, - ptr_event.service_instance); - if (it == g_services->end()) { - g_services->emplace(ptr_event.service_instance, - Service(ptr_event.service_instance)); - } - break; - case QueryEventHeader::Type::kRemoved: - // PTR may be removed and added without updating related entries (SRV - // and friends) so this simple logic is actually broken, but I don't - // want to do a better design or pointer hell for just a demo. - OSP_LOG_WARN << "ptr-remove: " << ptr_event.service_instance; - if (it != g_services->end()) - g_services->erase(it); - - break; - } - } - for (auto& srv_event : mdns_adapter->TakeSrvResponses()) { - auto it = g_services->find(srv_event.service_instance); - if (it == g_services->end()) - continue; - - switch (srv_event.header.response_type) { - case QueryEventHeader::Type::kAdded: - case QueryEventHeader::Type::kAddedNoCache: - mdns_adapter->StartAQuery(srv_event.header.socket, - srv_event.domain_name); - it->second.domain_name = std::move(srv_event.domain_name); - it->second.port = srv_event.port; - break; - case QueryEventHeader::Type::kRemoved: - OSP_LOG_WARN << "srv-remove: " << srv_event.service_instance; - it->second.domain_name = DomainName(); - it->second.port = 0; - break; - } - } - for (auto& txt_event : mdns_adapter->TakeTxtResponses()) { - auto it = g_services->find(txt_event.service_instance); - if (it == g_services->end()) - continue; - - switch (txt_event.header.response_type) { - case QueryEventHeader::Type::kAdded: - case QueryEventHeader::Type::kAddedNoCache: - it->second.txt = std::move(txt_event.txt_info); - break; - case QueryEventHeader::Type::kRemoved: - OSP_LOG_WARN << "txt-remove: " << txt_event.service_instance; - it->second.txt.clear(); - break; - } - } - for (const auto& a_event : mdns_adapter->TakeAResponses()) { - // TODO(btolsch): If multiple SRV records specify the same domain, the A - // will only update the first. I didn't think this would happen but I - // noticed this happens for cast groups. - auto it = std::find_if(g_services->begin(), g_services->end(), - [&a_event](const std::pair<DomainName, Service>& s) { - return s.second.domain_name == a_event.domain_name; - }); - if (it == g_services->end()) - continue; - - switch (a_event.header.response_type) { - case QueryEventHeader::Type::kAdded: - case QueryEventHeader::Type::kAddedNoCache: - it->second.address = a_event.address; - break; - case QueryEventHeader::Type::kRemoved: - OSP_LOG_WARN << "a-remove: " << a_event.domain_name; - it->second.address = IPAddress(0, 0, 0, 0); - break; - } - } -} - -void BrowseDemo(TaskRunner* task_runner, - const std::string& service_name, - const std::string& service_protocol, - const std::string& service_instance) { - SignalThings(); - - std::vector<std::string> labels{service_name, service_protocol}; - ErrorOr<DomainName> service_type = - DomainName::FromLabels(labels.begin(), labels.end()); - - if (!service_type) { - OSP_LOG_ERROR << "bad domain labels: " << service_name << ", " - << service_protocol; - return; - } - - auto mdns_adapter = std::make_unique<MdnsResponderAdapterImpl>(); - mdns_adapter->Init(); - mdns_adapter->SetHostLabel("gigliorononomicon"); - const std::vector<InterfaceInfo> interfaces = GetNetworkInterfaces(); - std::vector<NetworkInterfaceIndex> index_list; - for (const auto& interface : interfaces) { - OSP_LOG_INFO << "Found interface: " << interface; - if (!interface.addresses.empty()) { - index_list.push_back(interface.index); - } - } - OSP_LOG_IF(WARN, index_list.empty()) - << "No network interfaces had usable addresses for mDNS."; - - DemoSocketClient client(mdns_adapter.get()); - auto sockets = SetUpMulticastSockets(task_runner, index_list, &client); - // The code below assumes the elements in |sockets| is in exact 1:1 - // correspondence with the elements in |index_list|. Crash the demo if any - // sockets are missing (i.e., failed to be set up). - OSP_CHECK_EQ(sockets.size(), index_list.size()); - - // Listen on all interfaces. - auto socket_it = sockets.begin(); - for (NetworkInterfaceIndex index : index_list) { - const auto& interface = - *std::find_if(interfaces.begin(), interfaces.end(), - [index](const openscreen::InterfaceInfo& info) { - return info.index == index; - }); - // Pick any address for the given interface. - mdns_adapter->RegisterInterface(interface, interface.addresses.front(), - socket_it->get()); - ++socket_it; - } - - if (!service_instance.empty()) { - mdns_adapter->RegisterService(service_instance, service_name, - service_protocol, DomainName(), 12345, - {{"k1", "yurtle"}, {"k2", "turtle"}}); - } - - for (const std::unique_ptr<UdpSocket>& socket : sockets) { - mdns_adapter->StartPtrQuery(socket.get(), service_type.value()); - } - - while (!g_done) { - HandleEvents(mdns_adapter.get()); - if (g_dump_services) { - OSP_LOG_INFO << "num services: " << g_services->size(); - for (const auto& s : *g_services) { - LogService(s.second); - } - if (!service_instance.empty()) { - mdns_adapter->UpdateTxtData( - service_instance, service_name, service_protocol, - {{"k1", "oogley"}, {"k2", "moogley"}, {"k3", "googley"}}); - } - g_dump_services = false; - } - mdns_adapter->RunTasks(); - } - OSP_LOG_INFO << "num services: " << g_services->size(); - for (const auto& s : *g_services) { - LogService(s.second); - } - for (const std::unique_ptr<UdpSocket>& socket : sockets) { - mdns_adapter->DeregisterInterface(socket.get()); - } - mdns_adapter->Close(); -} - -} // namespace -} // namespace osp -} // namespace openscreen - -int main(int argc, char** argv) { - using openscreen::Clock; - using openscreen::PlatformClientPosix; - - openscreen::SetLogLevel(openscreen::LogLevel::kVerbose); - - std::string service_instance; - std::string service_type("_openscreen._udp"); - if (argc >= 2) - service_type = argv[1]; - - if (argc >= 3) - service_instance = argv[2]; - - if (service_type.size() && service_type[0] == '.') - return 1; - - auto labels = openscreen::osp::SplitByDot(service_type); - if (labels.size() != 2) - return 1; - - openscreen::osp::ServiceMap services; - openscreen::osp::g_services = &services; - - PlatformClientPosix::Create(std::chrono::milliseconds(50)); - - openscreen::osp::BrowseDemo( - PlatformClientPosix::GetInstance()->GetTaskRunner(), labels[0], labels[1], - service_instance); - - PlatformClientPosix::ShutDown(); - - openscreen::osp::g_services = nullptr; - return 0; -} |