blob: 73b71e46e00a69abb4b4e14f016c9eb4ea27d941 [file] [log] [blame]
Vitaly Buka7042c582015-07-30 17:02:14 -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/peerd_client.h"
6
7#include <map>
Alex Vakulenkoe32375b2015-09-28 08:55:40 -07008#include <vector>
Vitaly Buka7042c582015-07-30 17:02:14 -07009
10#include <base/message_loop/message_loop.h>
11#include <chromeos/errors/error.h>
12#include <chromeos/strings/string_utils.h>
13
14using org::chromium::peerd::PeerProxy;
15
16namespace buffet {
17
18namespace {
19
20// Commit changes only if no update request happened during the timeout.
21// Usually updates happen in batches, so we don't want to flood network with
22// updates relevant for a short amount of time.
23const int kCommitTimeoutSeconds = 1;
24
25const char kSelfPath[] = "/org/chromium/peerd/Self";
26
27void OnError(const std::string& operation, chromeos::Error* error) {
28 LOG(ERROR) << operation << " failed:" << error->GetMessage();
29}
30
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070031const char kExpectedServiceType[] = "_privet._tcp";
32const char kServiceName[] = "privet";
33
Vitaly Buka7042c582015-07-30 17:02:14 -070034} // namespace
35
36PeerdClient::PeerdClient(const scoped_refptr<dbus::Bus>& bus)
37 : peerd_object_manager_proxy_{bus} {
38 peerd_object_manager_proxy_.SetManagerAddedCallback(
39 base::Bind(&PeerdClient::OnPeerdOnline, weak_ptr_factory_.GetWeakPtr()));
40 peerd_object_manager_proxy_.SetManagerRemovedCallback(
41 base::Bind(&PeerdClient::OnPeerdOffline, weak_ptr_factory_.GetWeakPtr()));
42 peerd_object_manager_proxy_.SetPeerAddedCallback(
43 base::Bind(&PeerdClient::OnNewPeer, weak_ptr_factory_.GetWeakPtr()));
44}
45
46PeerdClient::~PeerdClient() {
47 RemoveService();
48}
49
50std::string PeerdClient::GetId() const {
51 return device_id_;
52}
53
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070054void PeerdClient::PublishService(const std::string& service_type,
55 uint16_t port,
56 const std::vector<std::string>& txt) {
Vitaly Buka7042c582015-07-30 17:02:14 -070057 // Only one service supported.
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070058 CHECK_EQ(service_type, kExpectedServiceType);
Vitaly Buka7042c582015-07-30 17:02:14 -070059 port_ = port;
60 txt_ = txt;
Vitaly Buka7042c582015-07-30 17:02:14 -070061 Update();
62}
63
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070064void PeerdClient::StopPublishing(const std::string& service_type) {
Vitaly Buka7042c582015-07-30 17:02:14 -070065 // Only one service supported.
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070066 CHECK_EQ(service_type, kExpectedServiceType);
Vitaly Buka7042c582015-07-30 17:02:14 -070067 port_ = 0;
Vitaly Buka7042c582015-07-30 17:02:14 -070068 Update();
69}
70
71void PeerdClient::Update() {
72 // Abort pending updates, and wait for more changes.
73 restart_weak_ptr_factory_.InvalidateWeakPtrs();
74 base::MessageLoop::current()->PostDelayedTask(
75 FROM_HERE, base::Bind(&PeerdClient::UpdateImpl,
76 restart_weak_ptr_factory_.GetWeakPtr()),
77 base::TimeDelta::FromSeconds(kCommitTimeoutSeconds));
78}
79
80void PeerdClient::OnNewPeer(PeerProxy* peer) {
81 if (!peer || peer->GetObjectPath().value() != kSelfPath)
82 return;
83 peer->SetPropertyChangedCallback(base::Bind(
84 &PeerdClient::OnPeerPropertyChanged, weak_ptr_factory_.GetWeakPtr()));
85 OnPeerPropertyChanged(peer, PeerProxy::UUIDName());
86}
87
88void PeerdClient::OnPeerPropertyChanged(PeerProxy* peer,
89 const std::string& property_name) {
90 if (property_name != PeerProxy::UUIDName() ||
91 peer->GetObjectPath().value() != kSelfPath)
92 return;
93 const std::string new_id{peer->uuid()};
94 if (new_id != device_id_) {
95 device_id_ = new_id;
96 Update();
97 }
98}
99
100void PeerdClient::OnPeerdOnline(
101 org::chromium::peerd::ManagerProxy* manager_proxy) {
102 peerd_manager_proxy_ = manager_proxy;
103 VLOG(1) << "Peerd manager is online at '"
104 << manager_proxy->GetObjectPath().value() << "'.";
105 Update();
106}
107
108void PeerdClient::OnPeerdOffline(const dbus::ObjectPath& object_path) {
109 peerd_manager_proxy_ = nullptr;
110 VLOG(1) << "Peerd manager is now offline.";
111}
112
113void PeerdClient::ExposeService() {
114 // Do nothing if peerd hasn't started yet.
115 if (peerd_manager_proxy_ == nullptr)
116 return;
117 VLOG(1) << "Starting peerd advertising.";
118 CHECK_NE(port_, 0);
Vitaly Buka7042c582015-07-30 17:02:14 -0700119 CHECK(!txt_.empty());
120 std::map<std::string, chromeos::Any> mdns_options{
121 {"port", chromeos::Any{port_}},
122 };
123
Alex Vakulenkoe32375b2015-09-28 08:55:40 -0700124 std::map<std::string, std::string> txt;
125 for (const auto& record : txt_) {
126 auto name_value = chromeos::string_utils::SplitAtFirst(record, "=");
127 CHECK(!name_value.second.empty());
128 txt.emplace(std::move(name_value));
129 }
130
131 published_ = true;
Vitaly Buka7042c582015-07-30 17:02:14 -0700132 peerd_manager_proxy_->ExposeServiceAsync(
Alex Vakulenkoe32375b2015-09-28 08:55:40 -0700133 kServiceName, txt, {{"mdns", mdns_options}}, base::Closure(),
Vitaly Buka7042c582015-07-30 17:02:14 -0700134 base::Bind(&OnError, "ExposeService"));
135}
136
137void PeerdClient::RemoveService() {
138 if (peerd_manager_proxy_ == nullptr)
139 return;
140
141 VLOG(1) << "Stopping peerd advertising.";
Alex Vakulenkoe32375b2015-09-28 08:55:40 -0700142 if (published_) {
143 published_ = false;
Vitaly Buka7042c582015-07-30 17:02:14 -0700144 peerd_manager_proxy_->RemoveExposedServiceAsync(
Alex Vakulenkoe32375b2015-09-28 08:55:40 -0700145 kServiceName, base::Closure(), base::Bind(&OnError, "RemoveService"));
Vitaly Buka7042c582015-07-30 17:02:14 -0700146 }
147}
148
149void PeerdClient::UpdateImpl() {
150 if (port_ == 0)
151 return RemoveService();
152 ExposeService();
153}
154
155} // namespace buffet