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 std::string
GetServiceType() const OVERRIDE
{
90 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
91 const std::string service_type_
;
96 class ServiceDiscoveryHostClient::ServiceResolverProxy
97 : public ServiceResolver
{
99 ServiceResolverProxy(ServiceDiscoveryHostClient
* host
,
100 const std::string
& service_name
,
101 const ServiceResolver::ResolveCompleteCallback
& callback
)
103 service_name_(service_name
),
104 id_(host
->RegisterResolverCallback(callback
)),
108 virtual ~ServiceResolverProxy() {
109 DVLOG(1) << "~ServiceResolverProxy with id " << id_
;
110 host_
->UnregisterResolverCallback(id_
);
112 host_
->Send(new LocalDiscoveryMsg_DestroyResolver(id_
));
115 virtual void StartResolving() OVERRIDE
{
116 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_
;
118 host_
->Send(new LocalDiscoveryMsg_ResolveService(id_
, service_name_
));
122 virtual std::string
GetName() const OVERRIDE
{
123 return service_name_
;
127 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
128 const std::string service_name_
;
133 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
134 : public LocalDomainResolver
{
136 LocalDomainResolverProxy(ServiceDiscoveryHostClient
* host
,
137 const std::string
& domain
,
138 net::AddressFamily address_family
,
139 const LocalDomainResolver::IPAddressCallback
& callback
)
142 address_family_(address_family
),
143 id_(host
->RegisterLocalDomainResolverCallback(callback
)),
147 virtual ~LocalDomainResolverProxy() {
148 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_
;
149 host_
->UnregisterLocalDomainResolverCallback(id_
);
151 host_
->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_
));
154 virtual void Start() OVERRIDE
{
155 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_
;
157 host_
->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_
, domain_
,
163 scoped_refptr
<ServiceDiscoveryHostClient
> host_
;
165 net::AddressFamily address_family_
;
170 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
171 callback_runner_
= base::MessageLoop::current()->message_loop_proxy();
172 io_runner_
= BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
175 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
176 DCHECK(service_watcher_callbacks_
.empty());
177 DCHECK(service_resolver_callbacks_
.empty());
178 DCHECK(domain_resolver_callbacks_
.empty());
181 scoped_ptr
<ServiceWatcher
> ServiceDiscoveryHostClient::CreateServiceWatcher(
182 const std::string
& service_type
,
183 const ServiceWatcher::UpdatedCallback
& callback
) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
185 return scoped_ptr
<ServiceWatcher
>(
186 new ServiceWatcherProxy(this, service_type
, callback
));
189 scoped_ptr
<ServiceResolver
> ServiceDiscoveryHostClient::CreateServiceResolver(
190 const std::string
& service_name
,
191 const ServiceResolver::ResolveCompleteCallback
& callback
) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
193 return scoped_ptr
<ServiceResolver
>(
194 new ServiceResolverProxy(this, service_name
, callback
));
197 scoped_ptr
<LocalDomainResolver
>
198 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
199 const std::string
& domain
,
200 net::AddressFamily address_family
,
201 const LocalDomainResolver::IPAddressCallback
& callback
) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
203 return scoped_ptr
<LocalDomainResolver
>(new LocalDomainResolverProxy(
204 this, domain
, address_family
, callback
));
207 uint64
ServiceDiscoveryHostClient::RegisterWatcherCallback(
208 const ServiceWatcher::UpdatedCallback
& callback
) {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
210 DCHECK(!ContainsKey(service_watcher_callbacks_
, current_id_
+ 1));
211 service_watcher_callbacks_
[++current_id_
] = callback
;
215 uint64
ServiceDiscoveryHostClient::RegisterResolverCallback(
216 const ServiceResolver::ResolveCompleteCallback
& callback
) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
218 DCHECK(!ContainsKey(service_resolver_callbacks_
, current_id_
+ 1));
219 service_resolver_callbacks_
[++current_id_
] = callback
;
223 uint64
ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
224 const LocalDomainResolver::IPAddressCallback
& callback
) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
226 DCHECK(!ContainsKey(domain_resolver_callbacks_
, current_id_
+ 1));
227 domain_resolver_callbacks_
[++current_id_
] = callback
;
231 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id
) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
233 service_watcher_callbacks_
.erase(id
);
236 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id
) {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
238 service_resolver_callbacks_
.erase(id
);
241 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
244 domain_resolver_callbacks_
.erase(id
);
247 void ServiceDiscoveryHostClient::Start(
248 const base::Closure
& error_callback
) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
250 DCHECK(!utility_host_
);
251 DCHECK(error_callback_
.is_null());
252 error_callback_
= error_callback
;
253 io_runner_
->PostTask(
255 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread
, this));
258 void ServiceDiscoveryHostClient::Shutdown() {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
260 io_runner_
->PostTask(
262 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread
, this));
265 #if defined(OS_POSIX)
267 void ServiceDiscoveryHostClient::StartOnIOThread() {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
269 DCHECK(!utility_host_
);
270 BrowserThread::PostTaskAndReplyWithResult(
273 base::Bind(&GetSocketsOnFileThread
),
274 base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady
, this));
277 void ServiceDiscoveryHostClient::OnSocketsReady(const SocketInfoList
& sockets
) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
279 DCHECK(!utility_host_
);
280 utility_host_
= UtilityProcessHost::Create(
281 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
284 utility_host_
->EnableMDns();
285 utility_host_
->StartBatchMode();
286 if (sockets
.empty()) {
287 ShutdownOnIOThread();
290 utility_host_
->Send(new LocalDiscoveryMsg_SetSockets(sockets
));
291 // Send messages for requests made during network enumeration.
292 for (size_t i
= 0; i
< delayed_messages_
.size(); ++i
)
293 utility_host_
->Send(delayed_messages_
[i
]);
294 delayed_messages_
.weak_clear();
299 void ServiceDiscoveryHostClient::StartOnIOThread() {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
301 DCHECK(!utility_host_
);
302 utility_host_
= UtilityProcessHost::Create(
303 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
306 utility_host_
->EnableMDns();
307 utility_host_
->StartBatchMode();
308 // Windows does not enumerate networks here.
309 DCHECK(delayed_messages_
.empty());
314 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
317 utility_host_
->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery
);
318 utility_host_
->EndBatchMode();
319 utility_host_
.reset();
321 error_callback_
= base::Closure();
324 void ServiceDiscoveryHostClient::Send(IPC::Message
* msg
) {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
326 io_runner_
->PostTask(
328 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread
, this, msg
));
331 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message
* msg
) {
332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
334 utility_host_
->Send(msg
);
336 delayed_messages_
.push_back(msg
);
340 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code
) {
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
342 DCHECK(!utility_host_
);
346 bool ServiceDiscoveryHostClient::OnMessageReceived(
347 const IPC::Message
& message
) {
349 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient
, message
)
350 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error
, OnError
)
351 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback
,
353 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback
,
355 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback
,
356 OnLocalDomainResolverCallback
)
357 IPC_MESSAGE_UNHANDLED(handled
= false)
358 IPC_END_MESSAGE_MAP()
362 void ServiceDiscoveryHostClient::InvalidateWatchers() {
363 WatcherCallbacks service_watcher_callbacks
;
364 service_watcher_callbacks_
.swap(service_watcher_callbacks
);
365 service_resolver_callbacks_
.clear();
366 domain_resolver_callbacks_
.clear();
368 for (WatcherCallbacks::iterator i
= service_watcher_callbacks
.begin();
369 i
!= service_watcher_callbacks
.end(); i
++) {
370 if (!i
->second
.is_null()) {
371 i
->second
.Run(ServiceWatcher::UPDATE_INVALIDATED
, "");
376 void ServiceDiscoveryHostClient::OnError() {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
378 if (!error_callback_
.is_null())
379 callback_runner_
->PostTask(FROM_HERE
, error_callback_
);
382 void ServiceDiscoveryHostClient::OnWatcherCallback(
384 ServiceWatcher::UpdateType update
,
385 const std::string
& service_name
) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
387 callback_runner_
->PostTask(
389 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback
, this, id
,
390 update
, service_name
));
393 void ServiceDiscoveryHostClient::OnResolverCallback(
395 ServiceResolver::RequestStatus status
,
396 const ServiceDescription
& description
) {
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
398 callback_runner_
->PostTask(
400 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback
, this, id
,
401 status
, description
));
404 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
407 const net::IPAddressNumber
& ip_address_ipv4
,
408 const net::IPAddressNumber
& ip_address_ipv6
) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
410 callback_runner_
->PostTask(
412 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback
,
413 this, id
, success
, ip_address_ipv4
, ip_address_ipv6
));
416 void ServiceDiscoveryHostClient::RunWatcherCallback(
418 ServiceWatcher::UpdateType update
,
419 const std::string
& service_name
) {
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
421 WatcherCallbacks::iterator it
= service_watcher_callbacks_
.find(id
);
422 if (it
!= service_watcher_callbacks_
.end() && !it
->second
.is_null())
423 it
->second
.Run(update
, service_name
);
426 void ServiceDiscoveryHostClient::RunResolverCallback(
428 ServiceResolver::RequestStatus status
,
429 const ServiceDescription
& description
) {
430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
431 ResolverCallbacks::iterator it
= service_resolver_callbacks_
.find(id
);
432 if (it
!= service_resolver_callbacks_
.end() && !it
->second
.is_null())
433 it
->second
.Run(status
, description
);
436 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
439 const net::IPAddressNumber
& ip_address_ipv4
,
440 const net::IPAddressNumber
& ip_address_ipv6
) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
442 DomainResolverCallbacks::iterator it
= domain_resolver_callbacks_
.find(id
);
443 if (it
!= domain_resolver_callbacks_
.end() && !it
->second
.is_null())
444 it
->second
.Run(success
, ip_address_ipv4
, ip_address_ipv6
);
447 } // namespace local_discovery