diff --git a/CHANGES b/CHANGES index 3e6bc6e35..65d6d86c8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,25 @@ Changes ======= +v2.10.9 +- Improve handling of service discovery messages with entries + referencing too many options. +- Prevent sending of duplicate remote subscriptions to local clients + if the local client processes incoming subscriptions too slow. +- Remote (un)subscriptions to the same eventgroup are now queued in + the routing manager until the local client has processed the + previous (un)subscription for this eventgroup. +- Introduce new json configuration parameter 'diagnosis_mask' to + control the number of bits in the client ID used for the diagnosis + address. This can be used to enable more than 254 concurrent clients + on a node. For more information see the vsomeipUserGuide. +- If the service discovery is enabled it is is only started if a + matching multicast route for the configured service discovery + multicast group is present in the system. This applies only to + Linux. +- Rework security configuration: + - Allow policy specifications without client specification. + - Allow policies to be specified for ranges of uids/gids. + For more information see the vsomeipUserGuide. v2.10.8 - Change dispatching of availability states in case an availability diff --git a/CMakeLists.txt b/CMakeLists.txt index 281530248..a9d9f4c1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project (vsomeip) set (VSOMEIP_MAJOR_VERSION 2) set (VSOMEIP_MINOR_VERSION 10) -set (VSOMEIP_PATCH_VERSION 8) +set (VSOMEIP_PATCH_VERSION 9) 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) @@ -39,6 +39,14 @@ foreach (p LIB BIN INCLUDE CMAKE) endforeach () ################################################################################################### +# Set a default build type if none was specified +set(default_build_type "RelWithDebInfo") +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() # OS if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") @@ -145,7 +153,7 @@ if (MSVC) link_directories(${Boost_LIBRARY_DIR_DEBUG}) ADD_DEFINITIONS( -DBOOST_ALL_DYN_LINK ) else() - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${OS} ${OS_CXX_FLAGS} -DBOOST_LOG_DYN_LINK -g ${OPTIMIZE} -std=c++0x ${NO_DEPRECATED} ${EXPORTSYMBOLS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${OS} ${OS_CXX_FLAGS} -DBOOST_LOG_DYN_LINK -g ${OPTIMIZE} -std=c++11 ${NO_DEPRECATED} ${EXPORTSYMBOLS}") set(USE_RT "rt") endif() diff --git a/documentation/vsomeipUserGuide b/documentation/vsomeipUserGuide index 395fdd573..9996063d4 100644 --- a/documentation/vsomeipUserGuide +++ b/documentation/vsomeipUserGuide @@ -291,8 +291,20 @@ The netmask to specify the subnet of the host system. + * 'diagnosis' + -The diagnosis address (byte) that will be used to build client identifiers. +The diagnosis address (byte) that will be used to build client identifiers. The +diagnosis address is assigned to the most significant byte in all client +identifiers if not specified otherwise (for example through a predefined client +ID). + +* 'diagnosis_mask' ++ +The diagnosis mask (2 byte) is used to control the amount of bits used for the +diagnosis address in client identifiers. The default value is `0xFF00` meaning +the most significant byte of the client ID is reserved for the diagnosis +address. Setting the mask to `0xFE00` allows to only use the 7 most +significant bits of the client ID as a diagnosis address. This can be used to +increase the maximum amount of concurrent active clients on an ECU. + * 'network' + Network identifier used to support multiple routing managers on one host. This @@ -330,16 +342,16 @@ _true, false_). + ** 'version' + -Configures logging of the vSomeIP version +Configures logging of the vsomeip version + *** 'enable' + -Enable or disable cyclic logging of vSomeIP version, defaults to true (valid +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. +Configures interval in seconds to log the vsomeip version. Default value is 10. + ** 'memory_log_interval' + @@ -742,7 +754,7 @@ reduced and starts to grow dynamically again. * `internal_services` (optional array) + Specifies service/instance ranges for pure internal service-instances. -This information is used by vSomeIP to avoid sending Find-Service messages +This information is used by vsomeip to avoid sending Find-Service messages via the Service-Discovery when a client is requesting a not available service- instance. Its can either be done on service/instance level or on service level only which then includes all instance from 0x0000-0xffff. @@ -974,15 +986,15 @@ Multiple addresses can be configuered. Security -------- -vSomeIP has a security implementation based on UNIX credentials. +vsomeip has a security implementation based on UNIX credentials. If activated every local connection is authenticated during connect using the standard UNIX credential passing mechanism. During authentification a client transfers its client identifier together with its credentials (UID / GID) to the server which is then matched against the configuration. If received credentials don't match the policy the socket will be immediately closed by the server and an message is logged. -If accepted the client identifier is bound to the receiving socket and can therefore be used to do further security checks on incoming messages (vSomeIP messages as well as internal commands). +If accepted the client identifier is bound to the receiving socket and can therefore be used to do further security checks on incoming messages (vsomeip messages as well as internal commands). In general clients can be configured to be allowed/denied to request (means communicate with) and offer different service instances. -Every incoming vSomeIP message (request/response/notifcation) as well as offer service requests or local subscriptions are then checked against the policy. -If an incoming vSomeIP message or another operation (e.g. offer/subscribe) violates the configured policies it is skipped and a message is logged. +Every incoming vsomeip message (request/response/notifcation) as well as offer service requests or local subscriptions are then checked against the policy. +If an incoming vsomeip message or another operation (e.g. offer/subscribe) violates the configured policies it is skipped and a message is logged. Furthermore if an application receives informations about other clients/services in the system, it must be received from the authenticated routing manager. This is to avoid malicious applications faking the routing manager and therefore being able to wrongly inform other clients about services running on the system. @@ -993,7 +1005,9 @@ Credential passing is only possible via Unix-Domain-Sockets and therefore only a However if security is activated method calls from remote clients to local services are checked as well which means remote clients needs to be explicitly allowed. Such a policy looks same in case for local clients except the _credentials_ tag can be skipped. -It follows the available configuration switches for the security feature including its functional behavior: +Security configuration +~~~~~~~~~~~~~~~~~~~~~~ +The available configuration switches for the security feature are: // Security * anchor:config-policy[]'security' (optional) @@ -1007,13 +1021,15 @@ Specifies whether security checks are active or not. This includes credentials c ** 'policies' (array) + -Specifies the security policies. Each policy at least needs to specify _client_ and _allow_ / _deny_. +Specifies the security policies. Each policy at least needs to specify _allow_ or _deny_. -*** 'client' +*** 'client' (optional) + Specifies a client for which a security policy will be applied (valid value: A valid client identifier in hex: e.g. _0x1234_). It is also possible to specify a client identifier range to easily apply a policy to a set of clients. A usecase is e.g. to allow a set of remote clients communicate with local services offered remote. ++ +No client specification equals to any client (_0xFFFF_). Such policies are applied if a client has no specific policy. **** 'first' + @@ -1042,6 +1058,20 @@ As a wildcard "any" can be used. Specifies the LINUX group id of the above client(s) as decimal number. As a wildcard "any" can be used. +**** 'allow/deny' (optional) ++ +Specifies whether the LINUX user and group ids are allowed or denied for the policy. + +***** 'uid' (array) ++ +Specifies a list of LINUX user ids. These may either be specified as decimal numbers or as ranges. Ranges +are specified by the first and the last valid id (see example below). + +***** 'gid' (array) ++ +Specifies a list of LINUX group ids. These may either be specified as decimal numbers or as ranges. Ranges +are specified by the first and the last valid id (see example below). + *** 'allow/deny' + This tag specifies either _allow_ or _deny_ depending on white- or blacklisting is needed. Specifing _allow_ and _deny_ entries in one policy is therefore not allowed. @@ -1072,15 +1102,75 @@ Specifies a service for the _offers_. + Specifies a instance for the _offers_ -In the `config/` folder are some vSomeIP configuration files to run the vSomeIP +Security configuration example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +[source, bash] +---- +... +"security" : +{ + ... + "policies" : + [ + { + ... + "credentials" : + { + "uid" : "44", + "gid" : "any" + }, + "allow" : + [ + "requests" : + [ + { + "service" : "0x6731", + "instance" : "0x0001" + } + ] + ] + }, + { + "credentials" : + { + "deny" : + [ + { + "uid" : [ "1000", { "first" : "1002", "last" : "max" }], + "gid" : [ "0", { "first" : "100", "last" : "243" }, "300"] + }, + { + "uid" : "55", + "gid" : "55" + } + ] + }, + "allow" : + [ + "requests" : + [ + { + "service" : "0x6732", + "instance" : "0x0001" + } + ] + ] + } + ] +} +---- + +The config/ folder contains some addition vsomeip configuration files to run the vsomeip examples with activated security checks. Additionally there's a security test in the `test/` subfolder which can be used for further reference. + -They give a basic overview how to use the security related configuration tags described in this chapter to run a simple request/response or subscribe/notify example locally or over remote. +They give a basic overview how to use the security related configuration tags described +in this chapter to run a simple request/response or subscribe/notify example locally or +remotely. Audit Mode ~~~~~~~~~~ -vSomeIP's security implementation can be put in a so called 'Audit Mode' where +vsomeip's security implementation can be put in a so called 'Audit Mode' where all security violations will be logged but allowed. This mode can be used to build a security configuration. @@ -1113,7 +1203,7 @@ DIAGNOSIS_ADDRESS when compiling vsomeip. vsomeip will use the diagnosis address as the high byte and enumerate the connecting applications within the low byte of the client identifier. -Autoconfiguration of client identifiers isn't meant to be used together with vSomeIP Security. +Autoconfiguration of client identifiers isn't meant to be used together with vsomeip Security. Every client running locally needs to have at least its own credentials configured when security is activated to ensure the credential checks can pass. Practically that means if a client requests its identifier over the autoconfiguration for which no credentials are configured (at least it isn't known which client identifier is used beforehand) it is impossible for that client to establish a connection to a server endpoint. However if the credentials for all clients are same it's possible to configure them for the overall (or DIAGNOSIS_ADDRESS) client identifier range to mix autoconfiguration together with activated security. diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp index 16ebd337d..142339299 100644 --- a/implementation/configuration/include/configuration.hpp +++ b/implementation/configuration/include/configuration.hpp @@ -43,6 +43,7 @@ class configuration { virtual const boost::asio::ip::address & get_unicast_address() const = 0; virtual unsigned short get_diagnosis_address() const = 0; + virtual std::uint16_t get_diagnosis_mask() const = 0; virtual bool is_v4() const = 0; virtual bool is_v6() const = 0; diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp index 93f7ebff2..d3b7572cc 100644 --- a/implementation/configuration/include/configuration_impl.hpp +++ b/implementation/configuration/include/configuration_impl.hpp @@ -60,6 +60,7 @@ class configuration_impl: VSOMEIP_EXPORT const boost::asio::ip::address & get_unicast_address() const; VSOMEIP_EXPORT unsigned short get_diagnosis_address() const; + VSOMEIP_EXPORT std::uint16_t get_diagnosis_mask() const; VSOMEIP_EXPORT bool is_v4() const; VSOMEIP_EXPORT bool is_v6() const; @@ -230,6 +231,8 @@ class configuration_impl: void load_selective_broadcasts_support(const element &_element); void load_policies(const element &_element); void load_policy(const boost::property_tree::ptree &_tree); + void load_credential(const boost::property_tree::ptree &_tree, ids_t &_ids); + void load_ranges(const boost::property_tree::ptree &_tree, ranges_t &_range); void load_debounce(const element &_element); void load_service_debounce(const boost::property_tree::ptree &_tree); @@ -279,6 +282,7 @@ class configuration_impl: // Configuration data boost::asio::ip::address unicast_; unsigned short diagnosis_; + std::uint16_t diagnosis_mask_; bool has_console_log_; bool has_file_log_; @@ -335,6 +339,7 @@ class configuration_impl: ET_NETWORK, ET_UNICAST, ET_DIAGNOSIS, + ET_DIAGNOSIS_MASK, ET_LOGGING_CONSOLE, ET_LOGGING_FILE, ET_LOGGING_DLT, @@ -362,7 +367,7 @@ class configuration_impl: ET_ENDPOINT_QUEUE_LIMITS, ET_ENDPOINT_QUEUE_LIMIT_EXTERNAL, ET_ENDPOINT_QUEUE_LIMIT_LOCAL, - ET_MAX = 30 + ET_MAX = 31 }; bool is_configured_[ET_MAX]; diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in index 601209218..e2f3da3a5 100644 --- a/implementation/configuration/include/internal.hpp.in +++ b/implementation/configuration/include/internal.hpp.in @@ -103,6 +103,7 @@ #define VSOMEIP_ID_REQUEST 0x1E #define VSOMEIP_OFFERED_SERVICES_REQUEST 0x1F #define VSOMEIP_OFFERED_SERVICES_RESPONSE 0x20 +#define VSOMEIP_UNSUBSCRIBE_ACK 0x21 #define VSOMEIP_OFFER_SERVICE_COMMAND_SIZE 16 #define VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE 17 @@ -111,7 +112,8 @@ #define VSOMEIP_SUBSCRIBE_COMMAND_SIZE 19 #define VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE 19 #define VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE 19 -#define VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE 16 +#define VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE 17 +#define VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE 15 #define VSOMEIP_REGISTER_EVENT_COMMAND_SIZE 15 #define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 14 #define VSOMEIP_ID_RESPONSE_COMMAND_SIZE 12 @@ -128,8 +130,6 @@ #define VSOMEIP_DEFAULT_SHM_PERMISSION 0666 #define VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS 0000 -#define VSOMEIP_MAX_CLIENTS 255 - #define VSOMEIP_ROUTING_READY_MESSAGE "@VSOMEIP_ROUTING_READY_MESSAGE@" namespace vsomeip { @@ -168,12 +168,11 @@ struct configuration_data_t { pid_t pid_; #endif unsigned short client_base_; - - unsigned short used_client_ids_[VSOMEIP_MAX_CLIENTS]; + unsigned short max_clients_; int max_used_client_ids_index_; - unsigned char max_assigned_client_id_low_byte_; - + unsigned short max_assigned_client_id_without_diagnosis_; unsigned short routing_manager_host_; + // array of used client ids here, pointer to it is kept in utility class }; const std::uint32_t MESSAGE_SIZE_UNLIMITED = (std::numeric_limits::max)(); diff --git a/implementation/configuration/include/policy.hpp b/implementation/configuration/include/policy.hpp index 89e8a9637..9132a4dd7 100644 --- a/implementation/configuration/include/policy.hpp +++ b/implementation/configuration/include/policy.hpp @@ -7,26 +7,25 @@ #define VSOMEIP_CFG_POLICY_HPP #include +#include #include namespace vsomeip { namespace cfg { +typedef std::set> ranges_t; +typedef std::set> ids_t; + struct policy { - policy() : - uid_(0), is_uid_set_(false), gid_(0), is_gid_set_(false) { - } - - std::set> allowed_services_; - std::set> allowed_offers_; - std::set> denied_services_; - std::set> denied_offers_; - std::uint32_t uid_; - bool is_uid_set_; - std::uint32_t gid_; - bool is_gid_set_; - bool allow_; + policy() : allow_who_(false), allow_what_(false) {}; + + ids_t ids_; + bool allow_who_; + + std::set> services_; + std::set> offers_; + bool allow_what_; }; } // namespace cfg diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp index 178481c5b..0b3301887 100644 --- a/implementation/configuration/src/configuration_impl.cpp +++ b/implementation/configuration/src/configuration_impl.cpp @@ -43,6 +43,7 @@ configuration_impl::configuration_impl() is_loaded_(false), is_logging_loaded_(false), diagnosis_(VSOMEIP_DIAGNOSIS_ADDRESS), + diagnosis_mask_(0xFF00), has_console_log_(true), has_file_log_(false), has_dlt_log_(false), @@ -105,6 +106,7 @@ configuration_impl::configuration_impl(const configuration_impl &_other) unicast_ = _other.unicast_; diagnosis_ = _other.diagnosis_; + diagnosis_mask_ = _other.diagnosis_mask_; has_console_log_ = _other.has_console_log_; has_file_log_ = _other.has_file_log_; @@ -771,6 +773,21 @@ void configuration_impl::load_diagnosis_address(const element &_element) { its_converter >> diagnosis_; is_configured_[ET_DIAGNOSIS] = true; } + std::string its_mask = _element.tree_.get("diagnosis_mask"); + if (is_configured_[ET_DIAGNOSIS_MASK]) { + VSOMEIP_WARNING << "Multiple definitions for diagnosis_mask." + "Ignoring definition from " << _element.name_; + } else { + std::stringstream its_converter; + + if (its_mask.size() > 1 && its_mask[0] == '0' && its_mask[1] == 'x') { + its_converter << std::hex << its_mask; + } else { + its_converter << std::dec << its_mask; + } + its_converter >> diagnosis_mask_; + is_configured_[ET_DIAGNOSIS_MASK] = true; + } } catch (...) { // intentionally left empty } @@ -1634,6 +1651,7 @@ void configuration_impl::load_policies(const element &_element) { void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { client_t client = 0x0; std::shared_ptr policy(std::make_shared()); + bool has_been_inserted(false); bool allow_deny_set(false); for (auto i = _tree.begin(); i != _tree.end(); ++i) { if (i->first == "client") { @@ -1655,16 +1673,13 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { its_converter >> lastClient; } } - if (firstClient < lastClient) { + if (firstClient < lastClient && lastClient != ANY_CLIENT) { uint32_t overrides(0); for (client_t c = firstClient; c <= lastClient; ++c) { if (policies_.find(c) != policies_.end()) { overrides++; } policies_[c] = policy; - if (c == 0xffff) { - break; - } } if (overrides) { VSOMEIP_INFO << std::hex << "Security configuration: " @@ -1672,6 +1687,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { << " - 0x" << lastClient << " overrides policy of " << std::dec << overrides << " clients"; } + has_been_inserted = true; } else { VSOMEIP_WARNING << std::hex << "Security configuration: " << "Client range have to be ascending, \"first\"=0x" @@ -1688,29 +1704,58 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { << "Overriding policy for client 0x" << client << "."; } policies_[client] = policy; + has_been_inserted= true; } } } else if (i->first == "credentials") { + std::pair its_uid_range, its_gid_range; + bool has_uid(false), has_gid(false); for (auto n = i->second.begin(); n != i->second.end(); ++n) { - if (n->first == "uid") { - std::stringstream its_converter; - std::string value = n->second.data(); - if (value != "any") { - its_converter << std::dec << value; - its_converter >> policy->uid_ ; - policy->is_uid_set_ = true; + std::string its_key(n->first); + std::string its_value(n->second.data()); + if (its_key == "uid") { + if (its_value != "any") { + uint32_t its_uid; + std::stringstream its_converter; + its_converter << std::dec << its_value; + its_converter >> its_uid; + std::get<0>(its_uid_range) = its_uid; + std::get<1>(its_uid_range) = its_uid; + } else { + std::get<0>(its_uid_range) = 0; + std::get<1>(its_uid_range) = 0xFFFFFFFF; } - } else if (n->first == "gid") { - std::stringstream its_converter; - std::string value = n->second.data(); - if (value != "any") { - its_converter << std::dec << value; - its_converter >> policy->gid_ ; - policy->is_gid_set_ = true; + has_uid = true; + } else if (its_key == "gid") { + if (its_value != "any") { + uint32_t its_gid; + std::stringstream its_converter; + its_converter << std::dec << its_value; + its_converter >> its_gid; + std::get<0>(its_gid_range) = its_gid; + std::get<1>(its_gid_range) = its_gid; + } else { + std::get<0>(its_gid_range) = 0; + std::get<1>(its_gid_range) = 0xFFFFFFFF; } + has_gid = true; + } else if (its_key == "allow" || its_key == "deny") { + policy->allow_who_ = (its_key == "allow"); + load_credential(n->second, policy->ids_); } } + + if (has_uid && has_gid) { + std::set> its_uids, its_gids; + + its_uids.insert(its_uid_range); + its_gids.insert(its_gid_range); + + policy->allow_who_ = true; + policy->ids_.insert(std::make_pair(its_uids, its_gids)); + } + } else if (i->first == "allow") { if (allow_deny_set) { VSOMEIP_WARNING << "Security configuration: \"allow\" tag overrides " @@ -1718,7 +1763,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { << "Either \"deny\" or \"allow\" is allowed."; } allow_deny_set = true; - policy->allow_ = true; + policy->allow_what_ = true; for (auto l = i->second.begin(); l != i->second.end(); ++l) { if (l->first == "requests") { for (auto n = l->second.begin(); n != l->second.end(); ++n) { @@ -1737,7 +1782,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { } } if (service != 0x0 && instance != 0x0) { - policy->allowed_services_.insert( + policy->services_.insert( std::make_pair(service, instance)); } } @@ -1758,7 +1803,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { } } if (service != 0x0 && instance != 0x0) { - policy->allowed_offers_.insert( + policy->offers_.insert( std::make_pair(service, instance)); } } @@ -1771,7 +1816,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { << "Either \"deny\" or \"allow\" is allowed."; } allow_deny_set = true; - policy->allow_ = false; + policy->allow_what_ = false; for (auto l = i->second.begin(); l != i->second.end(); ++l) { if (l->first == "requests") { for (auto n = l->second.begin(); n != l->second.end(); ++n) { @@ -1790,7 +1835,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { } } if (service != 0x0 && instance != 0x0) { - policy->denied_services_.insert( + policy->services_.insert( std::make_pair(service, instance)); } } @@ -1812,7 +1857,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { } } if (service != 0x0 && instance != 0x0) { - policy->denied_offers_.insert( + policy->offers_.insert( std::make_pair(service, instance)); } } @@ -1820,6 +1865,83 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { } } } + + if (!has_been_inserted) { + policies_[ANY_CLIENT] = policy; + } +} + +void configuration_impl::load_credential( + const boost::property_tree::ptree &_tree, ids_t &_ids) { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + ranges_t its_uid_ranges, its_gid_ranges; + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::string its_key(j->first); + if (its_key == "uid") { + load_ranges(j->second, its_uid_ranges); + } else if (its_key == "gid") { + load_ranges(j->second, its_gid_ranges); + } else { + VSOMEIP_WARNING << "Security configuration: " + << "Malformed credential (contains illegal key \"" + << its_key << "\""; + } + } + + _ids.insert(std::make_pair(its_uid_ranges, its_gid_ranges)); + } +} + +void configuration_impl::load_ranges( + const boost::property_tree::ptree &_tree, ranges_t &_range) { + ranges_t its_ranges; + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + auto its_data = i->second; + if (!its_data.data().empty()) { + uint32_t its_id; + std::stringstream its_converter; + its_converter << std::dec << its_data.data(); + its_converter >> its_id; + + its_ranges.insert(std::make_pair(its_id, its_id)); + } else { + uint32_t its_first, its_last; + bool has_first(false), has_last(false); + for (auto j = its_data.begin(); j != its_data.end(); ++j) { + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "first") { + if (its_value == "max") { + its_first = 0xFFFFFFFF; + } else { + std::stringstream its_converter; + its_converter << std::dec << j->second.data(); + its_converter >> its_first; + } + has_first = true; + } else if (its_key == "last") { + if (its_value == "max") { + its_last = 0xFFFFFFFF; + } else { + std::stringstream its_converter; + its_converter << std::dec << j->second.data(); + its_converter >> its_last; + } + has_last = true; + } else { + VSOMEIP_WARNING << "Security configuration: " + << " Malformed range. Contains illegal key (" + << its_key << ")"; + } + } + + if (has_first && has_last) { + its_ranges.insert(std::make_pair(its_first, its_last)); + } + } + } + + _range = its_ranges; } /////////////////////////////////////////////////////////////////////////////// @@ -1876,6 +1998,10 @@ unsigned short configuration_impl::get_diagnosis_address() const { return diagnosis_; } +std::uint16_t configuration_impl::get_diagnosis_mask() const { + return diagnosis_mask_; +} + bool configuration_impl::is_v4() const { return unicast_.is_v4(); } @@ -2410,10 +2536,38 @@ bool configuration_impl::check_credentials(client_t _client, uint32_t _uid, if (!policy_enabled_) { return true; } + + bool has_id(false); auto its_client = policies_.find(_client); + + // Search for generic policy if no specific could be found + if (its_client == policies_.end()) + its_client = policies_.find(ANY_CLIENT); + if (its_client != policies_.end()) { - if ((!its_client->second->is_uid_set_ || its_client->second->uid_ == _uid) - && (!its_client->second->is_gid_set_ || its_client->second->gid_ == _gid)) { + for (auto its_credential : its_client->second->ids_) { + bool has_uid(false), has_gid(false); + for (auto its_range : std::get<0>(its_credential)) { + if (std::get<0>(its_range) <= _uid && _uid <= std::get<1>(its_range)) { + has_uid = true; + break; + } + } + for (auto its_range : std::get<1>(its_credential)) { + if (std::get<0>(its_range) <= _gid && _gid <= std::get<1>(its_range)) { + has_gid = true; + break; + } + } + + if (has_uid && has_gid) { + has_id = true; + break; + } + } + + if ((has_id && its_client->second->allow_who_) + || (!has_id && !its_client->second->allow_who_)) { return true; } } @@ -2433,6 +2587,11 @@ bool configuration_impl::is_client_allowed(client_t _client, service_t _service, return true; } auto its_client = policies_.find(_client); + + // Search for generic policy if no specific could be found + if (its_client == policies_.end()) + its_client = policies_.find(ANY_CLIENT); + if (its_client == policies_.end()) { if (!check_credentials_) { VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client @@ -2443,18 +2602,13 @@ bool configuration_impl::is_client_allowed(client_t _client, service_t _service, return !check_credentials_; } - if (!its_client->second->allow_) { - auto its_denied_service = its_client->second->denied_services_.find( - std::make_pair(_service, _instance)); - if (its_denied_service == its_client->second->denied_services_.end()) { - return true; - } - } else { - auto its_allowed_service = its_client->second->allowed_services_.find( - std::make_pair(_service, _instance)); - if (its_allowed_service != its_client->second->allowed_services_.end()) { - return true; - } + auto its_service = its_client->second->services_.find(std::make_pair(_service, _instance)); + if (its_client->second->allow_what_ + && its_service != its_client->second->services_.end()) { + return true; + } else if (!its_client->second->allow_what_ + && its_service == its_client->second->services_.end()) { + return true; } if (!check_credentials_) { @@ -2472,7 +2626,13 @@ bool configuration_impl::is_offer_allowed(client_t _client, service_t _service, if (!policy_enabled_) { return true; } + auto its_client = policies_.find(_client); + + // Search for generic policy if no specific could be found + if (its_client == policies_.end()) + its_client = policies_.find(ANY_CLIENT); + if (its_client == policies_.end()) { if (!check_credentials_) { VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client @@ -2483,18 +2643,13 @@ bool configuration_impl::is_offer_allowed(client_t _client, service_t _service, return !check_credentials_; } - if (!its_client->second->allow_) { - auto its_denied_service = its_client->second->denied_offers_.find( - std::make_pair(_service, _instance)); - if (its_denied_service == its_client->second->denied_offers_.end()) { - return true; - } - } else { - auto its_allowed_service = its_client->second->allowed_offers_.find( - std::make_pair(_service, _instance)); - if (its_allowed_service != its_client->second->allowed_offers_.end()) { - return true; - } + auto its_offer = its_client->second->offers_.find(std::make_pair(_service, _instance)); + if (its_client->second->allow_what_ + && its_offer != its_client->second->offers_.end()) { + return true; + } else if (!its_client->second->allow_what_ + && its_offer == its_client->second->offers_.end()) { + return true; } if (!check_credentials_) { diff --git a/implementation/endpoints/include/netlink_connector.hpp b/implementation/endpoints/include/netlink_connector.hpp index fdad71883..f71ba883d 100644 --- a/implementation/endpoints/include/netlink_connector.hpp +++ b/implementation/endpoints/include/netlink_connector.hpp @@ -129,17 +129,18 @@ class nl_protocol { int proto; }; -typedef std::function< void (std::string, bool) > net_if_changed_handler_t; +typedef std::function< void (bool, std::string, bool) > net_if_changed_handler_t; class netlink_connector : public std::enable_shared_from_this { public: - netlink_connector(boost::asio::io_service& _io, boost::asio::ip::address _address): + netlink_connector(boost::asio::io_service& _io, boost::asio::ip::address _address, + boost::asio::ip::address _multicast_address): net_if_index_for_address_(0), handler_(nullptr), socket_(_io), recv_buffer_(recv_buffer_size, 0), - address_(_address) - { + address_(_address), + multicast_address_(_multicast_address) { } ~netlink_connector() {} @@ -155,10 +156,15 @@ class netlink_connector : public std::enable_shared_from_this const unsigned int address); void send_ifa_request(); void send_ifi_request(); + void send_rt_request(); void receive_cbk(boost::system::error_code const &_error, std::size_t _bytes); void send_cbk(boost::system::error_code const &_error, std::size_t _bytes); + bool check_sd_multicast_route_match(struct rtmsg* _routemsg, + size_t _length, + std::string* _routename) const; + std::map net_if_flags_; int net_if_index_for_address_; @@ -171,6 +177,7 @@ class netlink_connector : public std::enable_shared_from_this message_buffer_t recv_buffer_; boost::asio::ip::address address_; + boost::asio::ip::address multicast_address_; }; } diff --git a/implementation/endpoints/src/client_endpoint_impl.cpp b/implementation/endpoints/src/client_endpoint_impl.cpp index be8e68476..559982853 100644 --- a/implementation/endpoints/src/client_endpoint_impl.cpp +++ b/implementation/endpoints/src/client_endpoint_impl.cpp @@ -320,6 +320,7 @@ void client_endpoint_impl::send_cbk( if (!stopping) { print_status(); } + was_not_connected_ = true; shutdown_and_close_socket(true); connect(); } else if (_error == boost::asio::error::not_connected diff --git a/implementation/endpoints/src/netlink_connector.cpp b/implementation/endpoints/src/netlink_connector.cpp index eb43b74bc..94b75cf13 100644 --- a/implementation/endpoints/src/netlink_connector.cpp +++ b/implementation/endpoints/src/netlink_connector.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "../include/netlink_connector.hpp" #include "../../logging/include/logger.hpp" @@ -46,17 +47,23 @@ void netlink_connector::start() { if (ec) { VSOMEIP_WARNING << "Error opening NETLINK socket: " << ec.message(); if (handler_) { - handler_("n/a", true); + handler_(true, "n/a", true); + handler_(false, "n/a", true); } return; } if (socket_.is_open()) { - socket_.bind(nl_endpoint(RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR), ec); + socket_.bind(nl_endpoint( + RTMGRP_LINK | + RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | + RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | + RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_MROUTE), ec); if (ec) { VSOMEIP_WARNING << "Error binding NETLINK socket: " << ec.message(); if (handler_) { - handler_("n/a", true); + handler_(true, "n/a", true); + handler_(false, "n/a", true); } return; } @@ -75,7 +82,8 @@ void netlink_connector::start() { } else { VSOMEIP_WARNING << "Error opening NETLINK socket!"; if (handler_) { - handler_("n/a", true); + handler_(true, "n/a", true); + handler_(false, "n/a", true); } } } @@ -96,13 +104,11 @@ void netlink_connector::receive_cbk(boost::system::error_code const &_error, while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) { char ifname[1024]; - struct ifinfomsg *ifi = (ifinfomsg *)NLMSG_DATA(nlh); - struct ifaddrmsg *ifa = (ifaddrmsg *)NLMSG_DATA(nlh); switch (nlh->nlmsg_type) { - case RTM_NEWADDR: + case RTM_NEWADDR: { // New Address information - if (has_address((struct ifaddrmsg *)NLMSG_DATA(nlh), - IFA_PAYLOAD(nlh), address)) { + struct ifaddrmsg *ifa = (ifaddrmsg *)NLMSG_DATA(nlh); + if (has_address(ifa, IFA_PAYLOAD(nlh), address)) { net_if_index_for_address_ = ifa->ifa_index; auto its_if = net_if_flags_.find(ifa->ifa_index); if (its_if != net_if_flags_.end()) { @@ -110,12 +116,13 @@ void netlink_connector::receive_cbk(boost::system::error_code const &_error, (its_if->second & IFF_RUNNING)) { if (handler_) { if_indextoname(ifa->ifa_index,ifname); - handler_(ifname, true); + handler_(true, ifname, true); + send_rt_request(); } } else { if (handler_) { if_indextoname(ifa->ifa_index,ifname); - handler_(ifname, false); + handler_(true, ifname, false); } } } else { @@ -125,24 +132,59 @@ void netlink_connector::receive_cbk(boost::system::error_code const &_error, } } break; - case RTM_NEWLINK: + } + case RTM_NEWLINK: { // New Interface information + struct ifinfomsg *ifi = (ifinfomsg *)NLMSG_DATA(nlh); net_if_flags_[ifi->ifi_index] = ifi->ifi_flags; if (net_if_index_for_address_ == ifi->ifi_index) { if ((ifi->ifi_flags & IFF_UP) && (ifi->ifi_flags & IFF_RUNNING)) { if (handler_) { if_indextoname(ifi->ifi_index,ifname); - handler_(ifname, true); + handler_(true, ifname, true); + send_rt_request(); } } else { if (handler_) { if_indextoname(ifi->ifi_index,ifname); - handler_(ifname, false); + handler_(true, ifname, false); } } } break; + } + case RTM_NEWROUTE: { + struct rtmsg *routemsg = (rtmsg *)NLMSG_DATA(nlh); + std::string its_route_name; + if (check_sd_multicast_route_match(routemsg, RTM_PAYLOAD(nlh), + &its_route_name)) { + if (handler_) { + handler_(false, its_route_name, true); + } + } + break; + } + case RTM_DELROUTE: { + struct rtmsg *routemsg = (rtmsg *)NLMSG_DATA(nlh); + std::string its_route_name; + if (check_sd_multicast_route_match(routemsg, RTM_PAYLOAD(nlh), + &its_route_name)) { + if (handler_) { + handler_(false, its_route_name, false); + } + } + break; + } + case NLMSG_ERROR: { + struct nlmsgerr *errmsg = (nlmsgerr *)NLMSG_DATA(nlh); + VSOMEIP_ERROR << "netlink_connector::receive_cbk received " + "error message: " << std::dec << nlh->nlmsg_type + << " seq " << errmsg->msg.nlmsg_seq; + break; + } + case NLMSG_DONE: + case NLMSG_NOOP: default: break; } @@ -178,7 +220,8 @@ void netlink_connector::receive_cbk(boost::system::error_code const &_error, } } if (handler_) { - handler_("n/a", true); + handler_(true, "n/a", true); + handler_(false, "n/a", true); } } } @@ -189,7 +232,8 @@ void netlink_connector::send_cbk(boost::system::error_code const &_error, std::s if (_error) { VSOMEIP_WARNING << "Netlink send error : " << _error.message(); if (handler_) { - handler_("n/a", true); + handler_(true, "n/a", true); + handler_(false, "n/a", true); } } } @@ -204,6 +248,7 @@ void netlink_connector::send_ifa_request() { get_address_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); get_address_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; get_address_msg.nlhdr.nlmsg_type = RTM_GETADDR; + get_address_msg.nlhdr.nlmsg_seq = 1; if (address_.is_v4()) { get_address_msg.addrmsg.ifa_family = AF_INET; } else { @@ -232,6 +277,7 @@ void netlink_connector::send_ifi_request() { get_link_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; get_link_msg.nlhdr.nlmsg_type = RTM_GETLINK; get_link_msg.infomsg.ifi_family = AF_UNSPEC; + get_link_msg.nlhdr.nlmsg_seq = 2; { std::lock_guard its_lock(socket_mutex_); @@ -247,6 +293,38 @@ void netlink_connector::send_ifi_request() { } } +void netlink_connector::send_rt_request() { + typedef struct { + struct nlmsghdr nlhdr; + struct rtgenmsg routemsg; + } netlink_route_msg; + + netlink_route_msg get_route_msg; + memset(&get_route_msg, 0, sizeof(get_route_msg)); + get_route_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + get_route_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + get_route_msg.nlhdr.nlmsg_type = RTM_GETROUTE; + get_route_msg.nlhdr.nlmsg_seq = 3; + if (multicast_address_.is_v6()) { + get_route_msg.routemsg.rtgen_family = AF_INET6; + } else { + get_route_msg.routemsg.rtgen_family = AF_INET; + } + + { + std::lock_guard its_lock(socket_mutex_); + socket_.async_send( + boost::asio::buffer(&get_route_msg, get_route_msg.nlhdr.nlmsg_len), + std::bind( + &netlink_connector::send_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + bool netlink_connector::has_address(struct ifaddrmsg * ifa_struct, size_t length, const unsigned int address) { @@ -272,6 +350,88 @@ bool netlink_connector::has_address(struct ifaddrmsg * ifa_struct, return false; } +bool netlink_connector::check_sd_multicast_route_match(struct rtmsg* _routemsg, + size_t _length, + std::string* _routename) const { + struct rtattr *retrta; + retrta = static_cast(RTM_RTA(_routemsg)); + int if_index(0); + char if_name[1024] = "n/a"; + char address[INET6_ADDRSTRLEN] = "n/a"; + char gateway[INET6_ADDRSTRLEN] = "n/a"; + bool matches_sd_multicast(false); + while (RTA_OK(retrta, _length)) { + if (retrta->rta_type == RTA_DST) { + // check if added/removed route matches on configured SD multicast address + size_t rtattr_length = RTA_PAYLOAD(retrta); + if (rtattr_length == 4 && multicast_address_.is_v4()) { // IPv4 route + inet_ntop(AF_INET, RTA_DATA(retrta), address, sizeof(address)); + std::uint32_t netmask(0); + for (int i = 31; i > 31 - _routemsg->rtm_dst_len; i--) { + netmask |= (1 << i); + } + const std::uint32_t dst_addr = ntohl(*((std::uint32_t *)RTA_DATA(retrta))); + const std::uint32_t dst_net = (dst_addr & netmask); + const std::uint32_t sd_addr = static_cast(multicast_address_.to_v4().to_ulong()); + const std::uint32_t sd_net = (sd_addr & netmask); + matches_sd_multicast = !(dst_net ^ sd_net); + } else if (rtattr_length == 16 && multicast_address_.is_v6()) { // IPv6 route + inet_ntop(AF_INET6, RTA_DATA(retrta), address, sizeof(address)); + std::uint32_t netmask2[4] = {0,0,0,0}; + for (int i = 127; i > 127 - _routemsg->rtm_dst_len; i--) { + if (i > 95) { + netmask2[0] |= (1 << (i-96)); + } else if (i > 63) { + netmask2[1] |= (1 << (i-63)); + } else if (i > 31) { + netmask2[2] |= (1 << (i-32)); + } else { + netmask2[3] |= (1 << i); + } + } + + for (int i = 0; i < 4; i++) { + const std::uint32_t dst = ntohl((*(struct in6_addr*)RTA_DATA(retrta)).__in6_u.__u6_addr32[i]); + const std::uint32_t sd = ntohl(reinterpret_cast(multicast_address_.to_v6().to_bytes().data())[i]); + const std::uint32_t dst_net = dst & netmask2[i]; + const std::uint32_t sd_net = sd & netmask2[i]; + matches_sd_multicast = !(dst_net ^ sd_net); + if (!matches_sd_multicast) { + break; + } + } + } + } else if (retrta->rta_type == RTA_OIF) { + if_index = *(int *)(RTA_DATA(retrta)); + if_indextoname(if_index,if_name); + } else if (retrta->rta_type == RTA_GATEWAY) { + size_t rtattr_length = RTA_PAYLOAD(retrta); + if (rtattr_length == 4) { + inet_ntop(AF_INET, RTA_DATA(retrta), gateway, sizeof(gateway)); + } else if (rtattr_length == 16) { + inet_ntop(AF_INET6, RTA_DATA(retrta), gateway, sizeof(gateway)); + } + } + retrta = RTA_NEXT(retrta, _length); + } + if (matches_sd_multicast && net_if_index_for_address_ == if_index) { + std::stringstream stream; + stream << address << "/" << (static_cast(_routemsg->rtm_dst_len)) + << " if: " << if_name << " gw: " << gateway; + *_routename = stream.str(); + return true; + } else if (if_index > 0 && net_if_index_for_address_ == if_index && + _routemsg->rtm_dst_len == 0) { + // the default route is set to the interface on which the SD will listen + // therefore no explicit multicast route is required. + std::stringstream stream; + stream << "default route (0.0.0.0/0) if: " << if_name << " gw: " << gateway; + *_routename = stream.str(); + return true; + } + return false; +} + } // namespace vsomeip #endif diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index b1a2f7416..ab7d9c304 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -493,8 +493,12 @@ void tcp_client_endpoint_impl::receive_cbk( "out message_size. recv_buffer_capacity: " << _recv_buffer->capacity() << " its_iteration_gap: " << its_iteration_gap - << "local: " << get_address_port_local() - << " remote: " << get_address_port_remote(); + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Restarting connection due to missing/broken data TCP stream."; + its_lock.unlock(); + restart(); + return; } } while (has_full_message && _recv_buffer_size); if (its_iteration_gap) { diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index 01c6db1aa..4226c5523 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -529,15 +529,24 @@ void tcp_server_endpoint_impl::connection::receive_cbk( missing_capacity_ = VSOMEIP_SOMEIP_HEADER_SIZE - static_cast(recv_buffer_size_); } else { - std::lock_guard its_lock(socket_mutex_); - VSOMEIP_ERROR << "tse::c<" << this - << ">rcb: recv_buffer_size is: " << std::dec - << recv_buffer_size_ << " but couldn't read " - "out message_size. recv_buffer_capacity: " - << recv_buffer_.capacity() - << " its_iteration_gap: " << its_iteration_gap - << "local: " << get_address_port_local() - << " remote: " << get_address_port_remote(); + { + std::lock_guard its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse::c<" << this + << ">rcb: recv_buffer_size is: " << std::dec + << recv_buffer_size_ << " but couldn't read " + "out message_size. recv_buffer_capacity: " + << recv_buffer_.capacity() + << " its_iteration_gap: " << its_iteration_gap + << "local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } + { + std::lock_guard its_lock(its_server->connections_mutex_); + stop(); + } + its_server->remove_connection(this); + return; } } } while (has_full_message && recv_buffer_size_); diff --git a/implementation/routing/include/eventgroupinfo.hpp b/implementation/routing/include/eventgroupinfo.hpp index 9e50e8551..8420fd392 100644 --- a/implementation/routing/include/eventgroupinfo.hpp +++ b/implementation/routing/include/eventgroupinfo.hpp @@ -82,7 +82,7 @@ class eventgroupinfo { VSOMEIP_EXPORT pending_subscription_id_t add_pending_subscription( pending_subscription_t _pending_subscription); - VSOMEIP_EXPORT pending_subscription_t remove_pending_subscription( + VSOMEIP_EXPORT std::vector remove_pending_subscription( pending_subscription_id_t _subscription_id); VSOMEIP_EXPORT void clear_pending_subscriptions(); @@ -109,6 +109,8 @@ class eventgroupinfo { std::mutex pending_subscriptions_mutex_; std::map pending_subscriptions_; + std::map, + std::vector> pending_subscriptions_by_remote_; pending_subscription_id_t subscription_id_; }; diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp index c134d7b39..7bf3a4d85 100644 --- a/implementation/routing/include/routing_manager_base.hpp +++ b/implementation/routing/include/routing_manager_base.hpp @@ -139,6 +139,9 @@ class routing_manager_base : public routing_manager, std::shared_ptr create_local(client_t _client); std::shared_ptr find_or_create_local(client_t _client); void remove_local(client_t _client); + void remove_local(client_t _client, + const std::set>& _subscribed_eventgroups); + std::shared_ptr find_local(client_t _client); std::shared_ptr find_local(service_t _service, instance_t _instance); @@ -195,16 +198,17 @@ class routing_manager_base : public routing_manager, std::map> get_local_endpoints(); + std::set> + get_subscriptions(const client_t _client); private: std::shared_ptr create_local_unlocked(client_t _client); std::shared_ptr find_local_unlocked(client_t _client); - std::set> - get_subscriptions(const client_t _client); virtual bool create_placeholder_event_and_subscribe( service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, client_t _client) = 0; + protected: routing_manager_host *host_; boost::asio::io_service &io_; diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp index ad6810b65..2e90077e8 100644 --- a/implementation/routing/include/routing_manager_impl.hpp +++ b/implementation/routing/include/routing_manager_impl.hpp @@ -146,6 +146,10 @@ class routing_manager_impl: public routing_manager_base, void on_pong(client_t _client); + void on_unsubscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + pending_subscription_id_t _unsubscription_id); + // interface "endpoint_host" std::shared_ptr find_or_create_remote_client(service_t _service, instance_t _instance, @@ -191,12 +195,12 @@ class routing_manager_impl: public routing_manager_base, bool _has_reliable, bool _has_unreliable); void update_routing_info(std::chrono::milliseconds _elapsed); - remote_subscription_state_e on_remote_subscription( + void on_remote_subscription( service_t _service, instance_t _instance, eventgroup_t _eventgroup, const std::shared_ptr &_subscriber, - const std::shared_ptr &_target, - ttl_t _ttl, client_t *_client, - const std::shared_ptr &_sd_message_id); + const std::shared_ptr &_target, ttl_t _ttl, + const std::shared_ptr &_sd_message_id, + const std::function& _callback); void on_unsubscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr _target); @@ -324,7 +328,9 @@ class routing_manager_impl: public routing_manager_base, major_version_t _major, event_t _event, subscription_type_e _subscription_type); - void on_net_if_state_changed(std::string _if, bool _available); + void on_net_interface_or_route_state_changed(bool _is_interface, + std::string _if, + bool _available); void start_ip_routing(); @@ -354,6 +360,18 @@ class routing_manager_impl: public routing_manager_base, void memory_log_timer_cbk(boost::system::error_code const & _error); void status_log_timer_cbk(boost::system::error_code const & _error); + void send_subscription(client_t _offering_client, + client_t _subscribing_client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, + pending_subscription_id_t _pending_subscription_id); + + void send_unsubscription( + client_t _offering_client, client_t _subscribing_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + pending_subscription_id_t _pending_unsubscription_id); + + std::shared_ptr stub_; std::shared_ptr discovery_; @@ -407,6 +425,8 @@ class routing_manager_impl: public routing_manager_base, boost::asio::steady_timer version_log_timer_; bool if_state_running_; + bool sd_route_set_; + bool routing_running_; std::mutex pending_sd_offers_mutex_; std::vector> pending_sd_offers_; #ifndef _WIN32 diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index ac7bded98..a9f0762b3 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_proxy.hpp @@ -178,6 +178,10 @@ class routing_manager_proxy: public routing_manager_base { void send_request_services(std::set& _requests); + void send_unsubscribe_ack(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + pending_subscription_id_t _subscription_id); + private: enum class inner_state_type_e : std::uint8_t { ST_REGISTERED = 0x0, diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index f825b0b17..3e97a5f97 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -66,7 +66,7 @@ class routing_manager_stub: public endpoint_host, void send_unsubscribe(std::shared_ptr _target, client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, bool _is_remote_subscriber); + event_t _event, pending_subscription_id_t _unsubscription_id); void send_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event); diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp index 5497d6e7e..a6d461ee6 100644 --- a/implementation/routing/include/routing_manager_stub_host.hpp +++ b/implementation/routing/include/routing_manager_stub_host.hpp @@ -56,6 +56,10 @@ class routing_manager_stub_host { virtual void unsubscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) = 0; + virtual void on_unsubscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + pending_subscription_id_t _unsubscription_id) = 0; + virtual bool on_message(service_t _service, instance_t _instance, const byte_t *_data, length_t _size, bool _reliable, bool _is_valid_crc = true) = 0; diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp index 16bc56521..f33a944e9 100644 --- a/implementation/routing/include/types.hpp +++ b/implementation/routing/include/types.hpp @@ -11,8 +11,10 @@ #include #include +#include #include "../../service_discovery/include/message_impl.hpp" +#include "../../configuration/include/internal.hpp" namespace vsomeip { @@ -84,22 +86,29 @@ struct pending_subscription_t { std::shared_ptr _sd_message_identifier, std::shared_ptr _subscriber, std::shared_ptr _target, - ttl_t _ttl) : + ttl_t _ttl, + client_t _subscribing_client) : sd_message_identifier_(_sd_message_identifier), subscriber_(_subscriber), target_(_target), - ttl_(_ttl) { + ttl_(_ttl), + subscribing_client_(_subscribing_client), + pending_subscription_id_(DEFAULT_SUBSCRIPTION) { } pending_subscription_t () : sd_message_identifier_(std::shared_ptr()), subscriber_(std::shared_ptr()), target_(std::shared_ptr()), - ttl_(0) { + ttl_(0), + subscribing_client_(VSOMEIP_ROUTING_CLIENT), + pending_subscription_id_(DEFAULT_SUBSCRIPTION) { } std::shared_ptr sd_message_identifier_; std::shared_ptr subscriber_; std::shared_ptr target_; ttl_t ttl_; + client_t subscribing_client_; + pending_subscription_id_t pending_subscription_id_; }; enum remote_subscription_state_e : std::uint8_t { diff --git a/implementation/routing/src/eventgroupinfo.cpp b/implementation/routing/src/eventgroupinfo.cpp index 1432aa2cf..137a02110 100644 --- a/implementation/routing/src/eventgroupinfo.cpp +++ b/implementation/routing/src/eventgroupinfo.cpp @@ -237,28 +237,116 @@ pending_subscription_id_t eventgroupinfo::add_pending_subscription( subscription_id_++; } pending_subscriptions_[subscription_id_] = _pending_subscription; + + const auto remote_address_port = std::make_pair( + _pending_subscription.subscriber_->get_address(), + _pending_subscription.subscriber_->get_port()); + + auto found_address = pending_subscriptions_by_remote_.find(remote_address_port); + if (found_address != pending_subscriptions_by_remote_.end()) { + found_address->second.push_back(subscription_id_); + VSOMEIP_WARNING << __func__ << " num pending subscriptions: " + << std::dec << found_address->second.size(); + return DEFAULT_SUBSCRIPTION; + } else { + pending_subscriptions_by_remote_[remote_address_port].push_back(subscription_id_); + } return subscription_id_; } -pending_subscription_t eventgroupinfo::remove_pending_subscription( +std::vector eventgroupinfo::remove_pending_subscription( pending_subscription_id_t _subscription_id) { + std::vector its_pending_subscriptions; std::lock_guard its_lock(pending_subscriptions_mutex_); - pending_subscription_t its_pending_subscription; const auto found_pending_subscription = pending_subscriptions_.find( _subscription_id); if (found_pending_subscription != pending_subscriptions_.end()) { - its_pending_subscription = found_pending_subscription->second; - pending_subscriptions_.erase(found_pending_subscription); + pending_subscription_t its_pending_sub = found_pending_subscription->second; + const auto remote_address_port = std::make_pair( + its_pending_sub.subscriber_->get_address(), + its_pending_sub.subscriber_->get_port()); + const bool removed_is_subscribe = (found_pending_subscription->second.ttl_ > 0); + + // check if more (un)subscriptions to this eventgroup arrived from the + // same remote during the time the current pending subscription was processed + auto found_remote = pending_subscriptions_by_remote_.find(remote_address_port); + if (found_remote != pending_subscriptions_by_remote_.end()) { + if (found_remote->second.size() + && found_remote->second.front() == _subscription_id) { + pending_subscriptions_.erase(found_pending_subscription); + found_remote->second.erase(found_remote->second.begin()); + + if (removed_is_subscribe) { // only subscriptions must be acked via SD + its_pending_sub.pending_subscription_id_ = _subscription_id; + its_pending_subscriptions.push_back(its_pending_sub); + } + // retrieve all pending (un)subscriptions which arrived during + // the time the rm_proxy answered the currently processed subscription + for (auto iter = found_remote->second.begin(); + iter != found_remote->second.end();) { + const auto other_pen_sub = pending_subscriptions_.find(*iter); + if (other_pen_sub != pending_subscriptions_.end()) { + const bool queued_is_subscribe = (other_pen_sub->second.ttl_ > 0); + if (removed_is_subscribe) { + its_pending_subscriptions.push_back(other_pen_sub->second); + its_pending_subscriptions.back().pending_subscription_id_ = *iter; + if (!queued_is_subscribe) { + // unsubscribe was queued and needs to be sent to + // rm_proxy first before continuing processing + // following queued (un)subscriptions + break; + } else { + iter = found_remote->second.erase(iter); + pending_subscriptions_.erase(other_pen_sub); + } + } else { + if (queued_is_subscribe) { + // subscribe was queued and needs to be sent to + // rm_proxy first before continuing processing + // following queued (un)subscriptions + its_pending_subscriptions.push_back(other_pen_sub->second); + its_pending_subscriptions.back().pending_subscription_id_ = *iter; + break; + } else { + // further queued unsubscriptions can be ignored + iter = found_remote->second.erase(iter); + pending_subscriptions_.erase(other_pen_sub); + } + } + } else { + VSOMEIP_ERROR << __func__ << " didn't find queued subscription: " + << *iter; + ++iter; + } + } + + if (found_remote->second.empty()) { + pending_subscriptions_by_remote_.erase(found_remote); + } + } else { + boost::system::error_code ec; + VSOMEIP_WARNING << __func__ << " Subscriptions were answered in " + << " in wrong order by rm_proxy! [" + << " subscriber: " << remote_address_port.first.to_string(ec) + << ":" << std::dec << remote_address_port.second; + // found_pending_subscription isn't deleted from + // pending_subscriptions_ map in this case to ensure answer + // sequence of SD messages. + its_pending_subscriptions.clear(); + } + } } else { VSOMEIP_ERROR << __func__ << " didn't find pending_subscription: " - << _subscription_id;; + << _subscription_id; } - return its_pending_subscription; + return its_pending_subscriptions; } + void eventgroupinfo::clear_pending_subscriptions() { std::lock_guard its_lock(pending_subscriptions_mutex_); pending_subscriptions_.clear(); + pending_subscriptions_by_remote_.clear(); } } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp index baf6660ba..9296f993b 100644 --- a/implementation/routing/src/routing_manager_base.cpp +++ b/implementation/routing/src/routing_manager_base.cpp @@ -815,14 +815,17 @@ std::shared_ptr routing_manager_base::find_or_create_local(client_t _c } void routing_manager_base::remove_local(client_t _client) { - auto subscriptions = get_subscriptions(_client); - for (auto its_subscription : subscriptions) { + remove_local(_client, get_subscriptions(_client)); +} + +void routing_manager_base::remove_local(client_t _client, + const std::set>& _subscribed_eventgroups) { + for (auto its_subscription : _subscribed_eventgroups) { host_->on_subscription(std::get<0>(its_subscription), std::get<1>(its_subscription), std::get<2>(its_subscription), _client, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); routing_manager_base::unsubscribe(_client, std::get<0>(its_subscription), std::get<1>(its_subscription), std::get<2>(its_subscription), ANY_EVENT); } - std::shared_ptr its_endpoint(find_local(_client)); if (its_endpoint) { its_endpoint->register_error_handler(nullptr); diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 2acd4eb35..544213464 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -69,6 +69,8 @@ routing_manager_impl::routing_manager_impl(routing_manager_host *_host) : routing_manager_base(_host), version_log_timer_(_host->get_io()), if_state_running_(false), + sd_route_set_(false), + routing_running_(false), #ifndef WITHOUT_SYSTEMD watchdog_timer_(_host->get_io()), #endif @@ -142,13 +144,17 @@ void routing_manager_impl::init() { void routing_manager_impl::start() { #ifndef _WIN32 netlink_connector_ = std::make_shared(host_->get_io(), - configuration_->get_unicast_address()); + configuration_->get_unicast_address(), + boost::asio::ip::address::from_string(configuration_->get_sd_multicast())); netlink_connector_->register_net_if_changes_handler( - std::bind(&routing_manager_impl::on_net_if_state_changed, - this, std::placeholders::_1, std::placeholders::_2)); + std::bind(&routing_manager_impl::on_net_interface_or_route_state_changed, + this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); netlink_connector_->start(); #else - start_ip_routing(); + { + std::lock_guard its_lock(pending_sd_offers_mutex_); + start_ip_routing(); + } #endif stub_->start(); @@ -555,7 +561,8 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service, std::lock_guard ist_lock(pending_subscription_mutex_); remove_pending_subscription(_service, _instance, _eventgroup, _event); stub_->send_unsubscribe(find_local(_service, _instance), - _client, _service, _instance, _eventgroup, _event, false); + _client, _service, _instance, _eventgroup, _event, + DEFAULT_SUBSCRIPTION); } } clear_multicast_endpoints(_service, _instance); @@ -1035,7 +1042,6 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, 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]); @@ -1052,6 +1058,26 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } } } else { + its_instance = find_instance(its_service, _receiver); + if (its_instance == 0xFFFF) { + its_method = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); + const client_t its_client = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_CLIENT_POS_MIN], + _data[VSOMEIP_CLIENT_POS_MAX]); + const session_t its_session = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SESSION_POS_MIN], + _data[VSOMEIP_SESSION_POS_MAX]); + boost::system::error_code ec; + VSOMEIP_ERROR << "Received message on invalid port: [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_client << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "] from: " + << _remote_address.to_string(ec) << ":" << std::dec << _remote_port; + } //Ignore messages with invalid message type if(_size >= VSOMEIP_MESSAGE_TYPE_POS) { if(!utility::is_valid_message_type(static_cast(_data[VSOMEIP_MESSAGE_TYPE_POS]))) { @@ -1850,7 +1876,15 @@ std::shared_ptr routing_manager_impl::find_or_create_server_endpoint( } void routing_manager_impl::remove_local(client_t _client) { - routing_manager_base::remove_local(_client); + auto clients_subscriptions = get_subscriptions(_client); + { + std::lock_guard its_lock(remote_subscription_state_mutex_); + for (const auto& s : clients_subscriptions) { + remote_subscription_state_.erase(std::tuple_cat(s, std::make_tuple(_client))); + } + } + routing_manager_base::remove_local(_client, clients_subscriptions); + std::forward_list> services_to_release_; { std::lock_guard its_lock(requested_services_mutex_); @@ -2425,6 +2459,7 @@ void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address & std::shared_ptr invalid_endpoint_; client_t client_; std::set> events_; + std::shared_ptr eventgroupinfo_; }; std::vector subscriptions_to_expire_; { @@ -2455,7 +2490,8 @@ void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address & its_eventgroup.first, its_endpoint, its_client, - its_events}); + its_events, + its_eventgroup.second}); } if(its_eventgroup.second->is_multicast() && its_invalid_endpoints.size() && 0 == its_eventgroup.second->get_unreliable_target_count() ) { @@ -2476,21 +2512,19 @@ void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address & } const client_t its_hosting_client = find_local_client( s.service_id_, s.instance_id_); - const bool service_offered_by_host = (its_hosting_client - == host_->get_client()); - std::shared_ptr target = find_local(its_hosting_client); - - if (target) { - stub_->send_unsubscribe(target, s.client_, s.service_id_, - s.instance_id_, s.eventgroup_id_, ANY_EVENT, true); - } - if (service_offered_by_host) { - host_->on_subscription(s.service_id_, - s.instance_id_, s.eventgroup_id_, - s.client_, false, - [](const bool _subscription_accepted){ - (void)_subscription_accepted; - }); + if (its_hosting_client != VSOMEIP_ROUTING_CLIENT) { + const pending_subscription_t its_pending_unsubscription( + std::shared_ptr(), + s.invalid_endpoint_, s.invalid_endpoint_, + 0, s.client_); + pending_subscription_id_t its_pending_unsubscription_id = + s.eventgroupinfo_->add_pending_subscription( + its_pending_unsubscription); + if (its_pending_unsubscription_id != DEFAULT_SUBSCRIPTION) { + send_unsubscription(its_hosting_client, s.client_, + s.service_id_, s.instance_id_, s.eventgroup_id_, + its_pending_unsubscription_id); + } } } } @@ -2525,14 +2559,15 @@ void routing_manager_impl::init_routing_info() { } } -remote_subscription_state_e routing_manager_impl::on_remote_subscription( +void routing_manager_impl::on_remote_subscription( service_t _service, instance_t _instance, eventgroup_t _eventgroup, const std::shared_ptr &_subscriber, - const std::shared_ptr &_target, - ttl_t _ttl, client_t *_client, - const std::shared_ptr &_sd_message_id) { + const std::shared_ptr &_target, ttl_t _ttl, + const std::shared_ptr &_sd_message_id, + const std::function& _callback) { std::shared_ptr its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + client_t its_subscribing_client(ILLEGAL_CLIENT); if (!its_eventgroup) { VSOMEIP_ERROR << "REMOTE SUBSCRIBE: attempt to subscribe to unknown eventgroup [" << std::hex << std::setw(4) << std::setfill('0') << _service << "." @@ -2541,7 +2576,8 @@ remote_subscription_state_e routing_manager_impl::on_remote_subscription( << " from " << _subscriber->get_address().to_string() << ":" << std::dec << _subscriber->get_port() << (_subscriber->is_reliable() ? " reliable" : " unreliable"); - return remote_subscription_state_e::SUBSCRIPTION_ERROR; + _callback(remote_subscription_state_e::SUBSCRIPTION_ERROR, its_subscribing_client); + return; } // find out client id for selective subscriber if (!_subscriber->is_reliable()) { @@ -2550,7 +2586,7 @@ remote_subscription_state_e routing_manager_impl::on_remote_subscription( if (!its_eventgroup->is_multicast()) { auto endpoint = find_server_endpoint(unreliable_port, false); if (endpoint) { - *_client = std::dynamic_pointer_cast(endpoint)-> + its_subscribing_client = std::dynamic_pointer_cast(endpoint)-> get_client(_subscriber); } } @@ -2559,55 +2595,42 @@ remote_subscription_state_e routing_manager_impl::on_remote_subscription( _subscriber->set_remote_port(reliable_port); auto endpoint = find_server_endpoint(reliable_port, true); if (endpoint) { - *_client = std::dynamic_pointer_cast(endpoint)-> + its_subscribing_client = std::dynamic_pointer_cast(endpoint)-> get_client(_subscriber); } } + std::unique_lock eventgroup_lock(its_eventgroup->get_subscription_lock()); const std::chrono::steady_clock::time_point its_expiration = std::chrono::steady_clock::now() + std::chrono::seconds(_ttl); if (its_eventgroup->update_target(_subscriber, its_expiration)) { - return remote_subscription_state_e::SUBSCRIPTION_ACKED; + _callback(remote_subscription_state_e::SUBSCRIPTION_ACKED,its_subscribing_client); + return; } else { const pending_subscription_id_t its_subscription_id = its_eventgroup->add_pending_subscription( - pending_subscription_t(_sd_message_id, - _subscriber, _target, _ttl)); - if (host_->get_client() == find_local_client(_service, _instance)) { - auto self = shared_from_this(); - const client_t its_client = *_client; - host_->on_subscription(_service, _instance, _eventgroup, *_client, true, - [this, self, _service, _instance, - _eventgroup, its_client, its_subscription_id] - (const bool _subscription_accepted) { - try { - if (!_subscription_accepted) { - const auto its_callback = std::bind( - &routing_manager_stub_host::on_subscribe_nack, - std::dynamic_pointer_cast(shared_from_this()), - its_client, _service, _instance, - _eventgroup, ANY_EVENT, its_subscription_id); - io_.post(its_callback); - } else { - const auto its_callback = std::bind( - &routing_manager_stub_host::on_subscribe_ack, - std::dynamic_pointer_cast(shared_from_this()), - its_client, _service, _instance, - _eventgroup, ANY_EVENT, its_subscription_id); - io_.post(its_callback); - } - } catch (const std::exception &e) { - VSOMEIP_ERROR << __func__ << e.what(); - } - }); - return remote_subscription_state_e::SUBSCRIPTION_PENDING; - } else { // service hosted by local client - stub_->send_subscribe(find_local(_service, _instance), *_client, + pending_subscription_t(_sd_message_id, _subscriber, + _target, _ttl, its_subscribing_client)); + if (its_subscription_id != DEFAULT_SUBSCRIPTION) { + // only sent subscription to rm_proxy / hosting application if there's + // no subscription for this eventgroup from the same remote subscriber + // already pending + const client_t its_offering_client = find_local_client(_service, _instance); + send_subscription(its_offering_client, its_subscribing_client, _service, _instance, _eventgroup, - its_eventgroup->get_major(), ANY_EVENT, its_subscription_id); - return remote_subscription_state_e::SUBSCRIPTION_PENDING; + its_eventgroup->get_major(), its_subscription_id); + } else { + VSOMEIP_WARNING << __func__ << " a remote subscription is already pending [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]" + << " from " << _subscriber->get_address().to_string() + << ":" << std::dec << _subscriber->get_port() + << (_subscriber->is_reliable() ? " reliable" : " unreliable"); } + _callback(remote_subscription_state_e::SUBSCRIPTION_PENDING, its_subscribing_client); + return; } - return remote_subscription_state_e::SUBSCRIPTION_ERROR; + _callback(remote_subscription_state_e::SUBSCRIPTION_ERROR, its_subscribing_client); } void routing_manager_impl::on_unsubscribe(service_t _service, @@ -2617,14 +2640,22 @@ void routing_manager_impl::on_unsubscribe(service_t _service, _instance, _eventgroup); if (its_eventgroup) { client_t its_client = find_client(_service, _instance, its_eventgroup, _target); + const pending_subscription_t its_pending_unsubscription( + std::shared_ptr(), _target, _target, + 0, its_client); + pending_subscription_id_t its_pending_unsubscription_id = + its_eventgroup->add_pending_subscription( + its_pending_unsubscription); its_eventgroup->remove_target(_target); clear_remote_subscriber(_service, _instance, its_client, _target); - stub_->send_unsubscribe(find_local(_service, _instance), - its_client, _service, _instance, _eventgroup, ANY_EVENT, true); - - host_->on_subscription(_service, _instance, _eventgroup, its_client, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); + if (its_pending_unsubscription_id != DEFAULT_SUBSCRIPTION) { + // there are no pending (un)subscriptions + const client_t its_offering_client = find_local_client(_service, _instance); + send_unsubscription(its_offering_client, its_client, _service, + _instance, _eventgroup, its_pending_unsubscription_id); + } if (its_eventgroup->get_targets().size() == 0) { std::set > its_events @@ -2721,7 +2752,8 @@ void routing_manager_impl::on_subscribe_ack(client_t _client, } remote_subscription_state_[its_tuple] = subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED; } else { // ACK sent back from local client as answer to a remote subscription - if (find_local_client(_service, _instance) == VSOMEIP_ROUTING_CLIENT) { + const client_t its_offering_client = find_local_client(_service, _instance); + if (its_offering_client == VSOMEIP_ROUTING_CLIENT) { // service was stopped while subscription was pending // send subscribe_nack back instead eventgroup_lock.unlock(); @@ -2730,45 +2762,53 @@ void routing_manager_impl::on_subscribe_ack(client_t _client, return; } if (discovery_) { - pending_subscription_t its_sd_message_id = - its_eventgroup->remove_pending_subscription( - _subscription_id); - if (its_sd_message_id.sd_message_identifier_ - && its_sd_message_id.subscriber_ - && its_sd_message_id.target_) { - { - std::lock_guard its_lock(remote_subscribers_mutex_); - remote_subscribers_[_service][_instance][_client].insert(its_sd_message_id.subscriber_); - } - const std::chrono::steady_clock::time_point its_expiration = - std::chrono::steady_clock::now() - + std::chrono::seconds( - its_sd_message_id.ttl_); - // IP address of target is a multicast address if the event is in a multicast eventgroup - if (its_eventgroup->is_multicast() - && !its_sd_message_id.subscriber_->is_reliable()) { - // Event is in multicast eventgroup and subscribe for UDP - its_eventgroup->add_target( - { its_sd_message_id.target_, its_expiration }, - { its_sd_message_id.subscriber_, its_expiration }); - } else { - // subscribe for TCP or UDP - its_eventgroup->add_target( - { its_sd_message_id.subscriber_, its_expiration }); + std::vector its_pending_subscriptions = + its_eventgroup->remove_pending_subscription(_subscription_id); + for (const pending_subscription_t& its_sd_message_id : its_pending_subscriptions) { + if (its_sd_message_id.ttl_ > 0) { + if (its_sd_message_id.sd_message_identifier_ + && its_sd_message_id.subscriber_ + && its_sd_message_id.target_) { + { + std::lock_guard its_lock(remote_subscribers_mutex_); + remote_subscribers_[_service][_instance][_client].insert(its_sd_message_id.subscriber_); + } + const std::chrono::steady_clock::time_point its_expiration = + std::chrono::steady_clock::now() + + std::chrono::seconds( + its_sd_message_id.ttl_); + // IP address of target is a multicast address if the event is in a multicast eventgroup + if (its_eventgroup->is_multicast() + && !its_sd_message_id.subscriber_->is_reliable()) { + // Event is in multicast eventgroup and subscribe for UDP + its_eventgroup->add_target( + { its_sd_message_id.target_, its_expiration }, + { its_sd_message_id.subscriber_, its_expiration }); + } else { + // subscribe for TCP or UDP + its_eventgroup->add_target( + { its_sd_message_id.subscriber_, its_expiration }); + } + discovery_->remote_subscription_acknowledge(_service, + _instance, _eventgroup, _client, true, + its_sd_message_id.sd_message_identifier_); + + VSOMEIP_INFO << "REMOTE SUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]" + << " from " << its_sd_message_id.subscriber_->get_address().to_string() + << ":" << std::dec << its_sd_message_id.subscriber_->get_port() + << (its_sd_message_id.subscriber_->is_reliable() ? " reliable" : " unreliable") + << " was accepted"; + } + } else { // unsubscription was queued while subscription was pending -> send it to client + send_unsubscription(its_offering_client, + its_sd_message_id.subscribing_client_, + _service, _instance, _eventgroup, + its_sd_message_id.pending_subscription_id_); } - discovery_->remote_subscription_acknowledge(_service, - _instance, _eventgroup, _client, true, - its_sd_message_id.sd_message_identifier_); - - VSOMEIP_INFO << "REMOTE SUBSCRIBE(" - << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]" - << " from " << its_sd_message_id.subscriber_->get_address().to_string() - << ":" << std::dec << its_sd_message_id.subscriber_->get_port() - << (its_sd_message_id.subscriber_->is_reliable() ? " reliable" : " unreliable") - << " was accepted"; } } return; @@ -2830,20 +2870,30 @@ void routing_manager_impl::on_subscribe_nack(client_t _client, remote_subscription_state_[its_tuple] = subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; } else { // NACK sent back from local client as answer to a remote subscription if (discovery_) { - pending_subscription_t its_sd_message_id = + std::vector its_pending_subscriptions = its_eventgroup->remove_pending_subscription(_subscription_id); - if (its_sd_message_id.sd_message_identifier_ && its_sd_message_id.subscriber_) { - discovery_->remote_subscription_acknowledge(_service, _instance, - _eventgroup, _client, false, its_sd_message_id.sd_message_identifier_); - VSOMEIP_INFO << "REMOTE SUBSCRIBE(" - << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]" - << " from " << its_sd_message_id.subscriber_->get_address().to_string() - << ":" << std::dec <get_port() - << (its_sd_message_id.subscriber_->is_reliable() ? " reliable" : " unreliable") - << " was not accepted"; + for (const pending_subscription_t& its_sd_message_id : its_pending_subscriptions) { + if (its_sd_message_id.ttl_ > 0) { + if (its_sd_message_id.sd_message_identifier_ && its_sd_message_id.subscriber_) { + discovery_->remote_subscription_acknowledge(_service, _instance, + _eventgroup, _client, false, its_sd_message_id.sd_message_identifier_); + VSOMEIP_INFO << "REMOTE SUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]" + << " from " << its_sd_message_id.subscriber_->get_address().to_string() + << ":" << std::dec <get_port() + << (its_sd_message_id.subscriber_->is_reliable() ? " reliable" : " unreliable") + << " was not accepted"; + } + } else { // unsubscription was queued while subscription was pending -> send it to client + const client_t its_offering_client = find_local_client(_service, _instance); + send_unsubscription(its_offering_client, + its_sd_message_id.subscribing_client_, _service, + _instance, _eventgroup, + its_sd_message_id.pending_subscription_id_); + } } } return; @@ -3340,6 +3390,7 @@ routing_manager_impl::expire_subscriptions() { std::shared_ptr invalid_endpoint_; client_t client_; std::set> events_; + std::shared_ptr eventgroupinfo_; }; std::vector subscriptions_to_expire_; std::chrono::steady_clock::time_point now @@ -3379,7 +3430,8 @@ routing_manager_impl::expire_subscriptions() { its_eventgroup.first, its_endpoint, its_client, - its_events}); + its_events, + its_eventgroup.second}); } if(its_eventgroup.second->is_multicast() && its_expired_endpoints.size() && 0 == its_eventgroup.second->get_unreliable_target_count() ) { @@ -3400,30 +3452,29 @@ routing_manager_impl::expire_subscriptions() { } const client_t its_hosting_client = find_local_client(s.service_id_, s.instance_id_); - const bool service_offered_by_host = (its_hosting_client - == host_->get_client()); - std::shared_ptr target = find_local(its_hosting_client); - - if (target) { - stub_->send_unsubscribe(target, s.client_, s.service_id_, - s.instance_id_, s.eventgroup_id_, ANY_EVENT, true); - } - if (service_offered_by_host) { - host_->on_subscription(s.service_id_, - s.instance_id_, s.eventgroup_id_, - s.client_, false, - [](const bool _subscription_accepted){ - (void)_subscription_accepted; - }); - } - - VSOMEIP_INFO << "Expired subscription (" - << std::hex << s.service_id_ << "." - << s.instance_id_ << "." - << s.eventgroup_id_ << " from " - << s.invalid_endpoint_->get_address() << ":" - << std::dec << s.invalid_endpoint_->get_port() - << "(" << std::hex << s.client_ << ")"; + + if (its_hosting_client != VSOMEIP_ROUTING_CLIENT) { + const pending_subscription_t its_pending_unsubscription( + std::shared_ptr(), + s.invalid_endpoint_, s.invalid_endpoint_, + 0, s.client_); + pending_subscription_id_t its_pending_unsubscription_id = + s.eventgroupinfo_->add_pending_subscription( + its_pending_unsubscription); + if (its_pending_unsubscription_id != DEFAULT_SUBSCRIPTION) { + send_unsubscription(its_hosting_client, s.client_, s.service_id_, + s.instance_id_, s.eventgroup_id_, + its_pending_unsubscription_id); + } + } + + VSOMEIP_INFO << "Expired subscription [" + << std::hex << std::setfill('0') << std::setw(4) << s.service_id_ << "." + << std::hex << std::setfill('0') << std::setw(4) << s.instance_id_ << "." + << std::hex << std::setfill('0') << std::setw(4) << s.eventgroup_id_ << "] from " + << s.invalid_endpoint_->get_address() << ":" + << std::dec << s.invalid_endpoint_->get_port() + << "(" << std::hex << std::setfill('0') << std::setw(4) << s.client_ << ")"; } } return next_expiration; @@ -3976,20 +4027,58 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { } } -void routing_manager_impl::on_net_if_state_changed(std::string _if, bool _available) { - if (!if_state_running_ && _available) { - VSOMEIP_INFO << "Network interface \"" << _if << "\" is up and running."; - start_ip_routing(); +void routing_manager_impl::on_net_interface_or_route_state_changed( + bool _is_interface, std::string _if, bool _available) { + std::lock_guard its_lock(pending_sd_offers_mutex_); + auto log_change_message = [&_if, _available, _is_interface](bool _warning) { + std::stringstream ss; + ss << (_is_interface ? "Network interface" : "Route") << " \"" << _if + << "\" state changed: " << (_available ? "up" : "down"); + if (_warning) { + VSOMEIP_WARNING << ss.str(); + } else { + VSOMEIP_INFO << ss.str(); + } + }; + if (_is_interface) { + if (if_state_running_ + || (_available && !if_state_running_ && routing_running_)) { + log_change_message(true); + } else if (!if_state_running_) { + log_change_message(false); + } + if (_available && !if_state_running_) { + if_state_running_ = true; + if (!routing_running_) { + if(configuration_->is_sd_enabled()) { + if (sd_route_set_) { + start_ip_routing(); + } + } else { + // Static routing, don't wait for route! + start_ip_routing(); + } + } + } } else { - VSOMEIP_WARNING << "Network interface \"" << _if << "\" state changed: " - << std::string((_available) ? "up" : "down"); + if (sd_route_set_ + || (_available && !sd_route_set_ && routing_running_)) { + log_change_message(true); + } else if (!sd_route_set_) { + log_change_message(false); + } + if (_available && !sd_route_set_) { + sd_route_set_ = true; + if (!routing_running_) { + if (if_state_running_) { + start_ip_routing(); + } + } + } } } void routing_manager_impl::start_ip_routing() { - std::lock_guard its_lock(pending_sd_offers_mutex_); - if_state_running_ = true; - if (discovery_) { discovery_->start(); } else { @@ -4001,6 +4090,7 @@ void routing_manager_impl::start_ip_routing() { } pending_sd_offers_.clear(); + routing_running_ = true; VSOMEIP_INFO << VSOMEIP_ROUTING_READY_MESSAGE; } @@ -4367,4 +4457,104 @@ void routing_manager_impl::status_log_timer_cbk( } } +void routing_manager_impl::on_unsubscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + pending_subscription_id_t _unsubscription_id) { + std::shared_ptr its_eventgroup = find_eventgroup(_service, + _instance, _eventgroup); + if (!its_eventgroup) { + VSOMEIP_ERROR << __func__ << ": Received UNSUBSCRIBE_ACK for unknown " + << "eventgroup: (" + << std::hex << std::setw(4) << std::setfill('0') << _client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]"; + return; + } + // there will only be one or zero subscriptions returned here + std::vector its_pending_subscriptions = + its_eventgroup->remove_pending_subscription(_unsubscription_id); + for (const pending_subscription_t& its_sd_message_id : its_pending_subscriptions) { + const pending_subscription_id_t its_subscription_id = its_sd_message_id.pending_subscription_id_; + const client_t its_subscribing_client = its_sd_message_id.subscribing_client_; + const client_t its_offering_client = find_local_client(_service, _instance); + send_subscription(its_offering_client, its_subscribing_client, _service, + _instance, _eventgroup, its_eventgroup->get_major(), + its_subscription_id); + } +} + +void routing_manager_impl::send_unsubscription( + client_t _offering_client, client_t _subscribing_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + pending_subscription_id_t _pending_unsubscription_id) { + if (host_->get_client() == _offering_client) { + auto self = shared_from_this(); + host_->on_subscription(_service, _instance, _eventgroup, + _subscribing_client, false, + [this, self, _service, _instance, _eventgroup, + _subscribing_client, _pending_unsubscription_id, _offering_client] + (const bool _subscription_accepted) { + (void)_subscription_accepted; + try { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_unsubscribe_ack, + std::dynamic_pointer_cast(shared_from_this()), + _offering_client, _service, _instance, + _eventgroup, _pending_unsubscription_id); + io_.post(its_callback); + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << e.what(); + } + } + ); + } else { + stub_->send_unsubscribe(find_local(_offering_client), + _subscribing_client, + _service, _instance, _eventgroup, ANY_EVENT, + _pending_unsubscription_id); + } +} + +void routing_manager_impl::send_subscription( + client_t _offering_client, client_t _subscribing_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, + pending_subscription_id_t _pending_subscription_id) { + if (host_->get_client() == _offering_client) { + auto self = shared_from_this(); + host_->on_subscription(_service, _instance, _eventgroup, + _subscribing_client, true, + [this, self, _service, _instance, + _eventgroup, _subscribing_client, _pending_subscription_id] + (const bool _subscription_accepted) { + try { + if (!_subscription_accepted) { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_subscribe_nack, + std::dynamic_pointer_cast(shared_from_this()), + _subscribing_client, _service, _instance, + _eventgroup, ANY_EVENT, _pending_subscription_id); + io_.post(its_callback); + } else { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_subscribe_ack, + std::dynamic_pointer_cast(shared_from_this()), + _subscribing_client, _service, _instance, + _eventgroup, ANY_EVENT, _pending_subscription_id); + io_.post(its_callback); + } + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << e.what(); + } + }); + } else { // service hosted by local client + stub_->send_subscribe(find_local(_offering_client), + _subscribing_client, + _service, _instance, _eventgroup, + _major, ANY_EVENT, + _pending_subscription_id); + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index f6aa420bc..ca046edb9 100644 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ b/implementation/routing/src/routing_manager_proxy.cpp @@ -596,7 +596,8 @@ void routing_manager_proxy::unsubscribe(client_t _client, service_t _service, sizeof(_eventgroup)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_event, sizeof(_event)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8] = 0; // is_local + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &DEFAULT_SUBSCRIPTION, + sizeof(DEFAULT_SUBSCRIPTION)); // is_local auto its_target = find_local(_service, _instance); if (its_target) { @@ -849,7 +850,6 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, eventgroup_t its_eventgroup; event_t its_event; major_version_t its_major; - uint8_t is_remote_subscriber; client_t routing_host_id = configuration_->get_id(configuration_->get_routing_host()); client_t its_subscriber; bool its_reliable; @@ -1087,10 +1087,10 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, sizeof(its_eventgroup)); std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], sizeof(its_event)); - std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(is_remote_subscriber)); + std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], + sizeof(its_subscription_id)); host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); - if (!is_remote_subscriber) { + if (its_subscription_id == DEFAULT_SUBSCRIPTION) { // Local subscriber: withdraw subscription routing_manager_base::unsubscribe(its_client, its_service, its_instance, its_eventgroup, its_event); } else { @@ -1101,6 +1101,8 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, its_service, its_instance, its_eventgroup, its_event); } + send_unsubscribe_ack(its_service, its_instance, its_eventgroup, + its_subscription_id); } VSOMEIP_INFO << "UNSUBSCRIBE(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" @@ -1108,7 +1110,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." << std::hex << std::setw(4) << std::setfill('0') << its_event << "] " - << (bool)is_remote_subscriber << " " + << (bool)(its_subscription_id != DEFAULT_SUBSCRIPTION) << " " << std::dec << its_remote_subscriber_count; break; @@ -2032,5 +2034,34 @@ void routing_manager_proxy::send_get_offered_services_info(client_t _client, off } } +void routing_manager_proxy::send_unsubscribe_ack( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + pending_subscription_id_t _subscription_id) { + byte_t its_command[VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE]; + const std::uint32_t its_size = VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + + const client_t its_client = get_client(); + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE_ACK; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, + sizeof(its_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], + &_subscription_id, sizeof(_subscription_id)); + + { + std::lock_guard its_lock(sender_mutex_); + if (sender_) { + sender_->send(its_command, sizeof(its_command)); + } + } +} } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 8d484365e..a63642af9 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -400,7 +400,27 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." << std::hex << std::setw(4) << std::setfill('0') << its_event << "]"; break; - + case VSOMEIP_UNSUBSCRIBE_ACK: + if (_size != VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE) { + VSOMEIP_WARNING << "Received a VSOMEIP_UNSUBSCRIBE_ACK command with wrong size ~> skip!"; + break; + } + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_eventgroup)); + std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], + sizeof(its_subscription_id)); + host_->on_unsubscribe_ack(its_client, its_service, + its_instance, its_eventgroup, its_subscription_id); + VSOMEIP_INFO << "UNSUBSCRIBE ACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; + break; case VSOMEIP_SEND: { its_data = &_data[VSOMEIP_COMMAND_PAYLOAD_POS]; its_service = VSOMEIP_BYTES_TO_WORD( @@ -1233,12 +1253,21 @@ void routing_manager_stub::send_subscribe(std::shared_ptr _ta &_subscription_id, sizeof(_subscription_id)); _target->send(its_command, sizeof(its_command)); + } else { + VSOMEIP_WARNING << __func__ << " Couldn't send subscription to local client [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << _event << "]" + << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') + << _client; } } void routing_manager_stub::send_unsubscribe(std::shared_ptr _target, client_t _client, service_t _service, instance_t _instance, - eventgroup_t _eventgroup, event_t _event, bool _is_remote_subscriber) { + eventgroup_t _eventgroup, event_t _event, + pending_subscription_id_t _unsubscription_id) { if (_target) { byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE]; uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE @@ -1256,10 +1285,18 @@ void routing_manager_stub::send_unsubscribe(std::shared_ptr _ sizeof(_eventgroup)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_event, sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_is_remote_subscriber, - sizeof(_is_remote_subscriber)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_unsubscription_id, + sizeof(_unsubscription_id)); _target->send(its_command, sizeof(its_command)); + } else { + VSOMEIP_WARNING << __func__ << " Couldn't send unsubscription to local client [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << _event << "]" + << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') + << _client; } } diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp index 74abfd5c8..f9e8f297c 100644 --- a/implementation/service_discovery/include/service_discovery_host.hpp +++ b/implementation/service_discovery/include/service_discovery_host.hpp @@ -76,12 +76,12 @@ class service_discovery_host { virtual void expire_subscriptions(const boost::asio::ip::address &_address) = 0; virtual void expire_services(const boost::asio::ip::address &_address) = 0; - virtual remote_subscription_state_e on_remote_subscription( + virtual void on_remote_subscription( service_t _service, instance_t _instance, eventgroup_t _eventgroup, const std::shared_ptr &_subscriber, - const std::shared_ptr &_target, - ttl_t _ttl, client_t *_client, - const std::shared_ptr &_sd_message_id) = 0; + const std::shared_ptr &_target, ttl_t _ttl, + const std::shared_ptr &_sd_message_id, + const std::function& _callback) = 0; virtual void on_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp index 039fe7bf6..3cf33969f 100644 --- a/implementation/service_discovery/include/service_discovery_impl.hpp +++ b/implementation/service_discovery/include/service_discovery_impl.hpp @@ -315,10 +315,6 @@ class service_discovery_impl: public service_discovery, void remote_subscription_not_acknowledge_all(); - void remote_subscription_remove( - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - const std::shared_ptr &_subscriber); - bool check_stop_subscribe_subscribe(message_impl::entries_t::const_iterator _iter, message_impl::entries_t::const_iterator _end, const message_impl::options_t& _options) const; diff --git a/implementation/service_discovery/src/message_impl.cpp b/implementation/service_discovery/src/message_impl.cpp index d23bf31c2..f4695a939 100755 --- a/implementation/service_discovery/src/message_impl.cpp +++ b/implementation/service_discovery/src/message_impl.cpp @@ -417,7 +417,7 @@ void message_impl::increase_number_contained_acks() { } bool message_impl::all_required_acks_contained() const { - return number_contained_acks_ == number_required_acks_; + return number_contained_acks_ >= number_required_acks_; } std::unique_lock message_impl::get_message_lock() { diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp index 2d5aafff8..6042526b9 100644 --- a/implementation/service_discovery/src/service_discovery_impl.cpp +++ b/implementation/service_discovery/src/service_discovery_impl.cpp @@ -1237,8 +1237,8 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, if (its_message_response->all_required_acks_contained()) { update_subscription_expiration_timer(its_message_response); serialize_and_send(its_message_response, _sender); - // set required acks to zero to mark message as sent - its_message_response->set_number_required_acks(0); + // set required acks to 0xFF to mark message as sent + its_message_response->set_number_required_acks((std::numeric_limits::max)()); sent = true; } } @@ -1472,31 +1472,31 @@ void service_discovery_impl::process_offerservice_serviceentry( } if (its_subscription->is_acknowledged()) { - if (its_offer_type == remote_offer_type_e::UNRELIABLE && - its_unreliable && its_unreliable->is_connected()) { - // 28 = 16 (subscription) + 12 (option) - check_space(28); - const std::size_t options_size_before = - _resubscribes->back().second->get_options().size(); - if (insert_subscription(_resubscribes->back().second, - _service, _instance, - its_eventgroup.first, - its_subscription, its_offer_type)) { - its_subscription->set_acknowledged(false); - const std::size_t options_size_after = + if (its_offer_type == remote_offer_type_e::UNRELIABLE) { + if (its_unreliable && its_unreliable->is_connected()) { + // 28 = 16 (subscription) + 12 (option) + check_space(28); + const std::size_t options_size_before = _resubscribes->back().second->get_options().size(); - const std::size_t diff = options_size_after - options_size_before; - _resubscribes->back().first = - static_cast( - _resubscribes->back().first + (12u * diff - 12u)); - } else { - _resubscribes->back().first = - static_cast( - _resubscribes->back().first - 28); + if (insert_subscription(_resubscribes->back().second, + _service, _instance, + its_eventgroup.first, + its_subscription, its_offer_type)) { + its_subscription->set_acknowledged(false); + const std::size_t options_size_after = + _resubscribes->back().second->get_options().size(); + const std::size_t diff = options_size_after - options_size_before; + _resubscribes->back().first = + static_cast( + _resubscribes->back().first + (12u * diff - 12u)); + } else { + _resubscribes->back().first = + static_cast( + _resubscribes->back().first - 28); + } } - } else if (its_offer_type == remote_offer_type_e::RELIABLE && - its_reliable) { - if (its_reliable->is_connected()) { + } else if (its_offer_type == remote_offer_type_e::RELIABLE) { + if (its_reliable && its_reliable->is_connected()) { // 28 = 16 (subscription) + 12 (option) check_space(28); const std::size_t options_size_before = @@ -1520,7 +1520,9 @@ void service_discovery_impl::process_offerservice_serviceentry( } else { its_client.second->set_tcp_connection_established(false); // restart TCP endpoint if not connected - its_reliable->restart(); + if (its_reliable) { + its_reliable->restart(); + } } } else if (its_offer_type == remote_offer_type_e::RELIABLE_UNRELIABLE) { if (its_reliable && its_unreliable && @@ -1930,14 +1932,8 @@ void service_discovery_impl::process_eventgroupentry( << _message_id->sender_.to_string(ec) << " session: " << std::hex << std::setw(4) << std::setfill('0') << _message_id->session_; if(its_ttl > 0) { - const std::uint8_t num_overreferenced_options = - static_cast(_entry->get_num_options(1) + - _entry->get_num_options(2) - _options.size()); - if (its_message_response->get_number_required_acks() - - num_overreferenced_options > 0) { - its_message_response->decrease_number_required_acks( - num_overreferenced_options); - } + // set to 0 to ensure an answer containing at least this subscribe_nack is sent out + its_message_response->set_number_required_acks(0); insert_subscription_nack(its_message_response, its_service, its_instance, its_eventgroup, its_counter, its_major, its_reserved); } @@ -2347,7 +2343,6 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service, if (_ttl == 0) { // --> unsubscribe for (const auto &target : its_targets) { if (target.subscriber_) { - remote_subscription_remove(_service, _instance, _eventgroup, target.subscriber_); if (!_is_stop_subscribe_subscribe) { host_->on_unsubscribe(_service, _instance, _eventgroup, target.subscriber_); } @@ -2356,14 +2351,16 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service, return; } - std::lock_guard its_lock(pending_remote_subscriptions_mutex_); for (const auto &target : its_targets) { - if (target.target_) { - client_t its_subscribing_remote_client = VSOMEIP_ROUTING_CLIENT; - switch (host_->on_remote_subscription(_service, _instance, - _eventgroup, target.subscriber_, target.target_, - _ttl * get_ttl_factor(_service, _instance, ttl_factor_subscriptions_), - &its_subscribing_remote_client, _message_id)) { + if (!target.target_) { + continue; + } + host_->on_remote_subscription(_service, _instance, + _eventgroup, target.subscriber_, target.target_, + _ttl * get_ttl_factor(_service, _instance, ttl_factor_subscriptions_), + _message_id, + [&](remote_subscription_state_e _rss, client_t _subscribing_remote_client) { + switch (_rss) { case remote_subscription_state_e::SUBSCRIPTION_ACKED: insert_subscription_ack(its_message, _service, _instance, _eventgroup, its_info, _ttl, @@ -2396,15 +2393,16 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service, subscriber_->reserved_ = _reserved; subscriber_->counter_ = _counter; + std::lock_guard its_lock(pending_remote_subscriptions_mutex_); pending_remote_subscriptions_[_service] [_instance] [_eventgroup] - [its_subscribing_remote_client].push_back(subscriber_); + [_subscribing_remote_client].push_back(subscriber_); } default: break; } - } + }); } } } @@ -3410,8 +3408,8 @@ void service_discovery_impl::remote_subscription_acknowledge_subscriber( if (its_response->all_required_acks_contained()) { update_subscription_expiration_timer(its_response); serialize_and_send(its_response, _subscriber->response_message_id_->sender_); - // set required acks to zero to mark message as sent - its_response->set_number_required_acks(0); + // set required acks to 0xFF to mark message as sent + its_response->set_number_required_acks((std::numeric_limits::max)()); sent = true; } } @@ -3517,48 +3515,6 @@ void service_discovery_impl::remote_subscription_not_acknowledge_all() { } } -void service_discovery_impl::remote_subscription_remove( - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - const std::shared_ptr &_subscriber) { - std::lock_guard its_lock(pending_remote_subscriptions_mutex_); - const auto its_service = pending_remote_subscriptions_.find(_service); - if (its_service != pending_remote_subscriptions_.end()) { - const auto its_instance = its_service->second.find(_instance); - if (its_instance != its_service->second.end()) { - const auto its_eventgroup = its_instance->second.find(_eventgroup); - if (its_eventgroup != its_instance->second.end()) { - for (auto client_iter = its_eventgroup->second.begin(); - client_iter != its_eventgroup->second.end(); ) { - for (auto subscriber_iter = client_iter->second.begin(); - subscriber_iter != client_iter->second.end();) { - if ((*subscriber_iter)->subscriber == _subscriber) { - (*subscriber_iter)->response_message_id_->response_->decrease_number_required_acks(); - subscriber_iter = client_iter->second.erase( - subscriber_iter); - } else { - ++subscriber_iter; - } - } - if (!client_iter->second.size()) { - client_iter = its_eventgroup->second.erase(client_iter); - } else { - ++client_iter; - } - } - if (!its_eventgroup->second.size()) { - its_instance->second.erase(its_eventgroup); - if (!its_service->second.size()) { - its_service->second.erase(its_instance); - if (!its_service->second.size()) { - pending_remote_subscriptions_.erase(its_service); - } - } - } - } - } - } -} - bool service_discovery_impl::check_stop_subscribe_subscribe( message_impl::entries_t::const_iterator _iter, message_impl::entries_t::const_iterator _end, diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp index ac55fdbef..b0ff36076 100644 --- a/implementation/utility/include/utility.hpp +++ b/implementation/utility/include/utility.hpp @@ -124,11 +124,12 @@ class utility { } private: - static bool is_bigger_last_assigned_client_id(client_t _client); - static void set_client_id_lowbyte(client_t _client); + static bool is_bigger_last_assigned_client_id(client_t _client, std::uint16_t _diagnosis_mask); + static void set_max_assigned_client_id_without_diagnosis(client_t _client); static void check_client_id_consistency(); static uint16_t its_configuration_refs__; + static std::uint16_t* used_client_ids__; }; } // namespace vsomeip diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp index 81d8abaa7..a241618e4 100644 --- a/implementation/utility/src/utility.cpp +++ b/implementation/utility/src/utility.cpp @@ -89,6 +89,8 @@ configuration_data_t *utility::the_configuration_data__(nullptr); CriticalSection utility::its_local_configuration_mutex__; // number of times auto_configuration_init() has been called in this process uint16_t utility::its_configuration_refs__(0); +// pointer to used client IDs array in shared memory +std::uint16_t* utility::used_client_ids__(0); #ifdef _WIN32 // global (inter-process) mutex @@ -100,6 +102,8 @@ static HANDLE its_descriptor(INVALID_HANDLE_VALUE); bool utility::auto_configuration_init(const std::shared_ptr &_config) { std::unique_lock its_lock(its_local_configuration_mutex__); + const size_t its_shm_size = sizeof(configuration_data_t) + + static_cast(~_config->get_diagnosis_mask()) * sizeof(client_t); #ifdef _WIN32 if (its_configuration_refs__ > 0) { assert(configuration_data_mutex != INVALID_HANDLE_VALUE); @@ -126,7 +130,7 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) - sizeof(configuration_data_t), // maximum object size (low-order DWORD) + its_shm_size, // maximum object size (low-order DWORD) utility::get_shm_name(_config).c_str());// name of mapping object if (its_descriptor && GetLastError() == ERROR_ALREADY_EXISTS) { @@ -135,7 +139,7 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, - sizeof(configuration_data_t)); + its_shm_size); if (its_segment) { the_configuration_data__ @@ -165,7 +169,7 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) - sizeof(configuration_data_t), // maximum object size (low-order DWORD) + its_shm_size, // maximum object size (low-order DWORD) utility::get_shm_name(_config).c_str());// name of mapping object if (its_descriptor) { @@ -173,20 +177,22 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, - sizeof(configuration_data_t)); + its_shm_size); if (its_segment) { the_configuration_data__ = reinterpret_cast(its_segment); the_configuration_data__->client_base_ - = static_cast(_config->get_diagnosis_address() << 8); - the_configuration_data__->used_client_ids_[0] - = the_configuration_data__->client_base_; - the_configuration_data__->client_base_++; + = static_cast((_config->get_diagnosis_address() << 8) & _config->get_diagnosis_mask()); + the_configuration_data__->max_clients_ = static_cast(~_config->get_diagnosis_mask()); the_configuration_data__->max_used_client_ids_index_ = 1; - the_configuration_data__->max_assigned_client_id_low_byte_ = 0x00; - + the_configuration_data__->max_assigned_client_id_without_diagnosis_ = 0x00; the_configuration_data__->routing_manager_host_ = 0x0000; + // the clientid array starts right after the routing_manager_host_ struct member + used_client_ids__ = reinterpret_cast( + reinterpret_cast(&the_configuration_data__->routing_manager_host_) + sizeof(unsigned short)); + used_client_ids__[0] = the_configuration_data__->client_base_; + the_configuration_data__->client_base_++; std::string its_name = _config->get_routing_host(); if (its_name == "") the_configuration_data__->routing_manager_host_ = the_configuration_data__->client_base_; @@ -224,11 +230,11 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con static_cast(_config->get_permissions_shm())); ::umask(previous_mask); if (its_descriptor > -1) { - if (-1 == ftruncate(its_descriptor, sizeof(configuration_data_t))) { + if (-1 == ftruncate(its_descriptor, its_shm_size)) { VSOMEIP_ERROR << "utility::auto_configuration_init: " "ftruncate failed: " << std::strerror(errno); } else { - void *its_segment = mmap(0, sizeof(configuration_data_t), + void *its_segment = mmap(0, its_shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, its_descriptor, 0); if(MAP_FAILED == its_segment) { @@ -264,14 +270,17 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con } the_configuration_data__->client_base_ - = static_cast(_config->get_diagnosis_address() << 8); - the_configuration_data__->used_client_ids_[0] - = the_configuration_data__->client_base_; - the_configuration_data__->client_base_++; + = static_cast((_config->get_diagnosis_address() << 8) & _config->get_diagnosis_mask()); + the_configuration_data__->max_clients_ = static_cast(~_config->get_diagnosis_mask()); the_configuration_data__->max_used_client_ids_index_ = 1; - the_configuration_data__->max_assigned_client_id_low_byte_ = 0x00; - + the_configuration_data__->max_assigned_client_id_without_diagnosis_ = 0x00; the_configuration_data__->routing_manager_host_ = 0x0000; + // the clientid array starts right after the routing_manager_host_ struct member + used_client_ids__ = reinterpret_cast( + reinterpret_cast(&the_configuration_data__->routing_manager_host_) + sizeof(unsigned short)); + used_client_ids__[0] = the_configuration_data__->client_base_; + the_configuration_data__->client_base_++; + std::string its_name = _config->get_routing_host(); its_configuration_refs__++; @@ -301,11 +310,11 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con } else { // truncate to make sure we work on valid shm; // in case creator already called truncate, this effectively becomes a noop - if (-1 == ftruncate(its_descriptor, sizeof(configuration_data_t))) { + if (-1 == ftruncate(its_descriptor, its_shm_size)) { VSOMEIP_ERROR << "utility::auto_configuration_init: " "ftruncate failed: " << std::strerror(errno); } else { - void *its_segment = mmap(0, sizeof(configuration_data_t), + void *its_segment = mmap(0, its_shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, its_descriptor, 0); if(MAP_FAILED == its_segment) { @@ -334,6 +343,9 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con } } its_configuration_refs__++; + used_client_ids__ = reinterpret_cast( + reinterpret_cast(&the_configuration_data__->routing_manager_host_) + + sizeof(unsigned short)); pthread_mutex_unlock(&the_configuration_data__->mutex_); } @@ -352,6 +364,8 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con void utility::auto_configuration_exit(client_t _client, const std::shared_ptr &_config) { std::unique_lock its_lock(its_local_configuration_mutex__); + const size_t its_shm_size = sizeof(configuration_data_t) + + static_cast(~_config->get_diagnosis_mask()) * sizeof(client_t); if (the_configuration_data__) { #ifdef _WIN32 // not manipulating data in shared memory, no need to take global mutex @@ -368,6 +382,7 @@ void utility::auto_configuration_exit(client_t _client, if (its_configuration_refs__ == 0) { UnmapViewOfFile(the_configuration_data__); the_configuration_data__ = nullptr; + used_client_ids__ = nullptr; CloseHandle(its_descriptor); its_descriptor = NULL; @@ -385,13 +400,14 @@ void utility::auto_configuration_exit(client_t _client, } if (its_configuration_refs__ == 0) { - if (-1 == ::munmap(the_configuration_data__, sizeof(configuration_data_t))) { + if (-1 == ::munmap(the_configuration_data__, its_shm_size)) { VSOMEIP_ERROR << "utility::auto_configuration_exit: " "munmap failed: " << std::strerror(errno); } else { VSOMEIP_INFO << "utility::auto_configuration_exit: " "munmap succeeded."; the_configuration_data__ = nullptr; + used_client_ids__ = nullptr; if (unlink_shm) { shm_unlink(utility::get_shm_name(_config).c_str()); } @@ -407,7 +423,7 @@ bool utility::is_used_client_id(client_t _client, for (int i = 0; i < the_configuration_data__->max_used_client_ids_index_; i++) { - if (the_configuration_data__->used_client_ids_[i] == _client) { + if (used_client_ids__[i] == _client) { return true; } } @@ -448,7 +464,7 @@ std::set utility::get_used_client_ids() { for (int i = 1; i < the_configuration_data__->max_used_client_ids_index_; i++) { - clients.insert(the_configuration_data__->used_client_ids_[i]); + clients.insert(used_client_ids__[i]); } #ifdef _WIN32 @@ -514,9 +530,10 @@ client_t utility::request_client_id(const std::shared_ptr &_confi } if (the_configuration_data__->max_used_client_ids_index_ - == VSOMEIP_MAX_CLIENTS) { + == the_configuration_data__->max_clients_) { VSOMEIP_ERROR << "Max amount of possible concurrent active" - << " vsomeip applications reached."; + << " vsomeip applications reached (" << std::dec << + the_configuration_data__->max_clients_ << ")."; #ifdef _WIN32 BOOL releaseResult = ReleaseMutex(configuration_data_mutex); assert(releaseResult); @@ -561,17 +578,19 @@ client_t utility::request_client_id(const std::shared_ptr &_confi } int increase_count = 0; while (is_used_client_id(_client, _config) - || !is_bigger_last_assigned_client_id(_client) + || !is_bigger_last_assigned_client_id(_client, _config->get_diagnosis_mask()) || _config->is_configured_client_id(_client)) { - if ((_client & 0xFF) + 1 > VSOMEIP_MAX_CLIENTS) { + if ((_client & the_configuration_data__->max_clients_) + + 1 > the_configuration_data__->max_clients_) { _client = the_configuration_data__->client_base_; - the_configuration_data__->max_assigned_client_id_low_byte_ = 0; + the_configuration_data__->max_assigned_client_id_without_diagnosis_ = 0; } else { _client++; increase_count++; - if (increase_count > VSOMEIP_MAX_CLIENTS) { + if (increase_count > the_configuration_data__->max_clients_) { VSOMEIP_ERROR << "Max amount of possible concurrent active" - << " vsomeip applications reached."; + << " vsomeip applications reached (" << std::dec << + the_configuration_data__->max_clients_ << ")."; #ifdef _WIN32 BOOL releaseResult = ReleaseMutex(configuration_data_mutex); assert(releaseResult); @@ -583,7 +602,7 @@ client_t utility::request_client_id(const std::shared_ptr &_confi } } } - set_client_id_lowbyte(_client); + set_max_assigned_client_id_without_diagnosis(_client); } if (set_client_as_manager_host) { @@ -593,8 +612,7 @@ client_t utility::request_client_id(const std::shared_ptr &_confi #endif } - the_configuration_data__->used_client_ids_[ - the_configuration_data__->max_used_client_ids_index_] = _client; + used_client_ids__[the_configuration_data__->max_used_client_ids_index_] = _client; the_configuration_data__->max_used_client_ids_index_++; @@ -626,15 +644,14 @@ void utility::release_client_id(client_t _client) { #endif int i = 0; for (; i < the_configuration_data__->max_used_client_ids_index_; i++) { - if (the_configuration_data__->used_client_ids_[i] == _client) { + if (used_client_ids__[i] == _client) { break; } } if (i < the_configuration_data__->max_used_client_ids_index_) { for (; i < (the_configuration_data__->max_used_client_ids_index_ - 1); i++) { - the_configuration_data__->used_client_ids_[i] - = the_configuration_data__->used_client_ids_[i+1]; + used_client_ids__[i] = used_client_ids__[i+1]; } the_configuration_data__->max_used_client_ids_index_--; } @@ -702,25 +719,27 @@ void utility::set_routing_manager_host(client_t _client) { #endif } -bool utility::is_bigger_last_assigned_client_id(client_t _client) { +bool utility::is_bigger_last_assigned_client_id(client_t _client, std::uint16_t _diagnosis_mask) { return _client - > ((the_configuration_data__->client_base_ & 0xFF00) - + the_configuration_data__->max_assigned_client_id_low_byte_); + > ((the_configuration_data__->client_base_ & _diagnosis_mask) + + the_configuration_data__->max_assigned_client_id_without_diagnosis_); } -void utility::set_client_id_lowbyte(client_t _client) { - const unsigned char its_low_byte = - static_cast(_client & 0xFF); - the_configuration_data__->max_assigned_client_id_low_byte_ = its_low_byte - % VSOMEIP_MAX_CLIENTS; +void utility::set_max_assigned_client_id_without_diagnosis(client_t _client) { + const std::uint16_t its_client_id_without_diagnosis = + static_cast(_client + & the_configuration_data__->max_clients_); + the_configuration_data__->max_assigned_client_id_without_diagnosis_ = + static_cast(its_client_id_without_diagnosis + % the_configuration_data__->max_clients_); } void utility::check_client_id_consistency() { if (1 < the_configuration_data__->max_used_client_ids_index_) { - client_t prevID = the_configuration_data__->used_client_ids_[0]; + client_t prevID = used_client_ids__[0]; int i = 1; for (; i < the_configuration_data__->max_used_client_ids_index_; i++) { - const client_t currID = the_configuration_data__->used_client_ids_[i]; + const client_t currID = used_client_ids__[i]; if (prevID == currID) { break; } @@ -729,8 +748,7 @@ void utility::check_client_id_consistency() { if (i < the_configuration_data__->max_used_client_ids_index_) { for (; i < (the_configuration_data__->max_used_client_ids_index_ - 1); i++) { - the_configuration_data__->used_client_ids_[i] - = the_configuration_data__->used_client_ids_[i+1]; + used_client_ids__[i] = used_client_ids__[i+1]; } the_configuration_data__->max_used_client_ids_index_--; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 92a2461c0..fd70df6c1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1202,6 +1202,26 @@ if(NOT ${TESTS_BAT}) ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY_CONFIG_FILE} ${TEST_CLIENT_ID_UTILITY} ) + set(TEST_CLIENT_ID_UTILITY_MASKED_511_CONFIG_FILE ${TEST_CLIENT_ID_NAME}_utility_masked_511.json) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_UTILITY_MASKED_511_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY_MASKED_511_CONFIG_FILE} + ${TEST_CLIENT_ID_UTILITY} + ) + + set(TEST_CLIENT_ID_UTILITY_MASKED_4095_CONFIG_FILE ${TEST_CLIENT_ID_NAME}_utility_masked_4095.json) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_UTILITY_MASKED_4095_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY_MASKED_4095_CONFIG_FILE} + ${TEST_CLIENT_ID_UTILITY} + ) + + set(TEST_CLIENT_ID_UTILITY_MASKED_127_CONFIG_FILE ${TEST_CLIENT_ID_NAME}_utility_masked_127.json) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_UTILITY_MASKED_127_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY_MASKED_127_CONFIG_FILE} + ${TEST_CLIENT_ID_UTILITY} + ) # copy starter scripts into builddir set(TEST_CLIENT_ID_MASTER_STARTER ${TEST_CLIENT_ID_NAME}_master_starter.sh) @@ -2139,6 +2159,126 @@ if(NOT ${TESTS_BAT}) ) endif() +############################################################################## +# pending subscription tests tests +############################################################################## +if(NOT ${TESTS_BAT}) + set(TEST_PENDING_SUBSCRIPTION_NAME pending_subscription_test) + set(TEST_PENDING_SUBSCRIPTION_SERVICE ${TEST_PENDING_SUBSCRIPTION_NAME}_service) + add_executable(${TEST_PENDING_SUBSCRIPTION_SERVICE} pending_subscription_tests/${TEST_PENDING_SUBSCRIPTION_NAME}_service.cpp) + target_link_libraries(${TEST_PENDING_SUBSCRIPTION_SERVICE} + vsomeip + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ) + + file(GLOB sd_sources + "../implementation/service_discovery/src/*entry*.cpp" + "../implementation/service_discovery/src/*option*.cpp" + "../implementation/service_discovery/src/*message*.cpp" + ) + set(TEST_PENDING_SUBSCRIPTION_CLIENT ${TEST_PENDING_SUBSCRIPTION_NAME}_sd_msg_sender) + add_executable(${TEST_PENDING_SUBSCRIPTION_CLIENT} + pending_subscription_tests/${TEST_PENDING_SUBSCRIPTION_NAME}_sd_msg_sender.cpp + ${PROJECT_SOURCE_DIR}/implementation/message/src/deserializer.cpp + ${PROJECT_SOURCE_DIR}/implementation/message/src/message_impl.cpp + ${PROJECT_SOURCE_DIR}/implementation/message/src/payload_impl.cpp + ${sd_sources} + ) + + target_link_libraries(${TEST_PENDING_SUBSCRIPTION_CLIENT} + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + vsomeip + vsomeip-sd + ) + + # copy starter scripts into builddir + set(TEST_PENDING_SUBSCRIPTION_MASTER_STARTER ${TEST_PENDING_SUBSCRIPTION_NAME}_master_starter.sh) + configure_file( + ${PROJECT_SOURCE_DIR}/test/pending_subscription_tests/conf/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER}.in + ${PROJECT_SOURCE_DIR}/test/pending_subscription_tests/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} + @ONLY) + copy_to_builddir(${PROJECT_SOURCE_DIR}/test/pending_subscription_tests/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} + ${PROJECT_BINARY_DIR}/test/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} + ${TEST_PENDING_SUBSCRIPTION_SERVICE} + ) + + # Copy config file for local test into $BUILDDIR/test + set(TEST_PENDING_SUBSCRIPTION_CONFIG_FILE ${TEST_PENDING_SUBSCRIPTION_NAME}_master.json) + configure_file( + ${PROJECT_SOURCE_DIR}/test/pending_subscription_tests/conf/${TEST_PENDING_SUBSCRIPTION_CONFIG_FILE}.in + ${PROJECT_SOURCE_DIR}/test/pending_subscription_tests/${TEST_PENDING_SUBSCRIPTION_CONFIG_FILE} + @ONLY) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/pending_subscription_tests/${TEST_PENDING_SUBSCRIPTION_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_PENDING_SUBSCRIPTION_CONFIG_FILE} + ${TEST_PENDING_SUBSCRIPTION_SERVICE} + ) +endif() + +############################################################################## +# malicious data tests +############################################################################## +if(NOT ${TESTS_BAT}) + set(TEST_MALICIOUS_DATA_NAME malicious_data_test) + set(TEST_MALICIOUS_DATA_SERVICE ${TEST_MALICIOUS_DATA_NAME}_service) + add_executable(${TEST_MALICIOUS_DATA_SERVICE} malicious_data_tests/${TEST_MALICIOUS_DATA_NAME}_service.cpp) + target_link_libraries(${TEST_MALICIOUS_DATA_SERVICE} + vsomeip + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ) + + file(GLOB sd_sources + "../implementation/service_discovery/src/*entry*.cpp" + "../implementation/service_discovery/src/*option*.cpp" + "../implementation/service_discovery/src/*message*.cpp" + ) + set(TEST_MALICIOUS_DATA_CLIENT ${TEST_MALICIOUS_DATA_NAME}_msg_sender) + add_executable(${TEST_MALICIOUS_DATA_CLIENT} + malicious_data_tests/${TEST_MALICIOUS_DATA_CLIENT}.cpp + ${PROJECT_SOURCE_DIR}/implementation/message/src/deserializer.cpp + ${PROJECT_SOURCE_DIR}/implementation/message/src/message_impl.cpp + ${PROJECT_SOURCE_DIR}/implementation/message/src/payload_impl.cpp + ${sd_sources} + ) + + target_link_libraries(${TEST_MALICIOUS_DATA_CLIENT} + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + vsomeip + vsomeip-sd + ) + + # copy starter scripts into builddir + set(TEST_MALICIOUS_DATA_MASTER_STARTER ${TEST_MALICIOUS_DATA_NAME}_master_starter.sh) + configure_file( + ${PROJECT_SOURCE_DIR}/test/malicious_data_tests/conf/${TEST_MALICIOUS_DATA_MASTER_STARTER}.in + ${PROJECT_SOURCE_DIR}/test/malicious_data_tests/${TEST_MALICIOUS_DATA_MASTER_STARTER} + @ONLY) + copy_to_builddir(${PROJECT_SOURCE_DIR}/test/malicious_data_tests/${TEST_MALICIOUS_DATA_MASTER_STARTER} + ${PROJECT_BINARY_DIR}/test/${TEST_MALICIOUS_DATA_MASTER_STARTER} + ${TEST_MALICIOUS_DATA_SERVICE} + ) + + # Copy config file for local test into $BUILDDIR/test + set(TEST_MALICIOUS_DATA_CONFIG_FILE ${TEST_MALICIOUS_DATA_NAME}_master.json) + configure_file( + ${PROJECT_SOURCE_DIR}/test/malicious_data_tests/conf/${TEST_MALICIOUS_DATA_CONFIG_FILE}.in + ${PROJECT_SOURCE_DIR}/test/malicious_data_tests/${TEST_MALICIOUS_DATA_CONFIG_FILE} + @ONLY) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/malicious_data_tests/${TEST_MALICIOUS_DATA_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_MALICIOUS_DATA_CONFIG_FILE} + ${TEST_MALICIOUS_DATA_SERVICE} + ) +endif() + ############################################################################## # Add for every test a dependency to gtest ############################################################################## @@ -2178,6 +2318,10 @@ if(NOT ${TESTS_BAT}) add_dependencies(${TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER} gtest) add_dependencies(${TEST_OFFERED_SERVICES_INFO_CLIENT} gtest) add_dependencies(${TEST_OFFERED_SERVICES_INFO_SERVICE} gtest) + add_dependencies(${TEST_PENDING_SUBSCRIPTION_SERVICE} gtest) + add_dependencies(${TEST_PENDING_SUBSCRIPTION_CLIENT} gtest) + add_dependencies(${TEST_MALICIOUS_DATA_SERVICE} gtest) + add_dependencies(${TEST_MALICIOUS_DATA_CLIENT} gtest) else() add_dependencies(${TEST_LOCAL_ROUTING_SERVICE} gtest) add_dependencies(${TEST_LOCAL_ROUTING_CLIENT} gtest) @@ -2230,6 +2374,10 @@ if(NOT ${TESTS_BAT}) endif() add_dependencies(build_tests ${TEST_OFFERED_SERVICES_INFO_CLIENT}) add_dependencies(build_tests ${TEST_OFFERED_SERVICES_INFO_SERVICE}) + add_dependencies(build_tests ${TEST_PENDING_SUBSCRIPTION_SERVICE}) + add_dependencies(build_tests ${TEST_PENDING_SUBSCRIPTION_CLIENT}) + add_dependencies(build_tests ${TEST_MALICIOUS_DATA_SERVICE}) + add_dependencies(build_tests ${TEST_MALICIOUS_DATA_CLIENT}) else() add_dependencies(build_tests ${TEST_LOCAL_ROUTING_SERVICE}) add_dependencies(build_tests ${TEST_LOCAL_ROUTING_CLIENT}) @@ -2374,6 +2522,27 @@ if(NOT ${TESTS_BAT}) "VSOMEIP_CONFIGURATION=${TEST_CLIENT_ID_UTILITY_CONFIG_FILE}") set_tests_properties(${TEST_CLIENT_ID_UTILITY} PROPERTIES TIMEOUT 120) + add_test(NAME ${TEST_CLIENT_ID_UTILITY}_masked_511 + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY}) + set_property(TEST ${TEST_CLIENT_ID_UTILITY}_masked_511 + APPEND PROPERTY ENVIRONMENT + "VSOMEIP_CONFIGURATION=${TEST_CLIENT_ID_UTILITY_MASKED_511_CONFIG_FILE}") + set_tests_properties(${TEST_CLIENT_ID_UTILITY} PROPERTIES TIMEOUT 120) + + add_test(NAME ${TEST_CLIENT_ID_UTILITY}_masked_4095 + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY}) + set_property(TEST ${TEST_CLIENT_ID_UTILITY}_masked_4095 + APPEND PROPERTY ENVIRONMENT + "VSOMEIP_CONFIGURATION=${TEST_CLIENT_ID_UTILITY_MASKED_4095_CONFIG_FILE}") + set_tests_properties(${TEST_CLIENT_ID_UTILITY} PROPERTIES TIMEOUT 120) + + add_test(NAME ${TEST_CLIENT_ID_UTILITY}_masked_127 + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_UTILITY}) + set_property(TEST ${TEST_CLIENT_ID_UTILITY}_masked_127 + APPEND PROPERTY ENVIRONMENT + "VSOMEIP_CONFIGURATION=${TEST_CLIENT_ID_UTILITY_MASKED_127_CONFIG_FILE}") + set_tests_properties(${TEST_CLIENT_ID_UTILITY} PROPERTIES TIMEOUT 120) + # subscribe notify tests add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_udp COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}) @@ -2633,6 +2802,28 @@ if(NOT ${TESTS_BAT}) COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SECURITY_SERVICE_START_SCRIPT} ) endif() + + # pending subscriptions test + add_test(NAME ${TEST_PENDING_SUBSCRIPTION_NAME}_subscribe + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} SUBSCRIBE) + set_tests_properties(${TEST_PENDING_SUBSCRIPTION_NAME}_subscribe PROPERTIES TIMEOUT 180) + + add_test(NAME ${TEST_PENDING_SUBSCRIPTION_NAME}_alternating_subscribe_unsubscribe + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} SUBSCRIBE_UNSUBSCRIBE) + set_tests_properties(${TEST_PENDING_SUBSCRIPTION_NAME}_alternating_subscribe_unsubscribe PROPERTIES TIMEOUT 180) + + add_test(NAME ${TEST_PENDING_SUBSCRIPTION_NAME}_unsubscribe + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} UNSUBSCRIBE) + set_tests_properties(${TEST_PENDING_SUBSCRIPTION_NAME}_unsubscribe PROPERTIES TIMEOUT 180) + + add_test(NAME ${TEST_PENDING_SUBSCRIPTION_NAME}_alternating_subscribe_unsubscribe_nack + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_PENDING_SUBSCRIPTION_MASTER_STARTER} SUBSCRIBE_UNSUBSCRIBE_NACK) + set_tests_properties(${TEST_PENDING_SUBSCRIPTION_NAME}_alternating_subscribe_unsubscribe_nack PROPERTIES TIMEOUT 180) + + # malicious data test + add_test(NAME ${TEST_MALICIOUS_DATA_NAME} + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_MALICIOUS_DATA_MASTER_STARTER}) + set_tests_properties(${TEST_MALICIOUS_DATA_NAME} PROPERTIES TIMEOUT 180) else() # Routing tests add_test(NAME ${TEST_LOCAL_ROUTING_NAME} diff --git a/test/client_id_tests/client_id_test_utility.cpp b/test/client_id_tests/client_id_test_utility.cpp index 887646ff4..15121466d 100644 --- a/test/client_id_tests/client_id_test_utility.cpp +++ b/test/client_id_tests/client_id_test_utility.cpp @@ -20,22 +20,27 @@ static const std::string APPLICATION_NAME_ROUTING_MANAGER = "vsomeipd"; static const std::string APPLICATION_NAME_NOT_PREDEFINED = "test-application-name"; +vsomeip::client_t CLIENT_ID_ROUTING_MANAGER = 0xFFFF; + static const std::string APPLICATION_IN_NAME = "client_id_test_utility_service_in"; -static const vsomeip::client_t APPLICATION_IN_CLIENT_ID = 0x6311; +static vsomeip::client_t APPLICATION_IN_CLIENT_ID = 0xFFFF; static const std::string APPLICATION_IN_NAME_TWO = "client_id_test_utility_service_in_two"; -static const vsomeip::client_t APPLICATION_IN_CLIENT_ID_TWO = 0x6312; +static vsomeip::client_t APPLICATION_IN_CLIENT_ID_TWO = 0xFFFF; static const std::string APPLICATION_OUT_LOW_NAME = "client_id_test_utility_service_out_low"; -static const vsomeip::client_t APPLICATION_OUT_LOW_CLIENT_ID = 0x6011; +static const vsomeip::client_t APPLICATION_OUT_LOW_CLIENT_ID = 0x5911; 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; +static const vsomeip::client_t APPLICATION_OUT_HIGH_CLIENT_ID = 0x7411; class client_id_utility_test: public ::testing::Test { public: client_id_utility_test() : - client_id_routing_manager_(0x0) { + client_id_routing_manager_(0x0), + diagnosis_(0x0), + diagnosis_mask_(0xFF00), + client_id_base_(0x0) { std::shared_ptr its_configuration; auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( @@ -49,13 +54,21 @@ class client_id_utility_test: public ::testing::Test { ASSERT_FALSE(file_exist(std::string("/dev/shm").append(utility::get_shm_name(configuration_)))); ASSERT_TRUE(static_cast(configuration_)); configuration_->load(APPLICATION_NAME_ROUTING_MANAGER); + diagnosis_mask_ = configuration_->get_diagnosis_mask(); + diagnosis_ = configuration_->get_diagnosis_address(); + + // calculate all client IDs based on mask + client_id_base_ = static_cast((diagnosis_ << 8) & diagnosis_mask_); + CLIENT_ID_ROUTING_MANAGER = client_id_base_ | 0x1; + APPLICATION_IN_CLIENT_ID = static_cast(client_id_base_ | 0x11); + APPLICATION_IN_CLIENT_ID_TWO = static_cast(client_id_base_ | 0x12); utility::auto_configuration_init(configuration_); 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); - EXPECT_EQ(0x6301, client_id_routing_manager_); + EXPECT_EQ(client_id_base_ | 0x1, client_id_routing_manager_); EXPECT_TRUE(utility::is_routing_manager_host(client_id_routing_manager_)); } @@ -81,12 +94,15 @@ class client_id_utility_test: public ::testing::Test { protected: std::shared_ptr configuration_; vsomeip::client_t client_id_routing_manager_; + std::uint16_t diagnosis_; + std::uint16_t diagnosis_mask_; + client_t client_id_base_; }; TEST_F(client_id_utility_test, request_release_client_id) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6302, its_client_id); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id); utility::release_client_id(its_client_id); } @@ -94,11 +110,11 @@ TEST_F(client_id_utility_test, request_release_client_id) { TEST_F(client_id_utility_test, request_client_id_twice) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6302, its_client_id); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id); client_t its_client_id_2 = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6303, its_client_id_2); + EXPECT_EQ(client_id_base_ | 0x3, its_client_id_2); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -107,14 +123,14 @@ TEST_F(client_id_utility_test, request_client_id_twice) { TEST_F(client_id_utility_test, release_unknown_client_id) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6302, its_client_id); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id); utility::release_client_id(0x4711); utility::release_client_id(its_client_id); client_t its_client_id_2 = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6303, its_client_id_2); + EXPECT_EQ(client_id_base_ | 0x3, its_client_id_2); utility::release_client_id(its_client_id_2); } @@ -122,22 +138,24 @@ TEST_F(client_id_utility_test, release_client_id_twice) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6302, its_client_id); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id); client_t its_client_id_2 = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6303, its_client_id_2); + EXPECT_EQ(client_id_base_ | 0x3, its_client_id_2); utility::release_client_id(its_client_id_2); } TEST_F(client_id_utility_test, ensure_preconfigured_client_ids_not_used_for_autoconfig) { - const std::uint8_t limit = APPLICATION_IN_CLIENT_ID & 0xFF; + // request client ids until 10 over the preconfigured one + const std::uint16_t limit = static_cast((APPLICATION_IN_CLIENT_ID & ~diagnosis_mask_) + 10u); + std::vector its_client_ids; - for (int i = 0; i < limit + 10; i++ ) { + for (int i = 0; i < limit; i++ ) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); EXPECT_NE(ILLEGAL_CLIENT, its_client_id); @@ -161,7 +179,7 @@ TEST_F(client_id_utility_test, { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6302, its_client_id); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id); client_t its_client_id2 = utility::request_client_id(configuration_, APPLICATION_IN_NAME, APPLICATION_IN_CLIENT_ID); @@ -174,11 +192,11 @@ TEST_F(client_id_utility_test, client_t its_client_id4 = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6303, its_client_id4); + EXPECT_EQ(client_id_base_ | 0x3, its_client_id4); client_t its_client_id5 = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(0x6304, its_client_id5); + EXPECT_EQ(client_id_base_ | 0x4, its_client_id5); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id2); @@ -204,7 +222,7 @@ TEST_F(client_id_utility_test, client_t its_client_id_2 = utility::request_client_id(configuration_, APPLICATION_IN_NAME, APPLICATION_IN_CLIENT_ID); - EXPECT_EQ(0x6302, its_client_id_2); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id_2); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -213,18 +231,18 @@ TEST_F(client_id_utility_test, TEST_F(client_id_utility_test, request_different_client_id_with_predefined_app_name_in_diagnosis_range) { client_t its_client_id = utility::request_client_id(configuration_, - APPLICATION_IN_NAME, APPLICATION_IN_CLIENT_ID + 1u); + APPLICATION_IN_NAME, static_cast(APPLICATION_IN_CLIENT_ID + 1u)); // has to get predefined client id although other was requested EXPECT_EQ(APPLICATION_IN_CLIENT_ID, its_client_id); // predefined in json is now already used and requested should be assigned client_t its_client_id_2 = utility::request_client_id(configuration_, - APPLICATION_IN_NAME, APPLICATION_IN_CLIENT_ID + 1u); + APPLICATION_IN_NAME, static_cast(APPLICATION_IN_CLIENT_ID + 1u)); EXPECT_EQ(APPLICATION_IN_CLIENT_ID + 1u, its_client_id_2); client_t its_client_id_3 = utility::request_client_id(configuration_, APPLICATION_IN_NAME, APPLICATION_IN_CLIENT_ID); - EXPECT_EQ(0x6302, its_client_id_3); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id_3); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -248,7 +266,7 @@ TEST_F(client_id_utility_test, client_t its_client_id_2 = utility::request_client_id(configuration_, APPLICATION_OUT_LOW_NAME, APPLICATION_OUT_LOW_CLIENT_ID); - EXPECT_EQ(0x6302, its_client_id_2); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id_2); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -268,7 +286,7 @@ TEST_F(client_id_utility_test, client_t its_client_id_3 = utility::request_client_id(configuration_, APPLICATION_OUT_LOW_NAME, APPLICATION_OUT_LOW_CLIENT_ID); - EXPECT_EQ(0x6302, its_client_id_3); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id_3); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -292,7 +310,7 @@ TEST_F(client_id_utility_test, client_t its_client_id_2 = utility::request_client_id(configuration_, APPLICATION_OUT_HIGH_NAME, APPLICATION_OUT_HIGH_CLIENT_ID); - EXPECT_EQ(0x6302, its_client_id_2); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id_2); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -312,7 +330,7 @@ TEST_F(client_id_utility_test, client_t its_client_id_3 = utility::request_client_id(configuration_, APPLICATION_OUT_HIGH_NAME, APPLICATION_OUT_HIGH_CLIENT_ID); - EXPECT_EQ(0x6302, its_client_id_3); + EXPECT_EQ(client_id_base_ | 0x2, its_client_id_3); utility::release_client_id(its_client_id); utility::release_client_id(its_client_id_2); @@ -321,28 +339,30 @@ TEST_F(client_id_utility_test, TEST_F(client_id_utility_test, exhaust_client_id_range_sequential) { - std::vector its_client_ids; + std::vector its_client_ids; - // -1 for the routing manager, -2 as two predefined client IDs are present - // in the json file which aren't assigned via autoconfiguration - std::uint8_t max_allowed_clients = 0xFF - 3; - // acquire maximum amount of client IDs - for (std::uint8_t i = 0; i < max_allowed_clients; i++) { - client_t its_client_id = utility::request_client_id(configuration_, - APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_NE(ILLEGAL_CLIENT, its_client_id); - if (its_client_id != ILLEGAL_CLIENT) { - its_client_ids.push_back(its_client_id); - } else { - ADD_FAILURE() << "Received ILLEGAL_CLIENT " - << static_cast(i); - } - } + const std::uint16_t max_possible_clients = static_cast(~diagnosis_mask_); + // -1 for the routing manager, -2 as two predefined client IDs are present + // in the json file which aren't assigned via autoconfiguration + const std::uint16_t max_allowed_clients = static_cast(max_possible_clients - 3u); - // check limit is reached - client_t its_illegal_client_id = utility::request_client_id(configuration_, - APPLICATION_NAME_NOT_PREDEFINED, 0x0); - EXPECT_EQ(ILLEGAL_CLIENT, its_illegal_client_id); + // acquire maximum amount of client IDs + for (std::uint16_t i = 0; i < max_allowed_clients; i++) { + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, 0x0); + EXPECT_NE(ILLEGAL_CLIENT, its_client_id); + if (its_client_id != ILLEGAL_CLIENT) { + its_client_ids.push_back(its_client_id); + } else { + ADD_FAILURE()<< "Received ILLEGAL_CLIENT " + << static_cast(i); + } + } + + // check limit is reached + client_t its_illegal_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, 0x0); + EXPECT_EQ(ILLEGAL_CLIENT, its_illegal_client_id); // release all for (const client_t c : its_client_ids) { @@ -354,7 +374,7 @@ TEST_F(client_id_utility_test, exhaust_client_id_range_sequential) { // One more time! // acquire maximum amount of client IDs - for (std::uint8_t i = 0; i < max_allowed_clients; i++) { + for (std::uint16_t i = 0; i < max_allowed_clients; i++) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); EXPECT_NE(ILLEGAL_CLIENT, its_client_id); @@ -382,9 +402,11 @@ TEST_F(client_id_utility_test, exhaust_client_id_range_fragmented) { // -1 for the routing manager, -2 as two predefined client IDs are present // in the json file which aren't assigned via autoconfiguration - std::uint8_t max_allowed_clients = 0xFF - 3; + const std::uint16_t max_possible_clients = static_cast(~diagnosis_mask_); + const std::uint16_t max_allowed_clients = static_cast(max_possible_clients - 3u); + // acquire maximum amount of client IDs - for (std::uint8_t i = 0; i < max_allowed_clients; i++) { + for (std::uint16_t i = 0; i < max_allowed_clients; i++) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); EXPECT_NE(ILLEGAL_CLIENT, its_client_id); @@ -420,7 +442,7 @@ TEST_F(client_id_utility_test, exhaust_client_id_range_fragmented) { } // acquire client IDs up to the maximum allowed amount again - for (std::uint8_t i = 0; i < its_released_client_ids.size(); i++) { + for (std::uint16_t i = 0; i < its_released_client_ids.size(); i++) { client_t its_client_id = utility::request_client_id(configuration_, APPLICATION_NAME_NOT_PREDEFINED, 0x0); EXPECT_NE(ILLEGAL_CLIENT, its_client_id); diff --git a/test/client_id_tests/client_id_test_utility.json b/test/client_id_tests/client_id_test_utility.json index ea0aaa075..e928b0597 100644 --- a/test/client_id_tests/client_id_test_utility.json +++ b/test/client_id_tests/client_id_test_utility.json @@ -9,30 +9,27 @@ "enable":"false", "path":"/tmp/vsomeip.log" }, - "dlt":"false" }, - "diagnosis" : "0x63", + "diagnosis":"0x63", "applications": [ { "name":"client_id_test_utility_service_in", "id":"0x6311" }, - { + { "name":"client_id_test_utility_service_in_two", "id":"0x6312" }, { "name":"client_id_test_utility_service_out_low", - "id":"0x6011" + "id":"0x5911" }, - { "name":"client_id_test_utility_service_out_high", - "id":"0x6411" + "id":"0x7411" } ], - "routing":"vsomeipd" -} \ No newline at end of file +} diff --git a/test/client_id_tests/client_id_test_utility_masked_127.json b/test/client_id_tests/client_id_test_utility_masked_127.json new file mode 100644 index 000000000..c7c255bbd --- /dev/null +++ b/test/client_id_tests/client_id_test_utility_masked_127.json @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x63", + "diagnosis_mask":"0xFF80", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6311" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6312" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"vsomeipd" +} diff --git a/test/client_id_tests/client_id_test_utility_masked_4095.json b/test/client_id_tests/client_id_test_utility_masked_4095.json new file mode 100644 index 000000000..dfc42c087 --- /dev/null +++ b/test/client_id_tests/client_id_test_utility_masked_4095.json @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x63", + "diagnosis_mask":"0xF000", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6011" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6012" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"vsomeipd" +} diff --git a/test/client_id_tests/client_id_test_utility_masked_511.json b/test/client_id_tests/client_id_test_utility_masked_511.json new file mode 100644 index 000000000..274a5e00b --- /dev/null +++ b/test/client_id_tests/client_id_test_utility_masked_511.json @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x63", + "diagnosis_mask":"0xFE00", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6211" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6212" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"vsomeipd" +} diff --git a/test/malicious_data_tests/conf/malicious_data_test_master.json.in b/test/malicious_data_tests/conf/malicious_data_test_master.json.in new file mode 100644 index 000000000..066989bd1 --- /dev/null +++ b/test/malicious_data_tests/conf/malicious_data_test_master.json.in @@ -0,0 +1,44 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "applications" : + [ + { + "name" : "malicious_data_test_service", + "id" : "0x4289", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x3345", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + } + ], + "routing":"vsomeipd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.24.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000" + } +} \ No newline at end of file diff --git a/test/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in b/test/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in new file mode 100755 index 000000000..199f31881 --- /dev/null +++ b/test/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in @@ -0,0 +1,66 @@ +#!/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. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=malicious_data_test_master.json +# start daemon +../daemon/./vsomeipd & +PID_VSOMEIPD=$! +# Start the services +./malicious_data_test_service & +PID_SERIVCE=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_external_slave_starter.sh" + 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; ./malicious_data_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker run --name otems --cap-add NET_ADMIN $DOCKER_IMAGE sh -c "route add -net 224.0.0.0/4 dev eth0 && cd $DOCKER_TESTS && sleep 10; ./malicious_data_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@" & +else +cat < +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "../../implementation/utility/include/byteorder.hpp" +#include "../../implementation/message/include/deserializer.hpp" +#include "../../implementation/service_discovery/include/service_discovery.hpp" +#include "../../implementation/service_discovery/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/constants.hpp" +#include "../../implementation/service_discovery/include/enumeration_types.hpp" +#include "../../implementation/service_discovery/include/eventgroupentry_impl.hpp" +#include "../../implementation/message/include/message_impl.hpp" +#include "malicious_data_test_globals.hpp" + +static char* remote_address; +static char* local_address; + +class malicious_data : public ::testing::Test { +public: + malicious_data() : + work_(std::make_shared(io_)), + io_thread_(std::bind(&malicious_data::io_run, this)) {} +protected: + + void TearDown() { + work_.reset(); + io_thread_.join(); + io_.stop(); + } + + void io_run() { + io_.run(); + } + + boost::asio::io_service io_; + std::shared_ptr work_; + std::thread io_thread_; +}; + +TEST_F(malicious_data, send_malicious_events) +{ + std::promise client_subscribed; + + boost::asio::ip::tcp::socket tcp_socket(io_); + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + + std::thread receive_thread([&](){ + std::atomic keep_receiving(true); + std::function receive; + std::vector receive_buffer(4096); + std::vector its_received_events; + + const std::function receive_cbk = [&]( + const boost::system::error_code& error, std::size_t bytes_transferred) { + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_SERVICE_POS_MIN], + receive_buffer[VSOMEIP_SERVICE_POS_MAX]); + vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_METHOD_POS_MIN], + receive_buffer[VSOMEIP_METHOD_POS_MAX]); + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (auto e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr its_casted_entry = + std::static_pointer_cast(e); + EXPECT_EQ(1u, its_casted_entry->get_eventgroup()); + } + client_subscribed.set_value(true); + keep_receiving = false; + } + } + } + + + }; + + receive = [&]() { + udp_socket.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + receive(); + while(keep_receiving) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + + std::thread send_thread([&]() { + try { + std::promise client_connected; + boost::asio::ip::tcp::socket::endpoint_type local( + boost::asio::ip::address::from_string(std::string(local_address)), + 40001); + boost::asio::ip::tcp::acceptor its_acceptor(io_); + boost::system::error_code ec; + its_acceptor.open(local.protocol(), ec); + boost::asio::detail::throw_error(ec, "acceptor open"); + its_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "acceptor set_option"); + its_acceptor.bind(local, ec); + boost::asio::detail::throw_error(ec, "acceptor bind"); + its_acceptor.listen(boost::asio::socket_base::max_connections, ec); + boost::asio::detail::throw_error(ec, "acceptor listen"); + its_acceptor.async_accept(tcp_socket, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_connected.set_value(true); + } else { + ADD_FAILURE() << "accept_cbk: " << _error.message(); + } + }); + + + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x33, 0x44, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x06, 0x9c, 0x41, + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + + // wait until client established TCP connection + if (std::future_status::timeout == client_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't connect within time"; + } + + // wait until client subscribed + if (std::future_status::timeout == client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + } + + // send malicious data as server + std::uint8_t its_malicious_data[] = { + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x38, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x5f, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x86, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xad, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xd4, 0x8f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xfb, 0x9f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x22, 0xaf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, // payload missing + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0xbf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x70, 0xcf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x45, 0x22, 0x80, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x97, 0xdf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x23, 0x99, 0x00, 0x4e, 0xb3, 0xe4, 0x4e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x22, 0x91, 0x00, 0x4e, 0xb3, 0xe3, 0xd7, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x48, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x21, 0x6c, 0x00, 0x4e, 0xb3, 0xe3, 0x55, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x20, 0x00, 0x44, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x20, 0xa9, 0x00, 0x4e, 0xb3, 0xe3, 0x56, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x34, 0x1f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1f, 0xc6, 0x00, 0x4e, 0xb3, 0xe3, 0x87, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x5b, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1e, 0xf1, 0x00, 0x4e, 0xb3, 0xe3, 0x5e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x82, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xad, 0x00, 0x4e, 0xb3, 0xe3, 0xa8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xa9, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xec, 0x00, 0x4e, 0xb3, 0xe3, 0xd8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, 0xc0, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xd0, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xfa, 0x00, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x19, 0x20, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1e, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x09, 0x80, 0x00, 0x44, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + tcp_socket.send(boost::asio::buffer(its_malicious_data)); + + // establish second tcp connection as client and send malicious data as well + boost::asio::ip::tcp::socket tcp_socket2(io_); + boost::asio::ip::tcp::socket::endpoint_type remote( + boost::asio::ip::address::from_string(std::string(remote_address)), + 40001); + tcp_socket2.open(remote.protocol()); + tcp_socket2.connect(remote); + std::uint8_t its_malicious_client_data[] = { + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x38, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x5f, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x86, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xad, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xd4, 0x8f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xfb, 0x9f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x22, 0xaf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, // payload missing + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0xbf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x70, 0xcf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x45, 0x22, 0x80, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x97, 0xdf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x23, 0x99, 0x00, 0x4e, 0xb3, 0xe4, 0x4e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x22, 0x91, 0x00, 0x4e, 0xb3, 0xe3, 0xd7, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x48, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x21, 0x6c, 0x00, 0x4e, 0xb3, 0xe3, 0x55, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x20, 0x00, 0x44, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x20, 0xa9, 0x00, 0x4e, 0xb3, 0xe3, 0x56, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x34, 0x1f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1f, 0xc6, 0x00, 0x4e, 0xb3, 0xe3, 0x87, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x5b, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1e, 0xf1, 0x00, 0x4e, 0xb3, 0xe3, 0x5e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x82, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xad, 0x00, 0x4e, 0xb3, 0xe3, 0xa8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xa9, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xec, 0x00, 0x4e, 0xb3, 0xe3, 0xd8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, 0xc0, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xd0, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xfa, 0x00, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x19, 0x20, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1e, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x09, 0x80, 0x00, 0x44, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + tcp_socket2.send(boost::asio::buffer(its_malicious_client_data)); + + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x33, 0x45, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (const std::exception& _e) { + std::cout << "catched exception: " << _e.what(); + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); +} + +#ifndef _WIN32 +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + if(argc < 3) { + std::cerr << "Please pass an target and local IP address to this binary like: " + << argv[0] << " 10.0.3.1 10.0.3.202" << std::endl; + exit(1); + } + remote_address = argv[1]; + local_address = argv[2]; + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/malicious_data_tests/malicious_data_test_service.cpp b/test/malicious_data_tests/malicious_data_test_service.cpp new file mode 100644 index 000000000..17a4bb8a6 --- /dev/null +++ b/test/malicious_data_tests/malicious_data_test_service.cpp @@ -0,0 +1,170 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "../../implementation/logging/include/logger.hpp" + +#include "malicious_data_test_globals.hpp" + +class malicious_data_test_service { +public: + malicious_data_test_service(struct malicious_data_test::service_info _service_info, malicious_data_test::test_mode_e _testmode) : + service_info_(_service_info), + testmode_(_testmode), + app_(vsomeip::runtime::get()->create_application("malicious_data_test_service")), + wait_until_registered_(true), + wait_until_shutdown_method_called_(true), + received_events_(0), + received_methodcalls_(0), + offer_thread_(std::bind(&malicious_data_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&malicious_data_test_service::on_state, this, + std::placeholders::_1)); + + std::set its_eventgroups; + its_eventgroups.insert(_service_info.eventgroup_id); + app_->request_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, false); + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id, + std::bind(&malicious_data_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.event_id, + std::bind(&malicious_data_test_service::on_event, this, + std::placeholders::_1)); + + app_->register_message_handler(static_cast(service_info_.service_id + 1u), + service_info_.instance_id, 0x1, + std::bind(&malicious_data_test_service::on_message, this, + std::placeholders::_1)); + + // request service of client + app_->request_service(service_info_.service_id, service_info_.instance_id); + app_->subscribe(service_info_.service_id, service_info_.instance_id, + service_info_.eventgroup_id, 0, vsomeip::subscription_type_e::SU_RELIABLE, + service_info_.event_id); + + app_->start(); + } + + ~malicious_data_test_service() { + EXPECT_EQ(9u, received_events_); + EXPECT_EQ(9u, received_methodcalls_); + offer_thread_.join(); + } + + void offer() { + app_->offer_service(static_cast(service_info_.service_id + 1u), 0x1); + } + + void stop() { + app_->stop_offer_service(static_cast(service_info_.service_id + 1u), 0x1); + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + std::lock_guard its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_event(const std::shared_ptr &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(service_info_.event_id, _message->get_method()); + EXPECT_EQ(std::uint32_t(0x7F), _message->get_length()); + received_events_++; + } + + void on_message(const std::shared_ptr &_message) { + EXPECT_EQ(static_cast(service_info_.service_id + 1u), _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(vsomeip::method_t(0x1), _message->get_method()); + EXPECT_EQ(std::uint32_t(0x7F), _message->get_length()); + received_methodcalls_++; + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + stop(); + } + +private: + struct malicious_data_test::service_info service_info_; + malicious_data_test::test_mode_e testmode_; + std::shared_ptr app_; + + bool wait_until_registered_; + bool wait_until_shutdown_method_called_; + std::uint32_t received_events_; + std::uint32_t received_methodcalls_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; +}; + +malicious_data_test::test_mode_e its_testmode(malicious_data_test::test_mode_e::SUBSCRIBE); + +TEST(someip_malicious_data_test, block_subscription_handler) +{ + malicious_data_test_service its_sample(malicious_data_test::service, its_testmode); +} + + +#ifndef _WIN32 +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/pending_subscription_tests/conf/pending_subscription_test_master.json.in b/test/pending_subscription_tests/conf/pending_subscription_test_master.json.in new file mode 100644 index 000000000..5c363a759 --- /dev/null +++ b/test/pending_subscription_tests/conf/pending_subscription_test_master.json.in @@ -0,0 +1,44 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "applications" : + [ + { + "name" : "pending_subscription_test_service", + "id" : "0xCAFE", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x1122", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + } + ], + "routing":"vsomeipd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.23.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000" + } +} \ No newline at end of file diff --git a/test/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in b/test/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in new file mode 100755 index 000000000..0a3dd17f8 --- /dev/null +++ b/test/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in @@ -0,0 +1,75 @@ +#!/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. + +FAIL=0 + +if [ $# -lt 1 ] +then + echo "Please pass a test mode to this script." + echo "For example: $0 SUSCRIBE" + echo "Valid subscription types include:" + echo " [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE_NACK]" + exit 1 +fi +TESTMODE=$1 +export VSOMEIP_CONFIGURATION=pending_subscription_test_master.json +# start daemon +../daemon/./vsomeipd & +PID_VSOMEIPD=$! +# Start the services +./pending_subscription_test_service $1 & +PID_SERIVCE=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_external_slave_starter.sh" + 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; ./pending_subscription_test_sd_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker run --name otems --cap-add NET_ADMIN $DOCKER_IMAGE sh -c "route add -net 224.0.0.0/4 dev eth0 && cd $DOCKER_TESTS && sleep 10; ./pending_subscription_test_sd_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE" & +else +cat < +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "../../implementation/utility/include/byteorder.hpp" +#include "../../implementation/message/include/deserializer.hpp" +#include "../../implementation/service_discovery/include/service_discovery.hpp" +#include "../../implementation/service_discovery/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/constants.hpp" +#include "../../implementation/service_discovery/include/enumeration_types.hpp" +#include "../../implementation/service_discovery/include/eventgroupentry_impl.hpp" +#include "../../implementation/message/include/message_impl.hpp" +#include "pending_subscription_test_globals.hpp" + +static char* remote_address; +static char* local_address; + +class pending_subscription : public ::testing::Test { +public: + pending_subscription() : + work_(std::make_shared(io_)), + io_thread_(std::bind(&pending_subscription::io_run, this)) {} +protected: + + void TearDown() { + work_.reset(); + io_thread_.join(); + io_.stop(); + } + + void io_run() { + io_.run(); + } + + boost::asio::io_service io_; + std::shared_ptr work_; + std::thread io_thread_; +}; + +TEST_F(pending_subscription, send_multiple_subscriptions) +{ + std::promise trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + std::thread receive_thread([&](){ + std::atomic keep_receiving(true); + std::function receive; + std::vector receive_buffer(4096); + std::vector its_received_events; + + const std::function receive_cbk = [&]( + const boost::system::error_code& error, std::size_t bytes_transferred) { + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_SERVICE_POS_MIN], + receive_buffer[VSOMEIP_SERVICE_POS_MAX]); + vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_METHOD_POS_MIN], + receive_buffer[VSOMEIP_METHOD_POS_MAX]); + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (auto e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(3u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr its_casted_entry = + std::static_pointer_cast(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + } + } + + static int called = 0; + if (++called == 15) { // all subscribeAcks received + trigger_notifications.set_value(true); + } + if (called == 18) { // events were received as well + keep_receiving = false; + } + if (!error && keep_receiving) { + receive(); + } + }; + + receive = [&]() { + udp_socket.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + receive(); + while(keep_receiving) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + ++its_offer_service_message[11]; + } + + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); +} + +TEST_F(pending_subscription, send_alternating_subscribe_unsubscribe) +{ + std::promise trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(8); + std::atomic acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic notifications_received(0); + + bool triggered_notifications(false); + + std::function receive; + std::vector receive_buffer(4096); + std::vector its_received_events; + + const std::function receive_cbk = [&]( + const boost::system::error_code& error, std::size_t bytes_transferred) { + if (error) { + acks_received = expected_acks; + responses_received = expected_responses; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_SERVICE_POS_MIN], + receive_buffer[VSOMEIP_SERVICE_POS_MAX]); + vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_METHOD_POS_MIN], + receive_buffer[VSOMEIP_METHOD_POS_MAX]); + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (auto e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(16u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr its_casted_entry = + std::static_pointer_cast(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + acks_received++; + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + + if (!triggered_notifications && acks_received == expected_acks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + + if (!error && (acks_received != expected_acks || + responses_received != expected_responses || + notifications_received != expected_notifications)) { + receive(); + } + }; + + receive = [&]() { + udp_socket.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + receive(); + while(acks_received < expected_acks || + responses_received < expected_responses || + notifications_received < expected_notifications) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + ++its_offer_service_message[11]; + if (its_offer_service_message[11] % 2) { + its_offer_service_message[35] = 16; + its_offer_service_message[51] = 16; + } else { + its_offer_service_message[35] = 0; + its_offer_service_message[51] = 0; + } + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); +} + +TEST_F(pending_subscription, send_multiple_unsubscriptions) +{ + std::promise trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(2); + std::atomic acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic notifications_received(0); + + bool triggered_notifications(false); + + std::function receive; + std::vector receive_buffer(4096); + std::vector its_received_events; + + const std::function receive_cbk = [&]( + const boost::system::error_code& error, std::size_t bytes_transferred) { + if (error) { + acks_received = expected_acks; + responses_received = expected_responses; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_SERVICE_POS_MIN], + receive_buffer[VSOMEIP_SERVICE_POS_MAX]); + vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_METHOD_POS_MIN], + receive_buffer[VSOMEIP_METHOD_POS_MAX]); + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (auto e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(16u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr its_casted_entry = + std::static_pointer_cast(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + acks_received++; + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + + if (!triggered_notifications && acks_received == expected_acks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + + if (!error && (acks_received != expected_acks || + responses_received != expected_responses || + notifications_received != expected_notifications)) { + receive(); + } + }; + + receive = [&]() { + udp_socket.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + receive(); + while(acks_received < expected_acks || + responses_received < expected_responses || + notifications_received < expected_notifications) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + if (its_offer_service_message[11] == 15 || its_offer_service_message[11] == 0x1) { + its_offer_service_message[35] = 16; + its_offer_service_message[51] = 16; + } else { + its_offer_service_message[35] = 0; + its_offer_service_message[51] = 0; + } + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + ++its_offer_service_message[11]; + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); +} + +TEST_F(pending_subscription, send_alternating_subscribe_nack_unsubscribe) +{ + std::promise trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(8); + std::atomic acks_received(0); + + const std::uint32_t expected_nacks(8); + std::atomic nacks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic notifications_received(0); + + bool triggered_notifications(false); + + std::function receive; + std::vector receive_buffer(4096); + std::vector its_received_events; + + const std::function receive_cbk = [&]( + const boost::system::error_code& error, std::size_t bytes_transferred) { + if (error) { + acks_received = expected_acks; + responses_received = expected_responses; + nacks_received = expected_nacks; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_SERVICE_POS_MIN], + receive_buffer[VSOMEIP_SERVICE_POS_MAX]); + vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_METHOD_POS_MIN], + receive_buffer[VSOMEIP_METHOD_POS_MAX]); + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (auto e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + if (e->get_ttl()) { + EXPECT_EQ(16u, e->get_ttl()); + acks_received++; + } else { + EXPECT_EQ(0u, e->get_ttl()); + nacks_received++; + } + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr its_casted_entry = + std::static_pointer_cast(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + + if (!triggered_notifications && acks_received == expected_acks && + nacks_received == expected_nacks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + + if (!error && (acks_received != expected_acks || + responses_received != expected_responses || + notifications_received != expected_notifications || + nacks_received != expected_nacks)) { + receive(); + } + }; + + receive = [&]() { + udp_socket.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + receive(); + while(acks_received < expected_acks || + responses_received < expected_responses || + notifications_received < expected_notifications) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + ++its_offer_service_message[11]; + if (its_offer_service_message[11] % 2) { + its_offer_service_message[35] = 16; + its_offer_service_message[51] = 16; + } else { + its_offer_service_message[35] = 0; + its_offer_service_message[51] = 0; + } + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); +} + + +#ifndef _WIN32 +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + if(argc < 4) { + std::cerr << "Please pass an target and local IP address and test mode to this binary like: " + << argv[0] << " 10.0.3.1 10.0.3.202 SUBSCRIBE" << std::endl; + std::cerr << "Testmodes are [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE]" << std::endl; + exit(1); + } + remote_address = argv[1]; + local_address = argv[2]; + std::string its_testmode = argv[3]; + if (its_testmode == std::string("SUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_multiple_subscriptions"; + } else if (its_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_alternating_subscribe_unsubscribe"; + } else if (its_testmode == std::string("UNSUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_multiple_unsubscriptions"; + } else if (its_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_NACK")) { + ::testing::GTEST_FLAG(filter) = "*send_alternating_subscribe_nack_unsubscribe"; + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/pending_subscription_tests/pending_subscription_test_service.cpp b/test/pending_subscription_tests/pending_subscription_test_service.cpp new file mode 100644 index 000000000..00434f3c3 --- /dev/null +++ b/test/pending_subscription_tests/pending_subscription_test_service.cpp @@ -0,0 +1,311 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "../../implementation/logging/include/logger.hpp" + +#include "pending_subscription_test_globals.hpp" + +class pending_subscription_test_service { +public: + pending_subscription_test_service(struct pending_subscription_test::service_info _service_info, pending_subscription_test::test_mode_e _testmode) : + service_info_(_service_info), + testmode_(_testmode), + app_(vsomeip::runtime::get()->create_application("pending_subscription_test_service")), + wait_until_registered_(true), + wait_until_shutdown_method_called_(true), + subscription_accepted_asynchronous_(false), + subscription_accepted_synchronous_(false), + offer_thread_(std::bind(&pending_subscription_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&pending_subscription_test_service::on_state, this, + std::placeholders::_1)); + + // offer field + std::set its_eventgroups; + its_eventgroups.insert(_service_info.eventgroup_id); + app_->offer_event(service_info_.service_id, 0x1, + service_info_.event_id, its_eventgroups, true); + + its_eventgroups.clear(); + its_eventgroups.insert(static_cast(_service_info.eventgroup_id+1u)); + + app_->offer_event(service_info_.service_id, 0x1, + static_cast(service_info_.event_id+1u), + its_eventgroups, true); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id, + std::bind(&pending_subscription_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.notify_method_id, + std::bind(&pending_subscription_test_service::on_notify_method_called, this, + std::placeholders::_1)); + + app_->register_async_subscription_handler(service_info_.service_id, + 0x1, service_info_.eventgroup_id, + std::bind(&pending_subscription_test_service::subscription_handler_async, + this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + app_->register_subscription_handler(service_info_.service_id, + 0x1, static_cast(service_info_.eventgroup_id+1u), + std::bind(&pending_subscription_test_service::subscription_handler, + this, std::placeholders::_1, std::placeholders::_2)); + app_->start(); + } + + ~pending_subscription_test_service() { + offer_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, 0x1); + } + + void stop() { + app_->stop_offer_service(service_info_.service_id, 0x1); + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + std::lock_guard its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_notify_method_called(const std::shared_ptr &_message) { + (void)_message; + std::shared_ptr its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data( {0xDD}); + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload); + app_->notify(service_info_.service_id, service_info_.instance_id, + static_cast(service_info_.event_id + 1u) , its_payload); + notify_method_called_.set_value(true); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (!subscription_accepted_asynchronous_ || !subscription_accepted_synchronous_) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) { + async_subscription_handler_(true); + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) { + ; + } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) { + ; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) { + ; + } + std::future itsFuture = notify_method_called_.get_future(); + if (std::future_status::timeout == itsFuture.wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "notify method wasn't called within time!"; + } else { + EXPECT_TRUE(itsFuture.get()); + } + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + stop(); + } + + void subscription_handler_async(vsomeip::client_t _client, bool _subscribed, + std::function _cbk) { + VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed." << _subscribed; + if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) { + async_subscription_handler_ = _cbk; + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + subscription_accepted_asynchronous_ = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + _cbk(true); + if (count_subscribe == 8 || count_unsubscribe == 7) { + subscription_accepted_asynchronous_ = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + _cbk(true); + if (count_subscribe == 2 || count_unsubscribe == 1) { + subscription_accepted_asynchronous_ = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (_subscribed) { + _cbk((count_subscribe % 2)); // nack every second subscription + } else { + _cbk(true); + } + if (count_subscribe == 8 || count_unsubscribe == 7) { + subscription_accepted_asynchronous_ = true; + } + } + } + + bool subscription_handler(vsomeip::client_t _client, bool _subscribed) { + (void)_subscribed; + bool ret(false); + VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed. " << _subscribed; + if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) { + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + subscription_accepted_synchronous_ = true; + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 8 && count_unsubscribe == 7) { + subscription_accepted_synchronous_ = true; + } + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 2 && count_unsubscribe == 1) { + subscription_accepted_synchronous_ = true; + } + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 8 && count_unsubscribe == 7) { + subscription_accepted_synchronous_ = true; + } + if (_subscribed) { + ret = (count_subscribed % 2); // nack every second subscription + } else { + ret = true; + } + } + return ret; + } + +private: + struct pending_subscription_test::service_info service_info_; + pending_subscription_test::test_mode_e testmode_; + std::shared_ptr app_; + + bool wait_until_registered_; + bool wait_until_shutdown_method_called_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic subscription_accepted_asynchronous_; + std::atomic subscription_accepted_synchronous_; + std::thread offer_thread_; + std::function async_subscription_handler_; + std::promise notify_method_called_; +}; + +pending_subscription_test::test_mode_e its_testmode(pending_subscription_test::test_mode_e::SUBSCRIBE); + +TEST(someip_pending_subscription_test, block_subscription_handler) +{ + pending_subscription_test_service its_sample(pending_subscription_test::service, its_testmode); +} + + +#ifndef _WIN32 +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc < 2) { + std::cerr << "Please pass a test mode to this binary like: " + << argv[0] << " SUBSCRIBE" << std::endl; + std::cerr << "Testmodes are [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE]" << std::endl; + exit(1); + } + + std::string its_pased_testmode = argv[1]; + if (its_pased_testmode == std::string("SUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE; + } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE; + } else if (its_pased_testmode == std::string("UNSUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::UNSUBSCRIBE; + } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_NACK")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK; + } + + return RUN_ALL_TESTS(); +} +#endif