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/socket/socket_descriptor.h"
13 #include "base/file_descriptor_posix.h"
16 namespace local_discovery {
18 using content::BrowserThread;
19 using content::UtilityProcessHost;
21 class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
23 ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
24 const std::string& service_type,
25 const ServiceWatcher::UpdatedCallback& callback)
27 service_type_(service_type),
28 id_(host_->RegisterWatcherCallback(callback)),
32 virtual ~ServiceWatcherProxy() {
33 DVLOG(1) << "~ServiceWatcherProxy with id " << id_;
34 host_->UnregisterWatcherCallback(id_);
36 host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
39 virtual void Start() OVERRIDE {
40 DVLOG(1) << "ServiceWatcher::Start with id " << id_;
42 host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
46 virtual void DiscoverNewServices(bool force_update) OVERRIDE {
47 DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_;
49 host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
52 virtual std::string GetServiceType() const OVERRIDE {
57 scoped_refptr<ServiceDiscoveryHostClient> host_;
58 const std::string service_type_;
63 class ServiceDiscoveryHostClient::ServiceResolverProxy
64 : public ServiceResolver {
66 ServiceResolverProxy(ServiceDiscoveryHostClient* host,
67 const std::string& service_name,
68 const ServiceResolver::ResolveCompleteCallback& callback)
70 service_name_(service_name),
71 id_(host->RegisterResolverCallback(callback)),
75 virtual ~ServiceResolverProxy() {
76 DVLOG(1) << "~ServiceResolverProxy with id " << id_;
77 host_->UnregisterResolverCallback(id_);
79 host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
82 virtual void StartResolving() OVERRIDE {
83 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_;
85 host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
89 virtual std::string GetName() const OVERRIDE {
94 scoped_refptr<ServiceDiscoveryHostClient> host_;
95 const std::string service_name_;
100 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
101 : public LocalDomainResolver {
103 LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
104 const std::string& domain,
105 net::AddressFamily address_family,
106 const LocalDomainResolver::IPAddressCallback& callback)
109 address_family_(address_family),
110 id_(host->RegisterLocalDomainResolverCallback(callback)),
114 virtual ~LocalDomainResolverProxy() {
115 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_;
116 host_->UnregisterLocalDomainResolverCallback(id_);
118 host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
121 virtual void Start() OVERRIDE {
122 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_;
124 host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
130 scoped_refptr<ServiceDiscoveryHostClient> host_;
132 net::AddressFamily address_family_;
137 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
138 callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
139 io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
142 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
143 DCHECK(service_watcher_callbacks_.empty());
144 DCHECK(service_resolver_callbacks_.empty());
145 DCHECK(domain_resolver_callbacks_.empty());
148 scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
149 const std::string& service_type,
150 const ServiceWatcher::UpdatedCallback& callback) {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152 return scoped_ptr<ServiceWatcher>(
153 new ServiceWatcherProxy(this, service_type, callback));
156 scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
157 const std::string& service_name,
158 const ServiceResolver::ResolveCompleteCallback& callback) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 return scoped_ptr<ServiceResolver>(
161 new ServiceResolverProxy(this, service_name, callback));
164 scoped_ptr<LocalDomainResolver>
165 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
166 const std::string& domain,
167 net::AddressFamily address_family,
168 const LocalDomainResolver::IPAddressCallback& callback) {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170 return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy(
171 this, domain, address_family, callback));
174 uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
175 const ServiceWatcher::UpdatedCallback& callback) {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177 DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
178 service_watcher_callbacks_[++current_id_] = callback;
182 uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
183 const ServiceResolver::ResolveCompleteCallback& callback) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185 DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
186 service_resolver_callbacks_[++current_id_] = callback;
190 uint64 ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
191 const LocalDomainResolver::IPAddressCallback& callback) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 DCHECK(!ContainsKey(domain_resolver_callbacks_, current_id_ + 1));
194 domain_resolver_callbacks_[++current_id_] = callback;
198 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
200 service_watcher_callbacks_.erase(id);
203 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205 service_resolver_callbacks_.erase(id);
208 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 domain_resolver_callbacks_.erase(id);
214 void ServiceDiscoveryHostClient::Start(
215 const base::Closure& error_callback) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217 DCHECK(!utility_host_);
218 DCHECK(error_callback_.is_null());
219 error_callback_ = error_callback;
220 io_runner_->PostTask(
222 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
225 void ServiceDiscoveryHostClient::Shutdown() {
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227 io_runner_->PostTask(
229 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
232 void ServiceDiscoveryHostClient::StartOnIOThread() {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
234 DCHECK(!utility_host_);
235 utility_host_ = UtilityProcessHost::Create(
236 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
238 utility_host_->EnableZygote();
239 utility_host_->EnableMDns();
240 utility_host_->StartBatchMode();
242 #if defined(OS_POSIX)
243 base::FileDescriptor v4(net::CreatePlatformSocket(AF_INET, SOCK_DGRAM, 0),
245 base::FileDescriptor v6(net::CreatePlatformSocket(AF_INET6, SOCK_DGRAM, 0),
247 LOG_IF(ERROR, v4.fd == net::kInvalidSocket) << "Can't create IPv4 socket.";
248 LOG_IF(ERROR, v6.fd == net::kInvalidSocket) << "Can't create IPv6 socket.";
249 if (v4.fd == net::kInvalidSocket &&
250 v6.fd == net::kInvalidSocket) {
251 ShutdownOnIOThread();
253 utility_host_->Send(new LocalDiscoveryMsg_SetSockets(v4, v6));
259 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
262 utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
263 utility_host_->EndBatchMode();
264 utility_host_.reset();
266 error_callback_ = base::Closure();
269 void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 io_runner_->PostTask(
273 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg));
276 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
279 utility_host_->Send(msg);
285 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
287 DCHECK(!utility_host_);
291 bool ServiceDiscoveryHostClient::OnMessageReceived(
292 const IPC::Message& message) {
294 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
295 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError)
296 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
298 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
300 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback,
301 OnLocalDomainResolverCallback)
302 IPC_MESSAGE_UNHANDLED(handled = false)
303 IPC_END_MESSAGE_MAP()
307 void ServiceDiscoveryHostClient::InvalidateWatchers() {
308 WatcherCallbacks service_watcher_callbacks;
309 service_watcher_callbacks_.swap(service_watcher_callbacks);
310 service_resolver_callbacks_.clear();
311 domain_resolver_callbacks_.clear();
313 for (WatcherCallbacks::iterator i = service_watcher_callbacks.begin();
314 i != service_watcher_callbacks.end(); i++) {
315 if (!i->second.is_null()) {
316 i->second.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
321 void ServiceDiscoveryHostClient::OnError() {
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
323 if (!error_callback_.is_null())
324 callback_runner_->PostTask(FROM_HERE, error_callback_);
327 void ServiceDiscoveryHostClient::OnWatcherCallback(
329 ServiceWatcher::UpdateType update,
330 const std::string& service_name) {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
332 callback_runner_->PostTask(
334 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
335 update, service_name));
338 void ServiceDiscoveryHostClient::OnResolverCallback(
340 ServiceResolver::RequestStatus status,
341 const ServiceDescription& description) {
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
343 callback_runner_->PostTask(
345 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
346 status, description));
349 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
352 const net::IPAddressNumber& ip_address_ipv4,
353 const net::IPAddressNumber& ip_address_ipv6) {
354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
355 callback_runner_->PostTask(
357 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback,
358 this, id, success, ip_address_ipv4, ip_address_ipv6));
361 void ServiceDiscoveryHostClient::RunWatcherCallback(
363 ServiceWatcher::UpdateType update,
364 const std::string& service_name) {
365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
366 WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
367 if (it != service_watcher_callbacks_.end() && !it->second.is_null())
368 it->second.Run(update, service_name);
371 void ServiceDiscoveryHostClient::RunResolverCallback(
373 ServiceResolver::RequestStatus status,
374 const ServiceDescription& description) {
375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376 ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
377 if (it != service_resolver_callbacks_.end() && !it->second.is_null())
378 it->second.Run(status, description);
381 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
384 const net::IPAddressNumber& ip_address_ipv4,
385 const net::IPAddressNumber& ip_address_ipv6) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
387 DomainResolverCallbacks::iterator it = domain_resolver_callbacks_.find(id);
388 if (it != domain_resolver_callbacks_.end() && !it->second.is_null())
389 it->second.Run(success, ip_address_ipv4, ip_address_ipv6);
392 } // namespace local_discovery