blob: b052ab17ed845efac9a71542be6a5d5847d73962 [file] [log] [blame]
Vitaly Buka7ce499f2015-06-09 08:04:11 -07001// Copyright 2014 The Chromium OS 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 "buffet/privet/peerd_client.h"
6
7#include <map>
8
9#include <base/message_loop/message_loop.h>
10#include <chromeos/errors/error.h>
11#include <chromeos/strings/string_utils.h>
12
13#include "buffet/privet/cloud_delegate.h"
14#include "buffet/privet/device_delegate.h"
15#include "buffet/privet/wifi_bootstrap_manager.h"
16#include "buffet/privet/wifi_ssid_generator.h"
17
18using chromeos::string_utils::Join;
19using org::chromium::peerd::PeerProxy;
20
21namespace privetd {
22
23namespace {
24
25// Commit changes only if no update request happened during the timeout.
26// Usually updates happen in batches, so we don't want to flood network with
27// updates relevant for a short amount of time.
28const int kCommitTimeoutSeconds = 1;
29
30// The name of the service we'll expose via peerd.
31const char kPrivetServiceId[] = "privet";
32const char kSelfPath[] = "/org/chromium/peerd/Self";
33
34void OnError(const std::string& operation, chromeos::Error* error) {
35 LOG(ERROR) << operation << " failed:" << error->GetMessage();
36}
37
38} // namespace
39
40PeerdClient::PeerdClient(const scoped_refptr<dbus::Bus>& bus,
41 const DeviceDelegate* device,
42 const CloudDelegate* cloud,
43 const WifiDelegate* wifi)
44 : peerd_object_manager_proxy_{bus},
45 device_{device},
46 cloud_{cloud},
47 wifi_{wifi} {
48 CHECK(device_);
49 CHECK(cloud_);
50 peerd_object_manager_proxy_.SetManagerAddedCallback(
51 base::Bind(&PeerdClient::OnPeerdOnline, weak_ptr_factory_.GetWeakPtr()));
52 peerd_object_manager_proxy_.SetManagerRemovedCallback(
53 base::Bind(&PeerdClient::OnPeerdOffline, weak_ptr_factory_.GetWeakPtr()));
54 peerd_object_manager_proxy_.SetPeerAddedCallback(
55 base::Bind(&PeerdClient::OnNewPeer, weak_ptr_factory_.GetWeakPtr()));
56}
57
58PeerdClient::~PeerdClient() {
59 RemoveService();
60}
61
62std::string PeerdClient::GetId() const {
63 return device_id_;
64}
65
66void PeerdClient::Update() {
67 // Abort pending updates, and wait for more changes.
68 restart_weak_ptr_factory_.InvalidateWeakPtrs();
69 base::MessageLoop::current()->PostDelayedTask(
70 FROM_HERE, base::Bind(&PeerdClient::UpdateImpl,
71 restart_weak_ptr_factory_.GetWeakPtr()),
72 base::TimeDelta::FromSeconds(kCommitTimeoutSeconds));
73}
74
75void PeerdClient::OnNewPeer(PeerProxy* peer) {
76 if (!peer || peer->GetObjectPath().value() != kSelfPath)
77 return;
Vitaly Buka075b3d42015-06-09 08:34:25 -070078 peer->SetPropertyChangedCallback(base::Bind(
79 &PeerdClient::OnPeerPropertyChanged, weak_ptr_factory_.GetWeakPtr()));
Vitaly Buka7ce499f2015-06-09 08:04:11 -070080 OnPeerPropertyChanged(peer, PeerProxy::UUIDName());
81}
82
Vitaly Buka075b3d42015-06-09 08:34:25 -070083void PeerdClient::OnPeerPropertyChanged(PeerProxy* peer,
84 const std::string& property_name) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -070085 if (property_name != PeerProxy::UUIDName() ||
86 peer->GetObjectPath().value() != kSelfPath)
87 return;
88 const std::string new_id{peer->uuid()};
89 if (new_id != device_id_) {
90 device_id_ = new_id;
91 Update();
92 }
93}
94
95void PeerdClient::OnPeerdOnline(
96 org::chromium::peerd::ManagerProxy* manager_proxy) {
97 peerd_manager_proxy_ = manager_proxy;
98 VLOG(1) << "Peerd manager is online at '"
99 << manager_proxy->GetObjectPath().value() << "'.";
100 Update();
101}
102
103void PeerdClient::OnPeerdOffline(const dbus::ObjectPath& object_path) {
104 peerd_manager_proxy_ = nullptr;
105 VLOG(1) << "Peerd manager is now offline.";
106}
107
108void PeerdClient::ExposeService() {
109 // Do nothing if peerd hasn't started yet.
110 if (peerd_manager_proxy_ == nullptr)
111 return;
112
113 std::string name;
114 std::string model_id;
115 if (!cloud_->GetName(&name, nullptr) ||
116 !cloud_->GetModelId(&model_id, nullptr)) {
117 return;
118 }
119 DCHECK_EQ(model_id.size(), 5U);
120
121 VLOG(1) << "Starting peerd advertising.";
122 const uint16_t port = device_->GetHttpEnpoint().first;
123 std::map<std::string, chromeos::Any> mdns_options{
124 {"port", chromeos::Any{port}},
125 };
126 DCHECK_NE(port, 0);
127
128 std::string services;
129 if (!cloud_->GetServices().empty())
130 services += "_";
131 services += Join(",_", cloud_->GetServices());
132
133 std::map<std::string, std::string> txt_record{
134 {"txtvers", "3"},
135 {"ty", name},
136 {"services", services},
137 {"id", GetId()},
138 {"mmid", model_id},
139 {"flags", WifiSsidGenerator{cloud_, wifi_}.GenerateFlags()},
140 };
141
142 if (!cloud_->GetCloudId().empty())
143 txt_record.emplace("gcd_id", cloud_->GetCloudId());
144
145 if (!cloud_->GetDescription().empty())
146 txt_record.emplace("note", cloud_->GetDescription());
147
148 peerd_manager_proxy_->ExposeServiceAsync(
149 kPrivetServiceId, txt_record, {{"mdns", mdns_options}}, base::Closure(),
150 base::Bind(&OnError, "ExposeService"));
151}
152
153void PeerdClient::RemoveService() {
154 if (peerd_manager_proxy_ == nullptr)
155 return;
156
157 VLOG(1) << "Stopping peerd advertising.";
158 peerd_manager_proxy_->RemoveExposedServiceAsync(
159 kPrivetServiceId, base::Closure(), base::Bind(&OnError, "RemoveService"));
160}
161
162void PeerdClient::UpdateImpl() {
163 if (device_->GetHttpEnpoint().first == 0)
164 return RemoveService();
165 ExposeService();
166}
167
168} // namespace privetd