diff options
Diffstat (limited to 'implementation/routing/src/routing_manager_impl.cpp')
-rw-r--r-- | implementation/routing/src/routing_manager_impl.cpp | 1160 |
1 files changed, 719 insertions, 441 deletions
diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 07c0740..4ebca55 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -8,8 +8,9 @@ #include <memory> #include <sstream> #include <forward_list> +#include <thread> -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) #include <unistd.h> #include <cstdio> #include <time.h> @@ -30,10 +31,7 @@ #include "../include/routing_manager_stub.hpp" #include "../include/serviceinfo.hpp" #include "../../configuration/include/configuration.hpp" -#include "../../security/include/security.hpp" - #include "../../endpoints/include/endpoint_definition.hpp" -#include "../../endpoints/include/local_client_endpoint_impl.hpp" #include "../../endpoints/include/tcp_client_endpoint_impl.hpp" #include "../../endpoints/include/tcp_server_endpoint_impl.hpp" #include "../../endpoints/include/udp_client_endpoint_impl.hpp" @@ -42,13 +40,15 @@ #include "../../message/include/deserializer.hpp" #include "../../message/include/message_impl.hpp" #include "../../message/include/serializer.hpp" +#include "../../plugin/include/plugin_manager_impl.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../security/include/security.hpp" #include "../../service_discovery/include/constants.hpp" #include "../../service_discovery/include/defines.hpp" #include "../../service_discovery/include/runtime.hpp" #include "../../service_discovery/include/service_discovery.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" -#include "../../plugin/include/plugin_manager_impl.hpp" #ifdef USE_DLT #include "../../tracing/include/connector_impl.hpp" #endif @@ -89,11 +89,11 @@ routing_manager_impl::routing_manager_impl(routing_manager_host *_host) : } routing_manager_impl::~routing_manager_impl() { - utility::remove_lockfile(configuration_); - utility::reset_client_ids(); + utility::remove_lockfile(configuration_->get_network()); + utility::reset_client_ids(configuration_->get_network()); } -boost::asio::io_service & routing_manager_impl::get_io() { +boost::asio::io_context &routing_manager_impl::get_io() { return routing_manager_base::get_io(); } @@ -101,6 +101,34 @@ client_t routing_manager_impl::get_client() const { return routing_manager_base::get_client(); } +const vsomeip_sec_client_t *routing_manager_impl::get_sec_client() const { + + return (routing_manager_base::get_sec_client()); +} + +std::string routing_manager_impl::get_client_host() const { + return routing_manager_base::get_client_host(); +} + +void routing_manager_impl::set_client_host(const std::string &_client_host) { + routing_manager_base::set_client_host(_client_host); +} + +std::string routing_manager_impl::get_env(client_t _client) const { + + std::lock_guard<std::mutex> its_known_clients_lock(known_clients_mutex_); + return get_env_unlocked(_client); +} + +std::string routing_manager_impl::get_env_unlocked(client_t _client) const { + + auto find_client = known_clients_.find(_client); + if (find_client != known_clients_.end()) { + return (find_client->second); + } + return ""; +} + std::set<client_t> routing_manager_impl::find_local_clients(service_t _service, instance_t _instance) { return routing_manager_base::find_local_clients(_service, _instance); } @@ -109,18 +137,31 @@ client_t routing_manager_impl::find_local_client(service_t _service, instance_t return routing_manager_base::find_local_client(_service, _instance); } -bool routing_manager_impl::is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client, +bool routing_manager_impl::is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup) { - return routing_manager_base::is_subscribe_to_any_event_allowed(_credentials, _client, + + return routing_manager_base::is_subscribe_to_any_event_allowed(_sec_client, _client, _service, _instance, _eventgroup); } +void routing_manager_impl::add_known_client(client_t _client, const std::string &_client_host) { + routing_manager_base::add_known_client(_client, _client_host); +} + +bool routing_manager_impl::is_routing_manager() const { + return true; +} + void routing_manager_impl::init() { routing_manager_base::init(ep_mgr_impl_); - // TODO: Only instantiate the stub if needed - stub_ = std::make_shared<routing_manager_stub>(this, configuration_); - stub_->init(); + if (configuration_->is_routing_enabled()) { + stub_ = std::make_shared<routing_manager_stub>(this, configuration_); + stub_->init(); + } else { + VSOMEIP_INFO << "Internal message routing disabled!"; + } if (configuration_->is_sd_enabled()) { VSOMEIP_INFO<< "Service Discovery enabled. Trying to load module."; @@ -162,7 +203,7 @@ void routing_manager_impl::init() { } void routing_manager_impl::start() { -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) boost::asio::ip::address its_multicast; try { its_multicast = boost::asio::ip::address::from_string(configuration_->get_sd_multicast()); @@ -172,6 +213,20 @@ void routing_manager_impl::start() { << "\". Please check your configuration."; } + std::stringstream its_netmask_or_prefix; + auto its_unicast = configuration_->get_unicast_address(); + if (its_unicast.is_v4()) + its_netmask_or_prefix << "netmask:" << configuration_->get_netmask().to_string(); + else + its_netmask_or_prefix << "prefix:" << configuration_->get_prefix(); + + VSOMEIP_INFO << "Client [" + << std::hex << std::setw(4) << std::setfill('0') + << get_client() + << "] routes unicast:" << its_unicast.to_string() + << ", " + << its_netmask_or_prefix.str(); + netlink_connector_ = std::make_shared<netlink_connector>( host_->get_io(), configuration_->get_unicast_address(), its_multicast); netlink_connector_->register_net_if_changes_handler( @@ -185,7 +240,8 @@ void routing_manager_impl::start() { } #endif - stub_->start(); + if (stub_) + stub_->start(); host_->on_state(state_type_e::ST_REGISTERED); if (configuration_->log_version()) { @@ -195,7 +251,7 @@ void routing_manager_impl::start() { version_log_timer_.async_wait(std::bind(&routing_manager_impl::log_version_timer_cbk, this, std::placeholders::_1)); } -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) if (configuration_->log_memory()) { std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); boost::system::error_code ec; @@ -231,7 +287,7 @@ void routing_manager_impl::stop() { std::lock_guard<std::mutex> its_lock(local_services_mutex_); for (const auto& s : local_services_) { for (const auto& i : s.second) { - if (std::get<2>(i.second) == client_) { + if (std::get<2>(i.second) == get_client()) { its_services[s.first][i.first] = i.second; } } @@ -249,7 +305,7 @@ void routing_manager_impl::stop() { std::lock_guard<std::mutex> its_lock(version_log_timer_mutex_); version_log_timer_.cancel(); } -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) { boost::system::error_code ec; std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); @@ -276,9 +332,10 @@ void routing_manager_impl::stop() { if (discovery_) discovery_->stop(); - stub_->stop(); + if (stub_) + stub_->stop(); - for (const auto& client : ep_mgr_->get_connected_clients()) { + for (const auto client : ep_mgr_->get_connected_clients()) { if (client != VSOMEIP_ROUTING_CLIENT) { remove_local(client, true); } @@ -317,7 +374,7 @@ bool routing_manager_impl::erase_offer_command(service_t _service, instance_t _i if (!found_service_instance->second.empty()) { // check for other commands to be processed auto its_command = found_service_instance->second.front(); - if (std::get<0>(its_command) == VSOMEIP_OFFER_SERVICE) { + if (std::get<0>(its_command) == uint8_t(protocol::id_e::OFFER_SERVICE_ID)) { io_.post([&, its_command, _service, _instance](){ offer_service(std::get<1>(its_command), _service, _instance, std::get<2>(its_command), std::get<3>(its_command), false); @@ -355,7 +412,8 @@ bool routing_manager_impl::offer_service(client_t _client, // only queue commands if method was NOT called via erase_offer_command() if (_must_queue) { - if (!insert_offer_command(_service, _instance, VSOMEIP_OFFER_SERVICE, + if (!insert_offer_command(_service, _instance, + uint8_t(protocol::id_e::OFFER_SERVICE_ID), _client, _major, _minor)) { return false; } @@ -364,15 +422,8 @@ bool routing_manager_impl::offer_service(client_t _client, // Check if the application hosted by routing manager is allowed to offer // offer_service requests of local proxies are checked in rms::on:message if (_client == get_client()) { -#ifdef _WIN32 - std::uint32_t its_routing_uid = ANY_UID; - std::uint32_t its_routing_gid = ANY_GID; -#else - std::uint32_t its_routing_uid = getuid(); - std::uint32_t its_routing_gid = getgid(); -#endif - if (!security::get()->is_offer_allowed(its_routing_uid, its_routing_gid, - _client, _service, _instance)) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_offer( + get_sec_client(), _service, _instance)) { VSOMEIP_WARNING << "routing_manager_impl::offer_service: " << std::hex << "Security: Client 0x" << _client << " isn't allowed to offer the following service/instance " @@ -412,7 +463,8 @@ bool routing_manager_impl::offer_service(client_t _client, && ps.instance_ == _instance && ps.major_ == _major) { insert_subscription(ps.service_, ps.instance_, - ps.eventgroup_, ps.event_, client_, &its_already_subscribed_events); + ps.eventgroup_, ps.event_, nullptr, + get_client(), &its_already_subscribed_events); #if 0 VSOMEIP_ERROR << __func__ << ": event=" @@ -425,8 +477,9 @@ bool routing_manager_impl::offer_service(client_t _client, send_pending_subscriptions(_service, _instance, _major); } - stub_->on_offer_service(_client, _service, _instance, _major, _minor); - on_availability(_service, _instance, true, _major, _minor); + if (stub_) + stub_->on_offer_service(_client, _service, _instance, _major, _minor); + on_availability(_service, _instance, availability_state_e::AS_AVAILABLE, _major, _minor); erase_offer_command(_service, _instance); return true; } @@ -451,7 +504,8 @@ void routing_manager_impl::stop_offer_service(client_t _client, << " (" << std::boolalpha << _must_queue << ")"; if (_must_queue) { - if (!insert_offer_command(_service, _instance, VSOMEIP_STOP_OFFER_SERVICE, + if (!insert_offer_command(_service, _instance, + uint8_t(protocol::id_e::STOP_OFFER_SERVICE_ID), _client, _major, _minor)) { return; } @@ -476,8 +530,9 @@ void routing_manager_impl::stop_offer_service(client_t _client, } on_stop_offer_service(_client, _service, _instance, _major, _minor); - stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor); - on_availability(_service, _instance, false, _major, _minor); + if (stub_) + stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor); + on_availability(_service, _instance, availability_state_e::AS_UNAVAILABLE, _major, _minor); } else { VSOMEIP_WARNING << __func__ << " received STOP_OFFER(" << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" @@ -503,7 +558,7 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, auto its_info = find_service(_service, _instance); if (!its_info) { - requested_service_add(_client, _service, _instance, _major, _minor); + add_requested_service(_client, _service, _instance, _major, _minor); if (discovery_) { if (!configuration_->is_local_service(_service, _instance)) { // Non local service instance ~> tell SD to find it! @@ -525,7 +580,7 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, || DEFAULT_MINOR == its_info->get_minor() || _minor == ANY_MINOR)) { if(!its_info->is_local()) { - requested_service_add(_client, _service, _instance, _major, _minor); + add_requested_service(_client, _service, _instance, _major, _minor); if (discovery_) { // Non local service instance ~> tell SD to find it! discovery_->request_service(_service, _instance, _major, @@ -538,12 +593,15 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, } if (_client == get_client()) { - stub_->create_local_receiver(); + if (stub_) + stub_->create_local_receiver(); + + protocol::service its_request(_service, _instance, _major, _minor); + std::set<protocol::service> requests; + requests.insert(its_request); - service_data_t request = { _service, _instance, _major, _minor }; - std::set<service_data_t> requests; - requests.insert(request); - stub_->handle_requests(_client, requests); + if (stub_) + stub_->handle_requests(_client, requests); } } @@ -560,7 +618,7 @@ void routing_manager_impl::release_service(client_t _client, service_t _service, remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); } routing_manager_base::release_service(_client, _service, _instance); - requested_service_remove(_client, _service, _instance); + remove_requested_service(_client, _service, _instance, ANY_MAJOR, ANY_MINOR); std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); if (its_info && !its_info->is_local()) { @@ -582,9 +640,11 @@ void routing_manager_impl::release_service(client_t _client, service_t _service, } } -void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event) { +void routing_manager_impl::subscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { VSOMEIP_INFO << "SUBSCRIBE(" << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" @@ -600,21 +660,25 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, _eventgroup, _event, subscription_state_e::IS_SUBSCRIBING); #endif auto self = shared_from_this(); - host_->on_subscription(_service, _instance, _eventgroup, _client, _uid, _gid, true, - [this, self, _client, _uid, _gid, _service, _instance, _eventgroup, - _event, _major] + host_->on_subscription(_service, _instance, _eventgroup, _client, + _sec_client, get_env(_client), true, + [this, self, _client, _sec_client, _service, _instance, _eventgroup, + _major, _event, _filter] (const bool _subscription_accepted) { (void) ep_mgr_->find_or_create_local(_client); if (!_subscription_accepted) { - stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, _event); + if (stub_) + stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, _event); VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex << _client << std::dec << " for eventgroup: 0x" << _eventgroup << " rejected from application handler."; return; - } else { + } else if (stub_) { stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); } - routing_manager_base::subscribe(_client, _uid, _gid, _service, _instance, _eventgroup, _major, _event); + routing_manager_base::subscribe(_client, _sec_client, + _service, _instance, _eventgroup, _major, + _event, _filter); #ifdef VSOMEIP_ENABLE_COMPAT send_pending_notify_ones(_service, _instance, _eventgroup, _client); routing_manager_base::erase_incoming_subscription_state(_client, _service, _instance, @@ -631,7 +695,7 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, // handle_subscription_state. std::unique_lock<std::mutex> its_critical(remote_subscription_state_mutex_); bool inserted = insert_subscription(_service, _instance, _eventgroup, - _event, _client, &its_already_subscribed_events); + _event, _filter, _client, &its_already_subscribed_events); const bool subscriber_is_rm_host = (get_client() == _client); if (inserted) { if (0 == its_local_client) { @@ -654,17 +718,20 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, } } else { its_critical.unlock(); - if (is_available(_service, _instance, _major)) { + if (is_available(_service, _instance, _major) && stub_) { stub_->send_subscribe(ep_mgr_->find_local(_service, _instance), - _client, _service, _instance, _eventgroup, _major, _event, - PENDING_SUBSCRIPTION_ID); + _client, _service, _instance, _eventgroup, _major, + _event, _filter, PENDING_SUBSCRIPTION_ID); } } } if (subscriber_is_rm_host) { std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); subscription_data_t subscription = { - _service, _instance, _eventgroup, _major, _event, _uid, _gid + _service, _instance, + _eventgroup, _major, + _event, _filter, + *_sec_client }; pending_subscriptions_.insert(subscription); } @@ -674,8 +741,10 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, } } -void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { +void routing_manager_impl::unsubscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) { VSOMEIP_INFO << "UNSUBSCRIBE(" << std::hex << std::setw(4) << std::setfill('0') << _client << "): [" @@ -702,7 +771,8 @@ void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, } if (discovery_) { - host_->on_subscription(_service, _instance, _eventgroup, _client, _uid, _gid, false, + host_->on_subscription(_service, _instance, _eventgroup, _client, + _sec_client, get_env(_client), false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); if (0 == find_local_client(_service, _instance)) { if (get_client() == _client) { @@ -728,10 +798,11 @@ void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, if (get_client() == _client) { std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); remove_pending_subscription(_service, _instance, _eventgroup, _event); - stub_->send_unsubscribe( - ep_mgr_->find_local(_service, _instance), - _client, _service, _instance, _eventgroup, _event, - PENDING_SUBSCRIPTION_ID); + if (stub_) + stub_->send_unsubscribe( + ep_mgr_->find_local(_service, _instance), + _client, _service, _instance, _eventgroup, _event, + PENDING_SUBSCRIPTION_ID); } } ep_mgr_impl_->clear_multicast_endpoints(_service, _instance); @@ -742,15 +813,16 @@ void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, } bool routing_manager_impl::send(client_t _client, - std::shared_ptr<message> _message) { - return routing_manager_base::send(_client, _message); + std::shared_ptr<message> _message, bool _force) { + + return routing_manager_base::send(_client, _message, _force); } bool routing_manager_impl::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, bool _reliable, - client_t _bound_client, - credentials_t _credentials, - uint8_t _status_check, bool _sent_from_remote) { + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, bool _force) { + bool is_sent(false); if (_size > VSOMEIP_MESSAGE_TYPE_POS) { std::shared_ptr<endpoint> its_target; @@ -775,15 +847,14 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } else if (is_notification && _client && !is_service_discovery) { // Selective notifications! if (_client == get_client()) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #endif - deliver_message(_data, _size, _instance, _reliable, _bound_client, _credentials, _status_check, _sent_from_remote); + deliver_message(_data, _size, _instance, _reliable, + _bound_client, _sec_client, + _status_check, _sent_from_remote); return true; } its_target = find_local(_client); @@ -794,16 +865,15 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, if ((is_request && its_client == get_client()) || (is_response && find_local_client(its_service, _instance) == get_client()) || (is_notification && find_local_client(its_service, _instance) == VSOMEIP_ROUTING_CLIENT)) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif - is_sent = send_local(its_target, get_client(), _data, _size, _instance, _reliable, VSOMEIP_SEND, _status_check); + is_sent = send_local(its_target, get_client(), _data, _size, _instance, + _reliable, protocol::id_e::SEND_ID, _status_check); } else { // Check whether hosting application should get the message // If not, check routes to external @@ -811,7 +881,8 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, || (find_local_client(its_service, _instance) == host_->get_client() && is_request)) { // TODO: Find out how to handle session id here - is_sent = deliver_message(_data, _size, _instance, _reliable, VSOMEIP_ROUTING_CLIENT, _credentials, _status_check); + is_sent = deliver_message(_data, _size, _instance, _reliable, + VSOMEIP_ROUTING_CLIENT, _sec_client, _status_check); } else { e2e_buffer its_buffer; @@ -844,13 +915,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, its_service, _instance, _reliable); if (its_target) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #endif is_sent = its_target->send(_data, _size); } else { @@ -868,7 +936,8 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, std::shared_ptr<serviceinfo> its_info(find_service(its_service, _instance)); if (its_info || is_service_discovery) { if (is_notification && !is_service_discovery) { - send_local_notification(get_client(), _data, _size, _instance, _reliable, _status_check); + (void)send_local_notification(get_client(), _data, _size, _instance, + _reliable, _status_check, _force); method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); @@ -930,13 +999,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } #ifdef USE_DLT if (has_sent) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif } @@ -962,13 +1028,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, (sd_info_ ? sd_info_->get_endpoint(false) : nullptr) : its_info->get_endpoint(_reliable); if (its_target) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #endif is_sent = its_target->send(_data, _size); } else { @@ -1009,6 +1072,7 @@ bool routing_manager_impl::send_to( const client_t _client, const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message) { + bool is_sent(false); std::shared_ptr<serializer> its_serializer(get_serializer()); @@ -1050,19 +1114,17 @@ bool routing_manager_impl::send_to( bool routing_manager_impl::send_to( const std::shared_ptr<endpoint_definition> &_target, const byte_t *_data, uint32_t _size, instance_t _instance) { + std::shared_ptr<endpoint> its_endpoint = ep_mgr_impl_->find_server_endpoint( _target->get_remote_port(), _target->is_reliable()); if (its_endpoint) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_endpoint, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #else (void) _instance; #endif @@ -1081,13 +1143,10 @@ bool routing_manager_impl::send_via_sd( if (its_endpoint) { #ifdef USE_DLT if (tc_->is_sd_enabled()) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_endpoint, true, 0x0)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif @@ -1136,13 +1195,15 @@ void routing_manager_impl::register_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _notifier, const std::set<eventgroup_t> &_eventgroups, event_type_e _type, - reliability_type_e _reliability, bool _is_provided) { + reliability_type_e _reliability, bool _is_provided, bool _is_cyclic) { + routing_manager_base::register_event(_client, _service, _instance, _notifier, _eventgroups, _type, _reliability, - std::chrono::milliseconds::zero(), false, true, - nullptr, + (_is_cyclic ? std::chrono::milliseconds(1) + : std::chrono::milliseconds::zero()), + false, true, nullptr, _is_provided, true); } @@ -1172,7 +1233,7 @@ void routing_manager_impl::notify_one(service_t _service, instance_t _instance, if (its_event) { std::set<std::shared_ptr<endpoint_definition> > its_targets; const auto its_reliability = its_event->get_reliability(); - for (const auto& g : its_event->get_eventgroups()) { + for (const auto g : its_event->get_eventgroups()) { const auto its_eventgroup = find_eventgroup(_service, _instance, g); if (its_eventgroup) { const auto its_subscriptions = its_eventgroup->get_remote_subscriptions(); @@ -1197,7 +1258,7 @@ void routing_manager_impl::notify_one(service_t _service, instance_t _instance, if (its_targets.size() > 0) { for (const auto &its_target : its_targets) { - its_event->set_payload(_payload, _client, its_target, _force); + its_event->set_payload(_payload, _client, its_target); } } } else { @@ -1209,11 +1270,11 @@ void routing_manager_impl::notify_one(service_t _service, instance_t _instance, } void routing_manager_impl::on_availability(service_t _service, instance_t _instance, - bool _is_available, major_version_t _major, minor_version_t _minor) { + availability_state_e _state, major_version_t _major, minor_version_t _minor) { // insert subscriptions of routing manager into service discovery // to send SubscribeEventgroup after StopOffer / Offer was received - if (_is_available) { + if (_state == availability_state_e::AS_AVAILABLE) { if (discovery_) { const client_t its_local_client = find_local_client(_service, _instance); // remote service @@ -1241,7 +1302,7 @@ void routing_manager_impl::on_availability(service_t _service, instance_t _insta } } } - host_->on_availability(_service, _instance, _is_available, _major, _minor); + host_->on_availability(_service, _instance, _state, _major, _minor); } @@ -1273,7 +1334,7 @@ bool routing_manager_impl::offer_service_remotely(service_t _service, << "]"; ret = false; } else { - if (!stub_->send_provided_event_resend_request(its_offering_client, + if (stub_ && !stub_->send_provided_event_resend_request(its_offering_client, pending_remote_offer_add(_service, _instance))) { VSOMEIP_ERROR << __func__ << ": Couldn't send event resend" << "request to client 0x" << std::hex << std::setw(4) @@ -1332,7 +1393,7 @@ bool routing_manager_impl::stop_offer_service_remotely(service_t _service, clear_remote_subscriber(_service, _instance); if (discovery_ && its_info) { - discovery_->stop_offer_service(its_info); + discovery_->stop_offer_service(its_info, true); its_info->set_endpoint(std::shared_ptr<endpoint>(), _reliable); } } else { @@ -1344,7 +1405,7 @@ bool routing_manager_impl::stop_offer_service_remotely(service_t _service, // ensure to not send StopOffer for endpoint on which the service is // still offered its_copied_info->set_endpoint(std::shared_ptr<endpoint>(), !_reliable); - discovery_->stop_offer_service(its_copied_info); + discovery_->stop_offer_service(its_copied_info, true); } } @@ -1353,8 +1414,8 @@ bool routing_manager_impl::stop_offer_service_remotely(service_t _service, } void routing_manager_impl::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver, const boost::asio::ip::address &_destination, - client_t _bound_client, credentials_t _credentials, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port) { #if 0 @@ -1369,10 +1430,12 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, method_t its_method; uint8_t its_check_status = e2e::profile_interface::generic_check_status::E2E_OK; instance_t its_instance(0x0); + message_type_e its_message_type; #ifdef USE_DLT bool is_forwarded(true); #endif if (_size >= VSOMEIP_SOMEIP_HEADER_SIZE) { + its_message_type = static_cast<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]); its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); if (its_service == VSOMEIP_SD_SERVICE) { @@ -1381,7 +1444,11 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, if (discovery_ && its_method == sd::method) { if (configuration_->get_sd_port() == _remote_port) { if (!_remote_address.is_unspecified()) { - discovery_->on_message(_data, _size, _remote_address, _destination); + // ACL check SD message + if(!is_acl_message_allowed(_receiver, its_service, ANY_INSTANCE, _remote_address)) { + return; + } + discovery_->on_message(_data, _size, _remote_address, _is_multicast); } else { VSOMEIP_ERROR << "Ignored SD message from unknown address."; } @@ -1391,7 +1458,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } } } else { - if(_destination.is_multicast()) { + if (_is_multicast) { its_instance = ep_mgr_impl_->find_instance_multicast(its_service, _remote_address); } else { its_instance = ep_mgr_impl_->find_instance(its_service, _receiver); @@ -1417,7 +1484,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } //Ignore messages with invalid message type if(_size >= VSOMEIP_MESSAGE_TYPE_POS) { - if(!utility::is_valid_message_type(static_cast<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]))) { + if(!utility::is_valid_message_type(its_message_type)) { VSOMEIP_ERROR << "Ignored SomeIP message with invalid message type."; return; } @@ -1436,7 +1503,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } // Security checks if enabled! - if (security::get()->is_enabled()) { + if (configuration_->is_security_enabled()) { if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { client_t requester = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_CLIENT_POS_MIN], @@ -1456,7 +1523,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, << " which is already used locally ~> Skip message!"; return; } - if (!security::get()->is_remote_client_allowed()) { + if (!configuration_->is_remote_access_allowed()) { // check if policy allows remote requests. VSOMEIP_WARNING << "routing_manager_impl::on_message: " << std::hex << "Security: Remote client with client ID 0x" << requester @@ -1485,19 +1552,22 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } #endif } + + // ACL check message + if(!is_acl_message_allowed(_receiver, its_service, its_instance, _remote_address)) { + return; + } + // Common way of message handling #ifdef USE_DLT is_forwarded = #endif on_message(its_service, its_instance, _data, _size, _receiver->is_reliable(), - _bound_client, _credentials, its_check_status, true); + _bound_client, _sec_client, its_check_status, true); } } #ifdef USE_DLT if (is_forwarded) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; const boost::asio::ip::address_v4 its_remote_address = _remote_address.is_v4() ? _remote_address.to_v4() : @@ -1508,19 +1578,16 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, trace::protocol_e::udp; its_header.prepare(its_remote_address, _remote_port, its_protocol, false, its_instance); - tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, - its_data_size); + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); } #endif } -bool routing_manager_impl::on_message( - service_t _service, instance_t _instance, - const byte_t *_data, length_t _size, - bool _reliable, client_t _bound_client, - credentials_t _credentials, - uint8_t _check_status, - bool _is_from_remote) { +bool routing_manager_impl::on_message(service_t _service, instance_t _instance, + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _check_status, bool _is_from_remote) { #if 0 std::stringstream msg; msg << "rmi::on_message(" @@ -1541,15 +1608,29 @@ bool routing_manager_impl::on_message( _data[VSOMEIP_CLIENT_POS_MAX]); } +#if 0 + // ACL message check for local test purpouse + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + if (its_info) { + std::shared_ptr<endpoint> _receiver = its_info->get_endpoint(_reliable); + if (_receiver && _receiver.get()) { + if(!is_acl_message_allowed(_receiver.get(), _service, _instance, + boost::asio::ip::address_v4::from_string("127.0.0.1"))) { + return false; + } + } + } +#endif + if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { is_forwarded = deliver_notification(_service, _instance, _data, _size, - _reliable, _bound_client, _credentials, _check_status, _is_from_remote); + _reliable, _bound_client, _sec_client, _check_status, _is_from_remote); } else if (its_client == host_->get_client()) { deliver_message(_data, _size, _instance, - _reliable, _bound_client, _credentials, _check_status, _is_from_remote); + _reliable, _bound_client, _sec_client, _check_status, _is_from_remote); } else { send(its_client, _data, _size, _instance, _reliable, - _bound_client, _credentials, _check_status, _is_from_remote); //send to proxy + _bound_client, _sec_client, _check_status, _is_from_remote, false); //send to proxy } return is_forwarded; } @@ -1689,7 +1770,7 @@ void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _se if (discovery_) { if (its_info->get_major() == _major && its_info->get_minor() == _minor) { - discovery_->stop_offer_service(its_info); + discovery_->stop_offer_service(its_info, true); } } del_routing_info(_service, _instance, (its_reliable_endpoint != nullptr), @@ -1782,11 +1863,11 @@ void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _se } bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, - instance_t _instance, bool _reliable, client_t _bound_client, credentials_t _credentials, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check, bool _is_from_remote) { + bool is_delivered(false); - std::uint32_t its_sender_uid = std::get<0>(_credentials); - std::uint32_t its_sender_gid = std::get<1>(_credentials); auto its_deserializer = get_deserializer(); its_deserializer->set_data(_data, _size); @@ -1798,8 +1879,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, its_message->set_instance(_instance); its_message->set_reliable(_reliable); its_message->set_check_result(_status_check); - its_message->set_uid(std::get<0>(_credentials)); - its_message->set_gid(std::get<1>(_credentials)); + if (_sec_client) + its_message->set_sec_client(*_sec_client); + its_message->set_env(get_env(_bound_client)); if (!_is_from_remote) { if (utility::is_notification(its_message->get_message_type())) { @@ -1814,9 +1896,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, << " ~> Skip message!"; return false; } else { - if (!security::get()->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to receive a notification from service/instance/event " @@ -1828,7 +1910,8 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, } } } else if (utility::is_request(its_message->get_message_type())) { - if (security::get()->is_enabled() + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() && its_message->get_client() != _bound_client) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message:" @@ -1841,9 +1924,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, return false; } - if (!security::get()->is_client_allowed(its_sender_uid, its_sender_gid, - its_message->get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(_sec_client, + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to send a request to service/instance/method " @@ -1864,9 +1947,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, << " ~> Skip message!"; return false; } else { - if (!security::get()->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to receive a response from service/instance/method " @@ -1879,7 +1962,7 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, } } } else { - if (!security::get()->is_remote_client_allowed()) { + if (!configuration_->is_remote_access_allowed()) { // if the message is from remote, check if // policy allows remote requests. VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() @@ -1892,9 +1975,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, << " ~> Skip message!"; return false; } else if (utility::is_notification(its_message->get_message_type())) { - if (!security::get()->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to receive a notification from service/instance/event " @@ -1918,10 +2001,10 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, bool routing_manager_impl::deliver_notification( service_t _service, instance_t _instance, - const byte_t *_data, length_t _length, - bool _reliable, client_t _bound_client, - credentials_t _credentials, + const byte_t *_data, length_t _length, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check, bool _is_from_remote) { + event_t its_event_id = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); client_t its_client_id = VSOMEIP_BYTES_TO_WORD( @@ -1934,7 +2017,7 @@ bool routing_manager_impl::deliver_notification( // no subscribers for this specific event / check subscriptions // to other events of the event's eventgroups bool cache_event = false; - for (const auto& eg : its_event->get_eventgroups()) { + for (const auto eg : its_event->get_eventgroups()) { std::shared_ptr<eventgroupinfo> egi = find_eventgroup(_service, _instance, eg); if (egi) { for (const auto &e : egi->get_events()) { @@ -1957,37 +2040,30 @@ bool routing_manager_impl::deliver_notification( return true; // as there is nothing to do } } - const uint32_t its_length(utility::get_payload_size(_data, _length)); - if (its_length != _length - VSOMEIP_FULL_HEADER_SIZE) { - VSOMEIP_ERROR << "Message length mismatch, dropping message!"; - return false; - } - std::shared_ptr<payload> its_payload - = runtime::get()->create_payload(&_data[VSOMEIP_PAYLOAD_POS], - its_length); - if (!its_event->set_payload_dont_notify(its_payload)) { - // do not forward the notification as it was filtered - return false; - } } + auto its_length = utility::get_payload_size(_data, _length); + auto its_payload = runtime::get()->create_payload( + &_data[VSOMEIP_PAYLOAD_POS], its_length); + // incoming events statistics (void) insert_event_statistics( - _service, - _instance, - its_event_id, - utility::get_payload_size(_data, _length)); + _service, _instance, its_event_id, its_length); + // Ignore the filter for messages coming from other local clients + // as the filter was already applied there. + auto its_subscribers + = its_event->update_and_get_filtered_subscribers(its_payload, _is_from_remote); if (its_event->get_type() != event_type_e::ET_SELECTIVE_EVENT) { - for (const auto& its_local_client : its_event->get_subscribers()) { + for (const auto its_local_client : its_subscribers) { if (its_local_client == host_->get_client()) { deliver_message(_data, _length, _instance, _reliable, - _bound_client, _credentials, _status_check, _is_from_remote); + _bound_client, _sec_client, _status_check, _is_from_remote); } else { std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); if (its_local_target) { send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, - _data, _length, _instance, _reliable, VSOMEIP_SEND, _status_check); + _data, _length, _instance, _reliable, protocol::id_e::SEND_ID, _status_check); } } } @@ -1998,20 +2074,20 @@ bool routing_manager_impl::deliver_notification( if (its_client_id == VSOMEIP_ROUTING_CLIENT) its_client_id = get_client(); - auto its_subscribers = its_event->get_subscribers(); if (its_subscribers.find(its_client_id) != its_subscribers.end()) { if (its_client_id == host_->get_client()) { deliver_message(_data, _length, _instance, _reliable, - _bound_client, _credentials, _status_check, _is_from_remote); + _bound_client, _sec_client, _status_check, _is_from_remote); } else { std::shared_ptr<endpoint> its_local_target = find_local(its_client_id); if (its_local_target) { send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, - _data, _length, _instance, _reliable, VSOMEIP_SEND, _status_check); + _data, _length, _instance, _reliable, protocol::id_e::SEND_ID, _status_check); } } } } + } else { VSOMEIP_WARNING << __func__ << ": Event [" << std::hex << std::setw(4) << std::setfill('0') << _service << "." @@ -2048,10 +2124,10 @@ std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoin its_service_endpoint->add_default_target(VSOMEIP_SD_SERVICE, _address, _port); if (!_reliable) { - auto its_udp_server_endpoint_impl = std::dynamic_pointer_cast< + auto its_server_endpoint = std::dynamic_pointer_cast< udp_server_endpoint_impl>(its_service_endpoint); - if (its_udp_server_endpoint_impl) - its_udp_server_endpoint_impl->join(_address); + if (its_server_endpoint) + its_server_endpoint->join(_address); } } else { VSOMEIP_ERROR<< "Service Discovery endpoint could not be created. " @@ -2102,6 +2178,37 @@ routing_manager_impl::get_offered_service_instances(service_t _service) const { return its_instances; } +bool routing_manager_impl::is_acl_message_allowed(endpoint *_receiver, + service_t _service, instance_t _instance, + const boost::asio::ip::address &_remote_address) const { + if (message_acceptance_handler_ && _receiver) { + // Check the ACL whitelist rules if shall accepts the message + + message_acceptance_t message_acceptance { +#if VSOMEIP_BOOST_VERSION < 106600 + static_cast<uint32_t>(_remote_address.to_v4().to_ulong()), _receiver->get_local_port(), +#else + _remote_address.to_v4().to_uint(), _receiver->get_local_port(), +#endif + _receiver->is_local(), _service, _instance + }; + if (!message_acceptance_handler_(message_acceptance)) { + VSOMEIP_WARNING << "Message from " << _remote_address.to_string() + << std::hex << " with service/instance " << _instance << "/" + << _instance << " was rejected by the ACL check."; + return false; + } +#if 0 + else { + VSOMEIP_INFO << "Message from " << _remote_address.to_string() + << std::hex << " with service/instance " << _instance << "/" + << _instance << " was accepted by the ACL check."; + } +#endif + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// // PRIVATE /////////////////////////////////////////////////////////////////////////////// @@ -2166,20 +2273,7 @@ void routing_manager_impl::remove_local(client_t _client, bool _remove_uid) { } routing_manager_base::remove_local(_client, clients_subscriptions, _remove_uid); - std::forward_list<std::pair<service_t, instance_t>> services_to_release_; - { - std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - auto its_client = requested_services_.find(_client); - if (its_client != requested_services_.end()) { - for (const auto& its_service : its_client->second) { - for (const auto& its_instance : its_service.second) { - services_to_release_.push_front( - { its_service.first, its_instance.first }); - } - } - } - } - for (const auto &s : services_to_release_) { + for (const auto &s : get_requested_services(_client)) { release_service(_client, s.first, s.second); } } @@ -2210,7 +2304,7 @@ void routing_manager_impl::add_routing_info( std::lock_guard<std::mutex> its_lock(routing_state_mutex_); if (routing_state_ == routing_state_e::RS_SUSPENDED) { - VSOMEIP_INFO << "rmi::" << __func__ << " We are suspened --> do nothing."; + VSOMEIP_INFO << "rmi::" << __func__ << " We are suspended --> do nothing."; return; } @@ -2280,89 +2374,63 @@ void routing_manager_impl::add_routing_info( { bool connected(false); std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - for(const auto &client_id : requested_services_) { - auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second == ANY_MINOR)) { - // SWS_SD_00376 establish TCP connection to service - // service is marked as available later in on_connect() - if(!connected) { - if (udp_inserted) { - // atomically create reliable and unreliable endpoint - ep_mgr_impl_->find_or_create_remote_client( - _service, _instance); - } else { - ep_mgr_impl_->find_or_create_remote_client( - _service, _instance, true); - } - connected = true; - } - its_info->add_client(client_id.first); - break; - } - } + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + if (!connected) { + if (udp_inserted) { + // atomically create reliable and unreliable endpoint + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance); + } else { + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance, true); } + connected = true; } + its_info->add_client(its_client); } } } else if (_reliable_port != ILLEGAL_PORT && is_reliable_known) { std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - bool connected(false); - for(const auto &client_id : requested_services_) { - auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second == ANY_MINOR)) { - std::shared_ptr<endpoint> ep = its_info->get_endpoint(true); - if (ep) { - if (ep->is_established() && - !stub_->contained_in_routing_info( - VSOMEIP_ROUTING_CLIENT, _service, _instance, - its_info->get_major(), - its_info->get_minor())) { - on_availability(_service, _instance, - true, its_info->get_major(), its_info->get_minor()); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, - _service, _instance, - its_info->get_major(), - its_info->get_minor()); - if (discovery_) { - discovery_->on_endpoint_connected( - _service, _instance, ep); - } - } - } else { - // no endpoint yet, but requested -> create one - - // SWS_SD_00376 establish TCP connection to service - // service is marked as available later in on_connect() - if (!connected) { - ep_mgr_impl_->find_or_create_remote_client( - _service, _instance, true); - connected = true; - } - its_info->add_client(client_id.first); - } - break; - } + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(true); + if (ep) { + if (ep->is_established() && + stub_ && + !stub_->contained_in_routing_info( + VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), + its_info->get_minor())) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + _service, _instance, + its_info->get_major(), + its_info->get_minor()); + if (discovery_) { + discovery_->on_endpoint_connected( + _service, _instance, ep); } } + } else { + // no endpoint yet, but requested -> create one + + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance, true); + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + its_info->add_client(its_client); + } } + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, + its_info->get_major(), its_info->get_minor()); } } @@ -2375,38 +2443,28 @@ void routing_manager_impl::add_routing_info( { bool connected(false); std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - for (const auto &client_id : requested_services_) { - const auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - const auto found_instance = found_service->second.find( - _instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second - == ANY_MINOR)) { - if(!connected) { - ep_mgr_impl_->find_or_create_remote_client(_service, _instance, - false); - connected = true; - } - its_info->add_client(client_id.first); - break; - } - } - } + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + if (!connected) { + ep_mgr_impl_->find_or_create_remote_client(_service, _instance, + false); + connected = true; } + its_info->add_client(its_client); } } } if (!is_reliable_known && !tcp_inserted) { // UDP only service can be marked as available instantly - on_availability(_service, _instance, true, _major, _minor); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, _major, _minor); + if (stub_) + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, _major, _minor); + } } if (discovery_) { std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); @@ -2416,43 +2474,32 @@ void routing_manager_impl::add_routing_info( } } else if (_unreliable_port != ILLEGAL_PORT && is_unreliable_known) { std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - for(const auto &client_id : requested_services_) { - auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second == ANY_MINOR)) { - if (_reliable_port == ILLEGAL_PORT && !is_reliable_known && - !stub_->contained_in_routing_info( - VSOMEIP_ROUTING_CLIENT, _service, _instance, - its_info->get_major(), - its_info->get_minor())) { - on_availability(_service, _instance, - true, its_info->get_major(), its_info->get_minor()); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, - _service, _instance, - its_info->get_major(), - its_info->get_minor()); - if (discovery_) { - std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); - if (ep && ep->is_established()) { - discovery_->on_endpoint_connected( - _service, _instance, - ep); - } - } - } - break; - } + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + if (_reliable_port == ILLEGAL_PORT && !is_reliable_known && + stub_ && + !stub_->contained_in_routing_info( + VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), + its_info->get_minor())) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + _service, _instance, + its_info->get_major(), + its_info->get_minor()); + if (discovery_) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); + if (ep && ep->is_established()) { + discovery_->on_endpoint_connected( + _service, _instance, + ep); } } } + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, _major, _minor); } } } @@ -2464,10 +2511,12 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst if(!its_info) return; - on_availability(_service, _instance, false, - its_info->get_major(), its_info->get_minor()); - stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + on_availability(_service, _instance, + availability_state_e::AS_UNAVAILABLE, its_info->get_major(), its_info->get_minor()); + if (stub_) + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), its_info->get_minor()); // Implicit unsubscribe std::vector<std::shared_ptr<event>> its_events; @@ -2482,7 +2531,7 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst // do no longer exist and the last received payload is no // longer valid. for (auto &its_event : its_eventgroup.second->get_events()) { - const auto& its_subscribers = its_event->get_subscribers(); + const auto its_subscribers = its_event->get_subscribers(); for (const auto its_subscriber : its_subscribers) { if (its_subscriber != get_client()) { its_event->remove_subscriber( @@ -2747,24 +2796,12 @@ void routing_manager_impl::init_routing_info() { = configuration_->get_reliable_port(i.first, i.second); uint16_t its_unreliable_port = configuration_->get_unreliable_port(i.first, i.second); - major_version_t its_major - = configuration_->get_major_version(i.first, i.second); - minor_version_t its_minor - = configuration_->get_minor_version(i.first, i.second); - ttl_t its_ttl - = configuration_->get_ttl(i.first, i.second); if (its_reliable_port != ILLEGAL_PORT || its_unreliable_port != ILLEGAL_PORT) { - VSOMEIP_INFO << "Adding static remote service [" - << std::hex << std::setw(4) << std::setfill('0') - << i.first << "." << i.second - << std::dec << ":" << +its_major << "." << its_minor - << "]"; - add_routing_info(i.first, i.second, - its_major, its_minor, its_ttl, + DEFAULT_MAJOR, DEFAULT_MINOR, DEFAULT_TTL, its_address, its_reliable_port, its_address, its_unreliable_port); @@ -3009,7 +3046,7 @@ void routing_manager_impl::on_subscribe_ack(client_t _client, host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); } - } else { + } else if (stub_) { stub_->send_subscribe_ack(its_subscriber, _service, _instance, _eventgroup, _event); } @@ -3025,20 +3062,13 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client( void routing_manager_impl::on_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, remote_subscription_id_t _id, bool _simulated) { + event_t _event, remote_subscription_id_t _id) { (void)_event; // TODO: Remove completely? auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { auto its_subscription = its_eventgroup->get_remote_subscription(_id); if (its_subscription) { - if (_simulated) { - // method was called because a subscription for unoffered - // service was received. Therefore, remove the remote_subscription - // from the eventgroupinfo to ensure subsequent similar - // subscriptions are handled like a new/unknown subscription - its_eventgroup->remove_remote_subscription(_id); - } its_subscription->set_client_state(_client, remote_subscription_state_e::SUBSCRIPTION_NACKED); @@ -3167,13 +3197,10 @@ void routing_manager_impl::send_error(return_code_e _return_code, its_endpoint_def->is_reliable()); if (its_endpoint) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_endpoint, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #else (void) _instance; #endif @@ -3233,6 +3260,14 @@ routing_manager_impl::expire_subscriptions(bool _force) { auto its_subscriptions = its_eventgroup.second->get_remote_subscriptions(); for (auto &s : its_subscriptions) { + if(!s) { + VSOMEIP_ERROR << __func__ + << ": Remote subscription is NULL for eventgroup [" + << std::hex << std::setw(4) << std::setfill('0') << its_service.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup.first << "]"; + continue; + } for (auto its_client : s->get_clients()) { if (_force) { its_expired_subscriptions[s].insert(its_client); @@ -3429,13 +3464,10 @@ bool routing_manager_impl::handle_local_offer_service(client_t _client, service_ } if (!already_pinged) { // find out endpoint of previously offering application - std::shared_ptr<local_client_endpoint_base_impl> - its_old_endpoint - = std::dynamic_pointer_cast<local_client_endpoint_base_impl>( - find_local(its_stored_client)); + auto its_old_endpoint = find_local(its_stored_client); if (its_old_endpoint) { std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); - if(stub_->send_ping(its_stored_client)) { + if (stub_ && stub_->send_ping(its_stored_client)) { pending_offers_[_service][_instance] = std::make_tuple(_major, _minor, _client, its_stored_client); @@ -3557,10 +3589,11 @@ void routing_manager_impl::register_client_error_handler(client_t _client, } void routing_manager_impl::handle_client_error(client_t _client) { - VSOMEIP_INFO << "Client 0x" << std::hex << get_client() + VSOMEIP_INFO << "routing_manager_impl::" << __func__ << " Client 0x" << std::hex << get_client() << " handles a client error(" << std::hex << _client << ")"; if (stub_) - stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR); + stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR, + boost::asio::ip::address(), 0); std::forward_list<std::tuple<client_t, service_t, instance_t, major_version_t, minor_version_t>> its_offers; @@ -3619,17 +3652,18 @@ std::shared_ptr<endpoint_manager_impl> routing_manager_impl::get_endpoint_manage void routing_manager_impl::send_subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - event_t _event) { + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { auto endpoint = ep_mgr_->find_local(_service, _instance); - if (endpoint) { + if (endpoint && stub_) { stub_->send_subscribe(endpoint, _client, - _service, _instance, _eventgroup, _major, _event, PENDING_SUBSCRIPTION_ID); + _service, _instance, + _eventgroup, _major, + _event, _filter, + PENDING_SUBSCRIPTION_ID); } } void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { - - // Ignore setting to the current routing state { std::lock_guard<std::mutex> its_lock(routing_state_mutex_); if (routing_state_ == _routing_state) { @@ -3640,7 +3674,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { routing_state_ = _routing_state; } - if(discovery_) { + if (discovery_) { switch (_routing_state) { case routing_state_e::RS_SUSPENDED: { @@ -3656,6 +3690,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { // remove all remote subscriptions to remotely offered services on this node expire_subscriptions(true); + std::vector<std::shared_ptr<serviceinfo>> _service_infos; // send StopOffer messages for remotely offered services on this node for (const auto &its_service : get_offered_services()) { for (const auto &its_instance : its_service.second) { @@ -3666,9 +3701,16 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << " still offered by " << std::hex << std::setw(4) << std::setfill('0') << its_client; } - discovery_->stop_offer_service(its_instance.second); + // collect stop offers to be sent out + if (discovery_->stop_offer_service(its_instance.second, false)) { + _service_infos.push_back(its_instance.second); + } } } + // send collected stop offers packed together in one ore multiple SD messages + discovery_->send_collected_stop_offers(_service_infos); + _service_infos.clear(); + { std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); remote_subscription_state_.clear(); @@ -3746,7 +3788,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { for (const auto &its_instance : its_service.second) { if (host_->get_configuration()->is_someip( its_service.first, its_instance.first)) { - discovery_->stop_offer_service(its_instance.second); + discovery_->stop_offer_service(its_instance.second, true); } } } @@ -3791,7 +3833,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { } void routing_manager_impl::on_net_interface_or_route_state_changed( - bool _is_interface, std::string _if, bool _available) { + bool _is_interface, const std::string &_if, bool _available) { std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); auto log_change_message = [&_if, _available, _is_interface](bool _warning) { std::stringstream ss; @@ -3864,36 +3906,184 @@ void routing_manager_impl::start_ip_routing() { VSOMEIP_INFO << VSOMEIP_ROUTING_READY_MESSAGE; } -void routing_manager_impl::requested_service_add(client_t _client, - service_t _service, - instance_t _instance, - major_version_t _major, - minor_version_t _minor) { +void +routing_manager_impl::add_requested_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); - requested_services_[_client][_service][_instance].insert({ _major, _minor }); + requested_services_[_service][_instance][_major][_minor].insert(_client); } -void routing_manager_impl::requested_service_remove(client_t _client, - service_t _service, - instance_t _instance) { +void +routing_manager_impl::remove_requested_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); - auto found_client = requested_services_.find(_client); - if (found_client != requested_services_.end()) { - auto found_service = found_client->second.find(_service); - if (found_service != found_client->second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - // delete all requested major/minor versions - found_service->second.erase(_instance); - if (!found_service->second.size()) { - found_client->second.erase(_service); - if (!found_client->second.size()) { - requested_services_.erase(_client); + + using minor_map_t = std::map<minor_version_t, std::set<client_t> >; + using major_map_t = std::map<major_version_t, minor_map_t>; + using instance_map_t = std::map<instance_t, major_map_t>; + + auto delete_client = [&_client]( + minor_map_t::iterator& _minor_iter, + const major_map_t::iterator& _parent_major_iter) { + if (_minor_iter->second.erase(_client)) { // client was requester + if (_minor_iter->second.empty()) { + // client was last requester of this minor version + _minor_iter = _parent_major_iter->second.erase(_minor_iter); + } else { // there are still other requesters of this minor version + ++_minor_iter; + } + } else { // client wasn't requester + ++_minor_iter; + } + }; + + auto handle_minor = [&_minor, &delete_client]( + major_map_t::iterator& _major_iter, + const instance_map_t::iterator& _parent_instance_iter) { + if (_minor == ANY_MINOR) { + for (auto minor_iter = _major_iter->second.begin(); + minor_iter != _major_iter->second.end(); ) { + delete_client(minor_iter, _major_iter); + } + } else { + auto found_minor = _major_iter->second.find(_minor); + if (found_minor != _major_iter->second.end()) { + delete_client(found_minor, _major_iter); + } + } + if (_major_iter->second.empty()) { + // client was last requester of this major version + _major_iter = _parent_instance_iter->second.erase(_major_iter); + } else { + ++_major_iter; + } + }; + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (_major == ANY_MAJOR) { + for (auto major_iter = found_instance->second.begin(); + major_iter != found_instance->second.end();) { + handle_minor(major_iter, found_instance); + } + } else { + auto found_major = found_instance->second.find(_major); + if (found_major != found_instance->second.end()) { + handle_minor(found_major, found_instance); + } + } + if (found_instance->second.empty()) { + // client was last requester of this instance + found_service->second.erase(found_instance); + if (found_service->second.empty()) { + // client was last requester of this service + requested_services_.erase(found_service); + } + } + } + } +} + +std::vector<std::pair<service_t, instance_t> > +routing_manager_impl::get_requested_services(client_t _client) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + std::vector<std::pair<service_t, instance_t>> its_requests; + for (const auto& service : requested_services_) { + for (const auto& instance : service.second) { + bool requested = false; + for (const auto& major : instance.second) { + for (const auto& minor : major.second) { + if (minor.second.find(_client) != minor.second.end()) { + requested = true; + break; + } + } + if (requested) { + break; + } + } + if (requested) { + its_requests.push_back( + std::make_pair(service.first, instance.first)); + break; + } + } + } + return (its_requests); +} + +std::set<client_t> +routing_manager_impl::get_requesters(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + return (get_requesters_unlocked(_service, _instance, _major, _minor)); +} + +std::set<client_t> +routing_manager_impl::get_requesters_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::set<client_t> its_requesters; + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& its_major : found_instance->second) { + if (its_major.first == _major || _major == DEFAULT_MAJOR + || its_major.first == ANY_MAJOR) { + for (const auto &its_minor : its_major.second) { + if (its_minor.first <= _minor + || _minor == DEFAULT_MINOR + || its_minor.first == ANY_MINOR) { + if (its_requesters.empty()) { + its_requesters = its_minor.second; + } else { + its_requesters.insert(its_minor.second.cbegin(), + its_minor.second.cend()); + } + } } } } } } + return (its_requesters); +} + +bool +routing_manager_impl::has_requester_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& its_major : found_instance->second) { + if (its_major.first == _major || _major == DEFAULT_MAJOR + || its_major.first == ANY_MAJOR) { + for (const auto &its_minor : its_major.second) { + if (its_minor.first <= _minor + || _minor == DEFAULT_MINOR + || its_minor.first == ANY_MINOR) { + + return (true); + } + } + } + } + } + } + return (false); } std::set<eventgroup_t> @@ -3934,7 +4124,7 @@ void routing_manager_impl::clear_targets_and_pending_sub_from_eventgroups( // longer valid. for (auto &its_event : its_eventgroup.second->get_events()) { const auto its_subscribers = its_event->get_subscribers(); - for (const auto& its_subscriber : its_subscribers) { + for (const auto its_subscriber : its_subscribers) { if (its_subscriber != get_client()) { its_event->remove_subscriber( its_eventgroup.first, its_subscriber); @@ -3994,7 +4184,9 @@ void routing_manager_impl::call_sd_endpoint_connected( bool routing_manager_impl::create_placeholder_event_and_subscribe( service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, client_t _client) { + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client) { + bool is_inserted(false); // we received a event which was not yet requested/offered // create a placeholder field until someone requests/offers this event with @@ -4047,7 +4239,8 @@ bool routing_manager_impl::create_placeholder_event_and_subscribe( std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event) { - is_inserted = its_event->add_subscriber(_eventgroup, _client, false); + is_inserted = its_event->add_subscriber( + _eventgroup, _filter, _client, false); } return is_inserted; } @@ -4097,7 +4290,7 @@ void routing_manager_impl::handle_subscription_state( // Subscription already acknowledged! if (_client == get_client()) { host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); - } else { + } else if (stub_) { stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); } } @@ -4140,11 +4333,10 @@ void routing_manager_impl::memory_log_timer_cbk( if (_error) { return; } -#ifndef _WIN32 + +#if defined(__linux__) || defined(ANDROID) static const std::uint32_t its_pagesize = static_cast<std::uint32_t>(getpagesize() / 1024); -#else - static const std::uint32_t its_pagesize = 4096 / 1024; -#endif + std::FILE *its_file = std::fopen("/proc/self/statm", "r"); if (!its_file) { VSOMEIP_ERROR << "memory_log_timer_cbk: couldn't open:" @@ -4166,11 +4358,10 @@ void routing_manager_impl::memory_log_timer_cbk( << std::string(std::strerror(errno)); } std::fclose(its_file); -#ifndef _WIN32 + struct timespec cputs, monots; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cputs); clock_gettime(CLOCK_MONOTONIC, &monots); -#endif VSOMEIP_INFO << "memory usage: " << "VmSize " << std::dec << its_size * its_pagesize << " kB, " @@ -4178,12 +4369,11 @@ void routing_manager_impl::memory_log_timer_cbk( << "shared pages " << std::dec << its_sharedpages * its_pagesize << " kB, " << "text " << std::dec << its_text * its_pagesize << " kB, " << "data " << std::dec << its_data * its_pagesize << " kB " -#ifndef _WIN32 << "| monotonic time: " << std::dec << monots.tv_sec << "." << std::dec << monots.tv_nsec << " cpu time: " << std::dec << cputs.tv_sec << "." << std::dec << cputs.tv_nsec -#endif ; +#endif { std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); @@ -4278,8 +4468,9 @@ void routing_manager_impl::send_subscription( const remote_subscription_id_t _id) { if (host_->get_client() == _offering_client) { auto self = shared_from_this(); - for (const auto& its_client : _clients) { - host_->on_subscription(_service, _instance, _eventgroup, its_client, own_uid_, own_gid_, true, + for (const auto its_client : _clients) { + host_->on_subscription(_service, _instance, _eventgroup, its_client, + get_sec_client(), get_env(its_client), true, [this, self, _service, _instance, _eventgroup, its_client, _id] (const bool _is_accepted) { try { @@ -4288,7 +4479,7 @@ void routing_manager_impl::send_subscription( &routing_manager_stub_host::on_subscribe_nack, std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), its_client, _service, _instance, - _eventgroup, ANY_EVENT, _id, false); + _eventgroup, ANY_EVENT, _id); io_.post(its_callback); } else { const auto its_callback = std::bind( @@ -4304,15 +4495,15 @@ void routing_manager_impl::send_subscription( }); } } else { // service hosted by local client - for (const auto& its_client : _clients) { - if (!stub_->send_subscribe(find_local(_offering_client), its_client, - _service, _instance, _eventgroup, _major, ANY_EVENT, _id)) { + for (const auto its_client : _clients) { + if (stub_ && !stub_->send_subscribe(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, _major, ANY_EVENT, nullptr, _id)) { try { const auto its_callback = std::bind( &routing_manager_stub_host::on_subscribe_nack, std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), its_client, _service, _instance, _eventgroup, - ANY_EVENT, _id, true); + ANY_EVENT, _id); io_.post(its_callback); } catch (const std::exception &e) { VSOMEIP_ERROR << __func__ << e.what(); @@ -4378,7 +4569,8 @@ void routing_manager_impl::on_resend_provided_events_response( } void routing_manager_impl::print_stub_status() const { - stub_->print_endpoint_status(); + if (stub_) + stub_->print_endpoint_status(); } void routing_manager_impl::service_endpoint_connected( @@ -4389,9 +4581,12 @@ void routing_manager_impl::service_endpoint_connected( if (!_unreliable_only) { // Mark only TCP-only and TCP+UDP services available here // UDP-only services are already marked as available in add_routing_info - on_availability(_service, _instance, true, _major, _minor); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, _major, _minor); + if (stub_) + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + _major, _minor); } std::shared_ptr<boost::asio::steady_timer> its_timer = @@ -4413,9 +4608,12 @@ void routing_manager_impl::service_endpoint_disconnected( service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, const std::shared_ptr<endpoint>& _endpoint) { (void)_endpoint; - on_availability(_service, _instance, false, _major, _minor); - stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + on_availability(_service, _instance, + availability_state_e::AS_UNAVAILABLE, _major, _minor); + if (stub_) + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + _major, _minor); VSOMEIP_WARNING << __func__ << ": lost connection to remote service: [" << std::hex << std::setw(4) << std::setfill('0') << _service << "." << std::hex << std::setw(4) << std::setfill('0') << _instance << "]"; @@ -4432,9 +4630,9 @@ routing_manager_impl::send_unsubscription(client_t _offering_client, if (host_->get_client() == _offering_client) { auto self = shared_from_this(); - for (const auto& its_client : _removed) { - host_->on_subscription(_service, _instance, - _eventgroup, its_client, own_uid_, own_gid_, false, + for (const auto its_client : _removed) { + host_->on_subscription(_service, _instance, _eventgroup, + its_client, get_sec_client(), get_env(its_client),false, [this, self, _service, _instance, _eventgroup, its_client, _id] (const bool _is_accepted) { @@ -4452,8 +4650,8 @@ routing_manager_impl::send_unsubscription(client_t _offering_client, ); } } else { - for (const auto& its_client : _removed) { - if (!stub_->send_unsubscribe(find_local(_offering_client), its_client, + for (const auto its_client : _removed) { + if (stub_ && !stub_->send_unsubscribe(find_local(_offering_client), its_client, _service, _instance, _eventgroup, ANY_EVENT, _id)) { try { const auto its_callback = std::bind( @@ -4480,19 +4678,21 @@ routing_manager_impl::send_expired_subscription(client_t _offering_client, auto self = shared_from_this(); for (const auto its_client : _removed) { host_->on_subscription(_service, _instance, - _eventgroup, its_client, own_uid_, own_gid_, false, + _eventgroup, its_client, get_sec_client(), get_env(its_client), false, [] (const bool _subscription_accepted){ (void)_subscription_accepted; }); } } else { for (const auto its_client : _removed) { - stub_->send_expired_subscription(find_local(_offering_client), its_client, - _service, _instance, _eventgroup, ANY_EVENT, _id); + if (stub_) + stub_->send_expired_subscription(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, ANY_EVENT, _id); } } } +#ifndef VSOMEIP_DISABLE_SECURITY bool routing_manager_impl::update_security_policy_configuration( uint32_t _uid, uint32_t _gid, @@ -4518,6 +4718,7 @@ routing_manager_impl::remove_security_policy_configuration( return (false); } +#endif // !VSOMEIP_DISABLE_SECURITY bool routing_manager_impl::insert_event_statistics(service_t _service, instance_t _instance, method_t _method, length_t _length) { @@ -4527,7 +4728,7 @@ bool routing_manager_impl::insert_event_statistics(service_t _service, instance_ const auto its_tuple = std::make_tuple(_service, _instance, _method); const auto its_main_s = message_statistics_.find(its_tuple); if (its_main_s != message_statistics_.end()) { - // increase counter and calculate moving avergae for payload length + // increase counter and calculate moving average for payload length its_main_s->second.avg_length_ = (its_main_s->second.avg_length_ * its_main_s->second.counter_ + _length) / (its_main_s->second.counter_ + 1); @@ -4537,10 +4738,10 @@ bool routing_manager_impl::insert_event_statistics(service_t _service, instance_ // check list for entry with least counter value uint32_t its_min_count(0xFFFFFFFF); auto its_tuple_to_discard = std::make_tuple(0xFFFF, 0xFFFF, 0xFFFF); - for (const auto &it : message_statistics_) { - if (it.second.counter_ < its_min_count) { - its_min_count = it.second.counter_; - its_tuple_to_discard = it.first; + for (const auto &s : message_statistics_) { + if (s.second.counter_ < its_min_count) { + its_min_count = s.second.counter_; + its_tuple_to_discard = s.first; } } if (its_min_count != 0xFFFF @@ -4580,7 +4781,7 @@ void routing_manager_impl::statistics_log_timer_cbk(boost::system::error_code co { std::lock_guard<std::mutex> its_lock(message_statistics_mutex_); for (const auto &s : message_statistics_) { - if (s.second.counter_ / (its_interval / 1000) >= its_min_freq) { + if (s.second.counter_ / (its_interval / 1000) > its_min_freq) { uint16_t its_subscribed(0); std::shared_ptr<event> its_event = find_event(std::get<0>(s.first), std::get<1>(s.first), std::get<2>(s.first)); if (its_event) { @@ -4621,9 +4822,86 @@ void routing_manager_impl::statistics_log_timer_cbk(boost::system::error_code co } } +bool +routing_manager_impl::get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const { + + return (routing_manager_base::get_guest(_client, _address, _port)); +} + +void +routing_manager_impl::add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) { + + routing_manager_base::add_guest(_client, _address, _port); +} + +void +routing_manager_impl::remove_guest(client_t _client) { + + routing_manager_base::remove_guest(_client); +} + void routing_manager_impl::send_suspend() const { + if (stub_) + stub_->send_suspend(); +} + +void routing_manager_impl::clear_local_services() { + + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + local_services_.clear(); +} + +void routing_manager_impl::register_message_acceptance_handler( + const message_acceptance_handler_t& _handler) { + message_acceptance_handler_ = _handler; +} + +void +routing_manager_impl::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<eventgroupinfo> > > >its_eventgroups; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + its_eventgroups = eventgroups_; + } + for (const auto &its_service : its_eventgroups) { + for (const auto &its_instance : its_service.second) { + for (const auto &its_eventgroup : its_instance.second) { + const auto its_info = its_eventgroup.second; + for (auto its_subscription + : its_info->get_remote_subscriptions()) { + auto its_definition = its_subscription->get_reliable(); + if (its_definition + && its_definition->get_address() == _remote_address + && its_definition->get_port() == _remote_port + && its_definition->get_remote_port() == _local_port) { + + VSOMEIP_INFO << __func__ + << ": Removing subscription to [" + << std::hex << std::setw(4) << std::setfill('0') + << its_info->get_service() << "." + << std::hex << std::setw(4) << std::setfill('0') + << its_info->get_instance() << "." + << std::hex << std::setw(4) << std::setfill('0') + << its_info->get_eventgroup() + << "] from target " + << its_definition->get_address() << ":" + << std::dec << its_definition->get_port() + << " reliable=true"; - stub_->send_suspend(); + on_remote_unsubscribe(its_subscription); + } + } + } + } + } } } // namespace vsomeip_v3 |