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 "chrome/common/local_discovery/local_discovery_messages.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "content/public/browser/utility_process_host.h"
10 #include "net/dns/mdns_client.h"
11 #include "net/socket/socket_descriptor.h"
14 #include <netinet/in.h>
15 #include "base/file_descriptor_posix.h"
18 namespace local_discovery
{
20 using content::BrowserThread
;
21 using content::UtilityProcessHost
;
26 SocketInfoList
GetSocketsOnFileThread() {
27 net::InterfaceIndexFamilyList
interfaces(net::GetMDnsInterfacesToBind());
28 SocketInfoList sockets
;
29 for (size_t i
= 0; i
< interfaces
.size(); ++i
) {
30 DCHECK(interfaces
[i
].second
== net::ADDRESS_FAMILY_IPV4
||
31 interfaces
[i
].second
== net::ADDRESS_FAMILY_IPV6
);
32 base::FileDescriptor
socket_descriptor(
33 net::CreatePlatformSocket(
34 net::ConvertAddressFamily(interfaces
[i
].second
), SOCK_DGRAM
,
37 LOG_IF(ERROR
, socket_descriptor
.fd
== net::kInvalidSocket
)
38 << "Can't create socket, family=" << interfaces
[i
].second
;
39 if (socket_descriptor
.fd
!= net::kInvalidSocket
) {
40 LocalDiscoveryMsg_SocketInfo socket
;
41 socket
.descriptor
= socket_descriptor
;
42 socket
.interface_index
= interfaces
[i
].first
;
43 socket
.address_family
= interfaces
[i
].second
;
44 sockets
.push_back(socket
);
54 class ServiceDiscoveryHostClient::ServiceWatcherProxy
: public ServiceWatcher
{
56 ServiceWatcherProxy(ServiceDiscoveryHostClient
* host
,
57 const std::string
& service_type
,
58 const ServiceWatcher::UpdatedCallback
& callback
)
60 service_type_(service_type
),
61 id_(host_
->RegisterWatcherCallback(callback
)),
65 ~ServiceWatcherProxy() override
{
66 DVLOG(1) << "~ServiceWatcherProxy with id " << id_
;
67 host_
->UnregisterWatcherCallback(id_
);
69 host_
->Send(new LocalDiscoveryMsg_DestroyWatcher(id_
));
72 void Start() override
{
73 DVLOG(1) << "ServiceWatcher::Start with id " << id_
;
75 host_
->Send(new LocalDiscoveryMsg_StartWatcher(id_
, service_type_
));
79 void DiscoverNewServices(bool force_update
) override
{
80 DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_
;
82 host_
->Send(new LocalDiscoveryMsg_DiscoverServices(id_
, force_update
));
85 void SetActivelyRefreshServices(bool actively_refresh_services
) override
{
86 DVLOG(1) << "ServiceWatcher::SetActivelyRefreshServices with id " << id_
;
88 host_
->Send(new LocalDiscoveryMsg_SetActivelyRefreshServices(
89 id_
, actively_refresh_services
));
92 std::string
GetServiceType() const override
{ return service_type_
; }
95 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
96 const std::string service_type_
;
101 class ServiceDiscoveryHostClient::ServiceResolverProxy
102 : public ServiceResolver
{
104 ServiceResolverProxy(ServiceDiscoveryHostClient
* host
,
105 const std::string
& service_name
,
106 const ServiceResolver::ResolveCompleteCallback
& callback
)
108 service_name_(service_name
),
109 id_(host
->RegisterResolverCallback(callback
)),
113 ~ServiceResolverProxy() override
{
114 DVLOG(1) << "~ServiceResolverProxy with id " << id_
;
115 host_
->UnregisterResolverCallback(id_
);
117 host_
->Send(new LocalDiscoveryMsg_DestroyResolver(id_
));
120 void StartResolving() override
{
121 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_
;
123 host_
->Send(new LocalDiscoveryMsg_ResolveService(id_
, service_name_
));
127 std::string
GetName() const override
{ return service_name_
; }
130 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
131 const std::string service_name_
;
136 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
137 : public LocalDomainResolver
{
139 LocalDomainResolverProxy(ServiceDiscoveryHostClient
* host
,
140 const std::string
& domain
,
141 net::AddressFamily address_family
,
142 const LocalDomainResolver::IPAddressCallback
& callback
)
145 address_family_(address_family
),
146 id_(host
->RegisterLocalDomainResolverCallback(callback
)),
150 ~LocalDomainResolverProxy() override
{
151 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_
;
152 host_
->UnregisterLocalDomainResolverCallback(id_
);
154 host_
->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_
));
157 void Start() override
{
158 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_
;
160 host_
->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_
, domain_
,
166 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
168 net::AddressFamily address_family_
;
173 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
174 callback_runner_
= base::MessageLoop::current()->message_loop_proxy();
175 io_runner_
= BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
178 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
179 DCHECK(service_watcher_callbacks_
.empty());
180 DCHECK(service_resolver_callbacks_
.empty());
181 DCHECK(domain_resolver_callbacks_
.empty());
184 scoped_ptr
<ServiceWatcher
> ServiceDiscoveryHostClient::CreateServiceWatcher(
185 const std::string
& service_type
,
186 const ServiceWatcher::UpdatedCallback
& callback
) {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
188 return scoped_ptr
<ServiceWatcher
>(
189 new ServiceWatcherProxy(this, service_type
, callback
));
192 scoped_ptr
<ServiceResolver
> ServiceDiscoveryHostClient::CreateServiceResolver(
193 const std::string
& service_name
,
194 const ServiceResolver::ResolveCompleteCallback
& callback
) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
196 return scoped_ptr
<ServiceResolver
>(
197 new ServiceResolverProxy(this, service_name
, callback
));
200 scoped_ptr
<LocalDomainResolver
>
201 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
202 const std::string
& domain
,
203 net::AddressFamily address_family
,
204 const LocalDomainResolver::IPAddressCallback
& callback
) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
206 return scoped_ptr
<LocalDomainResolver
>(new LocalDomainResolverProxy(
207 this, domain
, address_family
, callback
));
210 uint64
ServiceDiscoveryHostClient::RegisterWatcherCallback(
211 const ServiceWatcher::UpdatedCallback
& callback
) {
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
213 DCHECK(!ContainsKey(service_watcher_callbacks_
, current_id_
+ 1));
214 service_watcher_callbacks_
[++current_id_
] = callback
;
218 uint64
ServiceDiscoveryHostClient::RegisterResolverCallback(
219 const ServiceResolver::ResolveCompleteCallback
& callback
) {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
221 DCHECK(!ContainsKey(service_resolver_callbacks_
, current_id_
+ 1));
222 service_resolver_callbacks_
[++current_id_
] = callback
;
226 uint64
ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
227 const LocalDomainResolver::IPAddressCallback
& callback
) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
229 DCHECK(!ContainsKey(domain_resolver_callbacks_
, current_id_
+ 1));
230 domain_resolver_callbacks_
[++current_id_
] = callback
;
234 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id
) {
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
236 service_watcher_callbacks_
.erase(id
);
239 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id
) {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
241 service_resolver_callbacks_
.erase(id
);
244 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
247 domain_resolver_callbacks_
.erase(id
);
250 void ServiceDiscoveryHostClient::Start(
251 const base::Closure
& error_callback
) {
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
253 DCHECK(!utility_host_
);
254 DCHECK(error_callback_
.is_null());
255 error_callback_
= error_callback
;
256 io_runner_
->PostTask(
258 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread
, this));
261 void ServiceDiscoveryHostClient::Shutdown() {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
263 io_runner_
->PostTask(
265 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread
, this));
268 #if defined(OS_POSIX)
270 void ServiceDiscoveryHostClient::StartOnIOThread() {
271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
272 DCHECK(!utility_host_
);
273 BrowserThread::PostTaskAndReplyWithResult(
276 base::Bind(&GetSocketsOnFileThread
),
277 base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady
, this));
280 void ServiceDiscoveryHostClient::OnSocketsReady(const SocketInfoList
& sockets
) {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
282 DCHECK(!utility_host_
);
283 utility_host_
= UtilityProcessHost::Create(
284 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
287 utility_host_
->EnableMDns();
288 utility_host_
->StartBatchMode();
289 if (sockets
.empty()) {
290 ShutdownOnIOThread();
293 utility_host_
->Send(new LocalDiscoveryMsg_SetSockets(sockets
));
294 // Send messages for requests made during network enumeration.
295 for (size_t i
= 0; i
< delayed_messages_
.size(); ++i
)
296 utility_host_
->Send(delayed_messages_
[i
]);
297 delayed_messages_
.weak_clear();
302 void ServiceDiscoveryHostClient::StartOnIOThread() {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
304 DCHECK(!utility_host_
);
305 utility_host_
= UtilityProcessHost::Create(
306 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
309 utility_host_
->EnableMDns();
310 utility_host_
->StartBatchMode();
311 // Windows does not enumerate networks here.
312 DCHECK(delayed_messages_
.empty());
317 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
320 utility_host_
->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery
);
321 utility_host_
->EndBatchMode();
322 utility_host_
.reset();
324 error_callback_
= base::Closure();
327 void ServiceDiscoveryHostClient::Send(IPC::Message
* msg
) {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
329 io_runner_
->PostTask(
331 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread
, this, msg
));
334 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message
* msg
) {
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
337 utility_host_
->Send(msg
);
339 delayed_messages_
.push_back(msg
);
343 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code
) {
344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
345 DCHECK(!utility_host_
);
349 bool ServiceDiscoveryHostClient::OnMessageReceived(
350 const IPC::Message
& message
) {
352 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient
, message
)
353 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error
, OnError
)
354 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback
,
356 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback
,
358 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback
,
359 OnLocalDomainResolverCallback
)
360 IPC_MESSAGE_UNHANDLED(handled
= false)
361 IPC_END_MESSAGE_MAP()
365 void ServiceDiscoveryHostClient::InvalidateWatchers() {
366 WatcherCallbacks service_watcher_callbacks
;
367 service_watcher_callbacks_
.swap(service_watcher_callbacks
);
368 service_resolver_callbacks_
.clear();
369 domain_resolver_callbacks_
.clear();
371 for (WatcherCallbacks::iterator i
= service_watcher_callbacks
.begin();
372 i
!= service_watcher_callbacks
.end(); i
++) {
373 if (!i
->second
.is_null()) {
374 i
->second
.Run(ServiceWatcher::UPDATE_INVALIDATED
, "");
379 void ServiceDiscoveryHostClient::OnError() {
380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
381 if (!error_callback_
.is_null())
382 callback_runner_
->PostTask(FROM_HERE
, error_callback_
);
385 void ServiceDiscoveryHostClient::OnWatcherCallback(
387 ServiceWatcher::UpdateType update
,
388 const std::string
& service_name
) {
389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
390 callback_runner_
->PostTask(
392 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback
, this, id
,
393 update
, service_name
));
396 void ServiceDiscoveryHostClient::OnResolverCallback(
398 ServiceResolver::RequestStatus status
,
399 const ServiceDescription
& description
) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
401 callback_runner_
->PostTask(
403 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback
, this, id
,
404 status
, description
));
407 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
410 const net::IPAddressNumber
& ip_address_ipv4
,
411 const net::IPAddressNumber
& ip_address_ipv6
) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
413 callback_runner_
->PostTask(
415 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback
,
416 this, id
, success
, ip_address_ipv4
, ip_address_ipv6
));
419 void ServiceDiscoveryHostClient::RunWatcherCallback(
421 ServiceWatcher::UpdateType update
,
422 const std::string
& service_name
) {
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
424 WatcherCallbacks::iterator it
= service_watcher_callbacks_
.find(id
);
425 if (it
!= service_watcher_callbacks_
.end() && !it
->second
.is_null())
426 it
->second
.Run(update
, service_name
);
429 void ServiceDiscoveryHostClient::RunResolverCallback(
431 ServiceResolver::RequestStatus status
,
432 const ServiceDescription
& description
) {
433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
434 ResolverCallbacks::iterator it
= service_resolver_callbacks_
.find(id
);
435 if (it
!= service_resolver_callbacks_
.end() && !it
->second
.is_null())
436 it
->second
.Run(status
, description
);
439 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
442 const net::IPAddressNumber
& ip_address_ipv4
,
443 const net::IPAddressNumber
& ip_address_ipv6
) {
444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
445 DomainResolverCallbacks::iterator it
= domain_resolver_callbacks_
.find(id
);
446 if (it
!= domain_resolver_callbacks_
.end() && !it
->second
.is_null())
447 it
->second
.Run(success
, ip_address_ipv4
, ip_address_ipv6
);
450 } // namespace local_discovery