service_discovery_host_client.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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
11namespace local_discovery {
12
13using content::BrowserThread;
14using content::UtilityProcessHost;
15
16class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
17 public:
18  ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
19                      const std::string& service_type,
20                      const ServiceWatcher::UpdatedCallback& callback)
21      : host_(host),
22        service_type_(service_type),
23        id_(host_->RegisterWatcherCallback(callback)),
24        started_(false) {
25  }
26
27  virtual ~ServiceWatcherProxy() {
28    host_->UnregisterWatcherCallback(id_);
29    if (started_)
30      host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
31  }
32
33  virtual void Start() OVERRIDE {
34    DCHECK(!started_);
35    host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
36    started_ = true;
37  }
38
39  virtual void DiscoverNewServices(bool force_update) OVERRIDE {
40    DCHECK(started_);
41    host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
42  }
43
44  virtual std::string GetServiceType() const OVERRIDE {
45    return service_type_;
46  }
47
48 private:
49  scoped_refptr<ServiceDiscoveryHostClient> host_;
50  const std::string service_type_;
51  const uint64 id_;
52  bool started_;
53};
54
55class ServiceDiscoveryHostClient::ServiceResolverProxy
56    : public ServiceResolver {
57 public:
58  ServiceResolverProxy(ServiceDiscoveryHostClient* host,
59                       const std::string& service_name,
60                       const ServiceResolver::ResolveCompleteCallback& callback)
61      : host_(host),
62        service_name_(service_name),
63        id_(host->RegisterResolverCallback(callback)),
64        started_(false) {
65  }
66
67  virtual ~ServiceResolverProxy() {
68    host_->UnregisterResolverCallback(id_);
69    if (started_)
70      host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
71  }
72
73  virtual void StartResolving() OVERRIDE {
74    DCHECK(!started_);
75    host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
76    started_ = true;
77  }
78
79  virtual std::string GetName() const OVERRIDE {
80    return service_name_;
81  }
82
83 private:
84  scoped_refptr<ServiceDiscoveryHostClient> host_;
85  const std::string service_name_;
86  const uint64 id_;
87  bool started_;
88};
89
90class ServiceDiscoveryHostClient::LocalDomainResolverProxy
91    : public LocalDomainResolver {
92 public:
93  LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
94                       const std::string& domain,
95                       net::AddressFamily address_family,
96                       const LocalDomainResolver::IPAddressCallback& callback)
97      : host_(host),
98        domain_(domain),
99        address_family_(address_family),
100        id_(host->RegisterLocalDomainResolverCallback(callback)),
101        started_(false) {
102  }
103
104  virtual ~LocalDomainResolverProxy() {
105    host_->UnregisterLocalDomainResolverCallback(id_);
106    if (started_)
107      host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
108  }
109
110  virtual void Start() OVERRIDE {
111    DCHECK(!started_);
112    host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
113                                                         address_family_));
114    started_ = true;
115  }
116
117 private:
118  scoped_refptr<ServiceDiscoveryHostClient> host_;
119  std::string domain_;
120  net::AddressFamily address_family_;
121  const uint64 id_;
122  bool started_;
123};
124
125ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
126  callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
127}
128
129ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
130  // The ServiceDiscoveryHostClient may be destroyed from the IO thread or the
131  // owning thread.
132  DetachFromThread();
133  DCHECK(service_watcher_callbacks_.empty());
134  DCHECK(service_resolver_callbacks_.empty());
135  DCHECK(domain_resolver_callbacks_.empty());
136}
137
138scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
139    const std::string& service_type,
140    const ServiceWatcher::UpdatedCallback& callback) {
141  DCHECK(CalledOnValidThread());
142  return scoped_ptr<ServiceWatcher>(
143      new ServiceWatcherProxy(this, service_type, callback));
144}
145
146scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
147    const std::string& service_name,
148    const ServiceResolver::ResolveCompleteCallback& callback) {
149  DCHECK(CalledOnValidThread());
150  return scoped_ptr<ServiceResolver>(
151      new ServiceResolverProxy(this, service_name, callback));
152}
153
154scoped_ptr<LocalDomainResolver>
155ServiceDiscoveryHostClient::CreateLocalDomainResolver(
156    const std::string& domain,
157    net::AddressFamily address_family,
158    const LocalDomainResolver::IPAddressCallback& callback) {
159  DCHECK(CalledOnValidThread());
160  return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy(
161      this, domain, address_family, callback));
162}
163
164uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
165    const ServiceWatcher::UpdatedCallback& callback) {
166  DCHECK(CalledOnValidThread());
167  DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
168  service_watcher_callbacks_[++current_id_] = callback;
169  return current_id_;
170}
171
172uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
173    const ServiceResolver::ResolveCompleteCallback& callback) {
174  DCHECK(CalledOnValidThread());
175  DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
176  service_resolver_callbacks_[++current_id_] = callback;
177  return current_id_;
178}
179
180uint64 ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
181    const LocalDomainResolver::IPAddressCallback& callback) {
182  DCHECK(CalledOnValidThread());
183  DCHECK(!ContainsKey(domain_resolver_callbacks_, current_id_ + 1));
184  domain_resolver_callbacks_[++current_id_] = callback;
185  return current_id_;
186}
187
188void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
189  DCHECK(CalledOnValidThread());
190  DCHECK(ContainsKey(service_watcher_callbacks_, id));
191  service_watcher_callbacks_.erase(id);
192}
193
194void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
195  DCHECK(CalledOnValidThread());
196  DCHECK(ContainsKey(service_resolver_callbacks_, id));
197  service_resolver_callbacks_.erase(id);
198}
199
200void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
201    uint64 id) {
202  DCHECK(CalledOnValidThread());
203  DCHECK(ContainsKey(domain_resolver_callbacks_, id));
204  domain_resolver_callbacks_.erase(id);
205}
206
207void ServiceDiscoveryHostClient::Start() {
208  DCHECK(CalledOnValidThread());
209  BrowserThread::PostTask(
210      BrowserThread::IO,
211      FROM_HERE,
212      base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
213}
214
215void ServiceDiscoveryHostClient::Shutdown() {
216  DCHECK(CalledOnValidThread());
217  BrowserThread::PostTask(
218      BrowserThread::IO,
219      FROM_HERE,
220      base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
221}
222
223void ServiceDiscoveryHostClient::StartOnIOThread() {
224  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
225  utility_host_ = UtilityProcessHost::Create(
226      this, base::MessageLoopProxy::current().get())->AsWeakPtr();
227  if (utility_host_) {
228    utility_host_->EnableZygote();
229    utility_host_->EnableMDns();
230    utility_host_->StartBatchMode();
231  }
232}
233
234void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
235  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
236  if (utility_host_) {
237    utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
238    utility_host_->EndBatchMode();
239  }
240}
241
242void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
243  DCHECK(CalledOnValidThread());
244  BrowserThread::PostTask(
245      BrowserThread::IO,
246      FROM_HERE,
247      base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg));
248}
249
250void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) {
251  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
252  if (utility_host_)
253    utility_host_->Send(msg);
254}
255
256bool ServiceDiscoveryHostClient::OnMessageReceived(
257    const IPC::Message& message) {
258  bool handled = true;
259  IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
260    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
261                        OnWatcherCallback)
262    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
263                        OnResolverCallback)
264    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback,
265                        OnLocalDomainResolverCallback)
266    IPC_MESSAGE_UNHANDLED(handled = false)
267  IPC_END_MESSAGE_MAP()
268  return handled;
269}
270
271void ServiceDiscoveryHostClient::OnWatcherCallback(
272    uint64 id,
273    ServiceWatcher::UpdateType update,
274    const std::string& service_name) {
275  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276  callback_runner_->PostTask(
277      FROM_HERE,
278      base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
279                 update, service_name));
280}
281
282void ServiceDiscoveryHostClient::OnResolverCallback(
283    uint64 id,
284    ServiceResolver::RequestStatus status,
285    const ServiceDescription& description) {
286  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
287  callback_runner_->PostTask(
288      FROM_HERE,
289      base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
290                 status, description));
291}
292
293void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
294    uint64 id,
295    bool success,
296    const net::IPAddressNumber& ip_address_ipv4,
297    const net::IPAddressNumber& ip_address_ipv6) {
298  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
299  callback_runner_->PostTask(
300      FROM_HERE,
301      base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback,
302                 this, id, success, ip_address_ipv4, ip_address_ipv6));
303}
304
305void ServiceDiscoveryHostClient::RunWatcherCallback(
306    uint64 id,
307    ServiceWatcher::UpdateType update,
308    const std::string& service_name) {
309  DCHECK(CalledOnValidThread());
310  WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
311  if (it != service_watcher_callbacks_.end() && !it->second.is_null())
312    it->second.Run(update, service_name);
313}
314
315void ServiceDiscoveryHostClient::RunResolverCallback(
316    uint64 id,
317    ServiceResolver::RequestStatus status,
318    const ServiceDescription& description) {
319  DCHECK(CalledOnValidThread());
320  ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
321  if (it != service_resolver_callbacks_.end() && !it->second.is_null())
322    it->second.Run(status, description);
323}
324
325void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
326    uint64 id,
327    bool success,
328    const net::IPAddressNumber& ip_address_ipv4,
329    const net::IPAddressNumber& ip_address_ipv6) {
330  DCHECK(CalledOnValidThread());
331  DomainResolverCallbacks::iterator it = domain_resolver_callbacks_.find(id);
332  if (it != domain_resolver_callbacks_.end() && !it->second.is_null())
333    it->second.Run(success, ip_address_ipv4, ip_address_ipv6);
334}
335
336ServiceDiscoveryHostClientFactory::ServiceDiscoveryHostClientFactory()
337    : instance_(NULL), references_(0) {
338}
339
340ServiceDiscoveryHostClientFactory::~ServiceDiscoveryHostClientFactory() {
341}
342
343// static
344ServiceDiscoveryHostClient* ServiceDiscoveryHostClientFactory::GetClient() {
345  return GetInstance()->GetClientInternal();
346}
347
348// static
349void ServiceDiscoveryHostClientFactory::ReleaseClient() {
350  GetInstance()->ReleaseClientInternal();
351}
352
353// static
354ServiceDiscoveryHostClientFactory*
355ServiceDiscoveryHostClientFactory::GetInstance() {
356  return Singleton<ServiceDiscoveryHostClientFactory>::get();
357}
358
359ServiceDiscoveryHostClient*
360ServiceDiscoveryHostClientFactory::GetClientInternal() {
361  DCHECK(CalledOnValidThread());
362  if (references_ == 0) {
363    instance_ = new ServiceDiscoveryHostClient;
364    instance_->Start();
365  }
366
367  references_++;
368  return instance_.get();
369}
370
371void ServiceDiscoveryHostClientFactory::ReleaseClientInternal() {
372  DCHECK(CalledOnValidThread());
373  references_--;
374  if (references_ == 0) {
375    instance_->Shutdown();
376    instance_ = NULL;
377  }
378}
379
380}  // namespace local_discovery
381