summaryrefslogtreecommitdiff
path: root/implementation/routing/src/routing_manager_stub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'implementation/routing/src/routing_manager_stub.cpp')
-rw-r--r--implementation/routing/src/routing_manager_stub.cpp428
1 files changed, 422 insertions, 6 deletions
diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp
index d7a1dd2..72668ea 100644
--- a/implementation/routing/src/routing_manager_stub.cpp
+++ b/implementation/routing/src/routing_manager_stub.cpp
@@ -47,7 +47,8 @@ routing_manager_stub::routing_manager_stub(
client_registration_running_(false),
max_local_message_size_(configuration_->get_max_message_size_local()),
configured_watchdog_timeout_(configuration_->get_watchdog_timeout()),
- pinged_clients_timer_(io_) {
+ pinged_clients_timer_(io_),
+ pending_security_update_id_(0) {
}
routing_manager_stub::~routing_manager_stub() {
@@ -760,7 +761,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
std::memcpy(&its_pending_security_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
sizeof(pending_security_update_id_t));
- host_->on_security_update_response(its_pending_security_update_id ,its_client);
+ on_security_update_response(its_pending_security_update_id ,its_client);
break;
}
case VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE: {
@@ -773,7 +774,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
std::memcpy(&its_pending_security_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
sizeof(pending_security_update_id_t));
- host_->on_security_update_response(its_pending_security_update_id ,its_client);
+ on_security_update_response(its_pending_security_update_id ,its_client);
break;
}
}
@@ -787,9 +788,20 @@ void routing_manager_stub::on_register_application(client_t _client) {
VSOMEIP_WARNING << "Reregistering application: " << std::hex << _client
<< ". Last registration might have been taken too long.";
} else {
- (void)host_->find_or_create_local(_client);
- std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
- routing_info_[_client].first = 0;
+ endpoint = host_->find_or_create_local(_client);
+ {
+ std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
+ routing_info_[_client].first = 0;
+ }
+
+ std::pair<uid_t, gid_t> its_uid_gid;
+ std::set<std::shared_ptr<policy> > its_policies;
+
+ security::get()->get_client_to_uid_gid_mapping(_client, its_uid_gid);
+ get_requester_policies(its_uid_gid.first, its_uid_gid.second, its_policies);
+
+ if (!its_policies.empty())
+ send_requester_policies({ _client }, its_policies);
}
}
@@ -2153,4 +2165,408 @@ bool routing_manager_stub::send_remove_security_policy_request( client_t _client
}
}
+bool
+routing_manager_stub::add_requester_policies(uid_t _uid, gid_t _gid,
+ const std::set<std::shared_ptr<policy> > &_policies) {
+
+ std::lock_guard<std::mutex> its_lock(requester_policies_mutex_);
+ auto found_uid = requester_policies_.find(_uid);
+ if (found_uid != requester_policies_.end()) {
+ auto found_gid = found_uid->second.find(_gid);
+ if (found_gid != found_uid->second.end()) {
+ found_gid->second.insert(_policies.begin(), _policies.end());
+ } else {
+ found_uid->second.insert(std::make_pair(_gid, _policies));
+ }
+ } else {
+ requester_policies_[_uid][_gid] = _policies;
+ }
+
+ // Check whether clients with uid/gid are already registered.
+ // If yes, update their policy
+ std::unordered_set<client_t> its_clients;
+ security::get()->get_clients(_uid, _gid, its_clients);
+
+ if (!its_clients.empty())
+ return send_requester_policies(its_clients, _policies);
+
+ return (true);
+}
+
+void
+routing_manager_stub::remove_requester_policies(uid_t _uid, gid_t _gid) {
+
+ std::lock_guard<std::mutex> its_lock(requester_policies_mutex_);
+ auto found_uid = requester_policies_.find(_uid);
+ if (found_uid != requester_policies_.end()) {
+ found_uid->second.erase(_gid);
+ if (found_uid->second.empty())
+ requester_policies_.erase(_uid);
+ }
+}
+
+void
+routing_manager_stub::get_requester_policies(uid_t _uid, gid_t _gid,
+ std::set<std::shared_ptr<policy> > &_policies) const {
+
+ std::lock_guard<std::mutex> its_lock(requester_policies_mutex_);
+ auto found_uid = requester_policies_.find(_uid);
+ if (found_uid != requester_policies_.end()) {
+ auto found_gid = found_uid->second.find(_gid);
+ if (found_gid != found_uid->second.end())
+ _policies = found_gid->second;
+ }
+}
+
+void
+routing_manager_stub::add_pending_security_update_handler(
+ pending_security_update_id_t _id, security_update_handler_t _handler) {
+
+ std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
+ security_update_handlers_[_id] = _handler;
+}
+
+void
+routing_manager_stub::add_pending_security_update_timer(
+ pending_security_update_id_t _id) {
+
+ std::shared_ptr<boost::asio::steady_timer> its_timer
+ = std::make_shared<boost::asio::steady_timer>(io_);
+
+ boost::system::error_code ec;
+ its_timer->expires_from_now(std::chrono::milliseconds(3000), ec);
+ if (!ec) {
+ its_timer->async_wait(
+ std::bind(
+ &routing_manager_stub::on_security_update_timeout,
+ shared_from_this(),
+ std::placeholders::_1, _id, its_timer));
+ } else {
+ VSOMEIP_ERROR << __func__
+ << "[" << std::dec << _id << "]: timer creation: "
+ << ec.message();
+ }
+ std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
+ security_update_timers_[_id] = its_timer;
+}
+
+bool
+routing_manager_stub::send_requester_policies(const std::unordered_set<client_t> &_clients,
+ const std::set<std::shared_ptr<policy> > &_policies) {
+
+ pending_security_update_id_t its_policy_id;
+
+ // serialize the policies and send them...
+ for (const auto p : _policies) {
+ std::vector<byte_t> its_policy_data;
+ if (p->serialize(its_policy_data)) {
+ std::vector<byte_t> its_message;
+ its_message.push_back(VSOMEIP_UPDATE_SECURITY_POLICY_INT);
+ its_message.push_back(0);
+ its_message.push_back(0);
+
+ uint32_t its_policy_size = static_cast<uint32_t>(its_policy_data.size() + sizeof(uint32_t));
+ its_message.push_back(VSOMEIP_LONG_BYTE0(its_policy_size));
+ its_message.push_back(VSOMEIP_LONG_BYTE1(its_policy_size));
+ its_message.push_back(VSOMEIP_LONG_BYTE2(its_policy_size));
+ its_message.push_back(VSOMEIP_LONG_BYTE3(its_policy_size));
+
+ its_policy_id = pending_security_update_add(_clients);
+ its_message.push_back(VSOMEIP_LONG_BYTE0(its_policy_id));
+ its_message.push_back(VSOMEIP_LONG_BYTE1(its_policy_id));
+ its_message.push_back(VSOMEIP_LONG_BYTE2(its_policy_id));
+ its_message.push_back(VSOMEIP_LONG_BYTE3(its_policy_id));
+
+ its_message.insert(its_message.end(), its_policy_data.begin(), its_policy_data.end());
+
+ for (const auto c : _clients) {
+ std::shared_ptr<endpoint> its_endpoint = host_->find_local(c);
+ if (its_endpoint)
+ its_endpoint->send(&its_message[0], static_cast<uint32_t>(its_message.size()));
+ }
+ }
+ }
+
+ return (true);
+}
+
+void routing_manager_stub::on_security_update_timeout(
+ const boost::system::error_code& _error,
+ pending_security_update_id_t _id,
+ std::shared_ptr<boost::asio::steady_timer> _timer) {
+ (void)_timer;
+ if (_error) {
+ // timer was cancelled
+ return;
+ }
+ security_update_state_e its_state = security_update_state_e::SU_UNKNOWN_USER_ID;
+ std::unordered_set<client_t> its_missing_clients = pending_security_update_get(_id);
+ {
+ // erase timer
+ std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
+ security_update_timers_.erase(_id);
+ }
+ {
+ // print missing responses and check if some clients did not respond because they already disconnected
+ if (!its_missing_clients.empty()) {
+ for (auto its_client : its_missing_clients) {
+ VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client
+ << " did not respond to the policy update / removal with ID: 0x" << std::hex << _id;
+ if (!host_->find_local(its_client)) {
+ VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client
+ << " is not connected anymore, do not expect answer for policy update / removal with ID: 0x"
+ << std::hex << _id;
+ pending_security_update_remove(_id, its_client);
+ }
+ }
+ }
+
+ its_missing_clients = pending_security_update_get(_id);
+ if (its_missing_clients.empty()) {
+ VSOMEIP_INFO << __func__ << ": Received all responses for "
+ "security update/removal ID: 0x" << std::hex << _id;
+ its_state = security_update_state_e::SU_SUCCESS;
+ }
+ {
+ // erase pending security update
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ pending_security_updates_.erase(_id);
+ }
+
+ // call handler with error on timeout or with SUCCESS if missing clients are not connected
+ std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
+ const auto found_handler = security_update_handlers_.find(_id);
+ if (found_handler != security_update_handlers_.end()) {
+ found_handler->second(its_state);
+ security_update_handlers_.erase(found_handler);
+ } else {
+ VSOMEIP_WARNING << __func__ << ": Callback not found for security update / removal with ID: 0x"
+ << std::hex << _id;
+ }
+ }
+}
+
+bool routing_manager_stub::update_security_policy_configuration(
+ uint32_t _uid, uint32_t _gid,
+ const std::shared_ptr<policy> &_policy,
+ const std::shared_ptr<payload> &_payload,
+ const security_update_handler_t &_handler) {
+
+ bool ret(true);
+
+ // cache security policy payload for later distribution to new registering clients
+ policy_cache_add(_uid, _payload);
+
+ // update security policy from configuration
+ security::get()->update_security_policy(_uid, _gid, _policy);
+
+ // Build requester policies for the services offered by the new policy
+ std::set<std::shared_ptr<policy> > its_requesters;
+ security::get()->get_requester_policies(_policy, its_requesters);
+
+ // and add them to the requester policy cache
+ add_requester_policies(_uid, _gid, its_requesters);
+
+ // determine currently connected clients
+ std::unordered_set<client_t> its_clients_to_inform;
+ auto its_epm = host_->get_endpoint_manager();
+ if (its_epm)
+ its_clients_to_inform = its_epm->get_connected_clients();
+
+ // add handler
+ pending_security_update_id_t its_id;
+ if (!its_clients_to_inform.empty()) {
+ its_id = pending_security_update_add(its_clients_to_inform);
+
+ add_pending_security_update_handler(its_id, _handler);
+ add_pending_security_update_timer(its_id);
+
+ // trigger all currently connected clients to update the security policy
+ uint32_t sent_counter(0);
+ uint32_t its_tranche =
+ uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1);
+ VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size()
+ << "] currently connected clients about policy update for UID: "
+ << std::dec << _uid << " with update ID: 0x" << std::hex << its_id;
+ for (auto its_client : its_clients_to_inform) {
+ if (!send_update_security_policy_request(its_client, its_id, _uid, _payload)) {
+ VSOMEIP_INFO << __func__ << ": Couldn't send update security policy "
+ << "request to client 0x" << std::hex << std::setw(4)
+ << std::setfill('0') << its_client << " policy UID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _gid
+ << " with update ID: 0x" << std::hex << its_id
+ << " as client already disconnected";
+ // remove client from expected answer list
+ pending_security_update_remove(its_id, its_client);
+ }
+ sent_counter++;
+ // Prevent burst
+ if (sent_counter % its_tranche == 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } else {
+ // if routing manager has no client call the handler directly
+ _handler(security_update_state_e::SU_SUCCESS);
+ }
+
+ return ret;
+}
+
+bool routing_manager_stub::remove_security_policy_configuration(
+ uint32_t _uid, uint32_t _gid, const security_update_handler_t &_handler) {
+
+ bool ret(true);
+
+ // remove security policy from configuration (only if there was a updateACL call before)
+ if (is_policy_cached(_uid)) {
+ if (!security::get()->remove_security_policy(_uid, _gid)) {
+ _handler(security_update_state_e::SU_UNKNOWN_USER_ID);
+ ret = false;
+ } else {
+ // remove policy from cache to prevent sending it to registering clients
+ policy_cache_remove(_uid);
+
+ // add handler
+ pending_security_update_id_t its_id;
+
+ // determine currently connected clients
+ std::unordered_set<client_t> its_clients_to_inform;
+ auto its_epm = host_->get_endpoint_manager();
+ if (its_epm)
+ its_clients_to_inform = its_epm->get_connected_clients();
+
+ if (!its_clients_to_inform.empty()) {
+ its_id = pending_security_update_add(its_clients_to_inform);
+
+ add_pending_security_update_handler(its_id, _handler);
+ add_pending_security_update_timer(its_id);
+
+ // trigger all clients to remove the security policy
+ uint32_t sent_counter(0);
+ uint32_t its_tranche =
+ uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1);
+ VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size()
+ << "] currently connected clients about policy removal for UID: "
+ << std::dec << _uid << " with update ID: " << its_id;
+ for (auto its_client : its_clients_to_inform) {
+ if (!send_remove_security_policy_request(its_client, its_id, _uid, _gid)) {
+ VSOMEIP_INFO << __func__ << ": Couldn't send remove security policy "
+ << "request to client 0x" << std::hex << std::setw(4)
+ << std::setfill('0') << its_client << " policy UID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _gid
+ << " with update ID: 0x" << std::hex << its_id
+ << " as client already disconnected";
+ // remove client from expected answer list
+ pending_security_update_remove(its_id, its_client);
+ }
+ sent_counter++;
+ // Prevent burst
+ if (sent_counter % its_tranche == 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } else {
+ // if routing manager has no client call the handler directly
+ _handler(security_update_state_e::SU_SUCCESS);
+ }
+ }
+ }
+ else {
+ _handler(security_update_state_e::SU_UNKNOWN_USER_ID);
+ ret = false;
+ }
+ return ret;
+}
+
+pending_security_update_id_t routing_manager_stub::pending_security_update_add(
+ const std::unordered_set<client_t>& _clients) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ if (++pending_security_update_id_ == 0) {
+ pending_security_update_id_++;
+ }
+ pending_security_updates_[pending_security_update_id_] = _clients;
+
+ return pending_security_update_id_;
+}
+
+std::unordered_set<client_t> routing_manager_stub::pending_security_update_get(
+ pending_security_update_id_t _id) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ std::unordered_set<client_t> its_missing_clients;
+ auto found_si = pending_security_updates_.find(_id);
+ if (found_si != pending_security_updates_.end()) {
+ its_missing_clients = pending_security_updates_[_id];
+ }
+ return its_missing_clients;
+}
+
+bool routing_manager_stub::pending_security_update_remove(
+ pending_security_update_id_t _id, client_t _client) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ auto found_si = pending_security_updates_.find(_id);
+ if (found_si != pending_security_updates_.end()) {
+ if (found_si->second.erase(_client)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool routing_manager_stub::is_pending_security_update_finished(
+ pending_security_update_id_t _id) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ bool ret(false);
+ auto found_si = pending_security_updates_.find(_id);
+ if (found_si != pending_security_updates_.end()) {
+ if (!found_si->second.size()) {
+ ret = true;
+ }
+ }
+ if (ret) {
+ pending_security_updates_.erase(_id);
+ }
+ return ret;
+}
+
+void routing_manager_stub::on_security_update_response(
+ pending_security_update_id_t _id, client_t _client) {
+ if (pending_security_update_remove(_id, _client)) {
+ if (is_pending_security_update_finished(_id)) {
+ // cancel timeout timer
+ {
+ std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
+ auto found_timer = security_update_timers_.find(_id);
+ if (found_timer != security_update_timers_.end()) {
+ boost::system::error_code ec;
+ found_timer->second->cancel(ec);
+ security_update_timers_.erase(found_timer);
+ } else {
+ VSOMEIP_WARNING << __func__ << ": Received all responses "
+ "for security update/removal ID: 0x"
+ << std::hex << _id << " but timeout already happened";
+ }
+ }
+
+ // call handler
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
+ auto found_handler = security_update_handlers_.find(_id);
+ if (found_handler != security_update_handlers_.end()) {
+ found_handler->second(security_update_state_e::SU_SUCCESS);
+ security_update_handlers_.erase(found_handler);
+ VSOMEIP_INFO << __func__ << ": Received all responses for "
+ "security update/removal ID: 0x" << std::hex << _id;
+ } else {
+ VSOMEIP_WARNING << __func__ << ": Received all responses "
+ "for security update/removal ID: 0x"
+ << std::hex << _id << " but didn't find handler";
+ }
+ }
+ }
+ }
+}
+
} // namespace vsomeip_v3