1 #include <boost/asio/deadline_timer.hpp> 2 #include <boost/asio/io_service.hpp> 3 #include <boost/asio/ip/tcp.hpp> 4 #include <boost/asio/placeholders.hpp> 5 #include <boost/bind.hpp> 8 #include <unordered_map> 9 #include <unordered_set> 11 #include "ipuptanesecondary.h" 12 #include "secondary.h" 13 #include "secondary_config.h" 17 using Secondaries = std::vector<std::shared_ptr<Uptane::SecondaryInterface>>;
18 using SecondaryFactoryRegistry =
19 std::unordered_map<std::string, std::function<Secondaries(const SecondaryConfig&, Aktualizr& aktualizr)>>;
21 static Secondaries createIPSecondaries(
const IPSecondariesConfig& config,
Aktualizr& aktualizr);
23 static SecondaryFactoryRegistry sec_factory_registry = {
24 {IPSecondariesConfig::Type,
25 [](
const SecondaryConfig& config,
Aktualizr& aktualizr) {
26 auto ip_sec_cgf =
dynamic_cast<const IPSecondariesConfig&
>(config);
27 return createIPSecondaries(ip_sec_cgf, aktualizr);
29 {VirtualSecondaryConfig::Type,
30 [](
const SecondaryConfig& config,
Aktualizr& ) {
31 auto virtual_sec_cgf =
dynamic_cast<const VirtualSecondaryConfig&
>(config);
32 return Secondaries({std::make_shared<VirtualSecondary>(virtual_sec_cgf)});
39 static Secondaries createSecondaries(
const SecondaryConfig& config,
Aktualizr& aktualizr) {
40 return (sec_factory_registry.at(config.type()))(config, aktualizr);
43 void initSecondaries(
Aktualizr& aktualizr,
const boost::filesystem::path& config_file) {
44 if (!boost::filesystem::exists(config_file)) {
45 throw std::invalid_argument(
"Secondary ECUs config file does not exist: " + config_file.string());
48 auto secondary_configs = SecondaryConfigParser::parse_config_file(config_file);
50 for (
auto& config : secondary_configs) {
52 LOG_INFO <<
"Registering " << config->type() <<
" Secondaries...";
53 Secondaries secondaries = createSecondaries(*config, aktualizr);
55 for (
const auto& secondary : secondaries) {
56 LOG_INFO <<
"Adding Secondary with ECU serial: " << secondary->getSerial()
57 <<
" with hardware ID: " << secondary->getHwId();
60 }
catch (
const std::exception& exc) {
61 LOG_ERROR <<
"Failed to initialize a Secondary: " << exc.what();
69 SecondaryWaiter(uint16_t wait_port,
int timeout_s, Secondaries& secondaries)
70 : endpoint_{boost::asio::ip::tcp::v4(), wait_port},
71 timeout_{
static_cast<boost::posix_time::seconds
>(timeout_s)},
73 connected_secondaries_(secondaries) {}
75 void addSecondary(
const std::string& ip, uint16_t port) { secondaries_to_wait_for_.insert(key(ip, port)); }
78 if (secondaries_to_wait_for_.empty()) {
82 timer_.expires_from_now(timeout_);
83 timer_.async_wait([&](
const boost::system::error_code& error_code) {
85 LOG_ERROR <<
"Wait for Secondaries has failed: " << error_code;
86 throw std::runtime_error(
"Error while waiting for Secondaries");
88 LOG_ERROR <<
"Timeout while waiting for Secondaries: " << error_code;
89 throw std::runtime_error(
"Timeout while waiting for Secondaries");
99 LOG_INFO <<
"Waiting for connection from " << secondaries_to_wait_for_.size() <<
" Secondaries...";
100 acceptor_.async_accept(con_socket_,
101 boost::bind(&SecondaryWaiter::connectionHdlr,
this, boost::asio::placeholders::error));
104 void connectionHdlr(
const boost::system::error_code& error_code) {
106 auto sec_ip = con_socket_.remote_endpoint().address().to_string();
107 auto sec_port = con_socket_.remote_endpoint().port();
109 LOG_INFO <<
"Accepted connection from a Secondary: (" << sec_ip <<
":" << sec_port <<
")";
111 auto secondary = Uptane::IpUptaneSecondary::create(sec_ip, sec_port, con_socket_.native_handle());
113 connected_secondaries_.push_back(secondary);
115 }
catch (
const std::exception& exc) {
116 LOG_ERROR <<
"Failed to initialize a Secondary: " << exc.what();
118 con_socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
121 secondaries_to_wait_for_.erase(key(sec_ip, sec_port));
122 if (!secondaries_to_wait_for_.empty()) {
128 LOG_ERROR <<
"Failed to accept connection from a Secondary";
132 static std::string key(
const std::string& ip, uint16_t port) {
return (ip + std::to_string(port)); }
135 boost::asio::io_service io_context_;
136 boost::asio::ip::tcp::endpoint endpoint_;
137 boost::asio::ip::tcp::acceptor acceptor_{io_context_, endpoint_};
138 boost::asio::ip::tcp::socket con_socket_{io_context_};
139 boost::posix_time::seconds timeout_;
140 boost::asio::deadline_timer timer_;
142 Secondaries& connected_secondaries_;
143 std::unordered_set<std::string> secondaries_to_wait_for_;
151 SecondaryWaiter sec_waiter{config.secondaries_wait_port, config.secondaries_timeout_s, result};
153 for (
const auto& ip_sec_cfg : config.secondaries_cfg) {
154 auto secondary = Uptane::IpUptaneSecondary::connectAndCreate(ip_sec_cfg.ip, ip_sec_cfg.port);
156 result.push_back(secondary);
158 sec_waiter.addSecondary(ip_sec_cfg.ip, ip_sec_cfg.port);
165 for (
size_t k = 0; k < config.secondaries_cfg.size(); k++) {
166 const auto cfg = config.secondaries_cfg[k];
167 const auto sec = result[k];
170 d[
"port"] = cfg.port;
176 for (
const auto& cfg : config.secondaries_cfg) {
177 Uptane::SecondaryInterface::Ptr secondary;
180 auto f = std::find_if(secondaries_info.cbegin(), secondaries_info.cend(), [&cfg](
const SecondaryInfo& i) {
181 Json::Value d = Utils::parseJSON(i.extra);
182 return d[
"ip"] == cfg.ip && d[
"port"] == cfg.port;
185 if (f == secondaries_info.cend() && config.secondaries_cfg.size() == 1 && secondaries_info.size() == 1) {
188 info = &secondaries_info[0];
191 d[
"port"] = cfg.port;
193 LOG_INFO <<
"Migrated single IP Secondary to new storage format";
194 }
else if (f == secondaries_info.cend()) {
196 secondary = Uptane::IpUptaneSecondary::connectAndCreate(cfg.ip, cfg.port);
197 if (secondary ==
nullptr) {
198 LOG_ERROR <<
"Could not instantiate Secondary " << cfg.ip <<
":" << cfg.port;
202 std::find_if(secondaries_info.cbegin(), secondaries_info.cend(),
203 [&secondary](
const SecondaryInfo& i) {
return i.serial == secondary->getSerial(); });
204 if (f_serial == secondaries_info.cend()) {
205 LOG_ERROR <<
"Could not instantiate Secondary " << cfg.ip <<
":" << cfg.port;
213 if (secondary ==
nullptr) {
215 Uptane::IpUptaneSecondary::connectAndCheck(cfg.ip, cfg.port, info->serial, info->hw_id, info->pub_key);
218 if (secondary !=
nullptr) {
219 result.push_back(secondary);
221 LOG_ERROR <<
"Could not instantiate Secondary " << info->serial;
void AddSecondary(const std::shared_ptr< Uptane::SecondaryInterface > &secondary)
Add new Secondary to aktualizr.
std::vector< SecondaryInfo > GetSecondaries() const
Returns a list of the registered Secondaries, along with some associated metadata.
bool IsRegistered() const
Returns true if the device has been registered to the backend succesffully.
void SetSecondaryData(const Uptane::EcuSerial &ecu, const std::string &data)
Store some free-form data to be associated with a particular Secondary, to be retrieved later through...
Results of libaktualizr API calls.
This class provides the main APIs necessary for launching and controlling libaktualizr.