service_discovery_device_lister.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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_device_lister.h"
6
7#include <utility>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/message_loop/message_loop.h"
12
13namespace local_discovery {
14
15namespace {
16#if defined(OS_MACOSX)
17const int kMacServiceResolvingIntervalSecs = 60;
18#endif
19}  // namespace
20
21ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister(
22    Delegate* delegate,
23    ServiceDiscoveryClient* service_discovery_client,
24    const std::string& service_type)
25    : delegate_(delegate),
26      service_discovery_client_(service_discovery_client),
27      service_type_(service_type),
28      weak_factory_(this) {
29}
30
31ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() {
32}
33
34void ServiceDiscoveryDeviceLister::Start() {
35  VLOG(1) << "DeviceListerStart: service_type: " << service_type_;
36  CreateServiceWatcher();
37}
38
39void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) {
40  VLOG(1) << "DiscoverNewDevices: service_type: " << service_type_;
41  service_watcher_->DiscoverNewServices(force_update);
42}
43
44void ServiceDiscoveryDeviceLister::OnServiceUpdated(
45    ServiceWatcher::UpdateType update,
46    const std::string& service_name) {
47  VLOG(1) << "OnServiceUpdated: service_type: " << service_type_
48          << ", service_name: " << service_name
49          << ", update: " << update;
50  if (update == ServiceWatcher::UPDATE_INVALIDATED) {
51    resolvers_.clear();
52    CreateServiceWatcher();
53
54    delegate_->OnDeviceCacheFlushed();
55    return;
56  }
57
58  if (update != ServiceWatcher::UPDATE_REMOVED) {
59    bool added = (update == ServiceWatcher::UPDATE_ADDED);
60    std::pair<ServiceResolverMap::iterator, bool> insert_result =
61        resolvers_.insert(make_pair(service_name,
62                                    linked_ptr<ServiceResolver>(NULL)));
63
64    // If there is already a resolver working on this service, don't add one.
65    if (insert_result.second) {
66      VLOG(1) << "Adding resolver for service_name: " << service_name;
67      scoped_ptr<ServiceResolver> resolver =
68          service_discovery_client_->CreateServiceResolver(
69          service_name, base::Bind(
70              &ServiceDiscoveryDeviceLister::OnResolveComplete,
71              weak_factory_.GetWeakPtr(),
72              added,
73              service_name));
74
75      insert_result.first->second.reset(resolver.release());
76      insert_result.first->second->StartResolving();
77    } else {
78      VLOG(1) << "Resolver already exists, service_name: " << service_name;
79    }
80  } else {
81    delegate_->OnDeviceRemoved(service_name);
82  }
83}
84
85// TODO(noamsml): Update ServiceDiscoveryClient interface to match this.
86void ServiceDiscoveryDeviceLister::OnResolveComplete(
87    bool added,
88    std::string service_name,
89    ServiceResolver::RequestStatus status,
90    const ServiceDescription& service_description) {
91  VLOG(1) << "OnResolveComplete: service_type: " << service_type_
92          << ", service_name: " << service_name
93          << ", status: " << status;
94  if (status == ServiceResolver::STATUS_SUCCESS) {
95    delegate_->OnDeviceChanged(added, service_description);
96
97#if defined(OS_MACOSX)
98    // On Mac, the Bonjour service does not seem to ever evict a service if a
99    // device is unplugged, so we need to continuously try to resolve the
100    // service to detect non-graceful shutdowns.
101    base::MessageLoop::current()->PostDelayedTask(
102        FROM_HERE,
103        base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
104                   weak_factory_.GetWeakPtr(),
105                   ServiceWatcher::UPDATE_CHANGED,
106                   service_description.service_name),
107        base::TimeDelta::FromSeconds(kMacServiceResolvingIntervalSecs));
108#endif
109  } else {
110    // TODO(noamsml): Add retry logic.
111  }
112  resolvers_.erase(service_name);
113}
114
115void ServiceDiscoveryDeviceLister::CreateServiceWatcher() {
116  service_watcher_ =
117      service_discovery_client_->CreateServiceWatcher(
118          service_type_,
119          base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
120                     weak_factory_.GetWeakPtr()));
121  service_watcher_->Start();
122}
123
124}  // namespace local_discovery
125