Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: chrome/browser/local_discovery/service_discovery_client_mdns.cc

Issue 256913005: In browser process implementation of ServiceDiscoveryClient. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Mon 04/28/2014 11:21:07.24 Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_client_mdns.h"
6
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"
13
14 namespace local_discovery {
15
16 using content::BrowserThread;
17
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;
23
24 explicit Proxy(ServiceDiscoveryClientMdns* client)
25 : client_(client),
26 weak_ptr_factory_(this) {
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28 client_->proxies_.insert(this);
29 }
30
31 virtual ~Proxy() {
32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33 client_->proxies_.erase(this);
34 }
35
36 // Notify proxies that mDNS layer is going to be destroyed.
37 virtual void OnMdnsDestroy() = 0;
38
39 // Notify proxies that new mDNS instance is ready.
40 virtual void OnNewMdnsReady() {}
41
42 protected:
43 bool PostToMdnsThread(const base::Closure& task) {
44 return client_->PostToMdnsThread(task);
45 }
46
47 static bool PostToUIThread(const base::Closure& task) {
48 return BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
49 }
50
51 ServiceDiscoveryClient* client() {
52 return client_->client_.get();
53 }
54
55 WeakPtr GetWeakPtr() {
56 return weak_ptr_factory_.GetWeakPtr();
57 }
58
59 // Run callback using this method to abort callback if instance of |Proxy|
60 // is deleted.
61 void RunCallback(const base::Closure& callback) {
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
63 callback.Run();
64 }
65
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;
72 }
73
74 private:
75 scoped_refptr<ServiceDiscoveryClientMdns> client_;
76 base::WeakPtrFactory<Proxy> weak_ptr_factory_;
77
78 DISALLOW_COPY_AND_ASSIGN(Proxy);
79 };
80
81 namespace {
82
83 const int kMaxRestartAttempts = 10;
84 const int kRestartDelayOnNetworkChangeSeconds = 3;
85
86 typedef base::Callback<void(bool)> MdnsInitCallback;
87
88 class SocketFactory : public net::MDnsSocketFactory {
89 public:
90 explicit SocketFactory(const net::InterfaceIndexFamilyList& interfaces)
91 : interfaces_(interfaces) {}
92
93 // net::MDnsSocketFactory implementation:
94 void CreateSockets(ScopedVector<net::DatagramServerSocket>* sockets) {
95 for (size_t i = 0; i < interfaces_.size(); ++i) {
96 DCHECK(interfaces_[i].second == net::ADDRESS_FAMILY_IPV4 ||
97 interfaces_[i].second == net::ADDRESS_FAMILY_IPV6);
98 scoped_ptr<net::DatagramServerSocket> socket(
99 CreateAndBindMDnsSocket(interfaces_[i].second, interfaces_[i].first));
100 if (socket)
101 sockets->push_back(socket.release());
102 }
103 }
104
105 private:
106 net::InterfaceIndexFamilyList interfaces_;
107 };
108
109 void InitMdns(const MdnsInitCallback& on_initialized,
110 const net::InterfaceIndexFamilyList& interfaces,
111 net::MDnsClient* mdns) {
112 SocketFactory socket_factory(interfaces);
113 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
114 base::Bind(on_initialized,
115 mdns->StartListening(&socket_factory)));
116 }
117
118 template<class T>
119 class ProxyBase : public ServiceDiscoveryClientMdns::Proxy, public T {
120 public:
121 typedef base::WeakPtr<Proxy> WeakPtr;
122 typedef ProxyBase<T> Base;
123
124 explicit ProxyBase(ServiceDiscoveryClientMdns* client)
125 : Proxy(client) {
126 }
127
128 virtual ~ProxyBase() {
129 DeleteOnMdnsThread(implementation_.release());
130 }
131
132 virtual void OnMdnsDestroy() OVERRIDE {
133 DeleteOnMdnsThread(implementation_.release());
134 };
135
136 protected:
137 void set_implementation(scoped_ptr<T> implementation) {
138 implementation_ = implementation.Pass();
139 }
140
141 T* implementation() const {
142 return implementation_.get();
143 }
144
145 private:
146 scoped_ptr<T> implementation_;
147 DISALLOW_COPY_AND_ASSIGN(ProxyBase);
148 };
149
150 class ServiceWatcherProxy : public ProxyBase<ServiceWatcher> {
151 public:
152 ServiceWatcherProxy(ServiceDiscoveryClientMdns* client_mdns,
153 const std::string& service_type,
154 const ServiceWatcher::UpdatedCallback& callback)
155 : ProxyBase(client_mdns),
156 service_type_(service_type),
157 callback_(callback) {
158 set_implementation(client()->CreateServiceWatcher(
Noam Samuel 2014/04/28 20:40:51 Do we want this created on the mdns thread?
Vitaly Buka (NO REVIEWS) 2014/04/28 22:56:31 Updated comment. On 2014/04/28 20:40:51, Noam Samu
159 service_type,
160 base::Bind(&ServiceWatcherProxy::OnCallback, GetWeakPtr(), callback)));
161 }
162
163 // ServiceWatcher methods.
164 virtual void Start() OVERRIDE {
165 if (implementation())
166 PostToMdnsThread(base::Bind(&ServiceWatcher::Start,
167 base::Unretained(implementation())));
168 }
169
170 virtual void DiscoverNewServices(bool force_update) OVERRIDE {
171 if (implementation())
172 PostToMdnsThread(base::Bind(&ServiceWatcher::DiscoverNewServices,
173 base::Unretained(implementation()),
174 force_update));
175 }
176
177 virtual void SetActivelyRefreshServices(
178 bool actively_refresh_services) OVERRIDE {
179 if (implementation())
180 PostToMdnsThread(base::Bind(&ServiceWatcher::SetActivelyRefreshServices,
181 base::Unretained(implementation()),
182 actively_refresh_services));
183 }
184
185 virtual std::string GetServiceType() const OVERRIDE {
186 return service_type_;
187 }
188
189 virtual void OnNewMdnsReady() OVERRIDE {
190 if (!implementation())
191 callback_.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
192 }
193
194 private:
195 static void OnCallback(const WeakPtr& proxy,
196 const ServiceWatcher::UpdatedCallback& callback,
197 UpdateType a1,
198 const std::string& a2) {
199 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
200 PostToUIThread(base::Bind(&Base::RunCallback, proxy,
201 base::Bind(callback, a1, a2)));
202 }
203 std::string service_type_;
204 ServiceWatcher::UpdatedCallback callback_;
205 DISALLOW_COPY_AND_ASSIGN(ServiceWatcherProxy);
206 };
207
208 class ServiceResolverProxy : public ProxyBase<ServiceResolver> {
209 public:
210 ServiceResolverProxy(ServiceDiscoveryClientMdns* client_mdns,
211 const std::string& service_name,
212 const ServiceResolver::ResolveCompleteCallback& callback)
213 : ProxyBase(client_mdns),
214 service_name_(service_name) {
215 set_implementation(client()->CreateServiceResolver(
Noam Samuel 2014/04/28 20:40:51 Ditto to 158
216 service_name,
217 base::Bind(&ServiceResolverProxy::OnCallback, GetWeakPtr(), callback)));
218 }
219
220 // ServiceResolver methods.
221 virtual void StartResolving() {
222 if (implementation())
223 PostToMdnsThread(base::Bind(&ServiceResolver::StartResolving,
224 base::Unretained(implementation())));
225 };
226
227 virtual std::string GetName() const OVERRIDE {
228 return service_name_;
229 }
230
231 private:
232 static void OnCallback(
233 const WeakPtr& proxy,
234 const ServiceResolver::ResolveCompleteCallback& callback,
235 RequestStatus a1,
236 const ServiceDescription& a2) {
237 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
238 PostToUIThread(base::Bind(&Base::RunCallback, proxy,
239 base::Bind(callback, a1, a2)));
240 }
241
242 std::string service_name_;
243 DISALLOW_COPY_AND_ASSIGN(ServiceResolverProxy);
244 };
245
246 class LocalDomainResolverProxy : public ProxyBase<LocalDomainResolver> {
247 public:
248 LocalDomainResolverProxy(
249 ServiceDiscoveryClientMdns* client_mdns,
250 const std::string& domain,
251 net::AddressFamily address_family,
252 const LocalDomainResolver::IPAddressCallback& callback)
253 : ProxyBase(client_mdns) {
254 set_implementation(client()->CreateLocalDomainResolver(
Noam Samuel 2014/04/28 20:40:51 Ditto to 158
255 domain,
256 address_family,
257 base::Bind(
258 &LocalDomainResolverProxy::OnCallback, GetWeakPtr(), callback)));
259 }
260
261 // LocalDomainResolver methods.
262 virtual void Start() OVERRIDE {
263 if (implementation())
264 PostToMdnsThread(base::Bind(&LocalDomainResolver::Start,
265 base::Unretained(implementation())));
266 };
267
268 private:
269 static void OnCallback(const WeakPtr& proxy,
270 const LocalDomainResolver::IPAddressCallback& callback,
271 bool a1,
272 const net::IPAddressNumber& a2,
273 const net::IPAddressNumber& a3) {
274 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
275 PostToUIThread(base::Bind(&Base::RunCallback, proxy,
276 base::Bind(callback, a1, a2, a3)));
277 }
278
279 DISALLOW_COPY_AND_ASSIGN(LocalDomainResolverProxy);
280 };
281
282 } // namespace
283
284 ServiceDiscoveryClientMdns::ServiceDiscoveryClientMdns()
285 : mdns_runner_(
286 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)),
287 restart_attempts_(0),
288 need_dalay_mdns_tasks_(true),
289 weak_ptr_factory_(this) {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
292 StartNewClient();
293 }
294
295 scoped_ptr<ServiceWatcher> ServiceDiscoveryClientMdns::CreateServiceWatcher(
296 const std::string& service_type,
297 const ServiceWatcher::UpdatedCallback& callback) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299 return scoped_ptr<ServiceWatcher>(
300 new ServiceWatcherProxy(this, service_type, callback));
301 }
302
303 scoped_ptr<ServiceResolver> ServiceDiscoveryClientMdns::CreateServiceResolver(
304 const std::string& service_name,
305 const ServiceResolver::ResolveCompleteCallback& callback) {
306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
307 return scoped_ptr<ServiceResolver>(
308 new ServiceResolverProxy(this, service_name, callback));
309 }
310
311 scoped_ptr<LocalDomainResolver>
312 ServiceDiscoveryClientMdns::CreateLocalDomainResolver(
313 const std::string& domain,
314 net::AddressFamily address_family,
315 const LocalDomainResolver::IPAddressCallback& callback) {
316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317 return scoped_ptr<LocalDomainResolver>(
318 new LocalDomainResolverProxy(this, domain, address_family, callback));
319 }
320
321 ServiceDiscoveryClientMdns::~ServiceDiscoveryClientMdns() {
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
323 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
324 DCHECK(proxies_.empty());
325 Reset();
326 }
327
328 void ServiceDiscoveryClientMdns::OnNetworkChanged(
329 net::NetworkChangeNotifier::ConnectionType type) {
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
331 // Only network changes resets counter.
332 restart_attempts_ = 0;
333 ScheduleStartNewClient();
334 }
335
336 void ServiceDiscoveryClientMdns::ScheduleStartNewClient() {
337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338 // Reset pointer to abort another restart request, if already scheduled.
339 weak_ptr_factory_.InvalidateWeakPtrs();
340 if (restart_attempts_ < kMaxRestartAttempts) {
341 base::MessageLoop::current()->PostDelayedTask(
342 FROM_HERE,
343 base::Bind(&ServiceDiscoveryClientMdns::StartNewClient,
344 weak_ptr_factory_.GetWeakPtr()),
345 base::TimeDelta::FromSeconds(
346 kRestartDelayOnNetworkChangeSeconds * (1 << restart_attempts_)));
347 } else {
348 ReportSuccess();
349 }
350 }
351
352 void ServiceDiscoveryClientMdns::StartNewClient() {
353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
354 ++restart_attempts_;
355 Reset();
356 mdns_.reset(net::MDnsClient::CreateDefault().release());
357 client_.reset(new ServiceDiscoveryClientImpl(mdns_.get()));
358 BrowserThread::PostTaskAndReplyWithResult(
359 BrowserThread::FILE,
360 FROM_HERE,
361 base::Bind(&net::GetMDnsInterfacesToBind),
362 base::Bind(&ServiceDiscoveryClientMdns::OnInterfaceListReady,
363 weak_ptr_factory_.GetWeakPtr()));
364 }
365
366 void ServiceDiscoveryClientMdns::OnInterfaceListReady(
367 const net::InterfaceIndexFamilyList& interfaces) {
368 mdns_runner_->PostTask(
369 FROM_HERE,
370 base::Bind(&InitMdns,
371 base::Bind(&ServiceDiscoveryClientMdns::OnMdnsInitialized,
372 weak_ptr_factory_.GetWeakPtr()),
373 interfaces,
374 base::Unretained(mdns_.get())));
375 // Initialization is posted, no need to delay tasks.
376 need_dalay_mdns_tasks_ = false;
377 for (size_t i = 0; i < delayed_tasks_.size(); ++i)
378 mdns_runner_->PostTask(FROM_HERE, delayed_tasks_[i]);
379 delayed_tasks_.clear();
380 }
381
382 void ServiceDiscoveryClientMdns::OnMdnsInitialized(bool success) {
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
384 if (!success) {
385 ScheduleStartNewClient();
386 return;
387 }
388 ReportSuccess();
389
390 std::set<Proxy*> tmp_proxies(proxies_);
391 std::for_each(tmp_proxies.begin(), tmp_proxies.end(),
392 std::mem_fun(&Proxy::OnNewMdnsReady));
393 }
394
395 void ServiceDiscoveryClientMdns::ReportSuccess() {
396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
397 UMA_HISTOGRAM_COUNTS_100("LocalDiscovery.ClientRestartAttempts",
398 restart_attempts_ /* +1 to match older data */);
Noam Samuel 2014/04/28 20:40:51 Confused. Should we be adding +1 so that the data
Vitaly Buka (NO REVIEWS) 2014/04/28 22:56:31 Outdated comment, it's already produce consistent
399 }
400
401 void ServiceDiscoveryClientMdns::Reset() {
402 need_dalay_mdns_tasks_ = true;
403 delayed_tasks_.clear();
404
405 weak_ptr_factory_.InvalidateWeakPtrs();
406
407 std::for_each(proxies_.begin(), proxies_.end(),
408 std::mem_fun(&Proxy::OnMdnsDestroy));
409 if (client_)
410 mdns_runner_->DeleteSoon(FROM_HERE, client_.release());
411 if (mdns_)
412 mdns_runner_->DeleteSoon(FROM_HERE, mdns_.release());
413 }
414
415 bool ServiceDiscoveryClientMdns::PostToMdnsThread(const base::Closure& task) {
416 // The first task on IO thread for each |mdns_| instance must be |InitMdns|.
417 // |OnInterfaceListReady| could be delayed by |GetMDnsInterfacesToBind|
418 // running on FILE thread, so |PostToMdnsThread| could to post task for
419 // |mdns_| that is not posted initialization for.
420 if (!need_dalay_mdns_tasks_)
421 return mdns_runner_->PostTask(FROM_HERE, task);
422 delayed_tasks_.push_back(task);
423 return true;
424 }
425
426 } // namespace local_discovery
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698