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