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/browser/local_discovery/service_discovery_host_client.h"
7 #include "base/location.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "chrome/common/local_discovery/local_discovery_messages.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/utility_process_host.h"
14 #include "net/dns/mdns_client.h"
15 #include "net/socket/socket_descriptor.h"
16 #include "ui/base/l10n/l10n_util.h"
19 #include <netinet/in.h>
20 #include "base/file_descriptor_posix.h"
23 namespace local_discovery
{
25 using content::BrowserThread
;
26 using content::UtilityProcessHost
;
31 SocketInfoList
GetSocketsOnFileThread() {
32 net::InterfaceIndexFamilyList
interfaces(net::GetMDnsInterfacesToBind());
33 SocketInfoList sockets
;
34 for (size_t i
= 0; i
< interfaces
.size(); ++i
) {
35 DCHECK(interfaces
[i
].second
== net::ADDRESS_FAMILY_IPV4
||
36 interfaces
[i
].second
== net::ADDRESS_FAMILY_IPV6
);
37 base::FileDescriptor
socket_descriptor(
38 net::CreatePlatformSocket(
39 net::ConvertAddressFamily(interfaces
[i
].second
), SOCK_DGRAM
,
42 LOG_IF(ERROR
, socket_descriptor
.fd
== net::kInvalidSocket
)
43 << "Can't create socket, family=" << interfaces
[i
].second
;
44 if (socket_descriptor
.fd
!= net::kInvalidSocket
) {
45 LocalDiscoveryMsg_SocketInfo socket
;
46 socket
.descriptor
= socket_descriptor
;
47 socket
.interface_index
= interfaces
[i
].first
;
48 socket
.address_family
= interfaces
[i
].second
;
49 sockets
.push_back(socket
);
59 class ServiceDiscoveryHostClient::ServiceWatcherProxy
: public ServiceWatcher
{
61 ServiceWatcherProxy(ServiceDiscoveryHostClient
* host
,
62 const std::string
& service_type
,
63 const ServiceWatcher::UpdatedCallback
& callback
)
65 service_type_(service_type
),
66 id_(host_
->RegisterWatcherCallback(callback
)),
70 ~ServiceWatcherProxy() override
{
71 DVLOG(1) << "~ServiceWatcherProxy with id " << id_
;
72 host_
->UnregisterWatcherCallback(id_
);
74 host_
->Send(new LocalDiscoveryMsg_DestroyWatcher(id_
));
77 void Start() override
{
78 DVLOG(1) << "ServiceWatcher::Start with id " << id_
;
80 host_
->Send(new LocalDiscoveryMsg_StartWatcher(id_
, service_type_
));
84 void DiscoverNewServices(bool force_update
) override
{
85 DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_
;
87 host_
->Send(new LocalDiscoveryMsg_DiscoverServices(id_
, force_update
));
90 void SetActivelyRefreshServices(bool actively_refresh_services
) override
{
91 DVLOG(1) << "ServiceWatcher::SetActivelyRefreshServices with id " << id_
;
93 host_
->Send(new LocalDiscoveryMsg_SetActivelyRefreshServices(
94 id_
, actively_refresh_services
));
97 std::string
GetServiceType() const override
{ return service_type_
; }
100 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
101 const std::string service_type_
;
106 class ServiceDiscoveryHostClient::ServiceResolverProxy
107 : public ServiceResolver
{
109 ServiceResolverProxy(ServiceDiscoveryHostClient
* host
,
110 const std::string
& service_name
,
111 const ServiceResolver::ResolveCompleteCallback
& callback
)
113 service_name_(service_name
),
114 id_(host
->RegisterResolverCallback(callback
)),
118 ~ServiceResolverProxy() override
{
119 DVLOG(1) << "~ServiceResolverProxy with id " << id_
;
120 host_
->UnregisterResolverCallback(id_
);
122 host_
->Send(new LocalDiscoveryMsg_DestroyResolver(id_
));
125 void StartResolving() override
{
126 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_
;
128 host_
->Send(new LocalDiscoveryMsg_ResolveService(id_
, service_name_
));
132 std::string
GetName() const override
{ return service_name_
; }
135 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
136 const std::string service_name_
;
141 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
142 : public LocalDomainResolver
{
144 LocalDomainResolverProxy(ServiceDiscoveryHostClient
* host
,
145 const std::string
& domain
,
146 net::AddressFamily address_family
,
147 const LocalDomainResolver::IPAddressCallback
& callback
)
150 address_family_(address_family
),
151 id_(host
->RegisterLocalDomainResolverCallback(callback
)),
155 ~LocalDomainResolverProxy() override
{
156 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_
;
157 host_
->UnregisterLocalDomainResolverCallback(id_
);
159 host_
->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_
));
162 void Start() override
{
163 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_
;
165 host_
->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_
, domain_
,
171 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
173 net::AddressFamily address_family_
;
178 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
179 callback_runner_
= base::MessageLoop::current()->task_runner();
180 io_runner_
= BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
183 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
184 DCHECK(service_watcher_callbacks_
.empty());
185 DCHECK(service_resolver_callbacks_
.empty());
186 DCHECK(domain_resolver_callbacks_
.empty());
189 scoped_ptr
<ServiceWatcher
> ServiceDiscoveryHostClient::CreateServiceWatcher(
190 const std::string
& service_type
,
191 const ServiceWatcher::UpdatedCallback
& callback
) {
192 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
193 return scoped_ptr
<ServiceWatcher
>(
194 new ServiceWatcherProxy(this, service_type
, callback
));
197 scoped_ptr
<ServiceResolver
> ServiceDiscoveryHostClient::CreateServiceResolver(
198 const std::string
& service_name
,
199 const ServiceResolver::ResolveCompleteCallback
& callback
) {
200 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
201 return scoped_ptr
<ServiceResolver
>(
202 new ServiceResolverProxy(this, service_name
, callback
));
205 scoped_ptr
<LocalDomainResolver
>
206 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
207 const std::string
& domain
,
208 net::AddressFamily address_family
,
209 const LocalDomainResolver::IPAddressCallback
& callback
) {
210 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
211 return scoped_ptr
<LocalDomainResolver
>(new LocalDomainResolverProxy(
212 this, domain
, address_family
, callback
));
215 uint64
ServiceDiscoveryHostClient::RegisterWatcherCallback(
216 const ServiceWatcher::UpdatedCallback
& callback
) {
217 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
218 DCHECK(!ContainsKey(service_watcher_callbacks_
, current_id_
+ 1));
219 service_watcher_callbacks_
[++current_id_
] = callback
;
223 uint64
ServiceDiscoveryHostClient::RegisterResolverCallback(
224 const ServiceResolver::ResolveCompleteCallback
& callback
) {
225 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
226 DCHECK(!ContainsKey(service_resolver_callbacks_
, current_id_
+ 1));
227 service_resolver_callbacks_
[++current_id_
] = callback
;
231 uint64
ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
232 const LocalDomainResolver::IPAddressCallback
& callback
) {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
234 DCHECK(!ContainsKey(domain_resolver_callbacks_
, current_id_
+ 1));
235 domain_resolver_callbacks_
[++current_id_
] = callback
;
239 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id
) {
240 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
241 service_watcher_callbacks_
.erase(id
);
244 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id
) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
246 service_resolver_callbacks_
.erase(id
);
249 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
251 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
252 domain_resolver_callbacks_
.erase(id
);
255 void ServiceDiscoveryHostClient::Start(
256 const base::Closure
& error_callback
) {
257 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
258 DCHECK(!utility_host_
);
259 DCHECK(error_callback_
.is_null());
260 error_callback_
= error_callback
;
261 io_runner_
->PostTask(
263 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread
, this));
266 void ServiceDiscoveryHostClient::Shutdown() {
267 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
268 io_runner_
->PostTask(
270 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread
, this));
273 #if defined(OS_POSIX)
275 void ServiceDiscoveryHostClient::StartOnIOThread() {
276 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
277 DCHECK(!utility_host_
);
278 BrowserThread::PostTaskAndReplyWithResult(
281 base::Bind(&GetSocketsOnFileThread
),
282 base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady
, this));
285 void ServiceDiscoveryHostClient::OnSocketsReady(const SocketInfoList
& sockets
) {
286 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
287 DCHECK(!utility_host_
);
289 UtilityProcessHost::Create(
290 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
291 utility_host_
->SetName(l10n_util::GetStringUTF16(
292 IDS_UTILITY_PROCESS_SERVICE_DISCOVERY_HANDLER_NAME
));
293 utility_host_
->EnableMDns();
294 utility_host_
->StartBatchMode();
295 if (sockets
.empty()) {
296 ShutdownOnIOThread();
299 utility_host_
->Send(new LocalDiscoveryMsg_SetSockets(sockets
));
300 // Send messages for requests made during network enumeration.
301 for (size_t i
= 0; i
< delayed_messages_
.size(); ++i
)
302 utility_host_
->Send(delayed_messages_
[i
]);
303 delayed_messages_
.weak_clear();
308 void ServiceDiscoveryHostClient::StartOnIOThread() {
309 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
310 DCHECK(!utility_host_
);
312 UtilityProcessHost::Create(
313 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
314 utility_host_
->SetName(l10n_util::GetStringUTF16(
315 IDS_UTILITY_PROCESS_SERVICE_DISCOVERY_HANDLER_NAME
));
316 utility_host_
->EnableMDns();
317 utility_host_
->StartBatchMode();
318 // Windows does not enumerate networks here.
319 DCHECK(delayed_messages_
.empty());
324 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
325 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
327 utility_host_
->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery
);
328 utility_host_
->EndBatchMode();
329 utility_host_
.reset();
331 error_callback_
= base::Closure();
334 void ServiceDiscoveryHostClient::Send(IPC::Message
* msg
) {
335 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
336 io_runner_
->PostTask(
338 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread
, this, msg
));
341 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message
* msg
) {
342 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
344 utility_host_
->Send(msg
);
346 delayed_messages_
.push_back(msg
);
350 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code
) {
351 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
352 DCHECK(!utility_host_
);
356 bool ServiceDiscoveryHostClient::OnMessageReceived(
357 const IPC::Message
& message
) {
359 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient
, message
)
360 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error
, OnError
)
361 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback
,
363 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback
,
365 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback
,
366 OnLocalDomainResolverCallback
)
367 IPC_MESSAGE_UNHANDLED(handled
= false)
368 IPC_END_MESSAGE_MAP()
372 void ServiceDiscoveryHostClient::InvalidateWatchers() {
373 WatcherCallbacks service_watcher_callbacks
;
374 service_watcher_callbacks_
.swap(service_watcher_callbacks
);
375 service_resolver_callbacks_
.clear();
376 domain_resolver_callbacks_
.clear();
378 for (WatcherCallbacks::iterator i
= service_watcher_callbacks
.begin();
379 i
!= service_watcher_callbacks
.end(); i
++) {
380 if (!i
->second
.is_null()) {
381 i
->second
.Run(ServiceWatcher::UPDATE_INVALIDATED
, "");
386 void ServiceDiscoveryHostClient::OnError() {
387 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
388 if (!error_callback_
.is_null())
389 callback_runner_
->PostTask(FROM_HERE
, error_callback_
);
392 void ServiceDiscoveryHostClient::OnWatcherCallback(
394 ServiceWatcher::UpdateType update
,
395 const std::string
& service_name
) {
396 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
397 callback_runner_
->PostTask(
399 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback
, this, id
,
400 update
, service_name
));
403 void ServiceDiscoveryHostClient::OnResolverCallback(
405 ServiceResolver::RequestStatus status
,
406 const ServiceDescription
& description
) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
408 callback_runner_
->PostTask(
410 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback
, this, id
,
411 status
, description
));
414 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
417 const net::IPAddressNumber
& ip_address_ipv4
,
418 const net::IPAddressNumber
& ip_address_ipv6
) {
419 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
420 callback_runner_
->PostTask(
422 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback
,
423 this, id
, success
, ip_address_ipv4
, ip_address_ipv6
));
426 void ServiceDiscoveryHostClient::RunWatcherCallback(
428 ServiceWatcher::UpdateType update
,
429 const std::string
& service_name
) {
430 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
431 WatcherCallbacks::iterator it
= service_watcher_callbacks_
.find(id
);
432 if (it
!= service_watcher_callbacks_
.end() && !it
->second
.is_null())
433 it
->second
.Run(update
, service_name
);
436 void ServiceDiscoveryHostClient::RunResolverCallback(
438 ServiceResolver::RequestStatus status
,
439 const ServiceDescription
& description
) {
440 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
441 ResolverCallbacks::iterator it
= service_resolver_callbacks_
.find(id
);
442 if (it
!= service_resolver_callbacks_
.end() && !it
->second
.is_null())
443 it
->second
.Run(status
, description
);
446 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
449 const net::IPAddressNumber
& ip_address_ipv4
,
450 const net::IPAddressNumber
& ip_address_ipv6
) {
451 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
452 DomainResolverCallbacks::iterator it
= domain_resolver_callbacks_
.find(id
);
453 if (it
!= domain_resolver_callbacks_
.end() && !it
->second
.is_null())
454 it
->second
.Run(success
, ip_address_ipv4
, ip_address_ipv6
);
457 } // namespace local_discovery