Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / utility / local_discovery / service_discovery_message_handler.cc
blob3110c9443f300dcb24d088f4082afd3e8c04ebb0
1 // Copyright 2013 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.
5 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
7 #include <algorithm>
9 #include "base/lazy_instance.h"
10 #include "chrome/common/local_discovery/local_discovery_messages.h"
11 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
12 #include "content/public/utility/utility_thread.h"
13 #include "net/socket/socket_descriptor.h"
14 #include "net/udp/datagram_server_socket.h"
16 namespace local_discovery {
18 namespace {
20 void ClosePlatformSocket(net::SocketDescriptor socket);
22 // Sets socket factory used by |net::CreatePlatformSocket|. Implemetation
23 // keeps single socket that will be returned to the first call to
24 // |net::CreatePlatformSocket| during object lifetime.
25 class ScopedSocketFactory : public net::PlatformSocketFactory {
26 public:
27 explicit ScopedSocketFactory(net::SocketDescriptor socket) : socket_(socket) {
28 net::PlatformSocketFactory::SetInstance(this);
31 ~ScopedSocketFactory() override {
32 net::PlatformSocketFactory::SetInstance(NULL);
33 ClosePlatformSocket(socket_);
34 socket_ = net::kInvalidSocket;
37 net::SocketDescriptor CreateSocket(int family,
38 int type,
39 int protocol) override {
40 DCHECK_EQ(type, SOCK_DGRAM);
41 DCHECK(family == AF_INET || family == AF_INET6);
42 net::SocketDescriptor result = net::kInvalidSocket;
43 std::swap(result, socket_);
44 return result;
47 private:
48 net::SocketDescriptor socket_;
49 DISALLOW_COPY_AND_ASSIGN(ScopedSocketFactory);
52 struct SocketInfo {
53 SocketInfo(net::SocketDescriptor socket,
54 net::AddressFamily address_family,
55 uint32 interface_index)
56 : socket(socket),
57 address_family(address_family),
58 interface_index(interface_index) {
60 net::SocketDescriptor socket;
61 net::AddressFamily address_family;
62 uint32 interface_index;
65 // Returns list of sockets preallocated before.
66 class PreCreatedMDnsSocketFactory : public net::MDnsSocketFactory {
67 public:
68 PreCreatedMDnsSocketFactory() {}
69 ~PreCreatedMDnsSocketFactory() override {
70 // Not empty if process exits too fast, before starting mDns code. If
71 // happened, destructors may crash accessing destroyed global objects.
72 sockets_.weak_clear();
75 // net::MDnsSocketFactory implementation:
76 void CreateSockets(
77 ScopedVector<net::DatagramServerSocket>* sockets) override {
78 sockets->swap(sockets_);
79 Reset();
82 void AddSocket(const SocketInfo& socket_info) {
83 // Takes ownership of socket_info.socket;
84 ScopedSocketFactory platform_factory(socket_info.socket);
85 scoped_ptr<net::DatagramServerSocket> socket(
86 net::CreateAndBindMDnsSocket(socket_info.address_family,
87 socket_info.interface_index));
88 if (socket) {
89 socket->DetachFromThread();
90 sockets_.push_back(socket.release());
94 void Reset() {
95 sockets_.clear();
98 private:
99 ScopedVector<net::DatagramServerSocket> sockets_;
101 DISALLOW_COPY_AND_ASSIGN(PreCreatedMDnsSocketFactory);
104 base::LazyInstance<PreCreatedMDnsSocketFactory>
105 g_local_discovery_socket_factory = LAZY_INSTANCE_INITIALIZER;
107 #if defined(OS_WIN)
109 void ClosePlatformSocket(net::SocketDescriptor socket) {
110 ::closesocket(socket);
113 void StaticInitializeSocketFactory() {
114 net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind());
115 for (size_t i = 0; i < interfaces.size(); ++i) {
116 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
117 interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
118 net::SocketDescriptor descriptor =
119 net::CreatePlatformSocket(
120 net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM,
121 IPPROTO_UDP);
122 g_local_discovery_socket_factory.Get().AddSocket(
123 SocketInfo(descriptor, interfaces[i].second, interfaces[i].first));
127 #else // OS_WIN
129 void ClosePlatformSocket(net::SocketDescriptor socket) {
130 ::close(socket);
133 void StaticInitializeSocketFactory() {
136 #endif // OS_WIN
138 void SendHostMessageOnUtilityThread(IPC::Message* msg) {
139 content::UtilityThread::Get()->Send(msg);
142 std::string WatcherUpdateToString(ServiceWatcher::UpdateType update) {
143 switch (update) {
144 case ServiceWatcher::UPDATE_ADDED:
145 return "UPDATE_ADDED";
146 case ServiceWatcher::UPDATE_CHANGED:
147 return "UPDATE_CHANGED";
148 case ServiceWatcher::UPDATE_REMOVED:
149 return "UPDATE_REMOVED";
150 case ServiceWatcher::UPDATE_INVALIDATED:
151 return "UPDATE_INVALIDATED";
153 return "Unknown Update";
156 std::string ResolverStatusToString(ServiceResolver::RequestStatus status) {
157 switch (status) {
158 case ServiceResolver::STATUS_SUCCESS:
159 return "STATUS_SUCESS";
160 case ServiceResolver::STATUS_REQUEST_TIMEOUT:
161 return "STATUS_REQUEST_TIMEOUT";
162 case ServiceResolver::STATUS_KNOWN_NONEXISTENT:
163 return "STATUS_KNOWN_NONEXISTENT";
165 return "Unknown Status";
168 } // namespace
170 ServiceDiscoveryMessageHandler::ServiceDiscoveryMessageHandler() {
173 ServiceDiscoveryMessageHandler::~ServiceDiscoveryMessageHandler() {
174 DCHECK(!discovery_thread_);
177 void ServiceDiscoveryMessageHandler::PreSandboxStartup() {
178 StaticInitializeSocketFactory();
181 void ServiceDiscoveryMessageHandler::InitializeMdns() {
182 if (service_discovery_client_ || mdns_client_)
183 return;
185 mdns_client_ = net::MDnsClient::CreateDefault();
186 bool result =
187 mdns_client_->StartListening(g_local_discovery_socket_factory.Pointer());
188 // Close unused sockets.
189 g_local_discovery_socket_factory.Get().Reset();
190 if (!result) {
191 VLOG(1) << "Failed to start MDnsClient";
192 Send(new LocalDiscoveryHostMsg_Error());
193 return;
196 service_discovery_client_.reset(
197 new local_discovery::ServiceDiscoveryClientImpl(mdns_client_.get()));
200 bool ServiceDiscoveryMessageHandler::InitializeThread() {
201 if (discovery_task_runner_.get())
202 return true;
203 if (discovery_thread_)
204 return false;
205 utility_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
206 discovery_thread_.reset(new base::Thread("ServiceDiscoveryThread"));
207 base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
208 if (discovery_thread_->StartWithOptions(thread_options)) {
209 discovery_task_runner_ = discovery_thread_->message_loop_proxy();
210 discovery_task_runner_->PostTask(FROM_HERE,
211 base::Bind(&ServiceDiscoveryMessageHandler::InitializeMdns,
212 base::Unretained(this)));
214 return discovery_task_runner_.get() != NULL;
217 bool ServiceDiscoveryMessageHandler::OnMessageReceived(
218 const IPC::Message& message) {
219 bool handled = true;
220 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryMessageHandler, message)
221 #if defined(OS_POSIX)
222 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetSockets, OnSetSockets)
223 #endif // OS_POSIX
224 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_StartWatcher, OnStartWatcher)
225 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DiscoverServices, OnDiscoverServices)
226 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetActivelyRefreshServices,
227 OnSetActivelyRefreshServices)
228 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyWatcher, OnDestroyWatcher)
229 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveService, OnResolveService)
230 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyResolver, OnDestroyResolver)
231 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveLocalDomain,
232 OnResolveLocalDomain)
233 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyLocalDomainResolver,
234 OnDestroyLocalDomainResolver)
235 IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ShutdownLocalDiscovery,
236 ShutdownLocalDiscovery)
237 IPC_MESSAGE_UNHANDLED(handled = false)
238 IPC_END_MESSAGE_MAP()
239 return handled;
242 void ServiceDiscoveryMessageHandler::PostTask(
243 const tracked_objects::Location& from_here,
244 const base::Closure& task) {
245 if (!InitializeThread())
246 return;
247 discovery_task_runner_->PostTask(from_here, task);
250 #if defined(OS_POSIX)
251 void ServiceDiscoveryMessageHandler::OnSetSockets(
252 const std::vector<LocalDiscoveryMsg_SocketInfo>& sockets) {
253 for (size_t i = 0; i < sockets.size(); ++i) {
254 g_local_discovery_socket_factory.Get().AddSocket(
255 SocketInfo(sockets[i].descriptor.fd, sockets[i].address_family,
256 sockets[i].interface_index));
259 #endif // OS_POSIX
261 void ServiceDiscoveryMessageHandler::OnStartWatcher(
262 uint64 id,
263 const std::string& service_type) {
264 PostTask(FROM_HERE,
265 base::Bind(&ServiceDiscoveryMessageHandler::StartWatcher,
266 base::Unretained(this), id, service_type));
269 void ServiceDiscoveryMessageHandler::OnDiscoverServices(uint64 id,
270 bool force_update) {
271 PostTask(FROM_HERE,
272 base::Bind(&ServiceDiscoveryMessageHandler::DiscoverServices,
273 base::Unretained(this), id, force_update));
276 void ServiceDiscoveryMessageHandler::OnSetActivelyRefreshServices(
277 uint64 id, bool actively_refresh_services) {
278 PostTask(FROM_HERE,
279 base::Bind(
280 &ServiceDiscoveryMessageHandler::SetActivelyRefreshServices,
281 base::Unretained(this), id, actively_refresh_services));
284 void ServiceDiscoveryMessageHandler::OnDestroyWatcher(uint64 id) {
285 PostTask(FROM_HERE,
286 base::Bind(&ServiceDiscoveryMessageHandler::DestroyWatcher,
287 base::Unretained(this), id));
290 void ServiceDiscoveryMessageHandler::OnResolveService(
291 uint64 id,
292 const std::string& service_name) {
293 PostTask(FROM_HERE,
294 base::Bind(&ServiceDiscoveryMessageHandler::ResolveService,
295 base::Unretained(this), id, service_name));
298 void ServiceDiscoveryMessageHandler::OnDestroyResolver(uint64 id) {
299 PostTask(FROM_HERE,
300 base::Bind(&ServiceDiscoveryMessageHandler::DestroyResolver,
301 base::Unretained(this), id));
304 void ServiceDiscoveryMessageHandler::OnResolveLocalDomain(
305 uint64 id, const std::string& domain,
306 net::AddressFamily address_family) {
307 PostTask(FROM_HERE,
308 base::Bind(&ServiceDiscoveryMessageHandler::ResolveLocalDomain,
309 base::Unretained(this), id, domain, address_family));
312 void ServiceDiscoveryMessageHandler::OnDestroyLocalDomainResolver(uint64 id) {
313 PostTask(FROM_HERE,
314 base::Bind(
315 &ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver,
316 base::Unretained(this), id));
319 void ServiceDiscoveryMessageHandler::StartWatcher(
320 uint64 id,
321 const std::string& service_type) {
322 VLOG(1) << "StartWatcher, id=" << id << ", type=" << service_type;
323 if (!service_discovery_client_)
324 return;
325 DCHECK(!ContainsKey(service_watchers_, id));
326 scoped_ptr<ServiceWatcher> watcher(
327 service_discovery_client_->CreateServiceWatcher(
328 service_type,
329 base::Bind(&ServiceDiscoveryMessageHandler::OnServiceUpdated,
330 base::Unretained(this), id)));
331 watcher->Start();
332 service_watchers_[id].reset(watcher.release());
335 void ServiceDiscoveryMessageHandler::DiscoverServices(uint64 id,
336 bool force_update) {
337 VLOG(1) << "DiscoverServices, id=" << id;
338 if (!service_discovery_client_)
339 return;
340 DCHECK(ContainsKey(service_watchers_, id));
341 service_watchers_[id]->DiscoverNewServices(force_update);
344 void ServiceDiscoveryMessageHandler::SetActivelyRefreshServices(
345 uint64 id,
346 bool actively_refresh_services) {
347 VLOG(1) << "ActivelyRefreshServices, id=" << id;
348 if (!service_discovery_client_)
349 return;
350 DCHECK(ContainsKey(service_watchers_, id));
351 service_watchers_[id]->SetActivelyRefreshServices(actively_refresh_services);
354 void ServiceDiscoveryMessageHandler::DestroyWatcher(uint64 id) {
355 VLOG(1) << "DestoryWatcher, id=" << id;
356 if (!service_discovery_client_)
357 return;
358 service_watchers_.erase(id);
361 void ServiceDiscoveryMessageHandler::ResolveService(
362 uint64 id,
363 const std::string& service_name) {
364 VLOG(1) << "ResolveService, id=" << id << ", name=" << service_name;
365 if (!service_discovery_client_)
366 return;
367 DCHECK(!ContainsKey(service_resolvers_, id));
368 scoped_ptr<ServiceResolver> resolver(
369 service_discovery_client_->CreateServiceResolver(
370 service_name,
371 base::Bind(&ServiceDiscoveryMessageHandler::OnServiceResolved,
372 base::Unretained(this), id)));
373 resolver->StartResolving();
374 service_resolvers_[id].reset(resolver.release());
377 void ServiceDiscoveryMessageHandler::DestroyResolver(uint64 id) {
378 VLOG(1) << "DestroyResolver, id=" << id;
379 if (!service_discovery_client_)
380 return;
381 service_resolvers_.erase(id);
384 void ServiceDiscoveryMessageHandler::ResolveLocalDomain(
385 uint64 id,
386 const std::string& domain,
387 net::AddressFamily address_family) {
388 VLOG(1) << "ResolveLocalDomain, id=" << id << ", domain=" << domain;
389 if (!service_discovery_client_)
390 return;
391 DCHECK(!ContainsKey(local_domain_resolvers_, id));
392 scoped_ptr<LocalDomainResolver> resolver(
393 service_discovery_client_->CreateLocalDomainResolver(
394 domain, address_family,
395 base::Bind(&ServiceDiscoveryMessageHandler::OnLocalDomainResolved,
396 base::Unretained(this), id)));
397 resolver->Start();
398 local_domain_resolvers_[id].reset(resolver.release());
401 void ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver(uint64 id) {
402 VLOG(1) << "DestroyLocalDomainResolver, id=" << id;
403 if (!service_discovery_client_)
404 return;
405 local_domain_resolvers_.erase(id);
408 void ServiceDiscoveryMessageHandler::ShutdownLocalDiscovery() {
409 if (!discovery_task_runner_.get())
410 return;
412 discovery_task_runner_->PostTask(
413 FROM_HERE,
414 base::Bind(&ServiceDiscoveryMessageHandler::ShutdownOnIOThread,
415 base::Unretained(this)));
417 // This will wait for message loop to drain, so ShutdownOnIOThread will
418 // definitely be called.
419 discovery_thread_.reset();
422 void ServiceDiscoveryMessageHandler::ShutdownOnIOThread() {
423 VLOG(1) << "ShutdownLocalDiscovery";
424 service_watchers_.clear();
425 service_resolvers_.clear();
426 local_domain_resolvers_.clear();
427 service_discovery_client_.reset();
428 mdns_client_.reset();
431 void ServiceDiscoveryMessageHandler::OnServiceUpdated(
432 uint64 id,
433 ServiceWatcher::UpdateType update,
434 const std::string& name) {
435 VLOG(1) << "OnServiceUpdated, id=" << id
436 << ", status=" << WatcherUpdateToString(update) << ", name=" << name;
437 DCHECK(service_discovery_client_);
439 Send(new LocalDiscoveryHostMsg_WatcherCallback(id, update, name));
442 void ServiceDiscoveryMessageHandler::OnServiceResolved(
443 uint64 id,
444 ServiceResolver::RequestStatus status,
445 const ServiceDescription& description) {
446 VLOG(1) << "OnServiceResolved, id=" << id
447 << ", status=" << ResolverStatusToString(status)
448 << ", name=" << description.service_name;
450 DCHECK(service_discovery_client_);
451 Send(new LocalDiscoveryHostMsg_ResolverCallback(id, status, description));
454 void ServiceDiscoveryMessageHandler::OnLocalDomainResolved(
455 uint64 id,
456 bool success,
457 const net::IPAddressNumber& address_ipv4,
458 const net::IPAddressNumber& address_ipv6) {
459 VLOG(1) << "OnLocalDomainResolved, id=" << id
460 << ", IPv4=" << (address_ipv4.empty() ? "" :
461 net::IPAddressToString(address_ipv4))
462 << ", IPv6=" << (address_ipv6.empty() ? "" :
463 net::IPAddressToString(address_ipv6));
465 DCHECK(service_discovery_client_);
466 Send(new LocalDiscoveryHostMsg_LocalDomainResolverCallback(
467 id, success, address_ipv4, address_ipv6));
470 void ServiceDiscoveryMessageHandler::Send(IPC::Message* msg) {
471 utility_task_runner_->PostTask(FROM_HERE,
472 base::Bind(&SendHostMessageOnUtilityThread,
473 msg));
476 } // namespace local_discovery