• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/local_discovery/service_discovery_host_client.h"
6 
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"
12 
13 #if defined(OS_POSIX)
14 #include <netinet/in.h>
15 #include "base/file_descriptor_posix.h"
16 #endif  // OS_POSIX
17 
18 namespace local_discovery {
19 
20 using content::BrowserThread;
21 using content::UtilityProcessHost;
22 
23 namespace {
24 
25 #if defined(OS_POSIX)
GetSocketsOnFileThread()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,
35                                       IPPROTO_UDP),
36         true);
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);
45     }
46   }
47 
48   return sockets;
49 }
50 #endif  // OS_POSIX
51 
52 }  // namespace
53 
54 class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
55  public:
ServiceWatcherProxy(ServiceDiscoveryHostClient * host,const std::string & service_type,const ServiceWatcher::UpdatedCallback & callback)56   ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
57                       const std::string& service_type,
58                       const ServiceWatcher::UpdatedCallback& callback)
59       : host_(host),
60         service_type_(service_type),
61         id_(host_->RegisterWatcherCallback(callback)),
62         started_(false) {
63   }
64 
~ServiceWatcherProxy()65   virtual ~ServiceWatcherProxy() {
66     DVLOG(1) << "~ServiceWatcherProxy with id " << id_;
67     host_->UnregisterWatcherCallback(id_);
68     if (started_)
69       host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
70   }
71 
Start()72   virtual void Start() OVERRIDE {
73     DVLOG(1) << "ServiceWatcher::Start with id " << id_;
74     DCHECK(!started_);
75     host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
76     started_ = true;
77   }
78 
DiscoverNewServices(bool force_update)79   virtual void DiscoverNewServices(bool force_update) OVERRIDE {
80     DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_;
81     DCHECK(started_);
82     host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
83   }
84 
SetActivelyRefreshServices(bool actively_refresh_services)85   virtual void SetActivelyRefreshServices(
86       bool actively_refresh_services) OVERRIDE {
87     DVLOG(1) << "ServiceWatcher::SetActivelyRefreshServices with id " << id_;
88     DCHECK(started_);
89     host_->Send(new LocalDiscoveryMsg_SetActivelyRefreshServices(
90         id_, actively_refresh_services));
91   }
92 
GetServiceType() const93   virtual std::string GetServiceType() const OVERRIDE {
94     return service_type_;
95   }
96 
97  private:
98   scoped_refptr<ServiceDiscoveryHostClient> host_;
99   const std::string service_type_;
100   const uint64 id_;
101   bool started_;
102 };
103 
104 class ServiceDiscoveryHostClient::ServiceResolverProxy
105     : public ServiceResolver {
106  public:
ServiceResolverProxy(ServiceDiscoveryHostClient * host,const std::string & service_name,const ServiceResolver::ResolveCompleteCallback & callback)107   ServiceResolverProxy(ServiceDiscoveryHostClient* host,
108                        const std::string& service_name,
109                        const ServiceResolver::ResolveCompleteCallback& callback)
110       : host_(host),
111         service_name_(service_name),
112         id_(host->RegisterResolverCallback(callback)),
113         started_(false) {
114   }
115 
~ServiceResolverProxy()116   virtual ~ServiceResolverProxy() {
117     DVLOG(1) << "~ServiceResolverProxy with id " << id_;
118     host_->UnregisterResolverCallback(id_);
119     if (started_)
120       host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
121   }
122 
StartResolving()123   virtual void StartResolving() OVERRIDE {
124     DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_;
125     DCHECK(!started_);
126     host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
127     started_ = true;
128   }
129 
GetName() const130   virtual std::string GetName() const OVERRIDE {
131     return service_name_;
132   }
133 
134  private:
135   scoped_refptr<ServiceDiscoveryHostClient> host_;
136   const std::string service_name_;
137   const uint64 id_;
138   bool started_;
139 };
140 
141 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
142     : public LocalDomainResolver {
143  public:
LocalDomainResolverProxy(ServiceDiscoveryHostClient * host,const std::string & domain,net::AddressFamily address_family,const LocalDomainResolver::IPAddressCallback & callback)144   LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
145                        const std::string& domain,
146                        net::AddressFamily address_family,
147                        const LocalDomainResolver::IPAddressCallback& callback)
148       : host_(host),
149         domain_(domain),
150         address_family_(address_family),
151         id_(host->RegisterLocalDomainResolverCallback(callback)),
152         started_(false) {
153   }
154 
~LocalDomainResolverProxy()155   virtual ~LocalDomainResolverProxy() {
156     DVLOG(1) << "~LocalDomainResolverProxy with id " << id_;
157     host_->UnregisterLocalDomainResolverCallback(id_);
158     if (started_)
159       host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
160   }
161 
Start()162   virtual void Start() OVERRIDE {
163     DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_;
164     DCHECK(!started_);
165     host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
166                                                          address_family_));
167     started_ = true;
168   }
169 
170  private:
171   scoped_refptr<ServiceDiscoveryHostClient> host_;
172   std::string domain_;
173   net::AddressFamily address_family_;
174   const uint64 id_;
175   bool started_;
176 };
177 
ServiceDiscoveryHostClient()178 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
179   callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
180   io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
181 }
182 
~ServiceDiscoveryHostClient()183 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
184   DCHECK(service_watcher_callbacks_.empty());
185   DCHECK(service_resolver_callbacks_.empty());
186   DCHECK(domain_resolver_callbacks_.empty());
187 }
188 
CreateServiceWatcher(const std::string & service_type,const ServiceWatcher::UpdatedCallback & callback)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));
195 }
196 
CreateServiceResolver(const std::string & service_name,const ServiceResolver::ResolveCompleteCallback & 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));
203 }
204 
205 scoped_ptr<LocalDomainResolver>
CreateLocalDomainResolver(const std::string & domain,net::AddressFamily address_family,const LocalDomainResolver::IPAddressCallback & callback)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));
213 }
214 
RegisterWatcherCallback(const ServiceWatcher::UpdatedCallback & 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;
220   return current_id_;
221 }
222 
RegisterResolverCallback(const ServiceResolver::ResolveCompleteCallback & 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;
228   return current_id_;
229 }
230 
RegisterLocalDomainResolverCallback(const LocalDomainResolver::IPAddressCallback & 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;
236   return current_id_;
237 }
238 
UnregisterWatcherCallback(uint64 id)239 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
241   service_watcher_callbacks_.erase(id);
242 }
243 
UnregisterResolverCallback(uint64 id)244 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
245   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
246   service_resolver_callbacks_.erase(id);
247 }
248 
UnregisterLocalDomainResolverCallback(uint64 id)249 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
250     uint64 id) {
251   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
252   domain_resolver_callbacks_.erase(id);
253 }
254 
Start(const base::Closure & error_callback)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(
262       FROM_HERE,
263       base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
264 }
265 
Shutdown()266 void ServiceDiscoveryHostClient::Shutdown() {
267   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
268   io_runner_->PostTask(
269       FROM_HERE,
270       base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
271 }
272 
273 #if defined(OS_POSIX)
274 
StartOnIOThread()275 void ServiceDiscoveryHostClient::StartOnIOThread() {
276   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
277   DCHECK(!utility_host_);
278   BrowserThread::PostTaskAndReplyWithResult(
279       BrowserThread::FILE,
280       FROM_HERE,
281       base::Bind(&GetSocketsOnFileThread),
282       base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady, this));
283 }
284 
OnSocketsReady(const SocketInfoList & sockets)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();
290   if (!utility_host_)
291     return;
292   utility_host_->EnableMDns();
293   utility_host_->StartBatchMode();
294   if (sockets.empty()) {
295     ShutdownOnIOThread();
296     return;
297   }
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();
303 }
304 
305 #else  // OS_POSIX
306 
StartOnIOThread()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();
312   if (!utility_host_)
313     return;
314   utility_host_->EnableMDns();
315   utility_host_->StartBatchMode();
316   // Windows does not enumerate networks here.
317   DCHECK(delayed_messages_.empty());
318 }
319 
320 #endif  // OS_POSIX
321 
ShutdownOnIOThread()322 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
323   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
324   if (utility_host_) {
325     utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
326     utility_host_->EndBatchMode();
327     utility_host_.reset();
328   }
329   error_callback_ = base::Closure();
330 }
331 
Send(IPC::Message * msg)332 void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
333   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
334   io_runner_->PostTask(
335       FROM_HERE,
336       base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg));
337 }
338 
SendOnIOThread(IPC::Message * msg)339 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) {
340   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
341   if (utility_host_) {
342     utility_host_->Send(msg);
343   } else {
344     delayed_messages_.push_back(msg);
345   }
346 }
347 
OnProcessCrashed(int exit_code)348 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) {
349   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
350   DCHECK(!utility_host_);
351   OnError();
352 }
353 
OnMessageReceived(const IPC::Message & message)354 bool ServiceDiscoveryHostClient::OnMessageReceived(
355     const IPC::Message& message) {
356   bool handled = true;
357   IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
358     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError)
359     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
360                         OnWatcherCallback)
361     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
362                         OnResolverCallback)
363     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback,
364                         OnLocalDomainResolverCallback)
365     IPC_MESSAGE_UNHANDLED(handled = false)
366   IPC_END_MESSAGE_MAP()
367   return handled;
368 }
369 
InvalidateWatchers()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();
375 
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, "");
380     }
381   }
382 }
383 
OnError()384 void ServiceDiscoveryHostClient::OnError() {
385   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
386   if (!error_callback_.is_null())
387     callback_runner_->PostTask(FROM_HERE, error_callback_);
388 }
389 
OnWatcherCallback(uint64 id,ServiceWatcher::UpdateType update,const std::string & service_name)390 void ServiceDiscoveryHostClient::OnWatcherCallback(
391     uint64 id,
392     ServiceWatcher::UpdateType update,
393     const std::string& service_name) {
394   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
395   callback_runner_->PostTask(
396       FROM_HERE,
397       base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
398                  update, service_name));
399 }
400 
OnResolverCallback(uint64 id,ServiceResolver::RequestStatus status,const ServiceDescription & description)401 void ServiceDiscoveryHostClient::OnResolverCallback(
402     uint64 id,
403     ServiceResolver::RequestStatus status,
404     const ServiceDescription& description) {
405   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
406   callback_runner_->PostTask(
407       FROM_HERE,
408       base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
409                  status, description));
410 }
411 
OnLocalDomainResolverCallback(uint64 id,bool success,const net::IPAddressNumber & ip_address_ipv4,const net::IPAddressNumber & ip_address_ipv6)412 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
413     uint64 id,
414     bool success,
415     const net::IPAddressNumber& ip_address_ipv4,
416     const net::IPAddressNumber& ip_address_ipv6) {
417   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
418   callback_runner_->PostTask(
419       FROM_HERE,
420       base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback,
421                  this, id, success, ip_address_ipv4, ip_address_ipv6));
422 }
423 
RunWatcherCallback(uint64 id,ServiceWatcher::UpdateType update,const std::string & service_name)424 void ServiceDiscoveryHostClient::RunWatcherCallback(
425     uint64 id,
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);
432 }
433 
RunResolverCallback(uint64 id,ServiceResolver::RequestStatus status,const ServiceDescription & description)434 void ServiceDiscoveryHostClient::RunResolverCallback(
435     uint64 id,
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);
442 }
443 
RunLocalDomainResolverCallback(uint64 id,bool success,const net::IPAddressNumber & ip_address_ipv4,const net::IPAddressNumber & ip_address_ipv6)444 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
445     uint64 id,
446     bool success,
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);
453 }
454 
455 }  // namespace local_discovery
456