1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "osp/impl/internal_services.h"
6 
7 #include <algorithm>
8 #include <utility>
9 
10 #include "osp/impl/discovery/mdns/mdns_responder_adapter_impl.h"
11 #include "osp/impl/mdns_responder_service.h"
12 #include "platform/api/udp_socket.h"
13 #include "platform/base/error.h"
14 #include "util/osp_logging.h"
15 
16 namespace openscreen {
17 namespace osp {
18 namespace {
19 
20 constexpr char kServiceName[] = "_openscreen";
21 constexpr char kServiceProtocol[] = "_udp";
22 const IPAddress kMulticastAddress{224, 0, 0, 251};
23 const IPAddress kMulticastIPv6Address{
24     // ff02::fb
25     0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00fb,
26 };
27 const uint16_t kMulticastListeningPort = 5353;
28 
29 class MdnsResponderAdapterImplFactory final
30     : public MdnsResponderAdapterFactory {
31  public:
32   MdnsResponderAdapterImplFactory() = default;
33   ~MdnsResponderAdapterImplFactory() override = default;
34 
Create()35   std::unique_ptr<MdnsResponderAdapter> Create() override {
36     return std::make_unique<MdnsResponderAdapterImpl>();
37   }
38 };
39 
SetUpMulticastSocket(UdpSocket * socket,NetworkInterfaceIndex ifindex)40 Error SetUpMulticastSocket(UdpSocket* socket, NetworkInterfaceIndex ifindex) {
41   const IPAddress broadcast_address =
42       socket->IsIPv6() ? kMulticastIPv6Address : kMulticastAddress;
43 
44   socket->JoinMulticastGroup(broadcast_address, ifindex);
45   socket->SetMulticastOutboundInterface(ifindex);
46   socket->Bind();
47 
48   return Error::None();
49 }
50 
51 // Ref-counted singleton instance of InternalServices. This lives only as long
52 // as there is at least one ServiceListener and/or ServicePublisher alive.
53 InternalServices* g_instance = nullptr;
54 int g_instance_ref_count = 0;
55 
56 }  // namespace
57 
58 // static
CreateListener(const MdnsServiceListenerConfig & config,ServiceListener::Observer * observer,TaskRunner * task_runner)59 std::unique_ptr<ServiceListener> InternalServices::CreateListener(
60     const MdnsServiceListenerConfig& config,
61     ServiceListener::Observer* observer,
62     TaskRunner* task_runner) {
63   auto* services = ReferenceSingleton(task_runner);
64   auto listener =
65       std::make_unique<ServiceListenerImpl>(&services->mdns_service_);
66   listener->AddObserver(observer);
67   listener->SetDestructionCallback(&InternalServices::DereferenceSingleton,
68                                    services);
69   return listener;
70 }
71 
72 // static
CreatePublisher(const ServicePublisher::Config & config,ServicePublisher::Observer * observer,TaskRunner * task_runner)73 std::unique_ptr<ServicePublisher> InternalServices::CreatePublisher(
74     const ServicePublisher::Config& config,
75     ServicePublisher::Observer* observer,
76     TaskRunner* task_runner) {
77   auto* services = ReferenceSingleton(task_runner);
78   services->mdns_service_.SetServiceConfig(
79       config.hostname, config.service_instance_name,
80       config.connection_server_port, config.network_interface_indices,
81       {{"fn", config.friendly_name}});
82   auto publisher = std::make_unique<ServicePublisherImpl>(
83       observer, &services->mdns_service_);
84   publisher->SetDestructionCallback(&InternalServices::DereferenceSingleton,
85                                     services);
86   return publisher;
87 }
88 
InternalPlatformLinkage(InternalServices * parent)89 InternalServices::InternalPlatformLinkage::InternalPlatformLinkage(
90     InternalServices* parent)
91     : parent_(parent) {}
92 
~InternalPlatformLinkage()93 InternalServices::InternalPlatformLinkage::~InternalPlatformLinkage() {
94   // If there are open sockets, then there will be dangling references to
95   // destroyed objects after destruction.
96   OSP_CHECK(open_sockets_.empty());
97 }
98 
99 std::vector<MdnsPlatformService::BoundInterface>
RegisterInterfaces(const std::vector<NetworkInterfaceIndex> & allowlist)100 InternalServices::InternalPlatformLinkage::RegisterInterfaces(
101     const std::vector<NetworkInterfaceIndex>& allowlist) {
102   const std::vector<InterfaceInfo> interfaces = GetNetworkInterfaces();
103   const bool do_filter_using_allowlist = !allowlist.empty();
104   std::vector<NetworkInterfaceIndex> index_list;
105   for (const auto& interface : interfaces) {
106     OSP_VLOG << "Found interface: " << interface;
107     if (do_filter_using_allowlist &&
108         std::find(allowlist.begin(), allowlist.end(), interface.index) ==
109             allowlist.end()) {
110       OSP_VLOG << "Ignoring interface not in allowed list: " << interface;
111       continue;
112     }
113     if (!interface.addresses.empty())
114       index_list.push_back(interface.index);
115   }
116   OSP_LOG_IF(WARN, index_list.empty())
117       << "No network interfaces had usable addresses for mDNS.";
118 
119   // Set up sockets to send and listen to mDNS multicast traffic on all
120   // interfaces.
121   std::vector<BoundInterface> result;
122   for (NetworkInterfaceIndex index : index_list) {
123     const auto& interface = *std::find_if(
124         interfaces.begin(), interfaces.end(),
125         [index](const InterfaceInfo& info) { return info.index == index; });
126     if (interface.addresses.empty()) {
127       continue;
128     }
129 
130     // Pick any address for the given interface.
131     const IPSubnet& primary_subnet = interface.addresses.front();
132 
133     auto create_result =
134         UdpSocket::Create(parent_->task_runner_, parent_,
135                           IPEndpoint{{}, kMulticastListeningPort});
136     if (!create_result) {
137       OSP_LOG_ERROR << "failed to create socket for interface " << index << ": "
138                     << create_result.error().message();
139       continue;
140     }
141     std::unique_ptr<UdpSocket> socket = std::move(create_result.value());
142     if (!SetUpMulticastSocket(socket.get(), index).ok()) {
143       continue;
144     }
145     result.emplace_back(interface, primary_subnet, socket.get());
146     parent_->RegisterMdnsSocket(socket.get());
147 
148     open_sockets_.emplace_back(std::move(socket));
149   }
150 
151   return result;
152 }
153 
DeregisterInterfaces(const std::vector<BoundInterface> & registered_interfaces)154 void InternalServices::InternalPlatformLinkage::DeregisterInterfaces(
155     const std::vector<BoundInterface>& registered_interfaces) {
156   for (const auto& interface : registered_interfaces) {
157     UdpSocket* const socket = interface.socket;
158     parent_->DeregisterMdnsSocket(socket);
159 
160     const auto it = std::find_if(open_sockets_.begin(), open_sockets_.end(),
161                                  [socket](const std::unique_ptr<UdpSocket>& s) {
162                                    return s.get() == socket;
163                                  });
164     OSP_DCHECK(it != open_sockets_.end());
165     open_sockets_.erase(it);
166   }
167 }
168 
InternalServices(ClockNowFunctionPtr now_function,TaskRunner * task_runner)169 InternalServices::InternalServices(ClockNowFunctionPtr now_function,
170                                    TaskRunner* task_runner)
171     : mdns_service_(now_function,
172                     task_runner,
173                     kServiceName,
174                     kServiceProtocol,
175                     std::make_unique<MdnsResponderAdapterImplFactory>(),
176                     std::make_unique<InternalPlatformLinkage>(this)),
177       task_runner_(task_runner) {}
178 
179 InternalServices::~InternalServices() = default;
180 
RegisterMdnsSocket(UdpSocket * socket)181 void InternalServices::RegisterMdnsSocket(UdpSocket* socket) {
182   OSP_CHECK(g_instance) << "No listener or publisher is alive.";
183   // TODO(rwkeane): Hook this up to the new mDNS library once we swap out the
184   // mDNSResponder.
185 }
186 
DeregisterMdnsSocket(UdpSocket * socket)187 void InternalServices::DeregisterMdnsSocket(UdpSocket* socket) {
188   // TODO(rwkeane): Hook this up to the new mDNS library once we swap out the
189   // mDNSResponder.
190 }
191 
192 // static
ReferenceSingleton(TaskRunner * task_runner)193 InternalServices* InternalServices::ReferenceSingleton(
194     TaskRunner* task_runner) {
195   if (!g_instance) {
196     OSP_CHECK_EQ(g_instance_ref_count, 0);
197     g_instance = new InternalServices(&Clock::now, task_runner);
198   }
199   ++g_instance_ref_count;
200   return g_instance;
201 }
202 
203 // static
DereferenceSingleton(void * instance)204 void InternalServices::DereferenceSingleton(void* instance) {
205   OSP_CHECK_EQ(static_cast<InternalServices*>(instance), g_instance);
206   OSP_CHECK_GT(g_instance_ref_count, 0);
207   --g_instance_ref_count;
208   if (g_instance_ref_count == 0) {
209     delete g_instance;
210     g_instance = nullptr;
211   }
212 }
213 
OnError(UdpSocket * socket,Error error)214 void InternalServices::OnError(UdpSocket* socket, Error error) {
215   OSP_LOG_ERROR << "failed to configure socket " << error.message();
216   this->DeregisterMdnsSocket(socket);
217 }
218 
OnSendError(UdpSocket * socket,Error error)219 void InternalServices::OnSendError(UdpSocket* socket, Error error) {
220   // TODO(crbug.com/openscreen/67): Implement this method.
221   OSP_UNIMPLEMENTED();
222 }
223 
OnRead(UdpSocket * socket,ErrorOr<UdpPacket> packet)224 void InternalServices::OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) {
225   g_instance->mdns_service_.OnRead(socket, std::move(packet));
226 }
227 
228 }  // namespace osp
229 }  // namespace openscreen
230