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 virtual ~ServiceWatcherProxy() {
66 DVLOG(1) << "~ServiceWatcherProxy with id " << id_
;
67 host_
->UnregisterWatcherCallback(id_
);
69 host_
->Send(new LocalDiscoveryMsg_DestroyWatcher(id_
));
72 virtual void Start() OVERRIDE
{
73 DVLOG(1) << "ServiceWatcher::Start with id " << id_
;
75 host_
->Send(new LocalDiscoveryMsg_StartWatcher(id_
, service_type_
));
79 virtual void DiscoverNewServices(bool force_update
) OVERRIDE
{
80 DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_
;
82 host_
->Send(new LocalDiscoveryMsg_DiscoverServices(id_
, force_update
));
85 virtual void SetActivelyRefreshServices(
86 bool actively_refresh_services
) OVERRIDE
{
87 DVLOG(1) << "ServiceWatcher::SetActivelyRefreshServices with id " << id_
;
89 host_
->Send(new LocalDiscoveryMsg_SetActivelyRefreshServices(
90 id_
, actively_refresh_services
));
93 virtual std::string
GetServiceType() const OVERRIDE
{
98 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
99 const std::string service_type_
;
104 class ServiceDiscoveryHostClient::ServiceResolverProxy
105 : public ServiceResolver
{
107 ServiceResolverProxy(ServiceDiscoveryHostClient
* host
,
108 const std::string
& service_name
,
109 const ServiceResolver::ResolveCompleteCallback
& callback
)
111 service_name_(service_name
),
112 id_(host
->RegisterResolverCallback(callback
)),
116 virtual ~ServiceResolverProxy() {
117 DVLOG(1) << "~ServiceResolverProxy with id " << id_
;
118 host_
->UnregisterResolverCallback(id_
);
120 host_
->Send(new LocalDiscoveryMsg_DestroyResolver(id_
));
123 virtual void StartResolving() OVERRIDE
{
124 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_
;
126 host_
->Send(new LocalDiscoveryMsg_ResolveService(id_
, service_name_
));
130 virtual std::string
GetName() const OVERRIDE
{
131 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 virtual ~LocalDomainResolverProxy() {
156 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_
;
157 host_
->UnregisterLocalDomainResolverCallback(id_
);
159 host_
->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_
));
162 virtual 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()->message_loop_proxy();
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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI
));
241 service_watcher_callbacks_
.erase(id
);
244 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id
) {
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
246 service_resolver_callbacks_
.erase(id
);
249 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
252 domain_resolver_callbacks_
.erase(id
);
255 void ServiceDiscoveryHostClient::Start(
256 const base::Closure
& error_callback
) {
257 DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI
));
268 io_runner_
->PostTask(
270 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread
, this));
273 #if defined(OS_POSIX)
275 void ServiceDiscoveryHostClient::StartOnIOThread() {
276 DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::IO
));
287 DCHECK(!utility_host_
);
288 utility_host_
= UtilityProcessHost::Create(
289 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
292 utility_host_
->EnableMDns();
293 utility_host_
->StartBatchMode();
294 if (sockets
.empty()) {
295 ShutdownOnIOThread();
298 utility_host_
->Send(new LocalDiscoveryMsg_SetSockets(sockets
));
299 // Send messages for requests made during network enumeration.
300 for (size_t i
= 0; i
< delayed_messages_
.size(); ++i
)
301 utility_host_
->Send(delayed_messages_
[i
]);
302 delayed_messages_
.weak_clear();
307 void ServiceDiscoveryHostClient::StartOnIOThread() {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
309 DCHECK(!utility_host_
);
310 utility_host_
= UtilityProcessHost::Create(
311 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
314 utility_host_
->EnableMDns();
315 utility_host_
->StartBatchMode();
316 // Windows does not enumerate networks here.
317 DCHECK(delayed_messages_
.empty());
322 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
325 utility_host_
->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery
);
326 utility_host_
->EndBatchMode();
327 utility_host_
.reset();
329 error_callback_
= base::Closure();
332 void ServiceDiscoveryHostClient::Send(IPC::Message
* msg
) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
334 io_runner_
->PostTask(
336 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread
, this, msg
));
339 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message
* msg
) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
342 utility_host_
->Send(msg
);
344 delayed_messages_
.push_back(msg
);
348 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code
) {
349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
350 DCHECK(!utility_host_
);
354 bool ServiceDiscoveryHostClient::OnMessageReceived(
355 const IPC::Message
& message
) {
357 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient
, message
)
358 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error
, OnError
)
359 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback
,
361 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback
,
363 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback
,
364 OnLocalDomainResolverCallback
)
365 IPC_MESSAGE_UNHANDLED(handled
= false)
366 IPC_END_MESSAGE_MAP()
370 void ServiceDiscoveryHostClient::InvalidateWatchers() {
371 WatcherCallbacks service_watcher_callbacks
;
372 service_watcher_callbacks_
.swap(service_watcher_callbacks
);
373 service_resolver_callbacks_
.clear();
374 domain_resolver_callbacks_
.clear();
376 for (WatcherCallbacks::iterator i
= service_watcher_callbacks
.begin();
377 i
!= service_watcher_callbacks
.end(); i
++) {
378 if (!i
->second
.is_null()) {
379 i
->second
.Run(ServiceWatcher::UPDATE_INVALIDATED
, "");
384 void ServiceDiscoveryHostClient::OnError() {
385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
386 if (!error_callback_
.is_null())
387 callback_runner_
->PostTask(FROM_HERE
, error_callback_
);
390 void ServiceDiscoveryHostClient::OnWatcherCallback(
392 ServiceWatcher::UpdateType update
,
393 const std::string
& service_name
) {
394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
395 callback_runner_
->PostTask(
397 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback
, this, id
,
398 update
, service_name
));
401 void ServiceDiscoveryHostClient::OnResolverCallback(
403 ServiceResolver::RequestStatus status
,
404 const ServiceDescription
& description
) {
405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
406 callback_runner_
->PostTask(
408 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback
, this, id
,
409 status
, description
));
412 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
415 const net::IPAddressNumber
& ip_address_ipv4
,
416 const net::IPAddressNumber
& ip_address_ipv6
) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
418 callback_runner_
->PostTask(
420 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback
,
421 this, id
, success
, ip_address_ipv4
, ip_address_ipv6
));
424 void ServiceDiscoveryHostClient::RunWatcherCallback(
426 ServiceWatcher::UpdateType update
,
427 const std::string
& service_name
) {
428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
429 WatcherCallbacks::iterator it
= service_watcher_callbacks_
.find(id
);
430 if (it
!= service_watcher_callbacks_
.end() && !it
->second
.is_null())
431 it
->second
.Run(update
, service_name
);
434 void ServiceDiscoveryHostClient::RunResolverCallback(
436 ServiceResolver::RequestStatus status
,
437 const ServiceDescription
& description
) {
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
439 ResolverCallbacks::iterator it
= service_resolver_callbacks_
.find(id
);
440 if (it
!= service_resolver_callbacks_
.end() && !it
->second
.is_null())
441 it
->second
.Run(status
, description
);
444 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
447 const net::IPAddressNumber
& ip_address_ipv4
,
448 const net::IPAddressNumber
& ip_address_ipv6
) {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
450 DomainResolverCallbacks::iterator it
= domain_resolver_callbacks_
.find(id
);
451 if (it
!= domain_resolver_callbacks_
.end() && !it
->second
.is_null())
452 it
->second
.Run(success
, ip_address_ipv4
, ip_address_ipv6
);
455 } // namespace local_discovery