summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuergen Gehring <juergen.gehring@bmw.de>2018-01-25 00:40:09 -0800
committerJuergen Gehring <juergen.gehring@bmw.de>2018-01-25 00:40:09 -0800
commit325b4724c9622bb7f8b1f3315a227dde867c70f1 (patch)
tree6bb43fd68d40daf5979f40b919eee7b037496067
parent565b97b0108a02ef41284629a6d226c053c0dd7e (diff)
downloadvSomeIP-325b4724c9622bb7f8b1f3315a227dde867c70f1.tar.gz
vsomeip 2.10.92.10.9
-rw-r--r--CHANGES20
-rw-r--r--CMakeLists.txt12
-rw-r--r--documentation/vsomeipUserGuide122
-rw-r--r--implementation/configuration/include/configuration.hpp1
-rw-r--r--implementation/configuration/include/configuration_impl.hpp7
-rw-r--r--implementation/configuration/include/internal.hpp.in13
-rw-r--r--implementation/configuration/include/policy.hpp25
-rw-r--r--implementation/configuration/src/configuration_impl.cpp255
-rw-r--r--implementation/endpoints/include/netlink_connector.hpp15
-rw-r--r--implementation/endpoints/src/client_endpoint_impl.cpp1
-rw-r--r--implementation/endpoints/src/netlink_connector.cpp192
-rw-r--r--implementation/endpoints/src/tcp_client_endpoint_impl.cpp8
-rw-r--r--implementation/endpoints/src/tcp_server_endpoint_impl.cpp27
-rw-r--r--implementation/routing/include/eventgroupinfo.hpp4
-rw-r--r--implementation/routing/include/routing_manager_base.hpp8
-rw-r--r--implementation/routing/include/routing_manager_impl.hpp30
-rw-r--r--implementation/routing/include/routing_manager_proxy.hpp4
-rw-r--r--implementation/routing/include/routing_manager_stub.hpp2
-rw-r--r--implementation/routing/include/routing_manager_stub_host.hpp4
-rw-r--r--implementation/routing/include/types.hpp15
-rw-r--r--implementation/routing/src/eventgroupinfo.cpp100
-rw-r--r--implementation/routing/src/routing_manager_base.cpp9
-rw-r--r--implementation/routing/src/routing_manager_impl.cpp502
-rw-r--r--implementation/routing/src/routing_manager_proxy.cpp43
-rw-r--r--implementation/routing/src/routing_manager_stub.cpp45
-rw-r--r--implementation/service_discovery/include/service_discovery_host.hpp8
-rw-r--r--implementation/service_discovery/include/service_discovery_impl.hpp4
-rwxr-xr-ximplementation/service_discovery/src/message_impl.cpp2
-rw-r--r--implementation/service_discovery/src/service_discovery_impl.cpp132
-rw-r--r--implementation/utility/include/utility.hpp5
-rw-r--r--implementation/utility/src/utility.cpp114
-rw-r--r--test/CMakeLists.txt191
-rw-r--r--test/client_id_tests/client_id_test_utility.cpp122
-rw-r--r--test/client_id_tests/client_id_test_utility.json13
-rw-r--r--test/client_id_tests/client_id_test_utility_masked_127.json36
-rw-r--r--test/client_id_tests/client_id_test_utility_masked_4095.json36
-rw-r--r--test/client_id_tests/client_id_test_utility_masked_511.json36
-rw-r--r--test/malicious_data_tests/conf/malicious_data_test_master.json.in44
-rwxr-xr-xtest/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in66
-rw-r--r--test/malicious_data_tests/malicious_data_test_globals.hpp32
-rw-r--r--test/malicious_data_tests/malicious_data_test_msg_sender.cpp283
-rw-r--r--test/malicious_data_tests/malicious_data_test_service.cpp170
-rw-r--r--test/pending_subscription_tests/conf/pending_subscription_test_master.json.in44
-rwxr-xr-xtest/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in75
-rw-r--r--test/pending_subscription_tests/pending_subscription_test_globals.hpp32
-rw-r--r--test/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp826
-rw-r--r--test/pending_subscription_tests/pending_subscription_test_service.cpp311
47 files changed, 3534 insertions, 512 deletions
diff --git a/CHANGES b/CHANGES
index 3e6bc6e..65d6d86 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 2815302..a9d9f4c 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 395fdd5..9996063 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 16ebd33..1423392 100644
--- a/implementation/configuration/include/configuration.hpp
+++ b/implementation/configuration/include/configuration.hpp
@@ -43,6 +43,7 @@ public:
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 93f7ebf..d3b7572 100644
--- a/implementation/configuration/include/configuration_impl.hpp
+++ b/implementation/configuration/include/configuration_impl.hpp
@@ -60,6 +60,7 @@ public:
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 @@ private:
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 @@ protected:
// 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 @@ protected:
ET_NETWORK,
ET_UNICAST,
ET_DIAGNOSIS,
+ ET_DIAGNOSIS_MASK,
ET_LOGGING_CONSOLE,
ET_LOGGING_FILE,
ET_LOGGING_DLT,
@@ -362,7 +367,7 @@ protected:
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 6012092..e2f3da3 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<std::uint32_t>::max)();
diff --git a/implementation/configuration/include/policy.hpp b/implementation/configuration/include/policy.hpp
index 89e8a96..9132a4d 100644
--- a/implementation/configuration/include/policy.hpp
+++ b/implementation/configuration/include/policy.hpp
@@ -7,26 +7,25 @@
#define VSOMEIP_CFG_POLICY_HPP
#include <memory>
+#include <set>
#include <vsomeip/primitive_types.hpp>
namespace vsomeip {
namespace cfg {
+typedef std::set<std::pair<uint32_t, uint32_t>> ranges_t;
+typedef std::set<std::pair<ranges_t, ranges_t>> ids_t;
+
struct policy {
- policy() :
- uid_(0), is_uid_set_(false), gid_(0), is_gid_set_(false) {
- }
-
- std::set<std::pair<service_t, instance_t>> allowed_services_;
- std::set<std::pair<service_t, instance_t>> allowed_offers_;
- std::set<std::pair<service_t, instance_t>> denied_services_;
- std::set<std::pair<service_t, instance_t>> 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<std::pair<service_t, instance_t>> services_;
+ std::set<std::pair<service_t, instance_t>> offers_;
+ bool allow_what_;
};
} // namespace cfg
diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp
index 178481c..0b33018 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<std::string>("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> policy(std::make_shared<policy>());
+ 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<uint32_t, uint32_t> 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<std::pair<uint32_t, uint32_t>> 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 fdad718..f71ba88 100644
--- a/implementation/endpoints/include/netlink_connector.hpp
+++ b/implementation/endpoints/include/netlink_connector.hpp
@@ -129,17 +129,18 @@ private:
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<netlink_connector> {
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 @@ private:
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<int, unsigned int> net_if_flags_;
int net_if_index_for_address_;
@@ -171,6 +177,7 @@ private:
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 be8e684..5599828 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<Protocol>::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 eb43b74..94b75cf 100644
--- a/implementation/endpoints/src/netlink_connector.cpp
+++ b/implementation/endpoints/src/netlink_connector.cpp
@@ -9,6 +9,7 @@
#include <boost/asio/write.hpp>
#include <boost/asio/read.hpp>
+#include<sstream>
#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<nl_protocol>(RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR), ec);
+ socket_.bind(nl_endpoint<nl_protocol>(
+ 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<std::mutex> 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<std::mutex> 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<struct rtattr *>(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<std::uint32_t>(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<std::uint32_t*>(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<uint32_t>(_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 b1a2f74..ab7d9c3 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 01c6db1..4226c55 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<std::uint32_t>(recv_buffer_size_);
} else {
- std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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 9e50e85..8420fd3 100644
--- a/implementation/routing/include/eventgroupinfo.hpp
+++ b/implementation/routing/include/eventgroupinfo.hpp
@@ -82,7 +82,7 @@ public:
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<pending_subscription_t> remove_pending_subscription(
pending_subscription_id_t _subscription_id);
VSOMEIP_EXPORT void clear_pending_subscriptions();
@@ -109,6 +109,8 @@ private:
std::mutex pending_subscriptions_mutex_;
std::map<pending_subscription_id_t, pending_subscription_t> pending_subscriptions_;
+ std::map<std::pair<boost::asio::ip::address, std::uint16_t>,
+ std::vector<pending_subscription_id_t>> 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 c134d7b..7bf3a4d 100644
--- a/implementation/routing/include/routing_manager_base.hpp
+++ b/implementation/routing/include/routing_manager_base.hpp
@@ -139,6 +139,9 @@ protected:
std::shared_ptr<endpoint> create_local(client_t _client);
std::shared_ptr<endpoint> find_or_create_local(client_t _client);
void remove_local(client_t _client);
+ void remove_local(client_t _client,
+ const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups);
+
std::shared_ptr<endpoint> find_local(client_t _client);
std::shared_ptr<endpoint> find_local(service_t _service,
instance_t _instance);
@@ -195,16 +198,17 @@ protected:
std::map<client_t, std::shared_ptr<endpoint>> get_local_endpoints();
+ std::set<std::tuple<service_t, instance_t, eventgroup_t>>
+ get_subscriptions(const client_t _client);
private:
std::shared_ptr<endpoint> create_local_unlocked(client_t _client);
std::shared_ptr<endpoint> find_local_unlocked(client_t _client);
- std::set<std::tuple<service_t, instance_t, eventgroup_t>>
- 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 ad6810b..2e90077 100644
--- a/implementation/routing/include/routing_manager_impl.hpp
+++ b/implementation/routing/include/routing_manager_impl.hpp
@@ -146,6 +146,10 @@ public:
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<endpoint> find_or_create_remote_client(service_t _service,
instance_t _instance,
@@ -191,12 +195,12 @@ public:
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<endpoint_definition> &_subscriber,
- const std::shared_ptr<endpoint_definition> &_target,
- ttl_t _ttl, client_t *_client,
- const std::shared_ptr<sd_message_identifier_t> &_sd_message_id);
+ const std::shared_ptr<endpoint_definition> &_target, ttl_t _ttl,
+ const std::shared_ptr<sd_message_identifier_t> &_sd_message_id,
+ const std::function<void(remote_subscription_state_e, client_t)>& _callback);
void on_unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _target);
@@ -324,7 +328,9 @@ private:
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 @@ private:
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<routing_manager_stub> stub_;
std::shared_ptr<sd::service_discovery> discovery_;
@@ -407,6 +425,8 @@ private:
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<std::pair<service_t, instance_t>> pending_sd_offers_;
#ifndef _WIN32
diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp
index ac7bded..a9f0762 100644
--- a/implementation/routing/include/routing_manager_proxy.hpp
+++ b/implementation/routing/include/routing_manager_proxy.hpp
@@ -178,6 +178,10 @@ private:
void send_request_services(std::set<service_data_t>& _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 f825b0b..3e97a5f 100644
--- a/implementation/routing/include/routing_manager_stub.hpp
+++ b/implementation/routing/include/routing_manager_stub.hpp
@@ -66,7 +66,7 @@ public:
void send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _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 5497d6e..a6d461e 100644
--- a/implementation/routing/include/routing_manager_stub_host.hpp
+++ b/implementation/routing/include/routing_manager_stub_host.hpp
@@ -56,6 +56,10 @@ public:
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 16bc565..f33a944 100644
--- a/implementation/routing/include/types.hpp
+++ b/implementation/routing/include/types.hpp
@@ -11,8 +11,10 @@
#include <boost/asio/ip/address.hpp>
#include <vsomeip/primitive_types.hpp>
+#include <vsomeip/constants.hpp>
#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_t> _sd_message_identifier,
std::shared_ptr<endpoint_definition> _subscriber,
std::shared_ptr<endpoint_definition> _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<sd_message_identifier_t>()),
subscriber_(std::shared_ptr<endpoint_definition>()),
target_(std::shared_ptr<endpoint_definition>()),
- ttl_(0) {
+ ttl_(0),
+ subscribing_client_(VSOMEIP_ROUTING_CLIENT),
+ pending_subscription_id_(DEFAULT_SUBSCRIPTION) {
}
std::shared_ptr<sd_message_identifier_t> sd_message_identifier_;
std::shared_ptr<endpoint_definition> subscriber_;
std::shared_ptr<endpoint_definition> 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 1432aa2..137a021 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<pending_subscription_t> eventgroupinfo::remove_pending_subscription(
pending_subscription_id_t _subscription_id) {
+ std::vector<pending_subscription_t> its_pending_subscriptions;
std::lock_guard<std::mutex> 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<std::mutex> 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 baf6660..9296f99 100644
--- a/implementation/routing/src/routing_manager_base.cpp
+++ b/implementation/routing/src/routing_manager_base.cpp
@@ -815,14 +815,17 @@ std::shared_ptr<endpoint> 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<std::tuple<service_t, instance_t, eventgroup_t>>& _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<endpoint> 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 2acd4eb..5442134 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<netlink_connector>(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<std::mutex> 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<std::mutex> 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<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]))) {
@@ -1850,7 +1876,15 @@ std::shared_ptr<endpoint> 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<std::mutex> 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<std::pair<service_t, instance_t>> services_to_release_;
{
std::lock_guard<std::mutex> its_lock(requested_services_mutex_);
@@ -2425,6 +2459,7 @@ void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address &
std::shared_ptr<endpoint_definition> invalid_endpoint_;
client_t client_;
std::set<std::shared_ptr<event>> events_;
+ std::shared_ptr<eventgroupinfo> eventgroupinfo_;
};
std::vector<struct subscriptions_info> 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<endpoint> 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<sd_message_identifier_t>(),
+ 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<endpoint_definition> &_subscriber,
- const std::shared_ptr<endpoint_definition> &_target,
- ttl_t _ttl, client_t *_client,
- const std::shared_ptr<sd_message_identifier_t> &_sd_message_id) {
+ const std::shared_ptr<endpoint_definition> &_target, ttl_t _ttl,
+ const std::shared_ptr<sd_message_identifier_t> &_sd_message_id,
+ const std::function<void(remote_subscription_state_e, client_t)>& _callback) {
std::shared_ptr<eventgroupinfo> 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<udp_server_endpoint_impl>(endpoint)->
+ its_subscribing_client = std::dynamic_pointer_cast<udp_server_endpoint_impl>(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<tcp_server_endpoint_impl>(endpoint)->
+ its_subscribing_client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)->
get_client(_subscriber);
}
}
+ std::unique_lock<std::mutex> 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<routing_manager_stub_host>(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<routing_manager_stub_host>(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<sd_message_identifier_t>(), _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<std::shared_ptr<event> > 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<std::mutex> 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<pending_subscription_t> 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<std::mutex> 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<pending_subscription_t> 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 <<its_sd_message_id.subscriber_->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 <<its_sd_message_id.subscriber_->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<endpoint_definition> invalid_endpoint_;
client_t client_;
std::set<std::shared_ptr<event>> events_;
+ std::shared_ptr<eventgroupinfo> eventgroupinfo_;
};
std::vector<struct subscriptions_info> 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<endpoint> 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<sd_message_identifier_t>(),
+ 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<std::mutex> 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<std::mutex> 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<eventgroupinfo> 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<pending_subscription_t> 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<routing_manager_stub_host>(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<routing_manager_stub_host>(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<routing_manager_stub_host>(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 f6aa420..ca046ed 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<std::mutex> 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 8d48436..a63642a 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<vsomeip::endpoint> _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<vsomeip::endpoint> _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<vsomeip::endpoint> _
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 74abfd5..f9e8f29 100644
--- a/implementation/service_discovery/include/service_discovery_host.hpp
+++ b/implementation/service_discovery/include/service_discovery_host.hpp
@@ -76,12 +76,12 @@ public:
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<endpoint_definition> &_subscriber,
- const std::shared_ptr<endpoint_definition> &_target,
- ttl_t _ttl, client_t *_client,
- const std::shared_ptr<sd_message_identifier_t> &_sd_message_id) = 0;
+ const std::shared_ptr<endpoint_definition> &_target, ttl_t _ttl,
+ const std::shared_ptr<sd_message_identifier_t> &_sd_message_id,
+ const std::function<void(remote_subscription_state_e, client_t)>& _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 039fe7b..3cf3396 100644
--- a/implementation/service_discovery/include/service_discovery_impl.hpp
+++ b/implementation/service_discovery/include/service_discovery_impl.hpp
@@ -315,10 +315,6 @@ private:
void remote_subscription_not_acknowledge_all();
- void remote_subscription_remove(
- service_t _service, instance_t _instance, eventgroup_t _eventgroup,
- const std::shared_ptr<endpoint_definition> &_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 d23bf31..f4695a9 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<std::mutex> 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 2d5aaff..6042526 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<uint8_t>::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<std::uint16_t>(
- _resubscribes->back().first + (12u * diff - 12u));
- } else {
- _resubscribes->back().first =
- static_cast<std::uint16_t>(
- _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<std::uint16_t>(
+ _resubscribes->back().first + (12u * diff - 12u));
+ } else {
+ _resubscribes->back().first =
+ static_cast<std::uint16_t>(
+ _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<std::uint8_t>(_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<std::mutex> 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<std::mutex> 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<uint8_t>::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<endpoint_definition> &_subscriber) {
- std::lock_guard<std::mutex> 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 ac55fdb..b0ff360 100644
--- a/implementation/utility/include/utility.hpp
+++ b/implementation/utility/include/utility.hpp
@@ -124,11 +124,12 @@ public:
}
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 81d8aba..a241618 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<configuration> &_config) {
std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__);
+ const size_t its_shm_size = sizeof(configuration_data_t) +
+ static_cast<std::uint16_t>(~_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<configuration> &_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<configuration> &_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<configuration> &_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<configuration> &_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<configuration_data_t *>(its_segment);
the_configuration_data__->client_base_
- = static_cast<unsigned short>(_config->get_diagnosis_address() << 8);
- the_configuration_data__->used_client_ids_[0]
- = the_configuration_data__->client_base_;
- the_configuration_data__->client_base_++;
+ = static_cast<unsigned short>((_config->get_diagnosis_address() << 8) & _config->get_diagnosis_mask());
+ the_configuration_data__->max_clients_ = static_cast<std::uint16_t>(~_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<unsigned short*>(
+ reinterpret_cast<size_t>(&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<configuration> &_con
static_cast<mode_t>(_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<configuration> &_con
}
the_configuration_data__->client_base_
- = static_cast<unsigned short>(_config->get_diagnosis_address() << 8);
- the_configuration_data__->used_client_ids_[0]
- = the_configuration_data__->client_base_;
- the_configuration_data__->client_base_++;
+ = static_cast<unsigned short>((_config->get_diagnosis_address() << 8) & _config->get_diagnosis_mask());
+ the_configuration_data__->max_clients_ = static_cast<std::uint16_t>(~_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<unsigned short*>(
+ reinterpret_cast<size_t>(&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<configuration> &_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<configuration> &_con
}
}
its_configuration_refs__++;
+ used_client_ids__ = reinterpret_cast<unsigned short*>(
+ reinterpret_cast<size_t>(&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<configuration> &_con
void utility::auto_configuration_exit(client_t _client,
const std::shared_ptr<configuration> &_config) {
std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__);
+ const size_t its_shm_size = sizeof(configuration_data_t) +
+ static_cast<std::uint16_t>(~_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<client_t> 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<configuration> &_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<configuration> &_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<configuration> &_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<configuration> &_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<unsigned char>(_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<std::uint16_t>(_client
+ & the_configuration_data__->max_clients_);
+ the_configuration_data__->max_assigned_client_id_without_diagnosis_ =
+ static_cast<std::uint16_t>(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 92a2461..fd70df6 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)
@@ -2140,6 +2160,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 887646f..1512146 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<vsomeip::configuration> its_configuration;
auto its_plugin = vsomeip::plugin_manager::get()->get_plugin(
@@ -49,13 +54,21 @@ protected:
ASSERT_FALSE(file_exist(std::string("/dev/shm").append(utility::get_shm_name(configuration_))));
ASSERT_TRUE(static_cast<bool>(configuration_));
configuration_->load(APPLICATION_NAME_ROUTING_MANAGER);
+ diagnosis_mask_ = configuration_->get_diagnosis_mask();
+ diagnosis_ = configuration_->get_diagnosis_address();
+
+ // calculate all client IDs based on mask
+ client_id_base_ = static_cast<client_t>((diagnosis_ << 8) & diagnosis_mask_);
+ CLIENT_ID_ROUTING_MANAGER = client_id_base_ | 0x1;
+ APPLICATION_IN_CLIENT_ID = static_cast<client_t>(client_id_base_ | 0x11);
+ APPLICATION_IN_CLIENT_ID_TWO = static_cast<client_t>(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 @@ protected:
protected:
std::shared_ptr<configuration> 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<std::uint16_t>((APPLICATION_IN_CLIENT_ID & ~diagnosis_mask_) + 10u);
+
std::vector<client_t> 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<client_t>(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<client_t>(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<client_t> its_client_ids;
+ std::vector<client_t> 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<std::uint32_t>(i);
- }
- }
+ const std::uint16_t max_possible_clients = static_cast<std::uint16_t>(~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<std::uint16_t>(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<std::uint32_t>(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<std::uint16_t>(~diagnosis_mask_);
+ const std::uint16_t max_allowed_clients = static_cast<std::uint16_t>(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 ea0aaa0..e928b05 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 0000000..c7c255b
--- /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 0000000..dfc42c0
--- /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 0000000..274a5e0
--- /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 0000000..066989b
--- /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 0000000..199f318
--- /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 <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** malicious_data_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** malicious_data_test_master.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+fi
+
+# Wait until all clients and services are finished
+for job in $PID_SERIVCE
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ echo "waiting for $job"
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_VSOMEIPD
+sleep 1
+
+if [ ! -z "$USE_DOCKER" ]; then
+ docker stop otems
+ docker rm otems
+fi
+
+# Check if everything went well
+exit $FAIL
diff --git a/test/malicious_data_tests/malicious_data_test_globals.hpp b/test/malicious_data_tests/malicious_data_test_globals.hpp
new file mode 100644
index 0000000..f6336a4
--- /dev/null
+++ b/test/malicious_data_tests/malicious_data_test_globals.hpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef MALICIOUS_DATA_TEST_GLOBALS_HPP_
+#define MALICIOUS_DATA_TEST_GLOBALS_HPP_
+
+namespace malicious_data_test {
+
+struct service_info {
+ vsomeip::service_t service_id;
+ vsomeip::instance_t instance_id;
+ vsomeip::method_t method_id;
+ vsomeip::event_t event_id;
+ vsomeip::eventgroup_t eventgroup_id;
+ vsomeip::method_t shutdown_method_id;
+ vsomeip::method_t notify_method_id;
+};
+
+struct service_info service = { 0x3344, 0x1, 0x1111, 0x8002, 0x1, 0x1404, 0x4242 };
+
+enum test_mode_e {
+ SUBSCRIBE,
+ SUBSCRIBE_UNSUBSCRIBE,
+ UNSUBSCRIBE,
+ SUBSCRIBE_UNSUBSCRIBE_NACK
+};
+
+}
+
+#endif /* MALICIOUS_DATA_TEST_GLOBALS_HPP_ */
diff --git a/test/malicious_data_tests/malicious_data_test_msg_sender.cpp b/test/malicious_data_tests/malicious_data_test_msg_sender.cpp
new file mode 100644
index 0000000..ad856b8
--- /dev/null
+++ b/test/malicious_data_tests/malicious_data_test_msg_sender.cpp
@@ -0,0 +1,283 @@
+// 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/.
+
+#include <iostream>
+#include <memory>
+#include <thread>
+#include <chrono>
+#include <cstring>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include <boost/asio.hpp>
+
+#include <vsomeip/vsomeip.hpp>
+
+#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<boost::asio::io_service::work>(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<boost::asio::io_service::work> work_;
+ std::thread io_thread_;
+};
+
+TEST_F(malicious_data, send_malicious_events)
+{
+ std::promise<bool> 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<bool> keep_receiving(true);
+ std::function<void()> receive;
+ std::vector<std::uint8_t> receive_buffer(4096);
+ std::vector<vsomeip::event_t> its_received_events;
+
+ const std::function<void(const boost::system::error_code&, std::size_t)> 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<vsomeip::sd::eventgroupentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(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<bool> 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 0000000..17a4bb8
--- /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 <chrono>
+#include <condition_variable>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <thread>
+#include <map>
+#include <algorithm>
+#include <atomic>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#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<vsomeip::eventgroup_t> 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<vsomeip::service_t>(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<vsomeip::service_t>(service_info_.service_id + 1u), 0x1);
+ }
+
+ void stop() {
+ app_->stop_offer_service(static_cast<vsomeip::service_t>(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<std::mutex> its_lock(mutex_);
+ wait_until_registered_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ app_->send(vsomeip::runtime::get()->create_response(_message));
+ VSOMEIP_WARNING << "************************************************************";
+ VSOMEIP_WARNING << "Shutdown method called -> going down!";
+ VSOMEIP_WARNING << "************************************************************";
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_shutdown_method_called_ = false;
+ condition_.notify_one();
+ }
+
+ void on_event(const std::shared_ptr<vsomeip::message> &_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<vsomeip::message> &_message) {
+ EXPECT_EQ(static_cast<vsomeip::service_t>(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<std::mutex> 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<vsomeip::application> 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 0000000..5c363a7
--- /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 0000000..0a3dd17
--- /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 <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** pending_subscription_test_sd_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** pending_subscription_test_master.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+fi
+
+# Wait until all clients and services are finished
+for job in $PID_SERIVCE
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ echo "waiting for $job"
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_VSOMEIPD
+sleep 1
+
+if [ ! -z "$USE_DOCKER" ]; then
+ docker stop otems
+ docker rm otems
+fi
+
+# Check if everything went well
+exit $FAIL
diff --git a/test/pending_subscription_tests/pending_subscription_test_globals.hpp b/test/pending_subscription_tests/pending_subscription_test_globals.hpp
new file mode 100644
index 0000000..8daf91a
--- /dev/null
+++ b/test/pending_subscription_tests/pending_subscription_test_globals.hpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PENDING_SUBSCRIPTION_TEST_GLOBALS_HPP_
+#define PENDING_SUBSCRIPTION_TEST_GLOBALS_HPP_
+
+namespace pending_subscription_test {
+
+struct service_info {
+ vsomeip::service_t service_id;
+ vsomeip::instance_t instance_id;
+ vsomeip::method_t method_id;
+ vsomeip::event_t event_id;
+ vsomeip::eventgroup_t eventgroup_id;
+ vsomeip::method_t shutdown_method_id;
+ vsomeip::method_t notify_method_id;
+};
+
+struct service_info service = { 0x1122, 0x1, 0x1111, 0x1111, 0x1000, 0x1404, 0x4242 };
+
+enum test_mode_e {
+ SUBSCRIBE,
+ SUBSCRIBE_UNSUBSCRIBE,
+ UNSUBSCRIBE,
+ SUBSCRIBE_UNSUBSCRIBE_NACK
+};
+
+}
+
+#endif /* PENDING_SUBSCRIPTION_TEST_GLOBALS_HPP_ */
diff --git a/test/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp b/test/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp
new file mode 100644
index 0000000..b5325ab
--- /dev/null
+++ b/test/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp
@@ -0,0 +1,826 @@
+// 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/.
+
+#include <iostream>
+#include <memory>
+#include <thread>
+#include <chrono>
+#include <cstring>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include <boost/asio.hpp>
+
+#include <vsomeip/vsomeip.hpp>
+
+#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<boost::asio::io_service::work>(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<boost::asio::io_service::work> work_;
+ std::thread io_thread_;
+};
+
+TEST_F(pending_subscription, send_multiple_subscriptions)
+{
+ std::promise<bool> 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<bool> keep_receiving(true);
+ std::function<void()> receive;
+ std::vector<std::uint8_t> receive_buffer(4096);
+ std::vector<vsomeip::event_t> its_received_events;
+
+ const std::function<void(const boost::system::error_code&, std::size_t)> 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<vsomeip::sd::eventgroupentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(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<vsomeip::event_t>(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<bool> 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<std::uint32_t> acks_received(0);
+
+ const std::uint32_t expected_responses(1);
+ std::atomic<std::uint32_t> responses_received(0);
+
+ const std::uint32_t expected_notifications(2);
+ std::atomic<std::uint32_t> notifications_received(0);
+
+ bool triggered_notifications(false);
+
+ std::function<void()> receive;
+ std::vector<std::uint8_t> receive_buffer(4096);
+ std::vector<vsomeip::event_t> its_received_events;
+
+ const std::function<void(const boost::system::error_code&, std::size_t)> 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<vsomeip::sd::eventgroupentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(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<vsomeip::event_t>(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<bool> 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<std::uint32_t> acks_received(0);
+
+ const std::uint32_t expected_responses(1);
+ std::atomic<std::uint32_t> responses_received(0);
+
+ const std::uint32_t expected_notifications(2);
+ std::atomic<std::uint32_t> notifications_received(0);
+
+ bool triggered_notifications(false);
+
+ std::function<void()> receive;
+ std::vector<std::uint8_t> receive_buffer(4096);
+ std::vector<vsomeip::event_t> its_received_events;
+
+ const std::function<void(const boost::system::error_code&, std::size_t)> 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<vsomeip::sd::eventgroupentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(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<vsomeip::event_t>(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<bool> 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<std::uint32_t> acks_received(0);
+
+ const std::uint32_t expected_nacks(8);
+ std::atomic<std::uint32_t> nacks_received(0);
+
+ const std::uint32_t expected_responses(1);
+ std::atomic<std::uint32_t> responses_received(0);
+
+ const std::uint32_t expected_notifications(2);
+ std::atomic<std::uint32_t> notifications_received(0);
+
+ bool triggered_notifications(false);
+
+ std::function<void()> receive;
+ std::vector<std::uint8_t> receive_buffer(4096);
+ std::vector<vsomeip::event_t> its_received_events;
+
+ const std::function<void(const boost::system::error_code&, std::size_t)> 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<vsomeip::sd::eventgroupentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(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<vsomeip::event_t>(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 0000000..00434f3
--- /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 <chrono>
+#include <condition_variable>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <thread>
+#include <map>
+#include <algorithm>
+#include <atomic>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#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<vsomeip::eventgroup_t> 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<vsomeip::eventgroup_t>(_service_info.eventgroup_id+1u));
+
+ app_->offer_event(service_info_.service_id, 0x1,
+ static_cast<vsomeip::event_t>(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<vsomeip::eventgroup_t>(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<std::mutex> its_lock(mutex_);
+ wait_until_registered_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ app_->send(vsomeip::runtime::get()->create_response(_message));
+ VSOMEIP_WARNING << "************************************************************";
+ VSOMEIP_WARNING << "Shutdown method called -> going down!";
+ VSOMEIP_WARNING << "************************************************************";
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_shutdown_method_called_ = false;
+ condition_.notify_one();
+ }
+
+ void on_notify_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ (void)_message;
+ std::shared_ptr<vsomeip::payload> 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<vsomeip::event_t>(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<std::mutex> 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<bool> 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<void(const bool)> _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<vsomeip::application> app_;
+
+ bool wait_until_registered_;
+ bool wait_until_shutdown_method_called_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::atomic<bool> subscription_accepted_asynchronous_;
+ std::atomic<bool> subscription_accepted_synchronous_;
+ std::thread offer_thread_;
+ std::function<void(const bool)> async_subscription_handler_;
+ std::promise<bool> 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