blob: dc1488866299f83988f2c4f89b86467f5ef0d49c [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LEADERD_GROUP_H_
#define LEADERD_GROUP_H_
#include <set>
#include <string>
#include <tuple>
#include <vector>
#include <base/macros.h>
#include <base/timer/timer.h>
#include <chromeos/dbus/async_event_sequencer.h>
#include <chromeos/dbus/dbus_service_watcher.h>
#include <chromeos/http/http_transport.h>
#include "leaderd/group_config.h"
#include "leaderd/org.chromium.leaderd.Group.h"
namespace chromeos {
namespace dbus_utils {
class ExportedObjectManager;
} // dbus_utils
} // chromeos
namespace leaderd {
// Represents a single group advertisement.
class Group : public org::chromium::leaderd::GroupInterface {
public:
using IpInfo = std::vector<std::tuple<std::vector<uint8_t>, uint16_t>>;
using CompletionAction =
chromeos::dbus_utils::AsyncEventSequencer::CompletionAction;
class Delegate {
public:
virtual ~Delegate() = default;
virtual void RemoveGroup(const std::string& group) = 0;
virtual const std::string& GetUUID() const = 0;
virtual IpInfo GetIPInfo(const std::string& peer_id) const = 0;
};
enum class State { WANDERER, FOLLOWER, LEADER };
Group(const std::string& guid,
std::unique_ptr<GroupConfig> config,
const scoped_refptr<dbus::Bus>& bus,
chromeos::dbus_utils::ExportedObjectManager* object_manager,
const dbus::ObjectPath& path,
const std::string& dbus_connection_id,
const std::set<std::string>& peer_list,
Delegate* delegate);
void RegisterAsync(const CompletionAction& completion_callback);
const dbus::ObjectPath& GetObjectPath() const;
// DBus handlers
bool LeaveGroup(chromeos::ErrorPtr* error) override;
bool SetScore(chromeos::ErrorPtr* error, int32_t new_score) override;
bool PokeLeader(chromeos::ErrorPtr* error) override;
// The manager informs us when a peer is interested in who the leader is.
void HandleLeaderDiscover(std::string* leader_id);
// The manager informs us when we need to respond to a challenge from a peer.
void HandleLeaderChallenge(const std::string& challenger_id,
int32_t challenger_score,
std::string* leader_id,
std::string* my_id);
// The manager informs us of leadership announcements from our peers.
bool HandleLeaderAnnouncement(const std::string& leader_id,
int32_t leader_score);
// The manager informs us of changes in group membership.
void AddPeer(const std::string& uuid);
void RemovePeer(const std::string& uuid);
void ClearPeers();
private:
friend class GroupTest;
FRIEND_TEST(GroupTest, LeaderChallengeIsWellFormed);
FRIEND_TEST(GroupTest, LeaderAnnouncementIsWellFormed);
void OnDBusServiceDeath();
void RemoveSoon();
void RemoveNow();
bool IsTheirScoreGreater(int32_t other_score,
const std::string& other_id) const;
void SetRole(State state, const std::string& leader);
void OnWandererTimeout();
bool BuildApiUrls(const std::string& api_verb,
const std::string& peer_id,
std::vector<std::string>* urls) const;
// These methods let us discover leaders.
void AskPeersForLeaderInfo();
void SendLeaderDiscover(const std::string& peer_id);
void HandleLeaderDiscoverResponse(
chromeos::http::RequestID request_id,
std::unique_ptr<chromeos::http::Response> response);
// These methods let us periodically challenge the leader to confirm fitness.
void SendLeaderChallenge(const std::string& peer_id);
void HandleLeaderChallengeResponse(
chromeos::http::RequestID request_id,
std::unique_ptr<chromeos::http::Response> response);
void HandleLeaderChallengeFailure(chromeos::http::RequestID request_id,
const chromeos::Error*);
// These methods let us announce our leadership. We ignore results.
void AnnounceLeadership();
void SendLeaderAnnouncement(const std::string& peer_id);
// Used in tests.
void ReplaceTimersWithMocksForTest(
std::unique_ptr<base::Timer> wanderer_timer,
std::unique_ptr<base::Timer> heartbeat_timer);
void ReplaceHTTPTransportForTest(
std::shared_ptr<chromeos::http::Transport> transport) {
transport_ = transport;
}
const std::string guid_;
const std::unique_ptr<GroupConfig> config_;
const dbus::ObjectPath object_path_;
std::unique_ptr<base::Timer> wanderer_timer_{
new base::OneShotTimer<Group>()};
std::unique_ptr<base::Timer> heartbeat_timer_{
new base::RepeatingTimer<Group>()};
// A set of UUIDs of the peers advertising this group.
std::set<std::string> peers_;
Delegate* delegate_;
State state_{State::WANDERER};
int32_t score_{0};
uint64_t failed_challenges_{0};
std::string leader_;
std::shared_ptr<chromeos::http::Transport> transport_;
org::chromium::leaderd::GroupAdaptor dbus_adaptor_{this};
chromeos::dbus_utils::DBusObject dbus_object_;
std::unique_ptr<chromeos::dbus_utils::DBusServiceWatcher> service_watcher_;
base::WeakPtrFactory<Group> lifetime_factory_{this};
base::WeakPtrFactory<Group> per_state_factory_{this};
DISALLOW_COPY_AND_ASSIGN(Group);
};
} // namespace leaderd
#endif // LEADERD_GROUP_H_