summaryrefslogtreecommitdiffstats
path: root/chrome/browser/local_discovery/service_discovery_device_lister.cc
blob: e797ae04f69a79782fb7d9fcf404603cd6a8d49d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/local_discovery/service_discovery_device_lister.h"

#include <utility>
#include <vector>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"

namespace local_discovery {

namespace {
#if defined(OS_MACOSX)
const int kMacServiceResolvingIntervalSecs = 60;
#endif
}  // namespace

ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister(
    Delegate* delegate,
    ServiceDiscoveryClient* service_discovery_client,
    const std::string& service_type)
    : delegate_(delegate),
      service_discovery_client_(service_discovery_client),
      service_type_(service_type),
      weak_factory_(this) {
}

ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() {
}

void ServiceDiscoveryDeviceLister::Start() {
  VLOG(1) << "DeviceListerStart: service_type: " << service_type_;
  CreateServiceWatcher();
}

void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) {
  VLOG(1) << "DiscoverNewDevices: service_type: " << service_type_;
  service_watcher_->DiscoverNewServices(force_update);
}

void ServiceDiscoveryDeviceLister::OnServiceUpdated(
    ServiceWatcher::UpdateType update,
    const std::string& service_name) {
  VLOG(1) << "OnServiceUpdated: service_type: " << service_type_
          << ", service_name: " << service_name
          << ", update: " << update;
  if (update == ServiceWatcher::UPDATE_INVALIDATED) {
    resolvers_.clear();
    CreateServiceWatcher();

    delegate_->OnDeviceCacheFlushed();
    return;
  }

  if (update != ServiceWatcher::UPDATE_REMOVED) {
    bool added = (update == ServiceWatcher::UPDATE_ADDED);
    std::pair<ServiceResolverMap::iterator, bool> insert_result =
        resolvers_.insert(make_pair(service_name,
                                    linked_ptr<ServiceResolver>(NULL)));

    // If there is already a resolver working on this service, don't add one.
    if (insert_result.second) {
      VLOG(1) << "Adding resolver for service_name: " << service_name;
      scoped_ptr<ServiceResolver> resolver =
          service_discovery_client_->CreateServiceResolver(
          service_name, base::Bind(
              &ServiceDiscoveryDeviceLister::OnResolveComplete,
              weak_factory_.GetWeakPtr(),
              added,
              service_name));

      insert_result.first->second.reset(resolver.release());
      insert_result.first->second->StartResolving();
    } else {
      VLOG(1) << "Resolver already exists, service_name: " << service_name;
    }
  } else {
    delegate_->OnDeviceRemoved(service_name);
  }
}

// TODO(noamsml): Update ServiceDiscoveryClient interface to match this.
void ServiceDiscoveryDeviceLister::OnResolveComplete(
    bool added,
    std::string service_name,
    ServiceResolver::RequestStatus status,
    const ServiceDescription& service_description) {
  VLOG(1) << "OnResolveComplete: service_type: " << service_type_
          << ", service_name: " << service_name
          << ", status: " << status;
  if (status == ServiceResolver::STATUS_SUCCESS) {
    delegate_->OnDeviceChanged(added, service_description);

#if defined(OS_MACOSX)
    // On Mac, the Bonjour service does not seem to ever evict a service if a
    // device is unplugged, so we need to continuously try to resolve the
    // service to detect non-graceful shutdowns.
    base::MessageLoop::current()->PostDelayedTask(
        FROM_HERE,
        base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
                   weak_factory_.GetWeakPtr(),
                   ServiceWatcher::UPDATE_CHANGED,
                   service_description.service_name),
        base::TimeDelta::FromSeconds(kMacServiceResolvingIntervalSecs));
#endif
  } else {
    // TODO(noamsml): Add retry logic.
  }
  resolvers_.erase(service_name);
}

void ServiceDiscoveryDeviceLister::CreateServiceWatcher() {
  service_watcher_ =
      service_discovery_client_->CreateServiceWatcher(
          service_type_,
          base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
                     weak_factory_.GetWeakPtr()));
  service_watcher_->Start();
}

}  // namespace local_discovery