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