diff options
author | Juergen Gehring <juergen.gehring@bmw.de> | 2017-06-20 02:54:31 -0700 |
---|---|---|
committer | Juergen Gehring <juergen.gehring@bmw.de> | 2017-06-20 02:54:31 -0700 |
commit | fdf86239b4a6867e0a961a307649a6d5eb3a2f93 (patch) | |
tree | b25be00a044a41135d11ddd3f15c1adce3a6411b | |
parent | 27698301f8bb528c2f618af5995865523de7e0d6 (diff) | |
download | vSomeIP-2.7.0.tar.gz |
vSomeIP 2.7.02.7.0
95 files changed, 4114 insertions, 1031 deletions
@@ -44,6 +44,9 @@ /test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_diff_ports_slave.json /test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_same_ports_master.json /test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_same_ports_slave.json +/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_master.json +/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json +/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json /test/subscribe_notify_one_tests/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json /test/subscribe_notify_one_tests/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json /test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master.json @@ -306,3 +306,26 @@ v2.6.3 v2.6.4 - Fix bug in reboot detection of other nodes - Improve restarting of TCP connections + +v2.7.0 +- Add possibility to register a subscription status handler via + application interface. The handler will be called if a subscription + is acknowledged / not acknowledged by the application hosting the + target service instance of the subscription +- The default subscription type of application::subscribe method was + changed from RELIABLE_AND_UNRELIABLE to PREFER_RELIABLE to harmonize + initial event behaviour +- Add generic plug-in concept +- Fix bug which caused sending out subscription messages containing + endpoint options with port set to zero +- Make magic cookie detection TCP connection based +- Avoid sending unneeded SIGKILLs to current routing manager +- Forward service's instance IDs to DLT +- Fixed performance loss on "client ID" lookup needed for ingoing + remote subscriptions +- Add signal handling for starting stopping the service discovery to + vsomeipd +- The message object can now be asked for CRC check state: + is_valid_crc() +- Incoming remote responses where the CRC check fails will trigger: + set_is_valid_crc(false) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15a7d59..5c2db35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ cmake_minimum_required (VERSION 2.8.12) project (vsomeip) set (VSOMEIP_MAJOR_VERSION 2) -set (VSOMEIP_MINOR_VERSION 6) -set (VSOMEIP_PATCH_VERSION 4) +set (VSOMEIP_MINOR_VERSION 7) +set (VSOMEIP_PATCH_VERSION 0) set (VSOMEIP_VERSION ${VSOMEIP_MAJOR_VERSION}.${VSOMEIP_MINOR_VERSION}.${VSOMEIP_PATCH_VERSION}) set (PACKAGE_VERSION ${VSOMEIP_VERSION}) # Used in documentatin/doxygen.in set (CMAKE_VERBOSE_MAKEFILE off) @@ -122,6 +122,7 @@ file(GLOB vsomeip_SRC "implementation/routing/src/*.cpp" "implementation/runtime/src/*.cpp" "implementation/utility/src/*.cpp" + "implementation/plugin/src/*.cpp" ) file(GLOB_RECURSE vsomeip_e2e_SRC @@ -167,6 +168,7 @@ add_library(vsomeip-cfg SHARED ${vsomeip-cfg_SRC}) set_target_properties (vsomeip-cfg PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION ${VSOMEIP_MAJOR_VERSION}) target_link_libraries(vsomeip-cfg vsomeip ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES}) +# Service-Discovery library file(GLOB vsomeip-sd_SRC "implementation/service_discovery/src/*.cpp" ) @@ -177,8 +179,8 @@ set_target_properties (vsomeip-sd PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSIO target_link_libraries(vsomeip-sd vsomeip ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) if (MSVC) - set_target_properties(vsomeip-cfg PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_CONFIG") - set_target_properties(vsomeip-sd PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION") + set_target_properties(vsomeip-cfg PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_PLUGIN") + set_target_properties(vsomeip-sd PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_PLUGIN") set_target_properties(vsomeip PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION") endif() @@ -378,6 +380,16 @@ add_subdirectory( tools ) add_custom_target( examples ) add_subdirectory( examples EXCLUDE_FROM_ALL ) +# build plugins located directly in the build tree +# (Non-Windows only) +if (NOT MSVC) + if(EXISTS "${PROJECT_SOURCE_DIR}/plugins/CMakeLists.txt") + # build plugins if available + message("Plugins CMakeList.txt found: Build plugins") + add_subdirectory( plugins ) + endif() +endif() + ############################################################################## # Test section diff --git a/daemon/vsomeipd.cpp b/daemon/vsomeipd.cpp index 6688ec2..b329534 100644 --- a/daemon/vsomeipd.cpp +++ b/daemon/vsomeipd.cpp @@ -26,13 +26,22 @@ static std::shared_ptr<vsomeip::application> its_application; * Handle signal to stop the daemon */ void vsomeipd_stop(int _signal) { - if (_signal == SIGINT || _signal == SIGTERM) + if (_signal == SIGINT || _signal == SIGTERM) { its_application->stop(); + } if (_signal == SIGABRT) { - VSOMEIP_INFO << "Suspending service discovery"; + VSOMEIP_INFO << "Stopping service discovery"; its_application->set_routing_state(vsomeip::routing_state_e::RS_SUSPENDED); its_application->stop(); } + if (_signal == SIGUSR1) { + VSOMEIP_INFO << "Suspending service discovery"; + its_application->set_routing_state(vsomeip::routing_state_e::RS_SUSPENDED); + } + if (_signal == SIGUSR2) { + VSOMEIP_INFO << "Resuming service discovery"; + its_application->set_routing_state(vsomeip::routing_state_e::RS_RESUMED); + } } #endif @@ -61,6 +70,8 @@ int vsomeipd_process(bool _is_quiet) { signal(SIGINT, vsomeipd_stop); signal(SIGTERM, vsomeipd_stop); signal(SIGABRT, vsomeipd_stop); + signal(SIGUSR1, vsomeipd_stop); + signal(SIGUSR2, vsomeipd_stop); #endif if (its_application->init()) { if (its_application->is_routing()) { diff --git a/documentation/vsomeipUserGuide b/documentation/vsomeipUserGuide index 19aa864..922af01 100644 --- a/documentation/vsomeipUserGuide +++ b/documentation/vsomeipUserGuide @@ -285,6 +285,14 @@ The netmask to specify the subnet of the host system. + The diagnosis address (byte) that will be used to build client identifiers. + +* 'network' ++ +Network identifier used to support multiple routing managers on one host. This +setting changes the name of the shared memory segment in `/dev/shm` and the name +of the unix domain sockets in `/tmp/`. Defaults to `vsomeip` meaning the shared +memory will be named `/dev/shm/vsomeip` and the unix domain sockets will be +named `/tmp/vsomeip-$CLIENTID` ++ //Logging * 'logging' + @@ -312,6 +320,19 @@ The absolute path of the log file. Specifies whether Diagnostic Log and Trace (DLT) is enabled (valid values: _true, false_). + +** 'version' ++ +Configures logging of the vSomeIP version ++ +*** 'enable' ++ +Enable or disable cyclic logging of vSomeIP version, defaults to true (valid +values: _true, false_) ++ +*** 'interval' ++ +Configures interval in seconds to log the vSomeIP version. Default value is 10. ++ //Tracing * anchor:config-tracing[]'tracing' (optional) + diff --git a/exportmap.gcc b/exportmap.gcc index e0136e6..61da700 100644 --- a/exportmap.gcc +++ b/exportmap.gcc @@ -38,9 +38,10 @@ global: vsomeip::sd::runtime::*; *vsomeip::utility; vsomeip::utility::is*; + *vsomeip::plugin_manager; + vsomeip::plugin_manager::*; }; - VSOMEIP_CFG_RUNTIME; - VSOMEIP_SD_RUNTIME; + vsomeip_plugin_init; local: *; }; diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp index c8b7717..6f18300 100644 --- a/implementation/configuration/include/configuration.hpp +++ b/implementation/configuration/include/configuration.hpp @@ -16,6 +16,7 @@ #include <vsomeip/export.hpp> #include <vsomeip/defines.hpp> +#include <vsomeip/plugin.hpp> #include <vsomeip/primitive_types.hpp> #include "internal.hpp" @@ -24,17 +25,20 @@ #include "../../e2e_protection/include/e2exf/config.hpp" #include "e2e.hpp" +#define VSOMEIP_CONFIG_PLUGIN_VERSION 1 + namespace vsomeip { class event; -class VSOMEIP_IMPORT_EXPORT_CONFIG configuration { +class configuration { public: - static std::shared_ptr<configuration> get(); virtual ~configuration() {} virtual bool load(const std::string &_name) = 0; + virtual const std::string &get_network() const = 0; + virtual const boost::asio::ip::address & get_unicast_address() const = 0; virtual unsigned short get_diagnosis_address() const = 0; virtual bool is_v4() const = 0; @@ -129,6 +133,12 @@ public: instance_t _instance) const = 0; virtual bool check_credentials(client_t _client, uint32_t _uid, uint32_t _gid) const = 0; + // Plugins + virtual std::map<plugin_type_e, std::string> get_plugins( + const std::string &_name) const = 0; + + virtual void set_configuration_path(const std::string &_path) = 0; + //E2E virtual std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const = 0; virtual bool is_e2e_enabled() const = 0; diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp index b345d9d..c519f05 100644 --- a/implementation/configuration/include/configuration_impl.hpp +++ b/implementation/configuration/include/configuration_impl.hpp @@ -41,16 +41,21 @@ struct element { } }; -class configuration_impl: public configuration, public std::enable_shared_from_this<configuration_impl> { +class configuration_impl: + public configuration, + public plugin_impl<configuration_impl>, + public std::enable_shared_from_this<configuration_impl> { public: - VSOMEIP_EXPORT static std::shared_ptr<configuration> get(); - VSOMEIP_EXPORT configuration_impl(); VSOMEIP_EXPORT configuration_impl(const configuration_impl &_cfg); VSOMEIP_EXPORT virtual ~configuration_impl(); VSOMEIP_EXPORT bool load(const std::string &_name); + VSOMEIP_EXPORT const std::string &get_network() const; + + VSOMEIP_EXPORT void set_configuration_path(const std::string &_path); + VSOMEIP_EXPORT const boost::asio::ip::address & get_unicast_address() const; VSOMEIP_EXPORT unsigned short get_diagnosis_address() const; VSOMEIP_EXPORT bool is_v4() const; @@ -139,8 +144,10 @@ public: VSOMEIP_EXPORT bool is_offer_allowed(client_t _client, service_t _service, instance_t _instance) const; VSOMEIP_EXPORT bool check_credentials(client_t _client, uint32_t _uid, uint32_t _gid) const; - - //E2E + + VSOMEIP_EXPORT std::map<plugin_type_e, std::string> get_plugins( + const std::string &_name) const; + // E2E VSOMEIP_EXPORT std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const; VSOMEIP_EXPORT bool is_e2e_enabled() const; @@ -171,6 +178,8 @@ private: std::string &_criteria, std::shared_ptr<trace_filter_rule> &_filter_rule); + void load_network(const element &_element); + void load_unicast_address(const element &_element); void load_diagnosis_address(const element &_element); @@ -237,7 +246,8 @@ protected: std::string logfile_; boost::log::trivial::severity_level loglevel_; - std::map<std::string, std::tuple<client_t, std::size_t, std::size_t, std::size_t, std::size_t>> applications_; + std::map<std::string, std::tuple<client_t, std::size_t, std::size_t, + size_t, size_t, std::map<plugin_type_e, std::string>>> applications_; std::set<client_t> client_identifiers_; std::map<service_t, @@ -284,6 +294,7 @@ protected: uint32_t log_version_interval_; enum element_type_e { + ET_NETWORK, ET_UNICAST, ET_DIAGNOSIS, ET_LOGGING_CONSOLE, @@ -308,7 +319,7 @@ protected: ET_TRACING_ENABLE, ET_TRACING_SD_ENABLE, ET_SERVICE_DISCOVERY_OFFER_DEBOUNCE_TIME, - ET_MAX = 24 + ET_MAX = 25 }; bool is_configured_[ET_MAX]; @@ -319,6 +330,9 @@ protected: bool policy_enabled_; bool check_credentials_; + std::string network_; + std::string configuration_path_; + bool e2e_enabled_; std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> e2e_configuration_; }; diff --git a/implementation/configuration/include/e2e.hpp b/implementation/configuration/include/e2e.hpp index 305ef7a..349c6f4 100644 --- a/implementation/configuration/include/e2e.hpp +++ b/implementation/configuration/include/e2e.hpp @@ -25,13 +25,15 @@ struct e2e { event_id(0), crc_offset(0), data_id_mode(0), - data_length(0) { + data_length(0), + data_id_nibble_offset(0), + counter_offset(0) { } e2e(uint16_t _data_id, std::string _variant, std::string _profile, uint16_t _service_id, uint16_t _event_id,uint16_t _crc_offset, - uint8_t _data_id_mode, uint16_t _data_length) : + uint8_t _data_id_mode, uint16_t _data_length, uint16_t _data_id_nibble_offset, uint16_t _counter_offset) : data_id(_data_id), variant(_variant), @@ -40,7 +42,9 @@ struct e2e { event_id(_event_id), crc_offset(_crc_offset), data_id_mode(_data_id_mode), - data_length(_data_length) { + data_length(_data_length), + data_id_nibble_offset(_data_id_nibble_offset), + counter_offset(_counter_offset) { } @@ -56,6 +60,8 @@ struct e2e { uint16_t crc_offset; uint8_t data_id_mode; uint16_t data_length; + uint16_t data_id_nibble_offset; + uint16_t counter_offset; }; diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in index 7d8a18c..14d58f9 100644 --- a/implementation/configuration/include/internal.hpp.in +++ b/implementation/configuration/include/internal.hpp.in @@ -14,6 +14,7 @@ #define VSOMEIP_ENV_CONFIGURATION "VSOMEIP_CONFIGURATION" #define VSOMEIP_ENV_CONFIGURATION_MODULE "VSOMEIP_CONFIGURATION_MODULE" #define VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES "VSOMEIP_MANDATORY_CONFIGURATION_FILES" +#define VSOMEIP_ENV_LOAD_PLUGINS "VSOMEIP_LOAD_PLUGINS" #define VSOMEIP_DEFAULT_CONFIGURATION_FILE "/etc/vsomeip.json" #define VSOMEIP_LOCAL_CONFIGURATION_FILE "./vsomeip.json" @@ -22,15 +23,19 @@ #define VSOMEIP_DEFAULT_CONFIGURATION_FOLDER "/etc/vsomeip" #define VSOMEIP_LOCAL_CONFIGURATION_FOLDER "./vsomeip" -#define VSOMEIP_BASE_PATH "/tmp/vsomeip-" +#define VSOMEIP_BASE_PATH "/tmp/" +#ifdef WIN32 +#define VSOMEIP_CFG_LIBRARY "vsomeip-cfg.dll" +#else #define VSOMEIP_CFG_LIBRARY "libvsomeip-cfg.so.@VSOMEIP_MAJOR_VERSION@" -#define VSOMEIP_CFG_RUNTIME_SYMBOL VSOMEIP_CFG_RUNTIME -#define VSOMEIP_CFG_RUNTIME_SYMBOL_STRING "VSOMEIP_CFG_RUNTIME" +#endif +#ifdef WIN32 +#define VSOMEIP_SD_LIBRARY "vsomeip-sd.dll" +#else #define VSOMEIP_SD_LIBRARY "libvsomeip-sd.so.@VSOMEIP_MAJOR_VERSION@" -#define VSOMEIP_SD_RUNTIME_SYMBOL VSOMEIP_SD_RUNTIME -#define VSOMEIP_SD_RUNTIME_SYMBOL_STRING "VSOMEIP_SD_RUNTIME" +#endif #define VSOMEIP_ROUTING "@VSOMEIP_ROUTING@" #define VSOMEIP_ROUTING_CLIENT 0 @@ -112,7 +117,6 @@ #endif #define VSOMEIP_DATA_ID 0x677D -#define VSOMEIP_SHM_NAME "/vsomeip" #define VSOMEIP_DIAGNOSIS_ADDRESS @VSOMEIP_DIAGNOSIS_ADDRESS@ #define VSOMEIP_DEFAULT_SHM_PERMISSION 0666 @@ -145,6 +149,12 @@ struct service_data_t { } }; +typedef enum { + SUBSCRIPTION_ACKNOWLEDGED, + SUBSCRIPTION_NOT_ACKNOWLEDGED, + IS_SUBSCRIBING +} subscription_state_e; + struct configuration_data_t { #ifndef _WIN32 volatile char initialized_; diff --git a/implementation/configuration/src/configuration.cpp b/implementation/configuration/src/configuration.cpp deleted file mode 100644 index c4039f7..0000000 --- a/implementation/configuration/src/configuration.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2014-2017 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/. - -#include "../include/configuration_impl.hpp" - -#ifdef _WIN32 -extern "C" -{ - __declspec(dllexport) std::shared_ptr<vsomeip::configuration> VSOMEIP_CFG_RUNTIME_SYMBOL; -} -#else -std::shared_ptr<vsomeip::configuration> VSOMEIP_CFG_RUNTIME_SYMBOL(vsomeip::configuration::get()); -#endif - -#ifdef _WIN32 -#define CCALL __cdecl -#pragma section(".CRT$XCU",read) -#define INITIALIZER(f) \ - static void __cdecl f(void); \ - __declspec(allocate(".CRT$XCU")) void(__cdecl*f##_)(void) = f; \ - static void __cdecl f(void) - -INITIALIZER(init_vsomeip_cfg) { - VSOMEIP_CFG_RUNTIME_SYMBOL = vsomeip::configuration::get(); -} -#endif - -namespace vsomeip { - -std::shared_ptr<configuration> configuration::get() { - return cfg::configuration_impl::get(); -} - -} // namespace vsomeip diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp index dc13103..68ad340 100644 --- a/implementation/configuration/src/configuration_impl.cpp +++ b/implementation/configuration/src/configuration_impl.cpp @@ -18,6 +18,7 @@ #include <boost/property_tree/json_parser.hpp> #include <vsomeip/constants.hpp> +#include <vsomeip/plugins/application_plugin.hpp> #include "../include/client.hpp" #include "../include/configuration_impl.hpp" @@ -30,15 +31,14 @@ #include "../../service_discovery/include/defines.hpp" #include "../../utility/include/utility.hpp" +VSOMEIP_PLUGIN(vsomeip::cfg::configuration_impl) + namespace vsomeip { namespace cfg { -std::shared_ptr<configuration> configuration_impl::get() { - return std::make_shared<configuration_impl>(); -} - configuration_impl::configuration_impl() - : is_loaded_(false), + : plugin_impl("vsomeip cfg plugin", 1, plugin_type_e::CONFIGURATION_PLUGIN), + is_loaded_(false), is_logging_loaded_(false), diagnosis_(VSOMEIP_DIAGNOSIS_ADDRESS), has_console_log_(true), @@ -70,6 +70,7 @@ configuration_impl::configuration_impl() umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS), policy_enabled_(false), check_credentials_(false), + network_("vsomeip"), e2e_enabled_(false) { unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS); for (auto i = 0; i < ET_MAX; i++) @@ -77,7 +78,8 @@ configuration_impl::configuration_impl() } configuration_impl::configuration_impl(const configuration_impl &_other) - : std::enable_shared_from_this<configuration_impl>(_other), + : plugin_impl("vsomeip cfg plugin", 1, plugin_type_e::CONFIGURATION_PLUGIN), + std::enable_shared_from_this<configuration_impl>(_other), is_loaded_(_other.is_loaded_), is_logging_loaded_(_other.is_logging_loaded_), mandatory_(_other.mandatory_), @@ -129,6 +131,7 @@ configuration_impl::configuration_impl(const configuration_impl &_other) policy_enabled_ = _other.policy_enabled_; check_credentials_ = _other.check_credentials_; + network_ = _other.network_; e2e_enabled_ = _other.e2e_enabled_; } @@ -155,7 +158,7 @@ bool configuration_impl::load(const std::string &_name) { its_folder = its_local_folder; } - // Finally, override with path from environment (if existing) + // Override with path from environment (if existing) const char *its_env = getenv(VSOMEIP_ENV_CONFIGURATION); if (nullptr != its_env) { if (utility::is_file(its_env)) { @@ -167,6 +170,17 @@ bool configuration_impl::load(const std::string &_name) { } } + // Finally, pverride with path from set config path (if existing) + if (configuration_path_.length()) { + if (utility::is_file(configuration_path_)) { + its_file = configuration_path_; + its_folder = ""; + } else if (utility::is_folder(configuration_path_)) { + its_folder = configuration_path_; + its_file = ""; + } + } + std::set<std::string> its_input; if (its_file != "") { its_input.insert(its_file); @@ -302,6 +316,7 @@ bool configuration_impl::load_data(const std::vector<element> &_elements, for (auto e : _elements) { has_routing = load_routing(e) || has_routing; has_applications = load_applications(e) || has_applications; + load_network(e); load_diagnosis_address(e); load_payload_sizes(e); load_permissions(e); @@ -447,6 +462,7 @@ void configuration_impl::load_application_data( std::size_t its_max_dispatch_time(VSOMEIP_MAX_DISPATCH_TIME); std::size_t its_io_thread_count(VSOMEIP_IO_THREAD_COUNT); std::size_t its_request_debounce_time(VSOMEIP_REQUEST_DEBOUNCE_TIME); + std::map<plugin_type_e, std::string> plugins; for (auto i = _tree.begin(); i != _tree.end(); ++i) { std::string its_key(i->first); std::string its_value(i->second.data()); @@ -483,6 +499,32 @@ void configuration_impl::load_application_data( VSOMEIP_WARNING << "Max. request debounce time is 10.000ms"; its_request_debounce_time = 10000; } + } else if (its_key == "plugins") { + for (auto l = i->second.begin(); l != i->second.end(); ++l) { + for (auto n = l->second.begin(); n != l->second.end(); ++n) { + std::string its_inner_key(n->first); + std::string its_inner_value(n->second.data()); + #ifdef _WIN32 + std::string library(its_inner_value); + library += ".dll"; + #else + std::string library("lib"); + library += its_inner_value; + library += ".so"; + #endif + if (its_inner_key == "application_plugin") { + #ifndef _WIN32 + library += "."; + library += (VSOMEIP_APPLICATION_PLUGIN_VERSION + '0'); + #endif + plugins[plugin_type_e::APPLICATION_PLUGIN] = library; + } else { + VSOMEIP_WARNING << "Unknown plug-in type (" + << its_inner_key << ") configured for client: " + << its_name; + } + } + } } } if (its_name != "") { @@ -501,7 +543,7 @@ void configuration_impl::load_application_data( applications_[its_name] = std::make_tuple(its_id, its_max_dispatchers, its_max_dispatch_time, its_io_thread_count, - its_request_debounce_time); + its_request_debounce_time, plugins); } else { VSOMEIP_WARNING << "Multiple configurations for application " << its_name << ". Ignoring a configuration from " @@ -654,6 +696,21 @@ void configuration_impl::load_unicast_address(const element &_element) { } } +void configuration_impl::load_network(const element &_element) { + try { + std::string its_value(_element.tree_.get<std::string>("network")); + if (is_configured_[ET_NETWORK]) { + VSOMEIP_WARNING << "Multiple definitions for network." + "Ignoring definition from " << _element.name_; + } else { + network_ = its_value; + is_configured_[ET_NETWORK] = true; + } + } catch (...) { + // intentionally left empty + } +} + void configuration_impl::load_diagnosis_address(const element &_element) { try { std::string its_value = _element.tree_.get<std::string>("diagnosis"); @@ -757,7 +814,9 @@ void configuration_impl::load_service_discovery( int tmp; its_converter << its_value; its_converter >> tmp; - sd_repetitions_max_ = (uint8_t)tmp; + sd_repetitions_max_ = (tmp > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : + static_cast<std::uint8_t>(tmp); is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX] = true; } } else if (its_key == "ttl") { @@ -820,7 +879,11 @@ void configuration_impl::load_delays( int tmp_repetition_max; its_converter << std::dec << i->second.data(); its_converter >> tmp_repetition_max; - sd_repetitions_max_ = uint8_t(tmp_repetition_max); + sd_repetitions_max_ = + (tmp_repetition_max + > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : + static_cast<std::uint8_t>(tmp_repetition_max); } else if (its_key == "cyclic-offer") { its_converter << std::dec << i->second.data(); its_converter >> sd_cyclic_offer_delay_; @@ -1061,7 +1124,10 @@ void configuration_impl::load_eventgroup( std::stringstream its_converter; its_converter << std::dec << its_value; its_converter >> std::dec >> its_threshold; - its_eventgroup->threshold_ = static_cast<uint8_t>(its_threshold); + its_eventgroup->threshold_ = + (its_threshold > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : + static_cast<uint8_t>(its_threshold); } else if (its_key == "events") { for (auto k = j->second.begin(); k != j->second.end(); ++k) { std::stringstream its_converter; @@ -1488,7 +1554,8 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { if (i->first == "client") { std::string value = i->second.data(); if (value == "") { - client_t firstClient, lastClient; + client_t firstClient(ILLEGAL_CLIENT); + client_t lastClient(ILLEGAL_CLIENT); for (auto n = i->second.begin(); n != i->second.end(); ++n) { if (n->first == "first") { @@ -1700,6 +1767,10 @@ bool configuration_impl::is_internal_service(service_t _service, /////////////////////////////////////////////////////////////////////////////// // Public interface /////////////////////////////////////////////////////////////////////////////// +const std::string &configuration_impl::get_network() const { + return network_; +} + const boost::asio::ip::address & configuration_impl::get_unicast_address() const { return unicast_; } @@ -2243,6 +2314,22 @@ bool configuration_impl::is_offer_allowed(client_t _client, service_t _service, return !check_credentials_; } +std::map<plugin_type_e, std::string> configuration_impl::get_plugins( + const std::string &_name) const { + std::map<plugin_type_e, std::string> result; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + result = std::get<5>(found_application->second); + } + + return result; +} + +void configuration_impl::set_configuration_path(const std::string &_path) { + configuration_path_ = _path; +} + bool configuration_impl::is_e2e_enabled() const { return e2e_enabled_; } @@ -2286,6 +2373,8 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_ uint16_t crc_offset(0); uint8_t data_id_mode(0); uint16_t data_length(0); + uint16_t data_id_nibble_offset(12); // data id nibble behind 4 bit counter value + uint16_t counter_offset(8); // counter field behind CRC8 for (auto l = _tree.begin(); l != _tree.end(); ++l) { std::stringstream its_converter; @@ -2326,12 +2415,21 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_ std::string value = l->second.data(); its_converter << value; its_converter >> crc_offset; + } else if (l->first == "counter_offset") { + std::string value = l->second.data(); + its_converter << value; + its_converter >> counter_offset; } else if (l->first == "data_id_mode") { std::string value = l->second.data(); its_converter << value; its_converter >> tmp; data_id_mode = static_cast<uint8_t>(tmp); - } else if (l->first == "data_length") { + } else if (l->first == "data_id_nibble_offset") { + std::string value = l->second.data(); + its_converter << value; + its_converter >> data_id_nibble_offset; + } + else if (l->first == "data_length") { std::string value = l->second.data(); its_converter << value; its_converter >> data_length; @@ -2346,7 +2444,9 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_ event_id, crc_offset, data_id_mode, - data_length + data_length, + data_id_nibble_offset, + counter_offset ); } diff --git a/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp b/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp index 4574ca3..569a20d 100644 --- a/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp +++ b/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp @@ -31,16 +31,18 @@ struct Config { uint16_t data_id; p01_data_id_mode data_id_mode; uint16_t data_length; + uint16_t counter_offset; + uint16_t data_id_nibble_offset; #ifndef E2E_DEVELOPMENT Config() = delete; #else Config() = default; #endif - Config(uint16_t _crc_offset, uint16_t _data_id, p01_data_id_mode _data_id_mode, uint16_t _data_length) + Config(uint16_t _crc_offset, uint16_t _data_id, p01_data_id_mode _data_id_mode, uint16_t _data_length, uint16_t _counter_offset, uint16_t _data_id_nibble_offset) : crc_offset(_crc_offset), data_id(_data_id), - data_id_mode(_data_id_mode), data_length(_data_length) { + data_id_mode(_data_id_mode), data_length(_data_length), counter_offset(_counter_offset), data_id_nibble_offset(_data_id_nibble_offset) { } Config(const Config &_config) = default; Config &operator=(const Config &_config) = default; diff --git a/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp b/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp index 7c10f25..f5a129d 100644 --- a/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp +++ b/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp @@ -18,16 +18,24 @@ class protector final : public e2e::profile::profile_interface::protector { public: protector(void) = delete; - explicit protector(const Config &_config) : config(_config){}; + explicit protector(const Config &_config) : config(_config), counter(0){}; void protect(buffer::e2e_buffer &_buffer) override final; private: + void write_counter(buffer::e2e_buffer &_buffer); + + void write_data_id(buffer::e2e_buffer &_buffer); + void write_crc(buffer::e2e_buffer &_buffer, uint8_t _computed_crc); + void increment_counter(void); + + private: Config config; + uint8_t counter; std::mutex protect_mutex; }; } diff --git a/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp b/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp index f00ab86..d28d17c 100644 --- a/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp +++ b/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp @@ -99,7 +99,10 @@ uint8_t profile_01::compute_crc(const Config &_config, const buffer::e2e_buffer /** @req [SWS_E2E_00356] */ bool profile_01::is_buffer_length_valid(const Config &_config, const buffer::e2e_buffer &_buffer) { - return (((_config.data_length / 8) + 1U <= _buffer.size()) && _config.crc_offset <= _buffer.size()); + return (((_config.data_length / 8) + 1U <= _buffer.size()) + && _config.crc_offset <= _buffer.size() + && _config.counter_offset / 8 <= _buffer.size() + && _config.data_id_nibble_offset / 8 <= _buffer.size()); } } } diff --git a/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp b/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp index f3e7134..639eb4c 100644 --- a/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp +++ b/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp @@ -21,19 +21,57 @@ void protector::protect(buffer::e2e_buffer &_buffer) { std::lock_guard<std::mutex> lock(protect_mutex); if(profile_01::is_buffer_length_valid(config, _buffer)) { + // write the current Counter value in Data + write_counter(_buffer); + + // write DataID nibble in Data (E2E_P01_DATAID_NIBBLE) in Data + write_data_id(_buffer); + // compute the CRC over DataID and Data uint8_t computed_crc = profile_01::compute_crc(config, _buffer); // write CRC in Data write_crc(_buffer, computed_crc); + + // increment the Counter (new value will be used in the next invocation of E2E_P01Protect()), + increment_counter(); } } +/** @req [SRS_E2E_08528] */ +void protector::write_counter(buffer::e2e_buffer &_buffer) { + if(config.counter_offset % 8 == 0) { + // write write counter value into low nibble + _buffer[config.counter_offset / 8] = static_cast<uint8_t>((_buffer[config.counter_offset / 8] & 0xF0) | (counter & 0x0F)); + } else { + // write counter into high nibble + _buffer[config.counter_offset / 8] = static_cast<uint8_t>((_buffer[config.counter_offset / 8] & 0x0F) | ((counter << 4) & 0xF0)); + } +} + +/** @req [SRS_E2E_08528] */ +void protector::write_data_id(buffer::e2e_buffer &_buffer) { + if(config.data_id_mode == p01_data_id_mode::E2E_P01_DATAID_NIBBLE) { + if(config.data_id_nibble_offset % 8 == 0) { + // write low nibble of high byte of Data ID + _buffer[config.data_id_nibble_offset / 8] = static_cast<uint8_t>((_buffer[config.data_id_nibble_offset / 8] & 0xF0) | ((config.data_id >> 8) & 0x0F)); + } else { + // write low nibble of high byte of Data ID + _buffer[config.data_id_nibble_offset / 8] = static_cast<uint8_t>((_buffer[config.data_id_nibble_offset / 8] & 0x0F) | ((config.data_id >> 4) & 0xF0)); + } + } +} /** @req [SRS_E2E_08528] */ void protector::write_crc(buffer::e2e_buffer &_buffer, uint8_t _computed_crc) { _buffer[config.crc_offset] = _computed_crc; } +/** @req [SWS_E2E_00075] */ +void protector::increment_counter(void) { + counter = static_cast<uint8_t>((counter + 1U) % 15); +} + + } } } diff --git a/implementation/endpoints/include/local_server_endpoint_impl.hpp b/implementation/endpoints/include/local_server_endpoint_impl.hpp index b6c26a7..f9fa0ab 100644 --- a/implementation/endpoints/include/local_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/local_server_endpoint_impl.hpp @@ -9,10 +9,10 @@ #include <map> #include <thread> #include <condition_variable> +#include <memory> #include <boost/asio/io_service.hpp> #include <boost/asio/local/stream_protocol.hpp> -#include <boost/enable_shared_from_this.hpp> #ifdef _WIN32 #include <boost/asio/ip/tcp.hpp> @@ -56,7 +56,6 @@ public: void start(); void stop(); - void restart(); void receive(); bool send_to(const std::shared_ptr<endpoint_definition>, @@ -70,14 +69,15 @@ public: void accept_client_func(); private: - class connection: public boost::enable_shared_from_this<connection> { + class connection: public std::enable_shared_from_this<connection> { public: - typedef boost::shared_ptr<connection> ptr; + typedef std::shared_ptr<connection> ptr; static ptr create(std::weak_ptr<local_server_endpoint_impl> _server, std::uint32_t _max_message_size, - std::uint32_t _buffer_shrink_threshold); + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_service &_io_service); socket_type & get_socket(); std::unique_lock<std::mutex> get_socket_lock(); @@ -92,7 +92,8 @@ private: connection(std::weak_ptr<local_server_endpoint_impl> _server, std::uint32_t _recv_buffer_size_initial, std::uint32_t _max_message_size, - std::uint32_t _buffer_shrink_threshold); + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_service &_io_service); void send_magic_cookie(); void receive_cbk(boost::system::error_code const &_error, @@ -128,7 +129,6 @@ private: std::mutex connections_mutex_; std::map<endpoint_type, connection::ptr> connections_; - connection::ptr current_; const std::uint32_t buffer_shrink_threshold_; private: diff --git a/implementation/endpoints/include/netlink_connector.hpp b/implementation/endpoints/include/netlink_connector.hpp index 3c77bb7..db0cbc5 100644 --- a/implementation/endpoints/include/netlink_connector.hpp +++ b/implementation/endpoints/include/netlink_connector.hpp @@ -73,7 +73,7 @@ public: /// Get the underlying endpoint in the native type. const data_type* data() const { - return (struct sockaddr*)&sockaddr; + return reinterpret_cast<const struct sockaddr*>(&sockaddr); } /// Get the underlying size of the endpoint in the native type. @@ -192,7 +192,7 @@ public: void stop(); private: - bool has_address(const struct ifaddrmsg * ifa_struct, + bool has_address(struct ifaddrmsg * ifa_struct, size_t length, const unsigned int address); void send_ifa_request(); diff --git a/implementation/endpoints/include/server_endpoint_impl.hpp b/implementation/endpoints/include/server_endpoint_impl.hpp index 701d6db..710df35 100644 --- a/implementation/endpoints/include/server_endpoint_impl.hpp +++ b/implementation/endpoints/include/server_endpoint_impl.hpp @@ -36,6 +36,7 @@ public: virtual ~server_endpoint_impl();
bool is_client() const;
+ void restart();
bool is_connected() const;
bool send(const uint8_t *_data, uint32_t _size, bool _flush);
@@ -64,6 +65,7 @@ protected: std::mutex clients_mutex_;
std::map<client_t, std::map<session_t, endpoint_type> > clients_;
+ std::map<client_t, endpoint_type> clients_to_endpoint_;
boost::asio::steady_timer flush_timer_;
diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp index 410bca7..179825e 100644 --- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp @@ -7,9 +7,9 @@ #define VSOMEIP_TCP_SERVER_ENDPOINT_IMPL_HPP
#include <map>
+#include <memory>
#include <boost/asio/ip/tcp.hpp>
-#include <boost/enable_shared_from_this.hpp>
#include <vsomeip/defines.hpp>
#include <vsomeip/export.hpp>
@@ -34,8 +34,6 @@ public: void start();
void stop();
- void stop_all_connections(const boost::asio::ip::address &_address);
-
bool send_to(const std::shared_ptr<endpoint_definition> _target,
const byte_t *_data, uint32_t _size, bool _flush);
void send_queued(queue_iterator_type _queue_iterator);
@@ -53,17 +51,18 @@ public: // dummies to implement endpoint_impl interface
// TODO: think about a better design!
void receive();
- void restart();
private:
- class connection: public boost::enable_shared_from_this<connection> {
+ class connection: public std::enable_shared_from_this<connection> {
public:
- typedef boost::shared_ptr<connection> ptr;
+ typedef std::shared_ptr<connection> ptr;
static ptr create(std::weak_ptr<tcp_server_endpoint_impl> _server,
std::uint32_t _max_message_size,
- std::uint32_t _buffer_shrink_threshold);
+ std::uint32_t _buffer_shrink_threshold,
+ bool _magic_cookies_enabled,
+ boost::asio::io_service & _io_service);
socket_type & get_socket();
std::unique_lock<std::mutex> get_socket_lock();
@@ -71,8 +70,6 @@ private: void stop();
void receive();
- client_t get_client(endpoint_type _endpoint_type);
-
void send_queued(queue_iterator_type _queue_iterator);
void set_remote_info(const endpoint_type &_remote);
@@ -81,7 +78,9 @@ private: connection(std::weak_ptr<tcp_server_endpoint_impl> _server,
std::uint32_t _max_message_size,
std::uint32_t _recv_buffer_size_initial,
- std::uint32_t _buffer_shrink_threshold);
+ std::uint32_t _buffer_shrink_threshold,
+ bool _magic_cookies_enabled,
+ boost::asio::io_service & _io_service);
void send_magic_cookie(message_buffer_ptr_t &_buffer);
bool is_magic_cookie(size_t _offset) const;
void receive_cbk(boost::system::error_code const &_error,
@@ -108,6 +107,7 @@ private: endpoint_type remote_;
boost::asio::ip::address remote_address_;
std::uint16_t remote_port_;
+ std::atomic<bool> magic_cookies_enabled_;
};
std::mutex acceptor_mutex_;
diff --git a/implementation/endpoints/include/udp_server_endpoint_impl.hpp b/implementation/endpoints/include/udp_server_endpoint_impl.hpp index 8d4add0..44bca0d 100644 --- a/implementation/endpoints/include/udp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/udp_server_endpoint_impl.hpp @@ -30,7 +30,6 @@ public: void start();
void stop();
- void restart();
void receive();
bool send_to(const std::shared_ptr<endpoint_definition> _target,
diff --git a/implementation/endpoints/src/endpoint_impl.cpp b/implementation/endpoints/src/endpoint_impl.cpp index 1d16d05..4e9d9aa 100644 --- a/implementation/endpoints/src/endpoint_impl.cpp +++ b/implementation/endpoints/src/endpoint_impl.cpp @@ -47,46 +47,45 @@ uint32_t endpoint_impl<Protocol>::find_magic_cookie( byte_t *_buffer, size_t _size) {
bool is_found(false);
uint32_t its_offset = 0xFFFFFFFF;
- if (has_enabled_magic_cookies_) {
- uint8_t its_cookie_identifier, its_cookie_type;
-
- if (is_client()) {
- its_cookie_identifier =
- static_cast<uint8_t>(MAGIC_COOKIE_SERVICE_MESSAGE);
- its_cookie_type =
- static_cast<uint8_t>(MAGIC_COOKIE_SERVICE_MESSAGE_TYPE);
+
+ uint8_t its_cookie_identifier, its_cookie_type;
+
+ if (is_client()) {
+ its_cookie_identifier =
+ static_cast<uint8_t>(MAGIC_COOKIE_SERVICE_MESSAGE);
+ its_cookie_type =
+ static_cast<uint8_t>(MAGIC_COOKIE_SERVICE_MESSAGE_TYPE);
+ } else {
+ its_cookie_identifier =
+ static_cast<uint8_t>(MAGIC_COOKIE_CLIENT_MESSAGE);
+ its_cookie_type =
+ static_cast<uint8_t>(MAGIC_COOKIE_CLIENT_MESSAGE_TYPE);
+ }
+
+ do {
+ its_offset++; // --> first loop has "its_offset = 0"
+ if (_size > its_offset + 16) {
+ is_found = (_buffer[its_offset] == 0xFF
+ && _buffer[its_offset + 1] == 0xFF
+ && _buffer[its_offset + 2] == its_cookie_identifier
+ && _buffer[its_offset + 3] == 0x00
+ && _buffer[its_offset + 4] == 0x00
+ && _buffer[its_offset + 5] == 0x00
+ && _buffer[its_offset + 6] == 0x00
+ && _buffer[its_offset + 7] == 0x08
+ && _buffer[its_offset + 8] == 0xDE
+ && _buffer[its_offset + 9] == 0xAD
+ && _buffer[its_offset + 10] == 0xBE
+ && _buffer[its_offset + 11] == 0xEF
+ && _buffer[its_offset + 12] == 0x01
+ && _buffer[its_offset + 13] == 0x01
+ && _buffer[its_offset + 14] == its_cookie_type
+ && _buffer[its_offset + 15] == 0x00);
} else {
- its_cookie_identifier =
- static_cast<uint8_t>(MAGIC_COOKIE_CLIENT_MESSAGE);
- its_cookie_type =
- static_cast<uint8_t>(MAGIC_COOKIE_CLIENT_MESSAGE_TYPE);
+ break;
}
- do {
- its_offset++; // --> first loop has "its_offset = 0"
- if (_size > its_offset + 16) {
- is_found = (_buffer[its_offset] == 0xFF
- && _buffer[its_offset + 1] == 0xFF
- && _buffer[its_offset + 2] == its_cookie_identifier
- && _buffer[its_offset + 3] == 0x00
- && _buffer[its_offset + 4] == 0x00
- && _buffer[its_offset + 5] == 0x00
- && _buffer[its_offset + 6] == 0x00
- && _buffer[its_offset + 7] == 0x08
- && _buffer[its_offset + 8] == 0xDE
- && _buffer[its_offset + 9] == 0xAD
- && _buffer[its_offset + 10] == 0xBE
- && _buffer[its_offset + 11] == 0xEF
- && _buffer[its_offset + 12] == 0x01
- && _buffer[its_offset + 13] == 0x01
- && _buffer[its_offset + 14] == its_cookie_type
- && _buffer[its_offset + 15] == 0x00);
- } else {
- break;
- }
-
- } while (!is_found);
- }
+ } while (!is_found);
return (is_found ? its_offset : 0xFFFFFFFF);
}
diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp index e9de8f7..3238153 100644 --- a/implementation/endpoints/src/local_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp @@ -107,7 +107,6 @@ void local_client_endpoint_impl::connect() { }
void local_client_endpoint_impl::receive() {
-#ifndef _WIN32
std::lock_guard<std::mutex> its_lock(socket_mutex_);
if (socket_->is_open()) {
socket_->async_receive(
@@ -122,7 +121,6 @@ void local_client_endpoint_impl::receive() { )
);
}
-#endif
}
void local_client_endpoint_impl::send_queued() {
diff --git a/implementation/endpoints/src/local_server_endpoint_impl.cpp b/implementation/endpoints/src/local_server_endpoint_impl.cpp index 0e9bd4f..5a44f2f 100644 --- a/implementation/endpoints/src/local_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_server_endpoint_impl.cpp @@ -32,7 +32,6 @@ local_server_endpoint_impl::local_server_endpoint_impl( std::uint32_t _buffer_shrink_threshold) : local_server_endpoint_base_impl(_host, _local, _io, _max_message_size), acceptor_(_io), - current_(nullptr), buffer_shrink_threshold_(_buffer_shrink_threshold) { is_supporting_magic_cookies_ = false; @@ -61,7 +60,6 @@ local_server_endpoint_impl::local_server_endpoint_impl( std::uint32_t _buffer_shrink_threshold) : local_server_endpoint_base_impl(_host, _local, _io, _max_message_size), acceptor_(_io), - current_(nullptr), buffer_shrink_threshold_(_buffer_shrink_threshold) { is_supporting_magic_cookies_ = false; @@ -86,21 +84,22 @@ bool local_server_endpoint_impl::is_local() const { void local_server_endpoint_impl::start() { std::lock_guard<std::mutex> its_lock(acceptor_mutex_); if (acceptor_.is_open()) { - current_ = connection::create( + connection::ptr new_connection = connection::create( std::dynamic_pointer_cast<local_server_endpoint_impl>( shared_from_this()), max_message_size_, - buffer_shrink_threshold_); + buffer_shrink_threshold_, + service_); { - std::unique_lock<std::mutex> its_lock(current_->get_socket_lock()); + std::unique_lock<std::mutex> its_lock(new_connection->get_socket_lock()); acceptor_.async_accept( - current_->get_socket(), + new_connection->get_socket(), std::bind( &local_server_endpoint_impl::accept_cbk, std::dynamic_pointer_cast< local_server_endpoint_impl >(shared_from_this()), - current_, + new_connection, std::placeholders::_1 ) ); @@ -148,10 +147,6 @@ void local_server_endpoint_impl::receive() { // intentionally left empty } -void local_server_endpoint_impl::restart() { - current_->start(); -} - bool local_server_endpoint_impl::get_default_target( service_t, local_server_endpoint_impl::endpoint_type &) const { @@ -187,8 +182,8 @@ void local_server_endpoint_impl::accept_cbk( if (its_host->get_configuration()->is_security_enabled()) { std::unique_lock<std::mutex> its_socket_lock(_connection->get_socket_lock()); socket_type &new_connection_socket = _connection->get_socket(); - uid_t uid; - gid_t gid; + uid_t uid(0); + gid_t gid(0); client_t client = credentials::receive_credentials( new_connection_socket.native(), uid, gid); if (!its_host->check_credentials(client, uid, gid)) { @@ -232,8 +227,9 @@ local_server_endpoint_impl::connection::connection( std::weak_ptr<local_server_endpoint_impl> _server, std::uint32_t _max_message_size, std::uint32_t _initial_recv_buffer_size, - std::uint32_t _buffer_shrink_threshold) - : socket_(_server.lock()->service_), + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_service &_io_service) + : socket_(_io_service), server_(_server), recv_buffer_size_initial_(_initial_recv_buffer_size + 8), max_message_size_(_max_message_size), @@ -249,13 +245,14 @@ local_server_endpoint_impl::connection::ptr local_server_endpoint_impl::connection::create( std::weak_ptr<local_server_endpoint_impl> _server, std::uint32_t _max_message_size, - std::uint32_t _buffer_shrink_threshold) { + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_service &_io_service) { const std::uint32_t its_initial_buffer_size = VSOMEIP_COMMAND_HEADER_SIZE + VSOMEIP_MAX_LOCAL_MESSAGE_SIZE + static_cast<std::uint32_t>(sizeof(instance_t) + sizeof(bool) + sizeof(bool)); return ptr(new connection(_server, _max_message_size, its_initial_buffer_size, - _buffer_shrink_threshold)); + _buffer_shrink_threshold, _io_service)); } local_server_endpoint_impl::socket_type & @@ -281,8 +278,8 @@ void local_server_endpoint_impl::connection::start() { } const std::size_t its_required_capacity(recv_buffer_size_ + missing_capacity_); if (its_capacity < its_required_capacity) { - recv_buffer_.reserve(its_required_capacity); - recv_buffer_.resize(its_required_capacity, 0x0); + recv_buffer_.reserve(its_required_capacity); + recv_buffer_.resize(its_required_capacity, 0x0); } buffer_size = missing_capacity_; missing_capacity_ = 0; diff --git a/implementation/endpoints/src/netlink_connector.cpp b/implementation/endpoints/src/netlink_connector.cpp index 2d832c8..eb43b74 100644 --- a/implementation/endpoints/src/netlink_connector.cpp +++ b/implementation/endpoints/src/netlink_connector.cpp @@ -85,7 +85,7 @@ void netlink_connector::receive_cbk(boost::system::error_code const &_error, if (!_error) { size_t len = _bytes; - unsigned int address; + unsigned int address(0); if (address_.is_v4()) { inet_pton(AF_INET, address_.to_string().c_str(), &address); } else { @@ -247,12 +247,12 @@ void netlink_connector::send_ifi_request() { } } -bool netlink_connector::has_address(const struct ifaddrmsg * ifa_struct, +bool netlink_connector::has_address(struct ifaddrmsg * ifa_struct, size_t length, const unsigned int address) { struct rtattr *retrta; - retrta = (struct rtattr *)IFA_RTA(ifa_struct); + retrta = static_cast<struct rtattr *>(IFA_RTA(ifa_struct)); while RTA_OK(retrta, length) { if (retrta->rta_type == IFA_ADDRESS) { char pradd[128]; diff --git a/implementation/endpoints/src/server_endpoint_impl.cpp b/implementation/endpoints/src/server_endpoint_impl.cpp index 1631c5d..3d00ca4 100644 --- a/implementation/endpoints/src/server_endpoint_impl.cpp +++ b/implementation/endpoints/src/server_endpoint_impl.cpp @@ -46,6 +46,11 @@ bool server_endpoint_impl<Protocol>::is_client() const { }
template<typename Protocol>
+void server_endpoint_impl<Protocol>::restart() {
+ // intentionally left blank
+}
+
+template<typename Protocol>
bool server_endpoint_impl<Protocol>::is_connected() const {
return true;
}
@@ -88,6 +93,11 @@ bool server_endpoint_impl<Protocol>::send(const uint8_t *_data, if (found_session != found_client->second.end()) {
its_target = found_session->second;
is_valid_target = true;
+ found_client->second.erase(its_session);
+ } else {
+ VSOMEIP_WARNING << "server_endpoint::send: session_id 0x"
+ << std::hex << its_session
+ << " not found for client 0x" << its_client;
}
} else {
is_valid_target = get_default_target(its_service, its_target);
diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index cee27ae..61a8b48 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -396,7 +396,9 @@ void tcp_client_endpoint_impl::receive_cbk( if (_error == boost::asio::error::connection_reset ||
_error == boost::asio::error::eof ||
_error == boost::asio::error::timed_out) {
- VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk error detected: " << _error.message();
+ if(_error == boost::asio::error::timed_out) {
+ VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk: " << _error.message();
+ }
shutdown_and_close_socket_unlocked();
} else {
its_lock.unlock();
diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index 251137b..3f4e548 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -54,7 +54,8 @@ void tcp_server_endpoint_impl::start() { connection::ptr new_connection = connection::create( std::dynamic_pointer_cast<tcp_server_endpoint_impl>( shared_from_this()), max_message_size_, - buffer_shrink_threshold_); + buffer_shrink_threshold_, has_enabled_magic_cookies_, + service_); { std::unique_lock<std::mutex> its_socket_lock(new_connection->get_socket_lock()); @@ -85,22 +86,6 @@ void tcp_server_endpoint_impl::stop() { } } -void tcp_server_endpoint_impl::stop_all_connections(const boost::asio::ip::address &_address) { - std::lock_guard<std::mutex> its_lock(connections_mutex_); - endpoint_type type; - - for (const auto &c : connections_) { - if(c.first.address() == _address) { - VSOMEIP_INFO << "Stopping connections for " << _address.to_string() - << " : " << std::dec << c.first.port(); - c.second->stop(); - type = c.first; - } - } - connections_.erase(type); -} - - bool tcp_server_endpoint_impl::send_to( const std::shared_ptr<endpoint_definition> _target, const byte_t *_data, @@ -215,8 +200,10 @@ tcp_server_endpoint_impl::connection::connection( std::weak_ptr<tcp_server_endpoint_impl> _server, std::uint32_t _max_message_size, std::uint32_t _initial_recv_buffer_size, - std::uint32_t _buffer_shrink_threshold) : - socket_(_server.lock()->service_), + std::uint32_t _buffer_shrink_threshold, + bool _magic_cookies_enabled, + boost::asio::io_service &_io_service) : + socket_(_io_service), server_(_server), max_message_size_(_max_message_size), recv_buffer_size_initial_(_initial_recv_buffer_size), @@ -225,19 +212,24 @@ tcp_server_endpoint_impl::connection::connection( missing_capacity_(0), shrink_count_(0), buffer_shrink_threshold_(_buffer_shrink_threshold), - remote_port_(0) { + remote_port_(0), + magic_cookies_enabled_(_magic_cookies_enabled) { } tcp_server_endpoint_impl::connection::ptr tcp_server_endpoint_impl::connection::create( std::weak_ptr<tcp_server_endpoint_impl> _server, - std::uint32_t _max_message_size, std::uint32_t _buffer_shrink_threshold) { + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + bool _magic_cookies_enabled, + boost::asio::io_service & _io_service) { const std::uint32_t its_initial_receveive_buffer_size = VSOMEIP_SOMEIP_HEADER_SIZE + 8 + MAGIC_COOKIE_SIZE + 8 + VSOMEIP_MAX_TCP_MESSAGE_SIZE; return ptr(new connection(_server, _max_message_size, its_initial_receveive_buffer_size, - _buffer_shrink_threshold)); + _buffer_shrink_threshold, _magic_cookies_enabled, + _io_service)); } tcp_server_endpoint_impl::socket_type & @@ -310,7 +302,7 @@ void tcp_server_endpoint_impl::connection::send_queued( return; } message_buffer_ptr_t its_buffer = _queue_iterator->second.front(); - if (its_server->has_enabled_magic_cookies_) { + if (magic_cookies_enabled_) { send_magic_cookie(its_buffer); } @@ -384,9 +376,9 @@ void tcp_server_endpoint_impl::connection::receive_cbk( if (has_full_message) { bool needs_forwarding(true); if (is_magic_cookie(its_iteration_gap)) { - its_server->has_enabled_magic_cookies_ = true; + magic_cookies_enabled_ = true; } else { - if (its_server->has_enabled_magic_cookies_) { + if (magic_cookies_enabled_) { uint32_t its_offset = its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap], recv_buffer_size_); @@ -416,9 +408,10 @@ void tcp_server_endpoint_impl::connection::receive_cbk( sizeof(session_t)); its_server->clients_mutex_.lock(); its_server->clients_[its_client][its_session] = remote_; + its_server->clients_to_endpoint_[its_client] = remote_; its_server->clients_mutex_.unlock(); } - if (!its_server->has_enabled_magic_cookies_) { + if (!magic_cookies_enabled_) { its_host->on_message(&recv_buffer_[its_iteration_gap], current_message_size, its_server.get(), boost::asio::ip::address(), @@ -439,7 +432,7 @@ void tcp_server_endpoint_impl::connection::receive_cbk( missing_capacity_ = 0; recv_buffer_size_ -= current_message_size; its_iteration_gap += current_message_size; - } else if (its_server->has_enabled_magic_cookies_ && recv_buffer_size_ > 0){ + } else if (magic_cookies_enabled_ && recv_buffer_size_ > 0) { uint32_t its_offset = its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap], recv_buffer_size_); @@ -468,7 +461,7 @@ void tcp_server_endpoint_impl::connection::receive_cbk( recv_buffer_size_ = 0; recv_buffer_.resize(recv_buffer_size_initial_, 0x0); recv_buffer_.shrink_to_fit(); - if (its_server->has_enabled_magic_cookies_) { + if (magic_cookies_enabled_) { VSOMEIP_ERROR << "Received a TCP message which exceeds " << "maximum message size (" << std::dec << current_message_size @@ -524,7 +517,9 @@ void tcp_server_endpoint_impl::connection::receive_cbk( if (_error == boost::asio::error::eof || _error == boost::asio::error::connection_reset || _error == boost::asio::error::timed_out) { - VSOMEIP_WARNING << "tcp_server_endpoint receive_cbk error detected: " << _error.message(); + if(_error == boost::asio::error::timed_out) { + VSOMEIP_WARNING << "tcp_server_endpoint receive_cbk: " << _error.message(); + } { std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_); stop(); @@ -546,33 +541,13 @@ void tcp_server_endpoint_impl::connection::calculate_shrink_count() { } client_t tcp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definition> _endpoint) { - endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); - { - std::lock_guard<std::mutex> its_lock(connections_mutex_); - auto its_remote = connections_.find(endpoint); - if (its_remote != connections_.end()) { - return its_remote->second->get_client(endpoint); - } - } - return 0; -} - -client_t tcp_server_endpoint_impl::connection::get_client(endpoint_type _endpoint_type) { - std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock()); - if (!its_server) { - VSOMEIP_TRACE << "tcp_server_endpoint_impl::connection::get_client " - " couldn't lock server_"; - return 0; - } - std::lock_guard<std::mutex> its_lock(its_server->clients_mutex_); - for (const auto its_client : its_server->clients_) { - for (const auto its_session : its_server->clients_[its_client.first]) { - auto endpoint = its_session.second; - if (endpoint == _endpoint_type) { - // TODO: Check system byte order before convert! - client_t client = client_t(its_client.first << 8 | its_client.first >> 8); - return client; - } + const endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); + std::lock_guard<std::mutex> its_lock(clients_mutex_); + for (const auto its_client : clients_to_endpoint_) { + if (its_client.second == endpoint) { + // TODO: Check system byte order before convert! + client_t client = client_t(its_client.first << 8 | its_client.first >> 8); + return client; } } return 0; @@ -646,8 +621,4 @@ void tcp_server_endpoint_impl::receive() { // intentionally left empty } -void tcp_server_endpoint_impl::restart() { - // intentionally left empty -} - } // namespace vsomeip diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp index 7a7a2e4..bd323e4 100644 --- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp @@ -110,10 +110,6 @@ void udp_server_endpoint_impl::receive() { } } -void udp_server_endpoint_impl::restart() { - receive(); -} - bool udp_server_endpoint_impl::send_to( const std::shared_ptr<endpoint_definition> _target, const byte_t *_data, uint32_t _size, bool _flush) { @@ -313,6 +309,7 @@ void udp_server_endpoint_impl::receive_cbk( sizeof(session_t)); clients_mutex_.lock(); clients_[its_client][its_session] = remote_; + clients_to_endpoint_[its_client] = remote_; clients_mutex_.unlock(); } service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[i + VSOMEIP_SERVICE_POS_MIN], @@ -341,7 +338,7 @@ void udp_server_endpoint_impl::receive_cbk( remaining_bytes = 0; } } while (remaining_bytes > 0); - restart(); + receive(); } else { receive(); } @@ -349,15 +346,13 @@ void udp_server_endpoint_impl::receive_cbk( } client_t udp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definition> _endpoint) { - endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); + const endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); std::lock_guard<std::mutex> its_lock(clients_mutex_); - for (auto its_client : clients_) { - for (auto its_session : clients_[its_client.first]) { - if (endpoint == its_session.second) { - // TODO: Check system byte order before convert! - client_t client = client_t(its_client.first << 8 | its_client.first >> 8); - return client; - } + for (const auto its_client : clients_to_endpoint_) { + if (its_client.second == endpoint) { + // TODO: Check system byte order before convert! + client_t client = client_t(its_client.first << 8 | its_client.first >> 8); + return client; } } return 0; diff --git a/implementation/logging/include/dlt_sink_backend.hpp b/implementation/logging/include/dlt_sink_backend.hpp index 30ed027..58983a6 100644 --- a/implementation/logging/include/dlt_sink_backend.hpp +++ b/implementation/logging/include/dlt_sink_backend.hpp @@ -37,7 +37,7 @@ private: #ifdef USE_DLT DltLogLevelType level_as_dlt(logging::trivial::severity_level _level); - DLT_DECLARE_CONTEXT(dlt_); + DLT_DECLARE_CONTEXT(dlt_) #endif }; diff --git a/implementation/message/include/message_base_impl.hpp b/implementation/message/include/message_base_impl.hpp index 812c527..ad42261 100644 --- a/implementation/message/include/message_base_impl.hpp +++ b/implementation/message/include/message_base_impl.hpp @@ -62,10 +62,14 @@ public: VSOMEIP_EXPORT message * get_owner() const;
VSOMEIP_EXPORT void set_owner(message *_owner);
+ VSOMEIP_EXPORT bool is_valid_crc() const;
+ VSOMEIP_EXPORT void set_is_valid_crc(bool _is_valid_crc);
+
protected: // members
message_header_impl header_;
bool is_reliable_;
bool is_initial_;
+ bool is_valid_crc_;
};
} // namespace vsomeip
diff --git a/implementation/message/src/message_base_impl.cpp b/implementation/message/src/message_base_impl.cpp index 2d690ff..e32a914 100644 --- a/implementation/message/src/message_base_impl.cpp +++ b/implementation/message/src/message_base_impl.cpp @@ -10,7 +10,8 @@ namespace vsomeip { message_base_impl::message_base_impl()
: is_reliable_(false),
- is_initial_(false) {
+ is_initial_(false),
+ is_valid_crc_(true) {
header_.set_owner(this);
}
@@ -118,4 +119,13 @@ void message_base_impl::set_initial(bool _is_initial) { is_initial_ = _is_initial;
}
+bool message_base_impl::is_valid_crc() const {
+ return is_valid_crc_;
+}
+
+void message_base_impl::set_is_valid_crc(bool _is_valid_crc) {
+ is_valid_crc_ = _is_valid_crc;
+}
+
+
} // namespace vsomeip
diff --git a/implementation/plugin/include/plugin_manager.hpp b/implementation/plugin/include/plugin_manager.hpp new file mode 100644 index 0000000..75ae8d7 --- /dev/null +++ b/implementation/plugin/include/plugin_manager.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2016-2017 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/. + +#ifndef VSOMEIP_PLUGIN_MANAGER_HPP +#define VSOMEIP_PLUGIN_MANAGER_HPP + +#include <map> +#include <chrono> +#include <mutex> +#include <set> + +#include <vsomeip/constants.hpp> +#include <vsomeip/export.hpp> +#include <vsomeip/plugin.hpp> + +namespace vsomeip { + +class plugin_manager { +public: + VSOMEIP_EXPORT static std::shared_ptr<plugin_manager> get(); + + plugin_manager(); + + ~plugin_manager(); + + VSOMEIP_EXPORT void load_plugins(); + + VSOMEIP_EXPORT std::shared_ptr<plugin> get_plugin(plugin_type_e _type); + + VSOMEIP_EXPORT std::shared_ptr<plugin> load_plugin( + const std::string _library, plugin_type_e _type, + const uint32_t _version); + + VSOMEIP_EXPORT bool unload_plugin(plugin_type_e _type); + +private: + void add_plugin(const std::shared_ptr<plugin> &_plugin); + + void * load_library(const std::string &_path); + void * load_symbol(void * _handle, const std::string &_symbol); + + bool plugins_loaded_; + std::mutex loader_mutex_; + + std::map<plugin_type_e, std::vector<std::shared_ptr<plugin> > > plugins_; + std::map<plugin_type_e, std::string> plugin_names_; + std::map<plugin_type_e, void*> handles_; + std::mutex plugins_mutex_; + + static std::shared_ptr<plugin_manager> the_plugin_manager__; +}; +} + +#endif // VSOMEIP_PLUGIN_MANAGER_HPP diff --git a/implementation/plugin/src/plugin_manager.cpp b/implementation/plugin/src/plugin_manager.cpp new file mode 100644 index 0000000..f81d7b2 --- /dev/null +++ b/implementation/plugin/src/plugin_manager.cpp @@ -0,0 +1,212 @@ +// Copyright (C) 2016-2017 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/. + +#include <sstream> +#include <vector> +#include <stdlib.h> +#include <iostream> + +#ifdef _WIN32 + #ifndef _WINSOCKAPI_ + #include <Windows.h> + #endif +#else + #include <dlfcn.h> +#endif + +#include <vsomeip/plugins/application_plugin.hpp> +#include <vsomeip/plugins/pre_configuration_plugin.hpp> + +#include "../include/plugin_manager.hpp" +#include "../../configuration/include/internal.hpp" +#include "../../logging/include/logger.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip { + +std::shared_ptr<plugin_manager> plugin_manager::the_plugin_manager__ = + std::make_shared<plugin_manager>(); + +std::shared_ptr<plugin_manager> plugin_manager::get() { + return the_plugin_manager__; +} + +plugin_manager::plugin_manager() : + plugins_loaded_(false) { + plugin_names_[plugin_type_e::CONFIGURATION_PLUGIN] = VSOMEIP_CFG_LIBRARY; + plugin_names_[plugin_type_e::SD_RUNTIME_PLUGIN] = VSOMEIP_SD_LIBRARY; +} + +plugin_manager::~plugin_manager() { + handles_.clear(); + plugins_.clear(); + plugin_names_.clear(); +} + +void plugin_manager::load_plugins() { + { + std::lock_guard<std::mutex> its_lock_start_stop(loader_mutex_); + if (plugins_loaded_) { + return; + } + plugins_loaded_ = true; + } + + // Get plug-ins libraries from environment + std::vector<std::string> plugins; + const char *its_plugins = getenv(VSOMEIP_ENV_LOAD_PLUGINS); + if (nullptr != its_plugins) { + std::string token; + std::stringstream ss(its_plugins); + while(std::getline(ss, token, ',')) { + plugins.push_back(token); + } + } + + std::lock_guard<std::mutex> its_lock_start_stop(plugins_mutex_); + // Load plug-in info from libraries parsed before + for (auto plugin_name : plugins) { + void* handle = load_library(plugin_name); + plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>( + load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL)); + if (its_init_func) { + create_plugin_func its_create_func = (*its_init_func)(); + if (its_create_func) { + auto its_plugin = (*its_create_func)(); + if (its_plugin) { + handles_[its_plugin->get_plugin_type()] = handle; + switch (its_plugin->get_plugin_type()) { + case plugin_type_e::APPLICATION_PLUGIN: + if (its_plugin->get_plugin_version() + == VSOMEIP_APPLICATION_PLUGIN_VERSION) { + add_plugin(its_plugin); + } else { + VSOMEIP_ERROR << "Plugin version mismatch. " + << "Ignoring application plugin " + << its_plugin->get_plugin_name(); + } + break; + case plugin_type_e::PRE_CONFIGURATION_PLUGIN: + if (its_plugin->get_plugin_version() + == VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION) { + add_plugin(its_plugin); + } else { + VSOMEIP_ERROR << "Plugin version mismatch. Ignoring " + << "pre-configuration plugin " + << its_plugin->get_plugin_name(); + } + break; + default: + break; + } + } + } + } + } +} + +std::shared_ptr<plugin> plugin_manager::get_plugin(plugin_type_e _type) { + std::lock_guard<std::mutex> its_lock_start_stop(plugins_mutex_); + if (plugins_[_type].size()) { + return plugins_[_type][0]; + } else { + auto its_name = plugin_names_.find(_type); + if (its_name != plugin_names_.end()) { + return load_plugin(its_name->second, _type, 1); + } + } + return nullptr; +} + +std::shared_ptr<plugin> plugin_manager::load_plugin(const std::string _library, + plugin_type_e _type, uint32_t _version) { + void* handle = load_library(_library); + plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>( + load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL)); + if (its_init_func) { + create_plugin_func its_create_func = (*its_init_func)(); + if (its_create_func) { + handles_[_type] = handle; + auto its_plugin = (*its_create_func)(); + if (its_plugin) { + if (its_plugin->get_plugin_type() == _type + && its_plugin->get_plugin_version() == _version) { + add_plugin(its_plugin); + return its_plugin; + } else { + VSOMEIP_ERROR << "Plugin version mismatch. Ignoring plugin " + << its_plugin->get_plugin_name(); + } + } + } + } + return nullptr; +} + +bool plugin_manager::unload_plugin(plugin_type_e _type) { + std::lock_guard<std::mutex> its_lock_start_stop(plugins_mutex_); + const auto found_handle = handles_.find(_type); + if (found_handle != handles_.end()) { +#ifdef _WIN32 + FreeLibrary((HMODULE)found_handle->second); +#else + if (dlclose(found_handle->second)) { + VSOMEIP_ERROR << "Unloading failed: (" << dlerror() << ")"; + } +#endif + } else { + VSOMEIP_ERROR << "plugin_manager::unload_plugin didn't find plugin" + << " type:" << (int)_type; + return false; + } + return plugins_.erase(_type); +} + +void plugin_manager::add_plugin(const std::shared_ptr<plugin> &_plugin) { + plugins_[_plugin->get_plugin_type()].push_back(_plugin); +} + +void * plugin_manager::load_library(const std::string &_path) { +#ifdef _WIN32 + return LoadLibrary(_path.c_str()); +#else + return dlopen(_path.c_str(), RTLD_LAZY | RTLD_GLOBAL); +#endif +} + +void * plugin_manager::load_symbol(void * _handle, + const std::string &_symbol) { + void * its_symbol = 0; +#ifdef _WIN32 + HINSTANCE hDLL = (HINSTANCE)_handle; + if (hDLL != NULL) { + + typedef UINT(CALLBACK* LPFNDLLFUNC1)(DWORD, UINT); + + LPFNDLLFUNC1 lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, _symbol.c_str()); + if (!lpfnDllFunc1) { + FreeLibrary(hDLL); + std::cerr << "Loading symbol \"" << _symbol << "\" failed (" << GetLastError() << ")" << std::endl; + } + else { + its_symbol = lpfnDllFunc1; + } + } +#else + if (0 != _handle) { + its_symbol = dlsym(_handle, _symbol.c_str()); + const char *dlsym_error = dlerror(); + if (dlsym_error) { + VSOMEIP_INFO << "Cannot load symbol : " << _symbol << " : " << dlsym_error; + dlclose(_handle); + } + } else { + VSOMEIP_ERROR << "Loading failed: (" << dlerror() << ")"; + } +#endif + return (its_symbol); +} + +} diff --git a/implementation/routing/include/event.hpp b/implementation/routing/include/event.hpp index 93eee34..e493eff 100644 --- a/implementation/routing/include/event.hpp +++ b/implementation/routing/include/event.hpp @@ -105,6 +105,8 @@ public: std::set<client_t> get_subscribers(eventgroup_t _eventgroup); + bool is_subscribed(client_t _client); + private: void update_cbk(boost::system::error_code const &_error); void notify(bool _flush); diff --git a/implementation/routing/include/eventgroupinfo.hpp b/implementation/routing/include/eventgroupinfo.hpp index ae3ab87..0db929c 100644 --- a/implementation/routing/include/eventgroupinfo.hpp +++ b/implementation/routing/include/eventgroupinfo.hpp @@ -74,6 +74,8 @@ public: VSOMEIP_EXPORT uint8_t get_threshold() const; VSOMEIP_EXPORT void set_threshold(uint8_t _threshold); + VSOMEIP_EXPORT std::unique_lock<std::mutex> get_subscription_lock(); + private: std::atomic<major_version_t> major_; std::atomic<ttl_t> ttl_; @@ -90,6 +92,7 @@ private: std::list<target_t> multicast_targets_; std::atomic<uint8_t> threshold_; + std::mutex subscription_mutex_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp index 8c408c3..b14f162 100644 --- a/implementation/routing/include/routing_manager.hpp +++ b/implementation/routing/include/routing_manager.hpp @@ -62,13 +62,14 @@ public: bool _flush) = 0; virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable) = 0; + instance_t _instance, bool _flush, bool _reliable, bool _is_valid_crc = true) = 0; virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message>, bool _flush) = 0; virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, - const byte_t *_data, uint32_t _size, bool _flush) = 0; + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _flush) = 0; virtual void register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp index e0ad57e..e5d7f11 100644 --- a/implementation/routing/include/routing_manager_base.hpp +++ b/implementation/routing/include/routing_manager_base.hpp @@ -96,7 +96,7 @@ public: bool _flush); virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable) = 0; + instance_t _instance, bool _flush, bool _reliable, bool _is_valid_crc = true) = 0; // Endpoint host ~> will be implemented by routing_manager_impl/_proxy/ virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0; @@ -151,15 +151,16 @@ protected: bool send_local_notification(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _flush = true, bool _reliable = false); + bool _flush = true, bool _reliable = false, bool _is_valid_crc = true); bool send_local( std::shared_ptr<endpoint> &_target, client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _flush, bool _reliable, uint8_t _command) const; + bool _flush, bool _reliable, uint8_t _command, bool _is_valid_crc = true) const; bool insert_subscription(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, event_t _event, client_t _client); + eventgroup_t _eventgroup, event_t _event, client_t _client, + std::set<event_t> *_already_subscribed_events); std::shared_ptr<deserializer> get_deserializer(); void put_deserializer(std::shared_ptr<deserializer>); @@ -184,7 +185,8 @@ protected: void notify_one_current_value(client_t _client, service_t _service, instance_t _instance, - eventgroup_t _eventgroup, event_t _event); + eventgroup_t _eventgroup, event_t _event, + const std::set<event_t> &_events_to_exclude); void send_identify_request(service_t _service, instance_t _instance, major_version_t _major, bool _reliable); diff --git a/implementation/routing/include/routing_manager_host.hpp b/implementation/routing/include/routing_manager_host.hpp index 4b0edad..532b0db 100644 --- a/implementation/routing/include/routing_manager_host.hpp +++ b/implementation/routing/include/routing_manager_host.hpp @@ -36,6 +36,8 @@ public: client_t _client, bool _subscribed) = 0; virtual void on_subscription_error(service_t _service, instance_t _instance, eventgroup_t _eventgroup, uint16_t _error) = 0; + virtual void on_subscription_status(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error) = 0; virtual void send(std::shared_ptr<message> _message, bool _flush) = 0; }; diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp index 69a8412..0150d15 100644 --- a/implementation/routing/include/routing_manager_impl.hpp +++ b/implementation/routing/include/routing_manager_impl.hpp @@ -15,6 +15,7 @@ #include <boost/asio/ip/address.hpp> #include <boost/asio/io_service.hpp> +#include <boost/asio/steady_timer.hpp> #include <vsomeip/primitive_types.hpp> #include <vsomeip/handler.hpp> @@ -83,13 +84,14 @@ public: bool send(client_t _client, std::shared_ptr<message> _message, bool _flush); bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable); + instance_t _instance, bool _flush, bool _reliable, bool _is_valid_crc = true); bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message, bool _flush); bool send_to(const std::shared_ptr<endpoint_definition> &_target, - const byte_t *_data, uint32_t _size, bool _flush); + const byte_t *_data, uint32_t _size, + instance_t _instance, bool _flush); bool send_to(const std::shared_ptr<endpoint_definition> &_target, const byte_t *_data, uint32_t _size, uint16_t _sd_port); @@ -156,7 +158,7 @@ public: const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port); void on_message(service_t _service, instance_t _instance, - const byte_t *_data, length_t _size, bool _reliable); + const byte_t *_data, length_t _size, bool _reliable, bool _is_valid_crc = true); void on_notification(client_t _client, service_t _service, instance_t _instance, const byte_t *_data, length_t _size, bool _notify_one); @@ -181,8 +183,6 @@ public: bool _has_reliable, bool _has_unreliable); std::chrono::milliseconds update_routing_info(std::chrono::milliseconds _elapsed); - void on_reboot(const boost::asio::ip::address &_address); - void on_subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _subscriber, @@ -214,9 +214,9 @@ public: private: bool deliver_message(const byte_t *_data, length_t _length, - instance_t _instance, bool _reliable); + instance_t _instance, bool _reliable, bool _is_valid_crc = true); bool deliver_notification(service_t _service, instance_t _instance, - const byte_t *_data, length_t _length, bool _reliable); + const byte_t *_data, length_t _length, bool _reliable, bool _is_valid_crc = true); instance_t find_instance(service_t _service, endpoint *_endpoint); @@ -321,8 +321,10 @@ private: void requested_service_remove(client_t _client, service_t _service, instance_t _instance); - void call_sd_reliable_endpoint_connected(service_t _service, instance_t _instance, - std::shared_ptr<endpoint> _endpoint); + void call_sd_reliable_endpoint_connected(const boost::system::error_code& _error, + service_t _service, instance_t _instance, + std::shared_ptr<endpoint> _endpoint, + std::shared_ptr<boost::asio::steady_timer> _timer); bool create_placeholder_event_and_subscribe(service_t _service, instance_t _instance, @@ -330,6 +332,14 @@ private: event_t _event, client_t _client); + void handle_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + client_t is_specific_endpoint_client(client_t _client, service_t _service, instance_t _instance); + std::unordered_set<client_t> get_specific_endpoint_clients(service_t _service, instance_t _instance); + + bool remote_service_offered_via_tcp_and_udp(service_t _service, instance_t _instance) const; + std::shared_ptr<routing_manager_stub> stub_; std::shared_ptr<sd::service_discovery> discovery_; @@ -401,6 +411,10 @@ private: std::mutex pending_subscription_mutex_; + std::mutex remote_subscription_state_mutex_; + std::map<std::tuple<service_t, instance_t, eventgroup_t, client_t>, + subscription_state_e> remote_subscription_state_; + std::map<e2exf::data_identifier, std::shared_ptr<e2e::profile::profile_interface::protector>> custom_protectors; std::map<e2exf::data_identifier, std::shared_ptr<e2e::profile::profile_interface::checker>> custom_checkers; }; diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index 0bc25f7..6d92c39 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_proxy.hpp @@ -59,13 +59,13 @@ public: eventgroup_t _eventgroup, event_t _event); bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush = true, bool _reliable = false); + instance_t _instance, bool _flush = true, bool _reliable = false, bool _is_valid_crc= true); bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message, bool _flush); bool send_to(const std::shared_ptr<endpoint_definition> &_target, - const byte_t *_data, uint32_t _size, bool _flush); + const byte_t *_data, uint32_t _size, instance_t _instance, bool _flush); void register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, @@ -130,10 +130,10 @@ private: event_t _event) const; void on_subscribe_nack(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup); + instance_t _instance, eventgroup_t _eventgroup, event_t _event); void on_subscribe_ack(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup); + instance_t _instance, eventgroup_t _eventgroup, event_t _event); void cache_event_payload(const std::shared_ptr<message> &_message); @@ -144,8 +144,8 @@ private: void init_receiver(); - void notify_remote_initally(service_t _service, instance_t _instance, - eventgroup_t _eventgroup); + void notify_remote_initially(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::set<event_t> &_events_to_exclude); uint32_t get_remote_subscriber_count(service_t _service, instance_t _instance, eventgroup_t _eventgroup, bool _increment); @@ -209,8 +209,8 @@ private: }; std::set<event_data_t> pending_event_registrations_; - std::map<client_t, std::set<subscription_data_t>> pending_ingoing_subscripitons_; - std::mutex pending_ingoing_subscripitons_mutex_; + std::map<client_t, std::set<subscription_data_t>> pending_incoming_subscripitons_; + std::mutex incoming_subscripitons_mutex_; std::mutex deserialize_mutex_; diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index 13911dc..385c9cf 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -100,8 +100,6 @@ private: void on_register_application(client_t _client); void on_deregister_application(client_t _client); - void broadcast_routing_stop(); - void inform_requesters(client_t _hoster, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, routing_info_entry_e _entry, diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp index 344d594..ec60c37 100644 --- a/implementation/routing/include/routing_manager_stub_host.hpp +++ b/implementation/routing/include/routing_manager_stub_host.hpp @@ -53,7 +53,7 @@ public: instance_t _instance, eventgroup_t _eventgroup, event_t _event) = 0; virtual void on_message(service_t _service, instance_t _instance, - const byte_t *_data, length_t _size, bool _reliable) = 0; + const byte_t *_data, length_t _size, bool _reliable, bool _is_valid_crc = true) = 0; virtual void on_notification(client_t _client, service_t _service, instance_t _instance, diff --git a/implementation/routing/src/event.cpp b/implementation/routing/src/event.cpp index df39b1c..5dd6309 100644 --- a/implementation/routing/src/event.cpp +++ b/implementation/routing/src/event.cpp @@ -441,4 +441,14 @@ std::set<client_t> event::get_subscribers(eventgroup_t _eventgroup) { return its_subscribers; } +bool event::is_subscribed(client_t _client) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (const auto &egp : eventgroups_) { + if (egp.second.find(_client) != egp.second.end()) { + return true; + } + } + return false; +} + } // namespace vsomeip diff --git a/implementation/routing/src/eventgroupinfo.cpp b/implementation/routing/src/eventgroupinfo.cpp index 0a32861..2f02a5c 100644 --- a/implementation/routing/src/eventgroupinfo.cpp +++ b/implementation/routing/src/eventgroupinfo.cpp @@ -189,4 +189,8 @@ void eventgroupinfo::set_threshold(uint8_t _threshold) { threshold_ = _threshold; } +std::unique_lock<std::mutex> eventgroupinfo::get_subscription_lock() { + return std::unique_lock<std::mutex>(subscription_mutex_); +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp index 04e4adb..19d1b86 100644 --- a/implementation/routing/src/routing_manager_base.cpp +++ b/implementation/routing/src/routing_manager_base.cpp @@ -71,6 +71,19 @@ bool routing_manager_base::offer_service(client_t _client, service_t _service, its_info = create_service_info(_service, _instance, _major, _minor, DEFAULT_TTL, true); } + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + // Set major version for all registered events of this service and instance + const auto found_service = events_.find(_service); + if (found_service != events_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &j : found_instance->second) { + j.second->set_version(_major); + } + } + } + } return true; } @@ -315,10 +328,12 @@ void routing_manager_base::subscribe(client_t _client, service_t _service, (void) _major; (void) _subscription_type; - - bool inserted = insert_subscription(_service, _instance, _eventgroup, _event, _client); + std::set<event_t> its_already_subscribed_events; + bool inserted = insert_subscription(_service, _instance, _eventgroup, + _event, _client, &its_already_subscribed_events); if (inserted) { - notify_one_current_value(_client, _service, _instance, _eventgroup, _event); + notify_one_current_value(_client, _service, _instance, _eventgroup, + _event, its_already_subscribed_events); } } @@ -468,11 +483,10 @@ void routing_manager_base::unset_all_eventpayloads(service_t _service, } } -void routing_manager_base::notify_one_current_value(client_t _client, - service_t _service, - instance_t _instance, - eventgroup_t _eventgroup, - event_t _event) { +void routing_manager_base::notify_one_current_value( + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + const std::set<event_t> &_events_to_exclude) { if (_event != ANY_EVENT) { std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event && its_event->is_field()) @@ -482,8 +496,11 @@ void routing_manager_base::notify_one_current_value(client_t _client, if (its_eventgroup) { std::set<std::shared_ptr<event> > its_events = its_eventgroup->get_events(); for (auto e : its_events) { - if (e->is_field()) + if (e->is_field() + && _events_to_exclude.find(e->get_event()) + == _events_to_exclude.end()) { e->notify_one(_client, true); // TODO: use _flush to send all events together! + } } } } @@ -603,7 +620,7 @@ client_t routing_manager_base::find_local_client(service_t _service, instance_t std::shared_ptr<endpoint> routing_manager_base::create_local_unlocked(client_t _client) { std::stringstream its_path; - its_path << VSOMEIP_BASE_PATH << std::hex << _client; + its_path << utility::get_base_path(configuration_) << std::hex << _client; #ifdef _WIN32 boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); @@ -795,7 +812,7 @@ void routing_manager_base::remove_eventgroup_info(service_t _service, bool routing_manager_base::send_local_notification(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _flush, bool _reliable) { + bool _flush, bool _reliable, bool _is_valid_crc) { #ifdef USE_DLT bool has_local(false); #endif @@ -822,7 +839,7 @@ bool routing_manager_base::send_local_notification(client_t _client, std::shared_ptr<endpoint> its_local_target = find_local(its_client); if (its_local_target) { send_local(its_local_target, _client, _data, _size, - _instance, _flush, _reliable, VSOMEIP_SEND); + _instance, _flush, _reliable, VSOMEIP_SEND, _is_valid_crc); } } } @@ -833,7 +850,7 @@ bool routing_manager_base::send_local_notification(client_t _client, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(nullptr, true)) + if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); } @@ -844,9 +861,9 @@ bool routing_manager_base::send_local_notification(client_t _client, bool routing_manager_base::send_local( std::shared_ptr<endpoint>& _target, client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _flush, bool _reliable, uint8_t _command) const { + bool _flush, bool _reliable, uint8_t _command, bool _is_valid_crc) const { std::size_t its_complete_size = _size + sizeof(instance_t) - + sizeof(bool) + sizeof(bool); + + sizeof(bool) + sizeof(bool) + sizeof(bool); client_t sender = get_client(); if (_command == VSOMEIP_NOTIFY_ONE) { its_complete_size +=sizeof(client_t); @@ -866,10 +883,12 @@ bool routing_manager_base::send_local( + sizeof(instance_t)], &_flush, sizeof(bool)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + sizeof(instance_t) + sizeof(bool)], &_reliable, sizeof(bool)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + + sizeof(instance_t) + sizeof(bool) + sizeof(bool)], &_is_valid_crc, sizeof(bool)); if (_command == VSOMEIP_NOTIFY_ONE) { // Add target client std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size - + sizeof(instance_t) + sizeof(bool) + sizeof(bool)], &_client, sizeof(client_t)); + + sizeof(instance_t) + sizeof(bool) + sizeof(bool) + sizeof(bool)], &_client, sizeof(client_t)); } return _target->send(&its_command[0], uint32_t(its_command.size())); @@ -877,7 +896,7 @@ bool routing_manager_base::send_local( bool routing_manager_base::insert_subscription( service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, client_t _client) { + event_t _event, client_t _client, std::set<event_t> *_already_subscribed_events) { bool is_inserted(false); if (_event != ANY_EVENT) { // subscribe to specific event std::shared_ptr<event> its_event = find_event(_service, _instance, _event); @@ -905,7 +924,13 @@ bool routing_manager_base::insert_subscription( if (!its_events.size()) { create_place_holder = true; } else { - for (auto e : its_events) { + for (const auto &e : its_events) { + if (e->is_subscribed(_client)) { + // client is already subscribed to event from eventgroup + // this can happen if events are members of multiple + // eventgroups + _already_subscribed_events->insert(e->get_event()); + } is_inserted = e->add_subscriber(_eventgroup, _client) || is_inserted; } } diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 96e3b08..343741f 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -13,6 +13,8 @@ #include <systemd/sd-daemon.h> #endif +#include <boost/asio/steady_timer.hpp> + #include <vsomeip/constants.hpp> #include <vsomeip/message.hpp> #include <vsomeip/payload.hpp> @@ -42,6 +44,7 @@ #include "../../service_discovery/include/service_discovery_impl.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" +#include "../../plugin/include/plugin_manager.hpp" #include "../../e2e_protection/include/buffer/buffer.hpp" #include "../../e2e_protection/include/e2exf/config.hpp" @@ -89,14 +92,11 @@ void routing_manager_impl::init() { if (configuration_->is_sd_enabled()) { VSOMEIP_INFO<< "Service Discovery enabled. Trying to load module."; - std::shared_ptr<sd::runtime> *its_runtime = - static_cast<std::shared_ptr<sd::runtime> *>(utility::load_library( - VSOMEIP_SD_LIBRARY, - VSOMEIP_SD_RUNTIME_SYMBOL_STRING)); - - if (its_runtime && (*its_runtime)) { + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::SD_RUNTIME_PLUGIN); + if (its_plugin) { VSOMEIP_INFO << "Service Discovery module loaded."; - discovery_ = (*its_runtime)->create_service_discovery(this); + discovery_ = std::dynamic_pointer_cast<sd::runtime>(its_plugin)->create_service_discovery(this); discovery_->init(); } } @@ -109,7 +109,7 @@ void routing_manager_impl::init() { if(its_cfg->profile == "CRC8") { e2exf::data_identifier its_data_identifier = {its_cfg->service_id, its_cfg->event_id}; e2e::profile::profile01::Config its_profile_config = e2e::profile::profile01::Config(its_cfg->crc_offset, its_cfg->data_id, - (e2e::profile::profile01::p01_data_id_mode) its_cfg->data_id_mode, its_cfg->data_length); + (e2e::profile::profile01::p01_data_id_mode) its_cfg->data_id_mode, its_cfg->data_length, its_cfg->counter_offset, its_cfg->data_id_nibble_offset); if ((its_cfg->variant == "protector") || (its_cfg->variant == "both")) { custom_protectors[its_data_identifier] = std::make_shared<e2e::profile::profile01::protector>(its_profile_config); } @@ -218,20 +218,6 @@ bool routing_manager_impl::offer_service(client_t _client, service_t _service, } } - { - std::lock_guard<std::mutex> its_lock(events_mutex_); - // Set major version for all registered events of this service and instance - auto find_service = events_.find(_service); - if (find_service != events_.end()) { - auto find_instance = find_service->second.find(_instance); - if (find_instance != find_service->second.end()) { - for (auto j : find_instance->second) { - j.second->set_version(_major); - } - } - } - } - if (discovery_) { std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); if (its_info) { @@ -241,11 +227,12 @@ bool routing_manager_impl::offer_service(client_t _client, service_t _service, { std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); + std::set<event_t> its_already_subscribed_events; for (auto &ps : pending_subscriptions_) { if (ps.service_ == _service && ps.instance_ == _instance && ps.major_ == _major) { insert_subscription(ps.service_, ps.instance_, - ps.eventgroup_, ps.event_, client_); + ps.eventgroup_, ps.event_, client_, &its_already_subscribed_events); } } send_pending_subscriptions(_service, _instance, _major); @@ -402,8 +389,8 @@ void routing_manager_impl::subscribe(client_t _client, service_t _service, << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << ":" << std::hex << std::setw(4) << std::setfill('0') << _event << ":" << std::dec << (uint16_t)_major << "]"; - - if (get_client() == find_local_client(_service, _instance)) { + const client_t its_local_client = find_local_client(_service, _instance); + if (get_client() == its_local_client) { bool subscription_accepted = host_->on_subscription(_service, _instance, _eventgroup, _client, true); (void) find_or_create_local(_client); if (!subscription_accepted) { @@ -420,37 +407,46 @@ void routing_manager_impl::subscribe(client_t _client, service_t _service, } else { if (discovery_) { client_t subscriber = VSOMEIP_ROUTING_CLIENT; - if (0 == find_local_client(_service, _instance)) { - // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint - bool identify(false); - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(_service); - if (found_service != specific_endpoint_clients_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_client = found_instance->second.find(_client); - if(found_client != found_instance->second.end()) { - subscriber = _client; - if (supports_selective(_service, _instance)) { - identify = true; - } else { - VSOMEIP_INFO << "Subcribe to legacy selective service: " << std::hex - << _service << ":" << _instance << "."; - } - } - } + if (0 == its_local_client) { + subscriber = is_specific_endpoint_client(_client, _service, _instance); + if (subscriber != VSOMEIP_ROUTING_CLIENT) { + if (supports_selective(_service, _instance)) { + identify_for_subscribe(_client, _service, _instance, + _major, _subscription_type); + } else { + VSOMEIP_INFO << "Subcribe to legacy selective service: " << std::hex + << _service << ":" << _instance << "."; } } - if(identify) { - identify_for_subscribe(_client, _service, _instance, _major, _subscription_type); - } } - bool inserted = insert_subscription(_service, _instance, _eventgroup, _event, _client); + std::unique_lock<std::mutex> eventgroup_lock; + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + eventgroup_lock = its_eventgroup->get_subscription_lock(); + } + std::set<event_t> its_already_subscribed_events; + bool inserted = insert_subscription(_service, _instance, _eventgroup, + _event, _client, &its_already_subscribed_events); if (inserted) { - if (0 == find_local_client(_service, _instance)) { + if (0 == its_local_client) { + handle_subscription_state(_client, _service, _instance, _eventgroup, _event); + if (its_eventgroup) { + eventgroup_lock.unlock(); + } static const ttl_t configured_ttl(configuration_->get_sd_ttl()); - notify_one_current_value(_client, _service, _instance, _eventgroup, _event); + std::uint8_t number_notify_initially(1); + if (_subscription_type == subscription_type_e::SU_RELIABLE_AND_UNRELIABLE && + remote_service_offered_via_tcp_and_udp(_service, _instance)) { + // to be consistent with remote initial events clients + // which want to subscribe via TCP and UDP need to get + // two initial events if the service is offered via TCP + // and UDP + number_notify_initially = 2; + } + for (std::uint8_t i = 0; i < number_notify_initially; i++) { + notify_one_current_value(_client, _service, _instance, + _eventgroup, _event, its_already_subscribed_events); + } discovery_->subscribe(_service, _instance, _eventgroup, _major, configured_ttl, subscriber, _subscription_type); } else { @@ -459,6 +455,8 @@ void routing_manager_impl::subscribe(client_t _client, service_t _service, _client, _service, _instance, _eventgroup, _major, _event, false); } } + } else if (its_eventgroup) { + eventgroup_lock.unlock(); } if (get_client() == _client) { std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); @@ -501,29 +499,25 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service, if (discovery_) { host_->on_subscription(_service, _instance, _eventgroup, _client, false); if (0 == find_local_client(_service, _instance)) { - client_t subscriber = VSOMEIP_ROUTING_CLIENT; - // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(_service); - if (found_service != specific_endpoint_clients_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_client = found_instance->second.find(_client); - if(found_client != found_instance->second.end()) { - subscriber = _client; - } - } - } - } + client_t subscriber = is_specific_endpoint_client(_client, _service, _instance); if (last_subscriber_removed) { unset_all_eventpayloads(_service, _instance, _eventgroup); } if (subscriber == VSOMEIP_ROUTING_CLIENT && last_subscriber_removed) { + { + auto tuple = std::make_tuple(_service, _instance, _eventgroup, subscriber); + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + remote_subscription_state_.erase(tuple); + } // for normal subscribers only unsubscribe via SD if last // subscriber was removed discovery_->unsubscribe(_service, _instance, _eventgroup, subscriber); } else if (subscriber != VSOMEIP_ROUTING_CLIENT) { + { + auto tuple = std::make_tuple(_service, _instance, _eventgroup, subscriber); + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + remote_subscription_state_.erase(tuple); + } // for selective subscribers always unsubscribe at the SD discovery_->unsubscribe(_service, _instance, _eventgroup, subscriber); } @@ -549,7 +543,7 @@ bool routing_manager_impl::send(client_t _client, bool routing_manager_impl::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, - bool _flush, bool _reliable) { + bool _flush, bool _reliable, bool _is_valid_crc) { bool is_sent(false); if (_size > VSOMEIP_MESSAGE_TYPE_POS) { std::shared_ptr<endpoint> its_target; @@ -577,11 +571,11 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(its_target, true)) + if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); #endif - deliver_message(_data, _size, _instance, _reliable); + deliver_message(_data, _size, _instance, _reliable, _is_valid_crc); return true; } its_target = find_local(_client); @@ -593,11 +587,11 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(its_target, true)) + if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); #endif - is_sent = send_local(its_target, get_client(), _data, _size, _instance, _flush, _reliable, VSOMEIP_SEND); + is_sent = send_local(its_target, get_client(), _data, _size, _instance, _flush, _reliable, VSOMEIP_SEND, _is_valid_crc); } else { // Check whether hosting application should get the message // If not, check routes to external @@ -605,7 +599,7 @@ 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); + is_sent = deliver_message(_data, _size, _instance, _reliable, _is_valid_crc); } else { buffer::e2e_buffer outputBuffer; if( configuration_->is_e2e_enabled()) { @@ -625,20 +619,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } } if (is_request) { - client_t client = VSOMEIP_ROUTING_CLIENT; - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(its_service); - if (found_service != specific_endpoint_clients_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_client = found_instance->second.find(its_client); - if (found_client != found_instance->second.end()) { - client = its_client; - } - } - } - } + client_t client = is_specific_endpoint_client(its_client, its_service, _instance); its_target = find_or_create_remote_client(its_service, _instance, _reliable, client); if (its_target) { #ifdef USE_DLT @@ -646,7 +627,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(its_target, true)) + if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); #endif @@ -658,7 +639,7 @@ 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, _flush, _reliable); + send_local_notification(get_client(), _data, _size, _instance, _flush, _reliable, _is_valid_crc); 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); @@ -666,49 +647,52 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, #ifdef USE_DLT bool has_sent(false); #endif - std::vector< byte_t > its_data; - for (auto its_group : its_event->get_eventgroups()) { - // we need both endpoints as clients can subscribe to events via TCP and UDP - std::shared_ptr<endpoint> its_unreliable_target = its_info->get_endpoint(false); - std::shared_ptr<endpoint> its_reliable_target = its_info->get_endpoint(true); - if (its_unreliable_target || its_reliable_target) { - // remote + std::set<std::shared_ptr<endpoint_definition>> its_targets; + // we need both endpoints as clients can subscribe to events via TCP and UDP + std::shared_ptr<endpoint> its_udp_server_endpoint = its_info->get_endpoint(false); + std::shared_ptr<endpoint> its_tcp_server_endpoint = its_info->get_endpoint(true); + if (its_udp_server_endpoint || its_tcp_server_endpoint) { + for (auto its_group : its_event->get_eventgroups()) { auto its_eventgroup = find_eventgroup(its_service, _instance, its_group); if (its_eventgroup) { // Unicast targets - for (auto its_remote : its_eventgroup->get_targets()) { - if(its_remote.endpoint_->is_reliable() && its_reliable_target) { - its_reliable_target->send_to(its_remote.endpoint_, _data, _size, _flush); - } else if (its_unreliable_target && !its_eventgroup->is_sending_multicast()) { - its_unreliable_target->send_to(its_remote.endpoint_, _data, _size, _flush); + for (const auto &its_remote : its_eventgroup->get_targets()) { + if(its_remote.endpoint_->is_reliable() && its_tcp_server_endpoint) { + its_targets.insert(its_remote.endpoint_); + } else if (its_udp_server_endpoint && !its_eventgroup->is_sending_multicast()) { + its_targets.insert(its_remote.endpoint_); } -#ifdef USE_DLT - has_sent = true; -#endif } // Send to multicast targets if subscribers are still interested if (its_eventgroup->is_sending_multicast()) { for (auto its_multicast_target : its_eventgroup->get_multicast_targets()) { - its_unreliable_target->send_to(its_multicast_target.endpoint_, _data, _size, _flush); -#ifdef USE_DLT - has_sent = true; -#endif + its_targets.insert(its_multicast_target.endpoint_); } } -#ifdef USE_DLT - if (has_sent) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - - tc::trace_header its_header; - if (its_header.prepare(nullptr, true)) - tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); - } -#endif } } } + for (auto const &target : its_targets) { + if (target->is_reliable()) { + its_tcp_server_endpoint->send_to(target, _data, _size, _flush); + } else { + its_udp_server_endpoint->send_to(target, _data, _size, _flush); + } +#ifdef USE_DLT + has_sent = true; +#endif + } +#ifdef USE_DLT + if (has_sent) { + const uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); + } +#endif } } else { its_target = is_service_discovery ? @@ -719,7 +703,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(its_target, true)) + if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); #endif @@ -768,7 +752,7 @@ bool routing_manager_impl::send_to( _data = outputBuffer.data(); } } - is_sent = send_to(_target, _data, _size, _flush); + is_sent = send_to(_target, _data, _size, _message->get_instance(), _flush); serializer_->reset(); } else { VSOMEIP_ERROR<< "routing_manager_impl::send_to: serialization failed."; @@ -778,7 +762,8 @@ 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, bool _flush) { + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _flush) { std::shared_ptr<endpoint> its_endpoint = find_server_endpoint( _target->get_remote_port(), _target->is_reliable()); @@ -788,16 +773,19 @@ bool routing_manager_impl::send_to( = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(its_endpoint, true)) + if (its_header.prepare(its_endpoint, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); +#else + (void) _instance; #endif return its_endpoint->send_to(_target, _data, _size, _flush); } return false; } -bool routing_manager_impl::send_to(const std::shared_ptr<endpoint_definition> &_target, +bool routing_manager_impl::send_to( + const std::shared_ptr<endpoint_definition> &_target, const byte_t *_data, uint32_t _size, uint16_t _sd_port) { std::shared_ptr<endpoint> its_endpoint = find_server_endpoint( _sd_port, _target->is_reliable()); @@ -808,7 +796,7 @@ bool routing_manager_impl::send_to(const std::shared_ptr<endpoint_definition> &_ = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(its_endpoint, true)) + if (its_header.prepare(its_endpoint, true, 0x0)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); #endif @@ -948,9 +936,13 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, (void)_bound_client; service_t its_service; method_t its_method; + bool its_is_crc_valid(true); + instance_t its_instance(0x0); + if (_size >= VSOMEIP_SOMEIP_HEADER_SIZE) { its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); + its_instance = find_instance(its_service, _receiver); if (its_service == VSOMEIP_SD_SERVICE) { its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); @@ -967,7 +959,6 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } } } else { - instance_t its_instance = find_instance(its_service, _receiver); //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]))) { @@ -1026,6 +1017,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, if ( check_status != e2e::profile::profile_interface::generic_check_status::E2E_OK ) { VSOMEIP_INFO << std::hex << "E2E protection: CRC check failed for service: " << its_service << " method: " << its_method; + its_is_crc_valid = false; } } } @@ -1038,7 +1030,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, its_data[VSOMEIP_CLIENT_POS_MAX] = 0x0; } // Common way of message handling - on_message(its_service, its_instance, _data, _size, _receiver->is_reliable()); + on_message(its_service, its_instance, _data, _size, _receiver->is_reliable(), its_is_crc_valid); } } } @@ -1054,7 +1046,8 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, _receiver->is_local() ? tc::protocol_e::local : _receiver->is_reliable() ? tc::protocol_e::tcp : tc::protocol_e::udp; - its_header.prepare(its_remote_address, _remote_port, its_protocol, false); + 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); #endif @@ -1063,7 +1056,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, void routing_manager_impl::on_message( service_t _service, instance_t _instance, const byte_t *_data, length_t _size, - bool _reliable) { + bool _reliable, bool _is_valid_crc) { #if 0 std::stringstream msg; msg << "rmi::on_message(" @@ -1085,11 +1078,11 @@ void routing_manager_impl::on_message( if (its_client == VSOMEIP_ROUTING_CLIENT && utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - deliver_notification(_service, _instance, _data, _size, _reliable); + deliver_notification(_service, _instance, _data, _size, _reliable, _is_valid_crc); } else if (its_client == host_->get_client()) { - deliver_message(_data, _size, _instance, _reliable); + deliver_message(_data, _size, _instance, _reliable, _is_valid_crc); } else { - send(its_client, _data, _size, _instance, true, _reliable); + send(its_client, _data, _size, _instance, true, _reliable, _is_valid_crc); //send to proxy } } @@ -1115,14 +1108,21 @@ void routing_manager_impl::on_notification(client_t _client, if (its_event->is_set()) { its_event->set_payload(its_payload, false, true); } else { - // Set payload first time ~> notify all remote subscriber per unicast (inital field) + // Set payload first time ~> notify all remote subscriber per unicast (initial field) + std::vector<std::unique_lock<std::mutex>> its_locks; + std::vector<std::shared_ptr<eventgroupinfo>> its_eventgroupinfos; for (auto its_group : its_event->get_eventgroups()) { auto its_eventgroup = find_eventgroup(_service, _instance, its_group); if (its_eventgroup) { - //Unicast targets - for (auto its_remote : its_eventgroup->get_targets()) { - its_event->set_payload(its_payload, its_remote.endpoint_, true, true); - } + its_locks.push_back(its_eventgroup->get_subscription_lock()); + its_eventgroupinfos.push_back(its_eventgroup); + } + } + + for (const auto &its_eventgroup : its_eventgroupinfos) { + //Unicast targets + for (auto its_remote : its_eventgroup->get_targets()) { + its_event->set_payload(its_payload, its_remote.endpoint_, true, true); } } } @@ -1130,7 +1130,6 @@ void routing_manager_impl::on_notification(client_t _client, its_event->set_payload(its_payload, false, true); } } - } } @@ -1192,15 +1191,20 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { if (s.reliable_) { stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, s.service_id_, s.instance_id_, s.major_, s.minor_); - try { - io_.post( + 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(3), ec); + if (!ec) { + its_timer->async_wait( std::bind( &routing_manager_impl::call_sd_reliable_endpoint_connected, - std::dynamic_pointer_cast<routing_manager_impl>( - shared_from_this()), s.service_id_, - s.instance_id_, s.endpoint_)); - } catch (const std::exception &e) { - VSOMEIP_ERROR<< "routing_manager_impl::on_connect: " << e.what(); + std::static_pointer_cast<routing_manager_impl>( + shared_from_this()), + std::placeholders::_1, s.service_id_, + s.instance_id_, s.endpoint_, its_timer)); + } else { + VSOMEIP_ERROR<< "routing_manager_impl::on_connect: " << ec.message(); } } } @@ -1382,7 +1386,7 @@ 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) { + instance_t _instance, bool _reliable, bool _is_valid_crc) { bool is_delivered(false); auto a_deserializer = get_deserializer(); @@ -1394,6 +1398,7 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, if (its_message) { its_message->set_instance(_instance); its_message->set_reliable(_reliable); + its_message->set_is_valid_crc(_is_valid_crc); host_->on_message(std::move(its_message)); is_delivered = true; } else { @@ -1406,7 +1411,7 @@ 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) { + bool _reliable, bool _is_valid_crc) { bool is_delivered(false); method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], @@ -1414,8 +1419,6 @@ bool routing_manager_impl::deliver_notification( std::shared_ptr<event> its_event = find_event(_service, _instance, its_method); if (its_event) { - std::vector< byte_t > its_data; - if(its_event->is_field() && !its_event->is_provided()) { // store the current value of the remote field const uint32_t its_length(utility::get_payload_size(_data, _length)); @@ -1428,12 +1431,12 @@ bool routing_manager_impl::deliver_notification( for (const auto its_local_client : its_event->get_subscribers()) { if (its_local_client == host_->get_client()) { - deliver_message(_data, _length, _instance, _reliable); + deliver_message(_data, _length, _instance, _reliable, _is_valid_crc); } 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, true, _reliable, VSOMEIP_SEND); + _data, _length, _instance, true, _reliable, VSOMEIP_SEND, _is_valid_crc); } } } @@ -2003,17 +2006,9 @@ void routing_manager_impl::add_routing_info( } } } - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service2 = specific_endpoint_clients_.find(_service); - if (found_service2 != specific_endpoint_clients_.end()) { - auto found_instance = found_service2->second.find(_instance); - if (found_instance != found_service2->second.end()) { - for (const client_t& c : found_instance->second) { - find_or_create_remote_client(_service, _instance, true, c); - } - } - } + auto specific_endpoint_clients = get_specific_endpoint_clients(_service, _instance); + for (const client_t& c : specific_endpoint_clients) { + find_or_create_remote_client(_service, _instance, true, c); } } else if (_reliable_port != ILLEGAL_PORT && is_reliable_known) { std::lock_guard<std::mutex> its_lock(requested_services_mutex_); @@ -2355,6 +2350,7 @@ void routing_manager_impl::on_subscribe( std::shared_ptr<eventgroupinfo> its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { + std::unique_lock<std::mutex> its_subscriptions_lock(its_eventgroup->get_subscription_lock()); // IP address of target is a multicast address if the event is in a multicast eventgroup bool target_added(false); if (its_eventgroup->is_multicast() && !_subscriber->is_reliable()) { @@ -2491,50 +2487,97 @@ void routing_manager_impl::on_subscribe_ack(service_t _service, void routing_manager_impl::on_subscribe_ack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(_service); - if(found_service != specific_endpoint_clients_.end()){ - auto found_instance = found_service->second.find(_instance); - if(found_instance != found_service->second.end()) { - auto found_client = found_instance->second.find(_client); - if(found_client == found_instance->second.end()) { - // Ack is only interesting for proxies using its own endpoint! + client_t its_client = is_specific_endpoint_client(_client, _service, _instance); + bool specific_endpoint_client = its_client != VSOMEIP_ROUTING_CLIENT; + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + std::unique_lock<std::mutex> eventgroup_lock(its_eventgroup->get_subscription_lock()); + { + auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, its_client); + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + auto its_state = remote_subscription_state_.find(its_tuple); + if (its_state != remote_subscription_state_.end()) { + if (its_state->second == subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) { + // Already notified! return; } } + remote_subscription_state_[its_tuple] = subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED; + } + + if (specific_endpoint_client) { + if (_client == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } else { + stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, + _event); + } + } else { + std::set<client_t> subscribed_clients; + for (auto its_event : its_eventgroup->get_events()) { + for (auto its_client : its_event->get_subscribers()) { + subscribed_clients.insert(its_client); + } + } + for (auto its_subscriber : subscribed_clients) { + if (its_subscriber == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } else { + stub_->send_subscribe_ack(its_subscriber, _service, _instance, + _eventgroup, _event); + } + } } - } - if (_client == get_client()) { - host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); - } else { - stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, - _event); } } void routing_manager_impl::on_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(_service); - if(found_service != specific_endpoint_clients_.end()){ - auto found_instance = found_service->second.find(_instance); - if(found_instance != found_service->second.end()) { - auto found_client = found_instance->second.find(_client); - if(found_client == found_instance->second.end()) { - // Nack is only interesting for proxies using its own endpoint! + client_t its_client = is_specific_endpoint_client(_client, _service, _instance); + bool specific_endpoint_client = its_client != VSOMEIP_ROUTING_CLIENT; + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + std::unique_lock<std::mutex> eventgroup_lock(its_eventgroup->get_subscription_lock()); + { + auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, its_client); + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + auto its_state = remote_subscription_state_.find(its_tuple); + if (its_state != remote_subscription_state_.end()) { + if (its_state->second == subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED) { + // Already notified! return; } } + remote_subscription_state_[its_tuple] = subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; + } + if (specific_endpoint_client) { + if (_client == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x7 /*Rejected*/); + } else { + stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, + _event); + } + } else { + std::set<client_t> subscribed_clients; + for (auto its_event : its_eventgroup->get_events()) { + for (auto its_client : its_event->get_subscribers()) { + subscribed_clients.insert(its_client); + } + } + for (auto its_subscriber : subscribed_clients) { + if (its_subscriber == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x7 /*Rejected*/); + } else { + stub_->send_subscribe_nack(its_subscriber, _service, _instance, + _eventgroup, _event); + } + } } - } - if (_client == get_client()) { - host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); - } else { - stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, - _event); } } @@ -2583,17 +2626,7 @@ bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service, void routing_manager_impl::clear_client_endpoints(service_t _service, instance_t _instance, bool _reliable) { - std::unordered_set<client_t> its_specific_endpoint_clients; - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(_service); - if(found_service != specific_endpoint_clients_.end()){ - auto found_instance = found_service->second.find(_instance); - if(found_instance != found_service->second.end()) { - its_specific_endpoint_clients = found_instance->second; - } - } - } + auto its_specific_endpoint_clients = get_specific_endpoint_clients(_service, _instance); { std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); std::shared_ptr<endpoint> deleted_endpoint; @@ -2828,7 +2861,7 @@ void routing_manager_impl::send_error(return_code_e _return_code, _receiver->is_reliable()); its_endpoint_def->set_remote_port(_receiver->get_local_port()); send_to(its_endpoint_def, serializer_->get_data(), - serializer_->get_size(), true); + serializer_->get_size(), _instance, true); } serializer_->reset(); } else { @@ -3360,29 +3393,22 @@ void routing_manager_impl::handle_client_error(client_t _client) { } } -void routing_manager_impl::remove_specific_client_endpoint(client_t _client, service_t _service, instance_t _instance, bool _reliable) -{ - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto found_service = specific_endpoint_clients_.find(_service); - if(found_service != specific_endpoint_clients_.end()){ - auto found_instance = found_service->second.find(_instance); - if(found_instance != found_service->second.end()) { - auto its_client = found_instance->second.find(_client); - if (its_client != found_instance->second.end()) { - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - if (remote_services_.find(_service) != remote_services_.end()) { - if (remote_services_[_service].find(_instance) != remote_services_[_service].end()) { - auto endpoint = remote_services_[_service][_instance][_client][_reliable]; - if (endpoint) { - service_instances_[_service].erase(endpoint.get()); - endpoint->stop(); - } - remote_services_[_service][_instance][_client].erase(_reliable); - auto found_endpoint = remote_services_[_service][_instance][_client].find(!_reliable); - if (found_endpoint == remote_services_[_service][_instance][_client].end()) { - remote_services_[_service][_instance].erase(_client); - } - } +void routing_manager_impl::remove_specific_client_endpoint(client_t _client, service_t _service, + instance_t _instance, bool _reliable) { + client_t its_client = is_specific_endpoint_client(_client, _service, _instance); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + if (remote_services_.find(_service) != remote_services_.end()) { + if (remote_services_[_service].find(_instance) != remote_services_[_service].end()) { + auto endpoint = remote_services_[_service][_instance][_client][_reliable]; + if (endpoint) { + service_instances_[_service].erase(endpoint.get()); + endpoint->stop(); + } + remote_services_[_service][_instance][_client].erase(_reliable); + auto found_endpoint = remote_services_[_service][_instance][_client].find(!_reliable); + if (found_endpoint == remote_services_[_service][_instance][_client].end()) { + remote_services_[_service][_instance].erase(_client); } } } @@ -3471,20 +3497,8 @@ void routing_manager_impl::remove_identifying_client(service_t _service, instanc void routing_manager_impl::unsubscribe_specific_client_at_sd( service_t _service, instance_t _instance, client_t _client) { - bool found(false); - { - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto its_service = specific_endpoint_clients_.find(_service); - if (its_service != specific_endpoint_clients_.end()) { - auto its_instance = its_service->second.find(_instance); - if (its_instance != its_service->second.end()) { - if (its_instance->second.find(_client) != its_instance->second.end()) { - found = true; - } - } - } - } - if (found && discovery_) { + client_t subscriber = is_specific_endpoint_client(_client, _service, _instance); + if (subscriber != VSOMEIP_ROUTING_CLIENT && discovery_) { discovery_->unsubscribe_client(_service, _instance, _client); } } @@ -3505,13 +3519,13 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { switch (_routing_state) { case vsomeip::routing_state_e::RS_SUSPENDED: { - // stop cycling offers for services and processing of incoming SD messages + VSOMEIP_INFO << "set routing to suspend mode"; + // stop processing of incoming SD messages discovery_->stop(); // send StopOffer messages for remotely offered services on this node - services_t offered_services = get_offered_services(); - for (const auto its_service : offered_services) { - for (const auto its_instance : its_service.second) { + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { its_instance.second->set_ttl(0); discovery_->stop_offer_service(its_service.first, its_instance.first, its_instance.second); } @@ -3525,15 +3539,9 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { } for (auto its_eventgroup : get_subscribed_eventgroups(s.first, i.first)) { discovery_->unsubscribe(s.first, i.first, its_eventgroup, VSOMEIP_ROUTING_CLIENT); - std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); - auto its_specific_service = specific_endpoint_clients_.find(s.first); - if (its_specific_service != specific_endpoint_clients_.end()) { - auto its_specific_instance = its_specific_service->second.find(i.first); - if (its_specific_instance != its_specific_service->second.end()) { - for (auto its_client : its_specific_instance->second) { - discovery_->unsubscribe(s.first, i.first, its_eventgroup, its_client); - } - } + auto specific_endpoint_clients = get_specific_endpoint_clients(s.first, i.first); + for (auto its_client : specific_endpoint_clients) { + discovery_->unsubscribe(s.first, i.first, its_eventgroup, its_client); } } } @@ -3542,9 +3550,72 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { } case vsomeip::routing_state_e::RS_RESUMED: { + VSOMEIP_INFO << "set routing to resume mode"; + + // Reset relevant in service info + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + its_instance.second->set_ttl(DEFAULT_TTL); + its_instance.second->set_is_in_mainphase(false); + } + } + // start processing of SD messages (incoming remote offers should lead to new subscribe messages) discovery_->start(); + + // Trigger initial offer phase for relevant services + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + discovery_->offer_service(its_service.first, + its_instance.first, its_instance.second); + } + } break; } + case routing_state_e::RS_DIAGNOSIS: + { + VSOMEIP_INFO << "set routing to diagnosis mode"; + discovery_->set_diagnosis_mode(true); + + // send StopOffer messages for all someip protocal services + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + if (host_->get_configuration()->is_someip( + its_service.first, its_instance.first)) { + its_instance.second->set_ttl(0); + discovery_->stop_offer_service( + its_service.first, its_instance.first, its_instance.second); + } + } + } + break; + } + case routing_state_e::RS_RUNNING: + VSOMEIP_INFO << "set routing to running mode"; + + // Reset relevant in service info + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + if (host_->get_configuration()->is_someip( + its_service.first, its_instance.first)) { + its_instance.second->set_ttl(DEFAULT_TTL); + its_instance.second->set_is_in_mainphase(false); + } + } + } + // Switch SD back to normal operation + discovery_->set_diagnosis_mode(false); + + // Trigger initial phase for relevant services + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + if (host_->get_configuration()->is_someip( + its_service.first, its_instance.first)) { + discovery_->offer_service(its_service.first, + its_instance.first, its_instance.second); + } + } + } + break; default: break; } @@ -3639,10 +3710,15 @@ routing_manager_impl::get_subscribed_eventgroups( } void routing_manager_impl::call_sd_reliable_endpoint_connected( + const boost::system::error_code& _error, service_t _service, instance_t _instance, - std::shared_ptr<endpoint> _endpoint) { + std::shared_ptr<endpoint> _endpoint, + std::shared_ptr<boost::asio::steady_timer> _timer) { + (void)_timer; + if (_error) { + return; + } if (discovery_) { - std::this_thread::sleep_for(std::chrono::milliseconds(3)); discovery_->on_reliable_endpoint_connected(_service, _instance, _endpoint); } @@ -3699,19 +3775,80 @@ bool routing_manager_impl::create_placeholder_event_and_subscribe( return is_inserted; } -void routing_manager_impl::on_reboot(const boost::asio::ip::address &_address){ - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - for (auto its_port : server_endpoints_) { - for (auto its_endpoint : its_port.second) { - if (its_endpoint.first == true) { - std::shared_ptr<tcp_server_endpoint_impl> endpoint = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(its_endpoint.second); - if (endpoint) { - endpoint->stop_all_connections(_address); +void routing_manager_impl::handle_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + + client_t subscriber = is_specific_endpoint_client(_client, _service, _instance); + auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, subscriber); + + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + auto its_state = remote_subscription_state_.find(its_tuple); + if (its_state != remote_subscription_state_.end()) { + if (its_state->second == subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) { + // Subscription already acknowledged! + if (_client == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } else { + stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); + } + } + } else { + remote_subscription_state_[its_tuple] = subscription_state_e::IS_SUBSCRIBING; + } +} + +client_t routing_manager_impl::is_specific_endpoint_client(client_t _client, + service_t _service, instance_t _instance) { + client_t result = VSOMEIP_ROUTING_CLIENT; + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if (found_service != specific_endpoint_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_client); + if(found_client != found_instance->second.end()) { + result = _client; } } } } + // A client_t != VSOMEIP_ROUTING_CLIENT implies true + return result; } +std::unordered_set<client_t> routing_manager_impl::get_specific_endpoint_clients( + service_t _service, instance_t _instance) { + std::unordered_set<client_t> result; + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if (found_service != specific_endpoint_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + result = found_instance->second; + } + } + } + return result; +} + +bool routing_manager_impl::remote_service_offered_via_tcp_and_udp( + service_t _service, instance_t _instance) const { + bool ret(false); + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + const auto found_service = remote_service_info_.find(_service); + if (found_service != remote_service_info_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (found_instance->second.find(false) != found_instance->second.end() && + found_instance->second.find(true) != found_instance->second.end()) { + ret = true; + } + } + } + return ret; +} } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index 00359f9..6e5cf6a 100644 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ b/implementation/routing/src/routing_manager_proxy.cpp @@ -139,7 +139,7 @@ void routing_manager_proxy::stop() { } std::stringstream its_client; - its_client << VSOMEIP_BASE_PATH << std::hex << client_; + its_client << utility::get_base_path(configuration_) << std::hex << client_; #ifdef _WIN32 ::_unlink(its_client.str().c_str()); #else @@ -593,7 +593,8 @@ void routing_manager_proxy::unsubscribe(client_t _client, service_t _service, bool routing_manager_proxy::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, bool _flush, - bool _reliable) { + bool _reliable, + bool _is_valid_crc) { (void)_client; bool is_sent(false); bool has_remote_subscribers(false); @@ -630,7 +631,7 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, _client == VSOMEIP_ROUTING_CLIENT) { // notify has_remote_subscribers = send_local_notification(get_client(), _data, _size, - _instance, _flush, _reliable); + _instance, _flush, _reliable, _is_valid_crc); } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && _client != VSOMEIP_ROUTING_CLIENT) { // notify_one @@ -641,12 +642,12 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(nullptr, true)) + if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); #endif return send_local(its_target, get_client(), _data, _size, - _instance, _flush, _reliable, VSOMEIP_SEND); + _instance, _flush, _reliable, VSOMEIP_SEND, _is_valid_crc); } } // If no direct endpoint could be found @@ -685,7 +686,7 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); tc::trace_header its_header; - if (its_header.prepare(nullptr, true)) + if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); } @@ -693,7 +694,7 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, if (send) { is_sent = send_local(its_target, (command == VSOMEIP_NOTIFY_ONE ? _client : get_client()), - _data, _size, _instance, _flush, _reliable, command); + _data, _size, _instance, _flush, _reliable, command, _is_valid_crc); } } return (is_sent); @@ -711,11 +712,12 @@ bool routing_manager_proxy::send_to( bool routing_manager_proxy::send_to( const std::shared_ptr<endpoint_definition> &_target, - const byte_t *_data, uint32_t _size, + const byte_t *_data, uint32_t _size, instance_t _instance, bool _flush) { (void)_target; (void)_data; (void)_size; + (void)_instance; (void)_flush; return (false); } @@ -817,14 +819,18 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, instance_t its_instance; std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) - sizeof(bool) - - sizeof(bool)], sizeof(instance_t)); + - sizeof(bool) - sizeof(bool)], sizeof(instance_t)); bool its_reliable; - std::memcpy(&its_reliable, &_data[_size - sizeof(bool)], + std::memcpy(&its_reliable, &_data[_size - sizeof(bool) - sizeof(bool)], sizeof(its_reliable)); - // reduce by size of instance, flush and reliable flag + bool its_is_vslid_crc; + std::memcpy(&its_is_vslid_crc, &_data[_size - sizeof(bool)], + sizeof(its_is_vslid_crc)); + + // reduce by size of instance, flush, reliable and is_valid_crc flag const std::uint32_t its_message_size = its_length - static_cast<uint32_t>(sizeof(its_instance) - + sizeof(bool) + sizeof(bool)); + + sizeof(bool) + sizeof(bool) + sizeof(bool)); auto a_deserializer = get_deserializer(); a_deserializer->set_data(&_data[VSOMEIP_COMMAND_PAYLOAD_POS], @@ -836,6 +842,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, if (its_message) { its_message->set_instance(its_instance); its_message->set_reliable(its_reliable); + its_message->set_is_valid_crc(its_is_vslid_crc); if (utility::is_notification(its_message->get_message_type())) { if (!configuration_->is_client_allowed(get_client(), its_message->get_service(), its_message->get_instance())) { @@ -909,48 +916,54 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 9], sizeof(is_remote_subscriber)); - if (is_remote_subscriber) { - // Remote subscriber: Notify routing manager initially + count subscribes - (void)host_->on_subscription(its_service, its_instance, - its_eventgroup, its_client, true); - bool inserted = insert_subscription(its_service, its_instance, its_eventgroup, - its_event, VSOMEIP_ROUTING_CLIENT); - if (inserted) { - notify_remote_initally(its_service, its_instance, its_eventgroup); - } - (void)get_remote_subscriber_count(its_service, its_instance, its_eventgroup, true); - } else if (is_client_known(its_client)) { - if (!configuration_->is_client_allowed(its_client, - its_service, its_instance)) { - VSOMEIP_WARNING << "Security: Client " << std::hex - << its_client << " subscribes to service/instance " - << its_service << "/" << its_instance - << " which violates the security policy ~> Skip subscribe!"; - return; - } + { + std::unique_lock<std::mutex> its_lock(incoming_subscripitons_mutex_); + if (is_remote_subscriber) { + its_lock.unlock(); + // Remote subscriber: Notify routing manager initially + count subscribes + (void)host_->on_subscription(its_service, its_instance, + its_eventgroup, its_client, true); + std::set<event_t> its_already_subscribed_events; + bool inserted = insert_subscription(its_service, its_instance, its_eventgroup, + its_event, VSOMEIP_ROUTING_CLIENT, &its_already_subscribed_events); + if (inserted) { + notify_remote_initially(its_service, its_instance, its_eventgroup, + its_already_subscribed_events); + } + (void)get_remote_subscriber_count(its_service, its_instance, its_eventgroup, true); + } else if (is_client_known(its_client)) { + its_lock.unlock(); + if (!configuration_->is_client_allowed(its_client, + its_service, its_instance)) { + VSOMEIP_WARNING << "Security: Client " << std::hex + << its_client << " subscribes to service/instance " + << its_service << "/" << its_instance + << " which violates the security policy ~> Skip subscribe!"; + return; + } - // Local & already known subscriber: create endpoint + send (N)ACK + insert subscription - (void) find_or_create_local(its_client); - bool subscription_accepted = host_->on_subscription(its_service, its_instance, - its_eventgroup, its_client, true); - if (!subscription_accepted) { - send_subscribe_nack(its_client, its_service, - its_instance, its_eventgroup, its_event); + // Local & already known subscriber: create endpoint + send (N)ACK + insert subscription + (void) find_or_create_local(its_client); + bool subscription_accepted = host_->on_subscription(its_service, its_instance, + its_eventgroup, its_client, true); + if (!subscription_accepted) { + send_subscribe_nack(its_client, its_service, + its_instance, its_eventgroup, its_event); + } else { + send_subscribe_ack(its_client, its_service, its_instance, + its_eventgroup, its_event); + routing_manager_base::subscribe(its_client, its_service, its_instance, + its_eventgroup, its_major, its_event, + subscription_type_e::SU_RELIABLE_AND_UNRELIABLE); + send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client); + } } else { - send_subscribe_ack(its_client, its_service, its_instance, - its_eventgroup, its_event); - routing_manager_base::subscribe(its_client, its_service, its_instance, + // Local & not yet known subscriber ~> set pending until subscriber gets known! + subscription_data_t subscription = { its_service, its_instance, its_eventgroup, its_major, its_event, - subscription_type_e::SU_RELIABLE_AND_UNRELIABLE); - send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client); + subscription_type_e::SU_RELIABLE_AND_UNRELIABLE}; + pending_incoming_subscripitons_[its_client].insert(subscription); } - } else { - // Local & not yet known subscriber ~> set pending until subscriber gets known! - subscription_data_t subscription = { its_service, its_instance, - its_eventgroup, its_major, its_event, - subscription_type_e::SU_RELIABLE_AND_UNRELIABLE}; - std::lock_guard<std::mutex> its_lock(pending_ingoing_subscripitons_mutex_); - pending_ingoing_subscripitons_[its_client].insert(subscription); } VSOMEIP_INFO << "SUBSCRIBE(" << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" @@ -1011,7 +1024,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], sizeof(its_event)); - on_subscribe_nack(its_subscriber, its_service, its_instance, its_eventgroup); + on_subscribe_nack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); VSOMEIP_INFO << "SUBSCRIBE NACK(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" << std::hex << std::setw(4) << std::setfill('0') << its_service << "." @@ -1036,7 +1049,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], sizeof(its_event)); - on_subscribe_ack(its_subscriber, its_service, its_instance, its_eventgroup); + on_subscribe_ack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); VSOMEIP_INFO << "SUBSCRIBE ACK(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" << std::hex << std::setw(4) << std::setfill('0') << its_service << "." @@ -1079,25 +1092,6 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, VSOMEIP_INFO << msg.str(); #endif - bool restart_sender(_size == 1); - if (restart_sender && is_started_) { - // Handle restart to routing manager! - std::unordered_set<client_t> clients_to_delete; - { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - for (auto its_client : known_clients_) { - if (its_client != get_client()) { - clients_to_delete.insert(its_client); - } - } - } - - reconnect(clients_to_delete); - - // Abort due to routing manager has stopped - return; - } - uint32_t i = 0; while (i + sizeof(uint32_t) + sizeof(routing_info_entry_e) <= _size) { routing_info_entry_e routing_info_entry; @@ -1233,14 +1227,14 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, major_version_t major_; event_t event_; }; - std::lock_guard<std::mutex> its_lock(pending_ingoing_subscripitons_mutex_); + std::lock_guard<std::mutex> its_lock(incoming_subscripitons_mutex_); std::forward_list<struct subscription_info> subscription_actions; - if (pending_ingoing_subscripitons_.size()) { + if (pending_incoming_subscripitons_.size()) { { std::lock_guard<std::mutex> its_lock(known_clients_mutex_); for (const client_t client : known_clients_) { - auto its_client = pending_ingoing_subscripitons_.find(client); - if (its_client != pending_ingoing_subscripitons_.end()) { + auto its_client = pending_incoming_subscripitons_.find(client); + if (its_client != pending_incoming_subscripitons_.end()) { for (const auto subscription : its_client->second) { subscription_actions.push_front( { subscription.service_, subscription.instance_, @@ -1268,7 +1262,7 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, send_pending_notify_ones(si.service_id_, si.instance_id_, si.eventgroup_id_, si.client_id_); } - pending_ingoing_subscripitons_.erase(si.client_id_); + pending_incoming_subscripitons_.erase(si.client_id_); } } } @@ -1307,8 +1301,6 @@ void routing_manager_proxy::register_application() { std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, sizeof(client_)); - std::memset(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], 0, - sizeof(uint32_t)); if (is_connected_) { std::lock_guard<std::mutex> its_state_lock(state_mutex_); @@ -1367,8 +1359,13 @@ void routing_manager_proxy::send_request_services(std::set<service_data_t>& _req if (!_requests.size()) { return; } - uint32_t its_size = (VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE - VSOMEIP_COMMAND_HEADER_SIZE) - * (uint32_t)_requests.size(); + size_t its_size = (VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE) * _requests.size(); + if (its_size > (std::numeric_limits<std::uint32_t>::max)()) { + VSOMEIP_ERROR<< "routing_manager_proxy::send_request_services too many" + << " requests (" << std::dec << its_size << "), returning."; + return; + } std::vector<byte_t> its_command(its_size + VSOMEIP_COMMAND_HEADER_SIZE); its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REQUEST_SERVICE; @@ -1397,7 +1394,7 @@ void routing_manager_proxy::send_request_services(std::set<service_data_t>& _req { std::lock_guard<std::mutex> its_lock(sender_mutex_); if (sender_) { - sender_->send(&its_command[0], its_size + VSOMEIP_COMMAND_HEADER_SIZE); + sender_->send(&its_command[0], static_cast<std::uint32_t>(its_size + VSOMEIP_COMMAND_HEADER_SIZE)); } } } @@ -1432,11 +1429,16 @@ void routing_manager_proxy::send_register_event(client_t _client, event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field, bool _is_provided) { - uint32_t its_eventgroups_size = uint32_t(_eventgroups.size() * sizeof(eventgroup_t)); - byte_t *its_command = new byte_t[VSOMEIP_REGISTER_EVENT_COMMAND_SIZE + its_eventgroups_size]; - uint32_t its_size = VSOMEIP_REGISTER_EVENT_COMMAND_SIZE - + its_eventgroups_size - - VSOMEIP_COMMAND_HEADER_SIZE; + std::size_t its_eventgroups_size = (_eventgroups.size() * sizeof(eventgroup_t)) + + VSOMEIP_REGISTER_EVENT_COMMAND_SIZE; + if (its_eventgroups_size > (std::numeric_limits<std::uint32_t>::max)()) { + VSOMEIP_ERROR<< "routing_manager_proxy::send_register_event too many" + << " eventgroups (" << std::dec << its_eventgroups_size << "), returning."; + return; + } + byte_t *its_command = new byte_t[its_eventgroups_size]; + uint32_t its_size = static_cast<std::uint32_t>(its_eventgroups_size) + - VSOMEIP_COMMAND_HEADER_SIZE; its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REGISTER_EVENT; std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, @@ -1464,9 +1466,7 @@ void routing_manager_proxy::send_register_event(client_t _client, { std::lock_guard<std::mutex> its_lock(sender_mutex_); if (sender_) { - sender_->send(its_command, - uint32_t(VSOMEIP_REGISTER_EVENT_COMMAND_SIZE - + its_eventgroups_size)); + sender_->send(its_command, static_cast<std::uint32_t>(its_eventgroups_size)); } } @@ -1474,15 +1474,37 @@ void routing_manager_proxy::send_register_event(client_t _client, } void routing_manager_proxy::on_subscribe_ack(client_t _client, - service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { (void)_client; - host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + if (_event == ANY_EVENT) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (auto its_event : its_eventgroup->get_events()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x0 /*OK*/); + } + } + } else { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } } void routing_manager_proxy::on_subscribe_nack(client_t _client, - service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { (void)_client; - host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); + if (_event == ANY_EVENT) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (auto its_event : its_eventgroup->get_events()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); + host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x7 /*Rejected*/); + } + } + } else { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x7 /*Rejected*/); + } } void routing_manager_proxy::on_identify_response(client_t _client, service_t _service, @@ -1575,7 +1597,7 @@ void routing_manager_proxy::send_pending_commands() { void routing_manager_proxy::init_receiver() { std::stringstream its_client; - its_client << VSOMEIP_BASE_PATH << std::hex << client_; + its_client << utility::get_base_path(configuration_) << std::hex << client_; #ifdef _WIN32 ::_unlink(its_client.str().c_str()); int port = VSOMEIP_INTERNAL_BASE_PORT + client_; @@ -1615,21 +1637,21 @@ void routing_manager_proxy::init_receiver() { #endif } -void routing_manager_proxy::notify_remote_initally(service_t _service, instance_t _instance, - eventgroup_t _eventgroup) { +void routing_manager_proxy::notify_remote_initially(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::set<event_t> &_events_to_exclude) { auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { - std::set<std::shared_ptr<event> > its_events - = its_eventgroup->get_events(); - for (auto e : its_events) { - if (e->is_field() && e->is_set()) { + auto service_info = find_service(_service, _instance); + for (const auto &e : its_eventgroup->get_events()) { + if (e->is_field() && e->is_set() + && _events_to_exclude.find(e->get_event()) + == _events_to_exclude.end()) { std::shared_ptr<message> its_notification = runtime::get()->create_notification(); its_notification->set_service(_service); its_notification->set_instance(_instance); its_notification->set_method(e->get_event()); its_notification->set_payload(e->get_payload()); - auto service_info = find_service(_service, _instance); if (service_info) { its_notification->set_interface_version(service_info->get_major()); } @@ -1706,13 +1728,11 @@ void routing_manager_proxy::register_application_timeout_cbk( } void routing_manager_proxy::send_registered_ack() { - byte_t its_command[VSOMEIP_COMMAND_HEADER_SIZE]; - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REGISTERED_ACK; + byte_t its_command[VSOMEIP_COMMAND_HEADER_SIZE] = { + VSOMEIP_REGISTERED_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; client_t client = get_client(); std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client, sizeof(client)); - std::memset(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], 0, - sizeof(uint32_t)); { std::lock_guard<std::mutex> its_lock(sender_mutex_); if (sender_) { diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 526d6ce..2ce4d63 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -154,11 +154,6 @@ void routing_manager_stub::stop() { } #endif } - - { - std::lock_guard<std::mutex> its_lock(routing_info_mutex_); - broadcast_routing_stop(); - } } const std::shared_ptr<configuration> routing_manager_stub::get_configuration() const { @@ -232,6 +227,8 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, client_t its_client_from_header; client_t its_target_client; client_t its_subscriber; + bool its_is_valid_crc(true); + its_command = _data[VSOMEIP_COMMAND_TYPE_POS]; std::memcpy(&its_client, &_data[VSOMEIP_COMMAND_CLIENT_POS], @@ -411,8 +408,11 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, its_data[VSOMEIP_CLIENT_POS_MIN], its_data[VSOMEIP_CLIENT_POS_MAX]); std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) - - sizeof(bool) - sizeof(bool)], sizeof(its_instance)); - std::memcpy(&its_reliable, &_data[_size - sizeof(bool)], sizeof(its_reliable)); + - sizeof(bool) - sizeof(bool) - sizeof(bool)], sizeof(its_instance)); + std::memcpy(&its_reliable, &_data[_size - sizeof(bool) - sizeof(bool)], sizeof(its_reliable)); + + std::memcpy(&its_is_valid_crc, &_data[_size - sizeof(bool)], sizeof(its_is_valid_crc)); + if (utility::is_request(its_data[VSOMEIP_MESSAGE_TYPE_POS])) { if (!configuration_->is_client_allowed(its_client_from_header, its_service, its_instance)) { @@ -434,11 +434,11 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, return; } } - // reduce by size of instance, flush and reliable flag + // reduce by size of instance, flush, reliable and is_valid_crc flag const std::uint32_t its_message_size = its_size - static_cast<std::uint32_t>(sizeof(its_instance) - + sizeof(bool) + sizeof(bool)); - host_->on_message(its_service, its_instance, its_data, its_message_size, its_reliable); + + sizeof(bool) + sizeof(bool) + sizeof(bool)); + host_->on_message(its_service, its_instance, its_data, its_message_size, its_reliable, its_is_valid_crc); break; } case VSOMEIP_NOTIFY: { @@ -447,8 +447,8 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, its_data[VSOMEIP_SERVICE_POS_MIN], its_data[VSOMEIP_SERVICE_POS_MAX]); std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) - - sizeof(bool) - sizeof(bool)], sizeof(its_instance)); - // reduce by size of instance, flush and reliable flag + - sizeof(bool) - sizeof(bool) - sizeof(bool)], sizeof(its_instance)); + // reduce by size of instance, flush, reliable and is_valid_crc flag const std::uint32_t its_message_size = its_size - static_cast<uint32_t>(sizeof(its_instance) + sizeof(bool) + sizeof(bool)); @@ -461,10 +461,10 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, its_data[VSOMEIP_SERVICE_POS_MIN], its_data[VSOMEIP_SERVICE_POS_MAX]); std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) - - sizeof(bool) - sizeof(bool) - sizeof(client_t)], + sizeof(bool) - sizeof(bool) - sizeof(bool) - sizeof(client_t)], sizeof(its_instance)); std::memcpy(&its_target_client, &_data[_size - sizeof(client_t)], sizeof(client_t)); - // reduce by size of instance, flush, reliable flag and target client + // reduce by size of instance, flush, reliable flag, is_valid_crc and target client const std::uint32_t its_message_size = its_size - static_cast<uint32_t>(sizeof(its_instance) + sizeof(bool) + sizeof(bool) + sizeof(client_t)); @@ -708,7 +708,8 @@ void routing_manager_stub::client_registration_func(void) { if (its_connection != connection_matrix_.end()) { for (auto its_client : its_connection->second) { if (its_client != r.first && - its_client != VSOMEIP_ROUTING_CLIENT) { + its_client != VSOMEIP_ROUTING_CLIENT && + its_client != get_client()) { create_client_routing_info(its_client); insert_client_routing_info(its_client, routing_info_entry_e::RIE_DEL_CLIENT, r.first); @@ -735,7 +736,7 @@ void routing_manager_stub::client_registration_func(void) { void routing_manager_stub::init_routing_endpoint() { std::stringstream its_endpoint_path; - its_endpoint_path << VSOMEIP_BASE_PATH << VSOMEIP_ROUTING_CLIENT; + its_endpoint_path << utility::get_base_path(configuration_) << VSOMEIP_ROUTING_CLIENT; endpoint_path_ = its_endpoint_path.str(); client_t routing_host_id = configuration_->get_id(configuration_->get_routing_host()); if (configuration_->is_security_enabled() && get_client() != routing_host_id) { @@ -893,7 +894,7 @@ void routing_manager_stub::send_client_routing_info(const client_t _target) { #if 0 std::stringstream msg; - msg << "rms::send_routing_info "; + msg << "rms::send_routing_info to (" << std::hex << _target << "): "; for (uint32_t i = 0; i < its_size; ++i) msg << std::hex << std::setw(2) << std::setfill('0') << (int)its_command[i] << " "; VSOMEIP_INFO << msg.str(); @@ -908,6 +909,9 @@ void routing_manager_stub::send_client_routing_info(const client_t _target) { } client_routing_info_.erase(_target); + } else { + VSOMEIP_ERROR << "Send routing info to client 0x" << std::hex << _target + << " failed: No valid endpoint!"; } } @@ -1009,10 +1013,13 @@ void routing_manager_stub::inform_requesters(client_t _hoster, service_t _servic } } } - create_client_routing_info(its_client.first); - insert_client_routing_info(its_client.first, _entry, _hoster, - _service, _instance, _major, _minor); - send_client_routing_info(its_client.first); + if (its_client.first != VSOMEIP_ROUTING_CLIENT && + its_client.first != get_client()) { + create_client_routing_info(its_client.first); + insert_client_routing_info(its_client.first, _entry, _hoster, + _service, _instance, _major, _minor); + send_client_routing_info(its_client.first); + } } } } @@ -1022,39 +1029,6 @@ bool routing_manager_stub::is_already_connected(client_t _source, client_t _sink return connection_matrix_[_source].find(_sink) != connection_matrix_[_source].end(); } -void routing_manager_stub::broadcast_routing_stop() { - std::vector<byte_t> its_command; - - // Routing command - its_command.push_back(VSOMEIP_ROUTING_INFO); - - // Sender client - client_t client = get_client(); - for (uint32_t i = 0; i < sizeof(client_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&client)[i]); - } - - // Overall size ~> 1 indicates routing stop - uint32_t size = 0x1; - for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&size)[i]); - } - - // Stop Placeholder - its_command.push_back(0x0); - - for (auto& info : routing_info_) { - if (info.first != VSOMEIP_ROUTING_CLIENT && info.first != host_->get_client()) { - std::shared_ptr<endpoint> its_endpoint = host_->find_local(info.first); - if (its_endpoint) { - its_endpoint->send(&its_command[0], uint32_t(its_command.size()), true); - } - } - } -} - void routing_manager_stub::broadcast(const std::vector<byte_t> &_command) const { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); for (auto a : routing_info_) { @@ -1288,7 +1262,7 @@ void routing_manager_stub::create_local_receiver() { return; } std::stringstream its_local_receiver_path; - its_local_receiver_path << VSOMEIP_BASE_PATH << std::hex << host_->get_client(); + its_local_receiver_path << utility::get_base_path(configuration_) << std::hex << host_->get_client(); local_receiver_path_ = its_local_receiver_path.str(); #if _WIN32 ::_unlink(local_receiver_path_.c_str()); @@ -1491,6 +1465,27 @@ void routing_manager_stub::update_registration(client_t _client, << (_type == registration_type_e::REGISTER ? "registering." : "deregistering."); + if (_type == registration_type_e::DEREGISTER) { + // If we receive a DEREGISTER client command + // the endpoint error handler is not longer needed + // as the client is going down anyways. + + // Normally the handler is removed in "remove_local" + // anyways, but as some time takes place until + // the client DEREGISTER command is consumed + // and therefore "remove_local" is finally called + // it was possible the same client registers itself + // again in very short time and then could "overtake" + // the occurring error in the endpoint and was then + // erroneously unregistered even that error has + // nothing to do with the newly registered client. + + auto its_endpoint = host_->find_local(_client); + if (its_endpoint) { + its_endpoint->register_error_handler(nullptr); + } + } + std::lock_guard<std::mutex> its_lock(client_registration_mutex_); pending_client_registrations_[_client].push_back(_type); client_registration_condition_.notify_one(); @@ -1509,6 +1504,7 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv if (!_requests.size()) { return; } + bool service_available(false); std::lock_guard<std::mutex> its_guard(routing_info_mutex_); create_client_routing_info(_client); for (auto request : _requests) { @@ -1522,6 +1518,7 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv found_client.first != host_->get_client()) { if (!is_already_connected(found_client.first, _client)) { if (_client == found_client.first) { + service_available = true; insert_client_routing_info(found_client.first, routing_info_entry_e::RIE_ADD_CLIENT, _client); } else { @@ -1535,6 +1532,7 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { for (auto instance : found_service->second) { + service_available = true; insert_client_routing_info(_client, routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, found_client.first, request.service_, instance.first, @@ -1549,6 +1547,7 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv found_client.first != host_->get_client()) { if (!is_already_connected(found_client.first, _client)) { if (_client == found_client.first) { + service_available = true; insert_client_routing_info(found_client.first, routing_info_entry_e::RIE_ADD_CLIENT, _client); } else { @@ -1561,6 +1560,7 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv } if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { + service_available = true; insert_client_routing_info(_client, routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, found_client.first, request.service_, request.instance_, @@ -1573,7 +1573,9 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv } } } - send_client_routing_info(_client); + if (service_available) { + send_client_routing_info(_client); + } } #ifndef _WIN32 @@ -1627,8 +1629,10 @@ void routing_manager_stub::on_client_id_timer_expired(boost::system::error_code } } for (auto client : erroneous_clients) { - VSOMEIP_WARNING << "Routinger Manager 0x" << std::hex << get_client() - << " : Release died Client 0x" << std::hex << client; + VSOMEIP_WARNING << "Expected client 0x" << std::hex + << client << " hasn't reconnected to the routing manager. " + << "Release identifier as client went offline while no" + << "routing manager was running."; host_->handle_client_error(client); } } diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp index 2dcc95b..f38cd2c 100644 --- a/implementation/runtime/include/application_impl.hpp +++ b/implementation/runtime/include/application_impl.hpp @@ -23,6 +23,7 @@ #include <vsomeip/application.hpp> #include "../../routing/include/routing_manager_host.hpp" +#include "../../configuration/include/internal.hpp" namespace vsomeip { @@ -154,6 +155,11 @@ public: eventgroup_t _eventgroup, client_t _client, bool _subscribed); VSOMEIP_EXPORT void on_subscription_error(service_t _service, instance_t _instance, eventgroup_t _eventgroup, uint16_t _error); + VSOMEIP_EXPORT void on_subscription_status(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error); + VSOMEIP_EXPORT void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler); // service_discovery_host VSOMEIP_EXPORT routing_manager * get_routing_manager() const; @@ -230,6 +236,12 @@ private: eventgroup_t _eventgroup, event_t _event); bool check_for_active_subscription(service_t _service, instance_t _instance, event_t _event); + + void deliver_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error); + + bool check_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); // // Attributes // @@ -333,6 +345,13 @@ private: bool stopped_called_; + std::map<service_t, std::map<instance_t, std::map<eventgroup_t, + std::map<event_t, subscription_status_handler_t > > > > subscription_status_handlers_; + std::mutex subscription_status_handlers_mutex_; + + std::mutex subscriptions_state_mutex_; + std::map<std::tuple<service_t, instance_t, eventgroup_t, event_t>, + subscription_state_e> subscription_state_; }; diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp index 3ae0d61..988d48f 100644 --- a/implementation/runtime/src/application_impl.cpp +++ b/implementation/runtime/src/application_impl.cpp @@ -13,6 +13,8 @@ #include <vsomeip/defines.hpp> #include <vsomeip/runtime.hpp> +#include <vsomeip/plugins/application_plugin.hpp> +#include <vsomeip/plugins/pre_configuration_plugin.hpp> #include "../include/application_impl.hpp" #include "../../configuration/include/configuration.hpp" @@ -24,6 +26,7 @@ #include "../../utility/include/utility.hpp" #include "../../tracing/include/trace_connector.hpp" #include "../../tracing/include/enumeration_types.hpp" +#include "../../plugin/include/plugin_manager.hpp" namespace vsomeip { @@ -75,19 +78,27 @@ bool application_impl::init() { } } + std::string configuration_path; + plugin_manager::get()->load_plugins(); + auto its_pre_config_plugin = plugin_manager::get()->get_plugin(plugin_type_e::PRE_CONFIGURATION_PLUGIN); + if (its_pre_config_plugin) { + configuration_path = std::dynamic_pointer_cast<pre_configuration_plugin>(its_pre_config_plugin)-> + get_configuration_path(); + } + // load configuration from module std::string config_module = ""; const char *its_config_module = getenv(VSOMEIP_ENV_CONFIGURATION_MODULE); if (nullptr != its_config_module) { // TODO: Add loading of custom configuration module } else { // load default module - std::shared_ptr<configuration> *its_configuration = - static_cast<std::shared_ptr<configuration> *>(utility::load_library( - VSOMEIP_CFG_LIBRARY, - VSOMEIP_CFG_RUNTIME_SYMBOL_STRING)); - - if (its_configuration && (*its_configuration)) { - configuration_ = (*its_configuration); + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::CONFIGURATION_PLUGIN); + if (its_plugin) { + configuration_ = std::dynamic_pointer_cast<configuration>(its_plugin); + if (configuration_path.length()) { + configuration_->set_configuration_path(configuration_path); + } configuration_->load(name_); VSOMEIP_INFO << "Default configuration module loaded."; } else { @@ -212,6 +223,24 @@ bool application_impl::init() { signals_.async_wait(its_signal_handler); } #endif + + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + auto its_application_plugin = plugin_manager::get()->get_plugin(plugin_type_e::APPLICATION_PLUGIN); + if (!its_application_plugin) { + VSOMEIP_INFO << std::hex << "Client 0x" << get_client() + << " : loading application plugin: " << its_app_plugin_info->second; + its_application_plugin = plugin_manager::get()->load_plugin( + its_app_plugin_info->second, plugin_type_e::APPLICATION_PLUGIN, + VSOMEIP_APPLICATION_PLUGIN_VERSION); + } + if (its_application_plugin) { + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_INITIALIZED); + } + } + return is_initialized_; } @@ -227,7 +256,7 @@ void application_impl::start() { } if (stopped_) { utility::release_client_id(client_); - utility::auto_configuration_exit(client_); + utility::auto_configuration_exit(client_, configuration_); { std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_); @@ -275,6 +304,16 @@ void application_impl::start() { } } + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + auto its_application_plugin = plugin_manager::get()->get_plugin(plugin_type_e::APPLICATION_PLUGIN); + if (its_application_plugin) { + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_STARTED); + } + } + app_counter_mutex__.lock(); app_counter__++; app_counter_mutex__.unlock(); @@ -290,7 +329,7 @@ void application_impl::start() { } utility::release_client_id(client_); - utility::auto_configuration_exit(client_); + utility::auto_configuration_exit(client_, configuration_); { std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_); @@ -338,6 +377,16 @@ void application_impl::stop() { block = false; } } + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + auto its_application_plugin = plugin_manager::get()->get_plugin(plugin_type_e::APPLICATION_PLUGIN); + if (its_application_plugin) { + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_STOPPED); + } + } + stop_cv_.notify_one(); if (block) { @@ -400,8 +449,10 @@ void application_impl::subscribe(service_t _service, instance_t _instance, send_back_cached_eventgroup(_service, _instance, _eventgroup); } - routing_->subscribe(client_, _service, _instance, _eventgroup, _major, - _event, _subscription_type); + if (check_subscription_state(_service, _instance, _eventgroup, _event)) { + routing_->subscribe(client_, _service, _instance, _eventgroup, _major, + _event, _subscription_type); + } } } @@ -793,6 +844,133 @@ void application_impl::unregister_subscription_handler(service_t _service, unregister_message_handler(_service, _instance, ANY_METHOD - 1); } +void application_impl::on_subscription_status(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + uint16_t _error) { + bool entry_found(false); + { + auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, _event); + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + auto its_subscription_state = subscription_state_.find(its_tuple); + if (its_subscription_state == subscription_state_.end()) { + its_tuple = std::make_tuple(_service, _instance, _eventgroup, ANY_EVENT); + auto its_any_subscription_state = subscription_state_.find(its_tuple); + if (its_any_subscription_state == subscription_state_.end()) { + VSOMEIP_TRACE << std::hex << get_client( ) + << " application_impl::on_subscription_status: " + << "Received a subscription status without subscribe for " + << std::hex << _service << "/" << _instance << "/" + << _eventgroup << "/" << _event << "/error=" << _error; + } else { + entry_found = true; + } + } else { + entry_found = true; + } + if (entry_found) { + if (_error) { + subscription_state_[its_tuple] = + subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; + } else { + subscription_state_[its_tuple] = + subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED; + } + } + } + + if (entry_found) { + deliver_subscription_state(_service, _instance, _eventgroup, _event, _error); + } +} + +void application_impl::deliver_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error) { + std::vector<subscription_status_handler_t> handlers; + { + std::lock_guard<std::mutex> its_lock(subscription_status_handlers_mutex_); + auto found_service = subscription_status_handlers_.find(_service); + if (found_service != subscription_status_handlers_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + handlers.push_back(found_event->second); + } else { + auto its_any_event = found_eventgroup->second.find(ANY_EVENT); + if (its_any_event != found_eventgroup->second.end()) { + handlers.push_back(its_any_event->second); + } + } + } + } + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + handlers.push_back(found_event->second); + } else { + auto its_any_event = found_eventgroup->second.find(ANY_EVENT); + if (its_any_event != found_eventgroup->second.end()) { + handlers.push_back(its_any_event->second); + } + } + } + } + } + found_service = subscription_status_handlers_.find(ANY_SERVICE); + if (found_service != subscription_status_handlers_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + handlers.push_back(found_event->second); + } else { + auto its_any_event = found_eventgroup->second.find(ANY_EVENT); + if (its_any_event != found_eventgroup->second.end()) { + handlers.push_back(its_any_event->second); + } + } + } + } + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + handlers.push_back(found_event->second); + } else { + auto its_any_event = found_eventgroup->second.find(ANY_EVENT); + if (its_any_event != found_eventgroup->second.end()) { + handlers.push_back(its_any_event->second); + } + } + } + } + } + } + for (auto &handler : handlers) { + std::unique_lock<std::mutex> handlers_lock(handlers_mutex_); + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>([handler, _service, + _instance, _eventgroup, + _event, _error]() { + handler(_service, _instance, + _eventgroup, _event, _error); + }); + handlers_.push_back(its_sync_handler); + } + if (handlers.size()) { + dispatcher_condition_.notify_all(); + } +} + void application_impl::on_subscription_error(service_t _service, instance_t _instance, eventgroup_t _eventgroup, uint16_t _error) { error_handler_t handler = nullptr; @@ -824,6 +1002,35 @@ void application_impl::on_subscription_error(service_t _service, } } +void application_impl::register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler) { + std::lock_guard<std::mutex> its_lock(subscription_status_handlers_mutex_); + if (_handler) { + subscription_status_handlers_[_service][_instance][_eventgroup][_event] = _handler; + } else { + auto its_service = subscription_status_handlers_.find(_service); + if (its_service != subscription_status_handlers_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_eventgroup = its_instance->second.find(_eventgroup); + if (its_eventgroup != its_instance->second.end()) { + its_eventgroup->second.erase(_event); + if (its_eventgroup->second.size() == 0) { + its_instance->second.erase(_eventgroup); + if (its_instance->second.size() == 0) { + its_service->second.erase(_instance); + if (its_service->second.size() == 0) { + subscription_status_handlers_.erase(_service); + } + } + } + } + } + } + } +} + void application_impl::register_subscription_error_handler(service_t _service, instance_t _instance, eventgroup_t _eventgroup, error_handler_t _handler) { @@ -1062,18 +1269,30 @@ void application_impl::on_availability(service_t _service, instance_t _instance, } } if (!_is_available) { - std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); - auto found_service = subscriptions_.find(_service); - if (found_service != subscriptions_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (auto &event : found_instance->second) { - for (auto &eventgroup : event.second) { - eventgroup.second = false; + { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + auto found_service = subscriptions_.find(_service); + if (found_service != subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (auto &event : found_instance->second) { + for (auto &eventgroup : event.second) { + eventgroup.second = false; + } } } } } + { + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + for (auto &its_subscription_state : subscription_state_) { + if (std::get<0>(its_subscription_state.first) == _service && + std::get<1>(its_subscription_state.first) == _instance) { + its_subscription_state.second = + subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; + } + } + } } if (its_handlers.size()) { @@ -1494,6 +1713,13 @@ void application_impl::remove_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + + { + auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, _event); + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + subscription_state_.erase(its_tuple); + } + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); auto found_service = subscriptions_.find(_service); @@ -1568,4 +1794,36 @@ bool application_impl::check_for_active_subscription(service_t _service, return false; } +bool application_impl::check_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + bool is_acknowledged(false); + bool should_subscribe(true); + { + auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, _event); + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + auto its_subscription_state = subscription_state_.find(its_tuple); + if (its_subscription_state != subscription_state_.end()) { + if (its_subscription_state->second != + subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED) { + // only return true if subscription is NACK + // as only then we need to subscribe! + should_subscribe = false; + if (its_subscription_state->second == + subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) { + is_acknowledged = true; + } + } + } else { + subscription_state_[its_tuple] = subscription_state_e::IS_SUBSCRIBING; + } + } + + if (!should_subscribe && is_acknowledged) { + // Deliver subscription state only if ACK has already received + deliver_subscription_state(_service, _instance, _eventgroup, _event, 0 /* OK */); + } + + return should_subscribe; +} + } // namespace vsomeip diff --git a/implementation/service_discovery/include/runtime.hpp b/implementation/service_discovery/include/runtime.hpp index 468d5ba..f99fec8 100644 --- a/implementation/service_discovery/include/runtime.hpp +++ b/implementation/service_discovery/include/runtime.hpp @@ -18,7 +18,6 @@ class service_discovery_host; class runtime {
public:
- static std::shared_ptr<runtime> get();
virtual ~runtime() {
}
diff --git a/implementation/service_discovery/include/runtime_impl.hpp b/implementation/service_discovery/include/runtime_impl.hpp index 4a8557f..dcdb7d7 100644 --- a/implementation/service_discovery/include/runtime_impl.hpp +++ b/implementation/service_discovery/include/runtime_impl.hpp @@ -6,14 +6,17 @@ #ifndef VSOMEIP_SD_RUNTIME_IMPL_HPP #define VSOMEIP_SD_RUNTIME_IMPL_HPP +#include <vsomeip/plugin.hpp> #include "runtime.hpp" namespace vsomeip { namespace sd { -class runtime_impl: public runtime { +class runtime_impl + : public runtime, + public plugin_impl<runtime_impl> { public: - static std::shared_ptr<runtime> get(); + runtime_impl(); virtual ~runtime_impl(); std::shared_ptr<service_discovery> create_service_discovery( diff --git a/implementation/service_discovery/include/service_discovery.hpp b/implementation/service_discovery/include/service_discovery.hpp index 19f3c93..703bf22 100644 --- a/implementation/service_discovery/include/service_discovery.hpp +++ b/implementation/service_discovery/include/service_discovery.hpp @@ -63,6 +63,8 @@ public: std::shared_ptr<serviceinfo> _info) = 0; virtual void stop_offer_service(service_t _service, instance_t _instance, std::shared_ptr<serviceinfo> _info) = 0; + + virtual void set_diagnosis_mode(const bool _activate) = 0; }; } // namespace sd diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp index 0e1de9e..e1e0ccd 100644 --- a/implementation/service_discovery/include/service_discovery_host.hpp +++ b/implementation/service_discovery/include/service_discovery_host.hpp @@ -81,9 +81,6 @@ public: virtual void expire_subscriptions(const boost::asio::ip::address &_address) = 0; virtual void expire_services(const boost::asio::ip::address &_address) = 0; - virtual void on_reboot(const boost::asio::ip::address &_address) = 0; - - virtual bool on_subscribe_accepted(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _target, const std::chrono::steady_clock::time_point &_expiration) = 0; diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp index 910fc61..b7be7ff 100644 --- a/implementation/service_discovery/include/service_discovery_impl.hpp +++ b/implementation/service_discovery/include/service_discovery_impl.hpp @@ -91,6 +91,8 @@ public: void stop_offer_service(service_t _service, instance_t _instance, std::shared_ptr<serviceinfo> _info); + void set_diagnosis_mode(const bool _activate); + private: std::pair<session_t, bool> get_session(const boost::asio::ip::address &_address); void increment_session(const boost::asio::ip::address &_address); @@ -353,6 +355,8 @@ private: std::string sd_multicast_; boost::asio::ip::address current_remote_address_; + + std::atomic<bool> is_diagnosis_; }; } // namespace sd diff --git a/implementation/service_discovery/src/ipv4_option_impl.cpp b/implementation/service_discovery/src/ipv4_option_impl.cpp index b12d60e..00bf7b5 100644 --- a/implementation/service_discovery/src/ipv4_option_impl.cpp +++ b/implementation/service_discovery/src/ipv4_option_impl.cpp @@ -49,7 +49,7 @@ bool ipv4_option_impl::serialize(vsomeip::serializer *_to) const { bool ipv4_option_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful = option_impl::deserialize(_from)
&& length_ == VSOMEIP_SD_IPV4_OPTION_LENGTH;
- uint8_t its_reserved;
+ uint8_t its_reserved(static_cast<std::uint8_t>(layer_four_protocol_e::UNKNOWN));
_from->deserialize(address_.data(), 4);
_from->deserialize(its_reserved);
_from->deserialize(its_reserved);
diff --git a/implementation/service_discovery/src/ipv6_option_impl.cpp b/implementation/service_discovery/src/ipv6_option_impl.cpp index ac9ebed..94c8fe4 100755 --- a/implementation/service_discovery/src/ipv6_option_impl.cpp +++ b/implementation/service_discovery/src/ipv6_option_impl.cpp @@ -49,7 +49,7 @@ bool ipv6_option_impl::serialize(vsomeip::serializer *_to) const { bool ipv6_option_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful = option_impl::deserialize(_from)
&& length_ == VSOMEIP_SD_IPV6_OPTION_LENGTH;;
- uint8_t its_reserved;
+ uint8_t its_reserved(static_cast<std::uint8_t>(layer_four_protocol_e::UNKNOWN));
_from->deserialize(address_.data(), 16);
_from->deserialize(its_reserved);
_from->deserialize(its_reserved);
diff --git a/implementation/service_discovery/src/runtime.cpp b/implementation/service_discovery/src/runtime.cpp deleted file mode 100644 index 54276fd..0000000 --- a/implementation/service_discovery/src/runtime.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2014-2017 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/. - -#include "../include/runtime_impl.hpp" -#include "../../configuration/include/internal.hpp" - -#ifdef _WIN32 -extern "C" -{ - __declspec(dllexport) std::shared_ptr<vsomeip::sd::runtime> VSOMEIP_SD_RUNTIME_SYMBOL; -} -#else -std::shared_ptr<vsomeip::sd::runtime> VSOMEIP_SD_RUNTIME_SYMBOL(vsomeip::sd::runtime::get()); -#endif - -#ifdef _WIN32 -#define CCALL __cdecl -#pragma section(".CRT$XCU",read) -#define INITIALIZER(f) \ - static void __cdecl f(void); \ - __declspec(allocate(".CRT$XCU")) void(__cdecl*f##_)(void) = f; \ - static void __cdecl f(void) - -INITIALIZER(init_vsomeip_sd) { - VSOMEIP_SD_RUNTIME_SYMBOL = vsomeip::sd::runtime::get(); -} -#endif - -namespace vsomeip { -namespace sd { - -std::shared_ptr<runtime> runtime::get() { - return runtime_impl::get(); -} - -} // namespace sd -} // namespace vsomeip - diff --git a/implementation/service_discovery/src/runtime_impl.cpp b/implementation/service_discovery/src/runtime_impl.cpp index b2ed34d..90743b8 100644 --- a/implementation/service_discovery/src/runtime_impl.cpp +++ b/implementation/service_discovery/src/runtime_impl.cpp @@ -12,13 +12,13 @@ #include "../include/runtime_impl.hpp" #include "../include/service_discovery_impl.hpp" +VSOMEIP_PLUGIN(vsomeip::sd::runtime_impl) + namespace vsomeip { namespace sd { -std::shared_ptr<runtime> runtime_impl::get() { - static std::shared_ptr<runtime> the_runtime = - std::make_shared<runtime_impl>(); - return the_runtime; +runtime_impl::runtime_impl() + : plugin_impl("vsomeip SD plug-in", 1, plugin_type_e::SD_RUNTIME_PLUGIN) { } runtime_impl::~runtime_impl() { diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp index 79e60bd..e8937ed 100644 --- a/implementation/service_discovery/src/service_discovery_impl.cpp +++ b/implementation/service_discovery/src/service_discovery_impl.cpp @@ -33,6 +33,7 @@ #include "../../message/include/serializer.hpp" #include "../../routing/include/eventgroupinfo.hpp" #include "../../routing/include/serviceinfo.hpp" +#include "../../plugin/include/plugin_manager.hpp" namespace vsomeip { namespace sd { @@ -62,7 +63,8 @@ service_discovery_impl::service_discovery_impl(service_discovery_host *_host) find_debounce_time_(VSOMEIP_SD_DEFAULT_FIND_DEBOUNCE_TIME), find_debounce_timer_(_host->get_io()), main_phase_timer_(_host->get_io()), - is_suspended_(true) { + is_suspended_(false), + is_diagnosis_(false) { std::chrono::seconds smallest_ttl(DEFAULT_TTL); smallest_ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(smallest_ttl); @@ -82,7 +84,7 @@ boost::asio::io_service & service_discovery_impl::get_io() { } void service_discovery_impl::init() { - runtime_ = runtime::get(); + runtime_ = std::dynamic_pointer_cast<sd::runtime>(plugin_manager::get()->get_plugin(plugin_type_e::SD_RUNTIME_PLUGIN)); std::shared_ptr < configuration > its_configuration = host_->get_configuration(); @@ -151,33 +153,7 @@ void service_discovery_impl::start() { } void service_discovery_impl::stop() { - boost::system::error_code ec; is_suspended_ = true; - { - std::lock_guard<std::mutex> its_lock(main_phase_timer_mutex_); - main_phase_timer_.cancel(ec); - } - { - std::lock_guard<std::mutex> its_lock(offer_debounce_timer_mutex_); - offer_debounce_timer_.cancel(ec); - } - { - std::lock_guard<std::mutex> its_lock(find_debounce_timer_mutex_); - find_debounce_timer_.cancel(ec); - } - { - std::lock_guard<std::mutex> its_lock(repetition_phase_timers_mutex_); - for(const auto &t : repetition_phase_timers_) { - t.first->cancel(ec); - } - } - { - std::lock_guard<std::mutex> its_lock(find_repetition_phase_timers_mutex_); - for(const auto &t : find_repetition_phase_timers_) { - t.first->cancel(ec); - } - } - } void service_discovery_impl::request_service(service_t _service, @@ -849,20 +825,23 @@ void service_discovery_impl::insert_offer_entries( uint32_t its_size(_size); for (const auto its_service : _services) { for (const auto its_instance : its_service.second) { - // Only insert services with configured endpoint(s) - if ((_ignore_phase || its_instance.second->is_in_mainphase()) - && (its_instance.second->get_endpoint(false) - || its_instance.second->get_endpoint(true))) { - if (i >= _start) { - if (!insert_offer_service(_message, its_service.first, - its_instance.first, its_instance.second, its_size)) { - _start = i; - _done = false; - return; + if ((!is_suspended_) + && ((!is_diagnosis_) || (is_diagnosis_ && !host_->get_configuration()->is_someip(its_service.first, its_instance.first)))) { + // Only insert services with configured endpoint(s) + if ((_ignore_phase || its_instance.second->is_in_mainphase()) + && (its_instance.second->get_endpoint(false) + || its_instance.second->get_endpoint(true))) { + if (i >= _start) { + if (!insert_offer_service(_message, its_service.first, + its_instance.first, its_instance.second, its_size)) { + _start = i; + _done = false; + return; + } } } + i++; } - i++; } } _start = i; @@ -1073,7 +1052,6 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, VSOMEIP_INFO << "Reboot detected: IP=" << _sender.to_string(); host_->expire_subscriptions(_sender); host_->expire_services(_sender); - host_->on_reboot(_sender); } std::chrono::milliseconds expired = stop_ttl_timer(); @@ -1226,9 +1204,11 @@ void service_discovery_impl::process_serviceentry( its_request->set_sent_counter(std::uint8_t(repetitions_max_ + 1)); } unsubscribe_all(its_service, its_instance); - host_->del_routing_info(its_service, its_instance, - (its_reliable_port != ILLEGAL_PORT), - (its_unreliable_port != ILLEGAL_PORT)); + if (!is_diagnosis_ && !is_suspended_) { + host_->del_routing_info(its_service, its_instance, + (its_reliable_port != ILLEGAL_PORT), + (its_unreliable_port != ILLEGAL_PORT)); + } } } @@ -1567,7 +1547,8 @@ bool service_discovery_impl::insert_offer_service( if (its_reliable) { insert_option(_message, its_entry, unicast_, its_reliable->get_local_port(), true); - if (0 == _info->get_ttl()) { + if ((0 == _info->get_ttl() && !is_diagnosis_) + && (0 == _info->get_ttl() && !is_suspended_)) { host_->del_routing_info(_service, _instance, true, false); } @@ -1576,7 +1557,8 @@ bool service_discovery_impl::insert_offer_service( if (its_unreliable) { insert_option(_message, its_entry, unicast_, its_unreliable->get_local_port(), false); - if (0 == _info->get_ttl()) { + if ((0 == _info->get_ttl() && !is_diagnosis_) + && (0 == _info->get_ttl() && !is_suspended_)) { host_->del_routing_info(_service, _instance, false, true); } @@ -1833,8 +1815,6 @@ void service_discovery_impl::process_eventgroupentry( } break; case option_type_e::CONFIGURATION: { - if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { - } break; } case option_type_e::UNKNOWN: @@ -1944,7 +1924,7 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service, } else if (_is_second_reliable) { // tcp unicast its_second_target = its_second_subscriber; // check if TCP connection is established by client - if( !is_tcp_connected(_service, _instance, its_second_target) && _ttl > 0) { + if(_ttl > 0 && !is_tcp_connected(_service, _instance, its_second_target)) { insert_subscription_nack(its_message, _service, _instance, _eventgroup, _counter, _major, _reserved); VSOMEIP_ERROR << "TCP connection to target2 : [" << its_second_target->get_address().to_string() @@ -2465,10 +2445,28 @@ void service_discovery_impl::on_offer_debounce_timer_expired( services_t repetition_phase_offers; bool new_offers(false); { + std::vector<services_t::iterator> non_someip_services; std::lock_guard<std::mutex> its_lock(collected_offers_mutex_); if (collected_offers_.size()) { - repetition_phase_offers = collected_offers_; - collected_offers_.clear(); + if (is_diagnosis_) { + for (services_t::iterator its_service = collected_offers_.begin(); + its_service != collected_offers_.end(); its_service++) { + for (auto its_instance : its_service->second) { + if (!host_->get_configuration()->is_someip( + its_service->first, its_instance.first)) { + non_someip_services.push_back(its_service); + } + } + } + for (auto its_service : non_someip_services) { + repetition_phase_offers.insert(*its_service); + collected_offers_.erase(its_service); + } + } else { + repetition_phase_offers = collected_offers_; + collected_offers_.clear(); + } + new_offers = true; } } @@ -2877,5 +2875,9 @@ bool service_discovery_impl::check_source_address( return is_valid; } +void service_discovery_impl::set_diagnosis_mode(const bool _activate) { + is_diagnosis_ = _activate; +} + } // namespace sd } // namespace vsomeip diff --git a/implementation/tracing/include/trace_header.hpp b/implementation/tracing/include/trace_header.hpp index 95e0d83..11ccbdd 100644 --- a/implementation/tracing/include/trace_header.hpp +++ b/implementation/tracing/include/trace_header.hpp @@ -12,7 +12,7 @@ #include <boost/asio/ip/address_v4.hpp> -#define VSOMEIP_TRACE_HEADER_SIZE 8 +#define VSOMEIP_TRACE_HEADER_SIZE 10 namespace vsomeip { @@ -28,10 +28,13 @@ enum class protocol_e : uint8_t { }; struct trace_header { - bool prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending); - bool prepare(const endpoint* _endpoint, bool _is_sending); + bool prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending, + instance_t _instance); + bool prepare(const endpoint* _endpoint, bool _is_sending, + instance_t _instance); void prepare(const boost::asio::ip::address_v4 &_address, - std::uint16_t _port, protocol_e _protocol, bool _is_sending); + std::uint16_t _port, protocol_e _protocol, bool _is_sending, + instance_t _instance); byte_t data_[VSOMEIP_TRACE_HEADER_SIZE]; }; diff --git a/implementation/tracing/src/trace_connector.cpp b/implementation/tracing/src/trace_connector.cpp index 08bbfd1..8734748 100644 --- a/implementation/tracing/src/trace_connector.cpp +++ b/implementation/tracing/src/trace_connector.cpp @@ -244,8 +244,8 @@ void trace_connector::trace(const byte_t *_header, uint16_t _header_size, DltContext *dlt_context = it->second; DLT_TRACE_NETWORK_SEGMENTED(*dlt_context, DLT_NW_TRACE_IPC, - _header_size, (void * )_header, - _data_size, (void * )_data); + _header_size, static_cast<void *>(const_cast<byte_t *>(_header)), + _data_size, static_cast<void *>(const_cast<byte_t *>(_data))); } } } diff --git a/implementation/tracing/src/trace_header.cpp b/implementation/tracing/src/trace_header.cpp index c92ce06..d78e600 100644 --- a/implementation/tracing/src/trace_header.cpp +++ b/implementation/tracing/src/trace_header.cpp @@ -13,11 +13,13 @@ namespace vsomeip { namespace tc { -bool trace_header::prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending) { - return prepare(_endpoint.get(), _is_sending); +bool trace_header::prepare(const std::shared_ptr<endpoint> &_endpoint, + bool _is_sending, instance_t _instance) { + return prepare(_endpoint.get(), _is_sending, _instance); } -bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending) { +bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending, + instance_t _instance) { if (_endpoint) { const client_endpoint* its_client_endpoint = dynamic_cast<const client_endpoint*>(_endpoint); @@ -40,7 +42,8 @@ bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending) { its_protocol = protocol_e::udp; } } - prepare(its_address.to_v4(), its_port, its_protocol, _is_sending); + prepare(its_address.to_v4(), its_port, its_protocol, _is_sending, + _instance); return true; } } @@ -50,7 +53,7 @@ bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending) { void trace_header::prepare(const boost::asio::ip::address_v4 &_address, std::uint16_t _port, protocol_e _protocol, - bool _is_sending) { + bool _is_sending, instance_t _instance) { unsigned long its_address_as_long = _address.to_ulong(); data_[0] = VSOMEIP_LONG_BYTE0(its_address_as_long); data_[1] = VSOMEIP_LONG_BYTE1(its_address_as_long); @@ -60,6 +63,8 @@ void trace_header::prepare(const boost::asio::ip::address_v4 &_address, data_[5] = VSOMEIP_WORD_BYTE1(_port); data_[6] = static_cast<byte_t>(_protocol); data_[7] = static_cast<byte_t>(_is_sending); + data_[8] = VSOMEIP_WORD_BYTE0(_instance); + data_[9] = VSOMEIP_WORD_BYTE1(_instance); } } // namespace tc diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp index e48be1a..9245f90 100644 --- a/implementation/utility/include/utility.hpp +++ b/implementation/utility/include/utility.hpp @@ -20,9 +20,6 @@ class configuration; class utility { public: - static void * load_library(const std::string &_path, - const std::string &_symbol); - static inline bool is_request(std::shared_ptr<message> _message) { return (_message ? is_request(_message->get_message_type()) : false); } @@ -76,16 +73,21 @@ public: static bool VSOMEIP_IMPORT_EXPORT is_file(const std::string &_path); static bool VSOMEIP_IMPORT_EXPORT is_folder(const std::string &_path); + static const std::string get_base_path(const std::shared_ptr<configuration> &_config); + static const std::string get_shm_name(const std::shared_ptr<configuration> &_config); + static CriticalSection its_local_configuration_mutex__; static struct configuration_data_t *the_configuration_data__; static bool auto_configuration_init(const std::shared_ptr<configuration> &_config); - static void auto_configuration_exit(client_t _client); + static void auto_configuration_exit(client_t _client, + const std::shared_ptr<configuration> &_config); static bool is_routing_manager_host(client_t _client); static void set_routing_manager_host(client_t _client); - static bool is_used_client_id(client_t _client); + static bool is_used_client_id(client_t _client, + const std::shared_ptr<configuration> &_config); static client_t request_client_id(const std::shared_ptr<configuration> &_config, const std::string &_name, client_t _client); static void release_client_id(client_t _client); diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp index f4f4449..81d8aba 100644 --- a/implementation/utility/src/utility.cpp +++ b/implementation/utility/src/utility.cpp @@ -15,10 +15,6 @@ #include <sys/stat.h> -#ifndef _WIN32 - #include <fcntl.h> -#endif - #include <vsomeip/constants.hpp> #include <vsomeip/defines.hpp> @@ -54,46 +50,6 @@ uint32_t utility::get_payload_size(const byte_t *_data, uint32_t _size) { return (its_size); } -void * utility::load_library(const std::string &_path, - const std::string &_symbol) { - void * its_symbol = 0; - -#ifdef _WIN32 - std::string path = _path.substr(0, _path.length() - 5).substr(3) + ".dll"; - - HINSTANCE hDLL = LoadLibrary(path.c_str()); - if (hDLL != NULL) { - //loadedLibraries_.insert(itsLibrary); - std::cout << "Loading interface library \"" << path << "\" succeeded." << std::endl; - - typedef UINT(CALLBACK* LPFNDLLFUNC1)(DWORD, UINT); - - LPFNDLLFUNC1 lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, _symbol.c_str()); - if (!lpfnDllFunc1) - { - FreeLibrary(hDLL); - std::cerr << "Loading symbol \"" << _symbol << "\" failed (" << GetLastError() << ")" << std::endl; - } - else - { - its_symbol = lpfnDllFunc1; - } - - } - else { - std::cerr << "Loading interface library \"" << path << "\" failed (" << GetLastError() << ")" << std::endl; - } -#else - void *handle = dlopen(_path.c_str(), RTLD_LAZY | RTLD_GLOBAL); - if (0 != handle) { - its_symbol = dlsym(handle, _symbol.c_str()); - } else { - VSOMEIP_ERROR << "Loading failed: (" << dlerror() << ")"; - } -#endif - return (its_symbol); -} - bool utility::exists(const std::string &_path) { struct stat its_stat; return (stat(_path.c_str(), &its_stat) == 0); @@ -117,6 +73,16 @@ bool utility::is_folder(const std::string &_path) { return false; } +const std::string utility::get_base_path( + const std::shared_ptr<configuration> &_config) { + return std::string(VSOMEIP_BASE_PATH + _config->get_network() + "-"); +} + +const std::string utility::get_shm_name( + const std::shared_ptr<configuration> &_config) { + return std::string("/" + _config->get_network()); +} + // pointer to shared memory configuration_data_t *utility::the_configuration_data__(nullptr); // critical section to protect shared memory pointers, handles and ref count in this process @@ -161,7 +127,7 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) sizeof(configuration_data_t), // maximum object size (low-order DWORD) - VSOMEIP_SHM_NAME); // name of mapping object + utility::get_shm_name(_config).c_str());// name of mapping object if (its_descriptor && GetLastError() == ERROR_ALREADY_EXISTS) { @@ -200,7 +166,7 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) sizeof(configuration_data_t), // maximum object size (low-order DWORD) - VSOMEIP_SHM_NAME); // name of mapping object + utility::get_shm_name(_config).c_str());// name of mapping object if (its_descriptor) { void *its_segment = (LPTSTR)MapViewOfFile(its_descriptor, // handle to map object @@ -254,7 +220,7 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con } #else const mode_t previous_mask(::umask(static_cast<mode_t>(_config->get_umask()))); - int its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR | O_CREAT | O_EXCL, + int its_descriptor = shm_open(utility::get_shm_name(_config).c_str(), O_RDWR | O_CREAT | O_EXCL, static_cast<mode_t>(_config->get_permissions_shm())); ::umask(previous_mask); if (its_descriptor > -1) { @@ -326,7 +292,7 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con } } else if (errno == EEXIST) { const mode_t previous_mask(::umask(static_cast<mode_t>(_config->get_umask()))); - its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR, + its_descriptor = shm_open(utility::get_shm_name(_config).c_str(), O_RDWR, static_cast<mode_t>(_config->get_permissions_shm())); ::umask(previous_mask); if (-1 == its_descriptor) { @@ -383,7 +349,8 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con return (the_configuration_data__ != nullptr); } -void utility::auto_configuration_exit(client_t _client) { +void utility::auto_configuration_exit(client_t _client, + const std::shared_ptr<configuration> &_config) { std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__); if (the_configuration_data__) { #ifdef _WIN32 @@ -426,7 +393,7 @@ void utility::auto_configuration_exit(client_t _client) { "munmap succeeded."; the_configuration_data__ = nullptr; if (unlink_shm) { - shm_unlink(VSOMEIP_SHM_NAME); + shm_unlink(utility::get_shm_name(_config).c_str()); } } @@ -435,7 +402,8 @@ void utility::auto_configuration_exit(client_t _client) { } } -bool utility::is_used_client_id(client_t _client) { +bool utility::is_used_client_id(client_t _client, + const std::shared_ptr<configuration> &_config) { for (int i = 0; i < the_configuration_data__->max_used_client_ids_index_; i++) { @@ -445,7 +413,7 @@ bool utility::is_used_client_id(client_t _client) { } #ifndef _WIN32 std::stringstream its_client; - its_client << VSOMEIP_BASE_PATH << std::hex << _client; + its_client << utility::get_base_path(_config) << std::hex << _client; if (exists(its_client.str())) { if (-1 == ::unlink(its_client.str().c_str())) { VSOMEIP_WARNING << "unlink failed for " << its_client.str() << ". Client identifier 0x" @@ -477,7 +445,7 @@ std::set<client_t> utility::get_used_client_ids() { } } #endif - for (int i = 0; + for (int i = 1; i < the_configuration_data__->max_used_client_ids_index_; i++) { clients.insert(the_configuration_data__->used_client_ids_[i]); @@ -499,6 +467,7 @@ client_t utility::request_client_id(const std::shared_ptr<configuration> &_confi std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__); if (the_configuration_data__ != nullptr) { + const std::string its_name = _config->get_routing_host(); #ifdef _WIN32 DWORD waitResult = WaitForSingleObject(configuration_data_mutex, INFINITE); assert(waitResult == WAIT_OBJECT_0); @@ -513,17 +482,18 @@ client_t utility::request_client_id(const std::shared_ptr<configuration> &_confi } pid_t pid = getpid(); - if (the_configuration_data__->pid_ != 0) { - if (pid != the_configuration_data__->pid_) { - if (kill(the_configuration_data__->pid_, 0) == -1) { - VSOMEIP_WARNING << "Routing Manager seems to be inactive. Taking over..."; - the_configuration_data__->routing_manager_host_ = 0x0000; + if (its_name == "" || _name == its_name) { + if (the_configuration_data__->pid_ != 0) { + if (pid != the_configuration_data__->pid_) { + if (kill(the_configuration_data__->pid_, 0) == -1) { + VSOMEIP_WARNING << "Routing Manager seems to be inactive. Taking over..."; + the_configuration_data__->routing_manager_host_ = 0x0000; + } } } } #endif - const std::string its_name = _config->get_routing_host(); bool set_client_as_manager_host(false); if (its_name != "" && its_name == _name) { if (the_configuration_data__->routing_manager_host_ == 0x0000) { @@ -566,17 +536,17 @@ client_t utility::request_client_id(const std::shared_ptr<configuration> &_confi if (its_preconfigured_client_id == _client) { // preconfigured client id for application name present in json // and requested - if (!is_used_client_id(_client)) { + if (!is_used_client_id(_client, _config)) { use_autoconfig = false; } } else { // preconfigured client id for application name present in // json, but different client id requested - if (!is_used_client_id(its_preconfigured_client_id)) { + if (!is_used_client_id(its_preconfigured_client_id, _config)) { // assign preconfigured client id if not already used _client = its_preconfigured_client_id; use_autoconfig = false; - } else if (!is_used_client_id(_client)) { + } else if (!is_used_client_id(_client, _config)) { // if preconfigured client id is already used and // requested is unused assign requested use_autoconfig = false; @@ -586,11 +556,11 @@ client_t utility::request_client_id(const std::shared_ptr<configuration> &_confi } if (use_autoconfig) { - if (_client == ILLEGAL_CLIENT || is_used_client_id(_client)) { + if (_client == ILLEGAL_CLIENT || is_used_client_id(_client, _config)) { _client = the_configuration_data__->client_base_; } int increase_count = 0; - while (is_used_client_id(_client) + while (is_used_client_id(_client, _config) || !is_bigger_last_assigned_client_id(_client) || _config->is_configured_client_id(_client)) { if ((_client & 0xFF) + 1 > VSOMEIP_MAX_CLIENTS) { diff --git a/interface/vsomeip/application.hpp b/interface/vsomeip/application.hpp index 0b71329..f8591df 100644 --- a/interface/vsomeip/application.hpp +++ b/interface/vsomeip/application.hpp @@ -312,7 +312,7 @@ public: */ virtual void subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major = DEFAULT_MAJOR, - subscription_type_e _subscription_type = subscription_type_e::SU_RELIABLE_AND_UNRELIABLE, + subscription_type_e _subscription_type = subscription_type_e::SU_PREFER_RELIABLE, event_t _event = ANY_EVENT) = 0; /** @@ -839,6 +839,28 @@ public: */ virtual void unsubscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) = 0; + + + /** + * + * \brief Registers a subscription status listener. + * + * When registered such a handler it will be called for + * every application::subscribe call. + * + * This method is intended to replace the application:: + * register_subscription_error_handler call in future releases. + * + * \param _service Service identifier of the service that is subscribed to. + * \param _instance Instance identifier of the service that is subscribed to. + * \param _eventgroup Eventgroup identifier of the eventgroup is subscribed to. + * \param _event Event indentifier of the event is subscribed to. + * \param _handler A subscription status handler which will be called by vSomeIP + * as a follow of application::subscribe. + */ + virtual void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler) = 0; }; /** @} */ diff --git a/interface/vsomeip/enumeration_types.hpp b/interface/vsomeip/enumeration_types.hpp index d906f1a..74358c6 100644 --- a/interface/vsomeip/enumeration_types.hpp +++ b/interface/vsomeip/enumeration_types.hpp @@ -59,6 +59,7 @@ enum class routing_state_e : uint8_t { RS_SUSPENDED = 0x01, RS_RESUMED = 0x02, RS_SHUTDOWN = 0x03, + RS_DIAGNOSIS = 0x04, RS_UNKNOWN = 0xFF }; diff --git a/interface/vsomeip/handler.hpp b/interface/vsomeip/handler.hpp index f2c0628..507ac3c 100644 --- a/interface/vsomeip/handler.hpp +++ b/interface/vsomeip/handler.hpp @@ -20,6 +20,8 @@ typedef std::function< void (const std::shared_ptr< message > &) > message_handl typedef std::function< void (service_t, instance_t, bool) > availability_handler_t; typedef std::function< bool (client_t, bool) > subscription_handler_t; typedef std::function< void (const uint16_t) > error_handler_t; +typedef std::function< void (const service_t, const instance_t, const eventgroup_t, + const event_t, const uint16_t) > subscription_status_handler_t; } // namespace vsomeip diff --git a/interface/vsomeip/message_base.hpp b/interface/vsomeip/message_base.hpp index 1518b9e..60c80e6 100644 --- a/interface/vsomeip/message_base.hpp +++ b/interface/vsomeip/message_base.hpp @@ -192,6 +192,17 @@ public: * \brief Set whether or not the message is an initial event.
*/
VSOMEIP_EXPORT virtual void set_initial(bool _is_initial) = 0;
+
+ /**
+ * \brief Return whether or not the CRC value received is valid.
+ */
+ VSOMEIP_EXPORT virtual bool is_valid_crc() const = 0;
+
+ /**
+ * \brief Set whether or not the CRC value received is valid.
+ */
+ VSOMEIP_EXPORT virtual void set_is_valid_crc(bool _is_valid_crc) = 0;
+
};
/** @} */
diff --git a/interface/vsomeip/plugin.hpp b/interface/vsomeip/plugin.hpp new file mode 100644 index 0000000..4d608f1 --- /dev/null +++ b/interface/vsomeip/plugin.hpp @@ -0,0 +1,89 @@ +// Copyright (C) 2016-2017 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/. + +#ifndef VSOMEIP_PLUGIN_HPP +#define VSOMEIP_PLUGIN_HPP + +#include <memory> + +#if WIN32 + #if VSOMEIP_DLL_COMPILATION_PLUGIN + #define VSOMEIP_IMPORT_EXPORT_PLUGIN __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT_PLUGIN __declspec(dllimport) + #endif +#else + #define VSOMEIP_IMPORT_EXPORT_PLUGIN +#endif + +#define VSOMEIP_PLUGIN_INIT_SYMBOL "vsomeip_plugin_init" + +namespace vsomeip { + +enum class plugin_type_e : uint8_t { + APPLICATION_PLUGIN, + PRE_CONFIGURATION_PLUGIN, + CONFIGURATION_PLUGIN, + SD_RUNTIME_PLUGIN +}; + +class plugin; +typedef std::shared_ptr<plugin> (*create_plugin_func)(); +typedef create_plugin_func (*plugin_init_func)(); + +/** + * Base class for all plug-ins + */ +class VSOMEIP_IMPORT_EXPORT_PLUGIN plugin { +public: + virtual ~plugin() {} + + virtual uint32_t get_plugin_version() const = 0; + virtual const std::string &get_plugin_name() const = 0; + virtual plugin_type_e get_plugin_type() const = 0; +}; + +template<class Plugin_> +class plugin_impl : public plugin { +public: + static std::shared_ptr<plugin> get_plugin() { + return std::make_shared<Plugin_>(); + } + + plugin_impl(const std::string &_name, uint32_t _version, + plugin_type_e _type) { + name_ = _name; + version_ = _version; + type_ = _type; + } + + const std::string &get_plugin_name() const { + return name_; + } + + uint32_t get_plugin_version() const { + return version_; + } + + plugin_type_e get_plugin_type() const { + return type_; + } + +private: + uint32_t version_; + std::string name_; + plugin_type_e type_; +}; + +#define VSOMEIP_PLUGIN(class_name) \ + extern "C" { \ + VSOMEIP_EXPORT vsomeip::create_plugin_func vsomeip_plugin_init() { \ + return class_name::get_plugin; \ + } \ + } + +} // namespace vsomeip + +#endif // VSOMEIP_PLUGIN_HPP diff --git a/interface/vsomeip/plugins/application_plugin.hpp b/interface/vsomeip/plugins/application_plugin.hpp new file mode 100644 index 0000000..3d5cce1 --- /dev/null +++ b/interface/vsomeip/plugins/application_plugin.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2016-2017 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/. + +#ifndef VSOMEIP_APPLICATION_PLUGIN_HPP +#define VSOMEIP_APPLICATION_PLUGIN_HPP + +#include <string> +#include <memory> + +#include <vsomeip/export.hpp> + +// Version should be incremented on breaking API change +#define VSOMEIP_APPLICATION_PLUGIN_VERSION 1 + +namespace vsomeip { + +enum class application_plugin_state_e : uint8_t { + STATE_INITIALIZED, + STATE_STARTED, + STATE_STOPPED +}; + +/** + * The application plug-in can be used to extend application behavior + * via an module/plug-in. + */ +class application_plugin { +public: + virtual ~application_plugin() {} + + // Called by vSomeIP to inform an application plug-in about its actual state + // Call should not be blocked from plug-in as there is no threading. + // The caller thread of "application::init/::start/::stop" will inform the plug-in. + virtual void on_application_state_change(const std::string _application_name, + const application_plugin_state_e _app_state) = 0; +}; + +} + +#endif // VSOMEIP_APPLICATION_PLUGIN_HPP diff --git a/interface/vsomeip/plugins/pre_configuration_plugin.hpp b/interface/vsomeip/plugins/pre_configuration_plugin.hpp new file mode 100644 index 0000000..6155796 --- /dev/null +++ b/interface/vsomeip/plugins/pre_configuration_plugin.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2017 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/. + +#ifndef VSOMEIP_PRE_CONFIGURATION_PLUGIN_HPP +#define VSOMEIP_PRE_CONFIGURATION_PLUGIN_HPP + +#include <vsomeip/export.hpp> + +// Version should be incremented on breaking API change +#define VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION 1 + +namespace vsomeip { +/** + * The pre configuration plug-in can be used to extend configuration load behavior + * via an module/plug-in. + */ +class pre_configuration_plugin { +public: + virtual ~pre_configuration_plugin() {} + + // Plug-In should return a valid path to a vSomeIP configuration. + // vSomeIP will use this path for config loading if such a plug-in is availablel. + virtual std::string get_configuration_path() = 0; +}; +} + +#endif // VSOMEIP_PRE_CONFIGURATION_PLUGIN_HPP diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt new file mode 100644 index 0000000..2ecebc1 --- /dev/null +++ b/plugins/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (C) 2016-2017 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/. + +cmake_minimum_required (VERSION 2.8) + +add_subdirectory ( mgu )
\ No newline at end of file diff --git a/plugins/mgu/CMakeLists.txt b/plugins/mgu/CMakeLists.txt new file mode 100644 index 0000000..16a2873 --- /dev/null +++ b/plugins/mgu/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2016-2017 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/. + +cmake_minimum_required (VERSION 2.8) + +set (VSOMEIP_DIAGNOSIS_PLUGIN_MAJOR_VERSION 1) +set (VSOMEIP_DIAGNOSIS_PLUGIN_MINOR_VERSION 0) +set (VSOMEIP_DIAGNOSIS_PLUGIN_PATCH_VERSION 0) + +if(DEFINED VSOMEIP_VERSION) + set (VSOMEIP_DIAGNOSIS_PLUGIN_VERSION ${VSOMEIP_VERSION}-${VSOMEIP_DIAGNOSIS_PLUGIN_MAJOR_VERSION}.${VSOMEIP_DIAGNOSIS_PLUGIN_MINOR_VERSION}.${VSOMEIP_DIAGNOSIS_PLUGIN_PATCH_VERSION}) +else() + find_package (vsomeip 2.7.0 REQUIRED) + set (VSOMEIP_DIAGNOSIS_PLUGIN_VERSION ${vsomeip_VERSION}-${VSOMEIP_DIAGNOSIS_PLUGIN_MAJOR_VERSION}.${VSOMEIP_DIAGNOSIS_PLUGIN_MINOR_VERSION}.${VSOMEIP_DIAGNOSIS_PLUGIN_PATCH_VERSION}) +endif() +message(STATUS "vsomeip-diagnosis-plugin-mgu: " ${VSOMEIP_DIAGNOSIS_PLUGIN_VERSION}) + +# Offer the user the choice of overriding the installation directories +set (INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") +set (INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set (INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + +include_directories ( + include + ${VSOMEIP_INCLUDE_DIRS} +) + +# OS +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(OS "LINUX") + set(DL_LIBRARY "dl") + set(NO_DEPRECATED "") + set(OPTIMIZE "") + set(OS_CXX_FLAGS "-D_GLIBCXX_USE_NANOSLEEP -pthread -O -Wall -Wextra -Wformat -Wformat-security -Wconversion -fexceptions -fstrict-aliasing -fstack-protector -fasynchronous-unwind-tables -fno-omit-frame-pointer -D_FORTIFY_SOURCE=2") +endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${OS} ${OS_CXX_FLAGS} -g ${OPTIMIZE} -std=c++0x ${NO_DEPRECATED}") +set(USE_RT "rt") + +# MGU diagnosis job plugin library +file(GLOB vsomeip-diagnosis-plugin-mgu_SRC + "src/diagnosis_plugin_mgu.cpp" +) +list(SORT vsomeip-diagnosis-plugin-mgu_SRC) + +add_library(vsomeip-diagnosis-plugin-mgu SHARED ${vsomeip-diagnosis-plugin-mgu_SRC}) +set_target_properties (vsomeip-diagnosis-plugin-mgu PROPERTIES VERSION ${VSOMEIP_DIAGNOSIS_PLUGIN_VERSION} SOVERSION ${VSOMEIP_DIAGNOSIS_PLUGIN_MAJOR_VERSION}) +target_link_libraries(vsomeip-diagnosis-plugin-mgu vsomeip) + +install ( + TARGETS vsomeip-diagnosis-plugin-mgu + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin +) + +###################################################################################################
\ No newline at end of file diff --git a/plugins/mgu/include/diagnosis_plugin_mgu.hpp b/plugins/mgu/include/diagnosis_plugin_mgu.hpp new file mode 100644 index 0000000..2520636 --- /dev/null +++ b/plugins/mgu/include/diagnosis_plugin_mgu.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2016-2017 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/. + +#ifndef VSOMEIP_DIAGNOSIS_PLUGIN_MGU_HPP +#define VSOMEIP_DIAGNOSIS_PLUGIN_MGU_HPP + +#include <mutex> + +#include <vsomeip/application.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/plugins/application_plugin.hpp> + +namespace vsomeip { +namespace mgu { + +class diagnosis_plugin_mgu + : public application_plugin, + public plugin_impl<diagnosis_plugin_mgu>, + public std::enable_shared_from_this<diagnosis_plugin_mgu> { +public: + diagnosis_plugin_mgu(); + VSOMEIP_EXPORT void on_application_state_change( + const std::string _application_name, + const application_plugin_state_e _app_state); +private: + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_state(vsomeip::state_type_e _state); + + std::string application_name_; + std::mutex application_name_mutex_; + + static const uint32_t error_ok_; + static const uint32_t error_out_of_range_; + static const uint32_t error_communication_error_; + static const uint8_t communication_type_mask_; + static const uint8_t expected_payload_length_; + static const uint8_t communication_type_payload_offset_; + static const vsomeip::service_t diag_job_service_id_; + static const vsomeip::instance_t diag_job_instance_id_; + static const vsomeip::major_version_t diag_job_major_; + static const vsomeip::minor_version_t diag_job_minor_; + static const vsomeip::method_t diag_job_rx_on_tx_on_; + static const vsomeip::method_t diag_job_rx_on_tx_off_; +}; + +} // namespace mgu +} // namespace vsomeip + +#endif // VSOMEIP_DIAGNOSIS_PLUGIN_MGU_HPP diff --git a/plugins/mgu/src/diagnosis_plugin_mgu.cpp b/plugins/mgu/src/diagnosis_plugin_mgu.cpp new file mode 100644 index 0000000..aa8c57d --- /dev/null +++ b/plugins/mgu/src/diagnosis_plugin_mgu.cpp @@ -0,0 +1,144 @@ +// Copyright (C) 2016-2017 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/. + +#include <vsomeip/plugin.hpp> +#include <byteswap.h> + +#include "../include/diagnosis_plugin_mgu.hpp" + +VSOMEIP_PLUGIN(vsomeip::mgu::diagnosis_plugin_mgu) + +namespace vsomeip { +namespace mgu { + +const uint32_t diagnosis_plugin_mgu::error_ok_ = 256; +const uint32_t diagnosis_plugin_mgu::error_out_of_range_ = 257; +const uint32_t diagnosis_plugin_mgu::error_communication_error_ = 576; +const uint8_t diagnosis_plugin_mgu::communication_type_mask_ = 2; +const uint8_t diagnosis_plugin_mgu::expected_payload_length_ = sizeof(uint32_t) + sizeof(uint8_t); +const uint8_t diagnosis_plugin_mgu::communication_type_payload_offset_ = sizeof(uint32_t); +const vsomeip::service_t diagnosis_plugin_mgu::diag_job_service_id_ = 0xFE9F; +const vsomeip::instance_t diagnosis_plugin_mgu::diag_job_instance_id_ = 0x80; +const vsomeip::major_version_t diagnosis_plugin_mgu::diag_job_major_ = 0x0; +const vsomeip::minor_version_t diagnosis_plugin_mgu::diag_job_minor_ = 0x1; +const vsomeip::method_t diagnosis_plugin_mgu::diag_job_rx_on_tx_on_ = 0x1; +const vsomeip::method_t diagnosis_plugin_mgu::diag_job_rx_on_tx_off_ = 0x2; + +diagnosis_plugin_mgu::diagnosis_plugin_mgu() + : plugin_impl("diagnosis job plug-in mgu", + VSOMEIP_APPLICATION_PLUGIN_VERSION, + vsomeip::plugin_type_e::APPLICATION_PLUGIN) { +} + +void diagnosis_plugin_mgu::on_application_state_change(const std::string _application_name, + const vsomeip::application_plugin_state_e _app_state) { + + std::shared_ptr<vsomeip::application> application = nullptr; + { + std::lock_guard<std::mutex> lock(application_name_mutex_); + application_name_ = _application_name; + application = runtime::get()->get_application(application_name_); + } + if (application) { + switch (_app_state) { + case vsomeip::application_plugin_state_e::STATE_INITIALIZED: + if (application->is_routing()) { + application->register_state_handler( + std::bind(&diagnosis_plugin_mgu::on_state, + this, std::placeholders::_1)); + application->register_message_handler(diag_job_service_id_, + diag_job_instance_id_, vsomeip::ANY_METHOD, + std::bind(&diagnosis_plugin_mgu::on_message, + this, std::placeholders::_1)); + } + break; + + case vsomeip::application_plugin_state_e::STATE_STARTED: + break; + case vsomeip::application_plugin_state_e::STATE_STOPPED: + if (application->is_routing()) { + application->stop_offer_service( + diag_job_service_id_, diag_job_instance_id_, diag_job_major_, diag_job_minor_); + application->unregister_message_handler( + diag_job_service_id_, diag_job_instance_id_, vsomeip::ANY_METHOD); + application->unregister_state_handler(); + } + break; + } + } +} + +void diagnosis_plugin_mgu::on_message(const std::shared_ptr<vsomeip::message> &_request) { + std::shared_ptr<vsomeip::application> application = nullptr; + { + std::lock_guard<std::mutex> lock(application_name_mutex_); + application = runtime::get()->get_application(application_name_); + } + if (application && application->is_routing()) { + vsomeip::routing_state_e state = vsomeip::routing_state_e::RS_UNKNOWN; + switch (_request->get_method()) { + case diag_job_rx_on_tx_on_: + state = vsomeip::routing_state_e::RS_RUNNING; + break; + case diag_job_rx_on_tx_off_: + state = vsomeip::routing_state_e::RS_DIAGNOSIS; + break; + default: + break; + } + // Only reply if one of the 2 well known message are called! + if (state != vsomeip::routing_state_e::RS_UNKNOWN) { + uint32_t error; + auto payload = _request->get_payload(); + // Check for correct data length + if (payload->get_length() == expected_payload_length_) { + // Check if bit 1 is set + if (payload->get_data()[communication_type_payload_offset_] + & communication_type_mask_) { + application->set_routing_state(state); + error = bswap_32(error_ok_); + } else { + error = bswap_32(error_out_of_range_); + } + } else { + error = bswap_32(error_communication_error_); + } + + auto its_payload = vsomeip::runtime::get()->create_payload(); + std::vector<byte_t> its_payload_data; + // Set error return type + for (uint8_t i = 0; i < sizeof(error); ++i) { + its_payload_data.push_back(reinterpret_cast<const byte_t*>(&error)[i]); + } + + // Copy handle from request-payload! + for (uint8_t i = 0; i < sizeof(uint32_t); ++i) { + its_payload_data.push_back(payload->get_data()[i]); + } + + // Create & send response + its_payload->set_data(its_payload_data); + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + its_response->set_payload(its_payload); + application->send(its_response, true); + } + } +} + +void diagnosis_plugin_mgu::on_state(vsomeip::state_type_e _state) { + std::shared_ptr<vsomeip::application> application = nullptr; + { + std::lock_guard<std::mutex> lock(application_name_mutex_); + application = runtime::get()->get_application(application_name_); + } + if (application && _state == vsomeip::state_type_e::ST_REGISTERED) { + application->offer_service(diag_job_service_id_, diag_job_instance_id_, + diag_job_major_, diag_job_minor_); + } +} + +} // namespace mgu +} // namespace vsomeip diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fde4c84..8e88a05 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -76,6 +76,7 @@ if(NOT ${TESTS_BAT}) vsomeip-cfg ${Boost_LIBRARIES} ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} ) # The following will make sure that ${TEST_CONFIGURATION_CONFIG_FILE} is copied @@ -1299,6 +1300,78 @@ if(NOT ${TESTS_BAT}) ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_SLAVE_STARTER} ${TEST_SUBSCRIBE_NOTIFY_SERVICE} ) + + # subscribe_notify_test_one_event_two_eventgroups + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME subscribe_notify_test_one_event_two_eventgroups) + + # service + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_service) + add_executable(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE} + subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE}.cpp) + target_link_libraries(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE} + vsomeip + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ) + # client + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_client) + add_executable(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT} + subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT}.cpp) + target_link_libraries(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT} + vsomeip + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ) + + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_master.json) + configure_file( + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE}.in + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE} + @ONLY) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE} + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE} + ) + + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_UDP_CONFIG_FILE + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_udp_slave.json) + configure_file( + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_UDP_CONFIG_FILE}.in + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_UDP_CONFIG_FILE} + @ONLY) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_UDP_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_UDP_CONFIG_FILE} + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT} + ) + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_TCP_CONFIG_FILE + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_tcp_slave.json) + configure_file( + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_TCP_CONFIG_FILE}.in + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_TCP_CONFIG_FILE} + @ONLY) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_TCP_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_TCP_CONFIG_FILE} + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT} + ) + + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_STARTER + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_master_starter.sh) + copy_to_builddir(${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_STARTER} + ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_STARTER} + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE} + ) + set(TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_STARTER + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_slave_starter.sh) + copy_to_builddir(${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_STARTER} + ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SLAVE_STARTER} + ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE} + ) endif() ############################################################################## @@ -1760,6 +1833,8 @@ if(NOT ${TESTS_BAT}) add_dependencies(${TEST_CLIENT_ID_SERVICE} gtest) add_dependencies(${TEST_CLIENT_ID_UTILITY} gtest) add_dependencies(${TEST_SUBSCRIBE_NOTIFY_SERVICE} gtest) + add_dependencies(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE} gtest) + add_dependencies(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT} gtest) add_dependencies(${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE} gtest) add_dependencies(${TEST_CPU_LOAD_SERVICE} gtest) add_dependencies(${TEST_CPU_LOAD_CLIENT} gtest) @@ -1800,6 +1875,8 @@ if(NOT ${TESTS_BAT}) add_dependencies(build_tests ${TEST_CLIENT_ID_SERVICE}) add_dependencies(build_tests ${TEST_CLIENT_ID_UTILITY}) add_dependencies(build_tests ${TEST_SUBSCRIBE_NOTIFY_SERVICE}) + add_dependencies(build_tests ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_SERVICE}) + add_dependencies(build_tests ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_CLIENT}) add_dependencies(build_tests ${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE}) add_dependencies(build_tests ${TEST_CPU_LOAD_SERVICE}) add_dependencies(build_tests ${TEST_CPU_LOAD_CLIENT}) @@ -1826,10 +1903,7 @@ endif() if(NOT ${TESTS_BAT}) add_test(NAME ${TEST_CONFIGURATION} - COMMAND ${TEST_CONFIGURATION} --someip ${TEST_CONFIGURATION_CONFIG_FILE} - ) - add_test(NAME ${TEST_CONFIGURATION}_deprecated_config_file - COMMAND ${TEST_CONFIGURATION} --someip ${TEST_CONFIGURATION_DEPRECATED_CONFIG_FILE} + COMMAND ${TEST_CONFIGURATION} ) # application test @@ -1998,6 +2072,14 @@ if(NOT ${TESTS_BAT}) COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE}) set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_same_service_id_udp PROPERTIES TIMEOUT 120) + add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_udp + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE}) + set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_udp PROPERTIES TIMEOUT 120) + + add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_tcp + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_STARTER} TCP ${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_MASTER_CONFIG_FILE}) + set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_ONE_EVENT_TWO_EVENTGROUPS_NAME}_tcp PROPERTIES TIMEOUT 120) + # subscribe notify one id tests add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_udp COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}) diff --git a/test/client_id_tests/client_id_test_utility.cpp b/test/client_id_tests/client_id_test_utility.cpp index 02b3b0e..f4e66c0 100644 --- a/test/client_id_tests/client_id_test_utility.cpp +++ b/test/client_id_tests/client_id_test_utility.cpp @@ -8,10 +8,11 @@ #include <unistd.h> // for access() #include <sstream> -#include "../../implementation/utility/include/utility.hpp" -#include "../../implementation/configuration/include/configuration.hpp" #include <vsomeip/constants.hpp> +#include "../../implementation/utility/include/utility.hpp" +#include "../../implementation/configuration/include/configuration.hpp" +#include "../../implementation/plugin/include/plugin_manager.hpp" using namespace vsomeip; @@ -31,22 +32,26 @@ static const vsomeip::client_t APPLICATION_OUT_LOW_CLIENT_ID = 0x6011; static const std::string APPLICATION_OUT_HIGH_NAME = "client_id_test_utility_service_out_high"; static const vsomeip::client_t APPLICATION_OUT_HIGH_CLIENT_ID = 0x6411; - - class client_id_utility_test: public ::testing::Test { public: client_id_utility_test() : - configuration_(vsomeip::configuration::get()), client_id_routing_manager_(0x0) { + + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN); + if (its_plugin) { + configuration_ = std::dynamic_pointer_cast<vsomeip::configuration>(its_plugin); + } } protected: virtual void SetUp() { - ASSERT_FALSE(file_exist(std::string("/dev/shm").append(VSOMEIP_SHM_NAME))); + ASSERT_FALSE(file_exist(std::string("/dev/shm").append(utility::get_shm_name(configuration_)))); ASSERT_TRUE(static_cast<bool>(configuration_)); configuration_->load(APPLICATION_NAME_ROUTING_MANAGER); utility::auto_configuration_init(configuration_); - EXPECT_TRUE(file_exist(std::string("/dev/shm").append(VSOMEIP_SHM_NAME))); + EXPECT_TRUE(file_exist(std::string("/dev/shm").append(utility::get_shm_name(configuration_)))); client_id_routing_manager_ = utility::request_client_id( configuration_, APPLICATION_NAME_ROUTING_MANAGER, 0x0); @@ -55,8 +60,8 @@ protected: } virtual void TearDown() { - utility::auto_configuration_exit(client_id_routing_manager_); - EXPECT_FALSE(file_exist(std::string("/dev/shm").append(VSOMEIP_SHM_NAME))); + utility::auto_configuration_exit(client_id_routing_manager_, configuration_); + EXPECT_FALSE(file_exist(std::string("/dev/shm").append(utility::get_shm_name(configuration_)))); } bool file_exist(const std::string &_path) { diff --git a/test/configuration_tests/configuration-test-deprecated.json b/test/configuration_tests/configuration-test-deprecated.json index 87f3279..ad4c0d6 100644 --- a/test/configuration_tests/configuration-test-deprecated.json +++ b/test/configuration_tests/configuration-test-deprecated.json @@ -1,21 +1,88 @@ { "unicast" : "10.0.2.15", + "diagnosis" : "85", "logging" : { "level" : "debug", "console" : "true", "file" : { "enable" : "true", "path" : "/home/someip/another-file.log" }, - "dlt" : "false" + "dlt" : "false", + "version" : { + "enable" : "false", + "interval" : "15" + } + }, + "watchdog" : + { + "enable" : "true", + "timeout" : "1234", + "allowed_missing_pongs" : "7" + }, + "file-permissions" : + { + "permissions-shm" : "444", + "umask" : "222" + }, + "supports_selective_broadcasts" : + { + "address" : "160.160.160.160" + }, + "tracing" : + { + "enable" : "true", + "sd_enable" : "true", + "channels" : + [ + { + "name" : "testname", + "id" : "testid" + }, + { + "name" : "testname2", + "id" : "testid2" + } + ], + "filters" : + [ + { + "channel" : "testname", + "services" : ["0x1111",2222], + "methods" : ["0x1111",2222], + "clients" : ["0x1111",2222] + }, + { + "channel" : "testname2", + "services" : ["0x3333",4444], + "methods" : ["0x3333",4444], + "clients" : ["0x3333",4444] + } + ] }, "applications" : [ { "name" : "my_application", - "id" : "0x7788" + "id" : "0x7788", + "max_dispatchers" : "25", + "max_dispatch_time" : "1234", + "threads" : "12", + "request_debounce_time" : "5000", + "plugins" : + [ + { + "application_plugin" : "testlibraryname" + }, + { + "intentionally_wrong_plugin" : "wrong" + } + ] }, { "name" : "other_application", - "id" : "0x9933" + "id" : "0x9933", + "threads" : "0", + "threads" : "256", + "request_debounce_time" : "10001" } ], "servicegroups" : @@ -37,7 +104,7 @@ { "service" : "0x1234", "instance" : "0x0022", - "reliable" : { "port" : "30506", "magic_cookies" : "false" }, + "reliable" : { "port" : "30506", "enable-magic-cookies" : "true" }, "unreliable" : "31000", "events" : [ @@ -77,6 +144,24 @@ "service" : "0x1234", "instance" : "0x0023", "reliable" : "30503" + }, + { + "service" : "0x7809", + "instance" : "0x1", + "multicast" : + { + "address" : "224.212.244.225", + "port" : "1234" + }, + "eventgroups" : + [ + { + "eventgroup" : "0x1111", + "threshold" : "8", + "is_multicast" : "true", + "events" : [ "0x778", "0x77A" ] + } + ] } ] }, @@ -105,6 +190,15 @@ "instance" : "0x0022", "reliable" : "30505", "unreliable" : "30507" + }, + { + "service" : "0x3333", + "instance" : "0x1" + }, + { + "service" : "0x3555", + "instance" : "0x1", + "protocol" : "other" } ] }, @@ -122,6 +216,38 @@ ] } ], + "internal_services" : + [ + { + "first" : "0xF100", + "last" : "0xF109" + }, + { + "first" : { + "service" : "0xF300", + "instance" : "0x1" + }, + "last" : { + "service" : "0xF300", + "instance" : "0x10" + } + } + ], + "clients" : + [ + { + "service" : "0x8888", + "instance" : "0x1", + "unreliable" : [ "0x11", "0x10" ], + "reliable" : [ "0x11", "0x10" ] + }, + { + "service" : "8888", + "instance" : "1", + "unreliable" : [ 40000, 40001 ], + "reliable" : [ 40000, 40001 ] + } + ], "max-payload-size-local" : "15000", "max-payload-size-reliable" : "17000", "buffer-shrink-threshold" : "11", @@ -148,12 +274,75 @@ ] } ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : "0x1277", + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : { "first" : "0x1343", "last" : "0x1346" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : { "first" : "0x1443", "last" : "0x1446" }, + "deny" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + } + ] + }, "routing" : "my_application", "service-discovery" : { "enable" : "true", "protocol" : "udp", "multicast" : "224.212.244.223", - "port" : "30666" + "port" : "30666", + "offer_debounce_time" : "1000" } } diff --git a/test/configuration_tests/configuration-test.cpp b/test/configuration_tests/configuration-test.cpp index 5eb9015..8693d4d 100644 --- a/test/configuration_tests/configuration-test.cpp +++ b/test/configuration_tests/configuration-test.cpp @@ -6,11 +6,17 @@ #include <cstdlib> #include <iostream> +#include <gtest/gtest.h> + #include <vsomeip/constants.hpp> +#include <vsomeip/plugins/application_plugin.hpp> #include "../implementation/configuration/include/configuration.hpp" +#include "../implementation/configuration/include/configuration_impl.hpp" #include "../implementation/logging/include/logger.hpp" +#include "../implementation/plugin/include/plugin_manager.hpp" + #define CONFIGURATION_FILE "configuration-test.json" #define DEPRECATED_CONFIGURATION_FILE "configuration-test-deprecated.json" @@ -24,6 +30,16 @@ #define EXPECTED_ROUTING_MANAGER_HOST "my_application" +// Logging +#define EXPECTED_VERSION_LOGGING_ENABLED false +#define EXPECTED_VERSION_LOGGING_INTERVAL 15 + +// Application +#define EXPECTED_APPLICATION_MAX_DISPATCHERS 25 +#define EXPECTED_APPLICATION_MAX_DISPATCH_TIME 1234 +#define EXPECTED_APPLICATION_THREADS 12 +#define EXPECTED_APPLICATION_REQUEST_DEBOUNCE_TIME 5000 + // Services #define EXPECTED_UNICAST_ADDRESS_1234_0022 EXPECTED_UNICAST_ADDRESS #define EXPECTED_RELIABLE_PORT_1234_0022 30506 @@ -67,11 +83,11 @@ #define EXPECTED_DEPRECATED_REQUEST_RESPONSE_DELAY 2001 template<class T> -void check(const T &_is, const T &_expected, const std::string &_test) { +::testing::AssertionResult check(const T &_is, const T &_expected, const std::string &_test) { if (_is == _expected) { - VSOMEIP_INFO << "Test \"" << _test << "\" succeeded."; + return ::testing::AssertionSuccess() << "Test \"" << _test << "\" succeeded."; } else { - VSOMEIP_ERROR << "Test \"" << _test << "\" failed! (" + return ::testing::AssertionFailure() << "Test \"" << _test << "\" failed! (" << _is << " != " << _expected << ")"; } } @@ -81,6 +97,12 @@ void check_file(const std::string &_config_file, bool _expected_has_console, bool _expected_has_file, bool _expected_has_dlt, + bool _expected_version_logging_enabled, + uint32_t _expected_version_logging_interval, + uint32_t _expected_application_max_dispatcher, + uint32_t _expected_application_max_dispatch_time, + uint32_t _expected_application_threads, + uint32_t _expected_application_request_debounce_time, const std::string &_expected_logfile, const std::string &_expected_loglevel, const std::string &_expected_unicast_address_1234_0022, @@ -111,16 +133,26 @@ void check_file(const std::string &_config_file, vsomeip::ttl_t _expected_request_response_delay) { // 0. Create configuration object - std::shared_ptr<vsomeip::configuration> its_configuration - = vsomeip::configuration::get(); + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN); + if (its_plugin) { + its_configuration = std::dynamic_pointer_cast<vsomeip::configuration>(its_plugin); + } // 1. Did we get a configuration object? if (0 == its_configuration) { - VSOMEIP_ERROR << "No configuration object. " + ADD_FAILURE() << "No configuration object. " "Either memory overflow or loading error detected!"; return; } + vsomeip::cfg::configuration_impl its_copied_config( + static_cast<vsomeip::cfg::configuration_impl&>(*its_configuration)); + vsomeip::cfg::configuration_impl* its_new_config = + new vsomeip::cfg::configuration_impl(its_copied_config); + delete its_new_config; + // 2. Set environment variable to config file and load it #ifndef _WIN32 setenv("VSOMEIP_CONFIGURATION", _config_file.c_str(), 1); @@ -129,11 +161,20 @@ void check_file(const std::string &_config_file, #endif its_configuration->load(EXPECTED_ROUTING_MANAGER_HOST); + its_configuration->set_configuration_path("/my/test/path"); + // 3. Check host address boost::asio::ip::address its_host_unicast_address = its_configuration->get_unicast_address(); - check<std::string>(its_host_unicast_address.to_string(), - _expected_unicast_address, "UNICAST ADDRESS"); + EXPECT_TRUE(check<std::string>(its_host_unicast_address.to_string(), + _expected_unicast_address, "UNICAST ADDRESS")); + EXPECT_TRUE(its_configuration->is_v4()); + EXPECT_FALSE(its_configuration->is_v6()); + + // check diagnosis prefix + EXPECT_NE(0x54, its_configuration->get_diagnosis_address()); + EXPECT_EQ(0x55, its_configuration->get_diagnosis_address()); + EXPECT_NE(0x56, its_configuration->get_diagnosis_address()); // 4. Check logging bool has_console = its_configuration->has_console_log(); @@ -142,13 +183,113 @@ void check_file(const std::string &_config_file, std::string logfile = its_configuration->get_logfile(); boost::log::trivial::severity_level loglevel = its_configuration->get_loglevel(); + bool has_version_logging = its_configuration->log_version(); + std::uint32_t version_logging_interval = its_configuration->get_log_version_interval(); + + EXPECT_TRUE(check<bool>(has_console, _expected_has_console, "HAS CONSOLE")); + EXPECT_TRUE(check<bool>(has_file, _expected_has_file, "HAS FILE")); + EXPECT_TRUE(check<bool>(has_dlt, _expected_has_dlt, "HAS DLT")); + EXPECT_TRUE(check<std::string>(logfile, _expected_logfile, "LOGFILE")); + EXPECT_TRUE(check<std::string>(boost::log::trivial::to_string(loglevel), + _expected_loglevel, "LOGLEVEL")); + EXPECT_TRUE(check<bool>(has_version_logging, _expected_version_logging_enabled, + "VERSION LOGGING")); + EXPECT_TRUE(check<uint32_t>(version_logging_interval, + _expected_version_logging_interval, + "VERSION LOGGING INTERVAL")); + + // watchdog + EXPECT_TRUE(its_configuration->is_watchdog_enabled()); + EXPECT_EQ(1234u, its_configuration->get_watchdog_timeout()); + EXPECT_EQ(7u, its_configuration->get_allowed_missing_pongs()); + + // file permissions + EXPECT_EQ(0444u, its_configuration->get_permissions_shm()); + EXPECT_EQ(0222u, its_configuration->get_umask()); + + // selective broadcasts + EXPECT_TRUE(its_configuration->supports_selective_broadcasts( + boost::asio::ip::address::from_string("160.160.160.160"))); + + // tracing + std::shared_ptr<vsomeip::cfg::trace> its_trace = its_configuration->get_trace(); + EXPECT_TRUE(its_trace->is_enabled_); + EXPECT_TRUE(its_trace->is_sd_enabled_); + EXPECT_EQ(2u, its_trace->channels_.size()); + EXPECT_EQ(2u, its_trace->filter_rules_.size()); + for (const auto &c : its_trace->channels_) { + EXPECT_TRUE(c->name_ == std::string("testname") || c->name_ == std::string("testname2")); + if (c->name_ == std::string("testname")) { + EXPECT_EQ(std::string("testid"), c->id_); + } else if (c->name_ == std::string("testname2")) { + EXPECT_EQ(std::string("testid2"), c->id_); + } + } + for (const auto &f : its_trace->filter_rules_) { + EXPECT_TRUE(f->channel_ == std::string("testname") || f->channel_ == std::string("testname2")); + if (f->channel_ == std::string("testname")) { + EXPECT_EQ(2u, f->services_.size()); + EXPECT_EQ(2u, f->methods_.size()); + EXPECT_EQ(2u, f->clients_.size()); + for (const vsomeip::service_t s : f->services_) { + EXPECT_TRUE(s == vsomeip::service_t(0x1111) || s == vsomeip::service_t(2222)); + } + for (const vsomeip::method_t s : f->methods_) { + EXPECT_TRUE(s == vsomeip::method_t(0x1111) || s == vsomeip::method_t(2222)); + } + for (const vsomeip::client_t s : f->clients_) { + EXPECT_TRUE(s == vsomeip::client_t(0x1111) || s == vsomeip::client_t(2222)); + } + } else if (f->channel_ == std::string("testname2")) { + EXPECT_EQ(2u, f->services_.size()); + EXPECT_EQ(2u, f->methods_.size()); + EXPECT_EQ(2u, f->clients_.size()); + for (const vsomeip::service_t s : f->services_) { + EXPECT_TRUE(s == vsomeip::service_t(0x3333) || s == vsomeip::service_t(4444)); + } + for (const vsomeip::method_t s : f->methods_) { + EXPECT_TRUE(s == vsomeip::method_t(0x3333) || s == vsomeip::method_t(4444)); + } + for (const vsomeip::client_t s : f->clients_) { + EXPECT_TRUE(s == vsomeip::client_t(0x3333) || s == vsomeip::client_t(4444)); + } + } + } + + // Applications + std::size_t max_dispatchers = its_configuration->get_max_dispatchers( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t max_dispatch_time = its_configuration->get_max_dispatch_time( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t io_threads = its_configuration->get_io_thread_count( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t request_time = its_configuration->get_request_debouncing( + EXPECTED_ROUTING_MANAGER_HOST); + + EXPECT_TRUE(check<std::size_t>(max_dispatchers, + _expected_application_max_dispatcher, "MAX DISPATCHERS")); + EXPECT_TRUE(check<std::size_t>(max_dispatch_time, + _expected_application_max_dispatch_time, "MAX DISPATCH TIME")); + EXPECT_TRUE(check<std::size_t>(io_threads, _expected_application_threads, + "IO THREADS")); + EXPECT_TRUE(check<std::size_t>(request_time, + _expected_application_request_debounce_time, "REQUEST DEBOUNCE TIME")); + + EXPECT_EQ(0x9933, its_configuration->get_id("other_application")); + + std::map<vsomeip::plugin_type_e, std::string> its_plugins = + its_configuration->get_plugins(EXPECTED_ROUTING_MANAGER_HOST); + EXPECT_EQ(1u, its_plugins.size()); + for (const auto plugin : its_plugins) { + EXPECT_EQ(vsomeip::plugin_type_e::APPLICATION_PLUGIN, plugin.first); + EXPECT_EQ(std::string("libtestlibraryname.so." + + std::to_string(VSOMEIP_APPLICATION_PLUGIN_VERSION)), + plugin.second); + } + EXPECT_EQ(vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, its_plugin->get_plugin_type()); + EXPECT_EQ("vsomeip cfg plugin", its_plugin->get_plugin_name()); + EXPECT_EQ(1u, its_plugin->get_plugin_version()); - check<bool>(has_console, _expected_has_console, "HAS CONSOLE"); - check<bool>(has_file, _expected_has_file, "HAS FILE"); - check<bool>(has_dlt, _expected_has_dlt, "HAS DLT"); - check<std::string>(logfile, _expected_logfile, "LOGFILE"); - check<std::string>(boost::log::trivial::to_string(loglevel), - _expected_loglevel, "LOGLEVEL"); // 5. Services std::string its_unicast_address @@ -158,15 +299,15 @@ void check_file(const std::string &_config_file, uint16_t its_unreliable_port = its_configuration->get_unreliable_port(0x1234, 0x0022); - check<std::string>(its_unicast_address, + EXPECT_TRUE(check<std::string>(its_unicast_address, _expected_unicast_address_1234_0022, - "UNICAST_ADDRESS_1234_0022"); - check<uint16_t>(its_reliable_port, + "UNICAST_ADDRESS_1234_0022")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, _expected_reliable_port_1234_0022, - "RELIABLE_PORT_1234_0022"); - check<uint16_t>(its_unreliable_port, + "RELIABLE_PORT_1234_0022")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, _expected_unreliable_port_1234_0022, - "UNRELIABLE_PORT_1234_0022"); + "UNRELIABLE_PORT_1234_0022")); its_unicast_address = its_configuration->get_unicast_address(0x1234, 0x0023); @@ -175,15 +316,15 @@ void check_file(const std::string &_config_file, its_unreliable_port = its_configuration->get_unreliable_port(0x1234, 0x0023); - check<std::string>(its_unicast_address, + EXPECT_TRUE(check<std::string>(its_unicast_address, _expected_unicast_address_1234_0023, - "UNICAST_ADDRESS_1234_0023"); - check<uint16_t>(its_reliable_port, + "UNICAST_ADDRESS_1234_0023")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, _expected_reliable_port_1234_0023, - "RELIABLE_PORT_1234_0023"); - check<uint16_t>(its_unreliable_port, + "RELIABLE_PORT_1234_0023")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, _expected_unreliable_port_1234_0023, - "UNRELIABLE_PORT_1234_0023"); + "UNRELIABLE_PORT_1234_0023")); its_unicast_address = its_configuration->get_unicast_address(0x2277, 0x0022); @@ -192,15 +333,15 @@ void check_file(const std::string &_config_file, its_unreliable_port = its_configuration->get_unreliable_port(0x2277, 0x0022); - check<std::string>(its_unicast_address, + EXPECT_TRUE(check<std::string>(its_unicast_address, _expected_unicast_address_2277_0022, - "UNICAST_ADDRESS_2277_0022"); - check<uint16_t>(its_reliable_port, + "UNICAST_ADDRESS_2277_0022")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, _expected_reliable_port_2277_0022, - "RELIABLE_PORT_2277_0022"); - check<uint16_t>(its_unreliable_port, + "RELIABLE_PORT_2277_0022")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, _expected_unreliable_port_2277_0022, - "UNRELIABLE_PORT_2277_0022"); + "UNRELIABLE_PORT_2277_0022")); its_unicast_address = its_configuration->get_unicast_address(0x2266, 0x0022); @@ -209,15 +350,15 @@ void check_file(const std::string &_config_file, its_unreliable_port = its_configuration->get_unreliable_port(0x2266, 0x0022); - check<std::string>(its_unicast_address, + EXPECT_TRUE(check<std::string>(its_unicast_address, _expected_unicast_address_2266_0022, - "UNICAST_ADDRESS_2266_0022"); - check<uint16_t>(its_reliable_port, + "UNICAST_ADDRESS_2266_0022")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, _expected_reliable_port_2266_0022, - "RELIABLE_PORT_2266_0022"); - check<uint16_t>(its_unreliable_port, + "RELIABLE_PORT_2266_0022")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, _expected_unreliable_port_2266_0022, - "UNRELIABLE_PORT_2266_0022"); + "UNRELIABLE_PORT_2266_0022")); its_unicast_address = its_configuration->get_unicast_address(0x4466, 0x0321); @@ -226,15 +367,74 @@ void check_file(const std::string &_config_file, its_unreliable_port = its_configuration->get_unreliable_port(0x4466, 0x0321); - check<std::string>(its_unicast_address, + EXPECT_TRUE(check<std::string>(its_unicast_address, _expected_unicast_address_4466_0321, - "UNICAST_ADDRESS_4466_0321"); - check<uint16_t>(its_reliable_port, + "UNICAST_ADDRESS_4466_0321")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, _expected_reliable_port_4466_0321, - "RELIABLE_PORT_4466_0321"); - check<uint16_t>(its_unreliable_port, + "RELIABLE_PORT_4466_0321")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, _expected_unreliable_port_4466_0321, - "UNRELIABLE_PORT_4466_0321"); + "UNRELIABLE_PORT_4466_0321")); + + std::string its_multicast_address; + std::uint16_t its_multicast_port; + its_configuration->get_multicast(0x7809, 0x1, 0x1111, + its_multicast_address, its_multicast_port); + EXPECT_EQ(1234u, its_multicast_port); + EXPECT_EQ(std::string("224.212.244.225"), its_multicast_address); + EXPECT_EQ(8u, its_configuration->get_threshold(0x7809, 0x1, 0x1111)); + + EXPECT_TRUE(its_configuration->is_offered_remote(0x1234,0x0022)); + EXPECT_FALSE(its_configuration->is_offered_remote(0x3333,0x1)); + + EXPECT_TRUE(its_configuration->has_enabled_magic_cookies("10.0.2.15", 30506)); + EXPECT_FALSE(its_configuration->has_enabled_magic_cookies("10.0.2.15", 30503)); + + std::set<std::pair<vsomeip::service_t, vsomeip::instance_t>> its_remote_services = + its_configuration->get_remote_services(); + EXPECT_EQ(1u, its_remote_services.size()); + for (const auto &p : its_remote_services) { + EXPECT_EQ(0x4466, p.first); + EXPECT_EQ(0x321, p.second); + } + + EXPECT_TRUE(its_configuration->is_someip(0x3333,0x1)); + EXPECT_FALSE(its_configuration->is_someip(0x3555,0x1)); + + // Internal services + EXPECT_TRUE(its_configuration->is_local_service(0x1234, 0x0022)); + EXPECT_TRUE(its_configuration->is_local_service(0x3333,0x1)); + // defined range, service level only + EXPECT_FALSE(its_configuration->is_local_service(0xF0FF,0x1)); + EXPECT_TRUE(its_configuration->is_local_service(0xF100,0x1)); + EXPECT_TRUE(its_configuration->is_local_service(0xF101,0x23)); + EXPECT_TRUE(its_configuration->is_local_service(0xF109,0xFFFF)); + EXPECT_FALSE(its_configuration->is_local_service(0xF10a,0x1)); + // defined range, service and instance level + EXPECT_FALSE(its_configuration->is_local_service(0xF2FF,0xFFFF)); + EXPECT_TRUE(its_configuration->is_local_service(0xF300,0x1)); + EXPECT_TRUE(its_configuration->is_local_service(0xF300,0x5)); + EXPECT_TRUE(its_configuration->is_local_service(0xF300,0x10)); + EXPECT_FALSE(its_configuration->is_local_service(0xF300,0x11)); + EXPECT_FALSE(its_configuration->is_local_service(0xF301,0x11)); + + // clients + std::map<bool, std::set<uint16_t>> used_ports; + used_ports[true].insert(0x11); + used_ports[false].insert(0x10); + std::uint16_t port_to_use(0x0); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x1, true, used_ports, port_to_use)); + EXPECT_EQ(0x10, port_to_use); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x1, false, used_ports, port_to_use)); + EXPECT_EQ(0x11, port_to_use); + + used_ports[true].insert(0x10); + used_ports[false].insert(0x11); + EXPECT_FALSE(its_configuration->get_client_port(0x8888, 0x1, true, used_ports, port_to_use)); + EXPECT_EQ(vsomeip::ILLEGAL_PORT, port_to_use); + EXPECT_FALSE(its_configuration->get_client_port(0x8888, 0x1, false, used_ports, port_to_use)); + EXPECT_EQ(vsomeip::ILLEGAL_PORT, port_to_use); // payload sizes // use 17000 instead of 1500 as configured max-local-payload size will be @@ -243,11 +443,42 @@ void check_file(const std::string &_config_file, 17000u + 16u + + VSOMEIP_COMMAND_HEADER_SIZE + sizeof(vsomeip::instance_t) + sizeof(bool) + sizeof(bool) + sizeof(vsomeip::client_t)); - check<std::uint32_t>(max_local_message_size, its_configuration->get_max_message_size_local(), "max-local-message-size"); - check<std::uint32_t>(11u, its_configuration->get_buffer_shrink_threshold(), "buffer shrink threshold"); - check<std::uint32_t>(14999u + 16u, its_configuration->get_max_message_size_reliable("10.10.10.10", 7777), "max-message-size-reliable1"); - check<std::uint32_t>(17000u + 16, its_configuration->get_max_message_size_reliable("11.11.11.11", 4711), "max-message-size-reliable2"); - check<std::uint32_t>(15001u + 16, its_configuration->get_max_message_size_reliable("10.10.10.11", 7778), "max-message-size-reliable3"); + EXPECT_EQ(max_local_message_size, its_configuration->get_max_message_size_local()); + EXPECT_EQ(11u, its_configuration->get_buffer_shrink_threshold()); + EXPECT_EQ(14999u + 16u, its_configuration->get_max_message_size_reliable("10.10.10.10", 7777)); + EXPECT_EQ(17000u + 16, its_configuration->get_max_message_size_reliable("11.11.11.11", 4711)); + EXPECT_EQ(15001u + 16, its_configuration->get_max_message_size_reliable("10.10.10.11", 7778)); + + // security + EXPECT_TRUE(its_configuration->is_security_enabled()); + EXPECT_TRUE(its_configuration->is_offer_allowed(0x1277, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_offer_allowed(0x1277, 0x1234, 0x5679)); + EXPECT_FALSE(its_configuration->is_offer_allowed(0x1277, 0x1233, 0x5679)); + EXPECT_FALSE(its_configuration->is_offer_allowed(0x1266, 0x1233, 0x5679)); + // explicitly denied offers + EXPECT_FALSE(its_configuration->is_offer_allowed(0x1443, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_offer_allowed(0x1443, 0x1235, 0x5678)); + EXPECT_TRUE(its_configuration->is_offer_allowed(0x1443, 0x1234, 0x5679)); + EXPECT_TRUE(its_configuration->is_offer_allowed(0x1443, 0x1300, 0x1)); + EXPECT_TRUE(its_configuration->is_offer_allowed(0x1443, 0x1300, 0x2)); + + EXPECT_TRUE(its_configuration->is_client_allowed(0x1343, 0x1234, 0x5678)); + EXPECT_TRUE(its_configuration->is_client_allowed(0x1346, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1347, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1342, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1343, 0x1234, 0x5679)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1343, 0x1230, 0x5678)); + // explicitly denied requests + EXPECT_FALSE(its_configuration->is_client_allowed(0x1443, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1446, 0x1234, 0x5678)); + EXPECT_TRUE(its_configuration->is_client_allowed(0x1443, 0x1234, 0x5679)); + EXPECT_TRUE(its_configuration->is_client_allowed(0x1443, 0x1234, 0x5679)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1442, 0x1234, 0x5678)); + EXPECT_FALSE(its_configuration->is_client_allowed(0x1447, 0x1234, 0x5678)); + + EXPECT_TRUE(its_configuration->check_credentials(0x1277, 1000, 1000)); + EXPECT_FALSE(its_configuration->check_credentials(0x1277, 1001, 1001)); + EXPECT_FALSE(its_configuration->check_credentials(0x1278, 1000, 1000)); // 6. Service discovery bool enabled = its_configuration->is_sd_enabled(); @@ -263,32 +494,36 @@ void check_file(const std::string &_config_file, int32_t cyclic_offer_delay = its_configuration->get_sd_cyclic_offer_delay(); int32_t request_response_delay = its_configuration->get_sd_request_response_delay(); - check<bool>(enabled, _expected_enabled, "SD ENABLED"); - check<std::string>(protocol, _expected_protocol, "SD PROTOCOL"); - check<std::string>(multicast, _expected_multicast, "SD MULTICAST"); - check<uint16_t>(port, _expected_port, "SD PORT"); - - check<int32_t>(initial_delay_min, _expected_initial_delay_min, "SD INITIAL DELAY MIN"); - check<int32_t>(initial_delay_max, _expected_initial_delay_max, "SD INITIAL DELAY MAX"); - check<int32_t>(repetitions_base_delay, _expected_repetitions_base_delay, "SD REPETITION BASE DELAY"); - check<uint8_t>(repetitions_max,_expected_repetitions_max, "SD REPETITION MAX"); - check<vsomeip::ttl_t>(ttl, _expected_ttl, "SD TTL"); - check<int32_t>(cyclic_offer_delay, _expected_cyclic_offer_delay, "SD CYCLIC OFFER DELAY"); - check<int32_t>(request_response_delay, _expected_request_response_delay, "SD RESPONSE REQUEST DELAY"); + EXPECT_TRUE(check<bool>(enabled, _expected_enabled, "SD ENABLED")); + EXPECT_TRUE(check<std::string>(protocol, _expected_protocol, "SD PROTOCOL")); + EXPECT_TRUE(check<std::string>(multicast, _expected_multicast, "SD MULTICAST")); + EXPECT_TRUE(check<uint16_t>(port, _expected_port, "SD PORT")); + + EXPECT_TRUE(check<int32_t>(initial_delay_min, _expected_initial_delay_min, "SD INITIAL DELAY MIN")); + EXPECT_TRUE(check<int32_t>(initial_delay_max, _expected_initial_delay_max, "SD INITIAL DELAY MAX")); + EXPECT_TRUE(check<int32_t>(repetitions_base_delay, _expected_repetitions_base_delay, "SD REPETITION BASE DELAY")); + EXPECT_TRUE(check<uint8_t>(repetitions_max,_expected_repetitions_max, "SD REPETITION MAX")); + EXPECT_TRUE(check<vsomeip::ttl_t>(ttl, _expected_ttl, "SD TTL")); + EXPECT_TRUE(check<int32_t>(cyclic_offer_delay, _expected_cyclic_offer_delay, "SD CYCLIC OFFER DELAY")); + EXPECT_TRUE(check<int32_t>(request_response_delay, _expected_request_response_delay, "SD RESPONSE REQUEST DELAY")); + EXPECT_EQ(1000u, its_configuration->get_sd_offer_debounce_time()); + + ASSERT_TRUE(vsomeip::plugin_manager::get()->unload_plugin(vsomeip::plugin_type_e::CONFIGURATION_PLUGIN)); } - - -int main() { +TEST(configuration_test, check_config_file) { // Check current configuration file format - std::cout << "/////////////////////////////////" << std::endl - << "// CHECKING CONFIGURATION FILE //" << std::endl - << "/////////////////////////////////" << std::endl; check_file(CONFIGURATION_FILE, EXPECTED_UNICAST_ADDRESS, EXPECTED_HAS_CONSOLE, EXPECTED_HAS_FILE, EXPECTED_HAS_DLT, + EXPECTED_VERSION_LOGGING_ENABLED, + EXPECTED_VERSION_LOGGING_INTERVAL, + EXPECTED_APPLICATION_MAX_DISPATCHERS, + EXPECTED_APPLICATION_MAX_DISPATCH_TIME, + EXPECTED_APPLICATION_THREADS, + EXPECTED_APPLICATION_REQUEST_DEBOUNCE_TIME, EXPECTED_LOGFILE, EXPECTED_LOGLEVEL, EXPECTED_UNICAST_ADDRESS_1234_0022, @@ -317,16 +552,21 @@ int main() { EXPECTED_TTL, EXPECTED_CYCLIC_OFFER_DELAY, EXPECTED_REQUEST_RESPONSE_DELAY); +} +TEST(configuration_test, check_deprecated_config_file) { // Check deprecated configuration file format - std::cout << "////////////////////////////////////////////" << std::endl - << "// CHECKING DEPRECATED CONFIGURATION FILE //" << std::endl - << "////////////////////////////////////////////" << std::endl; check_file(DEPRECATED_CONFIGURATION_FILE, EXPECTED_UNICAST_ADDRESS, EXPECTED_HAS_CONSOLE, EXPECTED_HAS_FILE, EXPECTED_HAS_DLT, + EXPECTED_VERSION_LOGGING_ENABLED, + EXPECTED_VERSION_LOGGING_INTERVAL, + EXPECTED_APPLICATION_MAX_DISPATCHERS, + EXPECTED_APPLICATION_MAX_DISPATCH_TIME, + EXPECTED_APPLICATION_THREADS, + EXPECTED_APPLICATION_REQUEST_DEBOUNCE_TIME, EXPECTED_LOGFILE, EXPECTED_LOGLEVEL, EXPECTED_UNICAST_ADDRESS_1234_0022, @@ -355,9 +595,9 @@ int main() { EXPECTED_DEPRECATED_TTL, EXPECTED_CYCLIC_OFFER_DELAY, EXPECTED_DEPRECATED_REQUEST_RESPONSE_DELAY); - - return 0; } - - +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/configuration_tests/configuration-test.json b/test/configuration_tests/configuration-test.json index afa3c41..1509ad4 100644 --- a/test/configuration_tests/configuration-test.json +++ b/test/configuration_tests/configuration-test.json @@ -1,21 +1,88 @@ { "unicast" : "10.0.2.15", + "diagnosis" : "0x55", "logging" : { "level" : "debug", "console" : "true", "file" : { "enable" : "true", "path" : "/home/someip/another-file.log" }, - "dlt" : "false" + "dlt" : "false", + "version" : { + "enable" : "false", + "interval" : "15" + } + }, + "watchdog" : + { + "enable" : "true", + "timeout" : "1234", + "allowed_missing_pongs" : "7" + }, + "file-permissions" : + { + "permissions-shm" : "0444", + "umask" : "0222" + }, + "supports_selective_broadcasts" : + { + "address" : "160.160.160.160" + }, + "tracing" : + { + "enable" : "true", + "sd_enable" : "true", + "channels" : + [ + { + "name" : "testname", + "id" : "testid" + }, + { + "name" : "testname2", + "id" : "testid2" + } + ], + "filters" : + [ + { + "channel" : "testname", + "services" : ["0x1111",2222], + "methods" : ["0x1111",2222], + "clients" : ["0x1111",2222] + }, + { + "channel" : "testname2", + "services" : ["0x3333",4444], + "methods" : ["0x3333",4444], + "clients" : ["0x3333",4444] + } + ] }, "applications" : [ { "name" : "my_application", - "id" : "0x7788" + "id" : "0x7788", + "max_dispatchers" : "25", + "max_dispatch_time" : "1234", + "threads" : "12", + "request_debounce_time" : "5000", + "plugins" : + [ + { + "application_plugin" : "testlibraryname" + }, + { + "intentionally_wrong_plugin" : "wrong" + } + ] }, { "name" : "other_application", - "id" : "0x9933" + "id" : "0x9933", + "threads" : "0", + "threads" : "256", + "request_debounce_time" : "10001" } ], "services" : @@ -24,7 +91,7 @@ "service" : "0x1234", "instance" : "0x0022", "unicast" : "local", - "reliable" : { "port" : "30506", "magic_cookies" : "false" }, + "reliable" : { "port" : "30506", "enable-magic-cookies" : "true" }, "unreliable" : "31000", "events" : [ @@ -83,6 +150,65 @@ "unicast" : "10.0.2.23", "reliable" : "30506", "unreliable" : "30444" + }, + { + "service" : "0x3333", + "instance" : "0x1" + }, + { + "service" : "0x7809", + "instance" : "0x1", + "multicast" : + { + "address" : "224.212.244.225", + "port" : "1234" + }, + "eventgroups" : + [ + { + "eventgroup" : "0x1111", + "threshold" : "8", + "is_multicast" : "true", + "events" : [ "0x778", "0x77A" ] + } + ] + }, + { + "service" : "0x3555", + "instance" : "0x1", + "protocol" : "other" + } + ], + "internal_services" : + [ + { + "first" : "0xF100", + "last" : "0xF109" + }, + { + "first" : { + "service" : "0xF300", + "instance" : "0x1" + }, + "last" : { + "service" : "0xF300", + "instance" : "0x10" + } + } + ], + "clients" : + [ + { + "service" : "0x8888", + "instance" : "0x1", + "unreliable" : [ "0x11", "0x10" ], + "reliable" : [ "0x11", "0x10" ] + }, + { + "service" : "8888", + "instance" : "1", + "unreliable" : [ 40000, 40001 ], + "reliable" : [ 40000, 40001 ] } ], "max-payload-size-local" : "15000", @@ -111,6 +237,68 @@ ] } ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : "0x1277", + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : { "first" : "0x1343", "last" : "0x1346" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : { "first" : "0x1443", "last" : "0x1446" }, + "deny" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + } + ] + }, "routing" : "my_application", "service-discovery" : { @@ -124,6 +312,7 @@ "repetitions_max" : "4", "ttl" : "13", "cyclic_offer_delay" : "2132", - "request_response_delay" : "1111" + "request_response_delay" : "1111", + "offer_debounce_time" : "1000" } }
\ No newline at end of file diff --git a/test/initial_event_tests/initial_event_test_client.cpp b/test/initial_event_tests/initial_event_test_client.cpp index 8f843c6..9e1314f 100644 --- a/test/initial_event_tests/initial_event_test_client.cpp +++ b/test/initial_event_tests/initial_event_test_client.cpp @@ -197,11 +197,15 @@ public: case vsomeip::subscription_type_e::SU_RELIABLE: case vsomeip::subscription_type_e::SU_PREFER_UNRELIABLE: case vsomeip::subscription_type_e::SU_PREFER_RELIABLE: - case vsomeip::subscription_type_e::SU_RELIABLE_AND_UNRELIABLE: if (all_notifications_received()) { notify = true; } break; + case vsomeip::subscription_type_e::SU_RELIABLE_AND_UNRELIABLE: + if (all_notifications_received_tcp_and_udp()) { + notify = true; + } + break; } if(notify && !dont_exit_) { @@ -222,24 +226,30 @@ public: if (v.second == initial_event_test::notifications_to_send) { return true; } else { - if (initial_event_strict_checking_) { - return false; - } else { - if (v.second >= initial_event_test::notifications_to_send) { - VSOMEIP_WARNING - << "[" << std::setw(4) << std::setfill('0') << std::hex - << client_number_ << "] " - << " Received multiple initial events from service/instance: " - << std::setw(4) << std::setfill('0') << std::hex << v.first.first - << "." - << std::setw(4) << std::setfill('0') << std::hex << v.first.second - << " number of received events: " << v.second - << ". This is caused by StopSubscribe/Subscribe messages and/or" - << " service offered via UDP and TCP"; - return true; - } else { - return false; + if (v.second >= initial_event_test::notifications_to_send) { + VSOMEIP_WARNING + << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second + << ". This is caused by StopSubscribe/Subscribe messages and/or" + << " service offered via UDP and TCP"; + if (initial_event_strict_checking_) { + ADD_FAILURE() << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second; } + return initial_event_strict_checking_ ? false : true; + + } else { + return false; } } } @@ -262,6 +272,15 @@ public: << ". This is caused by StopSubscribe/Subscribe messages and/or" << " service offered via UDP and TCP"; received_twice++; + } else if (initial_event_strict_checking_ && + v.second > initial_event_test::notifications_to_send * 2) { + ADD_FAILURE() << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second; } else if (v.second == initial_event_test::notifications_to_send * 2) { received_twice++; } else if(v.second == initial_event_test::notifications_to_send) { @@ -280,6 +299,11 @@ public: << " Normal: " << received_normal << " Twice: " << received_twice; return true; + } else if (initial_event_strict_checking_ && ( + received_twice > ((service_infos_.size() - 1) * events_to_subscribe_)/ 2)) { + ADD_FAILURE() << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received too much initial events twice: " << received_twice; } return false; } diff --git a/test/readme.txt b/test/readme.txt index 6b191d5..9f7985a 100644 --- a/test/readme.txt +++ b/test/readme.txt @@ -374,6 +374,12 @@ There are multiple versions of this test which differ in the used subscription method and port setup (use ctest -N to see all). For manual start the desired description method has to be passed to the starter script as first parameter. +The subscribe_notify_test_one_event_two_eventgroups_* tests are testing the +requirement that for events which are member of multiple eventgroups initial +events shall be sent per eventgroup. However normal updates of the event should +be sent only once even if a remote subscriber is subscribed to multiple of the +event's eventgroups (TR_SOMEIP_00570). + CPU load test ------------- diff --git a/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp b/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp index 9849613..b035b96 100644 --- a/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp +++ b/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp @@ -12,6 +12,7 @@ #include <map> #include <algorithm> #include <unordered_set> +#include <atomic> #include <gtest/gtest.h> @@ -35,7 +36,9 @@ public: wait_for_stop_(true), stop_thread_(std::bind(&subscribe_notify_one_test_service::wait_for_stop, this)), wait_for_notify_(true), - notify_thread_(std::bind(&subscribe_notify_one_test_service::notify_one, this)) { + notify_thread_(std::bind(&subscribe_notify_one_test_service::notify_one, this)), + subscription_state_handler_called_(0), + subscription_error_occured_(false) { if (!app_->init()) { ADD_FAILURE() << "Couldn't initialize application"; return; @@ -80,6 +83,14 @@ public: app_->request_service(i.service_id, i.instance_id, vsomeip::DEFAULT_MAJOR, vsomeip::DEFAULT_MINOR, true); + auto handler = std::bind(&subscribe_notify_one_test_service::on_subscription_state_change, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); + app_->register_subscription_status_handler(i.service_id, i.instance_id, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + app_->register_subscription_status_handler(vsomeip::ANY_SERVICE, i.instance_id, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + app_->register_subscription_status_handler(i.service_id, vsomeip::ANY_INSTANCE, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + app_->register_subscription_status_handler(vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + std::set<vsomeip::eventgroup_t> its_eventgroups; its_eventgroups.insert(i.eventgroup_id); app_->request_event(i.service_id, i.instance_id, i.event_id, its_eventgroups, false); @@ -143,6 +154,22 @@ public: } } + void on_subscription_state_change(const vsomeip::service_t _service, const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, const vsomeip::event_t _event, const uint16_t _error) { + (void)_service; + (void)_instance; + (void)_eventgroup; + (void)_event; + if (!_error) { + subscription_state_handler_called_++; + } else { + subscription_error_occured_ = true; + VSOMEIP_WARNING << std::hex << app_->get_client() + << " : on_subscription_state_change: for service " << std::hex + << _service << " received a subscription error!"; + } + } + bool on_subscription(vsomeip::client_t _client, bool _subscribed) { // check if all other services have subscribed: // -1 for placeholder in array and -1 for the service itself @@ -285,6 +312,7 @@ public: VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex << service_info_.service_id << "] Subscribing"; // subscribe to events of other services + uint32_t subscribe_count = 0; for(const subscribe_notify_one_test::service_info& i: subscribe_notify_one_test::service_infos) { if ((i.service_id == service_info_.service_id && i.instance_id == service_info_.instance_id) @@ -292,6 +320,7 @@ public: continue; } + ++subscribe_count; app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, vsomeip::DEFAULT_MAJOR, subscription_type_); @@ -306,6 +335,19 @@ public: while (wait_until_notified_from_other_services_) { condition_.wait(its_lock); } + + // It is possible that we run in the case a subscription is NACKED + // due to TCP endpoint not completely connected when subscription + // is processed in the server - due to resubscribing the error handler + // count may differ from expected value, but its not a real but as + // the subscription takes places anyways and all events will be received. + if (!subscription_error_occured_) { + // 4 * subscribe count cause we installed three additional wild-card handlers + ASSERT_EQ(subscribe_count * 4, subscription_state_handler_called_); + } else { + VSOMEIP_WARNING << "Subscription state handler check skipped: CallCount=" + << std::dec << subscription_state_handler_called_; + } } void notify_one() { @@ -363,12 +405,32 @@ public: wait_until_notified_from_other_services_ = false; condition_.notify_one(); } + + stop_offer(); + + // ensure that the service which hosts the routing doesn't exit to early + if (app_->is_routing()) { + for (const auto& i : subscribe_notify_one_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + while (app_->is_available(i.service_id, i.instance_id, + vsomeip::ANY_MAJOR, vsomeip::ANY_MINOR)) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + } + for(const auto& i : subscribe_notify_one_test::service_infos) { if ((i.service_id == service_info_.service_id && i.instance_id == service_info_.instance_id) || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { continue; } + app_->register_subscription_status_handler(i.service_id, i.instance_id, + i.eventgroup_id, vsomeip::ANY_EVENT, nullptr); app_->unsubscribe(i.service_id, i.instance_id, i.eventgroup_id); app_->release_event(i.service_id, i.instance_id, i.event_id); app_->release_service(i.service_id, i.instance_id); @@ -403,6 +465,8 @@ private: std::thread notify_thread_; std::unordered_set<vsomeip::client_t> subscribers_; + std::atomic<uint32_t> subscription_state_handler_called_; + std::atomic<bool> subscription_error_occured_; }; static int service_number; diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master.json.in new file mode 100644 index 0000000..0b0051a --- /dev/null +++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master.json.in @@ -0,0 +1,31 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_client", + "id" : "0x9999" + } + ], + "routing" : "vsomeipd", + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json.in new file mode 100644 index 0000000..558a873 --- /dev/null +++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json.in @@ -0,0 +1,39 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_service", + "id" : "0x8888" + } + ], + "services" : + [ + { + "service" : "0xcafe", + "instance" : "0x1", + "reliable" : { "port":"30509", "enable-magic-cookies":"false" } + } + ], + "routing" : "vsomeipd", + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json.in new file mode 100644 index 0000000..1828a7a --- /dev/null +++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json.in @@ -0,0 +1,39 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_service", + "id" : "0x8888" + } + ], + "services" : + [ + { + "service" : "0xcafe", + "instance" : "0x1", + "unreliable" : "30509" + } + ], + "routing" : "vsomeipd", + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp b/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp index ed41314..761c3c4 100644 --- a/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp +++ b/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp @@ -43,6 +43,13 @@ static constexpr std::array<service_info, 7> service_infos_same_service_id = {{ }}; static constexpr int notifications_to_send = 10; + +// one_event_two_eventgroups globals +static constexpr struct service_info service_info_subscriber_based_notification = + { 0xCAFE, 0x1, 0x8888, 0x8111, 0x1}; +static constexpr vsomeip::method_t shutdown_method_id = 0x6666; +static constexpr vsomeip::method_t set_method_id = 0x7777; + } #endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */ diff --git a/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_client.cpp b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_client.cpp new file mode 100644 index 0000000..eaec6be --- /dev/null +++ b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_client.cpp @@ -0,0 +1,370 @@ +// Copyright (C) 2014-2017 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/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <utility> + +#include <vsomeip/vsomeip.hpp> +#include "../../implementation/logging/include/logger.hpp" + +#include <gtest/gtest.h> + +#include "subscribe_notify_test_globals.hpp" + +class subscribe_notify_test_one_event_two_eventgroups_client { +public: + subscribe_notify_test_one_event_two_eventgroups_client( + struct subscribe_notify_test::service_info _info, bool _use_tcp) : + app_( + vsomeip::runtime::get()->create_application( + "subscribe_notify_test_client")), + info_(_info), + use_tcp_(_use_tcp), + wait_availability_(true), + wait_set_value_(true), + wait_shutdown_response_(true), + wait_events_(true), + run_thread_(std::bind(&subscribe_notify_test_one_event_two_eventgroups_client::run, this)) { + } + ~subscribe_notify_test_one_event_two_eventgroups_client() { + run_thread_.join(); + } + + bool init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind( + &subscribe_notify_test_one_event_two_eventgroups_client::on_state, + this, std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind( + &subscribe_notify_test_one_event_two_eventgroups_client::on_message, + this, std::placeholders::_1)); + + app_->register_availability_handler(info_.service_id, info_.instance_id, + std::bind( + &subscribe_notify_test_one_event_two_eventgroups_client::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + std::set<vsomeip::eventgroup_t> its_groups; + // the service offers three events in two eventgroups + // one of the events is in both eventgroups (info_.event_id + 2) + its_groups.insert(info_.eventgroup_id); + app_->request_event(info_.service_id, info_.instance_id, info_.event_id, its_groups, true); + app_->request_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 2), its_groups, true); + its_groups.erase(info_.eventgroup_id); + its_groups.insert(static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id +1)); + app_->request_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id+1), its_groups, true); + app_->request_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id+2), its_groups, true); + + + + return true; + } + + void start() { + app_->start(); + } + + void stop() { + app_->clear_all_handler(); + app_->unsubscribe(info_.service_id, info_.instance_id, info_.eventgroup_id); + app_->unsubscribe(info_.service_id, info_.instance_id, static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id+1)); + app_->release_event(info_.service_id, info_.instance_id, info_.event_id); + app_->release_event(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id+1)); + app_->release_event(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id+2)); + app_->release_service(info_.service_id, info_.instance_id); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(info_.service_id, info_.instance_id); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, + bool _is_available) { + VSOMEIP_DEBUG << "Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service + << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + if (_service == info_.service_id && _instance == info_.instance_id && _is_available) { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + wait_availability_ = false; + availability_condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_response) { + std::stringstream its_message; + its_message << "Received a message [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_instance() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_method() << "] from Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_session() + << "] = "; + std::shared_ptr<vsomeip::payload> its_payload = + _response->get_payload(); + its_message << "(" << std::dec << its_payload->get_length() << ") "; + for (uint32_t i = 0; i < its_payload->get_length(); ++i) + its_message << std::hex << std::setw(2) << std::setfill('0') + << (int) its_payload->get_data()[i] << " "; + VSOMEIP_DEBUG << its_message.str(); + ASSERT_EQ(info_.service_id, _response->get_service()); + + if (_response->get_method() == info_.method_id + || _response->get_method() == subscribe_notify_test::shutdown_method_id) { + ASSERT_EQ(vsomeip::message_type_e::MT_RESPONSE, _response->get_message_type()); + ASSERT_EQ(vsomeip::return_code_e::E_OK, _response->get_return_code()); + std::lock_guard<std::mutex> its_lock(shutdown_response_mutex_); + wait_shutdown_response_ = false; + shutdown_response_condition_.notify_one(); + } else if (_response->get_method() == subscribe_notify_test::set_method_id) { + std::lock_guard<std::mutex> its_lock(set_value_mutex_); + wait_set_value_ = false; + set_value_condition_.notify_one(); + } else if (_response->get_method() >= info_.event_id + && _response->get_method() <= static_cast<vsomeip::event_t>(info_.event_id + 3)) { + std::lock_guard<std::mutex> its_lock(events_mutex_); + received_events_.push_back(_response->get_payload()); + number_received_events_[_response->get_method()]++; + events_condition_.notify_one(); + } else { + ADD_FAILURE() << "Received unknown method id: " << std::setw(4) + << std::setfill('0') << std::hex << _response->get_method(); + } + + } + + void set_field_at_service(vsomeip::byte_t _value) { + std::shared_ptr<vsomeip::runtime> its_runtime = vsomeip::runtime::get(); + std::shared_ptr<vsomeip::message> its_request = its_runtime->create_request(false); + its_request->set_service(info_.service_id); + its_request->set_instance(info_.instance_id); + its_request->set_method(subscribe_notify_test::set_method_id); + its_request->set_reliable(use_tcp_); + std::shared_ptr<vsomeip::payload> its_payload = its_runtime->create_payload(&_value, sizeof(_value)); + its_request->set_payload(its_payload); + app_->send(its_request); + } + + void call_method_at_service(vsomeip::method_t _method) { + std::shared_ptr<vsomeip::runtime> its_runtime = vsomeip::runtime::get(); + std::shared_ptr<vsomeip::message> its_request = its_runtime->create_request(false); + its_request->set_service(info_.service_id); + its_request->set_instance(info_.instance_id); + its_request->set_method(_method); + its_request->set_reliable(use_tcp_); + app_->send(its_request); + } + + void wait_on_condition(std::unique_lock<std::mutex>&& _lock, bool *_predicate, std::condition_variable&& _condition) { + while (*_predicate) { + _condition.wait(_lock); + } + *_predicate = true; + } + + void subscribe_at_service() { + // subscribe to both eventgroups + app_->subscribe(info_.service_id, info_.instance_id, info_.eventgroup_id); + app_->subscribe(info_.service_id, info_.instance_id, static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id+1)); + } + + void unsubscribe_at_service() { + app_->unsubscribe(info_.service_id, info_.instance_id, info_.eventgroup_id); + app_->unsubscribe(info_.service_id, info_.instance_id, static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id+1)); + } + + void wait_for_events(std::unique_lock<std::mutex>&& _lock, + std::uint32_t _expected_number_received_events, + std::condition_variable&& _condition) { + while (wait_events_ && + received_events_.size() != _expected_number_received_events) { + _condition.wait(_lock); + } + ASSERT_EQ(size_t(_expected_number_received_events), received_events_.size()); + } + + void check_received_events_payload(vsomeip::byte_t _value) { + for (const auto &p : received_events_) { + ASSERT_EQ(vsomeip::length_t(1), p->get_length()); + ASSERT_EQ(vsomeip::byte_t(_value), *p->get_data()); + } + received_events_.clear(); + } + + void check_received_events_number(std::set<std::pair<vsomeip::event_t, std::uint32_t>> _expected) { + for (const auto &e : _expected) { + auto event = number_received_events_.find(e.first); + ASSERT_NE(number_received_events_.end(), event); + ASSERT_EQ(e.second, event->second); + } + number_received_events_.clear(); + } + + void run() { + std::unique_lock<std::mutex> its_availability_lock(availability_mutex_); + wait_on_condition(std::move(its_availability_lock), &wait_availability_, std::move(availability_condition_)); + // service is available now + + for (int i = 0; i < 3; i++) { + // set value + set_field_at_service(0x1); + std::unique_lock<std::mutex> its_set_value_lock(set_value_mutex_); + wait_on_condition(std::move(its_set_value_lock), &wait_set_value_, std::move(set_value_condition_)); + + // subscribe + std::unique_lock<std::mutex> its_events_lock(events_mutex_); + subscribe_at_service(); + wait_for_events(std::move(its_events_lock), 4, std::move(events_condition_)); + check_received_events_payload(0x1); + + std::set<std::pair<vsomeip::event_t, std::uint32_t>> its_expected; + its_expected.insert({info_.event_id, 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+1), 1}); + // Initial event for the event which is member of both eventgroups has to be sent twice + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+2), 2}); + + check_received_events_number(its_expected); + its_expected.clear(); + + // set value again + set_field_at_service(0x2); + wait_on_condition(std::move(its_set_value_lock), &wait_set_value_, std::move(set_value_condition_)); + + wait_for_events(std::move(its_events_lock), 3, std::move(events_condition_)); + check_received_events_payload(0x2); + its_expected.insert({info_.event_id, 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+1), 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+2), 1}); + + check_received_events_number(its_expected); + its_expected.clear(); + + + // set value again + set_field_at_service(0x3); + wait_on_condition(std::move(its_set_value_lock), &wait_set_value_, std::move(set_value_condition_)); + wait_for_events(std::move(its_events_lock), 3, std::move(events_condition_)); + check_received_events_payload(0x3); + its_expected.insert({info_.event_id, 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+1), 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+2), 1}); + check_received_events_number(its_expected); + + unsubscribe_at_service(); + // sleep some time to ensure the unsubscription was processed by the + // remote routing_manager before setting the field again in the next + // loop. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + std::unique_lock<std::mutex> its_shutdown_lock(shutdown_response_mutex_); + call_method_at_service(subscribe_notify_test::shutdown_method_id); + wait_on_condition(std::move(its_shutdown_lock), &wait_shutdown_response_, std::move(shutdown_response_condition_)); + stop(); + } + +private: + std::shared_ptr<vsomeip::application> app_; + struct subscribe_notify_test::service_info info_; + bool use_tcp_; + + bool wait_availability_; + std::mutex availability_mutex_; + std::condition_variable availability_condition_; + + bool wait_set_value_; + std::mutex set_value_mutex_; + std::condition_variable set_value_condition_; + + bool wait_shutdown_response_; + std::mutex shutdown_response_mutex_; + std::condition_variable shutdown_response_condition_; + + bool wait_events_; + std::mutex events_mutex_; + std::condition_variable events_condition_; + + std::vector<std::shared_ptr<vsomeip::payload>> received_events_; + std::map<vsomeip::event_t, std::uint32_t> number_received_events_; + std::thread run_thread_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + subscribe_notify_test_one_event_two_eventgroups_client *its_client_ptr(nullptr); + void handle_signal(int _signal) { + if (its_client_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_client_ptr->stop(); + } +#endif + +static bool use_tcp; + +TEST(someip_subscribe_notify_test_one_event_two_eventgroups, subscribe_to_service) +{ + subscribe_notify_test_one_event_two_eventgroups_client its_client( + subscribe_notify_test::service_info_subscriber_based_notification, use_tcp); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_client_ptr = &its_client; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_client.init()) { + its_client.start(); + } +} + +#ifndef _WIN32 +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a subscription type, like: " << argv[0] << " UDP" << std::endl; + std::cerr << "Valid subscription types include:" << std::endl; + std::cerr << "[UDP, TCP]" << std::endl; + return 1; + } + + if(std::string("TCP") == std::string(argv[1])) { + use_tcp = true; + } else if(std::string("UDP") == std::string(argv[1])) { + use_tcp = false; + } else { + std::cerr << "Wrong subscription type passed, exiting" << std::endl; + std::cerr << "Valid subscription types include:" << std::endl; + std::cerr << "[UDP, TCP]" << std::endl; + return 1; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh new file mode 100755 index 0000000..c983369 --- /dev/null +++ b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# Copyright (C) 2015-2017 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/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ]; then + echo "Please pass a json file and a subscription type to this script." + echo "Valid subscription types include:" + echo " [UDP, TCP]" + echo "For example: $0 UDP subscribe_notify_test_one_event_two_eventgroups_master.json" + exit 1 +fi + +# replace master with slave to be able display the correct json file to be used +# with the slave script +MASTER_JSON_FILE=$2 +if [ $1 == "UDP" ]; then + SLAVE_JSON_FILE=${MASTER_JSON_FILE/master/udp_slave} +elif [ $1 == "TCP" ]; then + SLAVE_JSON_FILE=${MASTER_JSON_FILE/master/tcp_slave} +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$2 +# start daemon +../daemon/./vsomeipd & +PID_VSOMEIPD=$! + +# Start the client +./subscribe_notify_test_one_event_two_eventgroups_client $1 & +PID_CLIENT=$! +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting subscribe_notify_test_slave_starter.sh on slave LXC with parameters $SLAVE_JSON_FILE" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip/test; ./subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh $SLAVE_JSON_FILE\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker run --name sntms --cap-add NET_ADMIN $DOCKER_IMAGE sh -c "route add -net 224.0.0.0/4 dev eth0 && cd $DOCKER_TESTS && ./subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh $SLAVE_JSON_FILE" & +else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh $SLAVE_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** subscribe_notify_test_diff_client_ids_diff_ports_master.json and +** subscribe_notify_test_diff_client_ids_diff_ports_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# wait until client exits successfully +wait $PID_CLIENT || FAIL=$(($FAIL+1)) + + +# kill daemon +kill $PID_VSOMEIPD +wait $PID_VSOMEIPD || FAIL=$(($FAIL+1)) + +if [ ! -z "$USE_DOCKER" ]; then + docker stop sntms + docker rm sntms +fi + +echo "" + +# Check if both exited successfully +if [ $FAIL -eq 0 ]; then + exit 0 +else + exit 1 +fi diff --git a/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_service.cpp b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_service.cpp new file mode 100644 index 0000000..1d7b0c3 --- /dev/null +++ b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_service.cpp @@ -0,0 +1,212 @@ +// Copyright (C) 2014-2017 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/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <atomic> + +#include <gtest/gtest.h> +#include "../../implementation/logging/include/logger.hpp" + +#include <vsomeip/vsomeip.hpp> + +#include "subscribe_notify_test_globals.hpp" + +class subscribe_notify_test_one_event_two_eventgroups_service { +public: + subscribe_notify_test_one_event_two_eventgroups_service(subscribe_notify_test::service_info _info) : + app_(vsomeip::runtime::get()->create_application()), + wait_for_shutdown_(true), + info_(_info), + notify_thread_(std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::wait_for_shutdown, this)) { + } + + ~subscribe_notify_test_one_event_two_eventgroups_service() { + notify_thread_.join(); + } + + bool init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_state_handler( + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + info_.service_id, + info_.instance_id, + subscribe_notify_test::set_method_id, + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_set, this, + std::placeholders::_1)); + + app_->register_message_handler( + info_.service_id, + info_.instance_id, + info_.method_id, + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler( + info_.service_id, + info_.instance_id, + subscribe_notify_test::shutdown_method_id, + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_shutdown, this, + std::placeholders::_1)); + + std::set<vsomeip::eventgroup_t> its_groups; + // the service offers three events in two eventgroups + // one of the events is in both eventgroups + its_groups.insert(info_.eventgroup_id); + app_->offer_event(info_.service_id, info_.instance_id, + info_.event_id, its_groups, true); + app_->offer_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 2), its_groups, true); + its_groups.erase(info_.eventgroup_id); + its_groups.insert(static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id + 1)); + app_->offer_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 1), its_groups, true); + app_->offer_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 2), its_groups, true); + payload_ = vsomeip::runtime::get()->create_payload(); + + return true; + } + + void start() { + app_->start(); + } + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + /* + * Handle signal to shutdown + */ + void stop() { + { + std::lock_guard<std::mutex> its_lock(shutdown_mutex_); + wait_for_shutdown_ = false; + shutdown_condition_.notify_one(); + } + app_->clear_all_handler(); + stop_offer(); + notify_thread_.join(); + app_->stop(); + } +#endif + + void offer() { + app_->offer_service(info_.service_id, info_.instance_id); + } + + void stop_offer() { + app_->stop_offer_service(info_.service_id, info_.instance_id); + } + + void on_state(vsomeip::state_type_e _state) { + std::cout << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered.") << std::endl; + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + offer(); + } + } + + void on_shutdown(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_message); + its_response->set_payload(payload_); + app_->send(its_response, true); + { + std::lock_guard<std::mutex> its_lock(shutdown_mutex_); + wait_for_shutdown_ = false; + shutdown_condition_.notify_one(); + } + } + + void on_set(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_message); + payload_ = _message->get_payload(); + its_response->set_payload(payload_); + app_->send(its_response, true); + app_->notify(info_.service_id, info_.instance_id, info_.event_id, payload_); + app_->notify(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id + 1), payload_); + app_->notify(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id + 2), payload_); + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message),true); + } + + void wait_for_shutdown() { + { + std::unique_lock<std::mutex> its_lock(shutdown_mutex_); + while (wait_for_shutdown_) { + shutdown_condition_.wait(its_lock); + } + wait_for_shutdown_= true; + } + + app_->clear_all_handler(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + stop_offer(); + app_->stop(); + } + +private: + std::shared_ptr<vsomeip::application> app_; + + std::mutex shutdown_mutex_; + bool wait_for_shutdown_; + std::condition_variable shutdown_condition_; + + std::shared_ptr<vsomeip::payload> payload_; + + subscribe_notify_test::service_info info_; + + std::thread notify_thread_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + subscribe_notify_test_one_event_two_eventgroups_service *its_service_ptr(nullptr); + void handle_signal(int _signal) { + if (its_service_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_service_ptr->stop(); + } +#endif + + +TEST(someip_subscribe_notify_test_one_event_two_eventgroups, wait_for_attribute_set) +{ + subscribe_notify_test_one_event_two_eventgroups_service its_service( + subscribe_notify_test::service_info_subscriber_based_notification); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_service_ptr = &its_service; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_service.init()) { + its_service.start(); + } +} + +#ifndef _WIN32 +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif + + diff --git a/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh new file mode 100755 index 0000000..8138612 --- /dev/null +++ b/test/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (C) 2015-2017 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/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ]; then + echo "Please pass a json file to this script." + echo "For example: $0 subscribe_notify_test_one_event_two_eventgroups_slave.json" + exit 1 +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +# start daemon +../daemon/./vsomeipd & +PID_VSOMEIPD=$! + +# Start the services +./subscribe_notify_test_one_event_two_eventgroups_service & +PID_SERVICE=$! + +# wait until service exits successfully +wait $PID_SERVICE || FAIL=$(($FAIL+1)) + + +# kill daemon +kill $PID_VSOMEIPD +wait $PID_VSOMEIPD || FAIL=$(($FAIL+1)) + +echo "" + +# Check if both exited successfully +if [ $FAIL -eq 0 ]; then + exit 0 +else + exit 1 +fi diff --git a/test/subscribe_notify_tests/subscribe_notify_test_service.cpp b/test/subscribe_notify_tests/subscribe_notify_test_service.cpp index bc2eedd..b49831c 100644 --- a/test/subscribe_notify_tests/subscribe_notify_test_service.cpp +++ b/test/subscribe_notify_tests/subscribe_notify_test_service.cpp @@ -11,6 +11,7 @@ #include <thread> #include <map> #include <algorithm> +#include <atomic> #include <gtest/gtest.h> @@ -36,7 +37,9 @@ public: wait_for_stop_(true), stop_thread_(std::bind(&subscribe_notify_test_service::wait_for_stop, this)), wait_for_notify_(true), - notify_thread_(std::bind(&subscribe_notify_test_service::notify, this)) { + notify_thread_(std::bind(&subscribe_notify_test_service::notify, this)), + subscription_state_handler_called_(0), + subscription_error_occured_(false) { if (!app_->init()) { ADD_FAILURE() << "Couldn't initialize application"; return; @@ -73,6 +76,12 @@ public: std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + auto handler = std::bind(&subscribe_notify_test_service::on_subscription_state_change, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); + app_->register_subscription_status_handler(i.service_id, i.instance_id, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + + std::set<vsomeip::eventgroup_t> its_eventgroups; its_eventgroups.insert(i.eventgroup_id); app_->request_event(i.service_id, i.instance_id, i.event_id, its_eventgroups, true); @@ -143,6 +152,23 @@ public: } } + void on_subscription_state_change(const vsomeip::service_t _service, const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, const vsomeip::event_t _event, const uint16_t _error) { + (void)_service; + (void)_instance; + (void)_eventgroup; + (void)_event; + + if (!_error) { + subscription_state_handler_called_++; + } else { + subscription_error_occured_ = true; + VSOMEIP_WARNING << std::hex << app_->get_client() + << " : on_subscription_state_change: for service " << std::hex + << _service << " received a subscription error!"; + } + } + bool on_subscription(vsomeip::client_t _client, bool _subscribed) { static bool notified(false); if (_subscribed) { @@ -285,12 +311,14 @@ public: VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex << service_info_.service_id << "] Subscribing"; // subscribe to events of other services + uint32_t subscribe_count = 0; for(const subscribe_notify_test::service_info& i: service_infos_) { if ((i.service_id == service_info_.service_id && i.instance_id == service_info_.instance_id) || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { continue; } + ++subscribe_count; app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, vsomeip::DEFAULT_MAJOR, subscription_type_); VSOMEIP_DEBUG << "[" << std::hex << service_info_.service_id @@ -303,6 +331,18 @@ public: while (wait_until_notified_from_other_services_) { condition_.wait(its_lock); } + + // It is possible that we run in the case a subscription is NACKED + // due to TCP endpoint not completely connected when subscription + // is processed in the server - due to resubscribing the error handler + // count may differ from expected value, but its not a real but as + // the subscription takes places anyways and all events will be received. + if (!subscription_error_occured_) { + ASSERT_EQ(subscribe_count, subscription_state_handler_called_); + } else { + VSOMEIP_WARNING << "Subscription state handler check skipped: CallCount=" + << std::dec << subscription_state_handler_called_; + } } void notify() { @@ -358,6 +398,23 @@ public: condition_.notify_one(); } + stop_offer(); + + // ensure that the service which hosts the routing doesn't exit to early + if (app_->is_routing()) { + for (const auto& i : service_infos_) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + while (app_->is_available(i.service_id, i.instance_id, + vsomeip::ANY_MAJOR, vsomeip::ANY_MINOR)) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + } + std::this_thread::sleep_for(std::chrono::seconds(1)); for(const auto& i : service_infos_) { if ((i.service_id == service_info_.service_id @@ -365,6 +422,8 @@ public: || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { continue; } + app_->register_subscription_status_handler(i.service_id, i.instance_id, + i.eventgroup_id, vsomeip::ANY_EVENT, nullptr); app_->unsubscribe(i.service_id, i.instance_id, i.eventgroup_id); app_->release_event(i.service_id, i.instance_id, i.event_id); app_->release_service(i.service_id, i.instance_id); @@ -398,6 +457,8 @@ private: std::mutex notify_mutex_; std::condition_variable notify_condition_; std::thread notify_thread_; + std::atomic<uint32_t> subscription_state_handler_called_; + std::atomic<bool> subscription_error_occured_; }; static int service_number; diff --git a/tools/vsomeip_ctrl.cpp b/tools/vsomeip_ctrl.cpp index 9dde00a..1f64c2f 100644 --- a/tools/vsomeip_ctrl.cpp +++ b/tools/vsomeip_ctrl.cpp @@ -375,8 +375,10 @@ int main(int argc, char** argv) { for (unsigned int i = 0; i < message.length(); i += 2) { vsomeip::byte_t its_byte; try { - its_byte = static_cast<vsomeip::byte_t>(std::stoul( - message.substr(i, 2), 0, 16)); + std::uint64_t tmp = std::stoul(message.substr(i, 2), 0, 16); + tmp = (tmp > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : tmp; + its_byte = static_cast<vsomeip::byte_t>(tmp); } catch (std::invalid_argument &e) { std::cerr << e.what() << ": Couldn't convert '" << message.substr(i, 2) << "' to hex, exiting: " @@ -404,8 +406,11 @@ int main(int argc, char** argv) { for (unsigned int i = 0; i < instance_str.length(); i += 2) { vsomeip::byte_t its_byte; try { - its_byte = static_cast<vsomeip::byte_t>(std::stoul( - instance_str.substr(i, 2), 0, 16)); + std::uint64_t tmp = std::stoul(instance_str.substr(i, 2), 0, 16); + tmp = (tmp > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : tmp; + its_byte = static_cast<vsomeip::byte_t>(tmp); + its_byte = static_cast<vsomeip::byte_t>(tmp); } catch (std::invalid_argument &e) { std::cerr << e.what() << ": Couldn't convert '" << instance_str.substr(i, 2) << "' to hex, exiting: " @@ -433,4 +438,5 @@ int main(int argc, char** argv) { } vsomeip_ctrl::vsomeip_sender sender(use_tcp, user_message, instance); + return EXIT_SUCCESS; } |