Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / local_discovery / service_discovery_client_mdns.cc
blob9162d2163099e00e3ac17da7435f21efde650e0c
1 // Copyright 2014 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_client_mdns.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/metrics/histogram.h"
9 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "net/dns/mdns_client.h"
12 #include "net/udp/datagram_server_socket.h"
14 namespace local_discovery {
16 using content::BrowserThread;
18 // Base class for objects returned by ServiceDiscoveryClient implementation.
19 // Handles interaction of client code on UI thread end net code on mdns thread.
20 class ServiceDiscoveryClientMdns::Proxy {
21 public:
22 typedef base::WeakPtr<Proxy> WeakPtr;
24 explicit Proxy(ServiceDiscoveryClientMdns* client)
25 : client_(client),
26 weak_ptr_factory_(this) {
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28 client_->proxies_.insert(this);
31 virtual ~Proxy() {
32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33 client_->proxies_.erase(this);
36 // Notify proxies that mDNS layer is going to be destroyed.
37 virtual void OnMdnsDestroy() = 0;
39 // Notify proxies that new mDNS instance is ready.
40 virtual void OnNewMdnsReady() {}
42 // Run callback using this method to abort callback if instance of |Proxy|
43 // is deleted.
44 void RunCallback(const base::Closure& callback) {
45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
46 callback.Run();
49 protected:
50 bool PostToMdnsThread(const base::Closure& task) {
51 return client_->PostToMdnsThread(task);
54 static bool PostToUIThread(const base::Closure& task) {
55 return BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
58 ServiceDiscoveryClient* client() {
59 return client_->client_.get();
62 WeakPtr GetWeakPtr() {
63 return weak_ptr_factory_.GetWeakPtr();
66 template<class T>
67 void DeleteOnMdnsThread(T* t) {
68 if (!t)
69 return;
70 if (!client_->mdns_runner_->DeleteSoon(FROM_HERE, t))
71 delete t;
74 private:
75 scoped_refptr<ServiceDiscoveryClientMdns> client_;
76 base::WeakPtrFactory<Proxy> weak_ptr_factory_;
78 DISALLOW_COPY_AND_ASSIGN(Proxy);
81 namespace {
83 const int kMaxRestartAttempts = 10;
84 const int kRestartDelayOnNetworkChangeSeconds = 3;
86 typedef base::Callback<void(bool)> MdnsInitCallback;
88 class SocketFactory : public net::MDnsSocketFactory {
89 public:
90 explicit SocketFactory(const net::InterfaceIndexFamilyList& interfaces)
91 : interfaces_(interfaces) {}
93 // net::MDnsSocketFactory implementation:
94 virtual void CreateSockets(
95 ScopedVector<net::DatagramServerSocket>* sockets) OVERRIDE {
96 for (size_t i = 0; i < interfaces_.size(); ++i) {
97 DCHECK(interfaces_[i].second == net::ADDRESS_FAMILY_IPV4 ||
98 interfaces_[i].second == net::ADDRESS_FAMILY_IPV6);
99 scoped_ptr<net::DatagramServerSocket> socket(
100 CreateAndBindMDnsSocket(interfaces_[i].second, interfaces_[i].first));
101 if (socket)
102 sockets->push_back(socket.release());
106 private:
107 net::InterfaceIndexFamilyList interfaces_;
110 void InitMdns(const MdnsInitCallback& on_initialized,
111 const net::InterfaceIndexFamilyList& interfaces,
112 net::MDnsClient* mdns) {
113 SocketFactory socket_factory(interfaces);
114 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
115 base::Bind(on_initialized,
116 mdns->StartListening(&socket_factory)));
119 template<class T>
120 class ProxyBase : public ServiceDiscoveryClientMdns::Proxy, public T {
121 public:
122 typedef base::WeakPtr<Proxy> WeakPtr;
123 typedef ProxyBase<T> Base;
125 explicit ProxyBase(ServiceDiscoveryClientMdns* client)
126 : Proxy(client) {
129 virtual ~ProxyBase() {
130 DeleteOnMdnsThread(implementation_.release());
133 virtual void OnMdnsDestroy() OVERRIDE {
134 DeleteOnMdnsThread(implementation_.release());
137 protected:
138 void set_implementation(scoped_ptr<T> implementation) {
139 implementation_ = implementation.Pass();
142 T* implementation() const {
143 return implementation_.get();
146 private:
147 scoped_ptr<T> implementation_;
148 DISALLOW_COPY_AND_ASSIGN(ProxyBase);
151 class ServiceWatcherProxy : public ProxyBase<ServiceWatcher> {
152 public:
153 ServiceWatcherProxy(ServiceDiscoveryClientMdns* client_mdns,
154 const std::string& service_type,
155 const ServiceWatcher::UpdatedCallback& callback)
156 : ProxyBase(client_mdns),
157 service_type_(service_type),
158 callback_(callback) {
159 // It's safe to call |CreateServiceWatcher| on UI thread, because
160 // |MDnsClient| is not used there. It's simplify implementation.
161 set_implementation(client()->CreateServiceWatcher(
162 service_type,
163 base::Bind(&ServiceWatcherProxy::OnCallback, GetWeakPtr(), callback)));
166 // ServiceWatcher methods.
167 virtual void Start() OVERRIDE {
168 if (implementation())
169 PostToMdnsThread(base::Bind(&ServiceWatcher::Start,
170 base::Unretained(implementation())));
173 virtual void DiscoverNewServices(bool force_update) OVERRIDE {
174 if (implementation())
175 PostToMdnsThread(base::Bind(&ServiceWatcher::DiscoverNewServices,
176 base::Unretained(implementation()),
177 force_update));
180 virtual void SetActivelyRefreshServices(
181 bool actively_refresh_services) OVERRIDE {
182 if (implementation())
183 PostToMdnsThread(base::Bind(&ServiceWatcher::SetActivelyRefreshServices,
184 base::Unretained(implementation()),
185 actively_refresh_services));
188 virtual std::string GetServiceType() const OVERRIDE {
189 return service_type_;
192 virtual void OnNewMdnsReady() OVERRIDE {
193 if (!implementation())
194 callback_.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
197 private:
198 static void OnCallback(const WeakPtr& proxy,
199 const ServiceWatcher::UpdatedCallback& callback,
200 UpdateType a1,
201 const std::string& a2) {
202 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
203 PostToUIThread(base::Bind(&Base::RunCallback, proxy,
204 base::Bind(callback, a1, a2)));
206 std::string service_type_;
207 ServiceWatcher::UpdatedCallback callback_;
208 DISALLOW_COPY_AND_ASSIGN(ServiceWatcherProxy);
211 class ServiceResolverProxy : public ProxyBase<ServiceResolver> {
212 public:
213 ServiceResolverProxy(ServiceDiscoveryClientMdns* client_mdns,
214 const std::string& service_name,
215 const ServiceResolver::ResolveCompleteCallback& callback)
216 : ProxyBase(client_mdns),
217 service_name_(service_name) {
218 // It's safe to call |CreateServiceResolver| on UI thread, because
219 // |MDnsClient| is not used there. It's simplify implementation.
220 set_implementation(client()->CreateServiceResolver(
221 service_name,
222 base::Bind(&ServiceResolverProxy::OnCallback, GetWeakPtr(), callback)));
225 // ServiceResolver methods.
226 virtual void StartResolving() OVERRIDE {
227 if (implementation())
228 PostToMdnsThread(base::Bind(&ServiceResolver::StartResolving,
229 base::Unretained(implementation())));
232 virtual std::string GetName() const OVERRIDE {
233 return service_name_;
236 private:
237 static void OnCallback(
238 const WeakPtr& proxy,
239 const ServiceResolver::ResolveCompleteCallback& callback,
240 RequestStatus a1,
241 const ServiceDescription& a2) {
242 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
243 PostToUIThread(base::Bind(&Base::RunCallback, proxy,
244 base::Bind(callback, a1, a2)));
247 std::string service_name_;
248 DISALLOW_COPY_AND_ASSIGN(ServiceResolverProxy);
251 class LocalDomainResolverProxy : public ProxyBase<LocalDomainResolver> {
252 public:
253 LocalDomainResolverProxy(
254 ServiceDiscoveryClientMdns* client_mdns,
255 const std::string& domain,
256 net::AddressFamily address_family,
257 const LocalDomainResolver::IPAddressCallback& callback)
258 : ProxyBase(client_mdns) {
259 // It's safe to call |CreateLocalDomainResolver| on UI thread, because
260 // |MDnsClient| is not used there. It's simplify implementation.
261 set_implementation(client()->CreateLocalDomainResolver(
262 domain,
263 address_family,
264 base::Bind(
265 &LocalDomainResolverProxy::OnCallback, GetWeakPtr(), callback)));
268 // LocalDomainResolver methods.
269 virtual void Start() OVERRIDE {
270 if (implementation())
271 PostToMdnsThread(base::Bind(&LocalDomainResolver::Start,
272 base::Unretained(implementation())));
275 private:
276 static void OnCallback(const WeakPtr& proxy,
277 const LocalDomainResolver::IPAddressCallback& callback,
278 bool a1,
279 const net::IPAddressNumber& a2,
280 const net::IPAddressNumber& a3) {
281 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
282 PostToUIThread(base::Bind(&Base::RunCallback, proxy,
283 base::Bind(callback, a1, a2, a3)));
286 DISALLOW_COPY_AND_ASSIGN(LocalDomainResolverProxy);
289 } // namespace
291 ServiceDiscoveryClientMdns::ServiceDiscoveryClientMdns()
292 : mdns_runner_(
293 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)),
294 restart_attempts_(0),
295 need_dalay_mdns_tasks_(true),
296 weak_ptr_factory_(this) {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
298 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
299 StartNewClient();
302 scoped_ptr<ServiceWatcher> ServiceDiscoveryClientMdns::CreateServiceWatcher(
303 const std::string& service_type,
304 const ServiceWatcher::UpdatedCallback& callback) {
305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
306 return scoped_ptr<ServiceWatcher>(
307 new ServiceWatcherProxy(this, service_type, callback));
310 scoped_ptr<ServiceResolver> ServiceDiscoveryClientMdns::CreateServiceResolver(
311 const std::string& service_name,
312 const ServiceResolver::ResolveCompleteCallback& callback) {
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
314 return scoped_ptr<ServiceResolver>(
315 new ServiceResolverProxy(this, service_name, callback));
318 scoped_ptr<LocalDomainResolver>
319 ServiceDiscoveryClientMdns::CreateLocalDomainResolver(
320 const std::string& domain,
321 net::AddressFamily address_family,
322 const LocalDomainResolver::IPAddressCallback& callback) {
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
324 return scoped_ptr<LocalDomainResolver>(
325 new LocalDomainResolverProxy(this, domain, address_family, callback));
328 ServiceDiscoveryClientMdns::~ServiceDiscoveryClientMdns() {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
330 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
331 DCHECK(proxies_.empty());
332 Reset();
335 void ServiceDiscoveryClientMdns::OnNetworkChanged(
336 net::NetworkChangeNotifier::ConnectionType type) {
337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338 // Only network changes resets counter.
339 restart_attempts_ = 0;
340 ScheduleStartNewClient();
343 void ServiceDiscoveryClientMdns::ScheduleStartNewClient() {
344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
345 // Reset pointer to abort another restart request, if already scheduled.
346 weak_ptr_factory_.InvalidateWeakPtrs();
347 if (restart_attempts_ < kMaxRestartAttempts) {
348 base::MessageLoop::current()->PostDelayedTask(
349 FROM_HERE,
350 base::Bind(&ServiceDiscoveryClientMdns::StartNewClient,
351 weak_ptr_factory_.GetWeakPtr()),
352 base::TimeDelta::FromSeconds(
353 kRestartDelayOnNetworkChangeSeconds * (1 << restart_attempts_)));
354 } else {
355 ReportSuccess();
359 void ServiceDiscoveryClientMdns::StartNewClient() {
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
361 ++restart_attempts_;
362 Reset();
363 mdns_.reset(net::MDnsClient::CreateDefault().release());
364 client_.reset(new ServiceDiscoveryClientImpl(mdns_.get()));
365 BrowserThread::PostTaskAndReplyWithResult(
366 BrowserThread::FILE,
367 FROM_HERE,
368 base::Bind(&net::GetMDnsInterfacesToBind),
369 base::Bind(&ServiceDiscoveryClientMdns::OnInterfaceListReady,
370 weak_ptr_factory_.GetWeakPtr()));
373 void ServiceDiscoveryClientMdns::OnInterfaceListReady(
374 const net::InterfaceIndexFamilyList& interfaces) {
375 mdns_runner_->PostTask(
376 FROM_HERE,
377 base::Bind(&InitMdns,
378 base::Bind(&ServiceDiscoveryClientMdns::OnMdnsInitialized,
379 weak_ptr_factory_.GetWeakPtr()),
380 interfaces,
381 base::Unretained(mdns_.get())));
382 // Initialization is posted, no need to delay tasks.
383 need_dalay_mdns_tasks_ = false;
384 for (size_t i = 0; i < delayed_tasks_.size(); ++i)
385 mdns_runner_->PostTask(FROM_HERE, delayed_tasks_[i]);
386 delayed_tasks_.clear();
389 void ServiceDiscoveryClientMdns::OnMdnsInitialized(bool success) {
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
391 if (!success) {
392 ScheduleStartNewClient();
393 return;
395 ReportSuccess();
397 std::set<Proxy*> tmp_proxies(proxies_);
398 std::for_each(tmp_proxies.begin(), tmp_proxies.end(),
399 std::mem_fun(&Proxy::OnNewMdnsReady));
402 void ServiceDiscoveryClientMdns::ReportSuccess() {
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
404 UMA_HISTOGRAM_COUNTS_100("LocalDiscovery.ClientRestartAttempts",
405 restart_attempts_);
408 void ServiceDiscoveryClientMdns::Reset() {
409 need_dalay_mdns_tasks_ = true;
410 delayed_tasks_.clear();
412 weak_ptr_factory_.InvalidateWeakPtrs();
414 std::for_each(proxies_.begin(), proxies_.end(),
415 std::mem_fun(&Proxy::OnMdnsDestroy));
416 if (client_)
417 mdns_runner_->DeleteSoon(FROM_HERE, client_.release());
418 if (mdns_)
419 mdns_runner_->DeleteSoon(FROM_HERE, mdns_.release());
422 bool ServiceDiscoveryClientMdns::PostToMdnsThread(const base::Closure& task) {
423 // The first task on IO thread for each |mdns_| instance must be |InitMdns|.
424 // |OnInterfaceListReady| could be delayed by |GetMDnsInterfacesToBind|
425 // running on FILE thread, so |PostToMdnsThread| could to post task for
426 // |mdns_| that is not posted initialization for.
427 if (!need_dalay_mdns_tasks_)
428 return mdns_runner_->PostTask(FROM_HERE, task);
429 delayed_tasks_.push_back(task);
430 return true;
433 } // namespace local_discovery