service_discovery_host_client.cc revision f2477e01787aa58f445919b809d89e252beef54f
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#include "net/socket/socket_descriptor.h" 11 12#if defined(OS_POSIX) 13#include "base/file_descriptor_posix.h" 14#endif // OS_POSIX 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 " << id_; 48 DCHECK(started_); 49 host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update)); 50 } 51 52 virtual std::string GetServiceType() const OVERRIDE { 53 return service_type_; 54 } 55 56 private: 57 scoped_refptr<ServiceDiscoveryHostClient> host_; 58 const std::string service_type_; 59 const uint64 id_; 60 bool started_; 61}; 62 63class ServiceDiscoveryHostClient::ServiceResolverProxy 64 : public ServiceResolver { 65 public: 66 ServiceResolverProxy(ServiceDiscoveryHostClient* host, 67 const std::string& service_name, 68 const ServiceResolver::ResolveCompleteCallback& callback) 69 : host_(host), 70 service_name_(service_name), 71 id_(host->RegisterResolverCallback(callback)), 72 started_(false) { 73 } 74 75 virtual ~ServiceResolverProxy() { 76 DVLOG(1) << "~ServiceResolverProxy with id " << id_; 77 host_->UnregisterResolverCallback(id_); 78 if (started_) 79 host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_)); 80 } 81 82 virtual void StartResolving() OVERRIDE { 83 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_; 84 DCHECK(!started_); 85 host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_)); 86 started_ = true; 87 } 88 89 virtual std::string GetName() const OVERRIDE { 90 return service_name_; 91 } 92 93 private: 94 scoped_refptr<ServiceDiscoveryHostClient> host_; 95 const std::string service_name_; 96 const uint64 id_; 97 bool started_; 98}; 99 100class ServiceDiscoveryHostClient::LocalDomainResolverProxy 101 : public LocalDomainResolver { 102 public: 103 LocalDomainResolverProxy(ServiceDiscoveryHostClient* host, 104 const std::string& domain, 105 net::AddressFamily address_family, 106 const LocalDomainResolver::IPAddressCallback& callback) 107 : host_(host), 108 domain_(domain), 109 address_family_(address_family), 110 id_(host->RegisterLocalDomainResolverCallback(callback)), 111 started_(false) { 112 } 113 114 virtual ~LocalDomainResolverProxy() { 115 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_; 116 host_->UnregisterLocalDomainResolverCallback(id_); 117 if (started_) 118 host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_)); 119 } 120 121 virtual void Start() OVERRIDE { 122 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_; 123 DCHECK(!started_); 124 host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_, 125 address_family_)); 126 started_ = true; 127 } 128 129 private: 130 scoped_refptr<ServiceDiscoveryHostClient> host_; 131 std::string domain_; 132 net::AddressFamily address_family_; 133 const uint64 id_; 134 bool started_; 135}; 136 137ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) { 138 callback_runner_ = base::MessageLoop::current()->message_loop_proxy(); 139 io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 140} 141 142ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() { 143 DCHECK(service_watcher_callbacks_.empty()); 144 DCHECK(service_resolver_callbacks_.empty()); 145 DCHECK(domain_resolver_callbacks_.empty()); 146} 147 148scoped_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)); 154} 155 156scoped_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)); 162} 163 164scoped_ptr<LocalDomainResolver> 165ServiceDiscoveryHostClient::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)); 172} 173 174uint64 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; 179 return current_id_; 180} 181 182uint64 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; 187 return current_id_; 188} 189 190uint64 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; 195 return current_id_; 196} 197 198void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) { 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 200 service_watcher_callbacks_.erase(id); 201} 202 203void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) { 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 205 service_resolver_callbacks_.erase(id); 206} 207 208void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback( 209 uint64 id) { 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 211 domain_resolver_callbacks_.erase(id); 212} 213 214void 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( 221 FROM_HERE, 222 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this)); 223} 224 225void ServiceDiscoveryHostClient::Shutdown() { 226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 227 io_runner_->PostTask( 228 FROM_HERE, 229 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this)); 230} 231 232void ServiceDiscoveryHostClient::StartOnIOThread() { 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 234 DCHECK(!utility_host_); 235 utility_host_ = UtilityProcessHost::Create( 236 this, base::MessageLoopProxy::current().get())->AsWeakPtr(); 237 if (utility_host_) { 238 utility_host_->EnableMDns(); 239 utility_host_->StartBatchMode(); 240 241#if defined(OS_POSIX) 242 base::FileDescriptor v4(net::CreatePlatformSocket(AF_INET, SOCK_DGRAM, 0), 243 true); 244 base::FileDescriptor v6(net::CreatePlatformSocket(AF_INET6, SOCK_DGRAM, 0), 245 true); 246 LOG_IF(ERROR, v4.fd == net::kInvalidSocket) << "Can't create IPv4 socket."; 247 LOG_IF(ERROR, v6.fd == net::kInvalidSocket) << "Can't create IPv6 socket."; 248 if (v4.fd == net::kInvalidSocket && 249 v6.fd == net::kInvalidSocket) { 250 ShutdownOnIOThread(); 251 } else { 252 utility_host_->Send(new LocalDiscoveryMsg_SetSockets(v4, v6)); 253 } 254#endif // OS_POSIX 255 } 256} 257 258void ServiceDiscoveryHostClient::ShutdownOnIOThread() { 259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 260 if (utility_host_) { 261 utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery); 262 utility_host_->EndBatchMode(); 263 utility_host_.reset(); 264 } 265 error_callback_ = base::Closure(); 266} 267 268void ServiceDiscoveryHostClient::Send(IPC::Message* msg) { 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 270 io_runner_->PostTask( 271 FROM_HERE, 272 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg)); 273} 274 275void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) { 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 277 if (utility_host_) { 278 utility_host_->Send(msg); 279 } else { 280 delete msg; 281 } 282} 283 284void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) { 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 286 DCHECK(!utility_host_); 287 OnError(); 288} 289 290bool ServiceDiscoveryHostClient::OnMessageReceived( 291 const IPC::Message& message) { 292 bool handled = true; 293 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message) 294 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError) 295 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback, 296 OnWatcherCallback) 297 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback, 298 OnResolverCallback) 299 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback, 300 OnLocalDomainResolverCallback) 301 IPC_MESSAGE_UNHANDLED(handled = false) 302 IPC_END_MESSAGE_MAP() 303 return handled; 304} 305 306void ServiceDiscoveryHostClient::InvalidateWatchers() { 307 WatcherCallbacks service_watcher_callbacks; 308 service_watcher_callbacks_.swap(service_watcher_callbacks); 309 service_resolver_callbacks_.clear(); 310 domain_resolver_callbacks_.clear(); 311 312 for (WatcherCallbacks::iterator i = service_watcher_callbacks.begin(); 313 i != service_watcher_callbacks.end(); i++) { 314 if (!i->second.is_null()) { 315 i->second.Run(ServiceWatcher::UPDATE_INVALIDATED, ""); 316 } 317 } 318} 319 320void ServiceDiscoveryHostClient::OnError() { 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 322 if (!error_callback_.is_null()) 323 callback_runner_->PostTask(FROM_HERE, error_callback_); 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(BrowserThread::CurrentlyOn(BrowserThread::UI)); 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(BrowserThread::CurrentlyOn(BrowserThread::UI)); 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(BrowserThread::CurrentlyOn(BrowserThread::UI)); 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 391} // namespace local_discovery 392