service_discovery_host_client.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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
90ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
91  callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
92}
93
94ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
95  DCHECK(CalledOnValidThread());
96  DCHECK(service_watcher_callbacks_.empty());
97  DCHECK(service_resolver_callbacks_.empty());
98}
99
100scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
101    const std::string& service_type,
102    const ServiceWatcher::UpdatedCallback& callback) {
103  DCHECK(CalledOnValidThread());
104  return scoped_ptr<ServiceWatcher>(
105      new ServiceWatcherProxy(this, service_type, callback));
106}
107
108scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
109    const std::string& service_name,
110    const ServiceResolver::ResolveCompleteCallback& callback) {
111  DCHECK(CalledOnValidThread());
112  return scoped_ptr<ServiceResolver>(
113      new ServiceResolverProxy(this, service_name, callback));
114}
115
116uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
117    const ServiceWatcher::UpdatedCallback& callback) {
118  DCHECK(CalledOnValidThread());
119  DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
120  service_watcher_callbacks_[++current_id_] = callback;
121  return current_id_;
122}
123
124uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
125    const ServiceResolver::ResolveCompleteCallback& callback) {
126  DCHECK(CalledOnValidThread());
127  DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
128  service_resolver_callbacks_[++current_id_] = callback;
129  return current_id_;
130}
131
132void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
133  DCHECK(CalledOnValidThread());
134  DCHECK(ContainsKey(service_watcher_callbacks_, id));
135  service_watcher_callbacks_.erase(id);
136}
137
138void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
139  DCHECK(CalledOnValidThread());
140  DCHECK(ContainsKey(service_resolver_callbacks_, id));
141  service_resolver_callbacks_.erase(id);
142}
143
144void ServiceDiscoveryHostClient::Start() {
145  DCHECK(CalledOnValidThread());
146  BrowserThread::PostTask(
147      BrowserThread::IO,
148      FROM_HERE,
149      base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
150}
151
152void ServiceDiscoveryHostClient::Shutdown() {
153  DCHECK(CalledOnValidThread());
154  BrowserThread::PostTask(
155      BrowserThread::IO,
156      FROM_HERE,
157      base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
158}
159
160void ServiceDiscoveryHostClient::StartOnIOThread() {
161  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
162  utility_host_ = UtilityProcessHost::Create(
163      this, base::MessageLoopProxy::current().get())->AsWeakPtr();
164  if (utility_host_) {
165    utility_host_->EnableZygote();
166    utility_host_->EnableMDns();
167    utility_host_->StartBatchMode();
168  }
169}
170
171void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
172  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
173  if (utility_host_)
174    utility_host_->EndBatchMode();
175}
176
177void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
178  DCHECK(CalledOnValidThread());
179  BrowserThread::PostTask(
180      BrowserThread::IO,
181      FROM_HERE,
182      base::Bind(base::IgnoreResult(&content::UtilityProcessHost::Send),
183                 utility_host_, msg));
184}
185
186bool ServiceDiscoveryHostClient::OnMessageReceived(
187    const IPC::Message& message) {
188  bool handled = true;
189  IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
190    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
191                        OnWatcherCallback)
192    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
193                        OnResolverCallback)
194    IPC_MESSAGE_UNHANDLED(handled = false)
195  IPC_END_MESSAGE_MAP()
196  return handled;
197}
198
199void ServiceDiscoveryHostClient::OnWatcherCallback(
200    uint64 id,
201    ServiceWatcher::UpdateType update,
202    const std::string& service_name) {
203  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
204  callback_runner_->PostTask(
205      FROM_HERE,
206      base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
207                 update, service_name));
208}
209
210void ServiceDiscoveryHostClient::OnResolverCallback(
211    uint64 id,
212    ServiceResolver::RequestStatus status,
213    const ServiceDescription& description) {
214  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
215  callback_runner_->PostTask(
216      FROM_HERE,
217      base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
218                 status, description));
219}
220
221void ServiceDiscoveryHostClient::RunWatcherCallback(
222    uint64 id,
223    ServiceWatcher::UpdateType update,
224    const std::string& service_name) {
225  DCHECK(CalledOnValidThread());
226  WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
227  if (it != service_watcher_callbacks_.end() && !it->second.is_null())
228    it->second.Run(update, service_name);
229}
230
231void ServiceDiscoveryHostClient::RunResolverCallback(
232    uint64 id,
233    ServiceResolver::RequestStatus status,
234    const ServiceDescription& description) {
235  DCHECK(CalledOnValidThread());
236  ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
237  if (it != service_resolver_callbacks_.end() && !it->second.is_null())
238    it->second.Run(status, description);
239}
240
241}  // namespace local_discovery
242