summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJürgen Gehring <Juergen.Gehring@bmw.de>2016-10-11 05:20:33 -0700
committerJürgen Gehring <Juergen.Gehring@bmw.de>2016-10-11 05:20:33 -0700
commit1375432503c0a72df7ad5c793c3e1f04e6b9e730 (patch)
tree4b229a9c5a7767db69db015f8e92e01c64614bf0
parent273814c76be4a8f906dc053492529b8d53b9e807 (diff)
downloadvSomeIP-1375432503c0a72df7ad5c793c3e1f04e6b9e730.tar.gz
vsomeip 2.4.22.4.2
-rw-r--r--.gitignore23
-rw-r--r--CHANGES132
-rw-r--r--CMakeLists.txt56
-rw-r--r--README70
-rwxr-xr-xREADME.md751
-rw-r--r--daemon/CMakeLists.txt2
-rw-r--r--daemon/vsomeipd.cpp39
-rw-r--r--examples/hello_world/CMakeLists.txt6
-rw-r--r--examples/hello_world/hello_world_client.cpp18
-rw-r--r--examples/hello_world/hello_world_service.cpp28
-rw-r--r--examples/notify-sample.cpp47
-rw-r--r--examples/request-sample.cpp30
-rw-r--r--examples/response-sample.cpp41
-rw-r--r--examples/subscribe-sample.cpp27
-rw-r--r--implementation/configuration/include/configuration.hpp12
-rw-r--r--implementation/configuration/include/configuration_impl.hpp26
-rw-r--r--implementation/configuration/include/event.hpp4
-rw-r--r--implementation/configuration/include/eventgroup.hpp1
-rw-r--r--implementation/configuration/include/internal.hpp.in12
-rw-r--r--implementation/configuration/include/service_instance_range.hpp24
-rw-r--r--implementation/configuration/include/trace.hpp4
-rw-r--r--implementation/configuration/src/configuration_impl.cpp192
-rw-r--r--implementation/endpoints/include/client_endpoint_impl.hpp10
-rw-r--r--implementation/endpoints/include/endpoint_impl.hpp2
-rw-r--r--implementation/endpoints/include/local_client_endpoint_impl.hpp2
-rw-r--r--implementation/endpoints/include/local_server_endpoint_impl.hpp15
-rw-r--r--implementation/endpoints/include/server_endpoint_impl.hpp2
-rw-r--r--implementation/endpoints/include/tcp_server_endpoint_impl.hpp9
-rw-r--r--implementation/endpoints/src/client_endpoint_impl.cpp52
-rw-r--r--implementation/endpoints/src/local_client_endpoint_impl.cpp30
-rw-r--r--implementation/endpoints/src/local_server_endpoint_impl.cpp181
-rw-r--r--implementation/endpoints/src/tcp_client_endpoint_impl.cpp11
-rw-r--r--implementation/endpoints/src/tcp_server_endpoint_impl.cpp196
-rw-r--r--implementation/endpoints/src/udp_client_endpoint_impl.cpp9
-rw-r--r--implementation/endpoints/src/udp_server_endpoint_impl.cpp8
-rw-r--r--implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp8
-rw-r--r--implementation/logging/include/logger.hpp4
-rw-r--r--implementation/logging/include/logger_impl.hpp5
-rw-r--r--implementation/logging/src/logger_impl.cpp8
-rw-r--r--implementation/message/include/payload_impl.hpp1
-rw-r--r--implementation/message/include/serializer.hpp2
-rw-r--r--implementation/message/src/message_header_impl.cpp4
-rw-r--r--implementation/message/src/message_impl.cpp2
-rw-r--r--implementation/message/src/payload_impl.cpp4
-rw-r--r--implementation/routing/include/event.hpp38
-rw-r--r--implementation/routing/include/eventgroupinfo.hpp12
-rw-r--r--implementation/routing/include/routing_manager.hpp31
-rw-r--r--implementation/routing/include/routing_manager_base.hpp31
-rw-r--r--implementation/routing/include/routing_manager_impl.hpp69
-rw-r--r--implementation/routing/include/routing_manager_proxy.hpp46
-rw-r--r--implementation/routing/include/routing_manager_stub.hpp34
-rw-r--r--implementation/routing/include/routing_manager_stub_host.hpp8
-rw-r--r--implementation/routing/src/event.cpp168
-rw-r--r--implementation/routing/src/eventgroupinfo.cpp29
-rw-r--r--implementation/routing/src/routing_manager_base.cpp139
-rw-r--r--implementation/routing/src/routing_manager_impl.cpp1285
-rw-r--r--implementation/routing/src/routing_manager_proxy.cpp1124
-rw-r--r--implementation/routing/src/routing_manager_stub.cpp490
-rw-r--r--implementation/runtime/include/application_impl.hpp52
-rw-r--r--implementation/runtime/src/application_impl.cpp342
-rw-r--r--implementation/service_discovery/include/defines.hpp4
-rw-r--r--implementation/service_discovery/include/fsm_base.hpp6
-rw-r--r--implementation/service_discovery/include/ip_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/ipv4_option_impl.hpp1
-rw-r--r--implementation/service_discovery/include/ipv6_option_impl.hpp1
-rwxr-xr-ximplementation/service_discovery/include/message_impl.hpp2
-rw-r--r--implementation/service_discovery/include/service_discovery_host.hpp8
-rw-r--r--implementation/service_discovery/include/service_discovery_impl.hpp16
-rw-r--r--implementation/service_discovery/include/subscription.hpp8
-rwxr-xr-ximplementation/service_discovery/src/entry_impl.cpp40
-rwxr-xr-ximplementation/service_discovery/src/eventgroupentry_impl.cpp12
-rw-r--r--implementation/service_discovery/src/ip_option_impl.cpp5
-rw-r--r--implementation/service_discovery/src/ipv4_option_impl.cpp4
-rwxr-xr-ximplementation/service_discovery/src/ipv6_option_impl.cpp4
-rwxr-xr-ximplementation/service_discovery/src/message_impl.cpp22
-rwxr-xr-ximplementation/service_discovery/src/option_impl.cpp6
-rw-r--r--implementation/service_discovery/src/runtime.cpp9
-rw-r--r--implementation/service_discovery/src/service_discovery_fsm.cpp36
-rw-r--r--implementation/service_discovery/src/service_discovery_impl.cpp610
-rwxr-xr-ximplementation/service_discovery/src/serviceentry_impl.cpp6
-rw-r--r--implementation/service_discovery/src/subscription.cpp6
-rw-r--r--implementation/tracing/include/trace_connector.hpp8
-rw-r--r--implementation/tracing/src/trace_connector.cpp40
-rw-r--r--implementation/tracing/src/trace_header.cpp5
-rw-r--r--implementation/utility/include/criticalsection.hpp44
-rw-r--r--implementation/utility/include/utility.hpp28
-rw-r--r--implementation/utility/src/criticalsection.cpp38
-rw-r--r--implementation/utility/src/utility.cpp403
-rw-r--r--interface/vsomeip/application.hpp28
-rw-r--r--interface/vsomeip/export.hpp12
-rw-r--r--interface/vsomeip/function_types.hpp22
-rw-r--r--interface/vsomeip/payload.hpp3
-rw-r--r--interface/vsomeip/runtime.hpp2
-rw-r--r--test/CMakeLists.txt426
-rwxr-xr-xtest/application_tests/application_test_starter.sh1
-rw-r--r--test/header_factory_tests/header_factory_test.cpp1
-rw-r--r--test/header_factory_tests/header_factory_test_client.cpp1
-rw-r--r--test/header_factory_tests/header_factory_test_service.cpp7
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in75
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in75
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in76
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in76
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in75
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in76
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in75
-rw-r--r--test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in76
-rw-r--r--test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in75
-rw-r--r--test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in76
-rw-r--r--test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in75
-rw-r--r--test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in76
-rw-r--r--test/initial_event_tests/initial_event_test_availability_checker.cpp160
-rw-r--r--test/initial_event_tests/initial_event_test_client.cpp284
-rw-r--r--test/initial_event_tests/initial_event_test_globals.hpp51
-rwxr-xr-xtest/initial_event_tests/initial_event_test_master_starter.sh143
-rw-r--r--test/initial_event_tests/initial_event_test_service.cpp130
-rwxr-xr-xtest/initial_event_tests/initial_event_test_slave_starter.sh123
-rw-r--r--test/initial_event_tests/initial_event_test_stop_service.cpp264
-rw-r--r--test/magic_cookies_tests/magic_cookies_test_client.cpp30
-rw-r--r--test/offer_tests/conf/offer_test_external_master.json.in36
-rwxr-xr-xtest/offer_tests/conf/offer_test_external_master_starter.sh.in114
-rw-r--r--test/offer_tests/conf/offer_test_external_slave.json.in36
-rw-r--r--test/offer_tests/offer_test_client.cpp281
-rw-r--r--test/offer_tests/offer_test_external_sd_msg_sender.cpp74
-rwxr-xr-xtest/offer_tests/offer_test_external_slave_starter.sh45
-rw-r--r--test/offer_tests/offer_test_globals.hpp25
-rw-r--r--test/offer_tests/offer_test_local.json20
-rwxr-xr-xtest/offer_tests/offer_test_local_starter.sh298
-rw-r--r--test/offer_tests/offer_test_service.cpp165
-rw-r--r--test/offer_tests/offer_test_service_external.cpp149
-rw-r--r--test/payload_tests/payload_test_client.cpp5
-rw-r--r--test/payload_tests/payload_test_service.cpp3
-rw-r--r--test/readme.txt121
-rw-r--r--test/routing_tests/external_local_routing_test_service.cpp2
-rw-r--r--test/routing_tests/local_routing_test_client.json2
-rw-r--r--test/routing_tests/local_routing_test_service.cpp5
-rw-r--r--test/routing_tests/local_routing_test_service.json2
-rw-r--r--test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp18
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in54
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in54
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave.json.in70
-rw-r--r--test/subscribe_notify_tests/subscribe_notify_test_globals.hpp13
-rwxr-xr-xtest/subscribe_notify_tests/subscribe_notify_test_master_starter.sh9
-rw-r--r--test/subscribe_notify_tests/subscribe_notify_test_service.cpp70
-rwxr-xr-xtest/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh7
-rw-r--r--tools/vsomeip_ctrl.cpp28
146 files changed, 9097 insertions, 2655 deletions
diff --git a/.gitignore b/.gitignore
index 3aa1ebf..fa624bc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
+/CMakeFiles
/build*/*
/examples/hello_world/build
/.settings
/doc
+/daemon/CMakeFiles
+/examples/CMakeFiles
/implementation/configuration/include/internal.hpp
/test/big_payload_tests/big_payload_test_tcp_client.json
/test/big_payload_tests/big_payload_test_tcp_service.json
@@ -34,7 +37,27 @@
/test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_same_ports_slave.json
/test/subscribe_notify_one_tests/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json
/test/subscribe_notify_one_tests/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave.json
/test/cpu_load_tests/cpu_load_test_client_slave.json
/test/cpu_load_tests/cpu_load_test_client_master.json
/test/cpu_load_tests/cpu_load_test_service_slave.json
/test/cpu_load_tests/cpu_load_test_service_master.json
+/tools/CMakeFiles
+/test/initial_event_tests/initial_event_test_diff_client_ids_diff_ports_master.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_diff_ports_slave.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_partial_same_ports_master.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_partial_same_ports_slave.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_same_ports_master.json
+/test/initial_event_tests/initial_event_test_diff_client_ids_same_ports_slave.json
+/test/initial_event_tests/initial_event_test_same_client_ids_diff_ports_master.json
+/test/initial_event_tests/initial_event_test_same_client_ids_diff_ports_slave.json
+/test/initial_event_tests/initial_event_test_same_client_ids_same_ports_master.json
+/test/initial_event_tests/initial_event_test_same_client_ids_same_ports_slave.json
+/test/offer_tests/offer_test_external_master.json
+/test/offer_tests/offer_test_external_slave.json
+/test/offer_tests/offer_test_external_master_starter.sh
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json
diff --git a/CHANGES b/CHANGES
index 362beb5..4b12f50 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,20 +5,27 @@ v1.1.0
- Local communication in multiprocessor environments was fixed
- Runtime access was changed from raw to shared pointer
- vsomeip logger is used whereever possible (replacing std::cerr calls)
-- Ensure the logger is not deleted before issueing tha last log message when shutting down
-- Fixed shutdown crash by checking the existence of endpoint host before accessing it
-- Routing info processing in case of multiple instances of the same service was fixed
+- Ensure the logger is not deleted before issueing tha last log message when
+ shutting down
+- Fixed shutdown crash by checking the existence of endpoint host before
+ accessing it
+- Routing info processing in case of multiple instances of the same service
+ was fixed
- Support for local communication on Windows was added
v1.2.0
- Added (optional) thread pool for distribution of messages to the application
-- Made configuration of service groups optional (as it is unneeded in pure client applications)
-- Support specification of transportation mode (reliable (TCP) / unreliable (UDP)) when creating messages
+- Made configuration of service groups optional (as it is unneeded in pure
+ client applications)
+- Support specification of transportation mode (reliable (TCP) / unreliable
+ (UDP)) when creating messages
- Fixed internal distribution of notication events
- Block messages that are received on the wrong port
- Fixed deregistration of local clients
-- Fixed startup of applications that were started earlier than the routing manager
-- Resetting all events of a service if it becomes unavailable (to ensure initial events are sent when it becomes available again)
+- Fixed startup of applications that were started earlier than the routing
+ manager
+- Resetting all events of a service if it becomes unavailable (to ensure initial
+ events are sent when it becomes available again)
- Ensure consistency of version information
- Fixed Service Discovery state machine
@@ -41,17 +48,21 @@ v2.0.0
- Added support for IPv6 multicast
- Improved handling of endpoints
- Report service state changes instead of service state to the application
-- Set and process TTL field in Service Discovery to support detection of "lost" services
+- Set and process TTL field in Service Discovery to support detection of "lost"
+ services
- Support automatic configuration of local communication
-- Added compile time variable DIAGNOSIS_ADDRESS (which maps to the high byte of the SOME/IP client identifier)
+- Added compile time variable DIAGNOSIS_ADDRESS (which maps to the high byte of
+ the SOME/IP client identifier)
- Configuration of events was moved from configuration file to API.
- Fixed routing of notication events.
- Increased robustness of configuration loader
- Changed default watchdog cycle from 1s to 5s
- Removed TTL arguments from public interface
-- Allow Service Discovery to report non-SOME/IP services by setting the configuration variable "protocol"
+- Allow Service Discovery to report non-SOME/IP services by setting the
+ configuration variable "protocol"
- Fixed serialization of major version in Eventgroup entries
-- Magic Cookies are no longer forwarded to the routing manager but handled in the receiving endpoint
+- Magic Cookies are no longer forwarded to the routing manager but handled in
+ the receiving endpoint
- vsomeip daemon was added
v2.0.1
@@ -78,7 +89,8 @@ v2.0.3
v2.0.4
- Service Discovery now used configured Client ID prefixes (=DIAGNOSIS_ADDRESS)
- Reworked reboot detection (now based on the destination address)
-- Aligned default TTL setting (was 5 in vsomeip and 0xFFFFFF in vsomeip-sd, now its constently 0xFFFFFF)
+- Aligned default TTL setting (was 5 in vsomeip and 0xFFFFFF in vsomeip-sd, now
+ its constently 0xFFFFFF)
v2.0.5
- Fixed reboot detection behavior
@@ -87,15 +99,18 @@ v2.0.6
- Diagnosis address can be configured at runtime
v2.1.0
-- Avoid duplicate notifications if a selective event is in more than one eventgroup
+- Avoid duplicate notifications if a selective event is in more than one
+ eventgroup
- Ensure SD messages are sent from the SD port
- Ignore SD messages with wrong message identifier
-- Accept unreliable subscription for eventgroups without configured multicast address
+- Accept unreliable subscription for eventgroups without configured multicast
+ address
- Reject subscriptions that contain invalid IP address or port
- Reject subscriptions for TCP if the connection is not established
- Exclude vsomeip_ctrl from default installation
- Only accept SD messages from SD port
-- Acknowledge multiple subscriptions sent within the same message with a single message
+- Acknowledge multiple subscriptions sent within the same message with a single
+ message
- Allow to specify an application specific DLT application
- Ensure correct ordering of availability notifications
- Automatically expire subscription based on the given TTL
@@ -119,8 +134,93 @@ v2.2.0
- Implemented Peer-to-Peer data exchange for notifications
- Fixed handling of minor version during service discovery
- Made initialization of application objects reentrant
-- Routing manager proxies now reconnect to the routing manager if the connection got lost
+- Routing manager proxies now reconnect to the routing manager if the
+ connection got lost
- Auto-configuration supports multiple (different) configuration files
- The opening of TCP connections is no longer done without an explicit request
- Request No Respose messages are no longer answered in case of errors
- Notifications over IP were fixed
+
+v2.2.1
+- Backward compatibility fixes
+
+v2.2.2
+- Ensure multicast messages are sent by the network adapter that is configured
+ to be used for unicasts instead of relying on the configured routes
+
+v2.2.3
+- Ensure service discovery messages to not exceed maximum packet size
+
+v2.2.4
+- Set default log level to DEBUG
+- Improved segmentation of service discovery messages
+- Fixed a race condition during subscriptions
+
+v2.3.0
+- Extend the API to force field notifications
+- Implemented cyclic updated for events/fields
+- Implemented epsilon updates (the used can provide a function to decide
+ whether or not a value update shall be considered as a change)
+- Fixed lifecycle: Wait acknowledge of de/register application
+- Periodically log version information
+- Avoid (shadow) event registrations for services only offered locally
+- Fixed determination of routing manager host in case auto-configuration
+ fails
+- Removed initial flag from internal message format
+- Fixed calling of registered message handlers for cases where wildcards
+ were used during registration.
+- Fixed availability reporting of reliable (TCP) remote services offered
+ on the same port
+
+v2.3.1
+- Fix shutdown crashes (logger & application shutdown)
+- Fix race condition in client identifier configuration
+- Fix vsomeipd crash
+- Fixed handling of notifications (compliance)
+
+v2.3.2
+- Fix client deregistration during the client registration
+- Fix handling of pending commands during registration
+
+v2.3.3
+- Added -q/--quiet switch to the daemon to allow it to be started without
+ DLT logging
+- Fix event caching in routing manager
+
+v2.3.4
+- Exhaust client id range before reuse
+- Provide public interface to ask for available instances
+
+v2.3.5
+- Fix TTL in Subscribe Eventgroup Entries
+
+v2.4.0
+- Disabled tracing SOME/IP-SD messages by default. Set "tracing/sd_enable"
+ switch to "true" to enable it.
+- Trace notification events once instead of per target.
+
+v2.4.1
+- Extended number of endpoints that can be referenced from entries array in
+ service discovery messages
+- Remove DLT contexts on application shutdown
+- Avoid initialization of vsomeip-applications if the maximum number of
+ applications (client identifiers) has been reached
+- Prevent sending of OfferService entry as a reply to FindService message for
+ internal services
+- Fixed deregistration of vsomeip-applications that became unresponsive
+- Fixed loop in endpoints causing high load during shutdown of vsomeip
+ applications
+- Fixed loop in endpoints causing temporary high load if other devices become
+ unavailable without deregistering
+
+v2.4.2
+- TCP connections for services no longer requested aren't reestablished anymore
+- The minor version of a service instance is no longer considered when reporting
+ the service instance's availability
+- Introduce new internal_services json file parameter to define the internal
+ service instances. This parameter can be used to control the sending behaviour
+ for find service entries
+- Fixed event processing if service and client shared the same application
+- Incoming find service entries with unicast flag set to 0 are now replied with
+ a unicast offer service message instead of a multicast offer service message.
+- application::stop() now blocks until the shutdown has finished completely
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5f85a14..2d886cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,8 +7,8 @@ cmake_minimum_required (VERSION 2.8.12)
project (vsomeip)
set (VSOMEIP_MAJOR_VERSION 2)
-set (VSOMEIP_MINOR_VERSION 2)
-set (VSOMEIP_PATCH_VERSION 4)
+set (VSOMEIP_MINOR_VERSION 4)
+set (VSOMEIP_PATCH_VERSION 2)
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)
@@ -59,9 +59,15 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set(OS_CXX_FLAGS "-pthread")
endif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+# Signal handling
+if (ENABLE_SIGNAL_HANDLING)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_ENABLE_SIGNAL_HANDLING")
+endif ()
+
include_directories(
"interface"
)
+
# Threads
find_package(Threads REQUIRED)
@@ -89,6 +95,14 @@ IF(DLT_FOUND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_DLT")
ENDIF(DLT_FOUND)
+# SystemD
+pkg_check_modules(SystemD "libsystemd")
+
+if(NOT SystemD_FOUND)
+MESSAGE( STATUS "Systemd was not found, watchdog disabled!")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITHOUT_SYSTEMD")
+endif(NOT SystemD_FOUND)
+
include_directories(
include
implementation/helper
@@ -110,17 +124,23 @@ file(GLOB vsomeip_SRC
"implementation/runtime/src/*.cpp"
"implementation/utility/src/*.cpp"
)
-
-if (MSVC)
-SET(BOOST_WINDOWS_VERSION "0x600" CACHE STRING "Set the same Version as the Version with which Boost was built, otherwise there will be errors. (normaly 0x600 is for Windows 7 and 0x501 is for Windows XP)")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -DUSE_VSOMEIP_STATISTICS -DCOMMONAPI_INTERNAL_COMPILATION -DBOOST_LOG_DYN_LINK -DBOOST_ASIO_DISABLE_IOCP /EHsc")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -DUSE_VSOMEIP_STATISTICS -DCOMMONAPI_INTERNAL_COMPILATION -DBOOST_LOG_DYN_LINK -DBOOST_ASIO_DISABLE_IOCP /EHsc")
-set(USE_RT "")
-set(Boost_LIBRARIES "")
-link_directories(${Boost_LIBRARY_DIR})
+list(SORT vsomeip_SRC)
+
+add_definitions(-DVSOMEIP_VERSION="${VSOMEIP_VERSION}")
+
+if (MSVC)
+ message("using MSVC Compiler")
+ add_definitions(-DVSOMEIP_DLL_COMPILATION)
+ SET(BOOST_WINDOWS_VERSION "0x600" CACHE STRING "Set the same Version as the Version with which Boost was built, otherwise there will be errors. (normaly 0x600 is for Windows 7 and 0x501 is for Windows XP)")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -DUSE_VSOMEIP_STATISTICS -DCOMMONAPI_INTERNAL_COMPILATION -DBOOST_LOG_DYN_LINK -DBOOST_ASIO_DISABLE_IOCP /EHsc")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -DUSE_VSOMEIP_STATISTICS -DCOMMONAPI_INTERNAL_COMPILATION -DBOOST_LOG_DYN_LINK -DBOOST_ASIO_DISABLE_IOCP /EHsc")
+ set(USE_RT "")
+ set(Boost_LIBRARIES "")
+ 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} -DUSE_VSOMEIP_STATISTICS -DBOOST_LOG_DYN_LINK -g ${OPTIMIZE} -std=c++0x ${NO_DEPRECATED} ${EXPORTSYMBOLS}")
-set(USE_RT "rt")
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${OS} ${OS_CXX_FLAGS} -DUSE_VSOMEIP_STATISTICS -DBOOST_LOG_DYN_LINK -g ${OPTIMIZE} -std=c++0x ${NO_DEPRECATED} ${EXPORTSYMBOLS}")
+ set(USE_RT "rt")
endif()
add_library(vsomeip SHARED ${vsomeip_SRC})
@@ -130,15 +150,16 @@ set_target_properties (vsomeip PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION $
# them (which shouldn't be required). ${Boost_LIBRARIES} includes absolute
# build host paths as of writing, which also makes this important as it breaks
# the build.
-target_link_libraries(vsomeip PRIVATE ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${DLT_LIBRARIES})
+target_link_libraries(vsomeip PRIVATE ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${DLT_LIBRARIES} ${SystemD_LIBRARIES} )
file(GLOB vsomeip-sd_SRC
"implementation/service_discovery/src/*.cpp"
)
+list(SORT vsomeip-sd_SRC)
add_library(vsomeip-sd SHARED ${vsomeip-sd_SRC})
set_target_properties (vsomeip-sd PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION ${VSOMEIP_MAJOR_VERSION})
-target_link_libraries(vsomeip-sd vsomeip ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY})
+target_link_libraries(vsomeip-sd vsomeip ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES})
# Configuration files
@@ -168,12 +189,12 @@ message("Predefined unicast address: ${VSOMEIP_UNICAST_ADDRESS}")
message("Predefined diagnosis address: ${VSOMEIP_DIAGNOSIS_ADDRESS}")
message("Predefined routing application: ${VSOMEIP_ROUTING}")
-
###################################################################################################
set(INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/interface/vsomeip")
file (GLOB_RECURSE vsomeip_INCLUDE RELATIVE ${INCLUDE_PATH} "interface/*.hpp" )
+list (SORT vsomeip_INCLUDE)
foreach ( file ${vsomeip_INCLUDE} )
get_filename_component( dir ${file} DIRECTORY )
@@ -184,8 +205,9 @@ install (
TARGETS vsomeip
# IMPORTANT: Add the vsomeip library to the "export-set"
EXPORT vsomeipTargets
- RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
- LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib
+ RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT
+ LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT
+ ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
COMPONENT dev
)
diff --git a/README b/README
index 79b7eff..8a453af 100644
--- a/README
+++ b/README
@@ -96,6 +96,17 @@ cmake -DDIAGNOSIS_ADDRESS=<YOUR DIAGNOSIS ADDRESS> ..
----
The diagnosis address is a single byte value.
+Compilation with signal handling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To compile vsomeip with signal handling (SIGINT/SIGTERM) enabled,
+call cmake like:
+[source,bash]
+----
+cmake -DENABLE_SIGNAL_HANDLING=1 ..
+----
+In the default setting, the application has to take care of shutting
+down vsomeip in case these signals are received.
+
Compilation of examples
^^^^^^^^^^^^^^^^^^^^^^^
For compilation of the examples call:
@@ -289,9 +300,15 @@ _true, false_).
+
** 'enable'
+
-Specifies whether the tracing of the internal messages is enabled
-(valid values: _true, false_). If tracing is enabled, the messages will be
-forwarded to DLT by the <<traceconnector, Trace Connector>>
+Specifies whether the tracing of the SOME/IP messages is enabled
+(valid values: _true, false_). Default value is _false_.
+If tracing is enabled, the messages will be forwarded to DLT by
+the <<traceconnector, Trace Connector>>
++
+** 'sd_enable'
++
+Specifies whether the tracing of the SOME/IP service discovery messages is
+enabled (valid values: _true, false_). Default value is _false_.
+
** 'channels (array)' (optional)
+
@@ -456,6 +473,15 @@ The multicast address.
+
The multicast port.
+*** `threshold`
++
+Specifies when to use multicast and when to use unicast to send a notification event.
+Must be set to a non-negative number. If it is set to zero, all events of the eventgroup
+will be sent by unicast. Otherwise, the events will be sent by unicast as long as the
+number of subscribers is lower than the threshold and by multicast if the number
+of subscribers is greater or equal. This means, a threshold of 1 will lead to all events
+being sent by multicast. The default value is _0_.
+
* `clients` (array)
+
The client-side ports that shall be used to connect to a specific service.
@@ -519,6 +545,40 @@ service offered on previously specified IP and port. If multiple services are
hosted on the same port all of them are allowed to receive oversized messages
and send oversized responses.
+* `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
+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.
+
+** `first`
++
+The lowest entry of the internal service range.
+
+*** `service`
++
+The lowest Service-ID in hex of the internal service range.
+
+*** `instance` (optional)
++
+The lowest Instance-ID in hex of a internal service-instance range.
+If not specified the lowest Instance-ID is 0x0000.
+
+** `last`
++
+The highest entry of the internal service range.
+
+*** `service`
++
+The highest Service-ID in hex of a internal service range.
+
+*** `instance` (optional)
++
+The highest Instance-ID in hex of a internal service-instance range.
+If not specified the highest Instance-ID is 0xFFFF.
+
* `routing`
+
The name of the application that is responsible for the routing.
@@ -535,11 +595,11 @@ _false_). The default value is _true_.
** `multicast`
+
The multicast address which the messages of the Service Discovery will be sent
-to. The default value is "224.0.0.1".
+to. The default value is _224.0.0.1_.
** `port`
+
-The port of the Service Discovery. The default setting is 30490.
+The port of the Service Discovery. The default setting is _30490_.
** `protocol`
+
diff --git a/README.md b/README.md
deleted file mode 100755
index 8864fec..0000000
--- a/README.md
+++ /dev/null
@@ -1,751 +0,0 @@
-# vSOMEIP
-
-Copyright
-+++++++++
-Copyright (C) 2015, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
-
-License
-+++++++
-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/.
-
-Version
-+++++++
-// set the version to the one we get from cmake
-// or pass it via -a version=$VSOMEIP_VERSION to asciidoc
-This documentation was generated for version {version} of vsomeip.
-
-vsomeip Overview
-----------------
-The vsomeip stack implements the http://some-ip.com/[Scalable service-Oriented
-MiddlewarE over IP (SOME/IP)] protocol. The stack consists out of:
-
-* a shared library for SOME/IP (`libvsomeip.so`)
-* a second shared library for SOME/IP's service discovery (`libvsomeip-sd.so`)
- which is loaded during runtime if the service discovery is enabled.
-
-Build Instructions
-------------------
-Dependencies
-~~~~~~~~~~~~
-* A C++11 enabled compiler like gcc >= 4.8 is needed.
-* vsomeip uses cmake as buildsystem.
-* vsomeip uses Boost >= 1.54:
-** Ubuntu 14.04:
-*** `sudo apt-get install libboost-system1.54-dev libboost-thread1.54-dev
- libboost-log1.54-dev`
-** Ubuntu 12.04: a PPA is necessary to use version 1.54 of Boost:
-*** URL: https://launchpad.net/~boost-latest/+archive/ubuntu/ppa
-*** `sudo add-apt-repository ppa:boost-latest/ppa`
-*** `sudo apt-get install libboost-system1.54-dev libboost-thread1.54-dev
- libboost-log1.54-dev`
-* For the tests Google's test framework
- https://code.google.com/p/googletest/[gtest] in version 1.7.0 is needed
-** URL: https://googletest.googlecode.com/files/gtest-1.7.0.zip[direct link,
- version 1.7.0]
-* To build the documentation asciidoc, source-highlight, doxygen and graphviz is needed:
-** `sudo apt-get install asciidoc source-highlight doxygen graphviz`
-
-Compilation
-~~~~~~~~~~~
-anchor:Compilation[]
-For compilation call:
-[source, bash]
-----
-mkdir build
-cd build
-cmake ..
-make
-----
-
-To specify a installation directory (like `--prefix=` if you're used to
-autotools) call cmake like:
-[source, bash]
-----
-cmake -DCMAKE_INSTALL_PREFIX:PATH=$YOUR_PATH ..
-make
-make install
-----
-
-Compilation of examples
-^^^^^^^^^^^^^^^^^^^^^^^
-For compilation of the examples call:
-[source, bash]
-----
-mkdir build
-cd build
-cmake ..
-make examples
-----
-
-Compilation of tests
-^^^^^^^^^^^^^^^^^^^^
-To compile the tests, first unzip gtest to location of your desire.
-Some of the tests require a second node on the same network. There are two cmake
-variables which are used to automatically adapt the json files to the used
-network setup:
-
-* `TEST_IP_MASTER`: The IP address of the interface which will act as test
- master.
-* `TEST_IP_SLAVE`: The IP address of the interface of the second node which will
- act as test slave.
-
-If one of this variables isn't specified, only the tests using local
-communication exclusively will be runnable.
-
-Example, compilation of tests:
-[source, bash]
-----
-mkdir build
-cd build
-export GTEST_ROOT=$PATH_TO_GTEST/gtest-1.7.0/
-cmake -DTEST_IP_MASTER=10.0.3.1 -DTEST_IP_SLAVE=10.0.3.125 ..
-make check
-----
-
-Additional make targets for the tests:
-
-* Call `make build_tests` to only compile the tests
-* Call `ctest` in the build directory to execute the tests without a verbose
- output
-* To run single tests call `ctest --verbose --tests-regex $TESTNAME` short
- form: `ctest -V -R $TESTNAME`
-* To list all available tests run `ctest -N`.
-* For further information about the tests please have a look at the
- `readme.txt` in the `test` subdirectory.
-
-For development purposes two cmake variables exist which control if the
-json files and test scripts are copied (default) or symlinked into the build
-directory. These settings are ignored on Windows.
-
-* `TEST_SYMLINK_CONFIG_FILES`: Controls if the json and scripts needed
- to run the tests are copied or symlinked into the build directory. (Default:
- OFF, ignored on Windows)
-* `TEST_SYMLINK_CONFIG_FILES_RELATIVE`: Controls if the json and scripts needed
- to run the tests are symlinked relatively into the build directory.
- (Default: OFF, ignored on Windows)
-
-Example cmake call:
-[source, bash]
-----
-cmake -DTEST_SYMLINK_CONFIG_FILES=ON -DTEST_SYMLINK_CONFIG_FILES_RELATIVE=ON ..
-----
-
-For compilation of only a subset of tests (for a quick
-functionality check) the cmake variable `TESTS_BAT` has
-to be set:
-
-Example cmake call:
-[source, bash]
-----
-cmake -DTESTS_BAT=ON ..
-----
-
-Generating the documentation
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-To generate the documentation call cmake as described in <<Compilation>> and
-then call `make doc`.
-This will generate:
-
-* The README file in html: `$BUILDDIR/documentation/README.html`
-* A doxygen documentation in `$BUILDDIR/documentation/html/index.html`
-
-Starting vsomeip Applications / Used environment variables
-----------------------------------------------------------
-On startup the following environment variables are read out:
-
-* `VSOMEIP_APPLICATION_NAME`: This environment variable is used to specify the
- name of the application. This name is later used to map a client id to the
- application in the configuration file. It is independent from the
- application's binary name.
-* `VSOMEIP_CONFIGURATION`: vsomeip uses the default configuration file `/etc/vsomeip.json`
- and/or the default configuration folder `/etc/vsomeip`. This can be overridden by a
- local configuration file `./vsomeip.json` and/or a local configuration folder `./vsomeip`.
- If `VSOMEIP_CONFIGURATION` is set to a valid file or directory path, this is used instead
- of the standard configuration (thus neither default nor local file/folder will be parsed).
-
-NOTE: If the file/folder that is configured by `VSOMEIP_CONFIGURATION` does _not_ exist,
-the default configuration locations will be used.
-
-NOTE: vsomeip will parse and use the configuration from all files in a configuration folder
-but will _not_ consider directories within the configuration folder.
-
-In the following example the application `my_vsomeip_application` is started.
-The settings are read from the file `my_settings.json` in the current working
-directory. The client id for the application can be found under the name
-`my_vsomeip_client` in the configuration file.
-
-[source, bash]
-----
-#!/bin/bash
-export VSOMEIP_APPLICATION_NAME=my_vsomeip_client
-export VSOMEIP_CONFIGURATION=my_settings.json
-./my_vsomeip_application
-----
-
-Configuration File Structure
-----------------------------
-The configuration files for vsomeip are http://www.json.org/[JSON]-Files and are
-composed out of multiple key value pairs and arrays.
-
-[quote, , json.org]
-____
-* An object is an unordered set of name/value pairs. An object begins with `{
-(left brace)` and ends with `} (right brace)`. Each name is followed by `:
-(colon)` and the name/value pairs are separated by `, (comma)`.
-
-* An array is an ordered collection of values. An array begins with `[ (left
-bracket)` and ends with `] (right bracket)`. Values are separated by `,
-(comma)`.
-
-* A value can be a _string_ in double quotes, or a _number_, or `true` or `false`
-or `null`, or an _object_ or an _array_. These structures can be nested.
-____
-
-Configuration file element explanation:
-
-
-* 'unicast'
-+
-The IP address of the host system.
-+
-* 'netmask'
-+
-The netmask to specify the subnet of the host system.
-+
-//Logging
-* 'logging'
-+
-** 'level'
-+
-Specifies the log level (valid values: _trace_, _debug_, _info_, _warning_,
-_error_, _fatal_).
-+
-** 'console'
-+
-Specifies whether logging via console is enabled (valid values: _true, false_).
-+
-** 'file'
-+
-*** 'enable'
-+
-Specifies whether a log file should be created (valid values: _true, false_).
-+
-*** 'path'
-+
-The absolute path of the log file.
-+
-** 'dlt'
-+
-Specifies whether Diagnostic Log and Trace (DLT) is enabled (valid values:
-_true, false_).
-+
-//Applications
-* 'applications (array)'
-+
-Contains the applications of the host system that use this config file.
-+
-** 'name'
-+
-The name of the application.
-+
-** 'id'
-+
-The id of the application.
-+
-** 'num_dispatchers'
-+
-The number of threads that shall be used to execute the callbacks to the application.
-If 'num_dispatchers' is set to '0', the callbacks will be executed within the
-application thread. If an application wants/must do time consuming work directly
-within event, availability or message callbacks, 'num_dispatchers' should be set
-to '2' or higher.
-+
-** `services` (array)
-+
-Contains the services of the service provider.
-
-*** `service`
-+
-The id of the service.
-
-*** `instance`
-+
-The id of the service instance.
-
-*** `protocol` (optional)
-+
-The protocol that is used to implement the service instance. The default setting
-is _someip_. If a different setting is provided, vsomeip does not open the specified
-port (server side) or does not connect to the specified port (client side). Thus,
-this option can be used to let the service discovery announce a service that is
-externally implemented.
-
-*** `unicast` (optional)
-+
-The unicast that hosts the service instance.
-+
-NOTE: The unicast address is needed if external service instances shall be used,
-but service discovery is disabled. In this case, the provided unicast address
-is used to access the service instance.
-
-*** `reliable`
-+
-Specifies that the communication with the service is reliable respectively the
-TCP protocol is used for communication.
-
-**** `port`
-+
-The port of the TCP endpoint.
-
-**** `enable-magic-cookies`
-+
-Specifies whether magic cookies are enabled (valid values: _true_, _false_).
-
-*** `unreliable`
-+
-Specifies that the communication with the service is unreliable respectively the
-UDP protocol is used for communication (valid values: the _port_ of the UDP
-endpoint).
-
-*** `multicast`
-+
-A service can be offered to a specific group of clients via multicast.
-
-**** `address`
-+
-The specific multicast address.
-
-**** `port`
-+
-The specific port.
-
-*** `events` (array)
-+
-Contains the events of the service.
-
-**** `event`
-+
-The id of the event.
-
-***** `is_field`
-+
-Specifies whether the event is of type field.
-+
-NOTE: A field is a combination of getter, setter and notification event. It
-contains at least a getter, a setter, or a notifier. The notifier sends an event
-message that transports the current value of a field on change.
-
-***** `is_reliable`
-+
-Specifies whether the communication is reliable respectively whether the event
-is sent with the TCP protocol (valid values: _true_,_false_).
-+
-If the value is _false_ the UDP protocol will be used.
-
-*** `eventgroups` (array)
-+
-Events can be grouped together into on event group. For a client it is thus
-possible to subscribe for an event group and to receive the appropriate events
-within the group.
-
-**** `eventgroup`
-+
-The id of the event group.
-
-**** `events` (array)
-+
-Contains the ids of the appropriate events.
-
-**** `is_multicast`
-+
-Specifies whether the events should be sent via multicast (valid values:
-_true_,_false_).
-
-**** `multicast`
-+
-The multicast address which the events are sent to.
-
-* `payload-sizes` (array)
-+
-Array to specify the maximum allowed payload sizes per IP and port. If not
-specified, or a smaller value than the default values is specified, the default
-values are used. The settings in this array only affect communication over TCP
-and local communication over UNIX domain sockets.
-
-** `unicast`
-+
-On client side: the IP of the remote service to which the oversized messages
-should be sent.
-On service side: the IP of the offered service which should receive the
-oversized messages and is allowed to respond with oversized messages.
-If client and service only communicate locally, any IP can be entered here as
-for local communication only the maximum specified payload size is relevant.
-
-** `ports` (array)
-+
-Array which holds pairs of port and payload-size statements.
-
-*** `port`
-+
-On client side: the port of the remote service to which the oversized messages
-should be sent.
-On service side: the port of the offered service which should receive the
-oversized messages and is allowed to respond with oversized messages.
-If client and service only communicate locally, any port number can be entered.
-
-*** `max-payload-size`
-+
-On client side: the maximum payload size in bytes of a message sent to the
-remote service hosted on beforehand specified IP and port.
-On service side: the maximum payload size in bytes of messages received by the
-service offered on previously specified IP and port. If multiple services are
-hosted on the same port all of them are allowed to receive oversized messages
-and send oversized responses.
-
-* `routing`
-+
-The name of the application that is responsible for the routing.
-
-* `service-discovery`
-+
-Contains settings related to the Service Discovery of the host application.
-
-** `enable`
-+
-Specifies whether the Service Discovery is enabled (valid values: _true_,
-_false_). The default value is _true_.
-
-** `multicast`
-+
-The multicast address which the messages of the Service Discovery will be sent
-to. The default value is "224.0.0.1".
-
-** `port`
-+
-The port of the Service Discovery. The default setting is 30490.
-
-** `protocol`
-+
-The protocol that is used for sending the Service Discovery messages (valid
-values: _tcp_, _udp_). The default setting is _udp_.
-
-** `initial_delay_min`
-+
-Minimum delay before first offer message.
-
-** `initial_delay_max`
-+
-Maximum delay before first offer message.
-
-** `repetitions_base_delay`
-+
-Base delay sending offer messages within the repetition phase.
-
-** `repetitions_max`
-+
-Maximum number of repetitions for provided services within the
-repetition phase.
-
-** `ttl`
-+
-Lifetime of entries for provided services as well as consumed services and eventgroups.
-
-** `cyclic_offer_delay`
-+
-Cycle of the OfferService messages in the main phase.
-
-** `request_response_delay`
-+
-Minimum delay of a unicast message to a multicast message for
-provided services and eventgroups.
-
-Autoconfiguration
------------------
-vsomeip supports the automatic configuration of client identifiers and the routing.
-The first application that starts using vsomeip will automatically become the
-routing manager if it is _not_ explicitly configured. The client identifiers
-are generated from the diagnosis address that can be specified by defining
-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.
-
-vsomeipd
---------
-The vsomeipd is a minimal vsomeip application intended to offer routing manager
-functionality on a node where one system wide configuration file is present.
-
-The vsomeipd uses the application name `vsomeipd` by default. This name can be
-overridden by specifying `-DROUTING=$DESIRED_NAME` during the cmake call.
-
-Example: Starting the daemon on a system where the system wide configuration is
-stored under `/etc/vsomeip.json`:
-[source, bash]
-----
-VSOMEIP_CONFIGURATION=/etc/vsomeip.json ./vsomeipd
-----
-
-When using the daemon it should be ensured that:
-
-* In the system wide configuration file the vsomeipd is defined as
- routing manager, meaning it contains the line `"routing" : "vsomeipd"`.
- If the default name is overridden the entry has to be adapted accordingly.
- The system wide configuration file should contain the information about all
- other offered services on the system as well.
-* There's no other vsomeip configuration file used on the system which contains
- a `"routing"` entry. As there can only be one routing manager per system.
-
-
-vsomeip Hello World
--------------------
-In this paragraph a Hello World program consisting out of a client and a service
-is developed. The client sends a message containing a string to the service.
-The service appends the received string to the string `Hello` and sends it back
-to the client.
-Upon receiving a response from the service the client prints the payload of the
-response ("Hello World").
-This example is intended to be run on the same host.
-
-All files listed here are contained in the `examples\hello_world` subdirectory.
-
-Build instructions
-~~~~~~~~~~~~~~~~~~
-The example can build with its own CMakeFile, please compile the vsomeip stack
-before hand as described in <<Compilation>>. Then compile the example starting
-from the repository root directory as followed:
-[source, bash]
-----
-cd examples/hello_world
-mkdir build
-cd build
-cmake ..
-make
-----
-
-Starting and expected output
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Starting and expected output of service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-[source, bash]
-----
-$ VSOMEIP_CONFIGURATION=../helloworld-local.json \
- VSOMEIP_APPLICATION_NAME=hello_world_service \
- ./hello_world_service
-2015-04-01 11:31:13.248437 [info] Using configuration file: ../helloworld-local.json
-2015-04-01 11:31:13.248766 [debug] Routing endpoint at /tmp/vsomeip-0
-2015-04-01 11:31:13.248913 [info] Service Discovery disabled. Using static routing information.
-2015-04-01 11:31:13.248979 [debug] Application(hello_world_service, 4444) is initialized.
-2015-04-01 11:31:22.705010 [debug] Application/Client 5555 got registered!
-----
-
-Starting and expected output of client
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-[source, bash]
-----
-$ VSOMEIP_CONFIGURATION=../helloworld-local.json \
- VSOMEIP_APPLICATION_NAME=hello_world_client \
- ./hello_world_client
-2015-04-01 11:31:22.704166 [info] Using configuration file: ../helloworld-local.json
-2015-04-01 11:31:22.704417 [debug] Connecting to [0] at /tmp/vsomeip-0
-2015-04-01 11:31:22.704630 [debug] Listening at /tmp/vsomeip-5555
-2015-04-01 11:31:22.704680 [debug] Application(hello_world_client, 5555) is initialized.
-Sending: World
-Received: Hello World
-----
-
-CMakeFile
-~~~~~~~~~
-
-[source, bash]
-----
-include::examples/hello_world/CMakeLists.txt[]
-----
-
-Configuration File For Client and Service
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-[source, bash]
-----
-include::examples/hello_world/helloworld-local.json[]
-----
-
-Service
-~~~~~~~
-
-[source, bash]
-----
-include::examples/hello_world/hello_world_service.cpp[]
-----
-
-The service example results in the following program execution:
-
-:numbered!:
-
-[float]
-
-Main
-^^^^^
-
-. __main()__
-+
-First the application is initialized. After the initialization is
-finished the application is started.
-
-[float]
-Initialization
-^^^^^^^^^^^^^^
-
-[start=2]
-. __init()__
-+
-The initialization contains the registration of a message
-handler and an event handler.
-+
-The message handler declares a callback (__on_message_cbk__) for messages that
-are sent to the specific service (specifying the service id, the service
-instance id and the service method id).
-+
-The event handler declares a callback (__on_event_cbk__) for events that occur.
-One event can be the successful registration of the application at the runtime.
-
-[float]
-Start
-^^^^^
-
-[start=3]
-. __start()__
-+
-The application will be started. This function only returns when the application
-will be stopped.
-
-[float]
-Callbacks
-^^^^^^^^^
-
-[start=4]
-. __on_state_cbk()__
-+
-This function is called by the application when an state change occurred. If
-the application was successfully registered at the runtime then the specific
-service is offered.
-
-. __on_message_cbk()__
-+
-This function is called when a message/request from a client for the specified
-service was received.
-+
-First a response based upon the request is created.
-Afterwards the string 'Hello' will be concatenated with the payload of the
-client's request.
-After that the payload of the response is created. The payload data is set with
-the previously concatenated string.
-Finally the response is sent back to the client and the application is stopped.
-
-[float]
-Stop
-^^^^
-
-[start=6]
-. __stop()__
-+
-This function stops offering the service, unregister the message and the event
-handler and shuts down the application.
-
-:numbered:
-
-Client
-~~~~~~
-[source, bash]
-----
-include::examples/hello_world/hello_world_client.cpp[]
-----
-
-The client example results in the following program execution:
-
-:numbered!:
-
-[float]
-Main
-^^^^^
-
-. __main()__
-+
-First the application is initialized. After the initialization is finished the
-application is started.
-
-[float]
-Initialization
-^^^^^^^^^^^^^^
-
-[start=2]
-. __init()__
-+
-The initialization contains the registration of a message handler, an event
-handler and an availability handler.
-+
-The event handler declares again a callback (__on_state_cbk__) for state changes
-that occur.
-+
-The message handler declares a callback (__on_message_cbk__) for messages that
-are received from any service, any service instance and any method.
-+
-The availability handler declares a callback (__on_availability_cbk__) which is
-called when the specific service is available (specifying the service id and the
-service instance id).
-
-[float]
-Start
-^^^^^
-
-[start=3]
-. __start()__
-+
-The application will be started. This function only returns when the application
-will be stopped.
-
-[float]
-Callbacks
-^^^^^^^^^
-
-[start=4]
-. __on_state_cbk()__
-+
-
-This function is called by the application when an state change occurred. If the
-application was successfully registered at the runtime then the specific service
-is requested.
-
-. __on_availability_cbk()__
-+
-This function is called when the requested service is available or no longer
-available.
-+
-First there is a check if the change of the availability is related to the
-'hello world service' and the availability changed to true.
-If the check is successful a service request is created and the appropriate
-service information are set (service id, service instance id, service method
-id).
-After that the payload of the request is created. The data of the payload is
-'World' and will be set afterwards.
-Finally the request is sent to the service.
-
-. __on_message_cbk()__
-+
-This function is called when a message/response was received.
-If the response is from the requested service, of type 'RESPONSE' and the return
-code is 'OK' then the payload of the response is printed. Finally the
-application is stopped.
-
-[float]
-Stop
-^^^^
-
-[start=7]
-. __stop()__
-+
-This function unregister the event and the message handler and shuts down the
-application.
-
-:numbered:
diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt
index 09d8b03..43a8f0a 100644
--- a/daemon/CMakeLists.txt
+++ b/daemon/CMakeLists.txt
@@ -7,7 +7,7 @@ cmake_minimum_required (VERSION 2.8)
# Daemon
add_executable(vsomeipd vsomeipd.cpp)
-target_link_libraries(vsomeipd vsomeip ${Boost_LIBRARIES} ${systemd-journal_LIBRARIES} ${DL_LIBRARY} ${DLT_LIBRARIES})
+target_link_libraries(vsomeipd vsomeip ${Boost_LIBRARIES} ${DL_LIBRARY} ${DLT_LIBRARIES})
install (
TARGETS vsomeipd
diff --git a/daemon/vsomeipd.cpp b/daemon/vsomeipd.cpp
index 54c6b9b..d924ac9 100644
--- a/daemon/vsomeipd.cpp
+++ b/daemon/vsomeipd.cpp
@@ -5,6 +5,7 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <signal.h>
#include <unistd.h>
#include <iostream>
@@ -18,13 +19,29 @@
#include "../implementation/logging/include/defines.hpp"
#endif
+static std::shared_ptr<vsomeip::application> its_application;
+
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+/*
+ * Handle signal to stop the daemon
+ */
+void vsomeipd_stop(int _signal) {
+ if (_signal == SIGINT || _signal == SIGTERM)
+ its_application->stop();
+}
+#endif
+
/*
* Create a vsomeip application object and start it.
*/
-int process(void) {
+int vsomeipd_process(bool _is_quiet) {
#ifdef USE_DLT
- DLT_REGISTER_APP(VSOMEIP_LOG_DEFAULT_APPLICATION_ID, VSOMEIP_LOG_DEFAULT_APPLICATION_NAME);
+ if (!_is_quiet)
+ DLT_REGISTER_APP(VSOMEIP_LOG_DEFAULT_APPLICATION_ID, VSOMEIP_LOG_DEFAULT_APPLICATION_NAME);
+#else
+ (void)_is_quiet;
#endif
+
std::shared_ptr<vsomeip::runtime> its_runtime
= vsomeip::runtime::get();
@@ -32,9 +49,13 @@ int process(void) {
return -1;
}
- std::shared_ptr<vsomeip::application> its_application
- = its_runtime->create_application(VSOMEIP_ROUTING);
-
+ // Create the application object
+ its_application = its_runtime->create_application(VSOMEIP_ROUTING);
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ // Handle signals
+ signal(SIGINT, vsomeipd_stop);
+ signal(SIGTERM, vsomeipd_stop);
+#endif
if (its_application->init()) {
if (its_application->is_routing()) {
its_application->start();
@@ -49,19 +70,23 @@ int process(void) {
* Parse command line options
* -h | --help print usage information
* -d | --daemonize start background processing by forking the process
+ * -q | --quiet do _not_ use dlt logging
*
* and start processing.
*/
int main(int argc, char **argv) {
bool must_daemonize(false);
+ bool is_quiet(false);
if (argc > 1) {
for (int i = 0; i < argc; i++) {
std::string its_argument(argv[i]);
if (its_argument == "-d" || its_argument == "--daemonize") {
must_daemonize = true;
+ } else if (its_argument == "-q" || its_argument == "--quiet") {
+ is_quiet = true;
} else if (its_argument == "-h" || its_argument == "--help") {
std::cout << "usage: "
- << argv[0] << " [-h|--help][-d|--daemonize]"
+ << argv[0] << " [-h|--help][-d|--daemonize][-q|--quiet]"
<< std::endl;
return 0;
}
@@ -90,5 +115,5 @@ int main(int argc, char **argv) {
}
}
- return process();
+ return vsomeipd_process(is_quiet);
}
diff --git a/examples/hello_world/CMakeLists.txt b/examples/hello_world/CMakeLists.txt
index cb32665..d6bc994 100644
--- a/examples/hello_world/CMakeLists.txt
+++ b/examples/hello_world/CMakeLists.txt
@@ -14,12 +14,14 @@ if (NOT vsomeip_FOUND)
message("vsomeip was not found. Please specify vsomeip_DIR")
endif()
+find_package(Threads REQUIRED)
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include_directories(${VSOMEIP_INCLUDE_DIRS})
add_executable (hello_world_service hello_world_service.cpp)
-target_link_libraries(hello_world_service ${VSOMEIP_LIBRARIES})
+target_link_libraries(hello_world_service ${VSOMEIP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_executable (hello_world_client hello_world_client.cpp)
-target_link_libraries(hello_world_client ${VSOMEIP_LIBRARIES})
+target_link_libraries(hello_world_client ${VSOMEIP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
diff --git a/examples/hello_world/hello_world_client.cpp b/examples/hello_world/hello_world_client.cpp
index 8007c32..8d5b33c 100644
--- a/examples/hello_world/hello_world_client.cpp
+++ b/examples/hello_world/hello_world_client.cpp
@@ -2,7 +2,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+#include <csignal>
+#endif
#include <vsomeip/vsomeip.hpp>
#include <iostream>
@@ -125,9 +127,23 @@ private:
std::shared_ptr<vsomeip::application> app_;
};
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+hello_world_client *hw_cl_ptr(nullptr);
+ void handle_signal(int _signal) {
+ if (hw_cl_ptr != nullptr &&
+ (_signal == SIGINT || _signal == SIGTERM))
+ hw_cl_ptr->stop();
+ }
+#endif
+
int main(int argc, char **argv)
{
hello_world_client hw_cl;
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ hw_cl_ptr = &hw_cl;
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+#endif
hw_cl.init();
hw_cl.start();
return 0;
diff --git a/examples/hello_world/hello_world_service.cpp b/examples/hello_world/hello_world_service.cpp
index b99a401..7e6b615 100644
--- a/examples/hello_world/hello_world_service.cpp
+++ b/examples/hello_world/hello_world_service.cpp
@@ -2,7 +2,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+#include <csignal>
+#endif
#include <vsomeip/vsomeip.hpp>
#include <chrono>
#include <thread>
@@ -75,6 +77,12 @@ public:
app_->stop();
}
+ void terminate() {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ stop_ = true;
+ condition_.notify_one();
+ }
+
void on_state_cbk(vsomeip::state_type_e _state)
{
if(_state == vsomeip::state_type_e::ST_REGISTERED)
@@ -104,9 +112,7 @@ public:
// Send the response back
app_->send(resp, true);
// we're finished stop now
- std::lock_guard<std::mutex> its_lock(mutex_);
- stop_ = true;
- condition_.notify_one();
+ terminate();
}
private:
@@ -118,9 +124,23 @@ private:
std::thread stop_thread_;
};
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+hello_world_service *hw_srv_ptr(nullptr);
+ void handle_signal(int _signal) {
+ if (hw_srv_ptr != nullptr &&
+ (_signal == SIGINT || _signal == SIGTERM))
+ hw_srv_ptr->terminate();
+ }
+#endif
+
int main(int argc, char **argv)
{
hello_world_service hw_srv;
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ hw_srv_ptr = &hw_srv;
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+#endif
hw_srv.init();
hw_srv.start();
return 0;
diff --git a/examples/notify-sample.cpp b/examples/notify-sample.cpp
index 12c9a4c..172bf7d 100644
--- a/examples/notify-sample.cpp
+++ b/examples/notify-sample.cpp
@@ -2,7 +2,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+#include <csignal>
+#endif
#include <chrono>
#include <condition_variable>
#include <iomanip>
@@ -22,6 +24,7 @@ public:
use_tcp_(_use_tcp),
cycle_(_cycle),
blocked_(false),
+ running_(true),
is_offered_(false),
offer_thread_(std::bind(&service_sample::run, this)),
notify_thread_(std::bind(&service_sample::notify, this)) {
@@ -67,6 +70,21 @@ public:
app_->start();
}
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ /*
+ * Handle signal to shutdown
+ */
+ void stop() {
+ running_ = false;
+ blocked_ = true;
+ condition_.notify_one();
+ notify_condition_.notify_one();
+ offer_thread_.join();
+ notify_thread_.join();
+ app_->stop();
+ }
+#endif
+
void offer() {
std::lock_guard<std::mutex> its_lock(notify_mutex_);
app_->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
@@ -117,13 +135,15 @@ public:
condition_.wait(its_lock);
bool is_offer(true);
- while (true) {
+ while (running_) {
if (is_offer)
offer();
else
stop_offer();
- std::this_thread::sleep_for(std::chrono::milliseconds(10000));
+ for (int i = 0; i < 10 && running_; i++)
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+
is_offer = !is_offer;
}
}
@@ -139,11 +159,11 @@ public:
vsomeip::byte_t its_data[10];
uint32_t its_size = 1;
- while (true) {
+ while (running_) {
std::unique_lock<std::mutex> its_lock(notify_mutex_);
- while (!is_offered_)
+ while (!is_offered_ && running_)
notify_condition_.wait(its_lock);
- while (is_offered_) {
+ while (is_offered_ && running_) {
if (its_size == sizeof(its_data))
its_size = 1;
@@ -171,6 +191,7 @@ private:
std::mutex mutex_;
std::condition_variable condition_;
bool blocked_;
+ bool running_;
std::mutex notify_mutex_;
std::condition_variable notify_condition_;
@@ -183,6 +204,15 @@ private:
std::thread notify_thread_;
};
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ service_sample *its_sample_ptr(nullptr);
+ void handle_signal(int _signal) {
+ if (its_sample_ptr != nullptr &&
+ (_signal == SIGINT || _signal == SIGTERM))
+ its_sample_ptr->stop();
+ }
+#endif
+
int main(int argc, char **argv) {
bool use_tcp = false;
uint32_t cycle = 1000; // default 1s
@@ -210,6 +240,11 @@ int main(int argc, char **argv) {
}
service_sample its_sample(use_tcp, cycle);
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ its_sample_ptr = &its_sample;
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+#endif
its_sample.init();
its_sample.start();
diff --git a/examples/request-sample.cpp b/examples/request-sample.cpp
index 86834d0..93b8f0e 100644
--- a/examples/request-sample.cpp
+++ b/examples/request-sample.cpp
@@ -2,7 +2,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+#include <csignal>
+#endif
#include <chrono>
#include <condition_variable>
#include <iomanip>
@@ -77,6 +79,19 @@ public:
app_->start();
}
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ /*
+ * Handle signal to shutdown
+ */
+ void stop() {
+ running_ = false;
+ blocked_ = true;
+ condition_.notify_one();
+ sender_.join();
+ app_->stop();
+ }
+#endif
+
void on_state(vsomeip::state_type_e _state) {
if (_state == vsomeip::state_type_e::ST_REGISTERED) {
app_->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
@@ -165,6 +180,14 @@ private:
std::thread sender_;
};
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ client_sample *its_sample_ptr(nullptr);
+ void handle_signal(int _signal) {
+ if (its_sample_ptr != nullptr &&
+ (_signal == SIGINT || _signal == SIGTERM))
+ its_sample_ptr->stop();
+ }
+#endif
int main(int argc, char **argv) {
bool use_tcp = false;
@@ -194,6 +217,11 @@ int main(int argc, char **argv) {
}
client_sample its_sample(use_tcp, be_quiet, cycle);
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ its_sample_ptr = &its_sample;
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+#endif
its_sample.init();
its_sample.start();
return 0;
diff --git a/examples/response-sample.cpp b/examples/response-sample.cpp
index c3ef177..883d821 100644
--- a/examples/response-sample.cpp
+++ b/examples/response-sample.cpp
@@ -2,7 +2,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+#include <csignal>
+#endif
#include <chrono>
#include <condition_variable>
#include <iomanip>
@@ -21,6 +23,7 @@ public:
is_registered_(false),
use_static_routing_(_use_static_routing),
blocked_(false),
+ running_(true),
offer_thread_(std::bind(&service_sample::run, this)) {
}
@@ -44,6 +47,19 @@ public:
app_->start();
}
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ /*
+ * Handle signal to shutdown
+ */
+ void stop() {
+ running_ = false;
+ blocked_ = true;
+ condition_.notify_one();
+ offer_thread_.join();
+ app_->stop();
+ }
+#endif
+
void offer() {
app_->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app_->offer_service(SAMPLE_SERVICE_ID + 1, SAMPLE_INSTANCE_ID);
@@ -101,14 +117,16 @@ public:
if (use_static_routing_) {
offer();
- while (true);
+ while (running_);
} else {
- while (true) {
+ while (running_) {
if (is_offer)
offer();
else
stop_offer();
- std::this_thread::sleep_for(std::chrono::milliseconds(10000));
+
+ for (int i = 0; i < 10 && running_; i++)
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
is_offer = !is_offer;
}
}
@@ -122,11 +140,21 @@ private:
std::mutex mutex_;
std::condition_variable condition_;
bool blocked_;
+ bool running_;
// blocked_ must be initialized before the thread is started.
std::thread offer_thread_;
};
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ service_sample *its_sample_ptr(nullptr);
+ void handle_signal(int _signal) {
+ if (its_sample_ptr != nullptr &&
+ (_signal == SIGINT || _signal == SIGTERM))
+ its_sample_ptr->stop();
+ }
+#endif
+
int main(int argc, char **argv) {
bool use_static_routing(false);
@@ -139,6 +167,11 @@ int main(int argc, char **argv) {
}
service_sample its_sample(use_static_routing);
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ its_sample_ptr = &its_sample;
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+#endif
its_sample.init();
its_sample.start();
diff --git a/examples/subscribe-sample.cpp b/examples/subscribe-sample.cpp
index 915ea11..38b80c8 100644
--- a/examples/subscribe-sample.cpp
+++ b/examples/subscribe-sample.cpp
@@ -2,7 +2,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+#include <csignal>
+#endif
#include <chrono>
#include <condition_variable>
#include <iomanip>
@@ -57,6 +59,15 @@ public:
app_->start();
}
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ /*
+ * Handle signal to shutdown
+ */
+ void stop() {
+ app_->stop();
+ }
+#endif
+
void on_state(vsomeip::state_type_e _state) {
if (_state == vsomeip::state_type_e::ST_REGISTERED) {
app_->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
@@ -134,6 +145,15 @@ private:
bool be_quiet_;
};
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ client_sample *its_sample_ptr(nullptr);
+ void handle_signal(int _signal) {
+ if (its_sample_ptr != nullptr &&
+ (_signal == SIGINT || _signal == SIGTERM))
+ its_sample_ptr->stop();
+ }
+#endif
+
int main(int argc, char **argv) {
bool use_tcp = false;
@@ -151,6 +171,11 @@ int main(int argc, char **argv) {
}
client_sample its_sample(use_tcp);
+#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
+ its_sample_ptr = &its_sample;
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+#endif
its_sample.init();
its_sample.start();
return 0;
diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp
index 8dab1b4..e33a0df 100644
--- a/implementation/configuration/include/configuration.hpp
+++ b/implementation/configuration/include/configuration.hpp
@@ -25,7 +25,7 @@ namespace vsomeip {
class event;
-class VSOMEIP_EXPORT configuration {
+class VSOMEIP_IMPORT_EXPORT configuration {
public:
static std::shared_ptr<configuration> get(
const std::set<std::string> &_input = std::set<std::string>());
@@ -65,6 +65,9 @@ public:
virtual bool get_multicast(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const = 0;
+ virtual uint8_t get_threshold(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) const = 0;
+
virtual client_t get_id(const std::string &_name) const = 0;
virtual bool is_configured_client_id(client_t _id) const = 0;
@@ -77,6 +80,10 @@ public:
virtual bool supports_selective_broadcasts(boost::asio::ip::address _address) const = 0;
+ virtual bool is_offered_remote(service_t _service, instance_t _instance) const = 0;
+
+ virtual bool is_local_service(service_t _service, instance_t _instance) const = 0;
+
// Service Discovery configuration
virtual bool is_sd_enabled() const = 0;
@@ -103,6 +110,9 @@ public:
// File permissions
virtual std::uint32_t get_umask() const = 0;
virtual std::uint32_t get_permissions_shm() const = 0;
+
+ virtual bool log_version() const = 0;
+ virtual uint32_t get_log_version_interval() const = 0;
};
} // namespace vsomeip
diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp
index 87a1d15..46b3166 100644
--- a/implementation/configuration/include/configuration_impl.hpp
+++ b/implementation/configuration/include/configuration_impl.hpp
@@ -17,6 +17,7 @@
#include "trace.hpp"
#include "configuration.hpp"
#include "watchdog.hpp"
+#include "service_instance_range.hpp"
namespace vsomeip {
namespace cfg {
@@ -24,6 +25,7 @@ namespace cfg {
struct client;
struct service;
struct servicegroup;
+struct event;
struct eventgroup;
struct watchdog;
@@ -85,12 +87,22 @@ public:
VSOMEIP_EXPORT bool get_multicast(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const;
+ VSOMEIP_EXPORT uint8_t get_threshold(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) const;
+
VSOMEIP_EXPORT std::uint32_t get_max_message_size_local() const;
VSOMEIP_EXPORT std::uint32_t get_message_size_reliable(const std::string& _address,
std::uint16_t _port) const;
VSOMEIP_EXPORT bool supports_selective_broadcasts(boost::asio::ip::address _address) const;
+ VSOMEIP_EXPORT bool is_offered_remote(service_t _service, instance_t _instance) const;
+
+ VSOMEIP_EXPORT bool log_version() const;
+ VSOMEIP_EXPORT uint32_t get_log_version_interval() const;
+
+ VSOMEIP_EXPORT bool is_local_service(service_t _service, instance_t _instance) const;
+
// Service Discovery configuration
VSOMEIP_EXPORT bool is_sd_enabled() const;
@@ -159,6 +171,7 @@ private:
std::string &_criteria,
std::shared_ptr<trace_filter_rule> &_filter_rule);
void get_permission_configuration(const element &_element);
+ void get_internal_services(const boost::property_tree::ptree &_tree);
servicegroup *find_servicegroup(const std::string &_name) const;
std::shared_ptr<client> find_client(service_t _service, instance_t _instance) const;
@@ -166,6 +179,11 @@ private:
std::shared_ptr<eventgroup> find_eventgroup(service_t _service,
instance_t _instance, eventgroup_t _eventgroup) const;
+ void set_magic_cookies_unicast_address();
+
+ bool is_remote(std::shared_ptr<service> _service) const;
+ bool is_internal_service(service_t _service, instance_t _instance) const;
+
private:
static std::shared_ptr<configuration_impl> the_configuration;
static std::mutex mutex_;
@@ -218,6 +236,11 @@ protected:
std::shared_ptr<watchdog> watchdog_;
+ std::vector<service_instance_range> internal_service_ranges_;
+
+ bool log_version_;
+ uint32_t log_version_interval_;
+
enum element_type_e {
ET_UNICAST,
ET_DIAGNOSIS,
@@ -241,7 +264,8 @@ protected:
ET_WATCHDOG_TIMEOUT,
ET_WATCHDOG_ALLOWED_MISSING_PONGS,
ET_TRACING_ENABLE,
- ET_MAX = 22
+ ET_TRACING_SD_ENABLE,
+ ET_MAX = 23
};
bool is_configured_[ET_MAX];
diff --git a/implementation/configuration/include/event.hpp b/implementation/configuration/include/event.hpp
index d488ec4..bc12ff1 100644
--- a/implementation/configuration/include/event.hpp
+++ b/implementation/configuration/include/event.hpp
@@ -17,8 +17,8 @@ namespace cfg {
struct eventgroup;
struct event {
- event(event_t _id, bool _is_field, bool _is_reliable) :
- id_(_id), is_field_(_is_field), is_reliable_(_is_reliable) {
+ event(event_t _id, bool _is_field, bool _is_reliable)
+ : id_(_id), is_field_(_is_field), is_reliable_(_is_reliable) {
}
event_t id_;
diff --git a/implementation/configuration/include/eventgroup.hpp b/implementation/configuration/include/eventgroup.hpp
index 93a91a3..7974d98 100644
--- a/implementation/configuration/include/eventgroup.hpp
+++ b/implementation/configuration/include/eventgroup.hpp
@@ -20,6 +20,7 @@ struct eventgroup {
std::set<std::shared_ptr<event> > events_;
std::string multicast_address_;
uint16_t multicast_port_;
+ uint8_t threshold_;
};
} // namespace cfg
diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in
index d7770c9..d10c6d6 100644
--- a/implementation/configuration/include/internal.hpp.in
+++ b/implementation/configuration/include/internal.hpp.in
@@ -85,7 +85,7 @@
#define VSOMEIP_SUBSCRIBE_COMMAND_SIZE 16
#define VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE 13
#define VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE 13
-#define VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE 13
+#define VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE 14
#define VSOMEIP_REGISTER_EVENT_COMMAND_SIZE 15
#define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 14
@@ -100,20 +100,22 @@
#define VSOMEIP_DEFAULT_SHM_PERMISSION 0666
#define VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS 0000
-#define VSOMEIP_MAX_CLIENTS 255
+#define VSOMEIP_MAX_CLIENTS 255
namespace vsomeip {
struct configuration_data_t {
-#ifdef WIN32
- void* mutex_;
-#else
+#ifndef WIN32
+ volatile char initialized_;
pthread_mutex_t mutex_;
#endif
unsigned short client_base_;
unsigned short used_client_ids_[VSOMEIP_MAX_CLIENTS];
int max_used_client_ids_index_;
+ unsigned char max_assigned_client_id_low_byte_;
+
+ unsigned short routing_manager_host_;
};
} // namespace vsomeip
diff --git a/implementation/configuration/include/service_instance_range.hpp b/implementation/configuration/include/service_instance_range.hpp
new file mode 100644
index 0000000..57a8c21
--- /dev/null
+++ b/implementation/configuration/include/service_instance_range.hpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef VSOMEIP_CFG_SERVICE_INSTANCE_RANGE_HPP
+#define VSOMEIP_CFG_SERVICE_INSTANCE_RANGE_HPP
+
+#include <vsomeip/primitive_types.hpp>
+
+namespace vsomeip {
+namespace cfg {
+
+struct service_instance_range {
+ service_t first_service_;
+ service_t last_service_;
+ instance_t first_instance_;
+ instance_t last_instance_;
+};
+
+}
+}
+
+#endif // VSOMEIP_CFG_SERVICE_INSTANCE_RANGE_HPP
diff --git a/implementation/configuration/include/trace.hpp b/implementation/configuration/include/trace.hpp
index cba4da8..3ffdf00 100644
--- a/implementation/configuration/include/trace.hpp
+++ b/implementation/configuration/include/trace.hpp
@@ -46,7 +46,8 @@ struct trace {
trace() :
channels_(),
filter_rules_(),
- is_enabled_(false) {
+ is_enabled_(false),
+ is_sd_enabled_(false) {
channels_.push_back(std::make_shared<trace_channel>());
}
@@ -54,6 +55,7 @@ struct trace {
std::vector<std::shared_ptr<trace_filter_rule>> filter_rules_;
bool is_enabled_;
+ bool is_sd_enabled_;
};
} // namespace cfg
diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp
index 3c78de0..ef5b706 100644
--- a/implementation/configuration/src/configuration_impl.cpp
+++ b/implementation/configuration/src/configuration_impl.cpp
@@ -42,6 +42,8 @@ std::shared_ptr<configuration> configuration_impl::get(
static bool has_reading_failed(false);
if (!the_configuration) {
+ std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
+
the_configuration = std::make_shared<configuration_impl>();
std::vector<element> its_configuration_elements;
@@ -95,7 +97,13 @@ std::shared_ptr<configuration> configuration_impl::get(
its_configuration_elements.end());
for (auto e : its_configuration_elements)
the_configuration->load(e);
+ // set global unicast address for all services with magic cookies enabled
+ the_configuration->set_magic_cookies_unicast_address();
}
+ std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+ VSOMEIP_DEBUG << "Parsed vSomeIP configuration in "
+ << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
+ << "ms";
}
// There is only one attempt to read the configuration file(s).
@@ -131,6 +139,8 @@ configuration_impl::configuration_impl() :
max_configured_message_size_(0),
trace_(std::make_shared<trace>()),
watchdog_(std::make_shared<watchdog>()),
+ log_version_(true),
+ log_version_interval_(10),
permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION),
umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS) {
unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS);
@@ -197,6 +207,7 @@ void configuration_impl::load(const element &_element) {
get_trace_configuration(_element);
get_supports_selective_broadcasts(_element.tree_);
get_watchdog_configuration(_element);
+ get_internal_services(_element.tree_);
} catch (std::exception &e) {
#ifdef WIN32
e; // silence MSVC warning C4101
@@ -281,6 +292,18 @@ void configuration_impl::get_logging_configuration(
boost::log::trivial::severity_level::info))))));
is_configured_[ET_LOGGING_LEVEL] = true;
}
+ } else if (its_key == "version") {
+ std::stringstream its_converter;
+ for (auto j : i->second) {
+ std::string its_sub_key(j.first);
+ std::string its_sub_value(j.second.data());
+ if (its_sub_key == "enable") {
+ log_version_ = (its_sub_value == "true");
+ } else if (its_sub_key == "interval") {
+ its_converter << std::dec << its_sub_value;
+ its_converter >> log_version_interval_;
+ }
+ }
}
}
} catch (...) {
@@ -325,7 +348,7 @@ void configuration_impl::get_services_configuration(
try {
auto its_services = _tree.get_child("services");
for (auto i = its_services.begin(); i != its_services.end(); ++i)
- get_service_configuration(i->second, "");
+ get_service_configuration(i->second, "local");
} catch (...) {
try {
auto its_servicegroups = _tree.get_child("servicegroups");
@@ -337,6 +360,19 @@ void configuration_impl::get_services_configuration(
}
}
+void configuration_impl::set_magic_cookies_unicast_address() {
+ // get services with static routing that have magic cookies enabled
+ std::map<std::string, std::set<uint16_t> > its_magic_cookies_ = magic_cookies_;
+ its_magic_cookies_.erase("local");
+
+ //set unicast address of host for all services without static routing
+ its_magic_cookies_[get_unicast_address().to_string()].insert(magic_cookies_["local"].begin(),
+ magic_cookies_["local"].end());
+ magic_cookies_.clear();
+ magic_cookies_ = its_magic_cookies_;
+}
+
+
void configuration_impl::get_clients_configuration(
const boost::property_tree::ptree &_tree) {
try {
@@ -553,8 +589,7 @@ void configuration_impl::get_service_configuration(
services_[its_service->service_][its_service->instance_] =
its_service;
if (use_magic_cookies) {
- magic_cookies_[get_unicast_address(its_service->service_,
- its_service->instance_)].insert(its_service->reliable_);
+ magic_cookies_[its_service->unicast_address_].insert(its_service->reliable_);
}
}
} catch (...) {
@@ -682,9 +717,8 @@ void configuration_impl::get_eventgroup_configuration(
for (auto j = i->second.begin(); j != i->second.end(); ++j) {
std::stringstream its_converter;
std::string its_key(j->first);
+ std::string its_value(j->second.data());
if (its_key == "eventgroup") {
-
- std::string its_value(j->second.data());
if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
@@ -706,6 +740,12 @@ void configuration_impl::get_eventgroup_configuration(
its_converter >> its_eventgroup->multicast_port_;
} catch (...) {
}
+ } else if (its_key == "threshold") {
+ int its_threshold(0);
+ std::stringstream its_converter;
+ its_converter << std::dec << its_value;
+ its_converter >> std::dec >> its_threshold;
+ its_eventgroup->threshold_ = static_cast<uint8_t>(its_threshold);
} else if (its_key == "events") {
for (auto k = j->second.begin(); k != j->second.end(); ++k) {
std::stringstream its_converter;
@@ -984,6 +1024,14 @@ void configuration_impl::get_trace_configuration(const element &_element) {
trace_->is_enabled_ = (its_value == "true");
is_configured_[ET_TRACING_ENABLE] = true;
}
+ } else if (its_key == "sd_enable") {
+ if (is_configured_[ET_TRACING_SD_ENABLE]) {
+ VSOMEIP_WARNING << "Multiple definitions of tracing.sd_enable."
+ << " Ignoring definition from " << _element.name_;
+ } else {
+ trace_->is_sd_enabled_ = (its_value == "true");
+ is_configured_[ET_TRACING_SD_ENABLE] = true;
+ }
} else if(its_key == "channels") {
get_trace_channels_configuration(i->second);
} else if(its_key == "filters") {
@@ -1144,6 +1192,92 @@ void configuration_impl::get_watchdog_configuration(const element &_element) {
}
}
+void configuration_impl::get_internal_services(
+ const boost::property_tree::ptree &_tree) {
+ try {
+ auto optional = _tree.get_child_optional("internal_services");
+ if (!optional) {
+ return;
+ }
+ auto its_internal_services = _tree.get_child("internal_services");
+ for (auto found_range = its_internal_services.begin();
+ found_range != its_internal_services.end(); ++found_range) {
+ service_instance_range range;
+ range.first_service_ = 0x0;
+ range.last_service_ = 0x0;
+ range.first_instance_ = 0x0;
+ range.last_instance_ = 0xffff;
+ for (auto i = found_range->second.begin();
+ i != found_range->second.end(); ++i) {
+ if (i->first == "first") {
+ if (i->second.size() == 0) {
+ std::stringstream its_converter;
+ std::string value = i->second.data();
+ its_converter << std::hex << value;
+ its_converter >> range.first_service_;
+ }
+ for (auto n = i->second.begin();
+ n != i->second.end(); ++n) {
+ if (n->first == "service") {
+ std::stringstream its_converter;
+ std::string value = n->second.data();
+ its_converter << std::hex << value;
+ its_converter >> range.first_service_;
+ } else if (n->first == "instance") {
+ std::stringstream its_converter;
+ std::string value = n->second.data();
+ its_converter << std::hex << value;
+ its_converter >> range.first_instance_;
+ }
+ }
+ } else if (i->first == "last") {
+ if (i->second.size() == 0) {
+ std::stringstream its_converter;
+ std::string value = i->second.data();
+ its_converter << std::hex << value;
+ its_converter >> range.last_service_;
+ }
+ for (auto n = i->second.begin();
+ n != i->second.end(); ++n) {
+ if (n->first == "service") {
+ std::stringstream its_converter;
+ std::string value = n->second.data();
+ its_converter << std::hex << value;
+ its_converter >> range.last_service_;
+ } else if (n->first == "instance") {
+ std::stringstream its_converter;
+ std::string value = n->second.data();
+ its_converter << std::hex << value;
+ its_converter >> range.last_instance_;
+ }
+ }
+ }
+ }
+ if (range.last_service_ >= range.first_service_) {
+ if (range.last_instance_ >= range.first_instance_) {
+ internal_service_ranges_.push_back(range);
+ }
+ }
+ }
+ } catch (...) {
+ VSOMEIP_ERROR << "Error parsing internal service range configuration!";
+ }
+}
+
+bool configuration_impl::is_internal_service(service_t _service,
+ instance_t _instance) const {
+
+ for (auto its_range : internal_service_ranges_) {
+ if (_service >= its_range.first_service_ &&
+ _service <= its_range.last_service_ &&
+ _instance >= its_range.first_instance_ &&
+ _instance <= its_range.last_instance_) {
+ return true;
+ }
+ }
+ return false;
+}
+
// Public interface
const boost::asio::ip::address & configuration_impl::get_unicast_address() const {
return unicast_;
@@ -1311,16 +1445,21 @@ configuration_impl::get_remote_services() const {
std::set<std::pair<service_t, instance_t> > its_remote_services;
for (auto i : services_) {
for (auto j : i.second) {
- if (j.second->unicast_address_ != "local" &&
- j.second->unicast_address_ != "" &&
- j.second->unicast_address_ != unicast_.to_string() &&
- j.second->unicast_address_ != VSOMEIP_UNICAST_ADDRESS)
+ if (is_remote(j.second)) {
its_remote_services.insert(std::make_pair(i.first, j.first));
+ }
}
}
return its_remote_services;
}
+bool configuration_impl::is_remote(std::shared_ptr<service> _service) const {
+ return (_service->unicast_address_ != "local" &&
+ _service->unicast_address_ != "" &&
+ _service->unicast_address_ != unicast_.to_string() &&
+ _service->unicast_address_ != VSOMEIP_UNICAST_ADDRESS);
+}
+
bool configuration_impl::get_multicast(service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
std::string &_address, uint16_t &_port) const
@@ -1338,6 +1477,13 @@ bool configuration_impl::get_multicast(service_t _service,
return true;
}
+uint8_t configuration_impl::get_threshold(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) const {
+ std::shared_ptr<eventgroup> its_eventgroup
+ = find_eventgroup(_service, _instance, _eventgroup);
+ return (its_eventgroup ? its_eventgroup->threshold_ : 0);
+}
+
std::shared_ptr<client> configuration_impl::find_client(service_t _service,
instance_t _instance) const {
std::shared_ptr<client> its_client;
@@ -1394,7 +1540,7 @@ std::uint32_t configuration_impl::get_max_message_size_local() const {
// to the routing_manager stub
return std::uint32_t(its_max_message_size
+ VSOMEIP_COMMAND_HEADER_SIZE + sizeof(instance_t)
- + sizeof(bool) + sizeof(bool) + sizeof(bool));
+ + sizeof(bool) + sizeof(bool));
}
std::uint32_t configuration_impl::get_message_size_reliable(
@@ -1413,6 +1559,32 @@ bool configuration_impl::supports_selective_broadcasts(boost::asio::ip::address
return supported_selective_addresses.find(_address.to_string()) != supported_selective_addresses.end();
}
+bool configuration_impl::log_version() const {
+ return log_version_;
+}
+
+uint32_t configuration_impl::get_log_version_interval() const {
+ return log_version_interval_;
+}
+
+bool configuration_impl::is_offered_remote(service_t _service, instance_t _instance) const {
+ uint16_t reliable_port = get_reliable_port(_service, _instance);
+ uint16_t unreliable_port = get_unreliable_port(_service, _instance);
+ return (reliable_port != ILLEGAL_PORT || unreliable_port != ILLEGAL_PORT);
+}
+
+bool configuration_impl::is_local_service(service_t _service, instance_t _instance) const {
+ std::shared_ptr<service> s = find_service(_service, _instance);
+ if (s && !is_remote(s)) {
+ return true;
+ }
+ if (is_internal_service(_service, _instance)) {
+ return true;
+ }
+
+ return false;
+}
+
// Service Discovery configuration
bool configuration_impl::is_sd_enabled() const {
return is_sd_enabled_;
diff --git a/implementation/endpoints/include/client_endpoint_impl.hpp b/implementation/endpoints/include/client_endpoint_impl.hpp
index f80e385..9d4fb25 100644
--- a/implementation/endpoints/include/client_endpoint_impl.hpp
+++ b/implementation/endpoints/include/client_endpoint_impl.hpp
@@ -60,17 +60,20 @@ public:
public:
virtual void connect() = 0;
virtual void receive() = 0;
+ typedef std::function<void()> endpoint_error_handler_t;
+ void register_error_callback(endpoint_error_handler_t _callback);
protected:
virtual void send_queued() = 0;
+ void shutdown_and_close_socket();
socket_type socket_;
endpoint_type remote_;
uint16_t local_port_;
- boost::asio::system_timer flush_timer_;
- boost::asio::system_timer connect_timer_;
+ boost::asio::steady_timer flush_timer_;
+ boost::asio::steady_timer connect_timer_;
uint32_t connect_timeout_;
bool is_connected_;
@@ -81,6 +84,9 @@ protected:
std::mutex mutex_;
bool was_not_connected_;
+
+ std::mutex error_handler_mutex_;
+ endpoint_error_handler_t error_handler_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/endpoint_impl.hpp b/implementation/endpoints/include/endpoint_impl.hpp
index bd05698..b000011 100644
--- a/implementation/endpoints/include/endpoint_impl.hpp
+++ b/implementation/endpoints/include/endpoint_impl.hpp
@@ -10,7 +10,7 @@
#include <memory>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/system_timer.hpp>
+#include <boost/asio/steady_timer.hpp>
#include "buffer.hpp"
#include "endpoint.hpp"
diff --git a/implementation/endpoints/include/local_client_endpoint_impl.hpp b/implementation/endpoints/include/local_client_endpoint_impl.hpp
index a6d777e..6b57e96 100644
--- a/implementation/endpoints/include/local_client_endpoint_impl.hpp
+++ b/implementation/endpoints/include/local_client_endpoint_impl.hpp
@@ -49,6 +49,8 @@ private:
void connect();
void receive();
+ void receive_cbk(boost::system::error_code const &_error,
+ std::size_t _bytes);
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/local_server_endpoint_impl.hpp b/implementation/endpoints/include/local_server_endpoint_impl.hpp
index d8f5288..b0ac2ba 100644
--- a/implementation/endpoints/include/local_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/local_server_endpoint_impl.hpp
@@ -57,39 +57,35 @@ public:
bool is_local() const;
- bool queue_message(const byte_t *_data, uint32_t _size);
-
private:
class connection: public boost::enable_shared_from_this<connection> {
public:
typedef boost::shared_ptr<connection> ptr;
- static ptr create(local_server_endpoint_impl *_server,
+ static ptr create(std::weak_ptr<local_server_endpoint_impl> _server,
std::uint32_t _max_message_size);
socket_type & get_socket();
void start();
+ void stop();
void send_queued(queue_iterator_type _queue_iterator);
- bool queue_message(const byte_t *_data, uint32_t _size);
-
private:
- connection(local_server_endpoint_impl *_owner, std::uint32_t _max_message_size);
+ connection(std::weak_ptr<local_server_endpoint_impl> _server,
+ std::uint32_t _max_message_size);
void send_magic_cookie();
local_server_endpoint_impl::socket_type socket_;
- local_server_endpoint_impl *server_;
+ std::weak_ptr<local_server_endpoint_impl> server_;
uint32_t max_message_size_;
receive_buffer_t recv_buffer_;
size_t recv_buffer_size_;
- static std::vector<byte_t> queued_data_;
-
private:
void receive_cbk(boost::system::error_code const &_error,
std::size_t _bytes);
@@ -101,6 +97,7 @@ private:
boost::asio::local::stream_protocol::acceptor acceptor_;
#endif
+ std::mutex connections_mutex_;
std::map<endpoint_type, connection::ptr> connections_;
connection::ptr current_;
diff --git a/implementation/endpoints/include/server_endpoint_impl.hpp b/implementation/endpoints/include/server_endpoint_impl.hpp
index 15d001b..c3f6b59 100644
--- a/implementation/endpoints/include/server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/server_endpoint_impl.hpp
@@ -67,7 +67,7 @@ protected:
std::mutex clients_mutex_;
std::map<client_t, std::map<session_t, endpoint_type> > clients_;
- boost::asio::system_timer flush_timer_;
+ boost::asio::steady_timer flush_timer_;
std::mutex mutex_;
};
diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
index 16197cc..eb0047a 100644
--- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
@@ -61,7 +61,7 @@ private:
public:
typedef boost::shared_ptr<connection> ptr;
- static ptr create(tcp_server_endpoint_impl *_server,
+ static ptr create(std::weak_ptr<tcp_server_endpoint_impl> _server,
std::uint32_t _max_message_size);
socket_type & get_socket();
@@ -74,11 +74,12 @@ private:
void send_queued(queue_iterator_type _queue_iterator);
private:
- connection(tcp_server_endpoint_impl *_owner, std::uint32_t _max_message_size);
+ connection(std::weak_ptr<tcp_server_endpoint_impl> _server,
+ std::uint32_t _max_message_size);
void send_magic_cookie(message_buffer_ptr_t &_buffer);
tcp_server_endpoint_impl::socket_type socket_;
- tcp_server_endpoint_impl *server_;
+ std::weak_ptr<tcp_server_endpoint_impl> server_;
uint32_t max_message_size_;
@@ -93,10 +94,12 @@ private:
};
boost::asio::ip::tcp::acceptor acceptor_;
+ std::mutex connections_mutex_;
std::map<endpoint_type, connection::ptr> connections_;
connection *current_;
private:
+ void remove_connection(connection *_connection);
void accept_cbk(connection::ptr _connection,
boost::system::error_code const &_error);
};
diff --git a/implementation/endpoints/src/client_endpoint_impl.cpp b/implementation/endpoints/src/client_endpoint_impl.cpp
index f68bad7..3d2a752 100644
--- a/implementation/endpoints/src/client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/client_endpoint_impl.cpp
@@ -74,13 +74,18 @@ void client_endpoint_impl<Protocol>::stop() {
}
}
- boost::system::error_code its_error;
- socket_.close(its_error);
+ if (socket_.is_open()) {
+ socket_.cancel();
+ }
}
}
template<typename Protocol>
void client_endpoint_impl<Protocol>::restart() {
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ queue_.clear();
+ }
is_connected_ = false;
connect_timer_.expires_from_now(
std::chrono::milliseconds(connect_timeout_));
@@ -152,9 +157,8 @@ bool client_endpoint_impl<Protocol>::send(const uint8_t *_data,
template<typename Protocol>
bool client_endpoint_impl<Protocol>::flush() {
bool is_successful(true);
-
+ std::lock_guard<std::mutex> its_lock(mutex_);
if (!packetizer_->empty()) {
- std::lock_guard<std::mutex> its_lock(mutex_);
queue_.push_back(packetizer_);
packetizer_ = std::make_shared<message_buffer_t>();
if (queue_.size() == 1) { // no writing in progress
@@ -170,12 +174,16 @@ bool client_endpoint_impl<Protocol>::flush() {
template<typename Protocol>
void client_endpoint_impl<Protocol>::connect_cbk(
boost::system::error_code const &_error) {
+ if (_error == boost::asio::error::operation_aborted) {
+ // endpoint was stopped
+ shutdown_and_close_socket();
+ return;
+ }
std::shared_ptr<endpoint_host> its_host = this->host_.lock();
if (its_host) {
if (_error && _error != boost::asio::error::already_connected) {
if(socket_.is_open()) {
- boost::system::error_code its_error;
- socket_.close(its_error);
+ shutdown_and_close_socket();
}
connect_timer_.expires_from_now(
@@ -232,12 +240,19 @@ void client_endpoint_impl<Protocol>::send_cbk(
}
} else if (_error == boost::asio::error::broken_pipe) {
is_connected_ = false;
- if (endpoint_impl<Protocol>::sending_blocked_) {
- std::lock_guard<std::mutex> its_lock(mutex_);
- queue_.clear();
+ if (endpoint_impl<Protocol>::sending_blocked_ || error_handler_) {
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ queue_.clear();
+ }
+ if (error_handler_) {
+ std::lock_guard<std::mutex> its_lock(error_handler_mutex_);
+ error_handler_();
+ }
}
if (socket_.is_open()) {
boost::system::error_code its_error;
+ socket_.shutdown(Protocol::socket::shutdown_both, its_error);
socket_.close(its_error);
}
connect();
@@ -245,6 +260,9 @@ void client_endpoint_impl<Protocol>::send_cbk(
|| _error == boost::asio::error::bad_descriptor) {
was_not_connected_ = true;
connect();
+ } else if (_error == boost::asio::error::operation_aborted) {
+ // endpoint was stopped
+ shutdown_and_close_socket();
}
}
@@ -256,6 +274,22 @@ void client_endpoint_impl<Protocol>::flush_cbk(
}
}
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::register_error_callback(
+ endpoint_error_handler_t _callback) {
+ std::lock_guard<std::mutex> its_lock(error_handler_mutex_);
+ error_handler_ = _callback;
+}
+
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::shutdown_and_close_socket() {
+ if (socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.shutdown(Protocol::socket::shutdown_both, its_error);
+ socket_.close(its_error);
+ }
+}
+
// Instantiate template
#ifndef WIN32
template class client_endpoint_impl<boost::asio::local::stream_protocol>;
diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp
index 62dba82..7e633e0 100644
--- a/implementation/endpoints/src/local_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp
@@ -40,6 +40,7 @@ void local_client_endpoint_impl::start() {
sending_blocked_ = false;
boost::system::error_code its_error;
socket_.cancel(its_error);
+ socket_.shutdown(socket_type::shutdown_both, its_error);
socket_.close(its_error);
restart();
} else {
@@ -63,6 +64,20 @@ void local_client_endpoint_impl::connect() {
}
void local_client_endpoint_impl::receive() {
+#ifndef WIN32
+ receive_buffer_t its_buffer(VSOMEIP_MAX_LOCAL_MESSAGE_SIZE , 0);
+ socket_.async_receive(
+ boost::asio::buffer(its_buffer),
+ std::bind(
+ &local_client_endpoint_impl::receive_cbk,
+ std::dynamic_pointer_cast<
+ local_client_endpoint_impl
+ >(shared_from_this()),
+ std::placeholders::_1,
+ std::placeholders::_2
+ )
+ );
+#endif
}
void local_client_endpoint_impl::send_queued() {
@@ -107,4 +122,19 @@ VSOMEIP_DEBUG << msg.str();
void local_client_endpoint_impl::send_magic_cookie() {
}
+void local_client_endpoint_impl::receive_cbk(
+ boost::system::error_code const &_error, std::size_t _bytes) {
+ (void)_bytes;
+ if (_error == boost::asio::error::operation_aborted) {
+ // endpoint was stopped
+ shutdown_and_close_socket();
+ } else if (_error == boost::asio::error::connection_reset
+ || _error == boost::asio::error::eof) {
+ VSOMEIP_TRACE << "local_client_endpoint: connection_reseted/EOF";
+ } else {
+ VSOMEIP_ERROR << "Local endpoint received message ("
+ << _error.message() << ")";
+ }
+}
+
} // namespace vsomeip
diff --git a/implementation/endpoints/src/local_server_endpoint_impl.cpp b/implementation/endpoints/src/local_server_endpoint_impl.cpp
index e67a646..42ffc2b 100644
--- a/implementation/endpoints/src/local_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/local_server_endpoint_impl.cpp
@@ -21,8 +21,18 @@ local_server_endpoint_impl::local_server_endpoint_impl(
endpoint_type _local, boost::asio::io_service &_io,
std::uint32_t _max_message_size)
: local_server_endpoint_base_impl(_host, _local, _io, _max_message_size),
- acceptor_(_io, _local), current_(nullptr) {
+ acceptor_(_io), current_(nullptr) {
is_supporting_magic_cookies_ = false;
+
+ boost::system::error_code ec;
+ acceptor_.open(_local.protocol(), ec);
+ boost::asio::detail::throw_error(ec, "acceptor open");
+ acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
+ boost::asio::detail::throw_error(ec, "acceptor set_option");
+ acceptor_.bind(_local, ec);
+ boost::asio::detail::throw_error(ec, "acceptor bind");
+ acceptor_.listen(boost::asio::socket_base::max_connections, ec);
+ boost::asio::detail::throw_error(ec, "acceptor listen");
}
local_server_endpoint_impl::~local_server_endpoint_impl() {
@@ -33,19 +43,23 @@ bool local_server_endpoint_impl::is_local() const {
}
void local_server_endpoint_impl::start() {
- current_ = connection::create(this, max_message_size_);
-
- acceptor_.async_accept(
- current_->get_socket(),
- std::bind(
- &local_server_endpoint_impl::accept_cbk,
- std::dynamic_pointer_cast<
- local_server_endpoint_impl
- >(shared_from_this()),
- current_,
- std::placeholders::_1
- )
- );
+ if (acceptor_.is_open()) {
+ current_ = connection::create(
+ std::dynamic_pointer_cast<local_server_endpoint_impl>(
+ shared_from_this()), max_message_size_);
+
+ acceptor_.async_accept(
+ current_->get_socket(),
+ std::bind(
+ &local_server_endpoint_impl::accept_cbk,
+ std::dynamic_pointer_cast<
+ local_server_endpoint_impl
+ >(shared_from_this()),
+ current_,
+ std::placeholders::_1
+ )
+ );
+ }
}
void local_server_endpoint_impl::stop() {
@@ -53,6 +67,16 @@ void local_server_endpoint_impl::stop() {
boost::system::error_code its_error;
acceptor_.close(its_error);
}
+ {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ for (const auto &c : connections_) {
+ if (c.second->get_socket().is_open()) {
+ boost::system::error_code its_error;
+ c.second->get_socket().cancel(its_error);
+ }
+ }
+ connections_.clear();
+ }
server_endpoint_impl::stop();
}
@@ -68,6 +92,7 @@ bool local_server_endpoint_impl::send_to(
void local_server_endpoint_impl::send_queued(
queue_iterator_type _queue_iterator) {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
auto connection_iterator = connections_.find(_queue_iterator->first);
if (connection_iterator != connections_.end())
connection_iterator->second->send_queued(_queue_iterator);
@@ -81,13 +106,6 @@ void local_server_endpoint_impl::restart() {
current_->start();
}
-bool local_server_endpoint_impl::queue_message(const byte_t *_data, uint32_t _size) {
- if (current_) {
- return current_->queue_message(_data, _size);
- }
- return false;
-}
-
local_server_endpoint_impl::endpoint_type
local_server_endpoint_impl::get_remote() const {
boost::system::error_code its_error;
@@ -102,15 +120,14 @@ bool local_server_endpoint_impl::get_default_target(
void local_server_endpoint_impl::remove_connection(
local_server_endpoint_impl::connection *_connection) {
- std::map< endpoint_type, connection::ptr >::iterator i
- = connections_.end();
- for (i = connections_.begin(); i != connections_.end(); i++) {
- if (i->second.get() == _connection)
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ for (auto it = connections_.begin(); it != connections_.end();) {
+ if (it->second.get() == _connection) {
+ it = connections_.erase(it);
break;
- }
-
- if (i != connections_.end()) {
- connections_.erase(i);
+ } else {
+ ++it;
+ }
}
}
@@ -122,23 +139,27 @@ void local_server_endpoint_impl::accept_cbk(
boost::system::error_code its_error;
endpoint_type remote = new_connection_socket.remote_endpoint(its_error);
if(!its_error) {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
connections_[remote] = _connection;
_connection->start();
}
}
- start();
+ if (_error != boost::asio::error::bad_descriptor &&
+ _error != boost::asio::error::operation_aborted) {
+ start();
+ }
}
///////////////////////////////////////////////////////////////////////////////
// class local_service_impl::connection
///////////////////////////////////////////////////////////////////////////////
-std::vector<byte_t> local_server_endpoint_impl::connection::queued_data_;
-
local_server_endpoint_impl::connection::connection(
- local_server_endpoint_impl *_server, std::uint32_t _max_message_size)
- : socket_(_server->service_), server_(_server),
+ std::weak_ptr<local_server_endpoint_impl> _server,
+ std::uint32_t _max_message_size)
+ : socket_(_server.lock()->service_),
+ server_(_server),
max_message_size_(_max_message_size + 8),
recv_buffer_(max_message_size_, 0),
recv_buffer_size_(0) {
@@ -146,7 +167,8 @@ local_server_endpoint_impl::connection::connection(
local_server_endpoint_impl::connection::ptr
local_server_endpoint_impl::connection::create(
- local_server_endpoint_impl *_server, std::uint32_t _max_message_size) {
+ std::weak_ptr<local_server_endpoint_impl> _server,
+ std::uint32_t _max_message_size) {
return ptr(new connection(_server, _max_message_size));
}
@@ -156,20 +178,30 @@ local_server_endpoint_impl::connection::get_socket() {
}
void local_server_endpoint_impl::connection::start() {
- if (recv_buffer_size_ == max_message_size_) {
- // Overrun -> Reset buffer
- recv_buffer_size_ = 0;
+ if (socket_.is_open()) {
+ if (recv_buffer_size_ == max_message_size_) {
+ // Overrun -> Reset buffer
+ recv_buffer_size_ = 0;
+ }
+ size_t buffer_size = max_message_size_ - recv_buffer_size_;
+ socket_.async_receive(
+ boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
+ std::bind(
+ &local_server_endpoint_impl::connection::receive_cbk,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2
+ )
+ );
+ }
+}
+
+void local_server_endpoint_impl::connection::stop() {
+ if (socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.shutdown(socket_.shutdown_both, its_error);
+ socket_.close(its_error);
}
- size_t buffer_size = max_message_size_ - recv_buffer_size_;
- socket_.async_receive(
- boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
- std::bind(
- &local_server_endpoint_impl::connection::receive_cbk,
- shared_from_this(),
- std::placeholders::_1,
- std::placeholders::_2
- )
- );
}
void local_server_endpoint_impl::connection::send_queued(
@@ -178,6 +210,12 @@ void local_server_endpoint_impl::connection::send_queued(
// TODO: We currently do _not_ use the send method of the local server
// endpoints. If we ever need it, we need to add the "start tag", "data",
// "end tag" sequence here.
+ std::shared_ptr<local_server_endpoint_impl> its_server(server_.lock());
+ if (!its_server) {
+ VSOMEIP_TRACE << "local_server_endpoint_impl::connection::send_queued "
+ " couldn't lock server_";
+ return;
+ }
message_buffer_ptr_t its_buffer = _queue_iterator->second.front();
#if 0
@@ -193,7 +231,7 @@ void local_server_endpoint_impl::connection::send_queued(
boost::asio::buffer(*its_buffer),
std::bind(
&local_server_endpoint_base_impl::send_cbk,
- server_->shared_from_this(),
+ its_server,
_queue_iterator,
std::placeholders::_1,
std::placeholders::_2
@@ -201,27 +239,23 @@ void local_server_endpoint_impl::connection::send_queued(
);
}
-bool local_server_endpoint_impl::connection::queue_message(const byte_t *_data, uint32_t _size) {
-#if 0
- std::stringstream msg;
- msg << "lse::qm: ";
- for (std::size_t i = 0; i < _size; i++)
- msg << std::setw(2) << std::setfill('0') << std::hex
- << (int)(_data)[i] << " ";
- VSOMEIP_INFO << msg.str();
-#endif
- queued_data_.resize(_size);
- memcpy(&queued_data_[0], _data, _size);
- return true;
-}
-
void local_server_endpoint_impl::connection::send_magic_cookie() {
}
void local_server_endpoint_impl::connection::receive_cbk(
boost::system::error_code const &_error, std::size_t _bytes) {
- std::shared_ptr<endpoint_host> its_host = server_->host_.lock();
+ if (_error == boost::asio::error::operation_aborted) {
+ stop();
+ return;
+ }
+ std::shared_ptr<local_server_endpoint_impl> its_server(server_.lock());
+ if (!its_server) {
+ VSOMEIP_TRACE << "local_server_endpoint_impl::connection::receive_cbk "
+ " couldn't lock server_";
+ return;
+ }
+ std::shared_ptr<endpoint_host> its_host = its_server->host_.lock();
if (its_host) {
std::size_t its_start;
std::size_t its_end;
@@ -269,13 +303,7 @@ void local_server_endpoint_impl::connection::receive_cbk(
if (its_start != MESSAGE_IS_EMPTY &&
its_end + 3 < recv_buffer_size_ + its_iteration_gap) {
its_host->on_message(&recv_buffer_[its_start],
- uint32_t(its_end - its_start), server_);
-
- // If there was a queued message --> consume it now!
- if (queued_data_.size() > 0) {
- its_host->on_message(&queued_data_[0], static_cast<length_t>(queued_data_.size()), server_);
- queued_data_.clear();
- }
+ uint32_t(its_end - its_start), its_server.get());
#if 0
std::stringstream local_msg;
@@ -301,9 +329,14 @@ void local_server_endpoint_impl::connection::receive_cbk(
} while (recv_buffer_size_ > 0 && its_start == FOUND_MESSAGE);
}
- if (_error == boost::asio::error::misc_errors::eof) {
- server_->remove_connection(this);
- } else {
+ if (_error == boost::asio::error::eof
+ || _error == boost::asio::error::connection_reset) {
+ {
+ std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
+ stop();
+ }
+ its_server->remove_connection(this);
+ } else if (_error != boost::asio::error::bad_descriptor) {
start();
}
}
diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
index d31a38b..97e5579 100644
--- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
@@ -173,6 +173,11 @@ void tcp_client_endpoint_impl::send_magic_cookie(message_buffer_ptr_t &_buffer)
void tcp_client_endpoint_impl::receive_cbk(
boost::system::error_code const &_error, std::size_t _bytes) {
+ if (_error == boost::asio::error::operation_aborted) {
+ // endpoint was stopped
+ shutdown_and_close_socket();
+ return;
+ }
#if 0
std::stringstream msg;
msg << "cei::rcb (" << _error.message() << "): ";
@@ -257,7 +262,11 @@ void tcp_client_endpoint_impl::receive_cbk(
}
receive();
} else {
- if (socket_.is_open()) {
+ if (_error == boost::asio::error::connection_reset ||
+ _error == boost::asio::error::eof) {
+ VSOMEIP_TRACE << "tcp_client_endpoint: connection_reseted/EOF ~> close socket!";
+ shutdown_and_close_socket();
+ } else if (socket_.is_open()) {
receive();
}
}
diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
index fc31850..f3035ef 100644
--- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
@@ -23,9 +23,19 @@ tcp_server_endpoint_impl::tcp_server_endpoint_impl(
std::shared_ptr<endpoint_host> _host, endpoint_type _local,
boost::asio::io_service &_io, std::uint32_t _max_message_size)
: tcp_server_endpoint_base_impl(_host, _local, _io, _max_message_size),
- acceptor_(_io, _local),
+ acceptor_(_io),
current_(0) {
is_supporting_magic_cookies_ = true;
+
+ boost::system::error_code ec;
+ acceptor_.open(_local.protocol(), ec);
+ boost::asio::detail::throw_error(ec, "acceptor open");
+ acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
+ boost::asio::detail::throw_error(ec, "acceptor set_option");
+ acceptor_.bind(_local, ec);
+ boost::asio::detail::throw_error(ec, "acceptor bind");
+ acceptor_.listen(boost::asio::socket_base::max_connections, ec);
+ boost::asio::detail::throw_error(ec, "acceptor listen");
}
tcp_server_endpoint_impl::~tcp_server_endpoint_impl() {
@@ -36,7 +46,9 @@ bool tcp_server_endpoint_impl::is_local() const {
}
void tcp_server_endpoint_impl::start() {
- connection::ptr new_connection = connection::create(this, max_message_size_);
+ connection::ptr new_connection = connection::create(
+ std::dynamic_pointer_cast<tcp_server_endpoint_impl>(
+ shared_from_this()), max_message_size_);
acceptor_.async_accept(new_connection->get_socket(),
std::bind(&tcp_server_endpoint_impl::accept_cbk,
@@ -46,13 +58,21 @@ void tcp_server_endpoint_impl::start() {
}
void tcp_server_endpoint_impl::stop() {
- server_endpoint_impl::stop();
- for (auto& i : connections_)
- i.second->stop();
if(acceptor_.is_open()) {
boost::system::error_code its_error;
acceptor_.close(its_error);
}
+ {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ for (const auto& c : connections_) {
+ if(c.second->get_socket().is_open()) {
+ boost::system::error_code its_error;
+ c.second->get_socket().cancel(its_error);
+ }
+ }
+ connections_.clear();
+ }
+ server_endpoint_impl::stop();
}
bool tcp_server_endpoint_impl::send_to(
@@ -65,34 +85,38 @@ bool tcp_server_endpoint_impl::send_to(
}
void tcp_server_endpoint_impl::send_queued(queue_iterator_type _queue_iterator) {
- auto connection_iterator = connections_.find(_queue_iterator->first);
- if (connection_iterator != connections_.end()) {
- connection_iterator->second->send_queued(_queue_iterator);
- } else {
- VSOMEIP_DEBUG << "Didn't find connection: "
- << _queue_iterator->first.address().to_string() << ":" << std::dec
- << static_cast<std::uint16_t>(_queue_iterator->first.port())
- << " dropping message.";
- _queue_iterator->second.pop_front();
+ connection::ptr its_connection;
+ {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ auto connection_iterator = connections_.find(_queue_iterator->first);
+ if (connection_iterator != connections_.end()) {
+ its_connection = connection_iterator->second;
+ } else {
+ VSOMEIP_DEBUG << "Didn't find connection: "
+ << _queue_iterator->first.address().to_string() << ":" << std::dec
+ << static_cast<std::uint16_t>(_queue_iterator->first.port())
+ << " dropping message.";
+ _queue_iterator->second.pop_front();
+ }
+ }
+ if (its_connection) {
+ its_connection->send_queued(_queue_iterator);
}
}
bool tcp_server_endpoint_impl::is_established(std::shared_ptr<endpoint_definition> _endpoint) {
bool is_connected = false;
endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port());
- auto connection_iterator = connections_.find(endpoint);
- if (connection_iterator != connections_.end()) {
-#if 0
- VSOMEIP_DEBUG << "tcp_server_endpoint_impl::is_established(): subscribers TCP connection for "
- << endpoint.address().to_string() << ":" << std::dec
- << static_cast<std::uint16_t>(endpoint.port())
- << " is established!" ;
-#endif
- is_connected = true;
- } else {
- VSOMEIP_DEBUG << "Didn't find TCP connection: Subscription rejected for: "
- << endpoint.address().to_string() << ":" << std::dec
- << static_cast<std::uint16_t>(endpoint.port());
+ {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ auto connection_iterator = connections_.find(endpoint);
+ if (connection_iterator != connections_.end()) {
+ is_connected = true;
+ } else {
+ VSOMEIP_DEBUG << "Didn't find TCP connection: Subscription "
+ << "rejected for: " << endpoint.address().to_string() << ":"
+ << std::dec << static_cast<std::uint16_t>(endpoint.port());
+ }
}
return is_connected;
}
@@ -138,6 +162,19 @@ bool tcp_server_endpoint_impl::get_default_target(service_t,
return false;
}
+void tcp_server_endpoint_impl::remove_connection(
+ tcp_server_endpoint_impl::connection *_connection) {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ for (auto it = connections_.begin(); it != connections_.end();) {
+ if (it->second.get() == _connection) {
+ it = connections_.erase(it);
+ break;
+ } else {
+ ++it;
+ }
+ }
+}
+
void tcp_server_endpoint_impl::accept_cbk(connection::ptr _connection,
boost::system::error_code const &_error) {
@@ -146,11 +183,13 @@ void tcp_server_endpoint_impl::accept_cbk(connection::ptr _connection,
boost::system::error_code its_error;
endpoint_type remote = new_connection_socket.remote_endpoint(its_error);
if(!its_error) {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
connections_[remote] = _connection;
_connection->start();
}
}
- if (_error != boost::asio::error::operation_aborted) {
+ if (_error != boost::asio::error::bad_descriptor
+ && _error != boost::asio::error::operation_aborted) {
start();
} else {
VSOMEIP_DEBUG << "Endpoint was stopped, don't starting again";
@@ -170,8 +209,9 @@ bool tcp_server_endpoint_impl::is_reliable() const {
// class tcp_service_impl::connection
///////////////////////////////////////////////////////////////////////////////
tcp_server_endpoint_impl::connection::connection(
- tcp_server_endpoint_impl *_server, std::uint32_t _max_message_size) :
- socket_(_server->service_), server_(_server),
+ std::weak_ptr<tcp_server_endpoint_impl> _server,
+ std::uint32_t _max_message_size) :
+ socket_(_server.lock()->service_), server_(_server),
max_message_size_(_max_message_size),
recv_buffer_(_max_message_size, 0),
recv_buffer_size_(0) {
@@ -179,7 +219,8 @@ tcp_server_endpoint_impl::connection::connection(
tcp_server_endpoint_impl::connection::ptr
tcp_server_endpoint_impl::connection::create(
- tcp_server_endpoint_impl *_server, std::uint32_t _max_message_size) {
+ std::weak_ptr<tcp_server_endpoint_impl> _server,
+ std::uint32_t _max_message_size) {
return ptr(new connection(_server, _max_message_size));
}
@@ -211,25 +252,29 @@ void tcp_server_endpoint_impl::connection::receive() {
void tcp_server_endpoint_impl::connection::stop() {
std::lock_guard<std::mutex> its_lock(stop_mutex_);
- if(socket_.is_open()) {
- boost::system::error_code its_shutdown_error;
- socket_.shutdown(socket_.shutdown_both, its_shutdown_error);
- boost::system::error_code its_close_error;
- socket_.close(its_close_error);
+ if (socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.shutdown(socket_.shutdown_both, its_error);
+ socket_.close(its_error);
}
}
void tcp_server_endpoint_impl::connection::send_queued(
queue_iterator_type _queue_iterator) {
+ std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock());
+ if (!its_server) {
+ VSOMEIP_TRACE << "tcp_server_endpoint_impl::connection::send_queued "
+ " couldn't lock server_";
+ return;
+ }
message_buffer_ptr_t its_buffer = _queue_iterator->second.front();
-
- if (server_->has_enabled_magic_cookies_) {
+ if (its_server->has_enabled_magic_cookies_) {
send_magic_cookie(its_buffer);
}
boost::asio::async_write(socket_, boost::asio::buffer(*its_buffer),
std::bind(&tcp_server_endpoint_base_impl::send_cbk,
- server_->shared_from_this(),
+ its_server,
_queue_iterator, std::placeholders::_1,
std::placeholders::_2));
}
@@ -251,6 +296,16 @@ bool tcp_server_endpoint_impl::connection::is_magic_cookie(size_t _offset) const
void tcp_server_endpoint_impl::connection::receive_cbk(
boost::system::error_code const &_error,
std::size_t _bytes) {
+ if (_error == boost::asio::error::operation_aborted) {
+ stop();
+ return;
+ }
+ std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock());
+ if (!its_server) {
+ VSOMEIP_ERROR << "tcp_server_endpoint_impl::connection::receive_cbk "
+ " couldn't lock server_";
+ return;
+ }
#if 0
std::stringstream msg;
for (std::size_t i = 0; i < _bytes + recv_buffer_size_; ++i)
@@ -258,7 +313,7 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
<< (int) recv_buffer_[i] << " ";
VSOMEIP_DEBUG<< msg.str();
#endif
- std::shared_ptr<endpoint_host> its_host = server_->host_.lock();
+ std::shared_ptr<endpoint_host> its_host = its_server->host_.lock();
if (its_host) {
if (!_error && 0 < _bytes) {
recv_buffer_size_ += _bytes;
@@ -274,17 +329,17 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
if (has_full_message) {
bool needs_forwarding(true);
if (is_magic_cookie(its_iteration_gap)) {
- server_->has_enabled_magic_cookies_ = true;
+ its_server->has_enabled_magic_cookies_ = true;
} else {
- if (server_->has_enabled_magic_cookies_) {
+ if (its_server->has_enabled_magic_cookies_) {
uint32_t its_offset
- = server_->find_magic_cookie(&recv_buffer_[its_iteration_gap],
+ = its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap],
recv_buffer_size_);
if (its_offset < current_message_size) {
VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing.";
if (!is_magic_cookie(its_iteration_gap)) {
its_host->on_error(&recv_buffer_[its_iteration_gap],
- static_cast<length_t>(recv_buffer_size_), server_);
+ static_cast<length_t>(recv_buffer_size_), its_server.get());
}
current_message_size = its_offset;
needs_forwarding = false;
@@ -306,50 +361,50 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
{
std::lock_guard<std::mutex> its_lock(stop_mutex_);
if (socket_.is_open()) {
- server_->clients_mutex_.lock();
+ its_server->clients_mutex_.lock();
boost::system::error_code its_error;
endpoint_type its_endpoint(socket_.remote_endpoint(its_error));
if (!its_error) {
- server_->clients_[its_client][its_session] = its_endpoint;
+ its_server->clients_[its_client][its_session] = its_endpoint;
}
- server_->clients_mutex_.unlock();
- server_->current_ = this;
+ its_server->clients_mutex_.unlock();
+ its_server->current_ = this;
}
}
}
- if (!server_->has_enabled_magic_cookies_) {
+ if (!its_server->has_enabled_magic_cookies_) {
its_host->on_message(&recv_buffer_[its_iteration_gap],
- current_message_size, server_);
+ current_message_size, its_server.get());
} else {
// Only call on_message without a magic cookie in front of the buffer!
if (!is_magic_cookie(its_iteration_gap)) {
its_host->on_message(&recv_buffer_[its_iteration_gap],
- current_message_size, server_);
+ current_message_size, its_server.get());
}
}
}
recv_buffer_size_ -= current_message_size;
its_iteration_gap += current_message_size;
- } else if (server_->has_enabled_magic_cookies_ && recv_buffer_size_ > 0){
+ } else if (its_server->has_enabled_magic_cookies_ && recv_buffer_size_ > 0){
uint32_t its_offset =
- server_->find_magic_cookie(&recv_buffer_[its_iteration_gap],
+ its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap],
recv_buffer_size_);
if (its_offset < recv_buffer_size_) {
VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing.";
if (!is_magic_cookie(its_iteration_gap)) {
its_host->on_error(&recv_buffer_[its_iteration_gap],
- static_cast<length_t>(recv_buffer_size_), server_);
+ static_cast<length_t>(recv_buffer_size_), its_server.get());
}
recv_buffer_size_ -= its_offset;
its_iteration_gap += its_offset;
has_full_message = true; // trigger next loop
if (!is_magic_cookie(its_iteration_gap)) {
its_host->on_error(&recv_buffer_[its_iteration_gap],
- static_cast<length_t>(recv_buffer_size_), server_);
+ static_cast<length_t>(recv_buffer_size_), its_server.get());
}
}
} else if (current_message_size > max_message_size_) {
- if (server_->has_enabled_magic_cookies_) {
+ if (its_server->has_enabled_magic_cookies_) {
VSOMEIP_ERROR << "Received a TCP message which exceeds "
<< "maximum message size ("
<< std::dec << current_message_size
@@ -376,21 +431,38 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
receive();
}
}
+ if (_error == boost::asio::error::eof
+ || _error == boost::asio::error::connection_reset) {
+ {
+ std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
+ stop();
+ }
+ its_server->remove_connection(this);
+ }
}
client_t tcp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definition> _endpoint) {
endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port());
- auto its_remote = connections_.find(endpoint);
- if (its_remote != connections_.end()) {
- return its_remote->second->get_client(endpoint);
+ {
+ std::lock_guard<std::mutex> its_lock(connections_mutex_);
+ auto its_remote = connections_.find(endpoint);
+ if (its_remote != connections_.end()) {
+ return its_remote->second->get_client(endpoint);
+ }
}
return 0;
}
client_t tcp_server_endpoint_impl::connection::get_client(endpoint_type _endpoint_type) {
- std::lock_guard<std::mutex> its_lock(server_->clients_mutex_);
- for (auto its_client : server_->clients_) {
- for (auto its_session : server_->clients_[its_client.first]) {
+ std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock());
+ if (!its_server) {
+ VSOMEIP_TRACE << "tcp_server_endpoint_impl::connection::get_client "
+ " couldn't lock server_";
+ return 0;
+ }
+ std::lock_guard<std::mutex> its_lock(its_server->clients_mutex_);
+ for (const auto its_client : its_server->clients_) {
+ for (const auto its_session : its_server->clients_[its_client.first]) {
auto endpoint = its_session.second;
if (endpoint == _endpoint_type) {
// TODO: Check system byte order before convert!
diff --git a/implementation/endpoints/src/udp_client_endpoint_impl.cpp b/implementation/endpoints/src/udp_client_endpoint_impl.cpp
index a6029db..c92fff0 100644
--- a/implementation/endpoints/src/udp_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/udp_client_endpoint_impl.cpp
@@ -124,6 +124,11 @@ unsigned short udp_client_endpoint_impl::get_remote_port() const {
void udp_client_endpoint_impl::receive_cbk(
boost::system::error_code const &_error, std::size_t _bytes) {
+ if (_error == boost::asio::error::operation_aborted) {
+ // endpoint was stopped
+ shutdown_and_close_socket();
+ return;
+ }
std::shared_ptr<endpoint_host> its_host = host_.lock();
if (!_error && 0 < _bytes && its_host) {
#if 0
@@ -147,7 +152,9 @@ void udp_client_endpoint_impl::receive_cbk(
if (!_error) {
receive();
} else {
- if (socket_.is_open()) {
+ if (_error == boost::asio::error::connection_refused) {
+ shutdown_and_close_socket();
+ } else if (socket_.is_open()) {
receive();
}
}
diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp
index 8b3fd30..f1cd692 100644
--- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp
@@ -8,7 +8,6 @@
#include <boost/asio/ip/multicast.hpp>
-
#include "../include/endpoint_definition.hpp"
#include "../include/endpoint_host.hpp"
#include "../include/udp_server_endpoint_impl.hpp"
@@ -40,6 +39,12 @@ udp_server_endpoint_impl::udp_server_endpoint_impl(
= configuration::get()->get_unicast_address().to_v4();
boost::asio::ip::multicast::outbound_interface option(its_unicast_address);
socket_.set_option(option);
+ } else if (_local.address().is_v6()) {
+ boost::asio::ip::address_v6 its_unicast_address
+ = configuration::get()->get_unicast_address().to_v6();
+ boost::asio::ip::multicast::outbound_interface option(
+ static_cast<unsigned int>(its_unicast_address.scope_id()));
+ socket_.set_option(option);
}
socket_.bind(_local, ec);
@@ -75,6 +80,7 @@ void udp_server_endpoint_impl::stop() {
server_endpoint_impl::stop();
if (socket_.is_open()) {
boost::system::error_code its_error;
+ socket_.shutdown(socket_type::shutdown_both, its_error);
socket_.close(its_error);
}
}
diff --git a/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp b/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp
index d81fb42..3b66297 100644
--- a/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp
+++ b/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp
@@ -58,11 +58,15 @@
#if defined(__clang__)
# if defined(__apple_build_version__)
# if (__clang_major__ >= 7)
-# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# if !defined(BOOST_ASIO_UNUSED_TYPEDEF)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif
# endif // (__clang_major__ >= 7)
# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \
|| (__clang_major__ > 3)
-# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# if !defined(BOOST_ASIO_UNUSED_TYPEDEF)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif
# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6))
// || (__clang_major__ > 3)
#elif defined(__GNUC__)
diff --git a/implementation/logging/include/logger.hpp b/implementation/logging/include/logger.hpp
index 7bbc00a..2d8cda4 100644
--- a/implementation/logging/include/logger.hpp
+++ b/implementation/logging/include/logger.hpp
@@ -19,14 +19,14 @@
namespace vsomeip {
-class VSOMEIP_EXPORT logger {
+class VSOMEIP_IMPORT_EXPORT logger {
public:
static std::shared_ptr<logger> get();
virtual ~logger() {
}
- virtual boost::log::sources::severity_logger<
+ virtual boost::log::sources::severity_logger_mt<
boost::log::trivial::severity_level> & get_internal() = 0;
};
diff --git a/implementation/logging/include/logger_impl.hpp b/implementation/logging/include/logger_impl.hpp
index 3916874..9c7d0bf 100644
--- a/implementation/logging/include/logger_impl.hpp
+++ b/implementation/logging/include/logger_impl.hpp
@@ -37,7 +37,7 @@ public:
logger_impl();
- boost::log::sources::severity_logger<
+ boost::log::sources::severity_logger_mt<
boost::log::trivial::severity_level> & get_internal();
private:
@@ -47,13 +47,14 @@ private:
const std::string &_context_id);
private:
- boost::log::sources::severity_logger<
+ static boost::log::sources::severity_logger_mt<
boost::log::trivial::severity_level> logger_;
boost::log::trivial::severity_level loglevel_;
boost::shared_ptr<sink_t> console_sink_;
boost::shared_ptr<sink_t> file_sink_;
boost::shared_ptr<dlt_sink_t> dlt_sink_;
+ boost::log::core_ptr log_core_;
private:
void use_null_logger();
diff --git a/implementation/logging/src/logger_impl.cpp b/implementation/logging/src/logger_impl.cpp
index 3934c1e..f7c1948 100644
--- a/implementation/logging/src/logger_impl.cpp
+++ b/implementation/logging/src/logger_impl.cpp
@@ -46,6 +46,9 @@ using namespace boost::log::trivial;
namespace vsomeip {
+boost::log::sources::severity_logger_mt<
+ boost::log::trivial::severity_level> logger_impl::logger_;
+
std::shared_ptr<logger_impl> & logger_impl::get() {
static std::shared_ptr<logger_impl> the_logger__ = std::make_shared<
logger_impl>();
@@ -53,11 +56,12 @@ std::shared_ptr<logger_impl> & logger_impl::get() {
}
logger_impl::logger_impl()
- : loglevel_(debug) {
+ : loglevel_(debug),
+ log_core_(logging::core::get()) {
logging::add_common_attributes();
}
-boost::log::sources::severity_logger<boost::log::trivial::severity_level> &
+boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> &
logger_impl::get_internal() {
return logger_;
}
diff --git a/implementation/message/include/payload_impl.hpp b/implementation/message/include/payload_impl.hpp
index 66b3afa..b034918 100644
--- a/implementation/message/include/payload_impl.hpp
+++ b/implementation/message/include/payload_impl.hpp
@@ -32,6 +32,7 @@ public:
VSOMEIP_EXPORT void set_data(const byte_t *_data, length_t _length);
VSOMEIP_EXPORT void set_data(const std::vector< byte_t > &_data);
+ VSOMEIP_EXPORT void set_data(std::vector< byte_t > &&_data);
VSOMEIP_EXPORT bool serialize(serializer *_to) const;
VSOMEIP_EXPORT bool deserialize(deserializer *_from);
diff --git a/implementation/message/include/serializer.hpp b/implementation/message/include/serializer.hpp
index 7928a52..a61f9ef 100644
--- a/implementation/message/include/serializer.hpp
+++ b/implementation/message/include/serializer.hpp
@@ -15,7 +15,7 @@ namespace vsomeip {
class serializable;
-class VSOMEIP_EXPORT serializer {
+class VSOMEIP_IMPORT_EXPORT serializer {
public:
serializer();
virtual ~serializer();
diff --git a/implementation/message/src/message_header_impl.cpp b/implementation/message/src/message_header_impl.cpp
index 39446b7..3262c8d 100644
--- a/implementation/message/src/message_header_impl.cpp
+++ b/implementation/message/src/message_header_impl.cpp
@@ -48,12 +48,11 @@ bool message_header_impl::deserialize(deserializer *_from) {
bool is_successful;
uint8_t tmp_message_type, tmp_return_code;
- uint32_t tmp_length;
is_successful = (0 != _from
&& _from->deserialize(service_)
&& _from->deserialize(method_)
- && _from->deserialize(tmp_length)
+ && _from->deserialize(length_)
&& _from->deserialize(client_)
&& _from->deserialize(session_)
&& _from->deserialize(protocol_version_)
@@ -64,7 +63,6 @@ bool message_header_impl::deserialize(deserializer *_from) {
if (is_successful) {
type_ = static_cast< message_type_e >(tmp_message_type);
code_ = static_cast< return_code_e >(tmp_return_code);
- length_ = static_cast< length_t >(tmp_length - VSOMEIP_SOMEIP_HEADER_SIZE);
}
return is_successful;
diff --git a/implementation/message/src/message_impl.cpp b/implementation/message/src/message_impl.cpp
index c19ae76..1d3d6bd 100644
--- a/implementation/message/src/message_impl.cpp
+++ b/implementation/message/src/message_impl.cpp
@@ -41,7 +41,7 @@ bool message_impl::deserialize(deserializer *_from) {
payload_ = runtime::get()->create_payload();
bool is_successful = header_.deserialize(_from);
if (is_successful) {
- payload_->set_capacity(header_.length_);
+ payload_->set_capacity(header_.length_ - VSOMEIP_SOMEIP_HEADER_SIZE);
is_successful = payload_->deserialize(_from);
}
return is_successful;
diff --git a/implementation/message/src/payload_impl.cpp b/implementation/message/src/payload_impl.cpp
index 3355788..663a7b8 100644
--- a/implementation/message/src/payload_impl.cpp
+++ b/implementation/message/src/payload_impl.cpp
@@ -64,6 +64,10 @@ void payload_impl::set_data(const std::vector< byte_t > &_data) {
data_ = _data;
}
+void payload_impl::set_data(std::vector< byte_t > &&_data) {
+ data_ = std::move(_data);
+}
+
bool payload_impl::serialize(serializer *_to) const {
return (0 != _to && _to->serialize(data_.data(), uint32_t(data_.size())));
}
diff --git a/implementation/routing/include/event.hpp b/implementation/routing/include/event.hpp
index 9033160..2a76ad8 100644
--- a/implementation/routing/include/event.hpp
+++ b/implementation/routing/include/event.hpp
@@ -13,9 +13,11 @@
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/address.hpp>
-#include <boost/asio/system_timer.hpp>
+#include <boost/asio/steady_timer.hpp>
#include <vsomeip/primitive_types.hpp>
+#include <vsomeip/function_types.hpp>
+#include <vsomeip/payload.hpp>
namespace vsomeip {
@@ -43,14 +45,17 @@ public:
const std::shared_ptr<payload> get_payload() const;
- void set_payload(std::shared_ptr<payload> _payload, const client_t _client);
+ void set_payload(const std::shared_ptr<payload> &_payload,
+ const client_t _client, bool _force = false);
- void set_payload(std::shared_ptr<payload> _payload,
- const std::shared_ptr<endpoint_definition> _target);
+ void set_payload(const std::shared_ptr<payload> &_payload,
+ const std::shared_ptr<endpoint_definition> _target,
+ bool _force = false);
- void set_payload_dont_notify(std::shared_ptr<payload> _payload);
+ void set_payload_dont_notify(const std::shared_ptr<payload> &_payload);
- void set_payload(std::shared_ptr<payload> _payload);
+ void set_payload(const std::shared_ptr<payload> &_payload,
+ bool _force = false);
void unset_payload(bool _force = false);
bool is_field() const;
@@ -63,18 +68,20 @@ public:
// SIP_RPC_357
void set_update_cycle(std::chrono::milliseconds &_cycle);
+ void set_change_resets_cycle(bool _change_resets_cycle);
// SIP_RPC_358
void set_update_on_change(bool _is_on);
- // SIP_RPC_359 (epsilon change) is not supported!
+ // SIP_RPC_359 (epsilon change)
+ void set_epsilon_change_function(const epsilon_change_func_t &_epsilon_change_func);
const std::set<eventgroup_t> & get_eventgroups() const;
void add_eventgroup(eventgroup_t _eventgroup);
void set_eventgroups(const std::set<eventgroup_t> &_eventgroups);
void notify_one(const std::shared_ptr<endpoint_definition> &_target);
- void notify_one(client_t _client, bool _is_initial = false);
+ void notify_one(client_t _client);
void add_ref(client_t _client, bool _is_provided);
void remove_ref(client_t _client, bool _is_provided);
@@ -91,17 +98,24 @@ private:
void notify();
void notify(client_t _client, const std::shared_ptr<endpoint_definition> &_target);
-private:
- bool set_payload_helper(std::shared_ptr<payload> _payload);
+ void start_cycle();
+ void stop_cycle();
+
+ bool compare(const std::shared_ptr<payload> &_lhs, const std::shared_ptr<payload> &_rhs) const;
+
+ bool set_payload_helper(const std::shared_ptr<payload> &_payload, bool _force);
+ void reset_payload(const std::shared_ptr<payload> &_payload);
+private:
routing_manager *routing_;
std::mutex mutex_;
std::shared_ptr<message> message_;
bool is_field_;
- boost::asio::system_timer cycle_timer_;
+ boost::asio::steady_timer cycle_timer_;
std::chrono::milliseconds cycle_;
+ bool change_resets_cycle_;
bool is_updating_on_change_;
@@ -115,6 +129,8 @@ private:
bool is_shadow_;
bool is_cache_placeholder_;
+
+ epsilon_change_func_t epsilon_change_func_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/eventgroupinfo.hpp b/implementation/routing/include/eventgroupinfo.hpp
index 7e832a1..fc3d321 100644
--- a/implementation/routing/include/eventgroupinfo.hpp
+++ b/implementation/routing/include/eventgroupinfo.hpp
@@ -25,7 +25,7 @@ class eventgroupinfo {
public:
struct target_t {
std::shared_ptr<endpoint_definition> endpoint_;
- std::chrono::high_resolution_clock::time_point expiration_;
+ std::chrono::steady_clock::time_point expiration_;
bool operator==(const target_t &_other) const {
return (endpoint_ == _other.endpoint_);
@@ -47,19 +47,20 @@ public:
uint16_t &_port) const;
VSOMEIP_EXPORT void set_multicast(const boost::asio::ip::address &_address,
uint16_t _port);
+ VSOMEIP_EXPORT bool is_sending_multicast() const;
VSOMEIP_EXPORT const std::set<std::shared_ptr<event> > get_events() const;
VSOMEIP_EXPORT void add_event(std::shared_ptr<event> _event);
VSOMEIP_EXPORT void remove_event(std::shared_ptr<event> _event);
VSOMEIP_EXPORT const std::list<target_t> get_targets() const;
- VSOMEIP_EXPORT uint32_t get_unreliable_target_count();
+ VSOMEIP_EXPORT uint32_t get_unreliable_target_count() const;
VSOMEIP_EXPORT bool add_target(const target_t &_target);
VSOMEIP_EXPORT bool add_target(const target_t &_target, const target_t &_subscriber);
VSOMEIP_EXPORT bool update_target(
const std::shared_ptr<endpoint_definition> &_target,
- const std::chrono::high_resolution_clock::time_point &_expiration);
+ const std::chrono::steady_clock::time_point &_expiration);
VSOMEIP_EXPORT bool remove_target(
const std::shared_ptr<endpoint_definition> &_target);
VSOMEIP_EXPORT void clear_targets();
@@ -68,6 +69,9 @@ public:
VSOMEIP_EXPORT void clear_multicast_targets();
VSOMEIP_EXPORT const std::list<target_t> get_multicast_targets() const;
+ VSOMEIP_EXPORT uint8_t get_threshold() const;
+ VSOMEIP_EXPORT void set_threshold(uint8_t _threshold);
+
private:
major_version_t major_;
ttl_t ttl_;
@@ -78,6 +82,8 @@ private:
std::set<std::shared_ptr<event> > events_;
std::list<target_t> targets_;
std::list<target_t> multicast_targets_;
+
+ uint8_t threshold_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp
index ee18957..dcbdd5a 100644
--- a/implementation/routing/include/routing_manager.hpp
+++ b/implementation/routing/include/routing_manager.hpp
@@ -12,6 +12,7 @@
#include <boost/asio/io_service.hpp>
+#include <vsomeip/function_types.hpp>
#include <vsomeip/message.hpp>
#include <vsomeip/handler.hpp>
@@ -35,12 +36,13 @@ public:
virtual void start() = 0;
virtual void stop() = 0;
- virtual void offer_service(client_t _client, service_t _service,
+ virtual bool offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor) = 0;
virtual void stop_offer_service(client_t _client, service_t _service,
- instance_t _instance, major_version_t _major, minor_version_t _minor) = 0;
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor) = 0;
virtual void request_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
@@ -61,7 +63,7 @@ public:
bool _flush) = 0;
virtual bool send(client_t _client, const byte_t *_data, uint32_t _size,
- instance_t _instance, bool _flush, bool _reliable, bool _initial) = 0;
+ instance_t _instance, bool _flush, bool _reliable) = 0;
virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message>) = 0;
@@ -69,13 +71,16 @@ public:
virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target,
const byte_t *_data, uint32_t _size) = 0;
- virtual void register_event(client_t _client, service_t _service, instance_t _instance,
- event_t _event, const std::set<eventgroup_t> &_eventgroups,
- bool _is_field, bool _is_provided, bool _is_shadow = false,
+ virtual void register_event(client_t _client, service_t _service,
+ instance_t _instance, event_t _event,
+ const std::set<eventgroup_t> &_eventgroups, bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle,
+ epsilon_change_func_t _epsilon_change_func,
+ bool _is_provided, bool _is_shadow = false,
bool _is_cache_placeholder = false) = 0;
- virtual void unregister_event(client_t _client, service_t _service, instance_t _instance,
- event_t _event, bool _is_provided) = 0;
+ virtual void unregister_event(client_t _client, service_t _service,
+ instance_t _instance, event_t _event, bool _is_provided) = 0;
virtual std::shared_ptr<event> get_event(service_t _service,
instance_t _instance, event_t _event) const = 0;
@@ -84,13 +89,15 @@ public:
instance_t _instance, eventgroup_t _eventgroup) const = 0;
virtual void notify(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload) = 0;
+ event_t _event, std::shared_ptr<payload> _payload,
+ bool _force) = 0;
virtual void notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload, client_t _client) = 0;
+ event_t _event, std::shared_ptr<payload> _payload,
+ client_t _client, bool _force) = 0;
- virtual void on_identify_response(client_t _client, service_t _service, instance_t _instance,
- bool _reliable) = 0;
+ virtual void on_identify_response(client_t _client, service_t _service,
+ instance_t _instance, bool _reliable) = 0;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp
index 1d69f6f..a7c127c 100644
--- a/implementation/routing/include/routing_manager_base.hpp
+++ b/implementation/routing/include/routing_manager_base.hpp
@@ -48,7 +48,7 @@ public:
virtual void init();
- virtual void offer_service(client_t _client, service_t _service,
+ virtual bool offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor);
@@ -63,9 +63,10 @@ public:
instance_t _instance);
virtual void register_event(client_t _client, service_t _service, instance_t _instance,
- event_t _event, const std::set<eventgroup_t> &_eventgroups,
- bool _is_field, bool _is_provided, bool _is_shadow = false,
- bool _is_cache_placeholder = false);
+ event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle,
+ epsilon_change_func_t _epsilon_change_func,
+ bool _is_provided, bool _is_shadow = false, bool _is_cache_placeholder = false);
virtual void unregister_event(client_t _client, service_t _service, instance_t _instance,
event_t _event, bool _is_provided);
@@ -84,19 +85,18 @@ public:
virtual void unsubscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup);
- virtual void notify(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload);
+ virtual void notify(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload, bool _force);
- virtual void notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload, client_t _client);
+ virtual void notify_one(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload,
+ client_t _client, bool _force);
virtual bool send(client_t _client, std::shared_ptr<message> _message,
bool _flush);
virtual bool send(client_t _client, const byte_t *_data, uint32_t _size,
- instance_t _instance, bool _flush, bool _reliable, bool _initial) = 0;
-
- virtual bool queue_message(const byte_t *_data, uint32_t _size) const = 0;
+ instance_t _instance, bool _flush, bool _reliable) = 0;
// Endpoint host ~> will be implemented by routing_manager_impl/_proxy/
virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0;
@@ -107,6 +107,8 @@ public:
virtual void on_error(const byte_t *_data, length_t _length,
endpoint *_receiver) = 0;
+ virtual void on_clientendpoint_error(client_t _client);
+
protected:
std::shared_ptr<serviceinfo> find_service(service_t _service, instance_t _instance) const;
std::shared_ptr<serviceinfo> create_service_info(service_t _service,
@@ -138,15 +140,14 @@ protected:
void remove_eventgroup_info(service_t _service, instance_t _instance,
eventgroup_t _eventgroup);
- void send_local_notification(client_t _client,
+ bool send_local_notification(client_t _client,
const byte_t *_data, uint32_t _size, instance_t _instance,
- bool _flush = true, bool _reliable = false, bool _inital = false);
+ bool _flush = true, bool _reliable = false);
bool send_local(
std::shared_ptr<endpoint> &_target, client_t _client,
const byte_t *_data, uint32_t _size, instance_t _instance,
- bool _flush, bool _reliable, uint8_t _command, bool _queue_message = false,
- bool _initial = false) const;
+ bool _flush, bool _reliable, uint8_t _command) const;
bool insert_subscription(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, client_t _client);
diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp
index 13936a4..b08f2cd 100644
--- a/implementation/routing/include/routing_manager_impl.hpp
+++ b/implementation/routing/include/routing_manager_impl.hpp
@@ -58,7 +58,7 @@ public:
void start();
void stop();
- void offer_service(client_t _client, service_t _service,
+ bool offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor);
@@ -82,7 +82,7 @@ public:
bool send(client_t _client, std::shared_ptr<message> _message, bool _flush);
bool send(client_t _client, const byte_t *_data, uint32_t _size,
- instance_t _instance, bool _flush, bool _reliable, bool _initial = false);
+ instance_t _instance, bool _flush, bool _reliable);
bool send_to(const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message> _message);
@@ -103,10 +103,11 @@ public:
bool _is_provided);
void notify(service_t _service, instance_t _instance, event_t _event,
- std::shared_ptr<payload> _payload);
+ std::shared_ptr<payload> _payload, bool _force);
void notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload, client_t _client);
+ event_t _event, std::shared_ptr<payload> _payload,
+ client_t _client, bool _force);
void on_subscribe_nack(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup);
@@ -117,15 +118,15 @@ public:
void on_identify_response(client_t _client, service_t _service, instance_t _instance,
bool _reliable);
- bool queue_message(const byte_t *_data, uint32_t _size) const;
-
// interface to stub
std::shared_ptr<endpoint> find_local(client_t _client);
std::shared_ptr<endpoint> find_or_create_local(client_t _client);
void remove_local(client_t _client);
- void on_stop_offer_service(service_t _service, instance_t _instance,
+ void on_stop_offer_service(client_t _client, service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor);
+ void on_pong(client_t _client);
+
// interface "endpoint_host"
std::shared_ptr<endpoint> find_or_create_remote_client(service_t _service,
instance_t _instance,
@@ -151,7 +152,7 @@ public:
std::shared_ptr<endpoint> create_service_discovery_endpoint(const std::string &_address,
uint16_t _port, bool _reliable);
void init_routing_info();
- void add_routing_info(service_t _service, instance_t _instance,
+ std::chrono::milliseconds add_routing_info(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor, ttl_t _ttl,
const boost::asio::ip::address &_reliable_address,
uint16_t _reliable_port,
@@ -165,11 +166,11 @@ public:
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _subscriber,
std::shared_ptr<endpoint_definition> _target,
- const std::chrono::high_resolution_clock::time_point &_expiration);
+ const std::chrono::steady_clock::time_point &_expiration);
bool on_subscribe_accepted(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _target,
- const std::chrono::high_resolution_clock::time_point &_expiration);
+ const std::chrono::steady_clock::time_point &_expiration);
void on_unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _target);
@@ -179,11 +180,14 @@ public:
void expire_subscriptions(const boost::asio::ip::address &_address);
void expire_services(const boost::asio::ip::address &_address);
- std::chrono::high_resolution_clock::time_point expire_subscriptions();
+ std::chrono::steady_clock::time_point expire_subscriptions();
bool has_identified(client_t _client, service_t _service,
instance_t _instance, bool _reliable);
+ void on_clientendpoint_error(client_t _client);
+ void confirm_pending_offers(client_t _client);
+
private:
bool deliver_message(const byte_t *_data, length_t _length,
instance_t _instance, bool _reliable);
@@ -197,7 +201,7 @@ private:
std::shared_ptr<endpoint> create_client_endpoint(
const boost::asio::ip::address &_address,
- uint16_t _local_port, uint16_t _remote_port,
+ uint16_t _local_port, uint16_t _remote_port,
bool _reliable, client_t _client, bool _start);
std::shared_ptr<endpoint> create_server_endpoint(uint16_t _port,
@@ -223,6 +227,9 @@ private:
void stop_and_delete_client_endpoint(std::shared_ptr<endpoint> _endpoint);
void clear_multicast_endpoints(service_t _service, instance_t _instance);
+ bool is_identifying(client_t _client, service_t _service,
+ instance_t _instance, bool _reliable);
+
private:
return_code_e check_error(const byte_t *_data, length_t _size,
instance_t _instance);
@@ -244,6 +251,23 @@ private:
client_t _client,
const std::shared_ptr<endpoint_definition> &_target);
+ void log_version_timer_cbk(boost::system::error_code const & _error);
+
+ void clear_remote_service_info(service_t _service, instance_t _instance, bool _reliable);
+
+ bool handle_local_offer_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major,minor_version_t _minor);
+
+ void remove_specific_client_endpoint(client_t _client, service_t _service, instance_t _instance, bool _reliable);
+
+ void clear_identified_clients( service_t _service, instance_t _instance);
+
+ void clear_identifying_clients( service_t _service, instance_t _instance);
+
+ void remove_identified_client(service_t _service, instance_t _instance, client_t _client);
+
+ void remove_identifying_client(service_t _service, instance_t _instance, client_t _client);
+
std::shared_ptr<routing_manager_stub> stub_;
std::shared_ptr<sd::service_discovery> discovery_;
@@ -272,17 +296,36 @@ private:
std::mutex identified_clients_mutex_;
std::mutex requested_services_mutex_;
+ std::mutex remote_subscribers_mutex_;
std::map<service_t, std::map<instance_t, std::map<client_t,
std::set<std::shared_ptr<endpoint_definition>>>>> remote_subscribers_;
std::mutex specific_endpoint_clients_mutex_;
std::map<service_t, std::map<instance_t, std::unordered_set<client_t>>>specific_endpoint_clients_;
std::map<service_t, std::map<instance_t,
- std::map<bool, std::unordered_set<client_t> > > >identified_clients_;
+ std::map<bool, std::unordered_set<client_t> > > > identified_clients_;
+ std::map<service_t, std::map<instance_t,
+ std::map<bool, std::unordered_set<client_t> > > > identifying_clients_;
std::shared_ptr<serviceinfo> sd_info_;
std::map<bool, std::set<uint16_t>> used_client_ports_;
+
+ boost::asio::steady_timer version_log_timer_;
+
+#ifndef WITHOUT_SYSTEMD
+ boost::asio::steady_timer watchdog_timer_;
+ void watchdog_cbk(boost::system::error_code const &_error);
+#endif
+
+ std::mutex pending_offers_mutex_;
+ // map to store pending offers.
+ // 1st client id in tuple: client id of new offering application
+ // 2nd client id in tuple: client id of previously/stored offering application
+ std::map<service_t,
+ std::map<instance_t,
+ std::tuple<major_version_t, minor_version_t,
+ client_t, client_t>>> pending_offers_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp
index d2f61d7..bea1c24 100644
--- a/implementation/routing/include/routing_manager_proxy.hpp
+++ b/implementation/routing/include/routing_manager_proxy.hpp
@@ -10,6 +10,7 @@
#include <mutex>
#include <boost/asio/io_service.hpp>
+#include <boost/asio/steady_timer.hpp>
#include "routing_manager_base.hpp"
#include <vsomeip/enumeration_types.hpp>
@@ -30,7 +31,7 @@ public:
void start();
void stop();
- void offer_service(client_t _client, service_t _service,
+ bool offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor);
@@ -52,8 +53,7 @@ public:
eventgroup_t _eventgroup);
bool send(client_t _client, const byte_t *_data, uint32_t _size,
- instance_t _instance, bool _flush = true, bool _reliable = false,
- bool _initial = false);
+ instance_t _instance, bool _flush = true, bool _reliable = false);
bool send_to(const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message> _message);
@@ -63,15 +63,17 @@ public:
void register_event(client_t _client, service_t _service,
instance_t _instance, event_t _event,
- const std::set<eventgroup_t> &_eventgroups,
- bool _is_field, bool _is_provided, bool _is_shadow, bool _is_cache_placeholder);
+ const std::set<eventgroup_t> &_eventgroups, bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle,
+ epsilon_change_func_t _epsilon_change_func,
+ bool _is_provided, bool _is_shadow, bool _is_cache_placeholder);
void unregister_event(client_t _client, service_t _service,
instance_t _instance, event_t _event,
bool _is_provided);
void notify(service_t _service, instance_t _instance, event_t _event,
- std::shared_ptr<payload> _payload);
+ std::shared_ptr<payload> _payload, bool _force);
void on_connect(std::shared_ptr<endpoint> _endpoint);
void on_disconnect(std::shared_ptr<endpoint> _endpoint);
@@ -85,8 +87,6 @@ public:
void on_identify_response(client_t _client, service_t _service, instance_t _instance,
bool _reliable);
- bool queue_message(const byte_t *_data, uint32_t _size) const;
-
private:
void register_application();
void deregister_application();
@@ -131,10 +131,27 @@ private:
void on_stop_offer_service(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor);
+ void send_pending_commands();
+
+ void init_receiver();
+
+ void notify_remote_initally(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup);
+
+ uint32_t get_remote_subscriber_count(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, bool _increment);
+
+ void register_application_timeout_cbk(boost::system::error_code const &_error);
private:
+ enum class inner_state_type_e : std::uint8_t {
+ ST_REGISTERED = 0x0,
+ ST_DEREGISTERED = 0x1,
+ ST_REGISTERING = 0x2
+ };
+
bool is_connected_;
bool is_started_;
- state_type_e state_;
+ inner_state_type_e state_;
std::shared_ptr<endpoint> sender_; // --> stub
std::shared_ptr<endpoint> receiver_; // --> from everybody
@@ -202,7 +219,16 @@ private:
std::mutex send_mutex_;
std::mutex deserialize_mutex_;
- std::mutex pending_mutex_;
+
+ std::mutex state_mutex_;
+ std::condition_variable state_condition_;
+
+ std::map<service_t,
+ std::map<instance_t, std::map<eventgroup_t, uint32_t > > > remote_subscriber_count_;
+
+ mutable std::recursive_mutex sender_mutex_;
+
+ boost::asio::steady_timer register_application_timer_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp
index 27b8ec5..6255cda 100644
--- a/implementation/routing/include/routing_manager_stub.hpp
+++ b/implementation/routing/include/routing_manager_stub.hpp
@@ -15,7 +15,7 @@
#include <thread>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/system_timer.hpp>
+#include <boost/asio/steady_timer.hpp>
#include "../../endpoints/include/endpoint_host.hpp"
@@ -48,8 +48,6 @@ public:
void on_stop_offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor);
- bool queue_message(const byte_t *_data, uint32_t _size);
-
void send_subscribe(std::shared_ptr<vsomeip::endpoint> _target,
client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
@@ -57,7 +55,8 @@ public:
void send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _target,
client_t _client, service_t _service,
- instance_t _instance, eventgroup_t _eventgroup);
+ instance_t _instance, eventgroup_t _eventgroup,
+ bool _is_remote_subscriber);
void send_subscribe_nack(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup);
@@ -65,8 +64,15 @@ public:
void send_subscribe_ack(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup);
+ bool contained_in_routing_info(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor) const;
+
+ void create_local_receiver();
+ bool send_ping(client_t _client);
+ void deregister_erroneous_client(client_t _client);
private:
- void broadcast(std::vector<byte_t> &_command) const;
+ void broadcast(const std::vector<byte_t> &_command) const;
void on_register_application(client_t _client);
void on_deregister_application(client_t _client);
@@ -81,11 +87,14 @@ private:
void send_application_lost(std::list<client_t> &_lost);
void client_registration_func(void);
+ void init_routing_endpoint();
+ void on_ping_timer_expired(boost::system::error_code const &_error);
+ void remove_from_pinged_clients(client_t _client);
private:
routing_manager_stub_host *host_;
boost::asio::io_service &io_;
- boost::asio::system_timer watchdog_timer_;
+ boost::asio::steady_timer watchdog_timer_;
std::string endpoint_path_;
std::string local_receiver_path_;
@@ -103,7 +112,18 @@ private:
std::shared_ptr<std::thread> client_registration_thread_;
std::mutex client_registration_mutex_;
std::condition_variable client_registration_condition_;
- std::map<client_t, std::vector<bool>> pending_client_registrations_;
+
+ enum class registration_type_e : std::uint8_t {
+ REGISTER = 0x1,
+ DEREGISTER = 0x2,
+ DEREGISTER_ERROR_CASE = 0x3
+ };
+ std::map<client_t, std::vector<registration_type_e>> pending_client_registrations_;
+ static const std::vector<byte_t> its_ping_;
+ const std::chrono::milliseconds configured_watchdog_timeout_;
+ boost::asio::steady_timer pinged_clients_timer_;
+ std::mutex pinged_clients_mutex_;
+ std::map<client_t, boost::asio::steady_timer::time_point> pinged_clients_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp
index e216b5a..0d1decb 100644
--- a/implementation/routing/include/routing_manager_stub_host.hpp
+++ b/implementation/routing/include/routing_manager_stub_host.hpp
@@ -16,7 +16,7 @@ public:
virtual ~routing_manager_stub_host() {
}
- virtual void offer_service(client_t _client, service_t _service,
+ virtual bool offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor) = 0;
@@ -59,7 +59,7 @@ public:
service_t _service, instance_t _instance,
const byte_t *_data, length_t _size, bool _notify_one = false) = 0;
- virtual void on_stop_offer_service(service_t _service,
+ virtual void on_stop_offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor) = 0;
@@ -74,6 +74,10 @@ public:
virtual void on_identify_response(client_t _client, service_t _service, instance_t _instance,
bool _reliable) = 0;
+
+ virtual void on_pong(client_t _client) = 0;
+ virtual void on_clientendpoint_error(client_t _client) = 0;
+ virtual void confirm_pending_offers(client_t _client) = 0;
};
} // namespace vsomeip
diff --git a/implementation/routing/src/event.cpp b/implementation/routing/src/event.cpp
index d536597..c077844 100644
--- a/implementation/routing/src/event.cpp
+++ b/implementation/routing/src/event.cpp
@@ -21,11 +21,15 @@ event::event(routing_manager *_routing, bool _is_shadow) :
message_(runtime::get()->create_notification()),
is_field_(false),
cycle_timer_(_routing->get_io()),
+ cycle_(std::chrono::milliseconds::zero()),
+ change_resets_cycle_(false),
is_updating_on_change_(true),
is_set_(false),
is_provided_(false),
is_shadow_(_is_shadow),
- is_cache_placeholder_(false) {
+ is_cache_placeholder_(false),
+ epsilon_change_func_(std::bind(&event::compare, this,
+ std::placeholders::_1, std::placeholders::_2)) {
}
service_t event::get_service() const {
@@ -84,33 +88,29 @@ const std::shared_ptr<payload> event::get_payload() const {
return (message_->get_payload());
}
-void event::set_payload_dont_notify(std::shared_ptr<payload> _payload) {
+void event::set_payload_dont_notify(const std::shared_ptr<payload> &_payload) {
if(is_cache_placeholder_) {
- std::shared_ptr<payload> its_new_payload
- = runtime::get()->create_payload(
- _payload->get_data(), _payload->get_length());
- message_->set_payload(its_new_payload);
+ reset_payload(_payload);
is_set_ = true;
} else {
- if (set_payload_helper(_payload)) {
- std::shared_ptr<payload> its_new_payload
- = runtime::get()->create_payload(
- _payload->get_data(), _payload->get_length());
- message_->set_payload(its_new_payload);
+ if (set_payload_helper(_payload, false)) {
+ reset_payload(_payload);
}
}
}
-void event::set_payload(std::shared_ptr<payload> _payload) {
+void event::set_payload(const std::shared_ptr<payload> &_payload, bool _force) {
if (is_provided_) {
- if (set_payload_helper(_payload)) {
- std::shared_ptr<payload> its_new_payload
- = runtime::get()->create_payload(
- _payload->get_data(), _payload->get_length());
-
- message_->set_payload(its_new_payload);
+ if (set_payload_helper(_payload, _force)) {
+ reset_payload(_payload);
if (is_updating_on_change_) {
+ if (change_resets_cycle_)
+ stop_cycle();
+
notify();
+
+ if (change_resets_cycle_)
+ start_cycle();
}
}
} else {
@@ -119,16 +119,14 @@ void event::set_payload(std::shared_ptr<payload> _payload) {
}
}
-void event::set_payload(std::shared_ptr<payload> _payload, client_t _client) {
+void event::set_payload(const std::shared_ptr<payload> &_payload, client_t _client,
+ bool _force) {
if (is_provided_) {
- set_payload_helper(_payload);
- std::shared_ptr<payload> its_new_payload
- = runtime::get()->create_payload(
- _payload->get_data(), _payload->get_length());
-
- message_->set_payload(its_new_payload);
- if (is_updating_on_change_) {
- notify_one(_client);
+ if (set_payload_helper(_payload, _force)) {
+ reset_payload(_payload);
+ if (is_updating_on_change_) {
+ notify_one(_client);
+ }
}
} else {
VSOMEIP_DEBUG << "Can't set payload for event " << std::hex
@@ -136,15 +134,12 @@ void event::set_payload(std::shared_ptr<payload> _payload, client_t _client) {
}
}
-void event::set_payload(std::shared_ptr<payload> _payload,
- const std::shared_ptr<endpoint_definition> _target) {
+void event::set_payload(const std::shared_ptr<payload> &_payload,
+ const std::shared_ptr<endpoint_definition> _target,
+ bool _force) {
if (is_provided_) {
- if (set_payload_helper(_payload)) {
- std::shared_ptr<payload> its_new_payload
- = runtime::get()->create_payload(
- _payload->get_data(), _payload->get_length());
-
- message_->set_payload(its_new_payload);
+ if (set_payload_helper(_payload, _force)) {
+ reset_payload(_payload);
if (is_updating_on_change_) {
notify_one(_target);
}
@@ -156,39 +151,42 @@ void event::set_payload(std::shared_ptr<payload> _payload,
}
void event::unset_payload(bool _force) {
- if(_force) {
+ if (_force) {
is_set_ = false;
+ stop_cycle();
message_->set_payload(std::make_shared<payload_impl>());
} else {
if (is_provided_) {
is_set_ = false;
+ stop_cycle();
message_->set_payload(std::make_shared<payload_impl>());
}
}
}
-void event::set_update_on_change(bool _is_active) {
- if (is_provided_) {
- is_updating_on_change_ = _is_active;
- }
-}
-
void event::set_update_cycle(std::chrono::milliseconds &_cycle) {
if (is_provided_) {
+ stop_cycle();
cycle_ = _cycle;
+ start_cycle();
+ }
+}
- cycle_timer_.cancel();
+void event::set_change_resets_cycle(bool _change_resets_cycle) {
+ change_resets_cycle_ = _change_resets_cycle;
+}
- if (std::chrono::milliseconds::zero() != _cycle) {
- cycle_timer_.expires_from_now(cycle_);
- std::function<void(boost::system::error_code const &)> its_handler =
- std::bind(&event::update_cbk, shared_from_this(),
- std::placeholders::_1);
- cycle_timer_.async_wait(its_handler);
- }
+void event::set_update_on_change(bool _is_active) {
+ if (is_provided_) {
+ is_updating_on_change_ = _is_active;
}
}
+void event::set_epsilon_change_function(const epsilon_change_func_t &_epsilon_change_func) {
+ if (_epsilon_change_func)
+ epsilon_change_func_ = _epsilon_change_func;
+}
+
const std::set<eventgroup_t> & event::get_eventgroups() const {
return (eventgroups_);
}
@@ -230,42 +228,36 @@ void event::notify_one(const std::shared_ptr<endpoint_definition> &_target) {
}
}
-void event::notify_one(client_t _client, bool _is_initial) {
+void event::notify_one(client_t _client) {
if (is_set_) {
- const bool old_initial_value(message_->is_initial());
- if(_is_initial) {
- message_->set_initial(true);
- }
routing_->send(_client, message_, true);
- if(_is_initial) {
- message_->set_initial(old_initial_value);
- }
} else {
VSOMEIP_DEBUG << "Notify one event " << std::hex << message_->get_method()
<< " to client " << _client << " failed. Event payload not set!";
}
}
-bool event::set_payload_helper(std::shared_ptr<payload> _payload) {
+bool event::set_payload_helper(const std::shared_ptr<payload> &_payload, bool _force) {
std::shared_ptr<payload> its_payload = message_->get_payload();
bool is_change(!is_field_);
if (is_field_) {
- is_change = (its_payload->get_length() != _payload->get_length());
- if (!is_change) {
- std::size_t its_pos = 0;
- const byte_t *its_old_data = its_payload->get_data();
- const byte_t *its_new_data = _payload->get_data();
- while (!is_change && its_pos < its_payload->get_length()) {
- is_change = (*its_old_data++ != *its_new_data++);
- its_pos++;
- }
- }
+ is_change = _force || epsilon_change_func_(its_payload, _payload);
}
- is_set_ = true;
-
return is_change;
}
+void event::reset_payload(const std::shared_ptr<payload> &_payload) {
+ std::shared_ptr<payload> its_new_payload
+ = runtime::get()->create_payload(
+ _payload->get_data(), _payload->get_length());
+ message_->set_payload(its_new_payload);
+
+ if (!is_set_)
+ start_cycle();
+
+ is_set_ = true;
+}
+
void event::add_ref(client_t _client, bool _is_provided) {
auto its_client = refs_.find(_client);
if (its_client == refs_.end()) {
@@ -316,4 +308,36 @@ void event::set_cache_placeholder(bool _is_cache_place_holder) {
is_cache_placeholder_ = _is_cache_place_holder;
}
-} // namespace vsomeip
+void event::start_cycle() {
+ if (std::chrono::milliseconds::zero() != cycle_) {
+ cycle_timer_.expires_from_now(cycle_);
+ std::function<void(boost::system::error_code const &)> its_handler =
+ std::bind(&event::update_cbk, shared_from_this(),
+ std::placeholders::_1);
+ cycle_timer_.async_wait(its_handler);
+ }
+}
+
+void event::stop_cycle() {
+ if (std::chrono::milliseconds::zero() != cycle_) {
+ boost::system::error_code ec;
+ cycle_timer_.cancel(ec);
+ }
+}
+
+bool event::compare(const std::shared_ptr<payload> &_lhs,
+ const std::shared_ptr<payload> &_rhs) const {
+ bool is_change = (_lhs->get_length() != _rhs->get_length());
+ if (!is_change) {
+ std::size_t its_pos = 0;
+ const byte_t *its_old_data = _lhs->get_data();
+ const byte_t *its_new_data = _rhs->get_data();
+ while (!is_change && its_pos < _lhs->get_length()) {
+ is_change = (*its_old_data++ != *its_new_data++);
+ its_pos++;
+ }
+ }
+ return is_change;
+}
+
+} // namespace vsomeip
diff --git a/implementation/routing/src/eventgroupinfo.cpp b/implementation/routing/src/eventgroupinfo.cpp
index 1380969..fd63c4d 100644
--- a/implementation/routing/src/eventgroupinfo.cpp
+++ b/implementation/routing/src/eventgroupinfo.cpp
@@ -44,6 +44,12 @@ bool eventgroupinfo::is_multicast() const {
return address_.is_multicast();
}
+bool eventgroupinfo::is_sending_multicast() const {
+ return (is_multicast() &&
+ threshold_ != 0 &&
+ get_unreliable_target_count() >= threshold_);
+}
+
bool eventgroupinfo::get_multicast(boost::asio::ip::address &_address,
uint16_t &_port) const {
@@ -77,7 +83,7 @@ const std::list<eventgroupinfo::target_t> eventgroupinfo::get_targets() const {
return targets_;
}
-uint32_t eventgroupinfo::get_unreliable_target_count(){
+uint32_t eventgroupinfo::get_unreliable_target_count() const {
uint32_t _count(0);
for (auto i = targets_.begin(); i != targets_.end(); i++) {
if (!i->endpoint_->is_reliable()) {
@@ -114,8 +120,6 @@ bool eventgroupinfo::add_target(const eventgroupinfo::target_t &_target, const e
std::size_t its_size = targets_.size();
if (std::find(targets_.begin(), targets_.end(), _subscriber) == targets_.end()) {
targets_.push_back(_subscriber);
- }
- if (its_size != targets_.size()) {
add_multicast_target(_target);
}
return (its_size != targets_.size());
@@ -123,12 +127,13 @@ bool eventgroupinfo::add_target(const eventgroupinfo::target_t &_target, const e
bool eventgroupinfo::update_target(
const std::shared_ptr<endpoint_definition> &_target,
- const std::chrono::high_resolution_clock::time_point &_expiration) {
+ const std::chrono::steady_clock::time_point &_expiration) {
for (auto i = targets_.begin(); i != targets_.end(); i++) {
- if (i->endpoint_ == _target) {
- i->expiration_ = _expiration;
- return true;
- }
+ if (i->endpoint_->get_address() == _target->get_address() &&
+ i->endpoint_->get_port() == _target->get_port()) {
+ i->expiration_ = _expiration;
+ return true;
+ }
}
return false;
}
@@ -151,4 +156,12 @@ void eventgroupinfo::clear_targets() {
targets_.clear();
}
+uint8_t eventgroupinfo::get_threshold() const {
+ return threshold_;
+}
+
+void eventgroupinfo::set_threshold(uint8_t _threshold) {
+ threshold_ = _threshold;
+}
+
} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp
index 1a04a20..e146d65 100644
--- a/implementation/routing/src/routing_manager_base.cpp
+++ b/implementation/routing/src/routing_manager_base.cpp
@@ -11,6 +11,7 @@
#include "../../logging/include/logger.hpp"
#include "../../endpoints/include/local_client_endpoint_impl.hpp"
#include "../../endpoints/include/local_server_endpoint_impl.hpp"
+#include "../include/routing_manager_impl.hpp"
namespace vsomeip {
@@ -42,7 +43,7 @@ void routing_manager_base::init() {
serializer_->create_data(configuration_->get_max_message_size_local());
}
-void routing_manager_base::offer_service(client_t _client, service_t _service,
+bool routing_manager_base::offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor) {
(void)_client;
@@ -50,16 +51,20 @@ void routing_manager_base::offer_service(client_t _client, service_t _service,
// Remote route (incoming only)
auto its_info = find_service(_service, _instance);
if (its_info) {
- if (its_info->get_major() == _major
+ if (!its_info->is_local()) {
+ return false;
+ } else if (its_info->get_major() == _major
&& its_info->get_minor() == _minor) {
its_info->set_ttl(DEFAULT_TTL);
} else {
host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH);
+ return false;
}
} else {
its_info = create_service_info(_service, _instance, _major, _minor,
DEFAULT_TTL, true);
}
+ return true;
}
void routing_manager_base::stop_offer_service(client_t _client, service_t _service,
@@ -118,9 +123,10 @@ void routing_manager_base::release_service(client_t _client, service_t _service,
}
void routing_manager_base::register_event(client_t _client, service_t _service, instance_t _instance,
- event_t _event, const std::set<eventgroup_t> &_eventgroups,
- bool _is_field, bool _is_provided, bool _is_shadow,
- bool _is_cache_placeholder) {
+ event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle,
+ epsilon_change_func_t _epsilon_change_func,
+ bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) {
std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
if (its_event) {
if(!its_event->is_cache_placeholder()) {
@@ -163,6 +169,9 @@ void routing_manager_base::register_event(client_t _client, service_t _service,
its_event->set_eventgroups(_eventgroups);
}
+ its_event->set_epsilon_change_function(_epsilon_change_func);
+ its_event->set_change_resets_cycle(_change_resets_cycle);
+ its_event->set_update_cycle(_cycle);
}
} else {
its_event = std::make_shared<event>(this, _is_shadow);
@@ -184,6 +193,10 @@ void routing_manager_base::register_event(client_t _client, service_t _service,
} else {
its_event->set_eventgroups(_eventgroups);
}
+
+ its_event->set_epsilon_change_function(_epsilon_change_func);
+ its_event->set_change_resets_cycle(_change_resets_cycle);
+ its_event->set_update_cycle(_cycle);
}
if(!_is_cache_placeholder) {
@@ -312,10 +325,10 @@ void routing_manager_base::unsubscribe(client_t _client, service_t _service,
}
void routing_manager_base::notify(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload) {
+ event_t _event, std::shared_ptr<payload> _payload, bool _force) {
std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
if (its_event) {
- its_event->set_payload(_payload);
+ its_event->set_payload(_payload, _force);
} else {
VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
<< std::hex << _service << "." << _instance << "." << _event
@@ -324,7 +337,8 @@ void routing_manager_base::notify(service_t _service, instance_t _instance,
}
void routing_manager_base::notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload, client_t _client) {
+ event_t _event, std::shared_ptr<payload> _payload,
+ client_t _client, bool _force) {
std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
if (its_event) {
// Event is valid for service/instance
@@ -340,7 +354,7 @@ void routing_manager_base::notify_one(service_t _service, instance_t _instance,
}
}
if (found_eventgroup) {
- its_event->set_payload(_payload, _client);
+ its_event->set_payload(_payload, _client, _force);
}
} else {
VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
@@ -360,7 +374,7 @@ bool routing_manager_base::send(client_t its_client,
if (serializer_->serialize(_message.get())) {
is_sent = send(its_client, serializer_->get_data(),
serializer_->get_size(), _message->get_instance(),
- _flush, _message->is_reliable(), _message->is_initial());
+ _flush, _message->is_reliable());
serializer_->reset();
} else {
VSOMEIP_ERROR << "Failed to serialize message. Check message size!";
@@ -399,6 +413,9 @@ void routing_manager_base::clear_service_info(service_t _service, instance_t _in
if (!its_info) {
return;
}
+
+ std::lock_guard<std::mutex> its_lock(services_mutex_);
+
// Clear service_info and service_group
std::shared_ptr<endpoint> its_empty_endpoint;
if (!its_info->get_endpoint(!_reliable)) {
@@ -467,7 +484,7 @@ std::shared_ptr<endpoint> routing_manager_base::create_local(client_t _client) {
VSOMEIP_DEBUG << "Client [" << std::hex << get_client() << "] is connecting to ["
<< std::hex << _client << "] at " << its_path.str();
#endif
- std::shared_ptr<endpoint> its_endpoint = std::make_shared<
+ std::shared_ptr<local_client_endpoint_impl> its_endpoint = std::make_shared<
local_client_endpoint_impl>(shared_from_this(),
#ifdef WIN32
boost::asio::ip::tcp::endpoint(address, port)
@@ -482,7 +499,16 @@ std::shared_ptr<endpoint> routing_manager_base::create_local(client_t _client) {
// with VSOMEIP_ROUTING_CLIENT as parameter
// as it indicates remote communication!
- local_endpoints_[_client] = its_endpoint;
+ local_endpoints_[_client] = std::static_pointer_cast<endpoint>(its_endpoint);
+ if (routing_manager_impl *rm_impl = dynamic_cast<routing_manager_impl*>(this)) {
+ its_endpoint->register_error_callback(
+ std::bind(&routing_manager_impl::on_clientendpoint_error,
+ rm_impl, _client));
+ } else {
+ its_endpoint->register_error_callback(
+ std::bind(&routing_manager_base::on_clientendpoint_error, this,
+ _client));
+ }
}
return (its_endpoint);
@@ -637,6 +663,8 @@ std::shared_ptr<eventgroupinfo> routing_manager_base::find_eventgroup(
}
its_info->set_major(its_service_info->get_major());
its_info->set_ttl(its_service_info->get_ttl());
+ its_info->set_threshold(configuration_->get_threshold(
+ _service, _instance, _eventgroup));
}
}
}
@@ -673,9 +701,13 @@ std::set<client_t> routing_manager_base::find_local_clients(service_t _service,
return (its_clients);
}
-void routing_manager_base::send_local_notification(client_t _client,
+bool routing_manager_base::send_local_notification(client_t _client,
const byte_t *_data, uint32_t _size, instance_t _instance,
- bool _flush, bool _reliable, bool _initial) {
+ bool _flush, bool _reliable) {
+#ifdef USE_DLT
+ bool has_local(false);
+#endif
+ bool has_remote(false);
method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN],
_data[VSOMEIP_METHOD_POS_MAX]);
service_t its_service = VSOMEIP_BYTES_TO_WORD(
@@ -688,52 +720,46 @@ void routing_manager_base::send_local_notification(client_t _client,
// local
auto its_local_clients = find_local_clients(its_service, _instance, its_group);
for (auto its_local_client : its_local_clients) {
- // If we also want to receive the message, send it to the routing manager
- // We cannot call deliver_message in this case as this would end in receiving
- // an answer before the call to send has finished.
- if (its_local_client == host_->get_client()) {
- uint8_t *local_data = const_cast<uint8_t *>(_data);
- local_data[VSOMEIP_CLIENT_POS_MIN] = VSOMEIP_WORD_BYTE1(its_local_client);
- local_data[VSOMEIP_CLIENT_POS_MAX] = VSOMEIP_WORD_BYTE0(its_local_client);
- std::shared_ptr<endpoint> its_local_target = find_local(get_client());
- if (its_local_target) {
- send_local(its_local_target, _client, _data, _size,
- _instance, _flush, _reliable, VSOMEIP_SEND, true, _initial);
- }
- std::memset(&local_data[VSOMEIP_CLIENT_POS_MIN], 0, 2);
- } else {
- std::shared_ptr<endpoint> its_local_target = find_local(its_local_client);
- if (its_local_target) {
- send_local(its_local_target, _client, _data, _size,
- _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial);
- }
+ if (its_local_client == VSOMEIP_ROUTING_CLIENT) {
+ has_remote = true;
+ continue;
+ }
+#ifdef USE_DLT
+ else {
+ has_local = true;
+ }
+#endif
+ std::shared_ptr<endpoint> its_local_target = find_local(its_local_client);
+ if (its_local_target) {
+ send_local(its_local_target, _client, _data, _size,
+ _instance, _flush, _reliable, VSOMEIP_SEND);
}
}
}
}
+#ifdef USE_DLT
+ // Trace the message if a local client but will _not_ be forwarded to the routing manager
+ if (has_local && !has_remote) {
+ uint16_t its_data_size
+ = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
+
+ tc::trace_header its_header;
+ if (its_header.prepare(nullptr, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+ }
+#endif
+ return has_remote;
}
bool routing_manager_base::send_local(
std::shared_ptr<endpoint>& _target, client_t _client,
- const byte_t *_data, uint32_t _size,
- instance_t _instance,
- bool _flush, bool _reliable, uint8_t _command, bool _queue_message, bool _initial) const {
-
- std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
-
-#ifdef USE_DLT
- uint16_t its_data_size
- = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
-
- tc::trace_header its_header;
- if (its_header.prepare(_target, true))
- tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
- _data, its_data_size);
-#endif
+ const byte_t *_data, uint32_t _size, instance_t _instance,
+ bool _flush, bool _reliable, uint8_t _command) const {
std::vector<byte_t> its_command(
VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t)
- + sizeof(bool) + sizeof(bool) + sizeof(bool));
+ + sizeof(bool) + sizeof(bool));
its_command[VSOMEIP_COMMAND_TYPE_POS] = _command;
std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client,
sizeof(client_t));
@@ -747,15 +773,8 @@ bool routing_manager_base::send_local(
+ sizeof(instance_t)], &_flush, sizeof(bool));
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size
+ sizeof(instance_t) + sizeof(bool)], &_reliable, sizeof(bool));
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size
- + sizeof(instance_t) + sizeof(bool) + sizeof(bool)],
- &_initial, sizeof(bool));
- if (_queue_message) {
- return queue_message(&its_command[0], uint32_t(its_command.size()));
- } else {
- return _target->send(&its_command[0], uint32_t(its_command.size()));
- }
+ return _target->send(&its_command[0], uint32_t(its_command.size()));
}
bool routing_manager_base::insert_subscription(
@@ -779,4 +798,10 @@ bool routing_manager_base::insert_subscription(
return true;
}
+void routing_manager_base::on_clientendpoint_error(client_t _client) {
+ VSOMEIP_ERROR << "Client endpoint error for application: " << std::hex
+ << std::setfill('0') << std::setw(4) << _client;
+ remove_local(_client);
+}
+
} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp
index 3c98334..99c8c7d 100644
--- a/implementation/routing/src/routing_manager_impl.cpp
+++ b/implementation/routing/src/routing_manager_impl.cpp
@@ -7,6 +7,11 @@
#include <iomanip>
#include <memory>
#include <sstream>
+#include <forward_list>
+
+#ifndef WITHOUT_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
#include <vsomeip/constants.hpp>
#include <vsomeip/message.hpp>
@@ -41,7 +46,12 @@
namespace vsomeip {
routing_manager_impl::routing_manager_impl(routing_manager_host *_host) :
- routing_manager_base(_host) {
+ routing_manager_base(_host),
+ version_log_timer_(_host->get_io())
+#ifndef WITHOUT_SYSTEMD
+ , watchdog_timer_(_host->get_io())
+#endif
+{
}
routing_manager_impl::~routing_manager_impl() {
@@ -88,9 +98,29 @@ void routing_manager_impl::start() {
discovery_->start();
host_->on_state(state_type_e::ST_REGISTERED);
+
+ if (configuration_->log_version()) {
+ version_log_timer_.expires_from_now(
+ std::chrono::seconds(0));
+ version_log_timer_.async_wait(std::bind(&routing_manager_impl::log_version_timer_cbk,
+ this, std::placeholders::_1));
+ }
+
+#ifndef WITHOUT_SYSTEMD
+ watchdog_timer_.expires_from_now(std::chrono::seconds(0));
+ watchdog_timer_.async_wait(std::bind(&routing_manager_impl::watchdog_cbk,
+ this, std::placeholders::_1));
+#endif
}
void routing_manager_impl::stop() {
+ version_log_timer_.cancel();
+
+#ifndef WITHOUT_SYSTEMD
+ watchdog_timer_.cancel();
+ sd_notify(0, "STOPPING=1");
+#endif
+
host_->on_state(state_type_e::ST_DEREGISTERED);
if (discovery_)
@@ -104,16 +134,20 @@ void routing_manager_impl::stop() {
}
}
-void routing_manager_impl::offer_service(client_t _client, service_t _service,
+bool routing_manager_impl::offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor) {
std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance);
- {
- std::lock_guard<std::mutex> its_lock(local_services_mutex_);
- local_services_[_service][_instance] = std::make_tuple(_major, _minor, _client);
+ VSOMEIP_DEBUG << "OFFER("
+ << 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::dec << int(_major) << "." << std::dec << _minor << "]";
+
+ if(!handle_local_offer_service(_client, _service, _instance, _major, _minor)) {
+ return false;
}
- routing_manager_base::offer_service(_client, _service, _instance, _major, _minor);
init_service_info(_service, _instance, true);
{
@@ -136,20 +170,35 @@ void routing_manager_impl::offer_service(client_t _client, service_t _service,
stub_->on_offer_service(_client, _service, _instance, _major, _minor);
host_->on_availability(_service, _instance, true, _major, _minor);
+ return true;
}
void routing_manager_impl::stop_offer_service(client_t _client,
service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor) {
+
+ VSOMEIP_DEBUG << "STOP OFFER("
+ << 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::dec << int(_major) << "." << _minor << "]";
+
routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor);
- on_stop_offer_service(_service, _instance, _major, _minor);
+ on_stop_offer_service(_client, _service, _instance, _major, _minor);
stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor);
+ host_->on_availability(_service, _instance, false, _major, _minor);
}
void routing_manager_impl::request_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor,
bool _use_exclusive_proxy) {
+ VSOMEIP_DEBUG << "REQUEST("
+ << 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::dec << int(_major) << "." << std::dec << _minor << "]";
+
routing_manager_base::request_service(_client, _service, _instance, _major,
_minor, _use_exclusive_proxy);
@@ -159,10 +208,18 @@ void routing_manager_impl::request_service(client_t _client, service_t _service,
std::lock_guard<std::mutex> ist_lock(requested_services_mutex_);
requested_services_[_client][_service][_instance].insert({ _major, _minor });
}
- // Unknown service instance ~> tell SD to find it!
if (discovery_) {
- discovery_->request_service(_service, _instance, _major, _minor,
- DEFAULT_TTL);
+ if (!configuration_->is_local_service(_service, _instance)) {
+ // Non local service instance ~> tell SD to find it!
+ discovery_->request_service(_service, _instance, _major, _minor,
+ DEFAULT_TTL);
+ } else {
+ VSOMEIP_DEBUG << std::hex
+ << "Avoid trigger SD find-service message"
+ << " for local service/instance/major/minor: "
+ << _service << "/" << _instance << std::dec
+ << "/" << (uint32_t)_major << "/" << _minor;
+ }
}
} else {
if ((_major == its_info->get_major()
@@ -171,6 +228,11 @@ void routing_manager_impl::request_service(client_t _client, service_t _service,
|| DEFAULT_MINOR == its_info->get_minor()
|| _minor == ANY_MINOR)) {
if(!its_info->is_local()) {
+ {
+ std::lock_guard<std::mutex> ist_lock(requested_services_mutex_);
+ requested_services_[_client][_service][_instance].insert({ _major, _minor });
+ its_info->add_client(_client);
+ }
find_or_create_remote_client(_service, _instance, true, VSOMEIP_ROUTING_CLIENT);
if (_use_exclusive_proxy) {
std::shared_ptr<endpoint> its_endpoint = its_info->get_endpoint(true);
@@ -186,17 +248,53 @@ void routing_manager_impl::request_service(client_t _client, service_t _service,
std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
specific_endpoint_clients_[_service][_instance].insert(_client);
}
+
+ if (_client == get_client()) {
+ stub_->create_local_receiver();
+ }
}
void routing_manager_impl::release_service(client_t _client, service_t _service,
instance_t _instance) {
+
+ VSOMEIP_DEBUG << "RELEASE("
+ << 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 << "]";
+
routing_manager_base::release_service(_client, _service, _instance);
+
+ {
+ std::lock_guard<std::mutex> its_lock(requested_services_mutex_);
+ auto its_client = requested_services_.find(_client);
+ if (its_client != requested_services_.end()) {
+ auto its_service = its_client->second.find(_service);
+ if (its_service != its_client->second.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ its_service->second.erase(_instance);
+ }
+ }
+ }
+ }
+
std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
- if(its_info) {
+ if(its_info && !its_info->is_local()) {
if(!its_info->get_requesters_size()) {
if(discovery_) {
discovery_->release_service(_service, _instance);
}
+ clear_client_endpoints(_service, _instance, true);
+ clear_client_endpoints(_service, _instance, false);
+ clear_service_info(_service, _instance, true);
+ clear_service_info(_service, _instance, false);
+ clear_identified_clients(_service, _instance);
+ clear_identifying_clients( _service, _instance);
+ } else {
+ remove_identified_client(_service, _instance, _client);
+ remove_identifying_client(_service, _instance, _client);
+ remove_specific_client_endpoint(_service, _instance, _client, true);
+ remove_specific_client_endpoint(_service, _instance, _client, false);
}
} else {
if(discovery_) {
@@ -208,45 +306,71 @@ void routing_manager_impl::release_service(client_t _client, service_t _service,
void routing_manager_impl::subscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup, major_version_t _major,
subscription_type_e _subscription_type) {
+
+ VSOMEIP_DEBUG << "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 << ":"
+ << std::dec << (uint16_t)_major << "]";
+
if (get_client() == find_local_client(_service, _instance)) {
- if (!host_->on_subscription(_service, _instance, _eventgroup, _client, true)) {
- on_subscribe_nack(_client, _service, _instance, _eventgroup);
+ bool subscription_accepted = host_->on_subscription(_service, _instance, _eventgroup, _client, true);
+ (void) find_or_create_local(_client);
+ if (!subscription_accepted) {
+ stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup);
VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex
<< _client << std::dec << " for eventgroup: 0x" << _eventgroup
<< " rejected from application handler.";
return;
} else {
- on_subscribe_ack(_client, _service, _instance, _eventgroup);
+ stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup);
}
routing_manager_base::subscribe(_client, _service, _instance, _eventgroup, _major, _subscription_type);
} else {
if (discovery_) {
- bool inserted = insert_subscription(_service, _instance, _eventgroup, _client);
- if (inserted) {
- if (0 == find_local_client(_service, _instance)) {
- client_t subscriber = VSOMEIP_ROUTING_CLIENT;
- // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint
- {
- std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
- auto found_service = specific_endpoint_clients_.find(_service);
- if (found_service != specific_endpoint_clients_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- auto found_client = found_instance->second.find(_client);
- if(found_client != found_instance->second.end()) {
- subscriber = _client;
- if (supports_selective(_service, _instance)) {
- identify_for_subscribe(_client, _service, _instance, _major);
- } else {
- VSOMEIP_INFO << "Subcribe to legacy selective service: " << std::hex
- << _service << ":" << _instance << ".";
- }
+ client_t subscriber = VSOMEIP_ROUTING_CLIENT;
+ if (0 == find_local_client(_service, _instance)) {
+ // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint
+ bool identify(false);
+ {
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service = specific_endpoint_clients_.find(_service);
+ if (found_service != specific_endpoint_clients_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_client = found_instance->second.find(_client);
+ if(found_client != found_instance->second.end()) {
+ subscriber = _client;
+ if (supports_selective(_service, _instance)) {
+ identify = true;
+ } else {
+ VSOMEIP_INFO << "Subcribe to legacy selective service: " << std::hex
+ << _service << ":" << _instance << ".";
}
}
}
}
+ }
+ if(identify) {
+ identify_for_subscribe(_client, _service, _instance, _major);
+ }
+ }
+ bool inserted = insert_subscription(_service, _instance, _eventgroup, _client);
+ if (inserted) {
+ if (0 == find_local_client(_service, _instance)) {
+ static const ttl_t configured_ttl(configuration_->get_sd_ttl());
discovery_->subscribe(_service, _instance, _eventgroup,
- _major, DEFAULT_TTL, subscriber, _subscription_type);
+ _major, configured_ttl, subscriber, _subscription_type);
+ auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup);
+ if (its_eventgroup) {
+ std::set<std::shared_ptr<event> > its_events
+ = its_eventgroup->get_events();
+ for (auto e : its_events) {
+ if (e->is_field())
+ e->notify_one(_client);
+ }
+ }
} else {
stub_->send_subscribe(routing_manager_base::find_local(_service, _instance),
_client, _service, _instance, _eventgroup, _major, false);
@@ -260,6 +384,14 @@ void routing_manager_impl::subscribe(client_t _client, service_t _service,
void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup) {
+
+ VSOMEIP_DEBUG << "UNSUBSCRIBE("
+ << 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 << "]";
+
+ bool last_subscriber_removed(false);
if (discovery_) {
{
std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
@@ -272,6 +404,7 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
if (found_eventgroup != found_instance->second.end()) {
found_eventgroup->second.erase(_client);
if (0 == found_eventgroup->second.size()) {
+ last_subscriber_removed = true;
eventgroup_clients_.erase(_eventgroup);
}
}
@@ -295,10 +428,11 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
}
}
}
- discovery_->unsubscribe(_service, _instance, _eventgroup, subscriber);
+ if( last_subscriber_removed )
+ discovery_->unsubscribe(_service, _instance, _eventgroup, subscriber);
} else {
stub_->send_unsubscribe(routing_manager_base::find_local(_service, _instance),
- _client, _service, _instance, _eventgroup);
+ _client, _service, _instance, _eventgroup, false);
}
clear_multicast_endpoints(_service, _instance);
} else {
@@ -308,12 +442,12 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
bool routing_manager_impl::send(client_t _client,
std::shared_ptr<message> _message, bool _flush) {
- return routing_manager_base::send(_client, _message, _flush);
+ return routing_manager_base::send(_client, _message, _flush);
}
bool routing_manager_impl::send(client_t _client, const byte_t *_data,
length_t _size, instance_t _instance,
- bool _flush, bool _reliable, bool _initial) {
+ bool _flush, bool _reliable) {
bool is_sent(false);
std::shared_ptr<endpoint> its_target;
@@ -345,7 +479,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
}
if (its_target) {
- is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial);
+ is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, VSOMEIP_SEND);
} else {
// Check whether hosting application should get the message
// If not, check routes to external
@@ -394,8 +528,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
_data[VSOMEIP_METHOD_POS_MAX]);
std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method);
if (its_event) {
+#ifdef USE_DLT
+ bool has_sent(false);
+#endif
std::vector< byte_t > its_data;
-
for (auto its_group : its_event->get_eventgroups()) {
// we need both endpoints as clients can subscribe to events via TCP and UDP
std::shared_ptr<endpoint> its_unreliable_target = its_info->get_endpoint(false);
@@ -404,45 +540,44 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
// remote
auto its_eventgroup = find_eventgroup(its_service, _instance, its_group);
if (its_eventgroup) {
- //Unicast targets
+ // Unicast targets
for (auto its_remote : its_eventgroup->get_targets()) {
if(its_remote.endpoint_->is_reliable() && its_reliable_target) {
-#ifdef USE_DLT
- uint16_t its_data_size
- = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
-
- tc::trace_header its_header;
- if (its_header.prepare(its_reliable_target, true))
- tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
- _data, its_data_size);
-#endif
its_reliable_target->send_to(its_remote.endpoint_, _data, _size);
- } else if(its_unreliable_target && !its_eventgroup->is_multicast()) {
-#ifdef USE_DLT
- uint16_t its_data_size
- = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
-
- tc::trace_header its_header;
- if (its_header.prepare(its_reliable_target, true))
- tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
- _data, its_data_size);
-#endif
+ } else if (its_unreliable_target && !its_eventgroup->is_sending_multicast()) {
its_unreliable_target->send_to(its_remote.endpoint_, _data, _size);
}
+#ifdef USE_DLT
+ has_sent = true;
+#endif
}
- //send to multicast targets if subscribers are still interested
- if(its_eventgroup->is_multicast()
- && its_eventgroup->get_unreliable_target_count() > 0 ) {
+ // Send to multicast targets if subscribers are still interested
+ if (its_eventgroup->is_sending_multicast()) {
for (auto its_multicast_target : its_eventgroup->get_multicast_targets()) {
its_unreliable_target->send_to(its_multicast_target.endpoint_, _data, _size);
+#ifdef USE_DLT
+ has_sent = true;
+#endif
}
}
+#ifdef USE_DLT
+ if (has_sent) {
+ uint16_t its_data_size
+ = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
+
+ tc::trace_header its_header;
+ if (its_header.prepare(nullptr, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+ }
+#endif
}
}
}
}
} else {
- its_target = is_service_discovery ? sd_info_->get_endpoint(false) : its_info->get_endpoint(_reliable);
+ its_target = is_service_discovery ?
+ (sd_info_ ? sd_info_->get_endpoint(false) : nullptr) : its_info->get_endpoint(_reliable);
if (its_target) {
#ifdef USE_DLT
uint16_t its_data_size
@@ -496,7 +631,6 @@ bool routing_manager_impl::send_to(
std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(
_target->get_remote_port(), _target->is_reliable());
-
if (its_endpoint) {
#ifdef USE_DLT
uint16_t its_data_size
@@ -538,7 +672,10 @@ void routing_manager_impl::register_shadow_event(client_t _client,
event_t _event, const std::set<eventgroup_t> &_eventgroups,
bool _is_field, bool _is_provided) {
routing_manager_base::register_event(_client, _service, _instance,
- _event, _eventgroups, _is_field, _is_provided, true);
+ _event, _eventgroups, _is_field,
+ std::chrono::milliseconds::zero(), false,
+ nullptr,
+ _is_provided, true);
}
void routing_manager_impl::unregister_shadow_event(client_t _client,
@@ -550,10 +687,10 @@ void routing_manager_impl::unregister_shadow_event(client_t _client,
void routing_manager_impl::notify(
service_t _service, instance_t _instance, event_t _event,
- std::shared_ptr<payload> _payload) {
+ std::shared_ptr<payload> _payload, bool _force) {
std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
if (its_event) {
- its_event->set_payload(_payload);
+ its_event->set_payload(_payload, _force);
} else {
VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
<< std::hex << _service << "." << _instance << "." << _event
@@ -562,47 +699,49 @@ void routing_manager_impl::notify(
}
void routing_manager_impl::notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload, client_t _client) {
- if (find_local(_client)) {
- routing_manager_base::notify_one(_service, _instance, _event, _payload,
- _client);
- } else {
- std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
- if (its_event) {
- // Event is valid for service/instance
- bool found_eventgroup(false);
- // Iterate over all groups of the event to ensure at least
- // one valid eventgroup for service/instance exists.
- for (auto its_group : its_event->get_eventgroups()) {
- auto its_eventgroup = find_eventgroup(_service, _instance, its_group);
- if (its_eventgroup) {
- // Eventgroup is valid for service/instance
- found_eventgroup = true;
- break;
- }
- }
- if (found_eventgroup) {
- // Now set event's payload!
- // Either with endpoint_definition (remote) or with client (local).
- auto its_service = remote_subscribers_.find(_service);
- if (its_service != remote_subscribers_.end()) {
- auto its_instance = its_service->second.find(_instance);
- if (its_instance != its_service->second.end()) {
- auto its_subscriber = its_instance->second.find(_client);
- if (its_subscriber != its_instance->second.end()) {
- for (auto its_target : its_subscriber->second) {
- its_event->set_payload(_payload, its_target);
- }
- }
- }
- }
- }
- } else {
- VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
- << std::hex << _service << "." << _instance << "." << _event
- << "]";
- }
- }
+ event_t _event, std::shared_ptr<payload> _payload, client_t _client,
+ bool _force) {
+ if (find_local(_client)) {
+ routing_manager_base::notify_one(_service, _instance, _event, _payload,
+ _client, _force);
+ } else {
+ std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
+ if (its_event) {
+ // Event is valid for service/instance
+ bool found_eventgroup(false);
+ // Iterate over all groups of the event to ensure at least
+ // one valid eventgroup for service/instance exists.
+ for (auto its_group : its_event->get_eventgroups()) {
+ auto its_eventgroup = find_eventgroup(_service, _instance, its_group);
+ if (its_eventgroup) {
+ // Eventgroup is valid for service/instance
+ found_eventgroup = true;
+ break;
+ }
+ }
+ if (found_eventgroup) {
+ // Now set event's payload!
+ // Either with endpoint_definition (remote) or with client (local).
+ std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_);
+ auto its_service = remote_subscribers_.find(_service);
+ if (its_service != remote_subscribers_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ auto its_subscriber = its_instance->second.find(_client);
+ if (its_subscriber != its_instance->second.end()) {
+ for (auto its_target : its_subscriber->second) {
+ its_event->set_payload(_payload, its_target, _force);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
+ << std::hex << _service << "." << _instance << "." << _event
+ << "]";
+ }
+ }
}
void routing_manager_impl::on_error(const byte_t *_data, length_t _length, endpoint *_receiver) {
@@ -617,7 +756,7 @@ void routing_manager_impl::on_error(const byte_t *_data, length_t _length, endpo
}
void routing_manager_impl::release_port(uint16_t _port, bool _reliable) {
- used_client_ports_[_reliable].erase(_port);
+ used_client_ports_[_reliable].erase(_port);
}
void routing_manager_impl::on_message(const byte_t *_data, length_t _size,
@@ -652,6 +791,13 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size,
}
} else {
instance_t its_instance = find_instance(its_service, _receiver);
+ //Ignore messages with invalid message type
+ if(_size >= VSOMEIP_MESSAGE_TYPE_POS) {
+ if(!utility::is_valid_message_type(static_cast<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]))) {
+ VSOMEIP_ERROR << "Ignored SomeIP message with invalid message type.";
+ return;
+ }
+ }
return_code_e return_code = check_error(_data, _size, its_instance);
if(!(_size >= VSOMEIP_MESSAGE_TYPE_POS && utility::is_request_no_return(_data[VSOMEIP_MESSAGE_TYPE_POS]))) {
if (return_code != return_code_e::E_OK && return_code != return_code_e::E_NOT_OK) {
@@ -736,46 +882,78 @@ void routing_manager_impl::on_notification(client_t _client,
&_data[VSOMEIP_PAYLOAD_POS],
its_length);
- if (!_notify_one) {
- its_event->set_payload(its_payload);
+ if (_notify_one) {
+ notify_one(_service, _instance, its_event->get_event(), its_payload, _client, true);
} else {
- notify_one(_service, _instance, its_event->get_event(), its_payload, _client);
+ if (its_event->is_field()) {
+ if (its_event->is_set()) {
+ its_event->set_payload(its_payload);
+ } else {
+ // Set payload first time ~> notify all remote subscriber per unicast (inital field)
+ for (auto its_group : its_event->get_eventgroups()) {
+ auto its_eventgroup = find_eventgroup(_service, _instance, its_group);
+ if (its_eventgroup) {
+ //Unicast targets
+ for (auto its_remote : its_eventgroup->get_targets()) {
+ its_event->set_payload(its_payload, its_remote.endpoint_, true);
+ }
+ }
+ }
+ }
+ } else {
+ its_event->set_payload(its_payload);
+ }
}
}
}
void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) {
- // Is called when endpoint->connect succeded!
- for (auto &its_service : remote_services_) {
- for (auto &its_instance : its_service.second) {
- for (auto &its_client : its_instance.second) {
- if (its_client.first == VSOMEIP_ROUTING_CLIENT ||
- its_client.first == get_client()) {
- auto found_endpoint = its_client.second.find(false);
- if (found_endpoint != its_client.second.end()) {
- if (found_endpoint->second.get() == _endpoint.get()) {
- std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first));
- if(!its_info) {
- return;
+ // Is called when endpoint->connect succeeded!
+ struct service_info {
+ service_t service_id_;
+ instance_t instance_id_;
+ major_version_t major_;
+ minor_version_t minor_;
+ bool reliable_;
+ std::shared_ptr<endpoint> endpoint_;
+ };
+ std::forward_list<struct service_info> services_to_report_;
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
+ for (auto &its_service : remote_services_) {
+ for (auto &its_instance : its_service.second) {
+ for (auto &its_client : its_instance.second) {
+ if (its_client.first == VSOMEIP_ROUTING_CLIENT ||
+ its_client.first == get_client()) {
+ auto found_endpoint = its_client.second.find(false);
+ if (found_endpoint != its_client.second.end()) {
+ if (found_endpoint->second.get() == _endpoint.get()) {
+ std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first));
+ if (!its_info) {
+ return;
+ }
+ services_to_report_.push_front(
+ { its_service.first,
+ its_instance.first,
+ its_info->get_major(),
+ its_info->get_minor(),
+ false, nullptr });
}
- host_->on_availability(its_service.first, its_instance.first,
- true, its_info->get_major(), its_info->get_minor());
}
- }
- found_endpoint = its_client.second.find(true);
- if (found_endpoint != its_client.second.end()) {
- if (found_endpoint->second.get() == _endpoint.get()) {
- std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first));
- if(!its_info){
- return;
- }
- host_->on_availability(its_service.first, its_instance.first,
- true, its_info->get_major(), its_info->get_minor());
- stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT,
- its_service.first, its_instance.first, its_info->get_major(), its_info->get_minor());
- if(discovery_) {
- discovery_->on_reliable_endpoint_connected(its_service.first, its_instance.first, _endpoint);
+ found_endpoint = its_client.second.find(true);
+ if (found_endpoint != its_client.second.end()) {
+ if (found_endpoint->second.get() == _endpoint.get()) {
+ std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first));
+ if (!its_info) {
+ return;
+ }
+ services_to_report_.push_front(
+ { its_service.first,
+ its_instance.first,
+ its_info->get_major(),
+ its_info->get_minor(),
+ true, _endpoint });
}
}
}
@@ -783,10 +961,23 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) {
}
}
}
+ for (const auto &s : services_to_report_) {
+ host_->on_availability(s.service_id_, s.instance_id_, true, s.major_,
+ s.minor_);
+ if (s.reliable_) {
+ stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, s.service_id_,
+ s.instance_id_, s.major_, s.minor_);
+ if (discovery_) {
+ discovery_->on_reliable_endpoint_connected(s.service_id_,
+ s.instance_id_, s.endpoint_);
+ }
+ }
+ }
}
void routing_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) {
// Is called when endpoint->connect fails!
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
for (auto &its_service : remote_services_) {
for (auto &its_instance : its_service.second) {
for (auto &its_client : its_instance.second) {
@@ -822,9 +1013,43 @@ void routing_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) {
}
}
-void routing_manager_impl::on_stop_offer_service(service_t _service,
+void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor) {
-
+ {
+ std::lock_guard<std::mutex> its_lock(local_services_mutex_);
+ auto found_service = local_services_.find(_service);
+ if (found_service != local_services_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ if ( std::get<0>(found_instance->second) != _major
+ || std::get<1>(found_instance->second) != _minor
+ || std::get<2>(found_instance->second) != _client) {
+ VSOMEIP_WARNING
+ << "routing_manager_impl::on_stop_offer_service: "
+ << "trying to delete service not matching exactly "
+ << "the one offered previously: " << "[" << std::hex
+ << std::setw(4) << std::setfill('0') << _service
+ << "." << _instance << "." << std::dec
+ << static_cast<std::uint32_t>(_major)
+ << "." << _minor << "] by application: "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << _client << ". Stored: [" << std::hex
+ << std::setw(4) << std::setfill('0') << _service
+ << "." << _instance << "." << std::dec
+ << static_cast<std::uint32_t>(std::get<0>(found_instance->second)) << "."
+ << std::get<1>(found_instance->second)
+ << "] by application: " << std::hex << std::setw(4)
+ << std::setfill('0') << std::get<2>(found_instance->second);
+ }
+ if (std::get<2>(found_instance->second) == _client) {
+ found_service->second.erase(_instance);
+ if (found_service->second.size() == 0) {
+ local_services_.erase(_service);
+ }
+ }
+ }
+ }
+ }
{
std::lock_guard<std::mutex> its_lock(events_mutex_);
auto its_events_service = events_.find(_service);
@@ -960,7 +1185,7 @@ bool routing_manager_impl::deliver_notification(
if (its_event) {
std::vector< byte_t > its_data;
std::set<client_t> its_local_client_set;
- if(its_event->is_field() && !its_event->is_shadow()) {
+ if(its_event->is_field() && !its_event->is_provided()) {
// store the current value of the remote field
const uint32_t its_length(utility::get_payload_size(_data, _length));
std::shared_ptr<payload> its_payload =
@@ -1072,6 +1297,7 @@ void routing_manager_impl::init_service_info(
if (its_reliable_endpoint) {
its_info->set_endpoint(its_reliable_endpoint, true);
its_reliable_endpoint->increment_use_count();
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
service_instances_[_service][its_reliable_endpoint.get()] =
_instance;
}
@@ -1083,6 +1309,7 @@ void routing_manager_impl::init_service_info(
if (its_unreliable_endpoint) {
its_info->set_endpoint(its_unreliable_endpoint, false);
its_unreliable_endpoint->increment_use_count();
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
service_instances_[_service][its_unreliable_endpoint.get()] =
_instance;
}
@@ -1229,6 +1456,22 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_local(
void routing_manager_impl::remove_local(client_t _client) {
routing_manager_base::remove_local(_client);
+ std::forward_list<std::pair<service_t, instance_t>> services_to_release_;
+ {
+ std::lock_guard<std::mutex> its_lock(requested_services_mutex_);
+ auto its_client = requested_services_.find(_client);
+ if (its_client != requested_services_.end()) {
+ for (auto its_service : its_client->second) {
+ for (auto its_instance : its_service.second) {
+ services_to_release_.push_front(
+ { its_service.first, its_instance.first });
+ }
+ }
+ }
+ }
+ for (const auto &s : services_to_release_) {
+ release_service(_client, s.first, s.second);
+ }
}
instance_t routing_manager_impl::find_instance(service_t _service,
@@ -1251,39 +1494,39 @@ std::shared_ptr<endpoint> routing_manager_impl::create_remote_client(
uint16_t its_local_port;
if (configuration_->get_client_port(_service, _instance, _reliable,
- used_client_ports_, its_local_port)) {
- auto found_service = remote_service_info_.find(_service);
- if (found_service != remote_service_info_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- auto found_reliability = found_instance->second.find(_reliable);
- if (found_reliability != found_instance->second.end()) {
- its_endpoint_def = found_reliability->second;
- its_endpoint = create_client_endpoint(
- its_endpoint_def->get_address(),
- its_local_port,
- its_endpoint_def->get_port(),
- _reliable, _client,
- configuration_->is_someip(_service, _instance)
- );
- }
- }
- }
- if (its_endpoint) {
- used_client_ports_[_reliable].insert(its_local_port);
- service_instances_[_service][its_endpoint.get()] = _instance;
- remote_services_[_service][_instance][_client][_reliable] = its_endpoint;
- if (_client == VSOMEIP_ROUTING_CLIENT) {
- client_endpoints_by_ip_[its_endpoint_def->get_address()]
- [its_endpoint_def->get_port()]
- [_reliable] = its_endpoint;
- // Set the basic route to the service in the service info
- auto found_service_info = find_service(_service, _instance);
- if (found_service_info) {
- found_service_info->set_endpoint(its_endpoint, _reliable);
- }
- }
- }
+ used_client_ports_, its_local_port)) {
+ auto found_service = remote_service_info_.find(_service);
+ if (found_service != remote_service_info_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_reliability = found_instance->second.find(_reliable);
+ if (found_reliability != found_instance->second.end()) {
+ its_endpoint_def = found_reliability->second;
+ its_endpoint = create_client_endpoint(
+ its_endpoint_def->get_address(),
+ its_local_port,
+ its_endpoint_def->get_port(),
+ _reliable, _client,
+ configuration_->is_someip(_service, _instance)
+ );
+ }
+ }
+ }
+ if (its_endpoint) {
+ used_client_ports_[_reliable].insert(its_local_port);
+ service_instances_[_service][its_endpoint.get()] = _instance;
+ remote_services_[_service][_instance][_client][_reliable] = its_endpoint;
+ if (_client == VSOMEIP_ROUTING_CLIENT) {
+ client_endpoints_by_ip_[its_endpoint_def->get_address()]
+ [its_endpoint_def->get_port()]
+ [_reliable] = its_endpoint;
+ // Set the basic route to the service in the service info
+ auto found_service_info = find_service(_service, _instance);
+ if (found_service_info) {
+ found_service_info->set_endpoint(its_endpoint, _reliable);
+ }
+ }
+ }
}
return its_endpoint;
}
@@ -1383,7 +1626,7 @@ bool routing_manager_impl::is_field(service_t _service, instance_t _instance,
return false;
}
-void routing_manager_impl::add_routing_info(
+std::chrono::milliseconds routing_manager_impl::add_routing_info(
service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor, ttl_t _ttl,
const boost::asio::ip::address &_reliable_address,
@@ -1391,6 +1634,37 @@ void routing_manager_impl::add_routing_info(
const boost::asio::ip::address &_unreliable_address,
uint16_t _unreliable_port) {
+ std::chrono::seconds default_ttl(DEFAULT_TTL);
+ std::chrono::milliseconds its_smallest_ttl =
+ std::chrono::duration_cast<std::chrono::milliseconds>(default_ttl);
+ std::chrono::milliseconds its_ttl(std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::seconds(_ttl)));
+
+ bool offer_exists(false);
+ for (auto &s : get_services()) {
+ for (auto &i : s.second) {
+ if (i.second->is_local()) {
+ continue; //ignore local services
+ }
+ std::chrono::milliseconds its_found_ttl(i.second->get_precise_ttl());
+ if ( its_found_ttl < its_smallest_ttl ) {
+ its_smallest_ttl = its_found_ttl;
+ if( its_ttl < its_smallest_ttl ) {
+ its_smallest_ttl = its_ttl;
+ }
+ }
+ offer_exists = true;
+ }
+ }
+ //if no remote service is in the list yet
+ if( !offer_exists ) {
+ if( its_ttl < its_smallest_ttl ) {
+ // set smallest TTL to TTL of first incoming remote offer
+ // this allows expiration of service if no further offer message is received which would trigger update_routing info
+ its_smallest_ttl = its_ttl;
+ }
+ }
+
// Create/Update service info
std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
if (!its_info) {
@@ -1406,6 +1680,23 @@ void routing_manager_impl::add_routing_info(
its_info = create_service_info(_service, _instance, _major, _minor, _ttl, is_local);
init_service_info(_service, _instance, is_local);
+ } else if (its_info->is_local()) {
+ // We received a service info for a service which is already offered locally
+ VSOMEIP_ERROR << "routing_manager_impl::add_routing_info: "
+ << "rejecting routing info. Remote: "
+ << ((_reliable_port != ILLEGAL_PORT) ? _reliable_address.to_string()
+ : _unreliable_address.to_string()) << " is trying to offer ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor
+ << "] on port " << ((_reliable_port != ILLEGAL_PORT) ? _reliable_port
+ : _unreliable_port) << " offered previously on this node: ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(its_info->get_major())
+ << "." << its_info->get_minor() << "]";
+ return its_smallest_ttl;
} else {
its_info->set_ttl(_ttl);
}
@@ -1427,7 +1718,15 @@ void routing_manager_impl::add_routing_info(
&& its_definition->get_port() == _reliable_port) {
is_reliable_known = true;
} else {
- VSOMEIP_WARNING << "Reliable service endpoint has changed!";
+ VSOMEIP_WARNING << "Reliable service endpoint has changed: ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor << "] old: "
+ << its_definition->get_address().to_string() << ":"
+ << its_definition->get_port() << " new: "
+ << _reliable_address.to_string() << ":"
+ << _reliable_port;
}
}
}
@@ -1439,7 +1738,15 @@ void routing_manager_impl::add_routing_info(
&& its_definition->get_port() == _unreliable_port) {
is_unreliable_known = true;
} else {
- VSOMEIP_WARNING << "Unreliable service endpoint has changed!";
+ VSOMEIP_WARNING << "Unreliable service endpoint has changed: ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor << "] old: "
+ << its_definition->get_address().to_string() << ":"
+ << its_definition->get_port() << " new: "
+ << _unreliable_address.to_string() << ":"
+ << _unreliable_port;
}
}
}
@@ -1447,12 +1754,10 @@ void routing_manager_impl::add_routing_info(
}
// Add endpoint(s) if necessary
- bool is_added(false);
if (_reliable_port != ILLEGAL_PORT && !is_reliable_known) {
std::shared_ptr<endpoint_definition> endpoint_def
= endpoint_definition::get(_reliable_address, _reliable_port, true);
remote_service_info_[_service][_instance][true] = endpoint_def;
- is_added = !is_unreliable_known;
// check if service was requested and establish TCP connection if necessary
{
@@ -1495,19 +1800,54 @@ void routing_manager_impl::add_routing_info(
}
}
}
+ } else if (_reliable_port != ILLEGAL_PORT && is_reliable_known) {
+ std::lock_guard<std::mutex> its_lock(requested_services_mutex_);
+ for(const auto &client_id : requested_services_) {
+ auto found_service = client_id.second.find(_service);
+ if (found_service != client_id.second.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ for (const auto &major_minor_pair : found_instance->second) {
+ if ((major_minor_pair.first == _major
+ || _major == DEFAULT_MAJOR)
+ && (major_minor_pair.second <= _minor
+ || _minor == DEFAULT_MINOR
+ || major_minor_pair.second == ANY_MINOR)) {
+ host_->on_availability(_service, _instance,
+ true, its_info->get_major(), its_info->get_minor());
+ if (!stub_->contained_in_routing_info(
+ VSOMEIP_ROUTING_CLIENT, _service, _instance,
+ its_info->get_major(),
+ its_info->get_minor())) {
+ stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT,
+ _service, _instance,
+ its_info->get_major(),
+ its_info->get_minor());
+ if (discovery_) {
+ discovery_->on_reliable_endpoint_connected(
+ _service, _instance,
+ its_info->get_endpoint(true));
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
}
if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) {
std::shared_ptr<endpoint_definition> endpoint_def
= endpoint_definition::get(_unreliable_address, _unreliable_port, false);
remote_service_info_[_service][_instance][false] = endpoint_def;
- is_added = !is_reliable_known;
- if (is_added) {
+ if (!is_reliable_known) {
host_->on_availability(_service, _instance, true, _major, _minor);
stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor);
}
}
+ return its_smallest_ttl;
}
void routing_manager_impl::del_routing_info(service_t _service, instance_t _instance,
@@ -1519,7 +1859,6 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst
host_->on_availability(_service, _instance, false, its_info->get_major(), its_info->get_minor());
stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, its_info->get_major(), its_info->get_minor());
-
// Implicit unsubscribe
{
std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
@@ -1533,28 +1872,29 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst
}
}
}
+
+ clear_identified_clients( _service, _instance);
+ clear_identifying_clients( _service, _instance);
+
{
- std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
- auto its_service = identified_clients_.find(_service);
- if (its_service != identified_clients_.end()) {
- auto found_instance = its_service->second.find(_instance);
- if (found_instance != its_service->second.end()) {
- auto found_reliable = found_instance->second.find(true);
- if (found_reliable != found_instance->second.end()) {
- found_reliable->second.clear();
- }
- auto found_unreliable = found_instance->second.find(false);
- if (found_unreliable != found_instance->second.end()) {
- found_unreliable->second.clear();
- }
+ std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_);
+ auto found_service = remote_subscribers_.find(_service);
+ if (found_service != remote_subscribers_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ found_instance->second.clear();
}
}
}
- if (_has_reliable)
+ if (_has_reliable) {
clear_client_endpoints(_service, _instance, true);
- if (_has_unreliable)
+ clear_remote_service_info(_service, _instance, true);
+ }
+ if (_has_unreliable) {
clear_client_endpoints(_service, _instance, false);
+ clear_remote_service_info(_service, _instance, false);
+ }
clear_multicast_endpoints(_service, _instance);
@@ -1562,6 +1902,14 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst
clear_service_info(_service, _instance, true);
if (_has_unreliable)
clear_service_info(_service, _instance, false);
+
+ // For expired services using only unreliable endpoints that have never been created before
+ if (!_has_reliable && !_has_unreliable) {
+ clear_remote_service_info(_service, _instance, true);
+ clear_remote_service_info(_service, _instance, false);
+ clear_service_info(_service, _instance, true);
+ clear_service_info(_service, _instance, false);
+ }
}
std::chrono::milliseconds routing_manager_impl::update_routing_info(std::chrono::milliseconds _elapsed) {
@@ -1574,7 +1922,7 @@ std::chrono::milliseconds routing_manager_impl::update_routing_info(std::chrono:
for (auto &s : get_services()) {
for (auto &i : s.second) {
- if (routing_manager_base::find_local(s.first, i.first)) {
+ if (routing_manager_base::find_local_client(s.first, i.first) != VSOMEIP_ROUTING_CLIENT) {
continue; //don't expire local services
}
ttl_t its_ttl = i.second->get_ttl();
@@ -1600,6 +1948,8 @@ std::chrono::milliseconds routing_manager_impl::update_routing_info(std::chrono:
for (auto &s : its_expired_offers) {
for (auto &i : s.second) {
+ VSOMEIP_DEBUG << "update_routing_info: elapsed=" << _elapsed.count()
+ << " : delete service/instance " << std::hex << s.first << "/" << i.first;
del_routing_info(s.first, i.first, i.second.first, i.second.second);
}
}
@@ -1614,7 +1964,7 @@ void routing_manager_impl::expire_services(const boost::asio::ip::address &_addr
for (auto &s : get_services()) {
for (auto &i : s.second) {
- if (routing_manager_base::find_local(s.first, i.first)) {
+ if (routing_manager_base::find_local_client(s.first, i.first) != VSOMEIP_ROUTING_CLIENT) {
continue; //don't expire local services
}
bool is_gone(false);
@@ -1646,6 +1996,8 @@ void routing_manager_impl::expire_services(const boost::asio::ip::address &_addr
for (auto &s : its_expired_offers) {
for (auto &i : s.second) {
+ VSOMEIP_DEBUG << "expire_services for address: " << _address.to_string()
+ << " : delete service/instance " << std::hex << s.first << "/" << i.first;
del_routing_info(s.first, i.first, i.second.first, i.second.second);
}
}
@@ -1664,8 +2016,13 @@ void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address &
for (auto &its_endpoint : its_invalid_endpoints) {
its_eventgroup.second->remove_target(its_endpoint);
+ auto target = routing_manager_base::find_local(its_service.first, its_instance.first);
+ if (target) {
+ stub_->send_unsubscribe(target, VSOMEIP_ROUTING_CLIENT, its_service.first,
+ its_instance.first, its_eventgroup.first, true);
+ }
}
- if(its_eventgroup.second->is_multicast() &&
+ if(its_eventgroup.second->is_multicast() && its_invalid_endpoints.size() &&
0 == its_eventgroup.second->get_unreliable_target_count() ) {
//clear multicast targets if no subscriber is left for multicast eventgroup
its_eventgroup.second->clear_multicast_targets();
@@ -1706,7 +2063,7 @@ void routing_manager_impl::init_routing_info() {
bool routing_manager_impl::on_subscribe_accepted(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, const std::shared_ptr<endpoint_definition> _target,
- const std::chrono::high_resolution_clock::time_point &_expiration) {
+ const std::chrono::steady_clock::time_point &_expiration) {
std::shared_ptr<eventgroupinfo> its_eventgroup
= find_eventgroup(_service, _instance, _eventgroup);
if (its_eventgroup) {
@@ -1759,8 +2116,10 @@ bool routing_manager_impl::on_subscribe_accepted(service_t _service, instance_t
stub_->send_subscribe(routing_manager_base::find_local(_service, _instance),
client, _service, _instance, _eventgroup, its_eventgroup->get_major(), true);
-
- remote_subscribers_[_service][_instance][client].insert(_target);
+ {
+ std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_);
+ remote_subscribers_[_service][_instance][client].insert(_target);
+ }
} else {
VSOMEIP_ERROR<< "subscribe: attempt to subscribe to unknown eventgroup!";
return false;
@@ -1772,14 +2131,14 @@ void routing_manager_impl::on_subscribe(
service_t _service, instance_t _instance, eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _subscriber,
std::shared_ptr<endpoint_definition> _target,
- const std::chrono::high_resolution_clock::time_point &_expiration) {
+ const std::chrono::steady_clock::time_point &_expiration) {
std::shared_ptr<eventgroupinfo> its_eventgroup
= find_eventgroup(_service, _instance, _eventgroup);
if (its_eventgroup) {
// IP address of target is a multicast address if the event is in a multicast eventgroup
bool target_added(false);
- if( its_eventgroup->is_multicast() && !_subscriber->is_reliable()) {
+ if (its_eventgroup->is_multicast() && !_subscriber->is_reliable()) {
// Event is in multicast eventgroup and subscribe for UDP
target_added = its_eventgroup->add_target({ _target, _expiration }, {_subscriber, _expiration});
@@ -1797,9 +2156,9 @@ void routing_manager_impl::on_subscribe(
}
if (target_added) { // unicast or multicast
- // send initial events
+ // send initial events if we already have a cached field (is_set)
for (auto its_event : its_eventgroup->get_events()) {
- if (its_event->is_field()) {
+ if (its_event->is_field() && its_event->is_set()) {
its_event->notify_one(_subscriber); // unicast
}
}
@@ -1830,10 +2189,20 @@ void routing_manager_impl::on_unsubscribe(service_t _service,
clear_remote_subscriber(_service, _instance, its_client, _target);
stub_->send_unsubscribe(routing_manager_base::find_local(_service, _instance),
- its_client, _service, _instance, _eventgroup);
+ its_client, _service, _instance, _eventgroup, true);
host_->on_subscription(_service, _instance, _eventgroup, its_client, false);
+ if (its_eventgroup->get_targets().size() == 0) {
+ std::set<std::shared_ptr<event> > its_events
+ = its_eventgroup->get_events();
+ for (auto e : its_events) {
+ if (e->is_shadow()) {
+ e->unset_payload();
+ }
+ }
+ }
+
} else {
VSOMEIP_ERROR<<"unsubscribe: attempt to subscribe to unknown eventgroup!";
}
@@ -1924,6 +2293,7 @@ void routing_manager_impl::on_subscribe_nack(client_t _client,
bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service,
instance_t _instance, const byte_t *_data, length_t _size, endpoint *_receiver) {
// Try to deliver specific endpoint message (for selective subscribers)
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
auto found_servic = remote_services_.find(_service);
if (found_servic != remote_services_.end()) {
auto found_instance = found_servic->second.find(_instance);
@@ -2011,21 +2381,8 @@ void routing_manager_impl::clear_client_endpoints(service_t _service, instance_t
}
}
}
- // Clear remote_service_info_
- if (remote_service_info_.find(_service) != remote_service_info_.end()) {
- if (remote_service_info_[_service].find(_instance) != remote_service_info_[_service].end()) {
- remote_service_info_[_service][_instance].erase(_reliable);
- auto found_endpoint_def = remote_service_info_[_service][_instance].find(!_reliable);
- if (found_endpoint_def == remote_service_info_[_service][_instance].end()) {
- remote_service_info_[_service].erase(_instance);
- if (0 >= remote_service_info_[_service].size()) {
- remote_service_info_.erase(_service);
- }
- }
- }
- }
- if (1 >= service_instances_[_service].size()) {
+ if (!service_instances_[_service].size()) {
service_instances_.erase(_service);
}
if(deleted_endpoint) {
@@ -2233,16 +2590,33 @@ void routing_manager_impl::send_error(return_code_e _return_code,
void routing_manager_impl::on_identify_response(client_t _client, service_t _service,
instance_t _instance, bool _reliable) {
- std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
- identified_clients_[_service][_instance][_reliable].insert(_client);
+ {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identifying_clients_.find(_service);
+ if (its_service != identifying_clients_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ auto its_reliable = its_instance->second.find(_reliable);
+ if (its_reliable != its_instance->second.end()) {
+ its_reliable->second.erase(_client);
+ }
+ }
+ }
+ identified_clients_[_service][_instance][_reliable].insert(_client);
+ }
discovery_->send_subscriptions(_service, _instance, _client, _reliable);
}
void routing_manager_impl::identify_for_subscribe(client_t _client,
service_t _service, instance_t _instance, major_version_t _major) {
- if (!has_identified(_client, _service, _instance, false)) {
+ if (!has_identified(_client, _service, _instance, false) &&
+ !is_identifying(_client, _service, _instance, false)) {
auto unreliable_endpoint = find_or_create_remote_client(_service, _instance, false, _client);
if (unreliable_endpoint) {
+ {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ identifying_clients_[_service][_instance][false].insert(_client);
+ }
auto message = runtime::get()->create_message(false);
message->set_service(_service);
message->set_instance(_instance);
@@ -2258,9 +2632,14 @@ void routing_manager_impl::identify_for_subscribe(client_t _client,
}
}
}
- if (!has_identified(_client, _service, _instance, true)) {
+ if (!has_identified(_client, _service, _instance, true) &&
+ !is_identifying(_client, _service, _instance, true)) {
auto reliable_endpoint = find_or_create_remote_client(_service, _instance, true, _client);
if (reliable_endpoint) {
+ {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ identifying_clients_[_service][_instance][true].insert(_client);
+ }
auto message = runtime::get()->create_message(true);
message->set_service(_service);
message->set_instance(_instance);
@@ -2294,6 +2673,30 @@ bool routing_manager_impl::supports_selective(service_t _service, instance_t _in
return supports_selective;
}
+bool routing_manager_impl::is_identifying(client_t _client, service_t _service,
+ instance_t _instance, bool _reliable) {
+ if (!supports_selective(_service, _instance)) {
+ // For legacy selective services clients can't be identified!
+ return false;
+ }
+ bool is_identifieing(false);
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identifying_clients_.find(_service);
+ if (its_service != identifying_clients_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ auto its_reliable = its_instance->second.find(_reliable);
+ if (its_reliable != its_instance->second.end()) {
+ auto its_client = its_reliable->second.find(_client);
+ if (its_client != its_reliable->second.end()) {
+ is_identifieing = true;
+ }
+ }
+ }
+ }
+ return is_identifieing;
+}
+
bool routing_manager_impl::has_identified(client_t _client, service_t _service,
instance_t _instance, bool _reliable) {
if (!supports_selective(_service, _instance)) {
@@ -2321,6 +2724,7 @@ bool routing_manager_impl::has_identified(client_t _client, service_t _service,
void routing_manager_impl::clear_remote_subscriber(
service_t _service, instance_t _instance, client_t _client,
const std::shared_ptr<endpoint_definition> &_target) {
+ std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_);
auto its_service = remote_subscribers_.find(_service);
if (its_service != remote_subscribers_.end()) {
auto its_instance = its_service->second.find(_instance);
@@ -2337,13 +2741,13 @@ void routing_manager_impl::clear_remote_subscriber(
}
}
-std::chrono::high_resolution_clock::time_point
+std::chrono::steady_clock::time_point
routing_manager_impl::expire_subscriptions() {
std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
- std::chrono::high_resolution_clock::time_point now
- = std::chrono::high_resolution_clock::now();
- std::chrono::high_resolution_clock::time_point next_expiration
- = std::chrono::high_resolution_clock::now() + std::chrono::hours(24);
+ std::chrono::steady_clock::time_point now
+ = std::chrono::steady_clock::now();
+ std::chrono::steady_clock::time_point next_expiration
+ = std::chrono::steady_clock::now() + std::chrono::hours(24);
for (auto &its_service : eventgroups_) {
for (auto &its_instance : its_service.second) {
@@ -2366,6 +2770,12 @@ routing_manager_impl::expire_subscriptions() {
clear_remote_subscriber(its_service.first, its_instance.first,
its_client, its_endpoint);
+ auto target = routing_manager_base::find_local(its_service.first, its_instance.first);
+ if (target) {
+ stub_->send_unsubscribe(target, VSOMEIP_ROUTING_CLIENT, its_service.first,
+ its_instance.first, its_eventgroup.first, true);
+ }
+
VSOMEIP_DEBUG << "Expired subscription ("
<< std::hex << its_service.first << "."
<< its_instance .first << "."
@@ -2374,7 +2784,7 @@ routing_manager_impl::expire_subscriptions() {
<< std::dec << its_endpoint->get_port()
<< "(" << std::hex << its_client << ")";
}
- if(its_eventgroup.second->is_multicast() &&
+ if(its_eventgroup.second->is_multicast() && its_expired_endpoints.size() &&
0 == its_eventgroup.second->get_unreliable_target_count() ) {
//clear multicast targets if no unreliable subscriber is left for multicast eventgroup
its_eventgroup.second->clear_multicast_targets();
@@ -2386,8 +2796,407 @@ routing_manager_impl::expire_subscriptions() {
return next_expiration;
}
-bool routing_manager_impl::queue_message(const byte_t *_data, uint32_t _size) const {
- return stub_->queue_message(_data, _size);
+void routing_manager_impl::log_version_timer_cbk(boost::system::error_code const & _error) {
+ if (!_error) {
+
+#ifndef VSOMEIP_VERSION
+#define VSOMEIP_VERSION "unknown version"
+#endif
+
+ VSOMEIP_INFO << "vSomeIP " << VSOMEIP_VERSION;
+ version_log_timer_.expires_from_now(
+ std::chrono::seconds(configuration_->get_log_version_interval()));
+ version_log_timer_.async_wait(std::bind(&routing_manager_impl::log_version_timer_cbk,
+ this, std::placeholders::_1));
+ }
+}
+
+#ifndef WITHOUT_SYSTEMD
+void routing_manager_impl::watchdog_cbk(boost::system::error_code const &_error) {
+ if (!_error) {
+ static bool is_ready(false);
+ static bool has_interval(false);
+ static uint64_t its_interval(0);
+
+ if (is_ready) {
+ sd_notify(0, "WATCHDOG=1");
+ } else {
+ is_ready = true;
+ sd_notify(0, "READY=1");
+ if (0 < sd_watchdog_enabled(0, &its_interval)) {
+ has_interval = true;
+ }
+ }
+
+ if (has_interval) {
+ watchdog_timer_.expires_from_now(std::chrono::microseconds(its_interval / 2));
+ watchdog_timer_.async_wait(std::bind(&routing_manager_impl::watchdog_cbk,
+ this, std::placeholders::_1));
+ }
+ }
+}
+#endif
+
+void routing_manager_impl::clear_remote_service_info(service_t _service, instance_t _instance, bool _reliable) {
+ // Clear remote_service_info_
+ if (remote_service_info_.find(_service) != remote_service_info_.end()) {
+ if (remote_service_info_[_service].find(_instance) != remote_service_info_[_service].end()) {
+ remote_service_info_[_service][_instance].erase(_reliable);
+ auto found_endpoint_def = remote_service_info_[_service][_instance].find(!_reliable);
+ if (found_endpoint_def == remote_service_info_[_service][_instance].end()) {
+ remote_service_info_[_service].erase(_instance);
+ if (0 >= remote_service_info_[_service].size()) {
+ remote_service_info_.erase(_service);
+ }
+ }
+ }
+ }
}
+bool routing_manager_impl::handle_local_offer_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major,minor_version_t _minor) {
+ bool previously_offered(false);
+ {
+ std::lock_guard<std::mutex> its_lock(local_services_mutex_);
+ auto found_service = local_services_.find(_service);
+ if (found_service != local_services_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ const major_version_t its_stored_major(std::get<0>(found_instance->second));
+ const minor_version_t its_stored_minor(std::get<1>(found_instance->second));
+ const client_t its_stored_client(std::get<2>(found_instance->second));
+ if ( its_stored_major == _major
+ && its_stored_minor == _minor
+ && its_stored_client == _client) {
+ VSOMEIP_WARNING << "routing_manager_impl::handle_local_offer_service: "
+ << "Application: " << std::hex << std::setfill('0')
+ << std::setw(4) << _client << " is offering: ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << _minor << "] offered previously by itself.";
+ previously_offered = true;
+ } else if ( its_stored_major == _major
+ && its_stored_minor == _minor
+ && its_stored_client != _client) {
+ // check if previous offering application is still alive
+ bool already_pinged(false);
+ {
+ std::lock_guard<std::mutex> its_lock(pending_offers_mutex_);
+ auto found_service2 = pending_offers_.find(_service);
+ if (found_service2 != pending_offers_.end()) {
+ auto found_instance2 = found_service2->second.find(_instance);
+ if (found_instance2 != found_service2->second.end()) {
+ if(std::get<2>(found_instance2->second) == _client) {
+ already_pinged = true;
+ } else {
+ VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: "
+ << "rejecting service registration. Application: "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << _client << " is trying to offer ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor
+ << "] current pending offer by application: " << std::hex
+ << std::setfill('0') << std::setw(4)
+ << its_stored_client << ": ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(its_stored_major)
+ << "." << its_stored_minor << "]";
+ return false;
+ }
+ }
+ }
+ }
+ if (!already_pinged) {
+ // find out endpoint of previously offering application
+ std::shared_ptr<local_client_endpoint_base_impl>
+ its_old_endpoint
+ = std::dynamic_pointer_cast<local_client_endpoint_base_impl>(
+ find_local(its_stored_client));
+ if (its_old_endpoint) {
+ std::lock_guard<std::mutex> its_lock(pending_offers_mutex_);
+ if(stub_->send_ping(its_stored_client)) {
+ pending_offers_[_service][_instance] =
+ std::make_tuple(_major, _minor, _client,
+ its_stored_client);
+ VSOMEIP_WARNING << "OFFER("
+ << 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::dec << int(_major) << "." << std::dec << _minor
+ << "] is now pending. Waiting for pong from application: "
+ << std::hex << std::setw(4) << std::setfill('0') << its_stored_client;
+ return false;
+ }
+ } else if (its_stored_client == host_->get_client()) {
+ VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: "
+ << "rejecting service registration. Application: "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << _client << " is trying to offer ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor
+ << "] offered previously by routing manager stub itself with application: "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << its_stored_client << ": ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(its_stored_major)
+ << "." << its_stored_minor << "] which is still alive";
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else {
+ VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: "
+ << "rejecting service registration. Application: "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << _client << " is trying to offer ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor
+ << "] offered previously by application: " << std::hex
+ << std::setfill('0') << std::setw(4)
+ << its_stored_client << ": ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(its_stored_major)
+ << "." << its_stored_minor << "]";
+ return false;
+ }
+ }
+ }
+
+ // check if the same service instance is already offered remotely
+ if (routing_manager_base::offer_service(_client, _service, _instance,
+ _major, _minor) || previously_offered) {
+ local_services_[_service][_instance] = std::make_tuple(_major,
+ _minor, _client);
+ } else {
+ VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: "
+ << "rejecting service registration. Application: "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << _client << " is trying to offer ["
+ << std::hex << std::setfill('0') << std::setw(4) << _service << "."
+ << std::hex << std::setfill('0') << std::setw(4) << _instance << "."
+ << std::dec << static_cast<std::uint32_t>(_major) << "."
+ << std::dec << _minor << "]"
+ << "] already offered remotely";
+ return false;
+ }
+ }
+ return true;
+}
+
+void routing_manager_impl::on_pong(client_t _client) {
+ std::lock_guard<std::mutex> its_lock(pending_offers_mutex_);
+ if (pending_offers_.size() == 0) {
+ return;
+ }
+ for (auto service_iter = pending_offers_.begin();
+ service_iter != pending_offers_.end(); ) {
+ for (auto instance_iter = service_iter->second.begin();
+ instance_iter != service_iter->second.end(); ) {
+ if (std::get<3>(instance_iter->second) == _client) {
+ // received pong from an application were another application wants
+ // to offer its service, delete the other applications offer as
+ // the current offering application is still alive
+ VSOMEIP_WARNING << "OFFER("
+ << std::hex << std::setw(4) << std::setfill('0')
+ << std::get<2>(instance_iter->second) <<"): ["
+ << std::hex << std::setw(4) << std::setfill('0')
+ << service_iter->first << "."
+ << std::hex << std::setw(4) << std::setfill('0')
+ << instance_iter->first << ":" << std::dec
+ << std::uint32_t(std::get<0>(instance_iter->second))
+ << "." << std::dec << std::get<1>(instance_iter->second)
+ << "] was rejected as application: "
+ << std::hex << std::setw(4) << std::setfill('0') << _client
+ << " is still alive";
+ instance_iter = service_iter->second.erase(instance_iter);
+ } else {
+ ++instance_iter;
+ }
+ }
+
+ if (service_iter->second.size() == 0) {
+ service_iter = pending_offers_.erase(service_iter);
+ } else {
+ ++service_iter;
+ }
+ }
+}
+
+void routing_manager_impl::on_clientendpoint_error(client_t _client) {
+ VSOMEIP_WARNING << "Application/Client "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << _client << " will be deregistered because of an client endpoint error.";
+ stub_->deregister_erroneous_client(_client);
+}
+
+void routing_manager_impl::confirm_pending_offers(client_t _client) {
+ std::forward_list<std::tuple<client_t, service_t, instance_t, major_version_t,
+ minor_version_t>> its_offers;
+ {
+ std::lock_guard<std::mutex> its_lock(pending_offers_mutex_);
+ if (pending_offers_.size() == 0) {
+ return;
+ }
+
+ for (auto service_iter = pending_offers_.begin();
+ service_iter != pending_offers_.end(); ) {
+ for (auto instance_iter = service_iter->second.begin();
+ instance_iter != service_iter->second.end(); ) {
+ if (std::get<3>(instance_iter->second) == _client) {
+ VSOMEIP_WARNING << "OFFER("
+ << std::hex << std::setw(4) << std::setfill('0')
+ << std::get<2>(instance_iter->second) <<"): ["
+ << std::hex << std::setw(4) << std::setfill('0')
+ << service_iter->first << "."
+ << std::hex << std::setw(4) << std::setfill('0')
+ << instance_iter->first << ":" << std::dec
+ << std::uint32_t(std::get<0>(instance_iter->second))
+ << "." << std::dec << std::get<1>(instance_iter->second)
+ << "] is not pending anymore as application: "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << std::get<3>(instance_iter->second)
+ << " is dead. Offering again!";
+ its_offers.push_front(std::make_tuple(
+ std::get<2>(instance_iter->second),
+ service_iter->first,
+ instance_iter->first,
+ std::get<0>(instance_iter->second),
+ std::get<1>(instance_iter->second)));
+ instance_iter = service_iter->second.erase(instance_iter);
+ } else {
+ ++instance_iter;
+ }
+ }
+
+ if (service_iter->second.size() == 0) {
+ service_iter = pending_offers_.erase(service_iter);
+ } else {
+ ++service_iter;
+ }
+ }
+ }
+ for (const auto &offer : its_offers) {
+ offer_service(std::get<0>(offer), std::get<1>(offer), std::get<2>(offer),
+ std::get<3>(offer), std::get<4>(offer));
+ }
+}
+
+void routing_manager_impl::remove_specific_client_endpoint(client_t _client, service_t _service, instance_t _instance, bool _reliable)
+{
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service = specific_endpoint_clients_.find(_service);
+ if(found_service != specific_endpoint_clients_.end()){
+ auto found_instance = found_service->second.find(_instance);
+ if(found_instance != found_service->second.end()) {
+ auto its_client = found_instance->second.find(_client);
+ if (its_client != found_instance->second.end()) {
+ if (remote_services_.find(_service) != remote_services_.end()) {
+ if (remote_services_[_service].find(_instance) != remote_services_[_service].end()) {
+ auto endpoint = remote_services_[_service][_instance][_client][_reliable];
+ if (endpoint) {
+ service_instances_[_service].erase(endpoint.get());
+ endpoint->stop();
+ }
+ remote_services_[_service][_instance][_client].erase(_reliable);
+ auto found_endpoint = remote_services_[_service][_instance][_client].find(!_reliable);
+ if (found_endpoint == remote_services_[_service][_instance][_client].end()) {
+ remote_services_[_service][_instance].erase(_client);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void routing_manager_impl::clear_identified_clients( service_t _service, instance_t _instance) {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identified_clients_.find(_service);
+ if (its_service != identified_clients_.end()) {
+ auto found_instance = its_service->second.find(_instance);
+ if (found_instance != its_service->second.end()) {
+ auto found_reliable = found_instance->second.find(true);
+ if (found_reliable != found_instance->second.end()) {
+ found_reliable->second.clear();
+ }
+ auto found_unreliable = found_instance->second.find(false);
+ if (found_unreliable != found_instance->second.end()) {
+ found_unreliable->second.clear();
+ }
+ }
+ }
+}
+
+void routing_manager_impl::clear_identifying_clients( service_t _service, instance_t _instance) {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identifying_clients_.find(_service);
+ if (its_service != identifying_clients_.end()) {
+ auto found_instance = its_service->second.find(_instance);
+ if (found_instance != its_service->second.end()) {
+ auto found_reliable = found_instance->second.find(true);
+ if (found_reliable != found_instance->second.end()) {
+ found_reliable->second.clear();
+ }
+ auto found_unreliable = found_instance->second.find(false);
+ if (found_unreliable != found_instance->second.end()) {
+ found_unreliable->second.clear();
+ }
+ }
+ }
+}
+
+void routing_manager_impl::remove_identified_client(service_t _service, instance_t _instance, client_t _client) {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identified_clients_.find(_service);
+ if (its_service != identified_clients_.end()) {
+ auto found_instance = its_service->second.find(_instance);
+ if (found_instance != its_service->second.end()) {
+ auto found_reliable = found_instance->second.find(true);
+ if (found_reliable != found_instance->second.end()) {
+ auto found_client = found_reliable->second.find(_client);
+ if(found_client != found_reliable->second.end())
+ found_reliable->second.erase(_client);
+ }
+ auto found_unreliable = found_instance->second.find(false);
+ if (found_unreliable != found_instance->second.end()) {
+ auto found_client = found_unreliable->second.find(_client);
+ if(found_client != found_unreliable->second.end())
+ found_unreliable->second.erase(_client);
+ }
+ }
+ }
+}
+
+void routing_manager_impl::remove_identifying_client(service_t _service, instance_t _instance, client_t _client) {
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identifying_clients_.find(_service);
+ if (its_service != identifying_clients_.end()) {
+ auto found_instance = its_service->second.find(_instance);
+ if (found_instance != its_service->second.end()) {
+ auto found_reliable = found_instance->second.find(true);
+ if (found_reliable != found_instance->second.end()) {
+ auto found_client = found_reliable->second.find(_client);
+ if(found_client != found_reliable->second.end())
+ found_reliable->second.erase(_client);
+ }
+ auto found_unreliable = found_instance->second.find(false);
+ if (found_unreliable != found_instance->second.end()) {
+ auto found_client = found_unreliable->second.find(_client);
+ if(found_client != found_unreliable->second.end())
+ found_unreliable->second.erase(_client);
+ }
+ }
+ }
+}
} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp
index 0a3f7b5..9491544 100644
--- a/implementation/routing/src/routing_manager_proxy.cpp
+++ b/implementation/routing/src/routing_manager_proxy.cpp
@@ -8,6 +8,7 @@
#include <mutex>
#include <unordered_set>
#include <future>
+#include <forward_list>
#ifndef WIN32
// for umask
@@ -38,9 +39,10 @@ routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host) :
routing_manager_base(_host),
is_connected_(false),
is_started_(false),
- state_(state_type_e::ST_DEREGISTERED),
+ state_(inner_state_type_e::ST_DEREGISTERED),
sender_(0),
- receiver_(0)
+ receiver_(0),
+ register_application_timer_(io_)
{
}
@@ -50,41 +52,29 @@ routing_manager_proxy::~routing_manager_proxy() {
void routing_manager_proxy::init() {
routing_manager_base::init();
- std::stringstream its_sender_path;
- sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
-
- std::stringstream its_client;
- its_client << VSOMEIP_BASE_PATH << std::hex << client_;
-#ifdef WIN32
- ::_unlink(its_client.str().c_str());
- int port = VSOMEIP_INTERNAL_BASE_PORT + client_;
-#else
- ::unlink(its_client.str().c_str());
- const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask())));
-#endif
- receiver_ = std::make_shared<local_server_endpoint_impl>(shared_from_this(),
-#ifdef WIN32
- boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port),
-#else
- boost::asio::local::stream_protocol::endpoint(its_client.str()),
-#endif
- io_, configuration_->get_max_message_size_local());
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
+ }
-#ifdef WIN32
- VSOMEIP_DEBUG << "Listening at " << port;
-#else
- ::umask(previous_mask);
- VSOMEIP_DEBUG<< "Listening at " << its_client.str();
-#endif
+ init_receiver();
}
void routing_manager_proxy::start() {
is_started_ = true;
- if (!sender_) {
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (!sender_) {
+ // application has been stopped and started again
+ sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
+ }
+ }
+ if (!receiver_) {
// application has been stopped and started again
- sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
+ init_receiver();
}
+
if (sender_) {
sender_->start();
}
@@ -94,7 +84,31 @@ void routing_manager_proxy::start() {
}
void routing_manager_proxy::stop() {
- deregister_application();
+ std::unique_lock<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERING) {
+ register_application_timer_.cancel();
+ }
+ while (state_ == inner_state_type_e::ST_REGISTERING) {
+ std::cv_status status = state_condition_.wait_for(its_lock, std::chrono::milliseconds(1000));
+ if (status == std::cv_status::timeout) {
+ VSOMEIP_WARNING << std::hex << client_ << " registering timeout on stop";
+ break;
+ }
+ }
+
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ deregister_application();
+ // Waiting de-register acknowledge to synchronize shutdown
+ while (state_ == inner_state_type_e::ST_REGISTERED) {
+ std::cv_status status = state_condition_.wait_for(its_lock, std::chrono::milliseconds(1000));
+ if (status == std::cv_status::timeout) {
+ VSOMEIP_WARNING << std::hex << client_ << " couldn't deregister application - timeout";
+ break;
+ }
+ }
+ }
+ is_started_ = false;
+ its_lock.unlock();
if (receiver_) {
receiver_->stop();
@@ -110,30 +124,39 @@ void routing_manager_proxy::stop() {
}
}
- // delete the sender
- sender_ = nullptr;
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ // delete the sender
+ sender_ = nullptr;
+ }
+ receiver_ = nullptr;
std::stringstream its_client;
its_client << VSOMEIP_BASE_PATH << std::hex << client_;
#ifdef WIN32
::_unlink(its_client.str().c_str());
#else
- ::unlink(its_client.str().c_str());
+ if (-1 == ::unlink(its_client.str().c_str())) {
+ VSOMEIP_ERROR<< "routing_manager_proxy::stop unlink failed ("
+ << its_client.str() << "): "<< std::strerror(errno);
+ }
#endif
-
- is_started_ = false;
}
-void routing_manager_proxy::offer_service(client_t _client, service_t _service,
+bool routing_manager_proxy::offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor) {
-
- routing_manager_base::offer_service(_client, _service, _instance, _major, _minor);
-
- if (is_connected_) {
- send_offer_service(_client, _service, _instance, _major, _minor);
+ if(!routing_manager_base::offer_service(_client, _service, _instance, _major, _minor)) {
+ VSOMEIP_WARNING << "routing_manager_proxy::offer_service,"
+ << "routing_manager_base::offer_service returned false";
+ }
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ send_offer_service(_client, _service, _instance, _major, _minor);
+ }
+ service_data_t offer = { _service, _instance, _major, _minor, false };
+ pending_offers_.insert(offer);
}
- service_data_t offer = { _service, _instance, _major, _minor, false };
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- pending_offers_.insert(offer);
+ return true;
}
void routing_manager_proxy::send_offer_service(client_t _client,
@@ -158,7 +181,12 @@ void routing_manager_proxy::send_offer_service(client_t _client,
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor,
sizeof(_minor));
- sender_->send(its_command, sizeof(its_command));
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ }
}
void routing_manager_proxy::stop_offer_service(client_t _client,
@@ -172,36 +200,43 @@ void routing_manager_proxy::stop_offer_service(client_t _client,
// create server endpoints which needs to be freed
clear_service_info(_service, _instance, false);
- if (is_connected_) {
- byte_t its_command[VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE
- - VSOMEIP_COMMAND_HEADER_SIZE;
-
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_STOP_OFFER_SERVICE;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
- sizeof(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));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major;
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor,
- sizeof(_minor));
-
- sender_->send(its_command, sizeof(its_command));
- }
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- auto it = pending_offers_.begin();
- while (it != pending_offers_.end()) {
- if (it->service_ == _service
- && it->instance_ == _instance) {
- break;
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ byte_t its_command[VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_STOP_OFFER_SERVICE;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
+ sizeof(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));
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor,
+ sizeof(_minor));
+
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ }
+ }
+ auto it = pending_offers_.begin();
+ while (it != pending_offers_.end()) {
+ if (it->service_ == _service
+ && it->instance_ == _instance) {
+ break;
+ }
+ it++;
}
- it++;
+ if (it != pending_offers_.end()) pending_offers_.erase(it);
}
- if (it != pending_offers_.end()) pending_offers_.erase(it);
}
void routing_manager_proxy::request_service(client_t _client,
@@ -209,29 +244,73 @@ void routing_manager_proxy::request_service(client_t _client,
minor_version_t _minor, bool _use_exclusive_proxy) {
routing_manager_base::request_service(_client, _service, _instance, _major,
_minor, _use_exclusive_proxy);
- send_request_service(_client, _service, _instance, _major, _minor,
- _use_exclusive_proxy);
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ send_request_service(_client, _service, _instance, _major, _minor,
+ _use_exclusive_proxy);
+ }
+ service_data_t request = { _service, _instance, _major, _minor, _use_exclusive_proxy };
+ pending_requests_.insert(request);
+ }
}
void routing_manager_proxy::release_service(client_t _client,
service_t _service, instance_t _instance) {
routing_manager_base::release_service(_client, _service, _instance);
- send_release_service(_client, _service, _instance);
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ send_release_service(_client, _service, _instance);
+ }
+ auto it = pending_requests_.begin();
+ while (it != pending_requests_.end()) {
+ if (it->service_ == _service
+ && it->instance_ == _instance) {
+ break;
+ }
+ it++;
+ }
+ if (it != pending_requests_.end()) pending_requests_.erase(it);
+ }
}
void routing_manager_proxy::register_event(client_t _client,
service_t _service, instance_t _instance,
event_t _event, const std::set<eventgroup_t> &_eventgroups,
- bool _is_field, bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) {
+ bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle,
+ epsilon_change_func_t _epsilon_change_func,
+ bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) {
(void)_is_shadow;
(void)_is_cache_placeholder;
routing_manager_base::register_event(_client, _service, _instance,
- _event,_eventgroups, _is_field, _is_provided);
-
- send_register_event(client_, _service, _instance,
- _event, _eventgroups, _is_field, _is_provided);
+ _event,_eventgroups, _is_field,
+ _cycle, _change_resets_cycle,
+ _epsilon_change_func,
+ _is_provided);
+
+ if (!_is_provided ||
+ configuration_->is_offered_remote(_service, _instance)) {
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ send_register_event(client_, _service, _instance,
+ _event, _eventgroups, _is_field, _is_provided);
+ }
+ event_data_t registration = {
+ _service,
+ _instance,
+ _event,
+ _is_field,
+ _is_provided,
+ _eventgroups
+ };
+ pending_event_registrations_.insert(registration);
+ }
+ }
}
void routing_manager_proxy::unregister_event(client_t _client,
@@ -241,39 +320,49 @@ void routing_manager_proxy::unregister_event(client_t _client,
routing_manager_base::unregister_event(_client, _service, _instance,
_event, _is_provided);
- if (is_connected_) {
- byte_t its_command[VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE
- - VSOMEIP_COMMAND_HEADER_SIZE;
-
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNREGISTER_EVENT;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
- sizeof(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], &_event,
- sizeof(_event));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6]
- = static_cast<byte_t>(_is_provided);
-
- sender_->send(its_command, sizeof(its_command));
- }
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- auto it = pending_event_registrations_.begin();
- while (it != pending_event_registrations_.end()) {
- if (it->service_ == _service
- && it->instance_ == _instance
- && it->event_ == _event) {
- break;
+ if (!_is_provided ||
+ configuration_->is_offered_remote(_service, _instance)) {
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ byte_t its_command[VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNREGISTER_EVENT;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
+ sizeof(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], &_event,
+ sizeof(_event));
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6]
+ = static_cast<byte_t>(_is_provided);
+
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ }
+ }
+ auto it = pending_event_registrations_.begin();
+ while (it != pending_event_registrations_.end()) {
+ if (it->service_ == _service
+ && it->instance_ == _instance
+ && it->event_ == _event) {
+ break;
+ }
+ it++;
+ }
+ if (it != pending_event_registrations_.end())
+ pending_event_registrations_.erase(it);
}
- it++;
}
- if (it != pending_event_registrations_.end())
- pending_event_registrations_.erase(it);
}
bool routing_manager_proxy::is_field(service_t _service, instance_t _instance,
@@ -288,15 +377,16 @@ bool routing_manager_proxy::is_field(service_t _service, instance_t _instance,
void routing_manager_proxy::subscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup, major_version_t _major,
subscription_type_e _subscription_type) {
-
- if (is_connected_ && is_available(_service, _instance, _major)) {
- send_subscribe(_client, _service, _instance, _eventgroup, _major,
- _subscription_type);
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED && is_available(_service, _instance, _major)) {
+ send_subscribe(_client, _service, _instance, _eventgroup, _major,
+ _subscription_type);
+ }
+ eventgroup_data_t subscription = { _service, _instance, _eventgroup, _major,
+ _subscription_type};
+ pending_subscriptions_.insert(subscription);
}
- eventgroup_data_t subscription = { _service, _instance, _eventgroup, _major,
- _subscription_type};
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- pending_subscriptions_.insert(subscription);
}
void routing_manager_proxy::send_subscribe(client_t _client, service_t _service,
@@ -329,7 +419,12 @@ void routing_manager_proxy::send_subscribe(client_t _client, service_t _service,
auto its_target = find_or_create_local(target_client);
its_target->send(its_command, sizeof(its_command));
} else {
- sender_->send(its_command, sizeof(its_command));
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ }
}
}
@@ -356,7 +451,12 @@ void routing_manager_proxy::send_subscribe_nack(client_t _subscriber,
if (its_target) {
its_target->send(its_command, sizeof(its_command));
} else {
- sender_->send(its_command, sizeof(its_command));
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ }
}
}
@@ -383,56 +483,70 @@ void routing_manager_proxy::send_subscribe_ack(client_t _subscriber,
if (its_target) {
its_target->send(its_command, sizeof(its_command));
} else {
- sender_->send(its_command, sizeof(its_command));
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ }
}
}
void routing_manager_proxy::unsubscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup) {
(void)_client;
-
- if (is_connected_) {
- byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE
- - VSOMEIP_COMMAND_HEADER_SIZE;
-
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client,
- sizeof(_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));
-
- auto its_target = find_local(_service, _instance);
- if (its_target) {
- its_target->send(its_command, sizeof(its_command));
- } else {
- sender_->send(its_command, sizeof(its_command));
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ bool is_remote(false);
+ byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client,
+ sizeof(_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], &is_remote,
+ sizeof(is_remote));
+
+ auto its_target = find_local(_service, _instance);
+ if (its_target) {
+ its_target->send(its_command, sizeof(its_command));
+ } else {
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
+ };
+ }
}
- }
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- auto it = pending_subscriptions_.begin();
- while (it != pending_subscriptions_.end()) {
- if (it->service_ == _service
- && it->instance_ == _instance) {
- break;
+ auto it = pending_subscriptions_.begin();
+ while (it != pending_subscriptions_.end()) {
+ if (it->service_ == _service
+ && it->instance_ == _instance) {
+ break;
+ }
+ it++;
}
- it++;
+ if (it != pending_subscriptions_.end()) pending_subscriptions_.erase(it);
}
- if (it != pending_subscriptions_.end()) pending_subscriptions_.erase(it);
}
bool routing_manager_proxy::send(client_t _client, const byte_t *_data,
length_t _size, instance_t _instance,
bool _flush,
- bool _reliable,
- bool _initial) {
- bool is_sent(false);
+ bool _reliable) {
+ bool is_sent(false);
+ bool has_remote_subscribers(false);
if (_size > VSOMEIP_MESSAGE_TYPE_POS) {
std::shared_ptr<endpoint> its_target;
if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
@@ -461,24 +575,46 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data,
} else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) &&
_client == VSOMEIP_ROUTING_CLIENT) {
// notify
- send_local_notification(get_client(), _data, _size,
- _instance, _flush, _reliable, _initial);
+ has_remote_subscribers = send_local_notification(get_client(), _data, _size,
+ _instance, _flush, _reliable);
} else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) &&
_client != VSOMEIP_ROUTING_CLIENT) {
// notify_one
its_target = find_local(_client);
if (its_target) {
return send_local(its_target, get_client(), _data, _size,
- _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial);
+ _instance, _flush, _reliable, VSOMEIP_SEND);
}
}
// If no direct endpoint could be found/is connected
// or for notifications ~> route to routing_manager_stub
if (!its_target || !its_target->is_connected()) {
- its_target = sender_;
+ if (sender_) {
+ its_target = sender_;
+ } else {
+ return false;
+ }
+ }
+
+ bool send(true);
+ uint8_t command = VSOMEIP_SEND;
+
+ if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
+ if (_client) {
+ command = VSOMEIP_NOTIFY_ONE;
+ } else {
+ command = VSOMEIP_NOTIFY;
+ // Do we need to deliver a notification to the routing manager?
+ // Only for services offered remote which already have remote clients subscribed to
+ service_t its_service = VSOMEIP_BYTES_TO_WORD(
+ _data[VSOMEIP_SERVICE_POS_MIN],
+ _data[VSOMEIP_SERVICE_POS_MAX]);
+ send = configuration_->is_offered_remote(its_service, _instance)
+ && has_remote_subscribers;
+ }
}
#ifdef USE_DLT
- else {
+ else if (its_target != sender_) {
uint16_t its_data_size
= uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
@@ -488,12 +624,10 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data,
_data, its_data_size);
}
#endif
- uint8_t command = utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) ?
- VSOMEIP_NOTIFY : VSOMEIP_SEND;
- if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && _client) {
- command = VSOMEIP_NOTIFY_ONE;
+ if (send) {
+ is_sent = send_local(its_target, _client, _data, _size,
+ _instance, _flush, _reliable, command);
}
- is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, command, false, _initial);
}
return (is_sent);
}
@@ -517,22 +651,26 @@ bool routing_manager_proxy::send_to(
void routing_manager_proxy::notify(
service_t _service, instance_t _instance, event_t _event,
- std::shared_ptr<payload> _payload) {
- std::shared_ptr<message> its_notification
- = runtime::get()->create_notification();
- its_notification->set_service(_service);
- its_notification->set_instance(_instance);
- its_notification->set_method(_event);
- its_notification->set_payload(_payload);
- auto service_info = find_service(_service, _instance);
- if (service_info) {
- its_notification->set_interface_version(service_info->get_major());
- }
- if (is_connected_) {
- routing_manager_base::notify(_service, _instance, _event, _payload);
- } else if (is_field(_service, _instance, _event)){
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- pending_notifications_[_service][_instance][_event] = its_notification;
+ std::shared_ptr<payload> _payload, bool _force) {
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ == inner_state_type_e::ST_REGISTERED) {
+ routing_manager_base::notify(_service, _instance, _event, _payload, _force);
+ }
+
+ if (is_field(_service, _instance, _event)){
+ std::shared_ptr<message> its_notification
+ = runtime::get()->create_notification();
+ its_notification->set_service(_service);
+ its_notification->set_instance(_instance);
+ its_notification->set_method(_event);
+ its_notification->set_payload(_payload);
+ auto service_info = find_service(_service, _instance);
+ if (service_info) {
+ its_notification->set_interface_version(service_info->get_major());
+ }
+ pending_notifications_[_service][_instance][_event] = its_notification;
+ }
}
}
@@ -566,9 +704,9 @@ void routing_manager_proxy::on_error(const byte_t *_data, length_t _length,
}
void routing_manager_proxy::release_port(uint16_t _port, bool _reliable) {
- (void)_port;
- (void)_reliable;
- // intentionally empty
+ (void)_port;
+ (void)_reliable;
+ // intentionally empty
}
void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
@@ -589,7 +727,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
instance_t its_instance;
eventgroup_t its_eventgroup;
major_version_t its_major;
- bool subscription_accepted;
+ bool is_remote_subscriber;
if (_size > VSOMEIP_COMMAND_SIZE_POS_MAX) {
its_command = _data[VSOMEIP_COMMAND_TYPE_POS];
@@ -603,9 +741,9 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
instance_t its_instance;
std::memcpy(&its_instance,
&_data[_size - sizeof(instance_t) - sizeof(bool)
- - sizeof(bool) - sizeof(bool)], sizeof(instance_t));
+ - sizeof(bool)], sizeof(instance_t));
bool its_reliable;
- std::memcpy(&its_reliable, &_data[_size - sizeof(bool) - sizeof(bool)],
+ std::memcpy(&its_reliable, &_data[_size - sizeof(bool)],
sizeof(its_reliable));
deserializer_->set_data(&_data[VSOMEIP_COMMAND_PAYLOAD_POS],
its_length);
@@ -615,9 +753,6 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
its_message->set_instance(its_instance);
its_message->set_reliable(its_reliable);
if(its_message->get_message_type() == message_type_e::MT_NOTIFICATION) {
- bool its_initial(false);
- std::memcpy(&its_initial, &_data[_size - sizeof(bool)], sizeof(its_initial));
- its_message->set_initial(its_initial);
cache_event_payload(its_message);
}
host_->on_message(its_message);
@@ -648,29 +783,37 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
sizeof(its_eventgroup));
std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6],
sizeof(its_major));
- bool is_remote_subscriber;
std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7],
sizeof(is_remote_subscriber));
- if (is_remote_subscriber || known_clients_.find(its_client) != known_clients_.end()) {
- subscription_accepted = host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, true);
- if (!is_remote_subscriber) {
- (void) find_or_create_local(its_client);
- if (!subscription_accepted) {
- send_subscribe_nack(its_client, its_service, its_instance, its_eventgroup);
- } else {
- routing_manager_base::subscribe(its_client, its_service, its_instance, its_eventgroup,
- its_major, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE);
- send_subscribe_ack(its_client, its_service, its_instance, its_eventgroup);
- }
+ if (is_remote_subscriber) {
+ // Remote subscriber: Notify routing manager initially + count subscribes
+ (void)host_->on_subscription(its_service, its_instance,
+ its_eventgroup, its_client, true);
+ bool inserted = insert_subscription(its_service, its_instance, its_eventgroup,
+ VSOMEIP_ROUTING_CLIENT);
+ if (inserted) {
+ notify_remote_initally(its_service, its_instance, its_eventgroup);
}
- } else {
- if (!is_remote_subscriber) {
- eventgroup_data_t subscription = { its_service, its_instance,
- its_eventgroup, its_major,
- subscription_type_e::SU_RELIABLE_AND_UNRELIABLE};
- pending_ingoing_subscripitons_[its_client].insert(subscription);
+ (void)get_remote_subscriber_count(its_service, its_instance, its_eventgroup, true);
+ } else if (known_clients_.find(its_client) != known_clients_.end()) {
+ // Local & already known subscriber: create endpoint + send (N)ACK + insert subscription
+ bool subscription_accepted = host_->on_subscription(its_service, its_instance,
+ its_eventgroup, its_client, true);
+ (void) find_or_create_local(its_client);
+ if (!subscription_accepted) {
+ send_subscribe_nack(its_client, its_service, its_instance, its_eventgroup);
+ } else {
+ routing_manager_base::subscribe(its_client, its_service, its_instance,
+ its_eventgroup, its_major, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE);
+ send_subscribe_ack(its_client, its_service, its_instance, its_eventgroup);
}
+ } else {
+ // Local & not yet known subscriber ~> set pending until subscriber gets known!
+ eventgroup_data_t subscription = { its_service, its_instance,
+ its_eventgroup, its_major,
+ subscription_type_e::SU_RELIABLE_AND_UNRELIABLE};
+ pending_ingoing_subscripitons_[its_client].insert(subscription);
}
VSOMEIP_DEBUG << "SUBSCRIBE("
<< std::hex << std::setw(4) << std::setfill('0') << its_client <<"): ["
@@ -687,8 +830,19 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
sizeof(its_instance));
std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
sizeof(its_eventgroup));
+ std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6],
+ sizeof(is_remote_subscriber));
host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, false);
- routing_manager_base::unsubscribe(its_client, its_service, its_instance, its_eventgroup);
+ if (!is_remote_subscriber) {
+ // Local subscriber: withdraw subscription
+ routing_manager_base::unsubscribe(its_client, its_service, its_instance, its_eventgroup);
+ } else {
+ // Remote subscriber: withdraw subscription only if no more remote subscriber exists
+ if (!get_remote_subscriber_count(its_service, its_instance, its_eventgroup, false)) {
+ routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, its_service,
+ its_instance, its_eventgroup);
+ }
+ }
VSOMEIP_DEBUG << "UNSUBSCRIBE("
<< std::hex << std::setw(4) << std::setfill('0') << its_client << "): ["
<< std::hex << std::setw(4) << std::setfill('0') << its_service << "."
@@ -743,10 +897,18 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
- state_type_e its_state(state_type_e::ST_DEREGISTERED);
- bool restart_sender(_size == 0);
+ inner_state_type_e its_state(inner_state_type_e::ST_DEREGISTERED);
+ bool restart_sender(_size == 1); // 1 indicates a routing master stop
std::map<service_t, std::map<instance_t, std::tuple< major_version_t, minor_version_t, client_t> > > old_local_services;
std::unordered_set<client_t> clients_to_delete;
+ struct service_info {
+ service_t service_id_;
+ instance_t instance_id_;
+ major_version_t major_;
+ minor_version_t minor_;
+ };
+ std::forward_list<struct service_info> services_to_remove;
+ std::forward_list<struct service_info> services_to_add;
{
std::lock_guard<std::mutex> its_lock(local_services_mutex_);
old_local_services = local_services_;
@@ -765,7 +927,7 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
i += uint32_t(sizeof(client_t));
if (its_client == client_) {
- its_state = state_type_e::ST_REGISTERED;
+ its_state = inner_state_type_e::ST_REGISTERED;
}
known_clients.insert(its_client);
@@ -806,98 +968,126 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
}
}
// Which clients are no longer needed?!
- for (auto client : get_connected_clients()) {
+ for (const auto client : get_connected_clients()) {
if (known_clients.find(client) == known_clients.end()) {
clients_to_delete.insert(client);
}
}
known_clients_ = known_clients;
- }
- // inform host about its own registration state changes
- if (state_ != its_state) {
- if (its_state == state_type_e::ST_REGISTERED) {
- VSOMEIP_INFO << std::hex << "Application/Client " << get_client()
- << " is registered.";
- } else {
- VSOMEIP_INFO << std::hex << "Application/Client " << get_client()
- << " is deregistered.";
+ // Check for services that are no longer available
+ for (const auto &i : old_local_services) {
+ auto found_service = local_services_.find(i.first);
+ if (found_service != local_services_.end()) {
+ for (const auto &j : i.second) {
+ auto found_instance = found_service->second.find(j.first);
+ if (found_instance == found_service->second.end()) {
+ services_to_remove.push_front(
+ { i.first, j.first, std::get<0>(j.second),
+ std::get<1>(j.second) });
+ }
+ }
+ } else {
+ for (const auto &j : i.second) {
+ services_to_remove.push_front(
+ { i.first, j.first, std::get<0>(j.second),
+ std::get<1>(j.second) });
+ }
+ }
}
- host_->on_state(its_state);
- state_ = its_state;
- }
- // Check for services that are no longer available
- for (auto i : old_local_services) {
- auto found_service = local_services_.find(i.first);
- if (found_service != local_services_.end()) {
- for (auto j : i.second) {
- auto found_instance = found_service->second.find(j.first);
- if (found_instance == found_service->second.end()) {
- auto version_info = j.second;
- on_stop_offer_service(i.first, j.first, std::get<0>(version_info), std::get<1>(version_info));
- host_->on_availability(i.first, j.first, false, std::get<0>(version_info), std::get<1>(version_info));
+ // Check for services that are newly available
+ for (const auto &i : local_services_) {
+ auto found_service = old_local_services.find(i.first);
+ if (found_service != old_local_services.end()) {
+ for (const auto &j : i.second) {
+ auto found_instance = found_service->second.find(j.first);
+ if (found_instance == found_service->second.end()) {
+ services_to_add.push_front(
+ { i.first, j.first, std::get<0>(j.second),
+ std::get<1>(j.second) });
+ }
+ }
+ } else {
+ for (const auto &j : i.second) {
+ services_to_add.push_front(
+ { i.first, j.first, std::get<0>(j.second),
+ std::get<1>(j.second) });
}
- }
- } else {
- for (auto j : i.second) {
- on_stop_offer_service(i.first, j.first, std::get<0>(j.second), std::get<1>(j.second));
- host_->on_availability(i.first, j.first, false, std::get<0>(j.second), std::get<1>(j.second));
}
}
}
- // Check for services that are newly available
- for (auto i : local_services_) {
- auto found_service = old_local_services.find(i.first);
- if (found_service != old_local_services.end()) {
- for (auto j : i.second) {
- auto found_instance = found_service->second.find(j.first);
- if (found_instance == found_service->second.end()) {
- send_pending_subscriptions(i.first, j.first, std::get<0>(j.second));
- host_->on_availability(i.first, j.first, true, std::get<0>(j.second), std::get<1>(j.second));
- }
- }
- } else {
- for (auto j : i.second) {
- send_pending_subscriptions(i.first, j.first, std::get<0>(j.second));
- host_->on_availability(i.first, j.first, true, std::get<0>(j.second), std::get<1>(j.second));
+ if (state_ != its_state) {
+ VSOMEIP_INFO << std::hex << "Application/Client " << get_client()
+ << (its_state == inner_state_type_e::ST_REGISTERED ?
+ " is registered." : " is deregistered.");
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (its_state == inner_state_type_e::ST_REGISTERED) {
+ boost::system::error_code ec;
+ register_application_timer_.cancel(ec);
+ send_pending_commands();
}
+ state_ = its_state;
}
+
+ // inform host about its own registration state changes
+ host_->on_state(static_cast<state_type_e>(its_state));
+
+ // Notify stop() call about clean deregistration
+ state_condition_.notify_one();
}
- for (client_t client : known_clients_) {
- auto its_client = pending_ingoing_subscripitons_.find(client);
- if (its_client != pending_ingoing_subscripitons_.end()) {
- for (auto subscription : its_client->second) {
- bool subscription_accepted = host_->on_subscription(subscription.service_, subscription.instance_, subscription.eventgroup_, client, true);
- (void) find_or_create_local(client);
- if (!subscription_accepted) {
- send_subscribe_nack(client, subscription.service_, subscription.instance_, subscription.eventgroup_);
- } else {
- routing_manager_base::subscribe(client, subscription.service_, subscription.instance_, subscription.eventgroup_,
- subscription.major_, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE);
- send_subscribe_ack(client, subscription.service_, subscription.instance_, subscription.eventgroup_);
+ // Report services that are no longer available
+ for (const struct service_info &sr : services_to_remove) {
+ on_stop_offer_service(sr.service_id_, sr.instance_id_, sr.major_, sr.minor_);
+ host_->on_availability(sr.service_id_, sr.instance_id_, false, sr.major_, sr.minor_);
+ }
+ // Report services that are newly available
+ for (const struct service_info &sa : services_to_add) {
+ send_pending_subscriptions(sa.service_id_, sa.instance_id_, sa.major_);
+ host_->on_availability(sa.service_id_, sa.instance_id_, true, sa.major_, sa.minor_);
+ }
+
+ if (pending_ingoing_subscripitons_.size()) {
+ for (const client_t client : known_clients_) {
+ auto its_client = pending_ingoing_subscripitons_.find(client);
+ if (its_client != pending_ingoing_subscripitons_.end()) {
+ for (const auto subscription : its_client->second) {
+ bool subscription_accepted = host_->on_subscription(subscription.service_, subscription.instance_, subscription.eventgroup_, client, true);
+ (void) find_or_create_local(client);
+ if (!subscription_accepted) {
+ send_subscribe_nack(client, subscription.service_, subscription.instance_, subscription.eventgroup_);
+ } else {
+ routing_manager_base::subscribe(client, subscription.service_, subscription.instance_, subscription.eventgroup_,
+ subscription.major_, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE);
+ send_subscribe_ack(client, subscription.service_, subscription.instance_, subscription.eventgroup_);
+ }
}
}
+ pending_ingoing_subscripitons_.erase(client);
}
- pending_ingoing_subscripitons_.erase(client);
}
- if (clients_to_delete.size() || restart_sender) {
+ if (clients_to_delete.size()) {
std::async(std::launch::async, [this, clients_to_delete, restart_sender] () {
- for (auto client : clients_to_delete) {
+ for (const auto client : clients_to_delete) {
if (client != VSOMEIP_ROUTING_CLIENT) {
remove_local(client);
}
}
- if (restart_sender && is_started_ && sender_) {
- VSOMEIP_INFO << std::hex << "Application/Client " << get_client()
- <<": Reconnecting to routing manager.";
- sender_->start();
- }
});
}
+
+ if (restart_sender && is_started_) {
+ VSOMEIP_INFO << std::hex << "Application/Client " << get_client()
+ <<": Reconnecting to routing manager.";
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->start();
+ }
+ }
}
void routing_manager_proxy::register_application() {
@@ -910,30 +1100,20 @@ void routing_manager_proxy::register_application() {
sizeof(uint32_t));
if (is_connected_) {
- (void)sender_->send(its_command, sizeof(its_command));
-
- for (auto &po : pending_offers_)
- send_offer_service(client_, po.service_, po.instance_,
- po.major_, po.minor_);
-
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- for (auto &per : pending_event_registrations_)
- send_register_event(client_, per.service_, per.instance_,
- per.event_, per.eventgroups_,
- per.is_field_, per.is_provided_);
-
- for (auto &s : pending_notifications_) {
- for (auto &i : s.second) {
- for (auto &pn : i.second) {
- routing_manager_base::notify(s.first, i.first,
- pn.first, pn.second->get_payload());
- }
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ {
+ std::lock_guard<std::mutex> its_state_lock(state_mutex_);
+ state_ = inner_state_type_e::ST_REGISTERING;
}
- }
+ sender_->send(its_command, sizeof(its_command));
- for (auto &po : pending_requests_) {
- send_request_service(client_, po.service_, po.instance_,
- po.major_, po.minor_, po.use_exclusive_proxy_);
+ register_application_timer_.cancel();
+ register_application_timer_.expires_from_now(std::chrono::milliseconds(1000));
+ register_application_timer_.async_wait(
+ std::bind(
+ &routing_manager_proxy::register_application_timeout_cbk,
+ this, std::placeholders::_1));
}
}
}
@@ -948,7 +1128,12 @@ void routing_manager_proxy::deregister_application() {
std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size,
sizeof(its_size));
if (is_connected_)
- (void)sender_->send(&its_command[0], uint32_t(its_command.size()));
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(&its_command[0], uint32_t(its_command.size()));
+ }
+ }
}
void routing_manager_proxy::send_pong() const {
@@ -958,8 +1143,14 @@ void routing_manager_proxy::send_pong() const {
std::memcpy(&its_pong[VSOMEIP_COMMAND_CLIENT_POS], &client_,
sizeof(client_t));
- if (is_connected_)
- sender_->send(its_pong, sizeof(its_pong));
+ if (is_connected_) {
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_pong, sizeof(its_pong));
+ }
+ }
+ }
}
void routing_manager_proxy::send_request_service(client_t _client, service_t _service,
@@ -967,32 +1158,32 @@ void routing_manager_proxy::send_request_service(client_t _client, service_t _se
minor_version_t _minor, bool _use_exclusive_proxy) {
(void)_client;
- if (is_connected_) {
- byte_t its_command[VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE
- - VSOMEIP_COMMAND_HEADER_SIZE;
-
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REQUEST_SERVICE;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
- sizeof(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));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major;
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor,
- sizeof(_minor));
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 9], &_use_exclusive_proxy,
- sizeof(_use_exclusive_proxy));
-
- sender_->send(its_command, sizeof(its_command));
- } else {
- service_data_t request = { _service, _instance, _major, _minor, _use_exclusive_proxy };
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- pending_requests_.insert(request);
+ byte_t its_command[VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REQUEST_SERVICE;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
+ sizeof(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));
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor,
+ sizeof(_minor));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 9], &_use_exclusive_proxy,
+ sizeof(_use_exclusive_proxy));
+
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
}
+
}
void routing_manager_proxy::send_release_service(client_t _client, service_t _service,
@@ -1002,18 +1193,21 @@ void routing_manager_proxy::send_release_service(client_t _client, service_t _se
uint32_t its_size = VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE
- VSOMEIP_COMMAND_HEADER_SIZE;
- if (is_connected_) {
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_RELEASE_SERVICE;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
- sizeof(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));
-
- sender_->send(its_command, sizeof(its_command));
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_RELEASE_SERVICE;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
+ sizeof(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::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, sizeof(its_command));
+ }
}
}
@@ -1021,53 +1215,46 @@ void routing_manager_proxy::send_register_event(client_t _client,
service_t _service, instance_t _instance,
event_t _event, const std::set<eventgroup_t> &_eventgroups,
bool _is_field, bool _is_provided) {
- if (is_connected_) {
- uint32_t its_eventgroups_size = uint32_t(_eventgroups.size() * sizeof(eventgroup_t));
- byte_t *its_command = new byte_t[VSOMEIP_REGISTER_EVENT_COMMAND_SIZE + its_eventgroups_size];
- uint32_t its_size = VSOMEIP_REGISTER_EVENT_COMMAND_SIZE
- + its_eventgroups_size
- - VSOMEIP_COMMAND_HEADER_SIZE;
-
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REGISTER_EVENT;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
- sizeof(_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], &_event,
- sizeof(_event));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6]
- = static_cast<byte_t>(_is_field);
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7]
- = static_cast<byte_t>(_is_provided);
-
- std::size_t i = 8;
- for (auto eg : _eventgroups) {
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + i], &eg,
- sizeof(eventgroup_t));
- i += sizeof(eventgroup_t);
- }
- sender_->send(its_command,
- uint32_t(VSOMEIP_REGISTER_EVENT_COMMAND_SIZE
- + its_eventgroups_size));
+ uint32_t its_eventgroups_size = uint32_t(_eventgroups.size() * sizeof(eventgroup_t));
+ byte_t *its_command = new byte_t[VSOMEIP_REGISTER_EVENT_COMMAND_SIZE + its_eventgroups_size];
+ uint32_t its_size = VSOMEIP_REGISTER_EVENT_COMMAND_SIZE
+ + its_eventgroups_size
+ - VSOMEIP_COMMAND_HEADER_SIZE;
- delete[] its_command;
- } else {
- event_data_t registration = {
- _service,
- _instance,
- _event,
- _is_field,
- _is_provided,
- _eventgroups
- };
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- pending_event_registrations_.insert(registration);
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REGISTER_EVENT;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
+ sizeof(_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], &_event,
+ sizeof(_event));
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6]
+ = static_cast<byte_t>(_is_field);
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7]
+ = static_cast<byte_t>(_is_provided);
+
+ std::size_t i = 8;
+ for (auto eg : _eventgroups) {
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + i], &eg,
+ sizeof(eventgroup_t));
+ i += sizeof(eventgroup_t);
}
+
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command,
+ uint32_t(VSOMEIP_REGISTER_EVENT_COMMAND_SIZE
+ + its_eventgroups_size));
+ }
+ }
+
+ delete[] its_command;
}
void routing_manager_proxy::on_subscribe_ack(client_t _client,
@@ -1099,13 +1286,12 @@ void routing_manager_proxy::on_identify_response(client_t _client, service_t _se
sizeof(_instance));
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_reliable,
sizeof(_reliable));
- sender_->send(its_command, size);
-}
-
-bool routing_manager_proxy::queue_message(const byte_t *_data, uint32_t _size) const {
- std::shared_ptr<local_server_endpoint_impl> its_server_endpoint
- = std::dynamic_pointer_cast<local_server_endpoint_impl>(receiver_);
- return its_server_endpoint->queue_message(_data, _size);
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ sender_->send(its_command, size);
+ }
+ }
}
void routing_manager_proxy::cache_event_payload(
@@ -1124,7 +1310,10 @@ void routing_manager_proxy::cache_event_payload(
// create a placeholder field until someone requests this event with
// full information like eventgroup, field or not etc.
routing_manager_base::register_event(host_->get_client(), its_service,
- its_instance, its_method, its_eventgroups, true, false, false, true);
+ its_instance, its_method, its_eventgroups, true,
+ std::chrono::milliseconds::zero(), false,
+ nullptr,
+ false, false, true);
std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method);
if (its_event) {
its_event->set_payload_dont_notify(_message->get_payload());
@@ -1135,6 +1324,7 @@ void routing_manager_proxy::cache_event_payload(
void routing_manager_proxy::send_pending_subscriptions(service_t _service,
instance_t _instance, major_version_t _major) {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
for (auto &ps : pending_subscriptions_) {
if (ps.service_ == _service &&
ps.instance_ == _instance && ps.major_ == _major) {
@@ -1163,4 +1353,154 @@ void routing_manager_proxy::on_stop_offer_service(service_t _service,
}
}
+void routing_manager_proxy::send_pending_commands() {
+ for (auto &po : pending_offers_)
+ send_offer_service(client_, po.service_, po.instance_,
+ po.major_, po.minor_);
+
+ for (auto &per : pending_event_registrations_)
+ send_register_event(client_, per.service_, per.instance_,
+ per.event_, per.eventgroups_,
+ per.is_field_, per.is_provided_);
+
+ for (auto &s : pending_notifications_) {
+ for (auto &i : s.second) {
+ for (auto &pn : i.second) {
+ routing_manager_base::notify(s.first, i.first,
+ pn.first, pn.second->get_payload(), false);
+ }
+ }
+ }
+
+ for (auto &po : pending_requests_) {
+ send_request_service(client_, po.service_, po.instance_,
+ po.major_, po.minor_, po.use_exclusive_proxy_);
+ }
+}
+
+void routing_manager_proxy::init_receiver() {
+ std::stringstream its_client;
+ its_client << VSOMEIP_BASE_PATH << std::hex << client_;
+#ifdef WIN32
+ ::_unlink(its_client.str().c_str());
+ int port = VSOMEIP_INTERNAL_BASE_PORT + client_;
+#else
+ if (-1 == ::unlink(its_client.str().c_str()) && errno != ENOENT) {
+ VSOMEIP_ERROR << "routing_manager_proxy::init_receiver unlink failed ("
+ << its_client.str() << "): "<< std::strerror(errno);
+ }
+ const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask())));
+#endif
+ try {
+ receiver_ = std::make_shared<local_server_endpoint_impl>(shared_from_this(),
+#ifdef WIN32
+ boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port),
+#else
+ boost::asio::local::stream_protocol::endpoint(its_client.str()),
+#endif
+ io_, configuration_->get_max_message_size_local());
+#ifdef WIN32
+ VSOMEIP_DEBUG << "Listening at " << port;
+#else
+ VSOMEIP_DEBUG<< "Listening at " << its_client.str();
+#endif
+ } catch (const std::exception &e) {
+ host_->on_error(error_code_e::SERVER_ENDPOINT_CREATION_FAILED);
+ VSOMEIP_ERROR << "Client ID: " << std::hex << client_ << ": " << e.what();
+ }
+#ifndef WIN32
+ ::umask(previous_mask);
+#endif
+}
+
+void routing_manager_proxy::notify_remote_initally(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) {
+ auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup);
+ if (its_eventgroup) {
+ std::set<std::shared_ptr<event> > its_events
+ = its_eventgroup->get_events();
+ for (auto e : its_events) {
+ if (e->is_field() && e->is_set()) {
+ std::shared_ptr<message> its_notification
+ = runtime::get()->create_notification();
+ its_notification->set_service(_service);
+ its_notification->set_instance(_instance);
+ its_notification->set_method(e->get_event());
+ its_notification->set_payload(e->get_payload());
+ auto service_info = find_service(_service, _instance);
+ if (service_info) {
+ its_notification->set_interface_version(service_info->get_major());
+ }
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
+ if (serializer_->serialize(its_notification.get())) {
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ if (sender_) {
+ send_local(sender_, VSOMEIP_ROUTING_CLIENT, serializer_->get_data(),
+ serializer_->get_size(), _instance, true, false, VSOMEIP_NOTIFY);
+ }
+ }
+ serializer_->reset();
+ } else {
+ VSOMEIP_ERROR << "Failed to serialize message. Check message size!";
+ }
+ }
+ }
+ }
+
+}
+
+uint32_t routing_manager_proxy::get_remote_subscriber_count(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup, bool _increment) {
+ uint32_t count (0);
+ bool found(false);
+ auto found_service = remote_subscriber_count_.find(_service);
+ if (found_service != remote_subscriber_count_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_group = found_instance->second.find(_eventgroup);
+ if (found_group != found_instance->second.end()) {
+ found = true;
+ if (_increment) {
+ found_group->second = found_group->second + 1;
+ } else {
+ if (found_group->second > 0) {
+ found_group->second = found_group->second - 1;
+ }
+ }
+ count = found_group->second;
+ }
+ }
+ }
+ if (!found) {
+ if (_increment) {
+ remote_subscriber_count_[_service][_instance][_eventgroup] = 1;
+ count = 1;
+ }
+ }
+ return count;
+}
+
+void routing_manager_proxy::register_application_timeout_cbk(
+ boost::system::error_code const &_error) {
+ if (!_error) {
+ bool register_again(false);
+ {
+ std::lock_guard<std::mutex> its_lock(state_mutex_);
+ if (state_ != inner_state_type_e::ST_REGISTERED) {
+ state_ = inner_state_type_e::ST_DEREGISTERED;
+ register_again = true;
+ }
+ }
+ if (register_again) {
+ std::lock_guard<std::recursive_mutex> its_lock(sender_mutex_);
+ VSOMEIP_WARNING << std::hex << "Client 0x" << get_client() << " register timeout!"
+ << " : Restart route to stub!";
+ if (sender_) {
+ sender_->start();
+ }
+ }
+ }
+}
+
} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp
index 01ca85a..900f266 100644
--- a/implementation/routing/src/routing_manager_stub.cpp
+++ b/implementation/routing/src/routing_manager_stub.cpp
@@ -6,6 +6,7 @@
#include <chrono>
#include <functional>
#include <iomanip>
+#include <forward_list>
#ifndef WIN32
// for umask
@@ -18,6 +19,7 @@
#include <vsomeip/constants.hpp>
#include <vsomeip/primitive_types.hpp>
#include <vsomeip/runtime.hpp>
+#include <vsomeip/error.hpp>
#include "../include/routing_manager_stub.hpp"
#include "../include/routing_manager_stub_host.hpp"
@@ -30,68 +32,39 @@
namespace vsomeip {
+const std::vector<byte_t> routing_manager_stub::its_ping_(
+ { VSOMEIP_PING, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
+
routing_manager_stub::routing_manager_stub(
routing_manager_stub_host *_host,
std::shared_ptr<configuration> _configuration) :
host_(_host),
io_(_host->get_io()),
watchdog_timer_(_host->get_io()),
+ endpoint_(nullptr),
+ local_receiver_(nullptr),
configuration_(_configuration),
- routingCommandSize_(VSOMEIP_ROUTING_INFO_SIZE_INIT) {
+ routingCommandSize_(VSOMEIP_ROUTING_INFO_SIZE_INIT),
+ client_registration_running_(false),
+ configured_watchdog_timeout_(configuration_->get_watchdog_timeout()),
+ pinged_clients_timer_(io_) {
}
routing_manager_stub::~routing_manager_stub() {
}
void routing_manager_stub::init() {
- std::stringstream its_endpoint_path;
- its_endpoint_path << VSOMEIP_BASE_PATH << VSOMEIP_ROUTING_CLIENT;
- endpoint_path_ = its_endpoint_path.str();
-
- std::stringstream its_local_receiver_path;
- its_local_receiver_path << VSOMEIP_BASE_PATH << std::hex << host_->get_client();
- local_receiver_path_ = its_local_receiver_path.str();
-#if WIN32
- ::_unlink(endpoint_path_.c_str());
- ::_unlink(local_receiver_path_.c_str());
- int port = VSOMEIP_INTERNAL_BASE_PORT;
- VSOMEIP_DEBUG << "Routing endpoint at " << port;
-#else
- ::unlink(endpoint_path_.c_str());
- ::unlink(local_receiver_path_.c_str());
- VSOMEIP_DEBUG << "Routing endpoint at " << endpoint_path_;
-
- const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask())));
-#endif
-
- endpoint_ =
- std::make_shared < local_server_endpoint_impl
- > (shared_from_this(),
- #ifdef WIN32
- boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port),
- #else
- boost::asio::local::stream_protocol::endpoint(endpoint_path_),
- #endif
- io_, configuration_->get_max_message_size_local());
-
- local_receiver_ =
- std::make_shared < local_server_endpoint_impl
- > (shared_from_this(),
- #ifdef WIN32
- boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port + host_->get_client()),
- #else
- boost::asio::local::stream_protocol::endpoint(local_receiver_path_),
- #endif
- io_, configuration_->get_max_message_size_local());
-
-#ifndef WIN32
- ::umask(previous_mask);
-#endif
+ init_routing_endpoint();
}
void routing_manager_stub::start() {
- endpoint_->start();
- local_receiver_->start();
+ if(!endpoint_) {
+ // application has been stopped and started again
+ init_routing_endpoint();
+ }
+ if(endpoint_) {
+ endpoint_->start();
+ }
client_registration_running_ = true;
client_registration_thread_ = std::make_shared<std::thread>(
@@ -107,6 +80,9 @@ void routing_manager_stub::start() {
} else {
VSOMEIP_INFO << "Watchdog is disabled!";
}
+
+ std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
+ routing_info_[host_->get_client()].first = 0;
}
void routing_manager_stub::stop() {
@@ -117,17 +93,31 @@ void routing_manager_stub::stop() {
}
watchdog_timer_.cancel();
- endpoint_->stop();
- local_receiver_->stop();
+ endpoint_->stop();
+ endpoint_ = nullptr;
#ifdef WIN32
::_unlink(endpoint_path_.c_str());
- ::_unlink(local_receiver_path_.c_str());
#else
- ::unlink(endpoint_path_.c_str());
- ::unlink(local_receiver_path_.c_str());
+ if (-1 == ::unlink(endpoint_path_.c_str())) {
+ VSOMEIP_ERROR << "routing_manager_stub::stop() unlink failed ("
+ << endpoint_path_ << "): "<< std::strerror(errno);
+ }
#endif
+ if(local_receiver_) {
+ local_receiver_->stop();
+ local_receiver_ = nullptr;
+#ifdef WIN32
+ ::_unlink(local_receiver_path_.c_str());
+#else
+ if (-1 == ::unlink(local_receiver_path_.c_str())) {
+ VSOMEIP_ERROR << "routing_manager_stub::stop() unlink (local receiver) failed ("
+ << local_receiver_path_ << "): "<< std::strerror(errno);
+ }
+#endif
+ }
+
broadcast_routing_info(true);
}
@@ -203,7 +193,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
VSOMEIP_INFO << "Application/Client "
<< std::hex << std::setw(4) << std::setfill('0')
<< its_client << " is registering.";
- pending_client_registrations_[its_client].push_back(true);
+ pending_client_registrations_[its_client].push_back(registration_type_e::REGISTER);
client_registration_condition_.notify_one();
}
break;
@@ -214,7 +204,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
VSOMEIP_INFO << "Application/Client "
<< std::hex << std::setw(4) << std::setfill('0')
<< its_client << " is deregistering.";
- pending_client_registrations_[its_client].push_back(false);
+ pending_client_registrations_[its_client].push_back(registration_type_e::DEREGISTER);
client_registration_condition_.notify_one();
}
break;
@@ -237,11 +227,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
sizeof(its_minor));
host_->offer_service(its_client, its_service, its_instance,
its_major, its_minor);
- VSOMEIP_DEBUG << "OFFER("
- << 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::dec << int(its_major) << "." << std::dec << its_minor << "]";
break;
case VSOMEIP_STOP_OFFER_SERVICE:
@@ -257,11 +242,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
sizeof(its_minor));
host_->stop_offer_service(its_client, its_service, its_instance, its_major, its_minor);
- VSOMEIP_DEBUG << "STOP OFFER("
- << 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::dec << int(its_major) << "." << its_minor << "]";
break;
case VSOMEIP_SUBSCRIBE:
@@ -279,12 +259,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
sizeof(its_subscription_type));
host_->subscribe(its_client, its_service,
its_instance, its_eventgroup, its_major, its_subscription_type);
- VSOMEIP_DEBUG << "SUBSCRIBE("
- << 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 << ":"
- << std::dec << (uint16_t)its_major << "]";
break;
case VSOMEIP_UNSUBSCRIBE:
@@ -296,11 +270,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
sizeof(its_eventgroup));
host_->unsubscribe(its_client, its_service,
its_instance, its_eventgroup);
- VSOMEIP_DEBUG << "UNSUBSCRIBE("
- << 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_SUBSCRIBE_ACK:
@@ -339,10 +308,8 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
its_data[VSOMEIP_SERVICE_POS_MIN],
its_data[VSOMEIP_SERVICE_POS_MAX]);
std::memcpy(&its_instance, &_data[_size - sizeof(instance_t)
- - sizeof(bool) - sizeof(bool)
- - sizeof(bool)], sizeof(its_instance));
- std::memcpy(&its_reliable, &_data[_size - sizeof(bool)
- - sizeof(bool)], sizeof(its_reliable));
+ - sizeof(bool) - sizeof(bool)], sizeof(its_instance));
+ std::memcpy(&its_reliable, &_data[_size - sizeof(bool)], sizeof(its_reliable));
host_->on_message(its_service, its_instance, its_data, its_size, its_reliable);
break;
@@ -355,8 +322,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
its_data[VSOMEIP_CLIENT_POS_MIN],
its_data[VSOMEIP_CLIENT_POS_MAX]);
std::memcpy(&its_instance, &_data[_size - sizeof(instance_t)
- - sizeof(bool) - sizeof(bool)
- - sizeof(bool)], sizeof(its_instance));
+ - sizeof(bool) - sizeof(bool)], sizeof(its_instance));
host_->on_notification(its_client, its_service, its_instance, its_data, its_size);
break;
case VSOMEIP_NOTIFY_ONE:
@@ -365,8 +331,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
its_data[VSOMEIP_SERVICE_POS_MIN],
its_data[VSOMEIP_SERVICE_POS_MAX]);
std::memcpy(&its_instance, &_data[_size - sizeof(instance_t)
- - sizeof(bool) - sizeof(bool)
- - sizeof(bool)], sizeof(its_instance));
+ - sizeof(bool) - sizeof(bool)], sizeof(its_instance));
host_->on_notification(its_client, its_service, its_instance, its_data, its_size, true);
break;
@@ -384,11 +349,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
sizeof(use_exclusive_proxy));
host_->request_service(its_client, its_service, its_instance,
its_major, its_minor, use_exclusive_proxy);
- VSOMEIP_DEBUG << "REQUEST("
- << 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::dec << int(its_major) << "." << std::dec << its_minor << "]";
break;
case VSOMEIP_RELEASE_SERVICE:
@@ -398,10 +358,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
&_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
sizeof(its_instance));
host_->release_service(its_client, its_service, its_instance);
- VSOMEIP_DEBUG << "RELEASE("
- << 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 << "]";
break;
case VSOMEIP_REGISTER_EVENT:
@@ -499,14 +455,15 @@ void routing_manager_stub::on_deregister_application(client_t _client) {
for (auto &its_instance : its_service.second) {
auto its_version = its_instance.second;
routing_info_mutex_.unlock();
- host_->on_stop_offer_service(its_service.first, its_instance.first, its_version.first, its_version.second);
+ host_->on_stop_offer_service(_client, its_service.first,
+ its_instance.first, its_version.first,
+ its_version.second);
routing_info_mutex_.lock();
}
}
}
routing_info_.erase(_client);
routing_info_mutex_.unlock();
- host_->remove_local(_client);
}
void routing_manager_stub::client_registration_func(void) {
@@ -516,34 +473,94 @@ void routing_manager_stub::client_registration_func(void) {
client_registration_condition_.wait(its_lock);
}
- std::map<client_t, std::vector<bool>> its_registrations(
- pending_client_registrations_);
+ std::map<client_t, std::vector<registration_type_e>> its_registrations(
+ pending_client_registrations_);
pending_client_registrations_.clear();
its_lock.unlock();
for (auto r : its_registrations) {
for (auto b : r.second) {
- if (b) {
+ if (b == registration_type_e::REGISTER) {
on_register_application(r.first);
} else {
on_deregister_application(r.first);
}
+ {
+ // Inform (de)registered client first then broadcast all others
+ // Don't inform client if we deregister because of an client
+ // endpoint error to avoid writing in an already closed socket
+ std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
+ if (b != registration_type_e::DEREGISTER_ERROR_CASE) {
+ send_routing_info(r.first);
+ }
+ for (auto& info : routing_info_) {
+ if (info.first != VSOMEIP_ROUTING_CLIENT &&
+ info.first != host_->get_client() &&
+ info.first != r.first) {
+ send_routing_info(info.first);
+ }
+ }
+ }
+ if (b == registration_type_e::DEREGISTER
+ || b == registration_type_e::DEREGISTER_ERROR_CASE) {
+ host_->remove_local(r.first);
+ }
+ if (b == registration_type_e::DEREGISTER_ERROR_CASE) {
+ utility::release_client_id(r.first);
+ host_->confirm_pending_offers(r.first);
+ }
}
}
-
- {
- std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
- broadcast_routing_info();
- }
-
its_lock.lock();
}
}
+void routing_manager_stub::init_routing_endpoint() {
+ std::stringstream its_endpoint_path;
+ its_endpoint_path << VSOMEIP_BASE_PATH << VSOMEIP_ROUTING_CLIENT;
+ endpoint_path_ = its_endpoint_path.str();
+
+#if WIN32
+ ::_unlink(endpoint_path_.c_str());
+ int port = VSOMEIP_INTERNAL_BASE_PORT;
+ VSOMEIP_DEBUG << "Routing endpoint at " << port;
+#else
+ if (-1 == ::unlink(endpoint_path_.c_str()) && errno != ENOENT) {
+ VSOMEIP_ERROR << "routing_manager_stub::init_endpoint unlink failed ("
+ << endpoint_path_ << "): "<< std::strerror(errno);
+ }
+ VSOMEIP_DEBUG << "Routing endpoint at " << endpoint_path_;
+
+ const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask())));
+#endif
+
+ try {
+ endpoint_ =
+ std::make_shared < local_server_endpoint_impl
+ > (shared_from_this(),
+ #ifdef WIN32
+ boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port),
+ #else
+ boost::asio::local::stream_protocol::endpoint(endpoint_path_),
+ #endif
+ io_, configuration_->get_max_message_size_local());
+ } catch (const std::exception &e) {
+ VSOMEIP_ERROR << ERROR_INFO[static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED)]
+ << " (" << static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED) << ")";
+ VSOMEIP_ERROR << "routing_manager_stub::init_endpoint Client ID: "
+ << std::hex << VSOMEIP_ROUTING_CLIENT << ": " << e.what();
+ }
+#ifndef WIN32
+ ::umask(previous_mask);
+#endif
+}
void routing_manager_stub::on_offer_service(client_t _client,
service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) {
std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
+ if (_client == host_->get_client()) {
+ create_local_receiver();
+ }
routing_info_[_client].second[_service][_instance] = std::make_pair(_major, _minor);
broadcast_routing_info();
}
@@ -603,6 +620,7 @@ void routing_manager_stub::send_routing_info(client_t _client, bool _empty) {
// Routing info loop
for (auto &info : routing_info_) {
if (_empty) {
+ its_command.push_back(0x0);
break;
}
std::size_t its_size_pos = its_command.size();
@@ -658,6 +676,9 @@ void routing_manager_stub::send_routing_info(client_t _client, bool _empty) {
// File overall size
std::size_t its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS;
+ if (_empty) {
+ its_size = 1; // Indicates stopping routing!
+ }
std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t));
its_size += VSOMEIP_COMMAND_PAYLOAD_POS;
@@ -686,16 +707,16 @@ void routing_manager_stub::send_routing_info(client_t _client, bool _empty) {
void routing_manager_stub::broadcast_routing_info(bool _empty) {
for (auto& info : routing_info_) {
- if (info.first != VSOMEIP_ROUTING_CLIENT) {
+ if (info.first != VSOMEIP_ROUTING_CLIENT && info.first != host_->get_client()) {
send_routing_info(info.first, _empty);
}
}
}
-void routing_manager_stub::broadcast(std::vector<byte_t> &_command) const {
+void routing_manager_stub::broadcast(const std::vector<byte_t> &_command) const {
std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
for (auto a : routing_info_) {
- if (a.first > 0) {
+ if (a.first != VSOMEIP_ROUTING_CLIENT && a.first != host_->get_client()) {
std::shared_ptr<endpoint> its_endpoint
= host_->find_local(a.first);
if (its_endpoint) {
@@ -725,6 +746,9 @@ void routing_manager_stub::send_subscribe(std::shared_ptr<vsomeip::endpoint> _ta
sizeof(_eventgroup));
its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major;
its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7] = _is_remote_subscriber;
+ // set byte for subscription_type to zero. It's only used
+ // in subscribe messages sent from rm_proxies to rm_stub.
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8] = 0x0;
_target->send(its_command, sizeof(its_command));
}
@@ -732,7 +756,7 @@ void routing_manager_stub::send_subscribe(std::shared_ptr<vsomeip::endpoint> _ta
void routing_manager_stub::send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _target,
client_t _client, service_t _service, instance_t _instance,
- eventgroup_t _eventgroup) {
+ eventgroup_t _eventgroup, bool _is_remote_subscriber) {
if (_target) {
byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE];
uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE
@@ -748,6 +772,8 @@ void routing_manager_stub::send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _
sizeof(_instance));
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup,
sizeof(_eventgroup));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_is_remote_subscriber,
+ sizeof(_is_remote_subscriber));
_target->send(its_command, sizeof(its_command));
}
@@ -758,8 +784,8 @@ void routing_manager_stub::send_subscribe_ack(client_t _client, service_t _servi
std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client);
if (its_endpoint) {
- byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE
+ byte_t its_command[VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE
- VSOMEIP_COMMAND_HEADER_SIZE;
its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK;
@@ -783,8 +809,8 @@ void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _serv
std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client);
if (its_endpoint) {
- byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE
+ byte_t its_command[VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE
- VSOMEIP_COMMAND_HEADER_SIZE;
its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK;
@@ -803,23 +829,43 @@ void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _serv
}
}
+bool routing_manager_stub::contained_in_routing_info(
+ client_t _client, service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) const {
+ std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
+ auto found_client = routing_info_.find(_client);
+ if (found_client != routing_info_.end()) {
+ auto found_service = found_client->second.second.find(_service);
+ if (found_service != found_client->second.second.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ if (found_instance->second.first == _major
+ && found_instance->second.second == _minor) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
// Watchdog
void routing_manager_stub::broadcast_ping() const {
- const byte_t its_ping[] = {
- VSOMEIP_PING, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
-
- std::vector<byte_t> its_command(sizeof(its_ping));
- its_command.assign(its_ping, its_ping + sizeof(its_ping));
- broadcast(its_command);
+ broadcast(its_ping_);
}
void routing_manager_stub::on_pong(client_t _client) {
- auto found_info = routing_info_.find(_client);
- if (found_info != routing_info_.end()) {
- found_info->second.first = 0;
- } else {
- VSOMEIP_ERROR << "Received PONG from unregistered application!";
+ {
+ std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
+ auto found_info = routing_info_.find(_client);
+ if (found_info != routing_info_.end()) {
+ found_info->second.first = 0;
+ } else {
+ VSOMEIP_ERROR << "Received PONG from unregistered application!";
+ }
}
+ remove_from_pinged_clients(_client);
+ host_->on_pong(_client);
}
void routing_manager_stub::start_watchdog() {
@@ -864,8 +910,7 @@ void routing_manager_stub::check_watchdog() {
}
}
for (auto i : lost) {
- utility::release_client_id(i);
- on_deregister_application(i);
+ deregister_erroneous_client(i);
}
start_watchdog();
};
@@ -873,10 +918,201 @@ void routing_manager_stub::check_watchdog() {
watchdog_timer_.async_wait(its_callback);
}
-bool routing_manager_stub::queue_message(const byte_t *_data, uint32_t _size) {
- std::shared_ptr<local_server_endpoint_impl> its_server_endpoint
- = std::dynamic_pointer_cast<local_server_endpoint_impl>(endpoint_);
- return its_server_endpoint->queue_message(_data, _size);
+void routing_manager_stub::create_local_receiver() {
+ if (local_receiver_) {
+ return;
+ }
+ std::stringstream its_local_receiver_path;
+ its_local_receiver_path << VSOMEIP_BASE_PATH << std::hex << host_->get_client();
+ local_receiver_path_ = its_local_receiver_path.str();
+#if WIN32
+ ::_unlink(local_receiver_path_.c_str());
+ int port = VSOMEIP_INTERNAL_BASE_PORT;
+#else
+ if (-1 == ::unlink(local_receiver_path_.c_str()) && errno != ENOENT) {
+ VSOMEIP_ERROR << "routing_manager_stub::create_local_receiver unlink (local receiver) failed ("
+ << local_receiver_path_ << "): "<< std::strerror(errno);
+ }
+
+ const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask())));
+#endif
+
+ try {
+ local_receiver_ =
+ std::make_shared < local_server_endpoint_impl
+ > (shared_from_this(),
+ #ifdef WIN32
+ boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port + host_->get_client()),
+ #else
+ boost::asio::local::stream_protocol::endpoint(local_receiver_path_),
+ #endif
+ io_, configuration_->get_max_message_size_local());
+ } catch (const std::exception &e) {
+ VSOMEIP_ERROR << ERROR_INFO[static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED)]
+ << " (" << static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED) << ")";
+ VSOMEIP_ERROR << "routing_manager_stub::_local_receiver Client ID: "
+ << std::hex << VSOMEIP_ROUTING_CLIENT << ": " << e.what();
+ }
+#ifndef WIN32
+ ::umask(previous_mask);
+#endif
+ local_receiver_->start();
+}
+
+bool routing_manager_stub::send_ping(client_t _client) {
+ std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client);
+ if (!its_endpoint) {
+ return false;
+ }
+
+ {
+ std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_);
+
+ if (pinged_clients_.find(_client) != pinged_clients_.end()) {
+ // client was already pinged: don't ping again and wait for answer
+ // or timeout of previous ping.
+ return true;
+ }
+
+ boost::system::error_code ec;
+ pinged_clients_timer_.cancel(ec);
+ if (ec) {
+ VSOMEIP_ERROR << "routing_manager_stub::send_ping cancellation of "
+ "timer failed: " << ec.message();
+ }
+ const std::chrono::steady_clock::time_point now(
+ std::chrono::steady_clock::now());
+
+ std::chrono::milliseconds next_timeout(configured_watchdog_timeout_);
+ for (const auto &tp : pinged_clients_) {
+ const std::chrono::milliseconds its_clients_timeout =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ now - tp.second);
+ if (next_timeout > its_clients_timeout) {
+ next_timeout = its_clients_timeout;
+ }
+ }
+
+ pinged_clients_[_client] = now;
+
+ ec.clear();
+ pinged_clients_timer_.expires_from_now(next_timeout, ec);
+ if (ec) {
+ VSOMEIP_ERROR<< "routing_manager_stub::send_ping setting "
+ "expiry time of timer failed: " << ec.message();
+ }
+ pinged_clients_timer_.async_wait(
+ std::bind(&routing_manager_stub::on_ping_timer_expired, this,
+ std::placeholders::_1));
+ return its_endpoint->send(&its_ping_[0], uint32_t(its_ping_.size()),
+ true);
+ }
+}
+
+void routing_manager_stub::on_ping_timer_expired(
+ boost::system::error_code const &_error) {
+ if(_error) {
+ return;
+ }
+ std::forward_list<client_t> timed_out_clients;
+ std::chrono::milliseconds next_timeout(configured_watchdog_timeout_);
+ bool pinged_clients_remaining(false);
+
+ {
+ // remove timed out clients
+ std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_);
+ const std::chrono::steady_clock::time_point now(
+ std::chrono::steady_clock::now());
+
+ for (auto client_iter = pinged_clients_.begin();
+ client_iter != pinged_clients_.end(); ) {
+ if ((now - client_iter->second) >= configured_watchdog_timeout_) {
+ timed_out_clients.push_front(client_iter->first);
+ client_iter = pinged_clients_.erase(client_iter);
+ } else {
+ ++client_iter;
+ }
+ }
+ pinged_clients_remaining = (pinged_clients_.size() > 0);
+
+ if(pinged_clients_remaining) {
+ // find out next timeout
+ for (const auto &tp : pinged_clients_) {
+ const std::chrono::milliseconds its_clients_timeout =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ now - tp.second);
+ if (next_timeout > its_clients_timeout) {
+ next_timeout = its_clients_timeout;
+ }
+ }
+ }
+ }
+
+ for (const client_t client : timed_out_clients) {
+ // client did not respond to ping. Report client_endpoint_error
+ // in order to accept pending offers trying to replace the offers of
+ // the now not responding client
+ host_->on_clientendpoint_error(client);
+ }
+ if (pinged_clients_remaining) {
+ boost::system::error_code ec;
+ pinged_clients_timer_.expires_from_now(next_timeout, ec);
+ if (ec) {
+ VSOMEIP_ERROR<< "routing_manager_stub::on_ping_timer_expired "
+ "setting expiry time of timer failed: " << ec.message();
+ }
+ pinged_clients_timer_.async_wait(
+ std::bind(&routing_manager_stub::on_ping_timer_expired, this,
+ std::placeholders::_1));
+ }
+}
+
+void routing_manager_stub::remove_from_pinged_clients(client_t _client) {
+ std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_);
+ if (!pinged_clients_.size()) {
+ return;
+ }
+ boost::system::error_code ec;
+ pinged_clients_timer_.cancel(ec);
+ if (ec) {
+ VSOMEIP_ERROR << "routing_manager_stub::remove_from_pinged_clients "
+ "cancellation of timer failed: " << ec.message();
+ }
+ pinged_clients_.erase(_client);
+
+ if (!pinged_clients_.size()) {
+ return;
+ }
+ const std::chrono::steady_clock::time_point now(
+ std::chrono::steady_clock::now());
+ std::chrono::milliseconds next_timeout(configured_watchdog_timeout_);
+ // find out next timeout
+ for (const auto &tp : pinged_clients_) {
+ const std::chrono::milliseconds its_clients_timeout =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ now - tp.second);
+ if (next_timeout > its_clients_timeout) {
+ next_timeout = its_clients_timeout;
+ }
+ }
+ ec.clear();
+ pinged_clients_timer_.expires_from_now(next_timeout, ec);
+ if (ec) {
+ VSOMEIP_ERROR<< "routing_manager_stub::remove_from_pinged_clients "
+ "setting expiry time of timer failed: " << ec.message();
+ }
+ pinged_clients_timer_.async_wait(
+ std::bind(&routing_manager_stub::on_ping_timer_expired, this,
+ std::placeholders::_1));
+}
+
+void routing_manager_stub::deregister_erroneous_client(client_t _client) {
+ std::lock_guard<std::mutex> its_lock(client_registration_mutex_);
+ VSOMEIP_INFO << "Application/Client "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << _client << " is deregistering.";
+ pending_client_registrations_[_client].push_back(registration_type_e::DEREGISTER_ERROR_CASE);
+ client_registration_condition_.notify_one();
}
} // namespace vsomeip
diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp
index 06f60eb..5b3fe26 100644
--- a/implementation/runtime/include/application_impl.hpp
+++ b/implementation/runtime/include/application_impl.hpp
@@ -17,7 +17,7 @@
#include <vector>
#include <boost/asio/signal_set.hpp>
-#include <boost/asio/system_timer.hpp>
+#include <boost/asio/steady_timer.hpp>
#include <vsomeip/export.hpp>
#include <vsomeip/application.hpp>
@@ -55,6 +55,12 @@ public:
instance_t _instance, event_t _event,
const std::set<eventgroup_t> &_eventgroups,
bool _is_field);
+ VSOMEIP_EXPORT void offer_event(service_t _service,
+ instance_t _instance, event_t _event,
+ const std::set<eventgroup_t> &_eventgroups,
+ bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle_,
+ const epsilon_change_func_t &_epsilon_change_func);
VSOMEIP_EXPORT void stop_offer_event(service_t _service,
instance_t _instance, event_t _event);
@@ -86,9 +92,15 @@ public:
VSOMEIP_EXPORT void notify(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload) const;
+ VSOMEIP_EXPORT void notify(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload,
+ bool _force) const;
VSOMEIP_EXPORT void notify_one(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload, client_t _client) const;
+ VSOMEIP_EXPORT void notify_one(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload, client_t _client,
+ bool _force) const;
VSOMEIP_EXPORT void register_state_handler(state_handler_t _handler);
VSOMEIP_EXPORT void unregister_state_handler();
@@ -137,6 +149,10 @@ public:
// service_discovery_host
VSOMEIP_EXPORT routing_manager * get_routing_manager() const;
+ VSOMEIP_EXPORT bool are_available(available_t &_available,
+ service_t _service = ANY_SERVICE, instance_t _instance = ANY_INSTANCE,
+ major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const;
+
private:
//
// Types
@@ -151,6 +167,17 @@ private:
bool is_dispatching_;
};
+ struct message_handler {
+ message_handler(message_handler_t _handler) :
+ handler_(_handler) {}
+
+ bool operator<(const message_handler& _other) const {
+ return handler_.target<void (*)(const std::shared_ptr<message> &)>()
+ < _other.handler_.target<void (*)(const std::shared_ptr<message> &)>();
+ }
+ message_handler_t handler_;
+ };
+
//
// Methods
//
@@ -165,10 +192,6 @@ private:
bool is_available_unlocked(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor) const;
- typedef std::map<service_t, std::map<instance_t, std::map<major_version_t, minor_version_t >>> available_t;
- bool are_available(available_t &_available,
- service_t _service = ANY_SERVICE, instance_t _instance = ANY_INSTANCE,
- major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const;
bool are_available_unlocked(available_t &_available,
service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor) const;
@@ -184,7 +207,7 @@ private:
void remove_elapsed_dispatchers();
void clear_all_handler();
- void wait_for_stop();
+ void shutdown();
void send_back_cached_event(service_t _service, instance_t _instance, event_t _event);
void send_back_cached_eventgroup(service_t _service, instance_t _instance, eventgroup_t _eventgroup);
@@ -205,6 +228,7 @@ private:
std::string folder_; // configuration folder
boost::asio::io_service io_;
+ std::shared_ptr<boost::asio::io_service::work> work_;
// Proxy to or the Routing Manager itself
std::shared_ptr<routing_manager> routing_;
@@ -236,8 +260,11 @@ private:
std::map<client_t, error_handler_t > > > > eventgroup_error_handlers_;
mutable std::mutex subscription_error_mutex_;
+#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING
// Signals
boost::asio::signal_set signals_;
+ bool catched_signal_;
+#endif
// Handlers
mutable std::deque<std::shared_ptr<sync_handler>> handlers_;
@@ -255,7 +282,7 @@ private:
std::mutex dispatcher_mutex_;
// Condition to wakeup the dispatcher thread
mutable std::condition_variable dispatcher_condition_;
- boost::asio::system_timer dispatcher_timer_;
+ boost::asio::steady_timer dispatcher_timer_;
std::size_t max_dispatchers_;
std::size_t max_dispatch_time_;
@@ -267,15 +294,24 @@ private:
bool stopped_;
std::thread stop_thread_;
- bool catched_signal_;
+ std::condition_variable block_stop_cv_;
+ std::mutex block_stop_mutex_;
+ bool block_stopping_;
static uint32_t app_counter__;
+ static std::mutex app_counter_mutex__;
bool is_routing_manager_host_;
// Event subscriptions
std::mutex event_subscriptions_mutex_;
std::map<service_t, std::map<instance_t, std::map<event_t, bool>>> event_subscriptions_;
+
+ std::thread::id stop_caller_id_;
+
+ bool stopped_called_;
+
+ std::thread::id io_thread_id_;
};
} // namespace vsomeip
diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp
index dc7bda5..d8f08d6 100644
--- a/implementation/runtime/src/application_impl.cpp
+++ b/implementation/runtime/src/application_impl.cpp
@@ -10,6 +10,7 @@
#ifndef WIN32
#include <dlfcn.h>
#endif
+
#include <vsomeip/defines.hpp>
#include <vsomeip/runtime.hpp>
@@ -28,18 +29,29 @@
namespace vsomeip {
uint32_t application_impl::app_counter__ = 0;
+std::mutex application_impl::app_counter_mutex__;
application_impl::application_impl(const std::string &_name)
- : is_initialized_(false), name_(_name),
+ : client_(ILLEGAL_CLIENT),
+ session_(1),
+ is_initialized_(false), name_(_name),
file_(VSOMEIP_DEFAULT_CONFIGURATION_FILE),
folder_(VSOMEIP_DEFAULT_CONFIGURATION_FOLDER),
routing_(0),
state_(state_type_e::ST_DEREGISTERED),
+#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING
signals_(io_, SIGINT, SIGTERM),
+ catched_signal_(false),
+#endif
+ is_dispatching_(false),
dispatcher_timer_(io_),
+ max_dispatchers_(VSOMEIP_MAX_DISPATCHERS),
+ max_dispatch_time_(VSOMEIP_MAX_DISPATCH_TIME),
logger_(logger::get()),
stopped_(false),
- catched_signal_(false) {
+ block_stopping_(false),
+ is_routing_manager_host_(false),
+ stopped_called_(false) {
}
application_impl::~application_impl() {
@@ -144,13 +156,17 @@ bool application_impl::init() {
max_dispatch_time_ = its_configuration->get_max_dispatch_time(name_);
std::string its_routing_host = its_configuration->get_routing_host();
- if (!utility::auto_configuration_init(name_)) {
+ if (!utility::auto_configuration_init()) {
VSOMEIP_WARNING << "Could _not_ initialize auto-configuration:"
" Cannot guarantee unique application identifiers!";
} else {
// Client Identifier
client_t its_old_client = client_;
- client_ = utility::request_client_id(client_);
+ client_ = utility::request_client_id(name_, client_);
+ if (client_ == ILLEGAL_CLIENT) {
+ VSOMEIP_ERROR << "Couldn't acquire client identifier";
+ return false;
+ }
VSOMEIP_INFO << "SOME/IP client identifier configured. "
<< "Using "
<< std::hex << std::setfill('0') << std::setw(4)
@@ -162,14 +178,16 @@ bool application_impl::init() {
// Routing
if (its_routing_host == "") {
- is_routing_manager_host_ = utility::is_routing_manager_host();
+ is_routing_manager_host_ = utility::is_routing_manager_host(client_);
VSOMEIP_INFO << "No routing manager configured. "
<< "Using auto-configuration ("
<< (is_routing_manager_host_ ?
"Host" : "Proxy") << ")";
- } else {
- is_routing_manager_host_ = (its_routing_host == name_);
- }
+ }
+ }
+
+ if (its_routing_host != "") {
+ is_routing_manager_host_ = (its_routing_host == name_);
}
if (is_routing_manager_host_) {
@@ -189,12 +207,12 @@ bool application_impl::init() {
std::shared_ptr<cfg::trace> its_trace_cfg = its_configuration->get_trace();
auto &its_channels_cfg = its_trace_cfg->channels_;
- for(auto it = its_channels_cfg.begin(); it != its_channels_cfg.end(); ++it) {
+ for (auto it = its_channels_cfg.begin(); it != its_channels_cfg.end(); ++it) {
its_trace_connector->add_channel(it->get()->id_, it->get()->name_);
}
auto &its_filter_rules_cfg = its_trace_cfg->filter_rules_;
- for(auto it = its_filter_rules_cfg.begin(); it != its_filter_rules_cfg.end(); ++it) {
+ for (auto it = its_filter_rules_cfg.begin(); it != its_filter_rules_cfg.end(); ++it) {
std::shared_ptr<cfg::trace_filter_rule> its_filter_rule_cfg = *it;
tc::trace_connector::filter_rule_t its_filter_rule;
@@ -206,9 +224,12 @@ bool application_impl::init() {
}
bool enable_tracing = its_trace_cfg->is_enabled_;
- if(enable_tracing)
+ if (enable_tracing)
its_trace_connector->init();
its_trace_connector->set_enabled(enable_tracing);
+
+ bool enable_sd_tracing = its_trace_cfg->is_sd_enabled_;
+ its_trace_connector->set_sd_enabled(enable_sd_tracing);
#endif
VSOMEIP_DEBUG << "Application(" << (name_ != "" ? name_ : "unnamed")
@@ -219,6 +240,7 @@ bool application_impl::init() {
is_initialized_ = true;
}
+#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING
if (is_initialized_) {
signals_.add(SIGINT);
signals_.add(SIGTERM);
@@ -240,7 +262,7 @@ bool application_impl::init() {
};
signals_.async_wait(its_signal_handler);
}
-
+#endif
return is_initialized_;
}
@@ -253,9 +275,27 @@ void application_impl::start() {
VSOMEIP_ERROR << "Trying to start an already started application.";
return;
}
+ if (stopped_) {
+ utility::release_client_id(client_);
+ utility::auto_configuration_exit(client_);
+
+ {
+ std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_);
+ block_stopping_ = true;
+ }
+ block_stop_cv_.notify_all();
+
+ stopped_ = false;
+ return;
+ }
+ stopped_ = false;
+ stopped_called_ = false;
+ VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\".";
is_dispatching_ = true;
+ io_thread_id_ = std::this_thread::get_id();
+
auto its_main_dispatcher = std::make_shared<std::thread>(
std::bind(&application_impl::main_dispatch, this));
dispatchers_[its_main_dispatcher->get_id()] = its_main_dispatcher;
@@ -263,49 +303,76 @@ void application_impl::start() {
if (stop_thread_.joinable()) {
stop_thread_.join();
}
- stop_thread_= std::thread(&application_impl::wait_for_stop, this);
+ stop_thread_= std::thread(&application_impl::shutdown, this);
if (routing_)
routing_->start();
}
- start_stop_mutex_.lock();
+ app_counter_mutex__.lock();
app_counter__++;
- start_stop_mutex_.unlock();
+ app_counter_mutex__.unlock();
- VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\".";
+ work_ = std::make_shared<boost::asio::io_service::work>(io_);
io_.run();
- {
- std::lock_guard<std::mutex> its_lock(start_stop_mutex_);
- stopped_ = true;
- stop_cv_.notify_one();
- }
if (stop_thread_.joinable()) {
stop_thread_.join();
}
- start_stop_mutex_.lock();
+ utility::release_client_id(client_);
+ utility::auto_configuration_exit(client_);
+
+ {
+ std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_);
+ block_stopping_ = true;
+ }
+ block_stop_cv_.notify_all();
+
+ {
+ std::lock_guard<std::mutex> its_lock(start_stop_mutex_);
+ stopped_ = false;
+ }
+
+ app_counter_mutex__.lock();
app_counter__--;
+#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING
if (catched_signal_ && !app_counter__) {
- start_stop_mutex_.unlock();
+ app_counter_mutex__.unlock();
VSOMEIP_INFO << "Exiting vsomeip application...";
exit(0);
}
- start_stop_mutex_.unlock();
+#endif
+ app_counter_mutex__.unlock();
}
void application_impl::stop() {
#ifndef WIN32 // Gives serious problems under Windows.
VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\".";
#endif
- utility::release_client_id(client_);
- utility::auto_configuration_exit();
-
- std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_);
- stopped_ = true;
+ bool block = true;
+ {
+ std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_);
+ if (stopped_ || stopped_called_) {
+ return;
+ }
+ stop_caller_id_ = std::this_thread::get_id();
+ stopped_ = true;
+ stopped_called_ = true;
+ if (io_thread_id_ == std::this_thread::get_id()) {
+ block = false;
+ }
+ }
stop_cv_.notify_one();
+
+ if (block) {
+ std::unique_lock<std::mutex> block_stop_lock(block_stop_mutex_);
+ while (!block_stopping_) {
+ block_stop_cv_.wait(block_stop_lock);
+ }
+ block_stopping_ = false;
+ }
}
void application_impl::offer_service(service_t _service, instance_t _instance,
@@ -573,16 +640,27 @@ void application_impl::send(std::shared_ptr<message> _message, bool _flush) {
void application_impl::notify(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload) const {
+ return notify(_service, _instance, _event, _payload, false);
+}
+
+void application_impl::notify(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload, bool _force) const {
if (routing_)
- routing_->notify(_service, _instance, _event, _payload);
+ routing_->notify(_service, _instance, _event, _payload, _force);
}
void application_impl::notify_one(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload,
client_t _client) const {
+ return notify_one(_service, _instance, _event, _payload, _client, false);
+}
+void application_impl::notify_one(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload,
+ client_t _client, bool _force) const {
if (routing_) {
- routing_->notify_one(_service, _instance, _event, _payload, _client);
+ routing_->notify_one(_service, _instance, _event, _payload, _client,
+ _force);
}
}
@@ -597,6 +675,7 @@ void application_impl::unregister_state_handler() {
void application_impl::register_availability_handler(service_t _service,
instance_t _instance, availability_handler_t _handler,
major_version_t _major, minor_version_t _minor) {
+ std::lock_guard<std::mutex> availability_lock(availability_mutex_);
if (state_ == state_type_e::ST_REGISTERED) {
do_register_availability_handler(_service, _instance,
_handler, _major, _minor);
@@ -609,23 +688,19 @@ void application_impl::register_availability_handler(service_t _service,
void application_impl::do_register_availability_handler(service_t _service,
instance_t _instance, availability_handler_t _handler,
major_version_t _major, minor_version_t _minor) {
-
- {
- std::unique_lock<std::mutex> availability_lock(availability_mutex_);
available_t available;
- bool are_available = are_available_unlocked(available, _service, _instance, _major, _minor);
- availability_[_service][_instance] = std::make_tuple(_major, _minor, _handler, true);
+ bool are_available = are_available_unlocked(available, _service, _instance, _major, _minor);
+ availability_[_service][_instance] = std::make_tuple(_major, _minor, _handler, true);
- std::lock_guard<std::mutex> handlers_lock(handlers_mutex_);
+ std::lock_guard<std::mutex> handlers_lock(handlers_mutex_);
- std::shared_ptr<sync_handler> its_sync_handler
- = std::make_shared<sync_handler>([_handler, are_available, available]() {
- for(auto available_services_it : available)
- for(auto available_instances_it : available_services_it.second)
- _handler(available_services_it.first, available_instances_it.first, are_available);
- });
- handlers_.push_back(its_sync_handler);
- }
+ std::shared_ptr<sync_handler> its_sync_handler
+ = std::make_shared<sync_handler>([_handler, are_available, available]() {
+ for(auto available_services_it : available)
+ for(auto available_instances_it : available_services_it.second)
+ _handler(available_services_it.first, available_instances_it.first, are_available);
+ });
+ handlers_.push_back(its_sync_handler);
dispatcher_condition_.notify_one();
}
@@ -770,10 +845,21 @@ void application_impl::unregister_message_handler(service_t _service,
}
void application_impl::offer_event(service_t _service, instance_t _instance,
- event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field) {
+ event_t _event, const std::set<eventgroup_t> &_eventgroups,
+ bool _is_field) {
+ return offer_event(_service, _instance, _event, _eventgroups, _is_field,
+ std::chrono::milliseconds::zero(), false, nullptr);
+}
+
+void application_impl::offer_event(service_t _service, instance_t _instance,
+ event_t _event, const std::set<eventgroup_t> &_eventgroups,
+ bool _is_field,
+ std::chrono::milliseconds _cycle, bool _change_resets_cycle,
+ const epsilon_change_func_t &_epsilon_change_func) {
if (routing_)
routing_->register_event(client_, _service, _instance, _event,
- _eventgroups, _is_field, true);
+ _eventgroups, _is_field, _cycle, _change_resets_cycle,
+ _epsilon_change_func, true);
}
void application_impl::stop_offer_event(service_t _service, instance_t _instance,
@@ -783,10 +869,14 @@ void application_impl::stop_offer_event(service_t _service, instance_t _instance
}
void application_impl::request_event(service_t _service, instance_t _instance,
- event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field) {
+ event_t _event, const std::set<eventgroup_t> &_eventgroups,
+ bool _is_field) {
if (routing_)
routing_->register_event(client_, _service, _instance, _event,
- _eventgroups, _is_field, false);
+ _eventgroups, _is_field,
+ std::chrono::milliseconds::zero(), false,
+ nullptr,
+ false);
}
void application_impl::release_event(service_t _service, instance_t _instance,
@@ -829,6 +919,7 @@ void application_impl::on_state(state_type_e _state) {
if (state_ != _state) {
state_ = _state;
if (state_ == state_type_e::ST_REGISTERED) {
+ std::lock_guard<std::mutex> availability_lock(availability_mutex_);
for (auto &its_service : availability_) {
for (auto &its_instance : its_service.second) {
if (!std::get<3>(its_instance.second)) {
@@ -847,9 +938,10 @@ void application_impl::on_state(state_type_e _state) {
{
std::lock_guard<std::mutex> its_lock(handlers_mutex_);
+ state_handler_t handler = handler_;
std::shared_ptr<sync_handler> its_sync_handler
- = std::make_shared<sync_handler>([this, _state]() {
- handler_(_state);
+ = std::make_shared<sync_handler>([handler, _state]() {
+ handler(_state);
});
handlers_.push_back(its_sync_handler);
@@ -897,16 +989,9 @@ void application_impl::on_availability(service_t _service, instance_t _instance,
if( found_instance != found_service->second.end()) {
auto found_version = found_instance->second;
auto requested_major = std::get<0>(found_version);
- auto requested_minor = std::get<1>(found_version);
if(requested_major == _major) {
- if(requested_minor <= _minor ) {
- has_handler = true;
- its_handler = std::get<2>(found_version);
- }
- } else if (requested_major == DEFAULT_MAJOR &&
- requested_minor == DEFAULT_MINOR) {
- has_handler = true;
- its_handler = std::get<2>(found_version);
+ has_handler = true;
+ its_handler = std::get<2>(found_version);
}
}
@@ -915,16 +1000,9 @@ void application_impl::on_availability(service_t _service, instance_t _instance,
if( found_instance != found_service->second.end()) {
auto found_version = found_instance->second;
auto requested_major = std::get<0>(found_version);
- auto requested_minor = std::get<1>(found_version);
if(requested_major == ANY_MAJOR) {
- if(requested_minor == ANY_MINOR) {
- has_wildcard_handler = true;
- its_wildcard_handler = std::get<2>(found_version);
- }
- } else if (requested_major == DEFAULT_MAJOR &&
- requested_minor == DEFAULT_MINOR) {
- has_handler = true;
- its_handler = std::get<2>(found_version);
+ has_wildcard_handler = true;
+ its_wildcard_handler = std::get<2>(found_version);
}
}
}
@@ -976,10 +1054,6 @@ void application_impl::on_message(std::shared_ptr<message> _message) {
instance_t its_instance = _message->get_instance();
method_t its_method = _message->get_method();
- std::map<method_t, message_handler_t>::iterator found_method;
- message_handler_t its_handler;
- bool has_handler(false);
-
if (_message->get_message_type() == message_type_e::MT_NOTIFICATION) {
std::lock_guard<std::mutex> its_lock(event_subscriptions_mutex_);
auto found_service = event_subscriptions_.find(its_service);
@@ -1010,39 +1084,68 @@ void application_impl::on_message(std::shared_ptr<message> _message) {
{
std::lock_guard<std::mutex> its_lock(members_mutex_);
-
+ std::set<message_handler> its_handlers;
auto found_service = members_.find(its_service);
- if (found_service == members_.end()) {
- found_service = members_.find(ANY_SERVICE);
- }
if (found_service != members_.end()) {
auto found_instance = found_service->second.find(its_instance);
- if (found_instance == found_service->second.end()) {
- found_instance = found_service->second.find(ANY_INSTANCE);
- }
if (found_instance != found_service->second.end()) {
auto found_method = found_instance->second.find(its_method);
- if (found_method == found_instance->second.end()) {
- found_method = found_instance->second.find(ANY_METHOD);
+ if (found_method != found_instance->second.end()) {
+ its_handlers.insert(found_method->second);
}
-
+ auto found_any_method = found_instance->second.find(ANY_METHOD);
+ if (found_any_method != found_instance->second.end()) {
+ its_handlers.insert(found_any_method->second);
+ }
+ }
+ auto found_any_instance = found_service->second.find(ANY_INSTANCE);
+ if (found_any_instance != found_service->second.end()) {
+ auto found_method = found_any_instance->second.find(its_method);
+ if (found_method != found_any_instance->second.end()) {
+ its_handlers.insert(found_method->second);
+ }
+ auto found_any_method = found_any_instance->second.find(ANY_METHOD);
+ if (found_any_method != found_any_instance->second.end()) {
+ its_handlers.insert(found_any_method->second);
+ }
+ }
+ }
+ auto found_any_service = members_.find(ANY_SERVICE);
+ if (found_any_service != members_.end()) {
+ auto found_instance = found_any_service->second.find(its_instance);
+ if (found_instance != found_any_service->second.end()) {
+ auto found_method = found_instance->second.find(its_method);
if (found_method != found_instance->second.end()) {
- its_handler = found_method->second;
- has_handler = true;
+ its_handlers.insert(found_method->second);
+ }
+ auto found_any_method = found_instance->second.find(ANY_METHOD);
+ if (found_any_method != found_instance->second.end()) {
+ its_handlers.insert(found_any_method->second);
+ }
+ }
+ auto found_any_instance = found_any_service->second.find(ANY_INSTANCE);
+ if (found_any_instance != found_any_service->second.end()) {
+ auto found_method = found_any_instance->second.find(its_method);
+ if (found_method != found_any_instance->second.end()) {
+ its_handlers.insert(found_method->second);
+ }
+ auto found_any_method = found_any_instance->second.find(ANY_METHOD);
+ if (found_any_method != found_any_instance->second.end()) {
+ its_handlers.insert(found_any_method->second);
}
}
}
- if (has_handler) {
+ if (its_handlers.size()) {
std::lock_guard<std::mutex> its_lock(handlers_mutex_);
- std::shared_ptr<sync_handler> its_sync_handler
- = std::make_shared<sync_handler>(
- [its_handler, _message]() {
- its_handler(_message);
- }
- );
-
- handlers_.push_back(its_sync_handler);
+ for (const auto &its_handler : its_handlers) {
+ auto handler = its_handler.handler_;
+ std::shared_ptr<sync_handler> its_sync_handler =
+ std::make_shared<sync_handler>([handler, _message]() {
+ handler(_message);
+ });
+ handlers_.push_back(its_sync_handler);
+ }
}
dispatcher_condition_.notify_one();
}
@@ -1071,7 +1174,9 @@ void application_impl::main_dispatch() {
// Cancel other waiting dispatcher
dispatcher_condition_.notify_all();
// Wait for new handlers to execute
- dispatcher_condition_.wait(its_lock);
+ while (handlers_.empty() && is_dispatching_) {
+ dispatcher_condition_.wait(its_lock);
+ }
} else {
while (!handlers_.empty()) {
std::shared_ptr<sync_handler> its_handler = handlers_.front();
@@ -1132,7 +1237,7 @@ void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) {
std::bind(&application_impl::dispatch, this));
dispatchers_[its_dispatcher->get_id()] = its_dispatcher;
} else {
- VSOMEIP_DEBUG << "Maximum number of dispatchers exceeded.";
+ VSOMEIP_ERROR << "Maximum number of dispatchers exceeded.";
}
}
});
@@ -1189,39 +1294,50 @@ void application_impl::clear_all_handler() {
std::lock_guard<std::mutex> its_lock(members_mutex_);
members_.clear();
}
+ {
+ std::unique_lock<std::mutex> its_lock(handlers_mutex_);
+ handlers_.clear();
+ }
}
-void application_impl::wait_for_stop() {
-
+void application_impl::shutdown() {
{
std::unique_lock<std::mutex> its_lock(start_stop_mutex_);
while(!stopped_) {
stop_cv_.wait(its_lock);
}
- stopped_ = false;
-
- // join dispatch threads
+ }
+ {
+ std::unique_lock<std::mutex> its_lock(handlers_mutex_);
is_dispatching_ = false;
- dispatcher_condition_.notify_all();
}
-
+ dispatcher_condition_.notify_all();
for (auto its_dispatcher : dispatchers_) {
- if (its_dispatcher.second->joinable())
- its_dispatcher.second->join();
+ if (its_dispatcher.second->get_id() != stop_caller_id_) {
+ if (its_dispatcher.second->joinable()) {
+ its_dispatcher.second->join();
+ }
+ } else {
+ // If the caller of stop() is one of our dispatchers
+ // it can happen the shutdown mechanism will block
+ // as that thread probably can't be joined. The reason
+ // is the caller of stop() probably wants to join the
+ // thread once call start (which got to the IO-Thread)
+ // and which is expected to return after stop() has been
+ // called.
+ // Therefore detach this thread instead of joining because
+ // after it will return to "main_dispatch" it will be
+ // properly shutdown anyways because "is_dispatching_"
+ // was set to "false" here.
+ its_dispatcher.second->detach();
+ }
}
if (routing_)
routing_->stop();
+ work_.reset();
io_.stop();
-
- {
- std::unique_lock<std::mutex> its_lock(start_stop_mutex_);
- while(!stopped_) {
- stop_cv_.wait(its_lock);
- }
- stopped_ = false;
- }
}
bool application_impl::is_routing() const {
diff --git a/implementation/service_discovery/include/defines.hpp b/implementation/service_discovery/include/defines.hpp
index 52c7216..a0129b6 100644
--- a/implementation/service_discovery/include/defines.hpp
+++ b/implementation/service_discovery/include/defines.hpp
@@ -12,11 +12,15 @@
#define VSOMEIP_MAX_UDP_SD_PAYLOAD 1380
#define VSOMEIP_SOMEIP_SD_DATA_SIZE 12
+#define VSOMEIP_SOMEIP_SD_ENTRY_LENGTH_SIZE 4
#define VSOMEIP_SOMEIP_SD_ENTRY_SIZE 16
#define VSOMEIP_SOMEIP_SD_IPV4_OPTION_SIZE 12
#define VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE 24
+#define VSOMEIP_SOMEIP_SD_OPTION_LENGTH_SIZE 4
#define VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE 3
+
+
#define VSOMEIP_SD_IPV4_OPTION_LENGTH 0x0009
#define VSOMEIP_SD_IPV6_OPTION_LENGTH 0x0015
diff --git a/implementation/service_discovery/include/fsm_base.hpp b/implementation/service_discovery/include/fsm_base.hpp
index ede92d3..b04f9a6 100644
--- a/implementation/service_discovery/include/fsm_base.hpp
+++ b/implementation/service_discovery/include/fsm_base.hpp
@@ -9,7 +9,7 @@
#include <memory>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/system_timer.hpp>
+#include <boost/asio/steady_timer.hpp>
namespace vsomeip {
namespace sd {
@@ -28,8 +28,8 @@ public:
bool _use_alt_timer) = 0;
private:
- boost::asio::system_timer timer_;
- boost::asio::system_timer alt_timer_;
+ boost::asio::steady_timer timer_;
+ boost::asio::steady_timer alt_timer_;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/ip_option_impl.hpp b/implementation/service_discovery/include/ip_option_impl.hpp
index e753b4e..e1344db 100644
--- a/implementation/service_discovery/include/ip_option_impl.hpp
+++ b/implementation/service_discovery/include/ip_option_impl.hpp
@@ -25,7 +25,7 @@ public:
layer_four_protocol_e get_layer_four_protocol() const;
void set_layer_four_protocol(layer_four_protocol_e _protocol);
- bool is_multicast() const;
+ virtual bool is_multicast() const = 0;
virtual bool serialize(vsomeip::serializer *_to) const = 0;
virtual bool deserialize(vsomeip::deserializer *_from) = 0;
diff --git a/implementation/service_discovery/include/ipv4_option_impl.hpp b/implementation/service_discovery/include/ipv4_option_impl.hpp
index c233f0f..fd80be9 100644
--- a/implementation/service_discovery/include/ipv4_option_impl.hpp
+++ b/implementation/service_discovery/include/ipv4_option_impl.hpp
@@ -21,6 +21,7 @@ public:
const ipv4_address_t & get_address() const;
void set_address(const ipv4_address_t &_address);
+ bool is_multicast() const;
bool serialize(vsomeip::serializer *_to) const;
bool deserialize(vsomeip::deserializer *_from);
diff --git a/implementation/service_discovery/include/ipv6_option_impl.hpp b/implementation/service_discovery/include/ipv6_option_impl.hpp
index c2b962f..c6fd270 100644
--- a/implementation/service_discovery/include/ipv6_option_impl.hpp
+++ b/implementation/service_discovery/include/ipv6_option_impl.hpp
@@ -21,6 +21,7 @@ public:
const ipv6_address_t & get_address() const;
void set_address(const ipv6_address_t &_address);
+ bool is_multicast() const;
bool serialize(vsomeip::serializer *_to) const;
bool deserialize(vsomeip::deserializer *_from);
diff --git a/implementation/service_discovery/include/message_impl.hpp b/implementation/service_discovery/include/message_impl.hpp
index a8573b8..add6fb4 100755
--- a/implementation/service_discovery/include/message_impl.hpp
+++ b/implementation/service_discovery/include/message_impl.hpp
@@ -73,6 +73,8 @@ public:
bool serialize(vsomeip::serializer *_to) const;
bool deserialize(vsomeip::deserializer *_from);
+ length_t get_someip_length() const;
+
private:
entry_impl * deserialize_entry(vsomeip::deserializer *_from);
option_impl * deserialize_option(vsomeip::deserializer *_from);
diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp
index 1795d89..3f7a594 100644
--- a/implementation/service_discovery/include/service_discovery_host.hpp
+++ b/implementation/service_discovery/include/service_discovery_host.hpp
@@ -43,7 +43,7 @@ public:
virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target,
const byte_t *_data, uint32_t _size, uint16_t _sd_port) = 0;
- virtual void add_routing_info(service_t _service, instance_t _instance,
+ virtual std::chrono::milliseconds add_routing_info(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor, ttl_t _ttl,
const boost::asio::ip::address &_reliable_address,
uint16_t _reliable_port,
@@ -60,7 +60,7 @@ public:
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _subscriber,
std::shared_ptr<endpoint_definition> _target,
- const std::chrono::high_resolution_clock::time_point &_expiration) = 0;
+ const std::chrono::steady_clock::time_point &_expiration) = 0;
virtual void on_unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
@@ -81,7 +81,7 @@ public:
virtual bool on_subscribe_accepted(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _target,
- const std::chrono::high_resolution_clock::time_point &_expiration) = 0;
+ const std::chrono::steady_clock::time_point &_expiration) = 0;
virtual void on_subscribe_nack(client_t _client,
service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0;
@@ -89,7 +89,7 @@ public:
virtual bool has_identified(client_t _client, service_t _service,
instance_t _instance, bool _reliable) = 0;
- virtual std::chrono::high_resolution_clock::time_point expire_subscriptions() = 0;
+ virtual std::chrono::steady_clock::time_point expire_subscriptions() = 0;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp
index 4e64328..910037d 100644
--- a/implementation/service_discovery/include/service_discovery_impl.hpp
+++ b/implementation/service_discovery/include/service_discovery_impl.hpp
@@ -11,7 +11,7 @@
#include <mutex>
#include <set>
-#include <boost/asio/system_timer.hpp>
+#include <boost/asio/steady_timer.hpp>
#include "service_discovery.hpp"
#include "../../endpoints/include/endpoint_definition.hpp"
@@ -41,7 +41,7 @@ typedef std::map<service_t, std::map<instance_t, std::shared_ptr<request> > > re
struct accepted_subscriber_t {
std::shared_ptr < endpoint_definition > subscriber;
std::shared_ptr < endpoint_definition > target;
- std::chrono::high_resolution_clock::time_point its_expiration;
+ std::chrono::steady_clock::time_point its_expiration;
vsomeip::service_t service_id;
vsomeip::instance_t instance_id;
vsomeip::eventgroup_t eventgroup_;
@@ -189,12 +189,6 @@ private:
bool check_static_header_fields(
const std::shared_ptr<const message> &_message) const;
- void send_eventgroup_subscription_nack(service_t _service,
- instance_t _instance,
- eventgroup_t _eventgroup,
- major_version_t _major,
- uint8_t _counter,
- uint16_t _reserved);
bool check_layer_four_protocol(
const std::shared_ptr<const ip_option_impl> _ip_option) const;
void get_subscription_endpoints(subscription_type_e _subscription_type,
@@ -262,13 +256,13 @@ private:
std::weak_ptr<runtime> runtime_;
// TTL handling for services offered by other hosts
- boost::asio::system_timer ttl_timer_;
+ boost::asio::steady_timer ttl_timer_;
std::chrono::milliseconds smallest_ttl_;
ttl_t ttl_;
// TTL handling for subscriptions done by other hosts
- boost::asio::system_timer subscription_expiration_timer_;
- std::chrono::high_resolution_clock::time_point next_subscription_expiration_;
+ boost::asio::steady_timer subscription_expiration_timer_;
+ std::chrono::steady_clock::time_point next_subscription_expiration_;
uint32_t max_message_size_;
};
diff --git a/implementation/service_discovery/include/subscription.hpp b/implementation/service_discovery/include/subscription.hpp
index eb2fb66..3cdcd34 100644
--- a/implementation/service_discovery/include/subscription.hpp
+++ b/implementation/service_discovery/include/subscription.hpp
@@ -25,7 +25,7 @@ public:
std::shared_ptr<endpoint> _unreliable,
subscription_type_e _subscription_type,
uint8_t _counter,
- std::chrono::high_resolution_clock::time_point _expiration);
+ std::chrono::steady_clock::time_point _expiration);
~subscription();
major_version_t get_major() const;
@@ -44,8 +44,8 @@ public:
uint8_t get_counter() const;
- std::chrono::high_resolution_clock::time_point get_expiration() const;
- void set_expiration(std::chrono::high_resolution_clock::time_point _expiration);
+ std::chrono::steady_clock::time_point get_expiration() const;
+ void set_expiration(std::chrono::steady_clock::time_point _expiration);
private:
major_version_t major_;
@@ -61,7 +61,7 @@ private:
uint8_t counter_;
- std::chrono::high_resolution_clock::time_point expiration_;
+ std::chrono::steady_clock::time_point expiration_;
};
} // namespace sd
diff --git a/implementation/service_discovery/src/entry_impl.cpp b/implementation/service_discovery/src/entry_impl.cpp
index efff9da..0637383 100755
--- a/implementation/service_discovery/src/entry_impl.cpp
+++ b/implementation/service_discovery/src/entry_impl.cpp
@@ -9,6 +9,7 @@
#include "../include/message_impl.hpp"
#include "../../message/include/deserializer.hpp"
#include "../../message/include/serializer.hpp"
+#include "../../logging/include/logger.hpp"
namespace vsomeip {
namespace sd {
@@ -87,25 +88,20 @@ const std::vector<uint8_t> & entry_impl::get_options(uint8_t _run) const {
void entry_impl::assign_option(const std::shared_ptr<option_impl> &_option) {
uint8_t option_index = uint8_t(get_owning_message()->get_option_index(_option));
- if (0x10 > option_index) { // as we have only a nibble for the option counter
- if (options_[0].empty() ||
+ if (options_[0].empty() ||
options_[0][0] == option_index + 1 ||
options_[0][options_[0].size() - 1] + 1 == option_index) {
- options_[0].push_back(option_index);
- std::sort(options_[0].begin(), options_[0].end());
- num_options_[0]++;
- } else
- if (options_[1].empty() ||
+ options_[0].push_back(option_index);
+ std::sort(options_[0].begin(), options_[0].end());
+ num_options_[0]++;
+ } else if (options_[1].empty() ||
options_[1][0] == option_index + 1 ||
options_[1][options_[1].size() - 1] + 1 == option_index) {
- options_[1].push_back(option_index);
- std::sort(options_[1].begin(), options_[1].end());
- num_options_[1]++;
- } else {
- // TODO: copy data
- }
+ options_[1].push_back(option_index);
+ std::sort(options_[1].begin(), options_[1].end());
+ num_options_[1]++;
} else {
- // TODO: decide what to do if option does not belong to the message.
+ VSOMEIP_WARNING << "Option is not referenced by entries array, maximum number of endpoint options reached!";
}
}
@@ -143,25 +139,25 @@ bool entry_impl::deserialize(vsomeip::deserializer *_from) {
is_successful = is_successful && _from->deserialize(its_type);
type_ = static_cast<entry_type_e>(its_type);
- uint8_t its_index1;
+ uint8_t its_index1(0);
is_successful = is_successful && _from->deserialize(its_index1);
- uint8_t its_index2;
+ uint8_t its_index2(0);
is_successful = is_successful && _from->deserialize(its_index2);
- uint8_t its_numbers;
+ uint8_t its_numbers(0);
is_successful = is_successful && _from->deserialize(its_numbers);
num_options_[0] = uint8_t(its_numbers >> 4);
num_options_[1] = uint8_t(its_numbers & 0xF);
- for (uint8_t i = its_index1; i < its_index1 + num_options_[0]; ++i)
- options_[0].push_back(i);
+ for (uint16_t i = its_index1; i < its_index1 + num_options_[0]; ++i)
+ options_[0].push_back((uint8_t)(i));
- for (uint8_t i = its_index2; i < its_index2 + num_options_[1]; ++i)
- options_[1].push_back(i);
+ for (uint16_t i = its_index2; i < its_index2 + num_options_[1]; ++i)
+ options_[1].push_back((uint8_t)(i));
- uint16_t its_id;
+ uint16_t its_id(0);
is_successful = is_successful && _from->deserialize(its_id);
service_ = static_cast<service_t>(its_id);
diff --git a/implementation/service_discovery/src/eventgroupentry_impl.cpp b/implementation/service_discovery/src/eventgroupentry_impl.cpp
index 220fc47..56ad9b0 100755
--- a/implementation/service_discovery/src/eventgroupentry_impl.cpp
+++ b/implementation/service_discovery/src/eventgroupentry_impl.cpp
@@ -11,13 +11,15 @@
namespace vsomeip {
namespace sd {
-eventgroupentry_impl::eventgroupentry_impl() {
+eventgroupentry_impl::eventgroupentry_impl() :
+ reserved_(0) {
eventgroup_ = 0xFFFF;
counter_ = 0;
}
eventgroupentry_impl::eventgroupentry_impl(const eventgroupentry_impl &_entry)
- : entry_impl(_entry) {
+ : entry_impl(_entry),
+ reserved_(0) {
eventgroup_ = _entry.eventgroup_;
counter_ = _entry.counter_;
}
@@ -84,15 +86,15 @@ bool eventgroupentry_impl::serialize(vsomeip::serializer *_to) const {
bool eventgroupentry_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful = entry_impl::deserialize(_from);
- uint8_t tmp_major_version;
+ uint8_t tmp_major_version(0);
is_successful = is_successful && _from->deserialize(tmp_major_version);
major_version_ = static_cast<major_version_t>(tmp_major_version);
- uint32_t its_ttl;
+ uint32_t its_ttl(0);
is_successful = is_successful && _from->deserialize(its_ttl, true);
ttl_ = static_cast<ttl_t>(its_ttl);
- uint8_t reserved1, reserved2;
+ uint8_t reserved1(0), reserved2(0);
is_successful = is_successful && _from->deserialize(reserved1); // deserialize reserved part 1
is_successful = is_successful && _from->deserialize(reserved2); // deserialize reserved part 2 and counter
diff --git a/implementation/service_discovery/src/ip_option_impl.cpp b/implementation/service_discovery/src/ip_option_impl.cpp
index 08f78b9..2dc5799 100644
--- a/implementation/service_discovery/src/ip_option_impl.cpp
+++ b/implementation/service_discovery/src/ip_option_impl.cpp
@@ -49,11 +49,6 @@ void ip_option_impl::set_layer_four_protocol(
protocol_ = _protocol;
}
-bool ip_option_impl::is_multicast() const {
- return (type_ == option_type_e::IP4_MULTICAST
- || type_ == option_type_e::IP6_MULTICAST);
-}
-
} // namespace sd
} // namespace vsomeip
diff --git a/implementation/service_discovery/src/ipv4_option_impl.cpp b/implementation/service_discovery/src/ipv4_option_impl.cpp
index 9f2cec4..2551bb0 100644
--- a/implementation/service_discovery/src/ipv4_option_impl.cpp
+++ b/implementation/service_discovery/src/ipv4_option_impl.cpp
@@ -33,6 +33,10 @@ void ipv4_option_impl::set_address(const ipv4_address_t &_address) {
address_ = _address;
}
+bool ipv4_option_impl::is_multicast() const {
+ return (type_ == option_type_e::IP4_MULTICAST);
+}
+
bool ipv4_option_impl::serialize(vsomeip::serializer *_to) const {
bool is_successful = option_impl::serialize(_to);
_to->serialize(&address_[0], uint32_t(address_.size()));
diff --git a/implementation/service_discovery/src/ipv6_option_impl.cpp b/implementation/service_discovery/src/ipv6_option_impl.cpp
index 089b509..28a2f02 100755
--- a/implementation/service_discovery/src/ipv6_option_impl.cpp
+++ b/implementation/service_discovery/src/ipv6_option_impl.cpp
@@ -33,6 +33,10 @@ void ipv6_option_impl::set_address(const ipv6_address_t &_address) {
address_ = _address;
}
+bool ipv6_option_impl::is_multicast() const {
+ return (type_ == option_type_e::IP6_MULTICAST);
+}
+
bool ipv6_option_impl::serialize(vsomeip::serializer *_to) const {
bool is_successful = option_impl::serialize(_to);
_to->serialize(&address_[0], uint32_t(address_.size()));
diff --git a/implementation/service_discovery/src/message_impl.cpp b/implementation/service_discovery/src/message_impl.cpp
index 8159bd4..dc9df91 100755
--- a/implementation/service_discovery/src/message_impl.cpp
+++ b/implementation/service_discovery/src/message_impl.cpp
@@ -38,12 +38,18 @@ message_impl::~message_impl() {
}
length_t message_impl::get_length() const {
- length_t current_length = (VSOMEIP_SOMEIP_HEADER_SIZE
- + VSOMEIP_SOMEIP_SD_DATA_SIZE);
- current_length += uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE);
- for (size_t i = 0; i < options_.size(); ++i) {
- current_length += (options_[i]->get_length()
- + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE);
+ length_t current_length = VSOMEIP_SOMEIP_SD_DATA_SIZE;
+ if( entries_.size()) {
+ current_length += VSOMEIP_SOMEIP_SD_ENTRY_LENGTH_SIZE;
+ current_length += uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE);
+ }
+
+ current_length += VSOMEIP_SOMEIP_SD_OPTION_LENGTH_SIZE;
+ if(options_.size()) {
+ for (size_t i = 0; i < options_.size(); ++i) {
+ current_length += (options_[i]->get_length()
+ + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE);
+ }
}
return current_length;
}
@@ -356,5 +362,9 @@ option_impl * message_impl::deserialize_option(vsomeip::deserializer *_from) {
return deserialized_option;
}
+length_t message_impl::get_someip_length() const {
+ return header_.length_;
+}
+
} // namespace sd
} // namespace vsomeip
diff --git a/implementation/service_discovery/src/option_impl.cpp b/implementation/service_discovery/src/option_impl.cpp
index 71aa085..8d2a11d 100755
--- a/implementation/service_discovery/src/option_impl.cpp
+++ b/implementation/service_discovery/src/option_impl.cpp
@@ -11,9 +11,9 @@
namespace vsomeip {
namespace sd {
-option_impl::option_impl() {
- length_ = 0;
- type_ = option_type_e::UNKNOWN;
+option_impl::option_impl() :
+ length_(0),
+ type_(option_type_e::UNKNOWN) {
}
option_impl::~option_impl() {
diff --git a/implementation/service_discovery/src/runtime.cpp b/implementation/service_discovery/src/runtime.cpp
index be68d24..3d12892 100644
--- a/implementation/service_discovery/src/runtime.cpp
+++ b/implementation/service_discovery/src/runtime.cpp
@@ -12,7 +12,7 @@ extern "C"
__declspec(dllexport) std::shared_ptr<vsomeip::sd::runtime> VSOMEIP_SD_RUNTIME_SYMBOL;
}
#else
-std::shared_ptr<vsomeip::sd::runtime> VSOMEIP_SD_RUNTIME_SYMBOL;
+std::shared_ptr<vsomeip::sd::runtime> VSOMEIP_SD_RUNTIME_SYMBOL(vsomeip::sd::runtime::get());
#endif
#ifdef WIN32
@@ -22,16 +22,11 @@ std::shared_ptr<vsomeip::sd::runtime> VSOMEIP_SD_RUNTIME_SYMBOL;
static void __cdecl f(void); \
__declspec(allocate(".CRT$XCU")) void(__cdecl*f##_)(void) = f; \
static void __cdecl f(void)
-#else
-#define CCALL
-#define INITIALIZER(f) \
- static void f(void) __attribute__((constructor)); \
- static void f(void)
-#endif
INITIALIZER(init_vsomeip_sd) {
VSOMEIP_SD_RUNTIME_SYMBOL = vsomeip::sd::runtime::get();
}
+#endif
namespace vsomeip {
namespace sd {
diff --git a/implementation/service_discovery/src/service_discovery_fsm.cpp b/implementation/service_discovery/src/service_discovery_fsm.cpp
index a4ede7b..ba1bd18 100644
--- a/implementation/service_discovery/src/service_discovery_fsm.cpp
+++ b/implementation/service_discovery/src/service_discovery_fsm.cpp
@@ -122,6 +122,12 @@ initial::initial(my_context _context)
sc::result initial::react(const ev_timeout &_event) {
(void)_event;
+ VSOMEIP_TRACE << "sd::active.initial.react";
+ std::shared_ptr < service_discovery_fsm > fsm =
+ outermost_context().fsm_.lock();
+ if (fsm) {
+ (void)fsm->send(false, false);
+ }
return transit<repeat>();
}
@@ -151,11 +157,11 @@ sc::result repeat::react(const ev_timeout &_event) {
}
sc::result repeat::react(const ev_find_service &_event) {
- VSOMEIP_TRACE << "sd::active.repeat.react.find";
std::shared_ptr < service_discovery_fsm > fsm =
outermost_context().fsm_.lock();
// Answer Find Service messages with unicast offer in repetition phase
if (fsm) {
+ VSOMEIP_TRACE << "sd::active.repeat.react.find";
fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_,
_event.major_, _event.minor_);
}
@@ -195,7 +201,7 @@ sc::result offer::react(const ev_find_service &_event) {
std::shared_ptr < service_discovery_fsm > fsm =
outermost_context().fsm_.lock();
if (fsm) {
- if(_event.unicast_flag_) {
+ if(_event.unicast_flag_) { //SIP_SD_826
if( !fsm->check_is_multicast_offer()) { // SIP_SD_89
fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_,
_event.major_, _event.minor_);
@@ -203,8 +209,8 @@ sc::result offer::react(const ev_find_service &_event) {
fsm->send_multicast_offer_service(_event.info_, _event.service_, _event.instance_,
_event.major_, _event.minor_);
}
- } else { // SIP_SD_91
- fsm->send_multicast_offer_service(_event.info_, _event.service_, _event.instance_,
+ } else { // SIP_SD_824
+ fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_,
_event.major_, _event.minor_);
}
}
@@ -247,15 +253,16 @@ send::send(my_context _context)
outermost_context().fsm_.lock();
if (fsm) {
VSOMEIP_TRACE << "sd::active.main.find.send";
- // Increment to the maximum run value (which is repetition_max-1)
- // As new request might be added in the meantime, this will be
- // used to calculate the maximum cycle time.
- if (context<find>().run_ < fsm->get_repetition_max()) {
- context<find>().run_++;
+ if( context<find>().run_ == 0)
+ {
+ outermost_context().start_timer(outermost_context().initial_delay_, true);
+ } else if ( context<find>().run_ < fsm->get_repetition_max() + 1 ) {
+ // Increment to the maximum run value (which is repetition_max-1)
+ // As new request might be added in the meantime, this will be
+ // used to calculate the maximum cycle time.
uint32_t its_timeout = (outermost_context().repetitions_base_delay_
<< context<find>().run_);
- if (fsm->send(true, true))
- outermost_context().start_timer(its_timeout, true);
+ outermost_context().start_timer(its_timeout, true);
}
else {
post_event(ev_none());
@@ -267,6 +274,13 @@ send::send(my_context _context)
sc::result send::react(const ev_alt_timeout &_event) {
(void)_event;
+ std::shared_ptr < service_discovery_fsm > fsm =
+ outermost_context().fsm_.lock();
+ if (fsm) {
+ VSOMEIP_TRACE << "sd::active.main.find.initial";
+ context<find>().run_++;
+ (void)fsm->send(true, true);
+ }
return transit<send>();
}
diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp
index 10c6c96..78af86b 100644
--- a/implementation/service_discovery/src/service_discovery_impl.cpp
+++ b/implementation/service_discovery/src/service_discovery_impl.cpp
@@ -5,6 +5,8 @@
#include <vsomeip/constants.hpp>
+#include <forward_list>
+
#include "../include/constants.hpp"
#include "../include/defines.hpp"
#include "../include/deserializer.hpp"
@@ -46,7 +48,7 @@ service_discovery_impl::service_discovery_impl(service_discovery_host *_host)
smallest_ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(smallest_ttl);
// TODO: cleanup start condition!
- next_subscription_expiration_ = std::chrono::high_resolution_clock::now() + std::chrono::hours(24);
+ next_subscription_expiration_ = std::chrono::steady_clock::now() + std::chrono::hours(24);
}
service_discovery_impl::~service_discovery_impl() {
@@ -153,28 +155,39 @@ service_discovery_impl::find_request(service_t _service, instance_t _instance) {
void service_discovery_impl::subscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, major_version_t _major, ttl_t _ttl, client_t _client,
subscription_type_e _subscription_type) {
- std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
- auto found_service = subscribed_.find(_service);
- if (found_service != subscribed_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- auto found_eventgroup = found_instance->second.find(_eventgroup);
- if (found_eventgroup != found_instance->second.end()) {
- auto found_client = found_eventgroup->second.find(_client);
- if (found_client != found_eventgroup->second.end()) {
- if (found_client->second->get_major() == _major) {
- found_client->second->set_ttl(_ttl);
- found_client->second->set_expiration(std::chrono::high_resolution_clock::now()
- + std::chrono::seconds(_ttl));
- } else {
- VSOMEIP_ERROR
- << "Subscriptions to different versions of the same "
- "service instance are not supported!";
+ uint8_t subscribe_count(0);
+ {
+ std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ auto found_service = subscribed_.find(_service);
+ if (found_service != subscribed_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_eventgroup = found_instance->second.find(_eventgroup);
+ if (found_eventgroup != found_instance->second.end()) {
+ auto found_client = found_eventgroup->second.find(_client);
+ if (found_client != found_eventgroup->second.end()) {
+ if (found_client->second->get_major() == _major) {
+ found_client->second->set_ttl(_ttl);
+ found_client->second->set_expiration(std::chrono::steady_clock::now()
+ + std::chrono::seconds(_ttl));
+ } else {
+ VSOMEIP_ERROR
+ << "Subscriptions to different versions of the same "
+ "service instance are not supported!";
+ }
+ return;
}
- return;
}
}
}
+
+ const uint8_t max_parallel_subscriptions = 16; // 4Bit Counter field
+ subscribe_count = static_cast<uint8_t>(subscribed_[_service][_instance][_eventgroup].size());
+ if (subscribe_count >= max_parallel_subscriptions) {
+ VSOMEIP_WARNING << "Too many parallel subscriptions (max.16) on same event group: "
+ << std::hex << _eventgroup << std::dec;
+ return;
+ }
}
std::shared_ptr < endpoint > its_unreliable;
@@ -185,57 +198,54 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance,
get_subscription_endpoints(_subscription_type, its_unreliable, its_reliable,
&its_address, &has_address, _service, _instance, _client);
- const uint8_t max_parallel_subscriptions = 16; // 4Bit Counter field
- uint8_t subscribe_count = static_cast<uint8_t>(subscribed_[_service][_instance][_eventgroup].size());
- if (subscribe_count >= max_parallel_subscriptions) {
- VSOMEIP_WARNING << "Too many parallel subscriptions (max.16) on same event group: "
- << std::hex << _eventgroup << std::dec;
+ std::shared_ptr<runtime> its_runtime = runtime_.lock();
+ if (!its_runtime) {
return;
}
+ std::shared_ptr<message_impl> its_message = its_runtime->create_message();
+ {
+ std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ // New subscription
+ std::shared_ptr < subscription > its_subscription = std::make_shared
+ < subscription > (_major, _ttl, its_reliable, its_unreliable,
+ _subscription_type, subscribe_count,
+ std::chrono::steady_clock::time_point() + std::chrono::seconds(_ttl));
+ subscribed_[_service][_instance][_eventgroup][_client] = its_subscription;
+ if (has_address) {
+
+ if (_client != VSOMEIP_ROUTING_CLIENT) {
+ if (its_subscription->get_endpoint(true) &&
+ !host_->has_identified(_client, _service, _instance, true)) {
+ return;
+ }
+ if (its_subscription->get_endpoint(false) &&
+ !host_->has_identified(_client, _service, _instance, false)) {
+ return;
+ }
+ }
- // New subscription
- std::shared_ptr < subscription > its_subscription = std::make_shared
- < subscription > (_major, _ttl, its_reliable, its_unreliable,
- _subscription_type, subscribe_count,
- std::chrono::high_resolution_clock::time_point() + std::chrono::seconds(_ttl));
- subscribed_[_service][_instance][_eventgroup][_client] = its_subscription;
- if (has_address) {
- std::shared_ptr<runtime> its_runtime = runtime_.lock();
- if (!its_runtime)
- return;
-
- if (_client != VSOMEIP_ROUTING_CLIENT) {
- if (its_subscription->get_endpoint(true) &&
- !host_->has_identified(_client, _service, _instance, true)) {
- return;
+ if (its_subscription->get_endpoint(true)
+ && its_subscription->get_endpoint(true)->is_connected()) {
+ insert_subscription(its_message,
+ _service, _instance,
+ _eventgroup,
+ its_subscription, true, true);
+ } else {
+ // don't insert reliable endpoint option if the
+ // TCP client endpoint is not yet connected
+ insert_subscription(its_message,
+ _service, _instance,
+ _eventgroup,
+ its_subscription, false, true);
+ its_subscription->set_tcp_connection_established(false);
}
- if (its_subscription->get_endpoint(false) &&
- !host_->has_identified(_client, _service, _instance, false)) {
- return;
+ if(0 < its_message->get_entries().size()) {
+ its_subscription->set_acknowledged(false);
}
}
-
- std::shared_ptr<message_impl> its_message
- = its_runtime->create_message();
- if (its_subscription->get_endpoint(true)
- && its_subscription->get_endpoint(true)->is_connected()) {
- insert_subscription(its_message,
- _service, _instance,
- _eventgroup,
- its_subscription, true, true);
- } else {
- // don't insert reliable endpoint option if the
- // TCP client endpoint is not yet connected
- insert_subscription(its_message,
- _service, _instance,
- _eventgroup,
- its_subscription, false, true);
- its_subscription->set_tcp_connection_established(false);
- }
- if(0 < its_message->get_entries().size()) {
- serialize_and_send(its_message, its_address);
- its_subscription->set_acknowledged(false);
- }
+ }
+ if(has_address && 0 < its_message->get_entries().size()) {
+ serialize_and_send(its_message, its_address);
}
}
@@ -304,44 +314,48 @@ void service_discovery_impl::get_subscription_endpoints(
void service_discovery_impl::unsubscribe(service_t _service,
instance_t _instance, eventgroup_t _eventgroup, client_t _client) {
-
- std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
- std::shared_ptr < subscription > its_subscription;
- auto found_service = subscribed_.find(_service);
- if (found_service != subscribed_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- auto found_eventgroup = found_instance->second.find(_eventgroup);
- if (found_eventgroup != found_instance->second.end()) {
- auto found_client = found_eventgroup->second.find(_client);
- if (found_client != found_eventgroup->second.end()) {
- its_subscription = found_client->second;
- its_subscription->set_ttl(0);
- std::shared_ptr < runtime > its_runtime = runtime_.lock();
- if (its_runtime) {
- boost::asio::ip::address its_address;
+ std::shared_ptr < runtime > its_runtime = runtime_.lock();
+ if(!its_runtime) {
+ return;
+ }
+ std::shared_ptr < message_impl > its_message = its_runtime->create_message();
+ boost::asio::ip::address its_address;
+ bool has_address(false);
+ {
+ std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ std::shared_ptr < subscription > its_subscription;
+ auto found_service = subscribed_.find(_service);
+ if (found_service != subscribed_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_eventgroup = found_instance->second.find(_eventgroup);
+ if (found_eventgroup != found_instance->second.end()) {
+ auto found_client = found_eventgroup->second.find(_client);
+ if (found_client != found_eventgroup->second.end()) {
+ its_subscription = found_client->second;
+ its_subscription->set_ttl(0);
+ found_eventgroup->second.erase(_client);
auto endpoint = its_subscription->get_endpoint(false);
if (endpoint) {
- endpoint->get_remote_address(its_address);
+ has_address = endpoint->get_remote_address(its_address);
} else {
endpoint = its_subscription->get_endpoint(true);
if (endpoint) {
- endpoint->get_remote_address(its_address);
+ has_address = endpoint->get_remote_address(its_address);
} else {
return;
}
}
- std::shared_ptr < message_impl > its_message = its_runtime->create_message();
insert_subscription(its_message, _service, _instance, _eventgroup,
its_subscription, true, true);
- serialize_and_send(its_message, its_address);
-
- found_eventgroup->second.erase(_client);
}
}
}
}
}
+ if (has_address && 0 < its_message->get_entries().size()) {
+ serialize_and_send(its_message, its_address);
+ }
}
void service_discovery_impl::unsubscribe_all(service_t _service, instance_t _instance) {
@@ -378,8 +392,8 @@ void service_discovery_impl::increment_session(
auto found_session = sessions_sent_.find(_address);
if (found_session != sessions_sent_.end()) {
found_session->second.first++;
- if (found_session->second.first == 0) { // Wrap --> change the reboot flag!
- found_session->second = { 1, !found_session->second.second };
+ if (found_session->second.first == 0) {
+ found_session->second = { 1, false };
}
}
}
@@ -464,7 +478,7 @@ std::shared_ptr<option_impl> service_discovery_impl::find_existing_option(
opt->get_type() == _option_type &&
std::static_pointer_cast<ip_option_impl>(opt)->get_layer_four_protocol() == _protocol &&
std::static_pointer_cast<ip_option_impl>(opt)->get_port() == _port &&
- std::static_pointer_cast<ip_option_impl>(opt)->is_multicast() == is_multicast &&
+ std::static_pointer_cast<Option>(opt)->is_multicast() == is_multicast &&
std::static_pointer_cast<Option>(opt)->get_address() == _address) {
return opt;
}
@@ -578,7 +592,7 @@ void service_discovery_impl::insert_find_entries(
for (auto its_instance : its_service.second) {
auto its_request = its_instance.second;
uint8_t its_sent_counter = its_request->get_sent_counter();
- if (its_sent_counter != default_->get_repetition_max()) {
+ if (its_sent_counter != default_->get_repetition_max() + 1) {
if (i >= _start) {
if (its_size + VSOMEIP_SOMEIP_SD_ENTRY_SIZE <= max_message_size_) {
std::shared_ptr < serviceentry_impl > its_entry =
@@ -591,8 +605,8 @@ void service_discovery_impl::insert_find_entries(
its_entry->set_minor_version(its_request->get_minor());
its_entry->set_ttl(its_request->get_ttl());
its_size += VSOMEIP_SOMEIP_SD_ENTRY_SIZE;
-
its_sent_counter++;
+
its_request->set_sent_counter(its_sent_counter);
} else {
VSOMEIP_ERROR << "Failed to create service entry!";
@@ -802,15 +816,20 @@ bool service_discovery_impl::send(bool _is_announcing, bool _is_find) {
// Serialize and send
bool has_sent(false);
- for (auto m : its_messages) {
- if (m->get_entries().size() > 0) {
- std::pair<session_t, bool> its_session = get_session(unicast_);
- m->set_session(its_session.first);
- m->set_reboot_flag(its_session.second);
- if (host_->send(VSOMEIP_SD_CLIENT, m, true)) {
- increment_session(unicast_);
+ {
+ // lock serialize mutex here as well even if we don't use the
+ // serializer as it's used to guard access to the sessions_sent_ map
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
+ for (auto m : its_messages) {
+ if (m->get_entries().size() > 0) {
+ std::pair<session_t, bool> its_session = get_session(unicast_);
+ m->set_session(its_session.first);
+ m->set_reboot_flag(its_session.second);
+ if (host_->send(VSOMEIP_SD_CLIENT, m, true)) {
+ increment_session(unicast_);
+ }
+ has_sent = true;
}
- has_sent = true;
}
}
return has_sent;
@@ -993,7 +1012,7 @@ void service_discovery_impl::process_serviceentry(
} else {
std::shared_ptr<request> its_request = find_request(its_service, its_instance);
if (its_request)
- its_request->set_sent_counter(default_->get_repetition_max());
+ its_request->set_sent_counter((uint8_t) (default_->get_repetition_max() + 1));
unsubscribe_all(its_service, its_instance);
host_->del_routing_info(its_service, its_instance,
@@ -1015,9 +1034,9 @@ void service_discovery_impl::process_offerservice_serviceentry(
std::shared_ptr<request> its_request = find_request(_service, _instance);
if (its_request)
- its_request->set_sent_counter(default_->get_repetition_max());
+ its_request->set_sent_counter((uint8_t) (default_->get_repetition_max() + 1));
- host_->add_routing_info(_service, _instance,
+ smallest_ttl_ = host_->add_routing_info(_service, _instance,
_major, _minor, _ttl,
_reliable_address, _reliable_port,
_unreliable_address, _unreliable_port);
@@ -1032,18 +1051,6 @@ void service_discovery_impl::process_offerservice_serviceentry(
= its_runtime->create_message();
for (auto its_eventgroup : found_instance->second) {
for (auto its_client : its_eventgroup.second) {
- if (its_client.first != VSOMEIP_ROUTING_CLIENT) {
- if (its_client.second->get_endpoint(true) &&
- !host_->has_identified(its_client.first, _service,
- _instance, true)) {
- continue;
- }
- if (its_client.second->get_endpoint(false) &&
- !host_->has_identified(its_client.first, _service,
- _instance, false)) {
- continue;
- }
- }
std::shared_ptr<subscription> its_subscription(its_client.second);
std::shared_ptr<endpoint> its_unreliable;
std::shared_ptr<endpoint> its_reliable;
@@ -1056,6 +1063,18 @@ void service_discovery_impl::process_offerservice_serviceentry(
its_client.first);
its_subscription->set_endpoint(its_reliable, true);
its_subscription->set_endpoint(its_unreliable, false);
+ if (its_client.first != VSOMEIP_ROUTING_CLIENT) {
+ if (its_client.second->get_endpoint(true) &&
+ !host_->has_identified(its_client.first, _service,
+ _instance, true)) {
+ continue;
+ }
+ if (its_client.second->get_endpoint(false) &&
+ !host_->has_identified(its_client.first, _service,
+ _instance, false)) {
+ continue;
+ }
+ }
if (its_subscription->is_acknowledged()) {
if (its_subscription->get_endpoint(true)
&& its_subscription->get_endpoint(true)->is_connected()) {
@@ -1096,6 +1115,7 @@ void service_discovery_impl::process_offerservice_serviceentry(
}
if (its_target) {
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
its_message->set_session(its_session.first);
its_message->set_reboot_flag(its_session.second);
serializer_->serialize(its_message.get());
@@ -1144,17 +1164,19 @@ void service_discovery_impl::send_unicast_offer_service(
instance_t _instance, major_version_t _major, minor_version_t _minor) {
if (_major == ANY_MAJOR || _major == _info->get_major()) {
if (_minor == 0xFFFFFFFF || _minor <= _info->get_minor()) {
- std::shared_ptr<runtime> its_runtime = runtime_.lock();
- if (!its_runtime) {
- return;
- }
- std::shared_ptr<message_impl> its_message =
- its_runtime->create_message();
-
- uint32_t its_size(max_message_size_);
- insert_offer_service(its_message, _service, _instance, _info, its_size);
+ if (_info->get_endpoint(false) || _info->get_endpoint(true)) {
+ std::shared_ptr<runtime> its_runtime = runtime_.lock();
+ if (!its_runtime) {
+ return;
+ }
+ std::shared_ptr<message_impl> its_message =
+ its_runtime->create_message();
+ uint32_t its_size(max_message_size_);
+ insert_offer_service(its_message, _service, _instance, _info,
+ its_size);
- serialize_and_send(its_message, get_current_remote_address());
+ serialize_and_send(its_message, get_current_remote_address());
+ }
}
}
}
@@ -1164,22 +1186,27 @@ void service_discovery_impl::send_multicast_offer_service(
instance_t _instance, major_version_t _major, minor_version_t _minor) {
if (_major == ANY_MAJOR || _major == _info->get_major()) {
if (_minor == 0xFFFFFFFF || _minor <= _info->get_minor()) {
- std::shared_ptr<runtime> its_runtime = runtime_.lock();
- if (!its_runtime) {
- return;
- }
- std::shared_ptr<message_impl> its_message =
- its_runtime->create_message();
-
- uint32_t its_size(max_message_size_);
- insert_offer_service(its_message, _service, _instance, _info, its_size);
-
- if (its_message->get_entries().size() > 0) {
- std::pair<session_t, bool> its_session = get_session(unicast_);
- its_message->set_session(its_session.first);
- its_message->set_reboot_flag(its_session.second);
- if (host_->send(VSOMEIP_SD_CLIENT, its_message, true)) {
- increment_session(unicast_);
+ if (_info->get_endpoint(false) || _info->get_endpoint(true)) {
+ std::shared_ptr<runtime> its_runtime = runtime_.lock();
+ if (!its_runtime) {
+ return;
+ }
+ std::shared_ptr<message_impl> its_message =
+ its_runtime->create_message();
+
+ uint32_t its_size(max_message_size_);
+ insert_offer_service(its_message, _service, _instance, _info,
+ its_size);
+
+ if (its_message->get_entries().size() > 0) {
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
+ std::pair<session_t, bool> its_session = get_session(
+ unicast_);
+ its_message->set_session(its_session.first);
+ its_message->set_reboot_flag(its_session.second);
+ if (host_->send(VSOMEIP_SD_CLIENT, its_message, true)) {
+ increment_session(unicast_);
+ }
}
}
}
@@ -1197,61 +1224,63 @@ void service_discovery_impl::on_reliable_endpoint_connected(
// send out subscriptions for services where the tcp connection
// wasn't established at time of subscription
- std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ std::shared_ptr<message_impl> its_message(its_runtime->create_message());
+ bool has_address(false);
+ boost::asio::ip::address its_address;
- auto found_service = subscribed_.find(_service);
- if (found_service != subscribed_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- if(0 < found_instance->second.size()) {
- std::shared_ptr<message_impl> its_message(its_runtime->create_message());
- bool has_address(false);
- boost::asio::ip::address its_address;
+ {
+ std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ auto found_service = subscribed_.find(_service);
+ if (found_service != subscribed_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ if(0 < found_instance->second.size()) {
- for(const auto &its_eventgroup : found_instance->second) {
- for(const auto &its_client : its_eventgroup.second) {
- if (its_client.first != VSOMEIP_ROUTING_CLIENT) {
- if (its_client.second->get_endpoint(true) &&
- !host_->has_identified(its_client.first, _service,
- _instance, true)) {
- continue;
+ for(const auto &its_eventgroup : found_instance->second) {
+ for(const auto &its_client : its_eventgroup.second) {
+ if (its_client.first != VSOMEIP_ROUTING_CLIENT) {
+ if (its_client.second->get_endpoint(true) &&
+ !host_->has_identified(its_client.first, _service,
+ _instance, true)) {
+ continue;
+ }
}
- }
- std::shared_ptr<subscription> its_subscription(its_client.second);
- if(its_subscription && !its_subscription->is_tcp_connection_established()) {
- const std::shared_ptr<const endpoint> its_endpoint(
- its_subscription->get_endpoint(true));
- if(its_endpoint && its_endpoint->is_connected()) {
- if(its_endpoint.get() == _endpoint.get()) {
- // mark as established
- its_subscription->set_tcp_connection_established(true);
-
- std::shared_ptr<endpoint> its_unreliable;
- std::shared_ptr<endpoint> its_reliable;
- get_subscription_endpoints(
- its_subscription->get_subscription_type(),
- its_unreliable, its_reliable, &its_address,
- &has_address, _service, _instance,
- its_client.first);
- its_subscription->set_endpoint(its_reliable, true);
- its_subscription->set_endpoint(its_unreliable, false);
- // only insert reliable subscriptions as unreliable
- // ones are immediately sent out
- insert_subscription(its_message, _service,
- _instance, its_eventgroup.first,
- its_subscription, true, false);
- its_subscription->set_acknowledged(false);
+ std::shared_ptr<subscription> its_subscription(its_client.second);
+ if(its_subscription && !its_subscription->is_tcp_connection_established()) {
+ const std::shared_ptr<const endpoint> its_endpoint(
+ its_subscription->get_endpoint(true));
+ if(its_endpoint && its_endpoint->is_connected()) {
+ if(its_endpoint.get() == _endpoint.get()) {
+ // mark as established
+ its_subscription->set_tcp_connection_established(true);
+
+ std::shared_ptr<endpoint> its_unreliable;
+ std::shared_ptr<endpoint> its_reliable;
+ get_subscription_endpoints(
+ its_subscription->get_subscription_type(),
+ its_unreliable, its_reliable, &its_address,
+ &has_address, _service, _instance,
+ its_client.first);
+ its_subscription->set_endpoint(its_reliable, true);
+ its_subscription->set_endpoint(its_unreliable, false);
+ // only insert reliable subscriptions as unreliable
+ // ones are immediately sent out
+ insert_subscription(its_message, _service,
+ _instance, its_eventgroup.first,
+ its_subscription, true, false);
+ its_subscription->set_acknowledged(false);
+ }
}
}
}
}
}
- if (0 < its_message->get_entries().size() && has_address) {
- serialize_and_send(its_message, its_address);
- }
}
}
}
+ if (has_address && 0 < its_message->get_entries().size()) {
+ serialize_and_send(its_message, its_address);
+ }
}
bool service_discovery_impl::insert_offer_service(
@@ -1359,8 +1388,10 @@ void service_discovery_impl::process_eventgroupentry(
if (_entry->get_owning_message()->get_return_code() != return_code) {
VSOMEIP_ERROR << "Invalid return code in SD header";
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
return;
}
@@ -1368,14 +1399,18 @@ void service_discovery_impl::process_eventgroupentry(
if (_entry->get_num_options(1) == 0
&& _entry->get_num_options(2) == 0) {
VSOMEIP_ERROR << "Invalid number of options in SubscribeEventGroup entry";
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
return;
}
if(_entry->get_owning_message()->get_options_length() < 12) {
VSOMEIP_ERROR << "Invalid options length in SD message";
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
return;
}
if (_options.size()
@@ -1385,8 +1420,18 @@ void service_discovery_impl::process_eventgroupentry(
(_entry->get_num_options(1)) + (_entry->get_num_options(2)))) {
VSOMEIP_ERROR << "Fewer options in SD message than "
"referenced in EventGroup entry or malformed option received";
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
+ return;
+ }
+ if(_entry->get_owning_message()->get_someip_length() < _entry->get_owning_message()->get_length()
+ && its_ttl > 0) {
+ VSOMEIP_ERROR << std::dec << "SomeIP length field in SubscribeEventGroup message header: ["
+ << _entry->get_owning_message()->get_someip_length()
+ << "] bytes, is shorter than length of deserialized message: ["
+ << (uint32_t) _entry->get_owning_message()->get_length() << "] bytes.";
return;
}
}
@@ -1410,7 +1455,7 @@ void service_discovery_impl::process_eventgroupentry(
VSOMEIP_ERROR << "Fewer options in SD message than "
"referenced in EventGroup entry for "
"option run number: " << i;
- if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) {
+ if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type && its_ttl > 0) {
insert_subscription_nack(its_message_response, its_service, its_instance,
its_eventgroup, its_counter, its_major, its_reserved);
}
@@ -1426,8 +1471,10 @@ void service_discovery_impl::process_eventgroupentry(
boost::asio::ip::address_v4 its_ipv4_address(
its_ipv4_option->get_address());
if (!check_layer_four_protocol(its_ipv4_option)) {
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
+ if( its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
return;
}
@@ -1439,9 +1486,11 @@ void service_discovery_impl::process_eventgroupentry(
if(!check_ipv4_address(its_first_address)
|| 0 == its_first_port) {
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
- VSOMEIP_ERROR << "Invalid port or IP address in first endpoint option specified!";
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
+ VSOMEIP_ERROR << "Invalid port or IP address in first IPv4 endpoint option specified!";
return;
}
} else
@@ -1453,9 +1502,11 @@ void service_discovery_impl::process_eventgroupentry(
if(!check_ipv4_address(its_second_address)
|| 0 == its_second_port) {
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
- VSOMEIP_ERROR << "Invalid port or IP address in second endpoint option specified!";
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
+ VSOMEIP_ERROR << "Invalid port or IP address in second IPv4 endpoint option specified!";
return;
}
} else {
@@ -1476,8 +1527,11 @@ void service_discovery_impl::process_eventgroupentry(
boost::asio::ip::address_v6 its_ipv6_address(
its_ipv6_option->get_address());
if (!check_layer_four_protocol(its_ipv6_option)) {
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
+ VSOMEIP_ERROR << "Invalid layer 4 protocol type in IPv6 endpoint option specified!";
return;
}
@@ -1557,9 +1611,10 @@ void service_discovery_impl::process_eventgroupentry(
case option_type_e::UNKNOWN:
default:
VSOMEIP_WARNING << "Unsupported eventgroup option";
- insert_subscription_nack(its_message_response, its_service, its_instance,
- its_eventgroup, its_counter, its_major, its_reserved);
-
+ if(its_ttl > 0) {
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+ }
break;
}
}
@@ -1604,10 +1659,23 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service,
// Could not find eventgroup or wrong version
if (!its_info || _major != its_info->get_major()) {
// Create a temporary info object with TTL=0 --> send NACK
+ if( its_info && (_major != its_info->get_major())) {
+ VSOMEIP_ERROR << "Requested major version:[" << (uint32_t) _major
+ << "] in subscription to service:[" << _service
+ << "] instance:[" << _instance
+ << "] eventgroup:[" << _eventgroup
+ << "], does not match with services major version:[" << (uint32_t) its_info->get_major()
+ << "]";
+ } else {
+ VSOMEIP_ERROR << "Requested eventgroup:[" << _eventgroup
+ << "] not found for subscription to service:["
+ << _service << "] instance:[" << _instance << "]";
+ }
its_info = std::make_shared < eventgroupinfo > (_major, 0);
- is_nack = true;
- insert_subscription_nack(its_message, _service, _instance,
- _eventgroup, _counter, _major, _reserved);
+ if(_ttl > 0) {
+ insert_subscription_nack(its_message, _service, _instance,
+ _eventgroup, _counter, _major, _reserved);
+ }
return;
} else {
boost::asio::ip::address its_first_address, its_second_address;
@@ -1622,10 +1690,14 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service,
} else if(_is_first_reliable) { // tcp unicast
its_first_target = its_first_subscriber;
// check if TCP connection is established by client
- if( !is_tcp_connected(_service, _instance, its_first_target) ) {
- is_nack = true;
+ if( !is_tcp_connected(_service, _instance, its_first_target) && _ttl > 0) {
insert_subscription_nack(its_message, _service, _instance,
_eventgroup, _counter, _major, _reserved);
+ VSOMEIP_ERROR << "TCP connection to target1: [" << its_first_target->get_address().to_string()
+ << ":" << its_first_target->get_port()
+ << "] not established for subscription to service:[" << _service
+ << "] instance:[" << _instance
+ << "] eventgroup:[" << _eventgroup << "]";
return;
}
} else { // udp unicast
@@ -1642,10 +1714,14 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service,
} else if (_is_second_reliable) { // tcp unicast
its_second_target = its_second_subscriber;
// check if TCP connection is established by client
- if( !is_tcp_connected(_service, _instance, its_second_target) ) {
- is_nack = true;
+ if( !is_tcp_connected(_service, _instance, its_second_target) && _ttl > 0) {
insert_subscription_nack(its_message, _service, _instance,
_eventgroup, _counter, _major, _reserved);
+ VSOMEIP_ERROR << "TCP connection to target2 : [" << its_second_target->get_address().to_string()
+ << ":" << its_second_target->get_port()
+ << "] not established for subscription to service:[" << _service
+ << "] instance:[" << _instance
+ << "] eventgroup:[" << _eventgroup << "]";
return;
}
} else { // udp unicast
@@ -1664,8 +1740,8 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service,
return;
}
- std::chrono::high_resolution_clock::time_point its_expiration
- = std::chrono::high_resolution_clock::now() + std::chrono::seconds(_ttl);
+ std::chrono::steady_clock::time_point its_expiration
+ = std::chrono::steady_clock::now() + std::chrono::seconds(_ttl);
if (its_first_target) {
if(!host_->on_subscribe_accepted(_service, _instance, _eventgroup,
@@ -1807,6 +1883,7 @@ bool service_discovery_impl::is_tcp_connected(service_t _service,
void service_discovery_impl::serialize_and_send(
std::shared_ptr<message_impl> _message,
const boost::asio::ip::address &_address) {
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
std::pair<session_t, bool> its_session = get_session(_address);
_message->set_session(its_session.first);
_message->set_reboot_flag(its_session.second);
@@ -1873,27 +1950,6 @@ bool service_discovery_impl::check_static_header_fields(
return true;
}
-void service_discovery_impl::send_eventgroup_subscription_nack(
- service_t _service, instance_t _instance,eventgroup_t _eventgroup,
- major_version_t _major, uint8_t _counter, uint16_t _reserved) {
- std::shared_ptr<runtime> its_runtime = runtime_.lock();
- if (!its_runtime) {
- return;
- }
- std::shared_ptr<message_impl> its_message = its_runtime->create_message();
- if (its_message) {
- std::shared_ptr<eventgroupinfo> its_info = host_->find_eventgroup(
- _service, _instance, _eventgroup);
- if(!its_info) {
- // Create a temporary info object with TTL=0
- its_info = std::make_shared < eventgroupinfo > (_major, 0);
- }
- insert_subscription_nack(its_message, _service, _instance, _eventgroup,
- _counter, _major, _reserved);
- serialize_and_send(its_message, get_current_remote_address());
- }
-}
-
bool service_discovery_impl::check_layer_four_protocol(
const std::shared_ptr<const ip_option_impl> _ip_option) const {
if (_ip_option->get_layer_four_protocol() == layer_four_protocol_e::UNKNOWN) {
@@ -1909,46 +1965,68 @@ void service_discovery_impl::send_subscriptions(service_t _service, instance_t _
if (!its_runtime) {
return;
}
- std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
- auto found_service = subscribed_.find(_service);
- if (found_service != subscribed_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- for (auto found_eventgroup : found_instance->second) {
- auto found_client = found_eventgroup.second.find(_client);
- if (found_client != found_eventgroup.second.end()) {
- boost::asio::ip::address its_address;
- auto endpoint = found_client->second->get_endpoint(_reliable);
- if (endpoint) {
- endpoint->get_remote_address(its_address);
- std::shared_ptr<message_impl> its_message
- = its_runtime->create_message();
-
- if(_reliable) {
- if(endpoint->is_connected()) {
+ std::forward_list<std::pair<std::shared_ptr<message_impl>,
+ const boost::asio::ip::address>> subscription_messages;
+ {
+ std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ auto found_service = subscribed_.find(_service);
+ if (found_service != subscribed_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ for (auto found_eventgroup : found_instance->second) {
+ auto found_client = found_eventgroup.second.find(_client);
+ if (found_client != found_eventgroup.second.end()) {
+ std::shared_ptr<endpoint> its_unreliable;
+ std::shared_ptr<endpoint> its_reliable;
+ bool has_address(false);
+ boost::asio::ip::address its_address;
+ get_subscription_endpoints(
+ found_client->second->get_subscription_type(),
+ its_unreliable, its_reliable, &its_address,
+ &has_address, _service, _instance,
+ found_client->first);
+ std::shared_ptr<endpoint> endpoint;
+ if (_reliable) {
+ endpoint = its_reliable;
+ found_client->second->set_endpoint(its_reliable, true);
+ } else {
+ endpoint = its_unreliable;
+ found_client->second->set_endpoint(its_unreliable, false);
+ }
+ if (endpoint) {
+ endpoint->get_remote_address(its_address);
+ std::shared_ptr<message_impl> its_message
+ = its_runtime->create_message();
+
+ if(_reliable) {
+ if(endpoint->is_connected()) {
+ insert_subscription(its_message, _service,
+ _instance, found_eventgroup.first,
+ found_client->second, _reliable, !_reliable);
+ found_client->second->set_tcp_connection_established(true);
+ } else {
+ // don't insert reliable endpoint option if the
+ // TCP client endpoint is not yet connected
+ found_client->second->set_tcp_connection_established(false);
+ }
+ } else {
insert_subscription(its_message, _service,
_instance, found_eventgroup.first,
found_client->second, _reliable, !_reliable);
- found_client->second->set_tcp_connection_established(true);
- } else {
- // don't insert reliable endpoint option if the
- // TCP client endpoint is not yet connected
- found_client->second->set_tcp_connection_established(false);
}
- } else {
- insert_subscription(its_message, _service,
- _instance, found_eventgroup.first,
- found_client->second, _reliable, !_reliable);
- }
- if(0 < its_message->get_entries().size()) {
- serialize_and_send(its_message, its_address);
- found_client->second->set_acknowledged(false);
+ if(0 < its_message->get_entries().size()) {
+ subscription_messages.push_front({its_message, its_address});
+ found_client->second->set_acknowledged(false);
+ }
}
}
}
}
}
}
+ for (const auto s : subscription_messages) {
+ serialize_and_send(s.first, s.second);
+ }
}
void service_discovery_impl::start_subscription_expiration_timer() {
diff --git a/implementation/service_discovery/src/serviceentry_impl.cpp b/implementation/service_discovery/src/serviceentry_impl.cpp
index 9f82b83..28da730 100755
--- a/implementation/service_discovery/src/serviceentry_impl.cpp
+++ b/implementation/service_discovery/src/serviceentry_impl.cpp
@@ -41,15 +41,15 @@ bool serviceentry_impl::serialize(vsomeip::serializer *_to) const {
bool serviceentry_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful = entry_impl::deserialize(_from);
- uint8_t tmp_major_version;
+ uint8_t tmp_major_version(0);
is_successful = is_successful && _from->deserialize(tmp_major_version);
major_version_ = static_cast<major_version_t>(tmp_major_version);
- uint32_t tmp_ttl;
+ uint32_t tmp_ttl(0);
is_successful = is_successful && _from->deserialize(tmp_ttl, true);
ttl_ = static_cast<ttl_t>(tmp_ttl);
- uint32_t tmp_minor_version;
+ uint32_t tmp_minor_version(0);
is_successful = is_successful && _from->deserialize(tmp_minor_version);
minor_version_ = static_cast<minor_version_t>(tmp_minor_version);
diff --git a/implementation/service_discovery/src/subscription.cpp b/implementation/service_discovery/src/subscription.cpp
index 402304c..06741cf 100644
--- a/implementation/service_discovery/src/subscription.cpp
+++ b/implementation/service_discovery/src/subscription.cpp
@@ -13,7 +13,7 @@ subscription::subscription(major_version_t _major, ttl_t _ttl,
std::shared_ptr<endpoint> _unreliable,
subscription_type_e _subscription_type,
uint8_t _counter,
- std::chrono::high_resolution_clock::time_point _expiration)
+ std::chrono::steady_clock::time_point _expiration)
: major_(_major), ttl_(_ttl),
reliable_(_reliable), unreliable_(_unreliable),
is_acknowledged_(true),
@@ -73,11 +73,11 @@ uint8_t subscription::get_counter() const {
return counter_;
}
-std::chrono::high_resolution_clock::time_point subscription::get_expiration() const {
+std::chrono::steady_clock::time_point subscription::get_expiration() const {
return expiration_;
}
-void subscription::set_expiration(std::chrono::high_resolution_clock::time_point _expiration) {
+void subscription::set_expiration(std::chrono::steady_clock::time_point _expiration) {
expiration_ = _expiration;
}
diff --git a/implementation/tracing/include/trace_connector.hpp b/implementation/tracing/include/trace_connector.hpp
index 95803c3..81b2e38 100644
--- a/implementation/tracing/include/trace_connector.hpp
+++ b/implementation/tracing/include/trace_connector.hpp
@@ -48,7 +48,12 @@ public:
VSOMEIP_EXPORT void reset();
VSOMEIP_EXPORT void set_enabled(const bool _enabled);
- VSOMEIP_EXPORT bool is_enabled();
+ VSOMEIP_EXPORT bool is_enabled() const;
+
+ VSOMEIP_EXPORT void set_sd_enabled(const bool _enabled);
+ VSOMEIP_EXPORT bool is_sd_enabled() const;
+
+ VSOMEIP_EXPORT bool is_sd_message(const byte_t *_data, uint16_t _data_size) const;
VSOMEIP_EXPORT bool add_channel(const trace_channel_t &_id,const std::string &_name);
VSOMEIP_EXPORT bool remove_channel(const trace_channel_t &_id);
@@ -80,6 +85,7 @@ private:
const byte_t *_data, const uint16_t _data_size);
bool is_enabled_;
+ bool is_sd_enabled_;
bool is_initialized_;
channels_t channels_;
diff --git a/implementation/tracing/src/trace_connector.cpp b/implementation/tracing/src/trace_connector.cpp
index dc01aa2..8abd0f1 100644
--- a/implementation/tracing/src/trace_connector.cpp
+++ b/implementation/tracing/src/trace_connector.cpp
@@ -20,6 +20,7 @@ std::shared_ptr<trace_connector> trace_connector::get() {
trace_connector::trace_connector() :
is_enabled_(false),
+ is_sd_enabled_(false),
is_initialized_(false),
channels_(),
filter_rules_()
@@ -33,12 +34,14 @@ trace_connector::~trace_connector() {
void trace_connector::init() {
#ifdef USE_DLT
- // register channels/contexts
- std::lock_guard<std::mutex> lock(dlt_contexts_mutex);
- for(auto it = channels_.begin(); it != channels_.end(); ++it) {
- DltContext *dlt_context = new DltContext();
- dlt_contexts_.insert(std::make_pair(it->first, dlt_context));
- DLT_REGISTER_CONTEXT_LL_TS(*dlt_context, it->first.c_str(), it->second.c_str(), DLT_LOG_DEBUG, DLT_TRACE_STATUS_ON);
+ if(!is_initialized_) {
+ // register channels/contexts
+ std::lock_guard<std::mutex> lock(dlt_contexts_mutex);
+ for(auto it = channels_.begin(); it != channels_.end(); ++it) {
+ DltContext *dlt_context = new DltContext();
+ dlt_contexts_.insert(std::make_pair(it->first, dlt_context));
+ DLT_REGISTER_CONTEXT_LL_TS(*dlt_context, it->first.c_str(), it->second.c_str(), DLT_LOG_DEBUG, DLT_TRACE_STATUS_ON);
+ }
}
#endif
is_initialized_ = true;
@@ -53,7 +56,9 @@ void trace_connector::reset() {
// unregister channels/contexts
for(auto it = dlt_contexts_.begin(); it != dlt_contexts_.end(); ++it) {
DLT_UNREGISTER_CONTEXT(*it->second);
+ delete it->second;
}
+ dlt_contexts_.clear();
#endif
// reset to default
@@ -62,16 +67,34 @@ void trace_connector::reset() {
channels_.insert(std::make_pair(VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME));
filter_rules_.clear();
+
+ is_initialized_ = false;
}
void trace_connector::set_enabled(const bool _enabled) {
is_enabled_ = _enabled;
}
-bool trace_connector::is_enabled() {
+bool trace_connector::is_enabled() const {
return is_enabled_;
}
+void trace_connector::set_sd_enabled(const bool _sd_enabled) {
+ is_sd_enabled_ = _sd_enabled;
+}
+
+bool trace_connector::is_sd_enabled() const {
+ return is_sd_enabled_;
+}
+
+bool trace_connector::is_sd_message(const byte_t *_data, uint16_t _data_size) const {
+ if (VSOMEIP_METHOD_POS_MAX < _data_size) {
+ return (_data[VSOMEIP_SERVICE_POS_MIN] == 0xFF && _data[VSOMEIP_SERVICE_POS_MAX] == 0xFF &&
+ _data[VSOMEIP_METHOD_POS_MIN] == 0x81 && _data[VSOMEIP_METHOD_POS_MAX] == 0x00);
+ }
+ return false;
+}
+
bool trace_connector::add_channel(const trace_channel_t &_id, const std::string &_name) {
std::lock_guard<std::mutex> its_lock_channels(channels_mutex_);
std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex);
@@ -207,6 +230,9 @@ void trace_connector::trace(const byte_t *_header, uint16_t _header_size,
if (_data_size == 0)
return; // no data
+ if (is_sd_message(_data, _data_size) && !is_sd_enabled_)
+ return; // tracing of service discovery messages is disabled!
+
// check if filter rules match
std::vector<trace_channel_t> its_channels;
if (apply_filter_rules(_data, _data_size, its_channels)) {
diff --git a/implementation/tracing/src/trace_header.cpp b/implementation/tracing/src/trace_header.cpp
index 6609412..2f293ee 100644
--- a/implementation/tracing/src/trace_header.cpp
+++ b/implementation/tracing/src/trace_header.cpp
@@ -17,11 +17,8 @@ bool trace_header::prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_
}
bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending) {
- if (!_endpoint)
- return false;
-
boost::asio::ip::address its_address;
- if (_endpoint->get_remote_address(its_address)) {
+ if (_endpoint && _endpoint->get_remote_address(its_address)) {
if (its_address.is_v6())
return false;
diff --git a/implementation/utility/include/criticalsection.hpp b/implementation/utility/include/criticalsection.hpp
new file mode 100644
index 0000000..6e247a3
--- /dev/null
+++ b/implementation/utility/include/criticalsection.hpp
@@ -0,0 +1,44 @@
+#ifndef VSOMEIP_CRITICALSECTION_HPP
+#define VSOMEIP_CRITICALSECTION_HPP
+
+#include <memory>
+#include <mutex>
+
+
+namespace vsomeip {
+
+#ifdef WIN32
+
+ // Windows: CriticalSection uses win32 CRITICAL_SECTION.
+ // Interface mimics std::mutex so we can use it in
+ // conjunction with std::unique_lock.
+ class CriticalSection final {
+ public:
+ CriticalSection();
+ ~CriticalSection();
+
+ // prevent copying
+ CriticalSection(const CriticalSection&) = delete;
+ CriticalSection& operator=(const CriticalSection&) = delete;
+
+ void lock();
+ void unlock();
+ bool try_lock();
+
+ private:
+ struct Impl;
+ std::unique_ptr<Impl> m_impl;
+ };
+
+#else
+
+ // Linux: CriticalSection is a type alias for std::mutex.
+ using CriticalSection = std::mutex;
+
+#endif
+
+} // namespace vsomeip
+
+
+
+#endif //VSOMEIP_CRITICALSECTION_HPP
diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp
index 9f3a7e3..0831bdb 100644
--- a/implementation/utility/include/utility.hpp
+++ b/implementation/utility/include/utility.hpp
@@ -11,6 +11,7 @@
#include <vsomeip/enumeration_types.hpp>
#include <vsomeip/message.hpp>
+#include "criticalsection.hpp"
namespace vsomeip {
@@ -72,17 +73,34 @@ public:
static bool is_file(const std::string &_path);
static bool is_folder(const std::string &_path);
+ static CriticalSection its_local_configuration_mutex__;
+
static struct configuration_data_t *the_configuration_data__;
- static bool auto_configuration_init(const std::string &_name);
- static void auto_configuration_exit();
+ static bool auto_configuration_init();
+ static void auto_configuration_exit(client_t _client);
- static bool is_routing_manager_host__;
- static bool is_routing_manager_host();
+ static bool is_routing_manager_host(client_t _client);
+ static void set_routing_manager_host(client_t _client);
static bool is_used_client_id(client_t _client);
- static client_t request_client_id(client_t _client);
+ static client_t request_client_id(const std::string &_name,
+ client_t _client);
static void release_client_id(client_t _client);
+ static inline bool is_valid_message_type(message_type_e _type) {
+ return (_type == message_type_e::MT_REQUEST
+ || _type == message_type_e::MT_REQUEST_NO_RETURN
+ || _type == message_type_e::MT_NOTIFICATION
+ || _type == message_type_e::MT_REQUEST_ACK
+ || _type == message_type_e::MT_REQUEST_NO_RETURN_ACK
+ || _type == message_type_e::MT_NOTIFICATION_ACK
+ || _type == message_type_e::MT_RESPONSE
+ || _type == message_type_e::MT_ERROR
+ || _type == message_type_e::MT_RESPONSE_ACK
+ || _type == message_type_e::MT_ERROR_ACK
+ || _type == message_type_e::MT_UNKNOWN);
+ }
+
static uint16_t its_configuration_refs__;
};
diff --git a/implementation/utility/src/criticalsection.cpp b/implementation/utility/src/criticalsection.cpp
new file mode 100644
index 0000000..edf7deb
--- /dev/null
+++ b/implementation/utility/src/criticalsection.cpp
@@ -0,0 +1,38 @@
+#include "../include/criticalsection.hpp"
+
+
+#ifdef WIN32
+
+#include <Windows.h>
+
+namespace vsomeip {
+
+ struct CriticalSection::Impl final {
+ CRITICAL_SECTION m_criticalSection;
+ };
+
+
+ CriticalSection::CriticalSection()
+ : m_impl(new CriticalSection::Impl()) {
+ InitializeCriticalSection(&m_impl->m_criticalSection);
+ }
+
+ CriticalSection::~CriticalSection() {
+ DeleteCriticalSection(&m_impl->m_criticalSection);
+ }
+
+ void CriticalSection::lock() {
+ EnterCriticalSection(&m_impl->m_criticalSection);
+ }
+
+ bool CriticalSection::try_lock() {
+ return (TryEnterCriticalSection(&m_impl->m_criticalSection) != 0);
+ }
+
+ void CriticalSection::unlock(){
+ LeaveCriticalSection(&m_impl->m_criticalSection);
+ }
+
+} // namespace vsomeip
+
+#endif
diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp
index c711320..62dcf59 100644
--- a/implementation/utility/src/utility.cpp
+++ b/implementation/utility/src/utility.cpp
@@ -8,6 +8,7 @@
#else
#include <dlfcn.h>
#include <sys/mman.h>
+ #include <thread>
#endif
#include <sys/stat.h>
@@ -114,56 +115,141 @@ bool utility::is_folder(const std::string &_path) {
return false;
}
+// pointer to shared memory
configuration_data_t *utility::the_configuration_data__(nullptr);
-bool utility::is_routing_manager_host__(false);
+// critical section to protect shared memory pointers, handles and ref count in this process
+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);
#ifdef WIN32
-HANDLE its_descriptor;
+// global (inter-process) mutex
+static HANDLE configuration_data_mutex(INVALID_HANDLE_VALUE);
+// memory mapping handle
+static HANDLE its_descriptor(INVALID_HANDLE_VALUE);
#endif
-bool utility::auto_configuration_init(const std::string &_name) {
+bool utility::auto_configuration_init() {
+ std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__);
std::shared_ptr<configuration> its_config(configuration::get());
+
#ifdef WIN32
- its_descriptor = CreateFileMapping(
- INVALID_HANDLE_VALUE, // use paging file
- 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)
- VSOMEIP_SHM_NAME); // name of mapping object
-
- if (its_descriptor != NULL) {
- void *its_segment = (LPTSTR)MapViewOfFile(its_descriptor, // handle to map object
- FILE_MAP_ALL_ACCESS, // read/write permission
- 0,
- 0,
- sizeof(configuration_data_t));
- the_configuration_data__
- = reinterpret_cast<configuration_data_t *>(its_segment);
- if (the_configuration_data__ != nullptr && is_routing_manager_host__) {
- the_configuration_data__->mutex_ = CreateMutex(
- NULL, // default security attributes
- true, // initially owned
- "vSomeIP\\SharedMemoryLock"); // named mutex
-
- the_configuration_data__->client_base_
- = static_cast<unsigned short>(its_config->get_diagnosis_address() << 8);
- the_configuration_data__->used_client_ids_[0]
- = the_configuration_data__->client_base_;
- the_configuration_data__->client_base_++;
- the_configuration_data__->max_used_client_ids_index_ = 1;
-
- if (its_config->get_routing_host() == "" ||
- its_config->get_routing_host() == _name)
- is_routing_manager_host__ = true;
-
- its_configuration_refs__++;
-
- ReleaseMutex(the_configuration_data__->mutex_);
- }
+ if (its_configuration_refs__ > 0) {
+ assert(configuration_data_mutex != INVALID_HANDLE_VALUE);
+ assert(its_descriptor != INVALID_HANDLE_VALUE);
+ assert(the_configuration_data__ != nullptr);
+
+ ++its_configuration_refs__;
} else {
- // TODO: Error
+ configuration_data_mutex = CreateMutex(
+ NULL, // default security attributes
+ true, // initially owned
+ "vSomeIP_SharedMemoryLock"); // named mutex
+ if (configuration_data_mutex) {
+
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ VSOMEIP_DEBUG << "utility::auto_configuration_init: use existing shared memory";
+
+ // mapping already exists, wait for mutex release and map in
+ DWORD waitResult = WaitForSingleObject(configuration_data_mutex, INFINITE);
+ if (waitResult == WAIT_OBJECT_0) {
+
+ its_descriptor = CreateFileMapping(
+ INVALID_HANDLE_VALUE, // use paging file
+ 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)
+ VSOMEIP_SHM_NAME); // name of mapping object
+
+ if (its_descriptor && GetLastError() == ERROR_ALREADY_EXISTS) {
+
+ void *its_segment = (LPTSTR)MapViewOfFile(its_descriptor, // handle to map object
+ FILE_MAP_ALL_ACCESS, // read/write permission
+ 0,
+ 0,
+ sizeof(configuration_data_t));
+
+ if (its_segment) {
+ the_configuration_data__
+ = reinterpret_cast<configuration_data_t *>(its_segment);
+
+ ++its_configuration_refs__;
+ } else {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: MapViewOfFile failed (" << GetLastError() << ")";
+ }
+ } else {
+ if (its_descriptor) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: CreateFileMapping failed. expected existing mapping";
+ } else {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: CreateFileMapping failed (" << GetLastError() << ")";
+ }
+ }
+ } else {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: WaitForSingleObject(mutex) failed (" << GetLastError() << ")";
+ }
+
+ } else {
+ VSOMEIP_DEBUG << "utility::auto_configuration_init: create new shared memory";
+
+ // create and init new mapping
+ its_descriptor = CreateFileMapping(
+ INVALID_HANDLE_VALUE, // use paging file
+ 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)
+ VSOMEIP_SHM_NAME); // name of mapping object
+
+ if (its_descriptor) {
+ void *its_segment = (LPTSTR)MapViewOfFile(its_descriptor, // handle to map object
+ FILE_MAP_ALL_ACCESS, // read/write permission
+ 0,
+ 0,
+ sizeof(configuration_data_t));
+ if (its_segment) {
+ the_configuration_data__
+ = reinterpret_cast<configuration_data_t *>(its_segment);
+
+ the_configuration_data__->client_base_
+ = static_cast<unsigned short>(its_config->get_diagnosis_address() << 8);
+ the_configuration_data__->used_client_ids_[0]
+ = the_configuration_data__->client_base_;
+ the_configuration_data__->client_base_++;
+ the_configuration_data__->max_used_client_ids_index_ = 1;
+ the_configuration_data__->max_assigned_client_id_low_byte_ = 0x00;
+
+ the_configuration_data__->routing_manager_host_ = 0x0000;
+ std::string its_name = its_config->get_routing_host();
+ if (its_name == "")
+ the_configuration_data__->routing_manager_host_ = the_configuration_data__->client_base_;
+
+ its_configuration_refs__++;
+ } else {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: MapViewOfFile failed (" << GetLastError() << ")";
+ }
+ } else {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: CreateFileMapping failed (" << GetLastError() << ")";
+ }
+ }
+
+ // always release mutex
+ ReleaseMutex(configuration_data_mutex);
+ } else {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: CreateMutex failed (" << GetLastError() << ")";
+ }
+
+ // cleanup in case of error
+ if (the_configuration_data__ == nullptr) {
+ if (its_descriptor != INVALID_HANDLE_VALUE) {
+ CloseHandle(its_descriptor);
+ its_descriptor = INVALID_HANDLE_VALUE;
+ }
+ if (configuration_data_mutex != INVALID_HANDLE_VALUE) {
+ CloseHandle(configuration_data_mutex);
+ configuration_data_mutex = INVALID_HANDLE_VALUE;
+ }
+ }
}
#else
const mode_t previous_mask(::umask(static_cast<mode_t>(its_config->get_umask())));
@@ -184,10 +270,6 @@ bool utility::auto_configuration_init(const std::string &_name) {
} else {
the_configuration_data__
= reinterpret_cast<configuration_data_t *>(its_segment);
- if(-1 == ::close(its_descriptor)) {
- VSOMEIP_ERROR << "utility::auto_configuration_init: "
- "close failed: " << std::strerror(errno);
- }
if (the_configuration_data__ != nullptr) {
int ret;
pthread_mutexattr_t attr;
@@ -215,21 +297,30 @@ bool utility::auto_configuration_init(const std::string &_name) {
= the_configuration_data__->client_base_;
the_configuration_data__->client_base_++;
the_configuration_data__->max_used_client_ids_index_ = 1;
+ the_configuration_data__->max_assigned_client_id_low_byte_ = 0x00;
- if (its_config->get_routing_host() == "" ||
- its_config->get_routing_host() == _name)
- is_routing_manager_host__ = true;
+ the_configuration_data__->routing_manager_host_ = 0x0000;
+ std::string its_name = its_config->get_routing_host();
+ if (its_name == "")
+ the_configuration_data__->routing_manager_host_ = the_configuration_data__->client_base_;
its_configuration_refs__++;
+ the_configuration_data__->initialized_ = 1;
+
ret = pthread_mutex_unlock(&the_configuration_data__->mutex_);
if (0 != ret) {
VSOMEIP_ERROR << "pthread_mutex_unlock() failed " << ret;
}
}
+
+ if(-1 == ::close(its_descriptor)) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: "
+ "close failed: " << std::strerror(errno);
+ }
}
}
- } else {
+ } else if (errno == EEXIST) {
const mode_t previous_mask(::umask(static_cast<mode_t>(its_config->get_umask())));
its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR,
static_cast<mode_t>(its_config->get_permissions_shm()));
@@ -238,30 +329,44 @@ bool utility::auto_configuration_init(const std::string &_name) {
VSOMEIP_ERROR << "utility::auto_configuration_init: "
"shm_open failed: " << std::strerror(errno);
} else {
- void *its_segment = mmap(0, sizeof(configuration_data_t),
- PROT_READ | PROT_WRITE, MAP_SHARED,
- its_descriptor, 0);
- if(MAP_FAILED == its_segment) {
+ // 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))) {
VSOMEIP_ERROR << "utility::auto_configuration_init: "
- "mmap failed: " << std::strerror(errno);
+ "ftruncate failed: " << std::strerror(errno);
} else {
- the_configuration_data__
- = reinterpret_cast<configuration_data_t *>(its_segment);
- if (-1 == ::close(its_descriptor)) {
+
+ void *its_segment = mmap(0, sizeof(configuration_data_t),
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ its_descriptor, 0);
+ if(MAP_FAILED == its_segment) {
VSOMEIP_ERROR << "utility::auto_configuration_init: "
- "close failed: " << std::strerror(errno);
+ "mmap failed: " << std::strerror(errno);
+ } else {
+ configuration_data_t *configuration_data
+ = reinterpret_cast<configuration_data_t *>(its_segment);
+
+ // check if it is ready for use (for 3 seconds)
+ int retry_count = 300;
+ while (configuration_data->initialized_ == 0 && --retry_count > 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+
+ if (configuration_data->initialized_ == 0) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: data in shm not initialized";
+ } else {
+ the_configuration_data__ = configuration_data;
+
+ pthread_mutex_lock(&the_configuration_data__->mutex_);
+ its_configuration_refs__++;
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+
+ if (-1 == ::close(its_descriptor)) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: "
+ "close failed: " << std::strerror(errno);
+ }
+ }
}
-#ifdef WIN32
- WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
-#else
- pthread_mutex_lock(&the_configuration_data__->mutex_);
-#endif
- its_configuration_refs__++;
-#ifdef WIN32
- ReleaseMutex(the_configuration_data__->mutex_);
-#else
- pthread_mutex_unlock(&the_configuration_data__->mutex_);
-#endif
}
}
}
@@ -269,24 +374,39 @@ bool utility::auto_configuration_init(const std::string &_name) {
return (the_configuration_data__ != nullptr);
}
-void utility::auto_configuration_exit() {
+void utility::auto_configuration_exit(client_t _client) {
+ std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__);
if (the_configuration_data__) {
#ifdef WIN32
- WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
+ // not manipulating data in shared memory, no need to take global mutex
+
+ assert(configuration_data_mutex != INVALID_HANDLE_VALUE);
+ assert(its_descriptor != INVALID_HANDLE_VALUE);
+
its_configuration_refs__--;
- ReleaseMutex(the_configuration_data__->mutex_);
+
+ if (is_routing_manager_host(_client)) {
+ set_routing_manager_host(0x0000);
+ }
if (its_configuration_refs__ == 0) {
UnmapViewOfFile(the_configuration_data__);
- }
+ the_configuration_data__ = nullptr;
- if (is_routing_manager_host__) {
CloseHandle(its_descriptor);
+ its_descriptor = NULL;
+
+ CloseHandle(configuration_data_mutex);
+ configuration_data_mutex = NULL;
}
#else
- pthread_mutex_lock(&the_configuration_data__->mutex_);
its_configuration_refs__--;
- pthread_mutex_unlock(&the_configuration_data__->mutex_);
+
+ bool unlink_shm = false;
+ if (is_routing_manager_host(_client)) {
+ set_routing_manager_host(0x0000);
+ unlink_shm = true;
+ }
if (its_configuration_refs__ == 0) {
if (-1 == ::munmap(the_configuration_data__, sizeof(configuration_data_t))) {
@@ -296,10 +416,11 @@ void utility::auto_configuration_exit() {
VSOMEIP_DEBUG << "utility::auto_configuration_exit: "
"munmap succeeded.";
the_configuration_data__ = nullptr;
+ if (unlink_shm) {
+ shm_unlink(VSOMEIP_SHM_NAME);
+ }
}
- }
- if (is_routing_manager_host__) {
- shm_unlink(VSOMEIP_SHM_NAME);
+
}
#endif
}
@@ -309,35 +430,98 @@ 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 (the_configuration_data__->used_client_ids_[i] == _client
+ || _client
+ < (the_configuration_data__->client_base_
+ + the_configuration_data__->max_assigned_client_id_low_byte_)) {
return true;
+ }
}
return false;
}
-client_t utility::request_client_id(client_t _client) {
+client_t utility::request_client_id(const std::string &_name, client_t _client) {
+ std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__);
+
if (the_configuration_data__ != nullptr) {
#ifdef WIN32
- WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
+ DWORD waitResult = WaitForSingleObject(configuration_data_mutex, INFINITE);
+ assert(waitResult == WAIT_OBJECT_0);
+ (void)waitResult;
#else
pthread_mutex_lock(&the_configuration_data__->mutex_);
#endif
+ std::shared_ptr<configuration> its_config(configuration::get());
+ const std::string its_name = its_config->get_routing_host();
+ bool set_client_as_manager_host(false);
+ if (its_name != "" && its_name == _name) {
+ if (the_configuration_data__->routing_manager_host_ == 0x0000) {
+ set_client_as_manager_host = true;
+ } else {
+ VSOMEIP_ERROR << "Routing manager with id " << the_configuration_data__->routing_manager_host_ << " already exists.";
+#ifdef WIN32
+ BOOL releaseResult = ReleaseMutex(configuration_data_mutex);
+ assert(releaseResult);
+ (void)releaseResult;
+#else
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+#endif
+ return VSOMEIP_DIAGNOSIS_ADDRESS;
+ }
+ } else if (its_name == "" && the_configuration_data__->routing_manager_host_ == 0x0000) {
+ set_client_as_manager_host = true;
+ }
+
if (the_configuration_data__->max_used_client_ids_index_
== VSOMEIP_MAX_CLIENTS) {
+ VSOMEIP_ERROR << "Max amount of possible concurrent active"
+ << " vsomeip applications reached.";
+#ifdef WIN32
+ BOOL releaseResult = ReleaseMutex(configuration_data_mutex);
+ assert(releaseResult);
+ (void)releaseResult;
+#else
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+#endif
return ILLEGAL_CLIENT;
}
+ bool configured_and_not_used(false);
+ if (_client != ILLEGAL_CLIENT && !is_used_client_id(_client)) {
+ configured_and_not_used = true;
+ }
+
if (_client == ILLEGAL_CLIENT || is_used_client_id(_client)) {
_client = the_configuration_data__->client_base_;
}
- while (is_used_client_id(_client)) _client++;
+ while (is_used_client_id(_client)) {
+ if ((_client & 0x00FF) + 1 > VSOMEIP_MAX_CLIENTS) {
+ _client = the_configuration_data__->client_base_;
+ the_configuration_data__->max_assigned_client_id_low_byte_ = 0;
+ } else {
+ _client++;
+ }
+ }
+ if (!configured_and_not_used) {
+ the_configuration_data__->max_assigned_client_id_low_byte_ =
+ static_cast<unsigned char>((_client & 0x00FF)
+ % VSOMEIP_MAX_CLIENTS);
+ }
+
+ if (set_client_as_manager_host) {
+ the_configuration_data__->routing_manager_host_ = _client;
+ }
the_configuration_data__->used_client_ids_[
the_configuration_data__->max_used_client_ids_index_] = _client;
the_configuration_data__->max_used_client_ids_index_++;
+
+
#ifdef WIN32
- ReleaseMutex(the_configuration_data__->mutex_);
+ BOOL releaseResult = ReleaseMutex(configuration_data_mutex);
+ assert(releaseResult);
+ (void)releaseResult;
#else
pthread_mutex_unlock(&the_configuration_data__->mutex_);
#endif
@@ -347,9 +531,10 @@ client_t utility::request_client_id(client_t _client) {
}
void utility::release_client_id(client_t _client) {
+ std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__);
if (the_configuration_data__ != nullptr) {
#ifdef WIN32
- WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
+ WaitForSingleObject(configuration_data_mutex, INFINITE);
#else
pthread_mutex_lock(&the_configuration_data__->mutex_);
#endif
@@ -359,7 +544,7 @@ void utility::release_client_id(client_t _client) {
i++;
}
- if (i < the_configuration_data__->max_used_client_ids_index_) {
+ if (i <= the_configuration_data__->max_used_client_ids_index_) {
the_configuration_data__->max_used_client_ids_index_--;
for (; i < the_configuration_data__->max_used_client_ids_index_; i++) {
the_configuration_data__->used_client_ids_[i]
@@ -367,15 +552,55 @@ void utility::release_client_id(client_t _client) {
}
}
#ifdef WIN32
- ReleaseMutex(the_configuration_data__->mutex_);
+ ReleaseMutex(configuration_data_mutex);
#else
pthread_mutex_unlock(&the_configuration_data__->mutex_);
#endif
}
}
-bool utility::is_routing_manager_host() {
- return is_routing_manager_host__;
+bool utility::is_routing_manager_host(client_t _client) {
+ if (the_configuration_data__ == nullptr) {
+ VSOMEIP_ERROR << "utility::is_routing_manager_host: configuration data not available";
+ return false;
+ }
+
+#ifdef WIN32
+ WaitForSingleObject(configuration_data_mutex, INFINITE);
+#else
+ pthread_mutex_lock(&the_configuration_data__->mutex_);
+#endif
+
+ bool is_routing_manager = (the_configuration_data__->routing_manager_host_ == _client);
+
+#ifdef WIN32
+ ReleaseMutex(configuration_data_mutex);
+#else
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+#endif
+
+ return is_routing_manager;
+}
+
+void utility::set_routing_manager_host(client_t _client) {
+ if (the_configuration_data__ == nullptr) {
+ VSOMEIP_ERROR << "utility::set_routing_manager_host: configuration data not available";
+ return;
+ }
+
+#ifdef WIN32
+ WaitForSingleObject(configuration_data_mutex, INFINITE);
+#else
+ pthread_mutex_lock(&the_configuration_data__->mutex_);
+#endif
+
+ the_configuration_data__->routing_manager_host_ = _client;
+
+#ifdef WIN32
+ ReleaseMutex(configuration_data_mutex);
+#else
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+#endif
}
} // namespace vsomeip
diff --git a/interface/vsomeip/application.hpp b/interface/vsomeip/application.hpp
index 67b35b5..64f60ce 100644
--- a/interface/vsomeip/application.hpp
+++ b/interface/vsomeip/application.hpp
@@ -6,11 +6,14 @@
#ifndef VSOMEIP_APPLICATION_HPP
#define VSOMEIP_APPLICATION_HPP
+#include <chrono>
#include <memory>
#include <set>
+#include <map>
#include <vsomeip/primitive_types.hpp>
#include <vsomeip/enumeration_types.hpp>
+#include <vsomeip/function_types.hpp>
#include <vsomeip/constants.hpp>
#include <vsomeip/handler.hpp>
@@ -78,9 +81,9 @@ public:
// Send a message
virtual void send(std::shared_ptr<message> _message, bool _flush = true) = 0;
- // Set a field or fire an event
+ // Set a field or fire an event (without/with the ability to force notification for field)
virtual void notify(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload) const = 0;
+ event_t _event, std::shared_ptr<payload> _payload) const = 0;
virtual void notify_one(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload,
@@ -123,6 +126,27 @@ public:
// Routing/SD hosted by this application!?
virtual bool is_routing() const = 0;
+
+ virtual void offer_event(service_t _service,
+ instance_t _instance, event_t _event,
+ const std::set<eventgroup_t> &_eventgroups,
+ bool _is_field,
+ std::chrono::milliseconds _cycle,
+ bool _change_resets_cycle,
+ const epsilon_change_func_t &_epsilon_change_func) = 0;
+
+ virtual void notify(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload,
+ bool _force) const = 0;
+
+ virtual void notify_one(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload,
+ client_t _client, bool _force) const = 0;
+
+ typedef std::map<service_t, std::map<instance_t, std::map<major_version_t, minor_version_t >>> available_t;
+ virtual bool are_available(available_t &_available,
+ service_t _service = ANY_SERVICE, instance_t _instance = ANY_INSTANCE,
+ major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const = 0;
};
} // namespace vsomeip
diff --git a/interface/vsomeip/export.hpp b/interface/vsomeip/export.hpp
index ab4af7f..16b4d23 100644
--- a/interface/vsomeip/export.hpp
+++ b/interface/vsomeip/export.hpp
@@ -7,9 +7,17 @@
#define __EXPORT__HPP__
#if WIN32
-#define VSOMEIP_EXPORT __declspec(dllexport)
+ #define VSOMEIP_EXPORT __declspec(dllexport)
+ #define VSOMEIP_EXPORT_CLASS_EXPLICIT
+
+ #if VSOMEIP_DLL_COMPILATION
+ #define VSOMEIP_IMPORT_EXPORT __declspec(dllexport)
+ #else
+ #define VSOMEIP_IMPORT_EXPORT __declspec(dllimport)
+ #endif
#else
-#define VSOMEIP_EXPORT
+ #define VSOMEIP_EXPORT
+ #define VSOMEIP_IMPORT_EXPORT
#endif
#endif
diff --git a/interface/vsomeip/function_types.hpp b/interface/vsomeip/function_types.hpp
new file mode 100644
index 0000000..7db3f1e
--- /dev/null
+++ b/interface/vsomeip/function_types.hpp
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef VSOMEIP_FUNCTION_TYPES_HPP
+#define VSOMEIP_FUNCTION_TYPES_HPP
+
+#include <functional>
+#include <memory>
+
+namespace vsomeip {
+
+class payload;
+
+typedef std::function<
+ bool (const std::shared_ptr<payload> &,
+ const std::shared_ptr<payload> &) > epsilon_change_func_t;
+
+} // namespace vsomeip
+
+#endif // VSOMEIP_FUNCTION_TYPES_HPP
diff --git a/interface/vsomeip/payload.hpp b/interface/vsomeip/payload.hpp
index 0186d30..10a3177 100644
--- a/interface/vsomeip/payload.hpp
+++ b/interface/vsomeip/payload.hpp
@@ -33,6 +33,9 @@ public:
VSOMEIP_EXPORT virtual length_t get_length() const = 0;
VSOMEIP_EXPORT virtual void set_capacity(length_t _length) = 0;
+
+ VSOMEIP_EXPORT virtual void set_data(
+ std::vector<byte_t> &&_data) = 0;
};
} // namespace vsomeip
diff --git a/interface/vsomeip/runtime.hpp b/interface/vsomeip/runtime.hpp
index fbdbded..14ecb60 100644
--- a/interface/vsomeip/runtime.hpp
+++ b/interface/vsomeip/runtime.hpp
@@ -19,7 +19,7 @@ class application;
class message;
class payload;
-class VSOMEIP_EXPORT runtime {
+class VSOMEIP_IMPORT_EXPORT runtime {
public:
static std::string get_property(const std::string &_name);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index e56ab54..358154c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1006,6 +1006,54 @@ if(NOT ${TESTS_BAT})
${TEST_SUBSCRIBE_NOTIFY_SERVICE}
)
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_same_service_id_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_same_service_id_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_autoconfig_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_autoconfig_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
# copy starter scripts into builddir
set(TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER ${TEST_SUBSCRIBE_NOTIFY_NAME}_master_starter.sh)
copy_to_builddir(${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER}
@@ -1160,6 +1208,299 @@ if(NOT ${TESTS_BAT})
)
endif()
+##############################################################################
+# initial event tests
+##############################################################################
+if(NOT ${TESTS_BAT})
+ set(TEST_INITIAL_EVENT_NAME initial_event_test)
+ set(TEST_INITIAL_EVENT_SERVICE ${TEST_INITIAL_EVENT_NAME}_service)
+ add_executable(${TEST_INITIAL_EVENT_SERVICE} initial_event_tests/${TEST_INITIAL_EVENT_NAME}_service.cpp)
+ target_link_libraries(${TEST_INITIAL_EVENT_SERVICE}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_INITIAL_EVENT_CLIENT ${TEST_INITIAL_EVENT_NAME}_client)
+ add_executable(${TEST_INITIAL_EVENT_CLIENT} initial_event_tests/${TEST_INITIAL_EVENT_NAME}_client.cpp)
+ target_link_libraries(${TEST_INITIAL_EVENT_CLIENT}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_INITIAL_EVENT_AVAILABILITY_CHECKER ${TEST_INITIAL_EVENT_NAME}_availability_checker)
+ add_executable(${TEST_INITIAL_EVENT_AVAILABILITY_CHECKER} initial_event_tests/${TEST_INITIAL_EVENT_NAME}_availability_checker.cpp)
+ target_link_libraries(${TEST_INITIAL_EVENT_AVAILABILITY_CHECKER}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_INITIAL_EVENT_STOP_SERVICE ${TEST_INITIAL_EVENT_NAME}_stop_service)
+ add_executable(${TEST_INITIAL_EVENT_STOP_SERVICE} initial_event_tests/${TEST_INITIAL_EVENT_NAME}_stop_service.cpp)
+ target_link_libraries(${TEST_INITIAL_EVENT_STOP_SERVICE}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ # Copy config files for test into $BUILDDIR/test
+ set(TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_partial_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_partial_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_same_client_ids_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_same_client_ids_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_same_client_ids_diff_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_same_client_ids_diff_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_same_service_id_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ set(TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE
+ ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_same_service_id_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/conf/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_SLAVE_CONFIG_FILE}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+
+ # copy starter scripts into builddir
+ set(TEST_INITIAL_EVENT_MASTER_STARTER ${TEST_INITIAL_EVENT_NAME}_master_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_MASTER_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+ set(TEST_INITIAL_EVENT_SLAVE_STARTER ${TEST_INITIAL_EVENT_NAME}_slave_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/initial_event_tests/${TEST_INITIAL_EVENT_SLAVE_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_SLAVE_STARTER}
+ ${TEST_INITIAL_EVENT_SERVICE}
+ )
+endif()
+
+##############################################################################
+# offer tests
+##############################################################################
+if(NOT ${TESTS_BAT})
+ set(TEST_OFFER_NAME offer_test)
+ set(TEST_OFFER_SERVICE ${TEST_OFFER_NAME}_service)
+ add_executable(${TEST_OFFER_SERVICE} offer_tests/${TEST_OFFER_NAME}_service.cpp)
+ target_link_libraries(${TEST_OFFER_SERVICE}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_OFFER_CLIENT ${TEST_OFFER_NAME}_client)
+ add_executable(${TEST_OFFER_CLIENT} offer_tests/${TEST_OFFER_NAME}_client.cpp)
+ target_link_libraries(${TEST_OFFER_CLIENT}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_OFFER_SERVICE_EXTERNAL ${TEST_OFFER_NAME}_service_external)
+ add_executable(${TEST_OFFER_SERVICE_EXTERNAL} offer_tests/${TEST_OFFER_NAME}_service_external.cpp)
+ target_link_libraries(${TEST_OFFER_SERVICE_EXTERNAL}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER ${TEST_OFFER_NAME}_external_sd_msg_sender)
+ add_executable(${TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER} offer_tests/${TEST_OFFER_NAME}_external_sd_msg_sender.cpp)
+ target_link_libraries(${TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER}
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ # copy starter scripts into builddir
+ set(TEST_OFFER_LOCAL_STARTER ${TEST_OFFER_NAME}_local_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_LOCAL_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_LOCAL_STARTER}
+ ${TEST_OFFER_SERVICE}
+ )
+
+ # Copy config file for local test into $BUILDDIR/test
+ set(TEST_OFFER_LOCAL_CONFIG_FILE ${TEST_OFFER_NAME}_local.json)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_LOCAL_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_LOCAL_CONFIG_FILE}
+ ${TEST_OFFER_SERVICE}
+ )
+
+ # generate and copy json files into builddir for external test
+ set(TEST_OFFER_SLAVE_CONFIG_FILE ${TEST_OFFER_NAME}_external_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/conf/${TEST_OFFER_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_SLAVE_CONFIG_FILE}
+ ${TEST_OFFER_SERVICE}
+ )
+
+ set(TEST_OFFER_MASTER_CONFIG_FILE ${TEST_OFFER_NAME}_external_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/conf/${TEST_OFFER_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_MASTER_CONFIG_FILE}
+ ${TEST_OFFER_SERVICE}
+ )
+
+ # Copy starter scripts for external test to $BUILDDIR/test
+ set(TEST_OFFER_EXTERNAL_MASTER_STARTER ${TEST_OFFER_NAME}_external_master_starter.sh)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/conf/${TEST_OFFER_EXTERNAL_MASTER_STARTER}.in
+ ${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_EXTERNAL_MASTER_STARTER}
+ @ONLY)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_EXTERNAL_MASTER_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_EXTERNAL_MASTER_STARTER}
+ ${TEST_OFFER_SERVICE}
+ )
+ set(TEST_OFFER_EXTERNAL_SLAVE_STARTER ${TEST_OFFER_NAME}_external_slave_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/offer_tests/${TEST_OFFER_EXTERNAL_SLAVE_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_EXTERNAL_SLAVE_STARTER}
+ ${TEST_OFFER_SERVICE}
+ )
+endif()
##############################################################################
# Add for every test a dependency to gtest
@@ -1185,6 +1526,14 @@ if(NOT ${TESTS_BAT})
add_dependencies(${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE} gtest)
add_dependencies(${TEST_CPU_LOAD_SERVICE} gtest)
add_dependencies(${TEST_CPU_LOAD_CLIENT} gtest)
+ add_dependencies(${TEST_INITIAL_EVENT_SERVICE} gtest)
+ add_dependencies(${TEST_INITIAL_EVENT_CLIENT} gtest)
+ add_dependencies(${TEST_INITIAL_EVENT_AVAILABILITY_CHECKER} gtest)
+ add_dependencies(${TEST_INITIAL_EVENT_STOP_SERVICE} gtest)
+ add_dependencies(${TEST_OFFER_SERVICE} gtest)
+ add_dependencies(${TEST_OFFER_CLIENT} gtest)
+ add_dependencies(${TEST_OFFER_SERVICE_EXTERNAL} gtest)
+ add_dependencies(${TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER} gtest)
else()
add_dependencies(${TEST_LOCAL_ROUTING_SERVICE} gtest)
add_dependencies(${TEST_LOCAL_ROUTING_CLIENT} gtest)
@@ -1214,6 +1563,14 @@ if(NOT ${TESTS_BAT})
add_dependencies(build_tests ${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE})
add_dependencies(build_tests ${TEST_CPU_LOAD_SERVICE})
add_dependencies(build_tests ${TEST_CPU_LOAD_CLIENT})
+ add_dependencies(build_tests ${TEST_INITIAL_EVENT_SERVICE})
+ add_dependencies(build_tests ${TEST_INITIAL_EVENT_CLIENT})
+ add_dependencies(build_tests ${TEST_INITIAL_EVENT_AVAILABILITY_CHECKER})
+ add_dependencies(build_tests ${TEST_INITIAL_EVENT_STOP_SERVICE})
+ add_dependencies(build_tests ${TEST_OFFER_SERVICE})
+ add_dependencies(build_tests ${TEST_OFFER_CLIENT})
+ add_dependencies(build_tests ${TEST_OFFER_SERVICE_EXTERNAL})
+ add_dependencies(build_tests ${TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER})
else()
add_dependencies(build_tests ${TEST_LOCAL_ROUTING_SERVICE})
add_dependencies(build_tests ${TEST_LOCAL_ROUTING_CLIENT})
@@ -1300,7 +1657,7 @@ if(NOT ${TESTS_BAT})
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_MASTER_STARTER} ${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE})
set_tests_properties(${TEST_CLIENT_ID_NAME}_diff_client_ids_partial_same_ports PROPERTIES TIMEOUT 60)
- # subscribe notify id tests
+ # 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})
set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_udp PROPERTIES TIMEOUT 60)
@@ -1345,7 +1702,15 @@ if(NOT ${TESTS_BAT})
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} TCP_AND_UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE})
set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_partial_same_ports_both_tcp_and_udp PROPERTIES TIMEOUT 60)
- # subscribe notify one id tests
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_same_service_id_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE} SAME_SERVICE_ID)
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_same_service_id_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_autoconfig_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_AUTOCONFIG_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_same_service_id_udp PROPERTIES TIMEOUT 60)
+
+ # subscribe notify one id tests
add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_udp
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_udp PROPERTIES TIMEOUT 60)
@@ -1371,6 +1736,63 @@ if(NOT ${TESTS_BAT})
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_MASTER_STARTER}
)
set_tests_properties(${TEST_CPU_LOAD_NAME} PROPERTIES TIMEOUT 1500)
+
+ # initial event tests
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} UDP ${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} TCP ${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_tcp PROPERTIES TIMEOUT 60)
+# TODO
+# add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_both_tcp_and_udp
+# COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} TCP_AND_UDP ${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+# set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_both_tcp_and_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_prefer_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} PREFER_UDP ${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_prefer_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_prefer_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} PREFER_TCP ${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_prefer_tcp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} UDP ${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} TCP ${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_tcp PROPERTIES TIMEOUT 60)
+# TODO
+# add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_both_tcp_and_udp
+# COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} TCP_AND_UDP ${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+# set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_both_tcp_and_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_prefer_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} PREFER_UDP ${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_prefer_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_prefer_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} PREFER_TCP ${TEST_INITIAL_EVENT_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_same_ports_prefer_tcp PROPERTIES TIMEOUT 60)
+# TODO
+# add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_partial_same_ports_both_tcp_and_udp
+# COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} TCP_AND_UDP ${TEST_INITIAL_EVENT_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE})
+# set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_partial_same_ports_both_tcp_and_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_same_service_id_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_INITIAL_EVENT_MASTER_STARTER} UDP ${TEST_INITIAL_EVENT_DIFF_IDS_DIFF_PORTS_SAME_SERVICEID_MASTER_CONFIG_FILE} SAME_SERVICE_ID)
+ set_tests_properties(${TEST_INITIAL_EVENT_NAME}_diff_client_ids_diff_ports_same_service_id_udp PROPERTIES TIMEOUT 60)
+
+ # offer tests
+ add_test(NAME ${TEST_OFFER_NAME}_local
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_LOCAL_STARTER})
+ set_tests_properties(${TEST_OFFER_NAME}_local PROPERTIES TIMEOUT 90)
+ add_test(NAME ${TEST_OFFER_NAME}_external
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_EXTERNAL_MASTER_STARTER})
+ set_tests_properties(${TEST_OFFER_NAME}_local PROPERTIES TIMEOUT 180)
else()
# Routing tests
add_test(NAME ${TEST_LOCAL_ROUTING_NAME}
diff --git a/test/application_tests/application_test_starter.sh b/test/application_tests/application_test_starter.sh
index a72c6c7..40ae927 100755
--- a/test/application_tests/application_test_starter.sh
+++ b/test/application_tests/application_test_starter.sh
@@ -39,6 +39,7 @@ then
fi
kill $DAEMON_PID
+wait $DAEMON_PID
export VSOMEIP_CONFIGURATION=application_test_daemon.json
../daemon/./vsomeipd &
diff --git a/test/header_factory_tests/header_factory_test.cpp b/test/header_factory_tests/header_factory_test.cpp
index c02fd74..e034769 100644
--- a/test/header_factory_tests/header_factory_test.cpp
+++ b/test/header_factory_tests/header_factory_test.cpp
@@ -69,7 +69,6 @@ TEST_F(someip_header_factory_test, create_request_and_response_test)
ASSERT_EQ(response_->get_service(), request_->get_service());
ASSERT_EQ(response_->get_method(), request_->get_method());
- ASSERT_EQ(response_->get_client(), request_->get_client());
ASSERT_EQ(response_->get_session(), request_->get_session());
// length? --> gets only set if a payload is added
diff --git a/test/header_factory_tests/header_factory_test_client.cpp b/test/header_factory_tests/header_factory_test_client.cpp
index dc4a041..b6f3858 100644
--- a/test/header_factory_tests/header_factory_test_client.cpp
+++ b/test/header_factory_tests/header_factory_test_client.cpp
@@ -105,7 +105,6 @@ void header_factory_test_client::on_message(const std::shared_ptr<vsomeip::messa
number_of_acknowledged_messages_++;
ASSERT_EQ(_response->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID);
ASSERT_EQ(_response->get_instance(), vsomeip_test::TEST_SERVICE_INSTANCE_ID);
- ASSERT_EQ(_response->get_client(), vsomeip_test::TEST_CLIENT_CLIENT_ID);
ASSERT_EQ(_response->get_session(),
static_cast<vsomeip::session_t>(number_of_acknowledged_messages_));
if(number_of_acknowledged_messages_ == number_of_messages_to_send_) {
diff --git a/test/header_factory_tests/header_factory_test_service.cpp b/test/header_factory_tests/header_factory_test_service.cpp
index 4d45d9f..0367d40 100644
--- a/test/header_factory_tests/header_factory_test_service.cpp
+++ b/test/header_factory_tests/header_factory_test_service.cpp
@@ -47,7 +47,7 @@ void header_factory_test_service::stop()
vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID);
app_->unregister_state_handler();
app_->stop();
- std::thread t([](){ usleep(1000000 * 5);});
+ std::thread t([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));});
t.join();
}
@@ -109,9 +109,6 @@ void header_factory_test_service::on_message(const std::shared_ptr<vsomeip::mess
// TR_SOMEIP_00055
ASSERT_EQ(_request->get_message_type(), vsomeip::message_type_e::MT_REQUEST);
- // make sure the message was sent from the service
- ASSERT_EQ(_request->get_client(), vsomeip_test::TEST_CLIENT_CLIENT_ID);
-
// check the session id.
ASSERT_EQ(_request->get_session(), static_cast<vsomeip::session_t>(number_of_received_messages_));
@@ -146,7 +143,7 @@ void header_factory_test_service::run()
while (!blocked_)
condition_.wait(its_lock);
- std::thread t([](){ usleep(1000000 * 5);});
+ std::thread t([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));});
t.join();
app_->stop();
}
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in
new file mode 100644
index 0000000..845cfe4
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in
@@ -0,0 +1,75 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30002",
+ "reliable":
+ {
+ "port":"40002",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3333",
+ "instance":"0x0001",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x8888",
+ "instance":"0x0001",
+ "unreliable":"8888"
+ }
+ ],
+ "routing":"initial_event_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in
new file mode 100644
index 0000000..4348be8
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in
@@ -0,0 +1,75 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x1111",
+ "instance":"0x0002",
+ "unreliable":"30002",
+ "reliable":
+ {
+ "port":"40002",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x1111",
+ "instance":"0x0003",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x8888",
+ "instance":"0x0001",
+ "unreliable":"8888"
+ }
+ ],
+ "routing":"initial_event_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in
new file mode 100644
index 0000000..5760288
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in
@@ -0,0 +1,76 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "diagnosis" : "0x63",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"initial_event_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"initial_event_test_service_six",
+ "id":"0x6666"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30004",
+ "reliable":
+ {
+ "port":"40004",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0002",
+ "unreliable":"30005",
+ "reliable":
+ {
+ "port":"40005",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0003",
+ "unreliable":"30006",
+ "reliable":
+ {
+ "port":"40006",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x9999",
+ "instance":"0x0001",
+ "unreliable":"9999"
+ }
+ ],
+ "routing":"initial_event_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in
new file mode 100644
index 0000000..e60c7b8
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in
@@ -0,0 +1,76 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "diagnosis" : "0x63",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"initial_event_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"initial_event_test_service_six",
+ "id":"0x6666"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4444",
+ "instance":"0x0001",
+ "unreliable":"30004",
+ "reliable":
+ {
+ "port":"40004",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5555",
+ "instance":"0x0001",
+ "unreliable":"30005",
+ "reliable":
+ {
+ "port":"40005",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6666",
+ "instance":"0x0001",
+ "unreliable":"30006",
+ "reliable":
+ {
+ "port":"40006",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x9999",
+ "instance":"0x0001",
+ "unreliable":"9999"
+ }
+ ],
+ "routing":"initial_event_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in
new file mode 100644
index 0000000..3a7c837
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in
@@ -0,0 +1,75 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40002",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3333",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x8888",
+ "instance":"0x0001",
+ "unreliable":"8888"
+ }
+ ],
+ "routing":"initial_event_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in
new file mode 100644
index 0000000..e296a42
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in
@@ -0,0 +1,76 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "diagnosis" : "0x63",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"initial_event_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"initial_event_test_service_six",
+ "id":"0x6666"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4444",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40004",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5555",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40005",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6666",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40006",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x9999",
+ "instance":"0x0001",
+ "unreliable":"9999"
+ }
+ ],
+ "routing":"initial_event_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in
new file mode 100644
index 0000000..17476ab
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in
@@ -0,0 +1,75 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3333",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x8888",
+ "instance":"0x0001",
+ "unreliable":"8888"
+ }
+ ],
+ "routing":"initial_event_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in
new file mode 100644
index 0000000..2f8d7d9
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in
@@ -0,0 +1,76 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "diagnosis" : "0x63",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"initial_event_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"initial_event_test_service_six",
+ "id":"0x6666"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4444",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5555",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6666",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x9999",
+ "instance":"0x0001",
+ "unreliable":"9999"
+ }
+ ],
+ "routing":"initial_event_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in b/test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in
new file mode 100644
index 0000000..845cfe4
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in
@@ -0,0 +1,75 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30002",
+ "reliable":
+ {
+ "port":"40002",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3333",
+ "instance":"0x0001",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x8888",
+ "instance":"0x0001",
+ "unreliable":"8888"
+ }
+ ],
+ "routing":"initial_event_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in b/test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in
new file mode 100644
index 0000000..df799e2
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in
@@ -0,0 +1,76 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "diagnosis" : "0x63",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_four",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_five",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_six",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4444",
+ "instance":"0x0001",
+ "unreliable":"30004",
+ "reliable":
+ {
+ "port":"40004",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5555",
+ "instance":"0x0001",
+ "unreliable":"30005",
+ "reliable":
+ {
+ "port":"40005",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6666",
+ "instance":"0x0001",
+ "unreliable":"30006",
+ "reliable":
+ {
+ "port":"40006",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x9999",
+ "instance":"0x0001",
+ "unreliable":"9999"
+ }
+ ],
+ "routing":"initial_event_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in b/test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in
new file mode 100644
index 0000000..17476ab
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in
@@ -0,0 +1,75 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3333",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x8888",
+ "instance":"0x0001",
+ "unreliable":"8888"
+ }
+ ],
+ "routing":"initial_event_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in b/test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in
new file mode 100644
index 0000000..c8113c3
--- /dev/null
+++ b/test/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in
@@ -0,0 +1,76 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "diagnosis" : "0x63",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"initial_event_test_service_four",
+ "id":"0x1111"
+ },
+ {
+ "name":"initial_event_test_service_five",
+ "id":"0x2222"
+ },
+ {
+ "name":"initial_event_test_service_six",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4444",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5555",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6666",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x9999",
+ "instance":"0x0001",
+ "unreliable":"9999"
+ }
+ ],
+ "routing":"initial_event_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/initial_event_tests/initial_event_test_availability_checker.cpp b/test/initial_event_tests/initial_event_test_availability_checker.cpp
new file mode 100644
index 0000000..772df22
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_availability_checker.cpp
@@ -0,0 +1,160 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "initial_event_test_globals.hpp"
+
+
+class initial_event_test_availability_checker {
+public:
+ initial_event_test_availability_checker(int _client_number,
+ std::array<initial_event_test::service_info, 7> _service_infos) :
+ client_number_(_client_number),
+ service_infos_(_service_infos),
+ app_(vsomeip::runtime::get()->create_application()),
+ wait_until_registered_(true),
+ wait_until_other_services_available_(true),
+ wait_for_stop_(true),
+ stop_thread_(std::bind(&initial_event_test_availability_checker::wait_for_stop, this)) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&initial_event_test_availability_checker::on_state, this,
+ std::placeholders::_1));
+
+ // register availability for all other services and request their event.
+ for(const auto& i : service_infos_) {
+ if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) {
+ continue;
+ }
+ other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false;
+ app_->register_availability_handler(i.service_id, i.instance_id,
+ std::bind(&initial_event_test_availability_checker::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ app_->request_service(i.service_id, i.instance_id);
+ }
+
+ app_->start();
+ }
+
+ ~initial_event_test_availability_checker() {
+ stop_thread_.join();
+ }
+
+ 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_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ if(_is_available) {
+ auto its_service = other_services_available_.find(std::make_pair(_service, _instance));
+ if(its_service != other_services_available_.end()) {
+ if(its_service->second != _is_available) {
+ its_service->second = true;
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_ << "] Service ["
+ << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
+ << "] is available.";
+
+ }
+ }
+
+ if(std::all_of(other_services_available_.cbegin(),
+ other_services_available_.cend(),
+ [](const std::map<std::pair<vsomeip::service_t,
+ vsomeip::instance_t>, bool>::value_type& v) {
+ return v.second;})) {
+
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ wait_for_stop_ = false;
+ stop_condition_.notify_one();
+ }
+ }
+ }
+
+ void wait_for_stop() {
+ std::unique_lock<std::mutex> its_lock(stop_mutex_);
+ while (wait_for_stop_) {
+ stop_condition_.wait(its_lock);
+ }
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_ << "] all services are available. Going down";
+ app_->stop();
+ }
+
+private:
+ int client_number_;
+ std::array<initial_event_test::service_info, 7> service_infos_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_;
+
+ bool wait_until_registered_;
+ bool wait_until_other_services_available_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+
+ bool wait_for_stop_;
+ std::mutex stop_mutex_;
+ std::condition_variable stop_condition_;
+ std::thread stop_thread_;
+};
+
+static int client_number;
+static bool use_same_service_id;
+
+TEST(someip_initial_event_test, wait_for_availability_and_exit)
+{
+ if(use_same_service_id) {
+ initial_event_test_availability_checker its_sample(client_number,
+ initial_event_test::service_infos_same_service_id);
+ } else {
+ initial_event_test_availability_checker its_sample(client_number,
+ initial_event_test::service_infos);
+ }
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cerr << "Please specify a client number and subscription type, like: " << argv[0] << " 2 SAME_SERVICE_ID" << std::endl;
+ std::cerr << "Valid client numbers are from 0 to 0xFFFF" << std::endl;
+ std::cerr << "If SAME_SERVICE_ID is specified as third parameter the test is run w/ multiple instances of the same service" << std::endl;
+ return 1;
+ }
+
+ client_number = std::stoi(std::string(argv[1]), nullptr);
+
+ if (argc >= 3 && std::string("SAME_SERVICE_ID") == std::string(argv[2])) {
+ use_same_service_id = true;
+ } else {
+ use_same_service_id = false;
+ }
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/initial_event_tests/initial_event_test_client.cpp b/test/initial_event_tests/initial_event_test_client.cpp
new file mode 100644
index 0000000..5ee194e
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_client.cpp
@@ -0,0 +1,284 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "initial_event_test_globals.hpp"
+
+
+class initial_event_test_client {
+public:
+ initial_event_test_client(int _client_number,
+ vsomeip::subscription_type_e _subscription_type,
+ std::array<initial_event_test::service_info, 7> _service_infos) :
+ client_number_(_client_number),
+ service_infos_(_service_infos),
+ subscription_type_(_subscription_type),
+ app_(vsomeip::runtime::get()->create_application()),
+ wait_until_registered_(true),
+ wait_until_other_services_available_(true),
+ wait_for_stop_(true),
+ stop_thread_(std::bind(&initial_event_test_client::wait_for_stop, this)) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&initial_event_test_client::on_state, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
+ std::bind(&initial_event_test_client::on_message, this,
+ std::placeholders::_1));
+
+ // register availability for all other services and request their event.
+ for(const auto& i : service_infos_) {
+ if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) {
+ continue;
+ }
+ app_->register_availability_handler(i.service_id, i.instance_id,
+ std::bind(&initial_event_test_client::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ app_->request_service(i.service_id, i.instance_id);
+
+ std::set<vsomeip::eventgroup_t> its_eventgroups;
+ its_eventgroups.insert(i.eventgroup_id);
+ app_->request_event(i.service_id, i.instance_id, i.event_id, its_eventgroups, true);
+
+ other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false;
+ other_services_received_notification_[std::make_pair(i.service_id, i.method_id)] = 0;
+
+ app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id,
+ vsomeip::DEFAULT_MAJOR, subscription_type_);
+ }
+
+ app_->start();
+ }
+
+ ~initial_event_test_client() {
+ stop_thread_.join();
+ }
+
+ 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_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ if(_is_available) {
+ auto its_service = other_services_available_.find(std::make_pair(_service, _instance));
+ if(its_service != other_services_available_.end()) {
+ if(its_service->second != _is_available) {
+ its_service->second = true;
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_ << "] Service ["
+ << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
+ << "] is available.";
+
+ }
+ }
+
+ if(std::all_of(other_services_available_.cbegin(),
+ other_services_available_.cend(),
+ [](const std::map<std::pair<vsomeip::service_t,
+ vsomeip::instance_t>, bool>::value_type& v) {
+ return v.second;})) {
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_ << "] all services are available.";
+ }
+ }
+ }
+
+ void on_message(const std::shared_ptr<vsomeip::message> &_message) {
+ if(_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) {
+
+ other_services_received_notification_[std::make_pair(_message->get_service(),
+ _message->get_method())]++;
+
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_ << "] "
+ << "Received a notification with Client/Session [" << std::setw(4)
+ << std::setfill('0') << std::hex << _message->get_client() << "/"
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _message->get_session() << "] from Service/Method ["
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _message->get_service() << "/" << std::setw(4) << std::setfill('0')
+ << std::hex << _message->get_method() <<"] (now have: "
+ << std::dec << other_services_received_notification_[std::make_pair(_message->get_service(),
+ _message->get_method())] << ")";
+
+ std::shared_ptr<vsomeip::payload> its_payload(_message->get_payload());
+ EXPECT_EQ(2u, its_payload->get_length());
+ EXPECT_EQ((_message->get_service() & 0xFF00 ) >> 8, its_payload->get_data()[0]);
+ EXPECT_EQ((_message->get_service() & 0xFF), its_payload->get_data()[1]);
+ bool notify(false);
+ switch(subscription_type_) {
+ case vsomeip::subscription_type_e::SU_UNRELIABLE:
+ case vsomeip::subscription_type_e::SU_RELIABLE:
+ case vsomeip::subscription_type_e::SU_PREFER_UNRELIABLE:
+ case vsomeip::subscription_type_e::SU_PREFER_RELIABLE:
+ if (all_notifications_received()) {
+ notify = true;
+ }
+ break;
+ case vsomeip::subscription_type_e::SU_RELIABLE_AND_UNRELIABLE:
+ if (all_notifications_received_tcp_and_udp()) {
+ notify = true;
+ }
+ break;
+ }
+
+ if(notify) {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ wait_for_stop_ = false;
+ stop_condition_.notify_one();
+ }
+ }
+ }
+
+ bool all_notifications_received() {
+ return std::all_of(
+ other_services_received_notification_.cbegin(),
+ other_services_received_notification_.cend(),
+ [&](const std::map<std::pair<vsomeip::service_t,
+ vsomeip::method_t>, std::uint32_t>::value_type& v)
+ {
+ return v.second == initial_event_test::notifications_to_send;
+ }
+ );
+ }
+
+ bool all_notifications_received_tcp_and_udp() {
+ std::uint32_t received_twice(0);
+ std::uint32_t received_normal(0);
+ for(const auto &v : other_services_received_notification_) {
+ if (v.second == initial_event_test::notifications_to_send * 2) {
+ received_twice++;
+ } else if(v.second == initial_event_test::notifications_to_send) {
+ received_normal++;
+ }
+ }
+
+ if( received_twice == (service_infos_.size() - 1) / 2
+ && received_normal == (service_infos_.size() - 1) / 2 - 1) {
+ // routing manager stub receives the notification
+ // - twice from external nodes
+ // - and normal from all internal nodes
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_ << "] "
+ << "Received notifications:"
+ << " Normal: " << received_normal
+ << " Twice: " << received_twice;
+ return true;
+ }
+ return false;
+ }
+
+ void wait_for_stop() {
+ std::unique_lock<std::mutex> its_lock(stop_mutex_);
+ while (wait_for_stop_) {
+ stop_condition_.wait(its_lock);
+ }
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << client_number_
+ << "] Received notifications from all services, going down";
+
+ app_->stop();
+ }
+
+private:
+ int client_number_;
+ std::array<initial_event_test::service_info, 7> service_infos_;
+ vsomeip::subscription_type_e subscription_type_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_;
+ std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_notification_;
+
+ bool wait_until_registered_;
+ bool wait_until_other_services_available_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+
+ bool wait_for_stop_;
+ std::mutex stop_mutex_;
+ std::condition_variable stop_condition_;
+ std::thread stop_thread_;
+};
+
+static int client_number;
+static vsomeip::subscription_type_e subscription_type;
+static bool use_same_service_id;
+
+TEST(someip_initial_event_test, wait_for_initial_events_of_all_services)
+{
+ if(use_same_service_id) {
+ initial_event_test_client its_sample(client_number,
+ subscription_type,
+ initial_event_test::service_infos_same_service_id);
+ } else {
+ initial_event_test_client its_sample(client_number, subscription_type,
+ initial_event_test::service_infos);
+ }
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 3) {
+ std::cerr << "Please specify a client number and subscription type, like: " << argv[0] << " 2 UDP SAME_SERVICE_ID" << std::endl;
+ std::cerr << "Valid client numbers are from 0 to 0xFFFF" << std::endl;
+ std::cerr << "Valid subscription types include:" << std::endl;
+ std::cerr << "[TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]" << std::endl;
+ std::cerr << "If SAME_SERVICE_ID is specified as third parameter the test is run w/ multiple instances of the same service" << std::endl;
+ return 1;
+ }
+
+ client_number = std::stoi(std::string(argv[1]), nullptr);
+
+ if(std::string("TCP_AND_UDP") == std::string(argv[2])) {
+ subscription_type = vsomeip::subscription_type_e::SU_RELIABLE_AND_UNRELIABLE;
+ } else if(std::string("PREFER_UDP") == std::string(argv[2])) {
+ subscription_type = vsomeip::subscription_type_e::SU_PREFER_UNRELIABLE;
+ } else if(std::string("PREFER_TCP") == std::string(argv[2])) {
+ subscription_type = vsomeip::subscription_type_e::SU_PREFER_RELIABLE;
+ } else if(std::string("UDP") == std::string(argv[2])) {
+ subscription_type = vsomeip::subscription_type_e::SU_UNRELIABLE;
+ } else if(std::string("TCP") == std::string(argv[2])) {
+ subscription_type = vsomeip::subscription_type_e::SU_RELIABLE;
+ } else {
+ std::cerr << "Wrong subscription type passed, exiting" << std::endl;
+ std::cerr << "Valid subscription types include:" << std::endl;
+ std::cerr << "[TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]" << std::endl;
+ return 1;
+ }
+
+ if (argc >= 4 && std::string("SAME_SERVICE_ID") == std::string(argv[3])) {
+ use_same_service_id = true;
+ } else {
+ use_same_service_id = false;
+ }
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/initial_event_tests/initial_event_test_globals.hpp b/test/initial_event_tests/initial_event_test_globals.hpp
new file mode 100644
index 0000000..36f8def
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_globals.hpp
@@ -0,0 +1,51 @@
+// Copyright (C) 2014-2016 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 SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_
+#define SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_
+
+namespace initial_event_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;
+};
+
+static constexpr std::array<service_info, 7> service_infos = {{
+ // placeholder to be consistent w/ client ids, service ids, app names
+ { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
+ // node 1
+ { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 },
+ { 0x2222, 0x1, 0x2222, 0x2222, 0x2000 },
+ { 0x3333, 0x1, 0x3333, 0x3333, 0x3000 },
+ // node 2
+ { 0x4444, 0x1, 0x4444, 0x4444, 0x4000 },
+ { 0x5555, 0x1, 0x5555, 0x5555, 0x5000 },
+ { 0x6666, 0x1, 0x6666, 0x6666, 0x6000 }
+}};
+
+static constexpr std::array<service_info, 7> service_infos_same_service_id = {{
+ // placeholder to be consistent w/ client ids, service ids, app names
+ { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
+ // node 1
+ { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 },
+ { 0x1111, 0x2, 0x2222, 0x2222, 0x2000 },
+ { 0x1111, 0x3, 0x3333, 0x3333, 0x3000 },
+ // node 2
+ { 0x2222, 0x1, 0x4444, 0x4444, 0x4000 },
+ { 0x2222, 0x2, 0x5555, 0x5555, 0x5000 },
+ { 0x2222, 0x3, 0x6666, 0x6666, 0x6000 }
+}};
+
+static constexpr service_info stop_service_master = { 0x8888, 0x1, 0x8888, 0x0, 0x0 };
+static constexpr service_info stop_service_slave = { 0x9999, 0x1, 0x9999, 0x0, 0x0 };
+
+static constexpr int notifications_to_send = 1;
+}
+
+#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */
diff --git a/test/initial_event_tests/initial_event_test_master_starter.sh b/test/initial_event_tests/initial_event_test_master_starter.sh
new file mode 100755
index 0000000..903104a
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_master_starter.sh
@@ -0,0 +1,143 @@
+#!/bin/bash
+# Copyright (C) 2015-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Purpose: This script is needed to start the services with
+# one command. This is necessary as ctest - which is used to run the
+# tests - isn't able to start multiple binaries for one testcase. Therefore
+# the testcase simply executes this script. This script then runs the services
+# and checks that all exit successfully.
+
+if [ $# -lt 2 ]
+then
+ echo "Please pass a subscription method to this script."
+ echo "For example: $0 UDP initial_event_test_diff_client_ids_diff_ports_master.json"
+ echo "Valid subscription types include:"
+ echo " [TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]"
+ echo "Please pass a json file to this script."
+ echo "For example: $0 UDP initial_event_test_diff_client_ids_diff_ports_master.json"
+ echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter"
+ exit 1
+fi
+
+PASSED_SUBSCRIPTION_TYPE=$1
+PASSED_JSON_FILE=$2
+PASSED_SAME_SERVICE_ID_FLAG=$3
+
+# Make sure only valid subscription types are passed to the script
+SUBSCRIPTION_TYPES="TCP_AND_UDP PREFER_UDP PREFER_TCP UDP TCP"
+VALID=0
+for valid_subscription_type in $SUBSCRIPTION_TYPES
+do
+ if [ $valid_subscription_type == $PASSED_SUBSCRIPTION_TYPE ]
+ then
+ VALID=1
+ fi
+done
+
+if [ $VALID -eq 0 ]
+then
+ echo "Invalid subscription type passed, valid types are:"
+ echo " [TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]"
+ echo "Exiting"
+ exit 1
+fi
+
+# replace master with slave to be able display the correct json file to be used
+# with the slave script
+MASTER_JSON_FILE=$PASSED_JSON_FILE
+CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave}
+
+FAIL=0
+
+# Start the services
+export VSOMEIP_CONFIGURATION=$PASSED_JSON_FILE
+
+export VSOMEIP_APPLICATION_NAME=initial_event_test_service_one
+./initial_event_test_service 1 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_SERVICE_ONE=$!
+
+export VSOMEIP_APPLICATION_NAME=initial_event_test_service_two
+./initial_event_test_service 2 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_SERVICE_TWO=$!
+
+export VSOMEIP_APPLICATION_NAME=initial_event_test_service_three
+./initial_event_test_service 3 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_SERVICE_THREE=$!
+
+unset VSOMEIP_APPLICATION_NAME
+
+# Array for client pids
+CLIENT_PIDS=()
+
+# Start some clients
+for client_number in $(seq 9000 9009)
+do
+ ./initial_event_test_client $client_number $PASSED_SUBSCRIPTION_TYPE $PASSED_SAME_SERVICE_ID_FLAG &
+ CLIENT_PIDS+=($!)
+done
+
+# Start availability checker in order to wait until the services on the remote
+# were started as well
+./initial_event_test_availability_checker 1234 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_AVAILABILITY_CHECKER=$!
+
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** initial_event_test_slave_starter.sh $PASSED_SUBSCRIPTION_TYPE $CLIENT_JSON_FILE $PASSED_SAME_SERVICE_ID_FLAG
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** initial_event_test_diff_client_ids_diff_ports_master.json and
+** initial_event_test_diff_client_ids_diff_ports_slave.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# wait unti the services on the remote node were started as well
+wait $PID_AVAILABILITY_CHECKER
+
+# sleep to make sure the following started clients will have to get
+# the cached event from the routing manager daemon
+sleep 2
+
+for client_number in $(seq 9010 9020)
+do
+ ./initial_event_test_client $client_number $PASSED_SUBSCRIPTION_TYPE $PASSED_SAME_SERVICE_ID_FLAG &
+ CLIENT_PIDS+=($!)
+done
+
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# wait until all clients exited on slave side
+./initial_event_test_stop_service MASTER &
+PID_STOP_SERVICE=$!
+wait $PID_STOP_SERVICE
+
+# kill the services
+kill $PID_SERVICE_THREE
+kill $PID_SERVICE_TWO
+kill $PID_SERVICE_ONE
+
+sleep 1
+echo ""
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/initial_event_tests/initial_event_test_service.cpp b/test/initial_event_tests/initial_event_test_service.cpp
new file mode 100644
index 0000000..26a8e06
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_service.cpp
@@ -0,0 +1,130 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "initial_event_test_globals.hpp"
+
+
+class initial_event_test_service {
+public:
+ initial_event_test_service(struct initial_event_test::service_info _service_info) :
+ service_info_(_service_info),
+ app_(vsomeip::runtime::get()->create_application()),
+ wait_until_registered_(true),
+ offer_thread_(std::bind(&initial_event_test_service::run, this)) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&initial_event_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, service_info_.instance_id,
+ service_info_.event_id, its_eventgroups, true);
+
+ // set value to field
+ std::shared_ptr<vsomeip::payload> its_payload =
+ vsomeip::runtime::get()->create_payload();
+ vsomeip::byte_t its_data[2] = {static_cast<vsomeip::byte_t>((service_info_.service_id & 0xFF00) >> 8),
+ static_cast<vsomeip::byte_t>((service_info_.service_id & 0xFF))};
+ its_payload->set_data(its_data, 2);
+ app_->notify(service_info_.service_id, service_info_.instance_id,
+ service_info_.event_id, its_payload);
+
+ app_->start();
+ }
+
+ ~initial_event_test_service() {
+ offer_thread_.join();
+ }
+
+ void offer() {
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ }
+
+ 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 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();
+ }
+
+private:
+ initial_event_test::service_info service_info_;
+ std::shared_ptr<vsomeip::application> app_;
+
+ bool wait_until_registered_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread offer_thread_;
+};
+
+static int service_number;
+static bool use_same_service_id;
+
+TEST(someip_initial_event_test, set_field_once)
+{
+ if(use_same_service_id) {
+ initial_event_test_service its_sample(
+ initial_event_test::service_infos_same_service_id[service_number]);
+ } else {
+ initial_event_test_service its_sample(
+ initial_event_test::service_infos[service_number]);
+ }
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cerr << "Please specify a service number and subscription type, like: " << argv[0] << " 2 SAME_SERVICE_ID" << std::endl;
+ std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl;
+ std::cerr << "If SAME_SERVICE_ID is specified as third parameter the test is run w/ multiple instances of the same service" << std::endl;
+ return 1;
+ }
+
+ service_number = std::stoi(std::string(argv[1]), nullptr);
+
+ if (argc >= 3 && std::string("SAME_SERVICE_ID") == std::string(argv[2])) {
+ use_same_service_id = true;
+ } else {
+ use_same_service_id = false;
+ }
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/initial_event_tests/initial_event_test_slave_starter.sh b/test/initial_event_tests/initial_event_test_slave_starter.sh
new file mode 100755
index 0000000..9bd2d78
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_slave_starter.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+# Copyright (C) 2015-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Purpose: This script is needed to start the services with
+# one command. This is necessary as ctest - which is used to run the
+# tests - isn't able to start multiple binaries for one testcase. Therefore
+# the testcase simply executes this script. This script then runs the services
+# and checks that all exit successfully.
+
+if [ $# -lt 2 ]
+then
+ echo "Please pass a subscription method to this script."
+ echo "For example: $0 UDP initial_event_test_diff_client_ids_diff_ports_slave.json"
+ echo "Valid subscription types include:"
+ echo " [TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]"
+ echo "Please pass a json file to this script."
+ echo "For example: $0 UDP initial_event_test_diff_client_ids_diff_ports_slave.json"
+ echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter"
+ exit 1
+fi
+
+PASSED_SUBSCRIPTION_TYPE=$1
+PASSED_JSON_FILE=$2
+PASSED_SAME_SERVICE_ID_FLAG=$3
+
+# Make sure only valid subscription types are passed to the script
+SUBSCRIPTION_TYPES="TCP_AND_UDP PREFER_UDP PREFER_TCP UDP TCP"
+VALID=0
+for valid_subscription_type in $SUBSCRIPTION_TYPES
+do
+ if [ $valid_subscription_type == $PASSED_SUBSCRIPTION_TYPE ]
+ then
+ VALID=1
+ fi
+done
+
+if [ $VALID -eq 0 ]
+then
+ echo "Invalid subscription type passed, valid types are:"
+ echo " [TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]"
+ echo "Exiting"
+ exit 1
+fi
+
+
+FAIL=0
+
+export VSOMEIP_CONFIGURATION=$PASSED_JSON_FILE
+
+# Start the services
+export VSOMEIP_APPLICATION_NAME=initial_event_test_service_four
+./initial_event_test_service 4 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_SERVICE_FOUR=$!
+
+export VSOMEIP_APPLICATION_NAME=initial_event_test_service_five
+./initial_event_test_service 5 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_SERVICE_FIVE=$!
+
+export VSOMEIP_APPLICATION_NAME=initial_event_test_service_six
+./initial_event_test_service 6 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_SERVICE_SIX=$!
+
+unset VSOMEIP_APPLICATION_NAME
+
+# Array for client pids
+CLIENT_PIDS=()
+
+# Start some clients
+for client_number in $(seq 9000 9009)
+do
+ ./initial_event_test_client $client_number $PASSED_SUBSCRIPTION_TYPE $PASSED_SAME_SERVICE_ID_FLAG &
+ CLIENT_PIDS+=($!)
+done
+
+# Start availability checker in order to wait until the services on the remote
+# were started as well
+./initial_event_test_availability_checker 1234 $PASSED_SAME_SERVICE_ID_FLAG &
+PID_AVAILABILITY_CHECKER=$!
+
+# wait unti the services on the remote node were started as well
+wait $PID_AVAILABILITY_CHECKER
+
+# sleep to make sure the following started clients will have to get
+# the cached event from the routing manager daemon
+sleep 2
+
+for client_number in $(seq 9010 9020)
+do
+ ./initial_event_test_client $client_number $PASSED_SUBSCRIPTION_TYPE $PASSED_SAME_SERVICE_ID_FLAG &
+ CLIENT_PIDS+=($!)
+done
+
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# wait until all clients exited on master side
+./initial_event_test_stop_service SLAVE &
+PID_STOP_SERVICE=$!
+wait $PID_STOP_SERVICE
+
+# kill the services
+kill $PID_SERVICE_SIX
+kill $PID_SERVICE_FIVE
+kill $PID_SERVICE_FOUR
+
+sleep 1
+echo ""
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/initial_event_tests/initial_event_test_stop_service.cpp b/test/initial_event_tests/initial_event_test_stop_service.cpp
new file mode 100644
index 0000000..c8e519e
--- /dev/null
+++ b/test/initial_event_tests/initial_event_test_stop_service.cpp
@@ -0,0 +1,264 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "initial_event_test_globals.hpp"
+
+
+class initial_event_test_stop_service {
+public:
+ initial_event_test_stop_service(struct initial_event_test::service_info _service_info, bool _is_master) :
+ service_info_(_service_info),
+ is_master_(_is_master),
+ app_(vsomeip::runtime::get()->create_application()),
+ wait_until_registered_(true),
+ wait_until_stop_service_other_node_available_(true),
+ wait_until_shutdown_method_called_(true),
+ offer_thread_(std::bind(&initial_event_test_stop_service::run, this)),
+ wait_for_stop_(true),
+ stop_thread_(std::bind(&initial_event_test_stop_service::wait_for_stop, this)),
+ called_other_node_(false) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&initial_event_test_stop_service::on_state, this,
+ std::placeholders::_1));
+ app_->register_message_handler(service_info_.service_id,
+ service_info_.instance_id, service_info_.method_id,
+ std::bind(&initial_event_test_stop_service::on_shutdown_method_called, this,
+ std::placeholders::_1));
+
+ // register availability for all other services and request their event.
+ if (is_master_) {
+ app_->request_service(
+ initial_event_test::stop_service_slave.service_id,
+ initial_event_test::stop_service_slave.instance_id);
+ app_->register_availability_handler(
+ initial_event_test::stop_service_slave.service_id,
+ initial_event_test::stop_service_slave.instance_id,
+ std::bind(&initial_event_test_stop_service::on_availability,
+ this, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ } else {
+ app_->request_service(
+ initial_event_test::stop_service_master.service_id,
+ initial_event_test::stop_service_master.instance_id);
+ app_->register_availability_handler(
+ initial_event_test::stop_service_master.service_id,
+ initial_event_test::stop_service_master.instance_id,
+ std::bind(&initial_event_test_stop_service::on_availability,
+ this, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ }
+ app_->start();
+ }
+
+ ~initial_event_test_stop_service() {
+ offer_thread_.join();
+ stop_thread_.join();
+ }
+
+ void offer() {
+ if (is_master_) {
+ app_->offer_service(
+ initial_event_test::stop_service_master.service_id,
+ initial_event_test::stop_service_master.instance_id);
+ } else {
+ app_->offer_service(
+ initial_event_test::stop_service_slave.service_id,
+ initial_event_test::stop_service_slave.instance_id);
+ }
+ }
+
+ void stop_offer() {
+ if (is_master_) {
+ app_->stop_offer_service(
+ initial_event_test::stop_service_master.service_id,
+ initial_event_test::stop_service_master.instance_id);
+ } else {
+ app_->stop_offer_service(
+ initial_event_test::stop_service_slave.service_id,
+ initial_event_test::stop_service_slave.instance_id);
+ }
+ }
+
+ 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_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ bool notify(false);
+ if(_is_available) {
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Service ["
+ << std::setw(4) << std::setfill('0') << std::hex << _service
+ << "." << _instance << "] is available.";
+ if(is_master_) {
+ if(_service == initial_event_test::stop_service_slave.service_id
+ && _instance == initial_event_test::stop_service_slave.instance_id) {
+ notify = true;
+ }
+ } else {
+ if(_service == initial_event_test::stop_service_master.service_id
+ && _instance == initial_event_test::stop_service_master.instance_id) {
+ notify = true;
+ }
+ }
+ }
+ if (notify) {
+ std::lock_guard<std::mutex> its_lock(availability_mutex_);
+ wait_until_stop_service_other_node_available_ = false;
+ availability_condition_.notify_one();
+ }
+ }
+
+ void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST_NO_RETURN) {
+ VSOMEIP_DEBUG << "Received a request with Client/Session [" << std::setw(4)
+ << std::setfill('0') << std::hex << _message->get_client() << "/"
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _message->get_session() << "] shutdown method called";
+
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ wait_for_stop_ = false;
+ stop_condition_.notify_one();
+ }
+ }
+
+ 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();
+
+ std::unique_lock<std::mutex> its_availability_lock(availability_mutex_);
+ while (wait_until_stop_service_other_node_available_) {
+ availability_condition_.wait(its_availability_lock);
+ }
+
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Calling shutdown method on remote side";
+
+ std::shared_ptr<vsomeip::message> msg(vsomeip::runtime::get()->create_request());
+ msg->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN);
+ if(is_master_) {
+ msg->set_service(initial_event_test::stop_service_slave.service_id);
+ msg->set_instance(initial_event_test::stop_service_slave.instance_id);
+ msg->set_method(initial_event_test::stop_service_slave.method_id);
+ } else {
+ msg->set_service(initial_event_test::stop_service_master.service_id);
+ msg->set_instance(initial_event_test::stop_service_master.instance_id);
+ msg->set_method(initial_event_test::stop_service_master.method_id);
+ }
+ app_->send(msg);
+ called_other_node_ = true;
+
+ while (wait_until_shutdown_method_called_) {
+ condition_.wait(its_lock);
+ }
+ }
+
+ void wait_for_stop() {
+ std::unique_lock<std::mutex> its_lock(stop_mutex_);
+ while (wait_for_stop_) {
+ stop_condition_.wait(its_lock);
+ }
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id
+ << "] shutdown method was called, going down";
+ while(!called_other_node_) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+ // let offer thread exit
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_shutdown_method_called_ = false;
+ condition_.notify_one();
+ }
+
+ app_->stop();
+ }
+
+private:
+ initial_event_test::service_info service_info_;
+ bool is_master_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_;
+ std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_notification_;
+
+ bool wait_until_registered_;
+ bool wait_until_stop_service_other_node_available_;
+ bool wait_until_shutdown_method_called_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread offer_thread_;
+
+ std::mutex availability_mutex_;
+ std::condition_variable availability_condition_;
+
+ bool wait_for_stop_;
+ std::mutex stop_mutex_;
+ std::condition_variable stop_condition_;
+ std::thread stop_thread_;
+
+ bool called_other_node_;
+};
+
+static bool is_master = false;
+
+TEST(someip_initial_event_test, wait_for_stop_method_to_be_called)
+{
+ if(is_master) {
+ initial_event_test_stop_service its_sample(initial_event_test::stop_service_master, is_master);
+ } else {
+ initial_event_test_stop_service its_sample(initial_event_test::stop_service_slave, is_master);
+ }
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cerr << "Please specify a valid type, like: " << argv[0] << " MASTER" << std::endl;
+ std::cerr << "Valid types are in the range of [MASTER,SLAVE]" << std::endl;
+ return 1;
+ }
+
+ if (argc >= 2 && std::string("MASTER") == std::string(argv[1])) {
+ is_master = true;
+ } else if (argc >= 2 && std::string("SLAVE") == std::string(argv[1])){
+ is_master = false;
+ }
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/magic_cookies_tests/magic_cookies_test_client.cpp b/test/magic_cookies_tests/magic_cookies_test_client.cpp
index 1b61e60..fb335f9 100644
--- a/test/magic_cookies_tests/magic_cookies_test_client.cpp
+++ b/test/magic_cookies_tests/magic_cookies_test_client.cpp
@@ -137,35 +137,35 @@ public:
// Test sequence
its_good_payload_data[11] = 0x01;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x02;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x03;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x04;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x05;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x06;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x07;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x08;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x09;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x0A;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x0B;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x0C;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x0D;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_bad_payload_data[11] = 0x0E;
- its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
its_good_payload_data[11] = 0x0F;
- its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
stop();
diff --git a/test/offer_tests/conf/offer_test_external_master.json.in b/test/offer_tests/conf/offer_test_external_master.json.in
new file mode 100644
index 0000000..b16a258
--- /dev/null
+++ b/test/offer_tests/conf/offer_test_external_master.json.in
@@ -0,0 +1,36 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "routing":"vsomeipd",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp",
+ "cyclic_offer_delay" : "500"
+ }
+} \ No newline at end of file
diff --git a/test/offer_tests/conf/offer_test_external_master_starter.sh.in b/test/offer_tests/conf/offer_test_external_master_starter.sh.in
new file mode 100755
index 0000000..9ff40e8
--- /dev/null
+++ b/test/offer_tests/conf/offer_test_external_master_starter.sh.in
@@ -0,0 +1,114 @@
+#!/bin/bash
+# Copyright (C) 2015-2016 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
+# Rejecting offer for which there is already a remote offer:
+# * start daemon
+# * start application which offers service
+# * start daemon remotely
+# * start same application which offers the same service again remotely
+# -> should be rejected as there is already a service instance
+# running in the network
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_external_master.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+# Start the services
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+
+./offer_test_client SUBSCRIBE &
+CLIENT_PIDS+=($!)
+
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** offer_test_external_slave_starter.sh
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** offer_test_external_master.json and
+** offer_test_external_slave.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+
+# Wait until all clients and services are finished
+for job in ${CLIENT_PIDS[*]} $PID_SERVICE_TWO
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_VSOMEIPD
+sleep 1
+
+
+# Rejecting remote offer for which there is already a local offer
+# * start application which offers service
+# * send sd message trying to offer the same service instance as already
+# offered locally from a remote host
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_external_master.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+# Start the services
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+
+./offer_test_client SUBSCRIBE &
+CLIENT_PIDS+=($!)
+
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** offer_test_external_sd_msg_sender @TEST_IP_MASTER@
+** (pass the correct ip address of your test master)
+** from an external host to successfully complete this test.
+**
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Wait until all clients and services are finished
+for job in ${CLIENT_PIDS[*]} $PID_SERVICE_TWO
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_VSOMEIPD
+sleep 1
+
+
+# Check if everything went well
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/offer_tests/conf/offer_test_external_slave.json.in b/test/offer_tests/conf/offer_test_external_slave.json.in
new file mode 100644
index 0000000..47a3e9d
--- /dev/null
+++ b/test/offer_tests/conf/offer_test_external_slave.json.in
@@ -0,0 +1,36 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "routing":"vsomeipd",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp",
+ "cyclic_offer_delay" : "500"
+ }
+} \ No newline at end of file
diff --git a/test/offer_tests/offer_test_client.cpp b/test/offer_tests/offer_test_client.cpp
new file mode 100644
index 0000000..bb1cb84
--- /dev/null
+++ b/test/offer_tests/offer_test_client.cpp
@@ -0,0 +1,281 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+#include "../../implementation/configuration/include/internal.hpp"
+
+#include "offer_test_globals.hpp"
+
+enum operation_mode_e {
+ SUBSCRIBE,
+ METHODCALL
+};
+
+class offer_test_client {
+public:
+ offer_test_client(struct offer_test::service_info _service_info, operation_mode_e _mode) :
+ service_info_(_service_info),
+ operation_mode_(_mode),
+ app_(vsomeip::runtime::get()->create_application("offer_test_client")),
+ service_available_(false),
+ wait_until_registered_(true),
+ wait_until_service_available_(true),
+ send_thread_(std::bind(&offer_test_client::send, this)),
+ wait_for_stop_(true),
+ stop_thread_(std::bind(&offer_test_client::wait_for_stop, this)),
+ last_received_counter_(0),
+ last_received_response_(std::chrono::steady_clock::now()),
+ number_received_responses_(0) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&offer_test_client::on_state, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
+ std::bind(&offer_test_client::on_message, this,
+ std::placeholders::_1));
+
+ // register availability for all other services and request their event.
+ app_->register_availability_handler(service_info_.service_id,
+ service_info_.instance_id,
+ std::bind(&offer_test_client::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ app_->request_service(service_info_.service_id,
+ service_info_.instance_id);
+
+ if (operation_mode_ == operation_mode_e::SUBSCRIBE) {
+ 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_->subscribe(service_info_.service_id, service_info_.instance_id,
+ service_info_.eventgroup_id, vsomeip::DEFAULT_MAJOR,
+ vsomeip::subscription_type_e::SU_RELIABLE_AND_UNRELIABLE);
+ }
+
+ app_->start();
+ }
+
+ ~offer_test_client() {
+ send_thread_.join();
+ stop_thread_.join();
+ }
+
+ 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_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ VSOMEIP_INFO << "Service [" << std::setw(4)
+ << std::setfill('0') << std::hex << _service << "." << _instance
+ << "] is " << (_is_available ? "available":"not available") << ".";
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ if(_is_available) {
+ wait_until_service_available_ = false;
+ condition_.notify_one();
+ } else {
+ wait_until_service_available_ = true;
+ condition_.notify_one();
+ }
+ }
+
+ void on_message(const std::shared_ptr<vsomeip::message> &_message) {
+ if(_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) {
+ on_notification(_message);
+ } else if (_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) {
+ on_response(_message);
+ }
+ }
+
+ void on_notification(const std::shared_ptr<vsomeip::message> &_message) {
+ std::shared_ptr<vsomeip::payload> its_payload(_message->get_payload());
+ EXPECT_EQ(4u, its_payload->get_length());
+ vsomeip::byte_t *d = its_payload->get_data();
+ static std::uint32_t number_received_notifications(0);
+ std::uint32_t counter(0);
+ counter |= d[0] << 24;
+ counter |= d[1] << 16;
+ counter |= d[2] << 8;
+ counter |= d[3];
+
+ VSOMEIP_DEBUG
+ << "Received a notification with Client/Session [" << std::setw(4)
+ << std::setfill('0') << std::hex << _message->get_client() << "/"
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _message->get_session() << "] from Service/Method ["
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _message->get_service() << "/" << std::setw(4) << std::setfill('0')
+ << std::hex << _message->get_method() <<"] got:" << std::dec << counter;
+
+ ASSERT_GT(counter, last_received_counter_);
+ last_received_counter_ = counter;
+ ++number_received_notifications;
+
+ if(number_received_notifications >= 250) {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ wait_for_stop_ = false;
+ VSOMEIP_INFO << "going down";
+ stop_condition_.notify_one();
+ }
+ }
+
+ void on_response(const std::shared_ptr<vsomeip::message> &_message) {
+ ++number_received_responses_;
+ static bool first(true);
+ if (first) {
+ first = false;
+ last_received_response_ = std::chrono::steady_clock::now();
+ return;
+ }
+ EXPECT_EQ(service_info_.service_id, _message->get_service());
+ EXPECT_EQ(service_info_.method_id, _message->get_method());
+ EXPECT_EQ(service_info_.instance_id, _message->get_instance());
+ ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - last_received_response_).count(),
+ (std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT)
+ + std::chrono::milliseconds(1000)).count());
+ last_received_response_ = std::chrono::steady_clock::now();
+ std::cout << ".";
+ std::cout.flush();
+ }
+
+ void send() {
+ if (operation_mode_ != operation_mode_e::METHODCALL) {
+ return;
+ }
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (wait_until_registered_) {
+ condition_.wait(its_lock);
+ }
+
+ while (wait_until_service_available_) {
+ condition_.wait(its_lock);
+ }
+ its_lock.unlock();
+ its_lock.release();
+
+ for (int var = 0; var < offer_test::number_of_messages_to_send; ++var) {
+ bool send(false);
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ send = !wait_until_service_available_;
+ }
+ if (send) {
+ std::shared_ptr<vsomeip::message> its_req = vsomeip::runtime::get()->create_request();
+ its_req->set_service(service_info_.service_id);
+ its_req->set_instance(service_info_.instance_id);
+ its_req->set_method(service_info_.method_id);
+ app_->send(its_req);
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ wait_for_stop_ = false;
+ VSOMEIP_INFO << "going down. Sent " << offer_test::number_of_messages_to_send
+ << " requests and received " << number_received_responses_
+ << " responses";
+ stop_condition_.notify_one();
+ }
+ }
+
+ void wait_for_stop() {
+ std::unique_lock<std::mutex> its_lock(stop_mutex_);
+ while (wait_for_stop_) {
+ stop_condition_.wait(its_lock);
+ }
+ VSOMEIP_INFO << "going down";
+
+ app_->stop();
+ }
+
+private:
+ struct offer_test::service_info service_info_;
+ operation_mode_e operation_mode_;
+ std::shared_ptr<vsomeip::application> app_;
+ bool service_available_;
+
+ bool wait_until_registered_;
+ bool wait_until_service_available_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread send_thread_;
+
+ bool wait_for_stop_;
+ std::mutex stop_mutex_;
+ std::condition_variable stop_condition_;
+ std::thread stop_thread_;
+
+ std::uint32_t last_received_counter_;
+ std::chrono::steady_clock::time_point last_received_response_;
+ std::uint32_t number_received_responses_;
+};
+
+static operation_mode_e passed_mode = operation_mode_e::SUBSCRIBE;
+
+TEST(someip_offer_test, subscribe_or_call_method_at_service)
+{
+ offer_test_client its_sample(offer_test::service, passed_mode);
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cerr << "Please specify a operation mode, like: " << argv[0] << " SUBSCRIBE" << std::endl;
+ std::cerr << "Valid operation modes are SUBSCRIBE and METHODCALL" << std::endl;
+ return 1;
+ }
+
+ if (std::string("SUBSCRIBE") == std::string(argv[1])) {
+ passed_mode = operation_mode_e::SUBSCRIBE;
+ } else if (std::string("METHODCALL") == std::string(argv[1])) {
+ passed_mode = operation_mode_e::METHODCALL;
+ } else {
+ std::cerr << "Wrong operation mode passed, exiting" << std::endl;
+ std::cerr << "Please specify a operation mode, like: " << argv[0] << " SUBSCRIBE" << std::endl;
+ std::cerr << "Valid operation modes are SUBSCRIBE and METHODCALL" << std::endl;
+ return 1;
+ }
+
+#if 0
+ if (argc >= 4 && std::string("SAME_SERVICE_ID") == std::string(argv[3])) {
+ use_same_service_id = true;
+ } else {
+ use_same_service_id = false;
+ }
+#endif
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/offer_tests/offer_test_external_sd_msg_sender.cpp b/test/offer_tests/offer_test_external_sd_msg_sender.cpp
new file mode 100644
index 0000000..16481aa
--- /dev/null
+++ b/test/offer_tests/offer_test_external_sd_msg_sender.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2015-2016 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 <gtest/gtest.h>
+
+#include <boost/asio.hpp>
+
+static char* passed_address;
+
+TEST(someip_offer_test, send_offer_service_sd_message)
+{
+ try {
+ boost::asio::io_service io;
+ boost::asio::ip::udp::socket::endpoint_type target_sd(
+ boost::asio::ip::address::from_string(std::string(passed_address)),
+ 30490);
+ boost::asio::ip::udp::socket udp_socket(io,
+ boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490));
+ std::uint8_t its_offer_service_message[] = {
+ 0xff, 0xff, 0x81, 0x00,
+ 0x00, 0x00, 0x00, 0x3c,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x01, 0x02, 0x00,
+ 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x20,
+ 0x11, 0x11, 0x00, 0x01,
+ 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18,
+ 0x00, 0x09, 0x04, 0x00,
+ 0x0a, 0x00, 0x03, 0x01,
+ 0x00, 0x06, 0x9c, 0x41,
+ 0x00, 0x09, 0x04, 0x00,
+ 0x0a, 0x00, 0x03, 0x7D, // slave address
+ 0x00, 0x11, 0x75, 0x31
+ };
+ 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];
+ }
+
+ // call shutdown method
+ std::uint8_t shutdown_call[] = {
+ 0x11, 0x11, 0x14, 0x04,
+ 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(passed_address)),
+ 30001);
+ udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service);
+ } catch (...) {
+ ASSERT_FALSE(true);
+ }
+}
+
+
+#ifndef WIN32
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cout << "Please pass an target IP address to this binary like: "
+ << argv[0] << " 10.0.3.1" << std::endl;
+ exit(1);
+ }
+ passed_address = argv[1];
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/offer_tests/offer_test_external_slave_starter.sh b/test/offer_tests/offer_test_external_slave_starter.sh
new file mode 100755
index 0000000..cdff0d8
--- /dev/null
+++ b/test/offer_tests/offer_test_external_slave_starter.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Copyright (C) 2015-2016 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/.
+
+FAIL=0
+# Rejecting offer for which there is already a remote offer:
+# * start daemon
+# * start application which offers service
+# * start daemon remotely
+# * start same application which offers the same service again remotely
+# -> should be rejected as there is already a service instance
+# running in the network
+
+export VSOMEIP_CONFIGURATION=offer_test_external_slave.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+sleep 1
+# Start the services
+./offer_test_service_external 2 &
+PID_SERVICE_TWO=$!
+sleep 1
+
+# Wait until all clients and services are finished
+for job in $PID_SERVICE_TWO
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_VSOMEIPD
+sleep 1
+
+
+
+# Check if everything went well
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/offer_tests/offer_test_globals.hpp b/test/offer_tests/offer_test_globals.hpp
new file mode 100644
index 0000000..7163741
--- /dev/null
+++ b/test/offer_tests/offer_test_globals.hpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2014-2016 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 SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_
+#define SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_
+
+namespace offer_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;
+};
+
+struct service_info service = { 0x1111, 0x1, 0x1111, 0x1111, 0x1000, 0x1404 };
+
+static constexpr int number_of_messages_to_send = 150;
+}
+
+#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */
diff --git a/test/offer_tests/offer_test_local.json b/test/offer_tests/offer_test_local.json
new file mode 100644
index 0000000..a54049c
--- /dev/null
+++ b/test/offer_tests/offer_test_local.json
@@ -0,0 +1,20 @@
+{
+ "unicast":"127.0.0.1",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "routing":"vsomeipd",
+ "service-discovery":
+ {
+ "enable":"false"
+ }
+}
+
diff --git a/test/offer_tests/offer_test_local_starter.sh b/test/offer_tests/offer_test_local_starter.sh
new file mode 100755
index 0000000..69b4821
--- /dev/null
+++ b/test/offer_tests/offer_test_local_starter.sh
@@ -0,0 +1,298 @@
+#!/bin/bash
+# Copyright (C) 2015-2016 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
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Running first test
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Rejecting offer of service instance whose hosting application is still
+# alive:
+# * start application which offers service
+# * start two clients which continuously exchanges messages with the service
+# * start application which offers the same service again -> should be
+# rejected and an error message should be printed.
+# * Message exchange with client application should not be interrupted.
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_local.json
+# Start the services
+./offer_test_service 1 &
+PID_SERVICE_ONE=$!
+./offer_test_client SUBSCRIBE &
+CLIENT_PIDS+=($!)
+./offer_test_client SUBSCRIBE &
+CLIENT_PIDS+=($!)
+
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_SERVICE_TWO
+kill $PID_SERVICE_ONE
+sleep 1
+
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Running second test
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Rejecting offer of service instance whose hosting application is still
+# alive with daemon:
+# * start daemon (needed as he has to ping the offering client)
+# * start application which offers service
+# * start two clients which continuously exchanges messages with the service
+# * start application which offers the same service again -> should be
+# rejected and an error message should be printed.
+# * Message exchange with client application should not be interrupted.
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_local.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+
+# Start the services
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+./offer_test_client SUBSCRIBE &
+CLIENT_PIDS+=($!)
+./offer_test_client SUBSCRIBE &
+CLIENT_PIDS+=($!)
+
+./offer_test_service 3 &
+PID_SERVICE_THREE=$!
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_SERVICE_THREE
+kill $PID_SERVICE_TWO
+sleep 1
+kill $PID_VSOMEIPD
+sleep 1
+
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Running third test
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Accepting offer of service instance whose hosting application crashed
+# with (send SIGKILL)
+# * start daemon
+# * start application which offers service
+# * start client which exchanges messages with the service
+# * kill application with SIGKILL
+# * start application which offers the same service again -> should be
+# accepted.
+# * start another client which exchanges messages with the service
+# * Client should now communicate with new offerer.
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_local.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+# Start the service
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+
+# Start a client
+./offer_test_client METHODCALL &
+CLIENT_PIDS+=($!)
+
+# Kill the service
+sleep 1
+kill -KILL $PID_SERVICE_TWO
+
+# reoffer the service
+./offer_test_service 3 &
+PID_SERVICE_THREE=$!
+
+# Start another client
+./offer_test_client METHODCALL &
+CLIENT_PIDS+=($!)
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_SERVICE_THREE
+kill $PID_VSOMEIPD
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Running fourth test
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Accepting offer of service instance whose hosting application became
+# unresponsive (SIGSTOP)
+# * start daemon
+# * start application which offers service
+# * Send a SIGSTOP to the service to make it unresponsive
+# * start application which offers the same service again -> should be
+# marked as PENDING_OFFER and a ping should be sent to the paused
+# application.
+# * After the timeout passed the new offer should be accepted.
+# * start client which exchanges messages with the service
+# * Client should now communicate with new offerer.
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_local.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+# Start the service
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+
+# Start a client
+./offer_test_client METHODCALL &
+CLIENT_PIDS+=($!)
+
+# Pause the service
+sleep 1
+kill -STOP $PID_SERVICE_TWO
+
+# reoffer the service
+./offer_test_service 3 &
+PID_SERVICE_THREE=$!
+
+# Start another client
+./offer_test_client METHODCALL &
+CLIENT_PIDS+=($!)
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill -CONT $PID_SERVICE_TWO
+kill $PID_SERVICE_TWO
+kill $PID_SERVICE_THREE
+kill $PID_VSOMEIPD
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Running fifth test
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Rejecting offers for which there is already a pending offer
+# * start daemon
+# * start application which offers service
+# * Send a SIGSTOP to the service to make it unresponsive
+# * start application which offers the same service again -> should be
+# marked as PENDING_OFFER and a ping should be sent to the paused
+# application.
+# * start application which offers the same service again -> should be
+# rejected as there is already a PENDING_OFFER pending.
+# * After the timeout passed the new offer should be accepted.
+# * start client which exchanges messages with the service
+# * Client should now communicate with new offerer.
+
+# Array for client pids
+CLIENT_PIDS=()
+export VSOMEIP_CONFIGURATION=offer_test_local.json
+# start daemon
+../daemon/./vsomeipd &
+PID_VSOMEIPD=$!
+# Start the service
+./offer_test_service 2 &
+PID_SERVICE_TWO=$!
+
+# Start a client
+./offer_test_client METHODCALL &
+CLIENT_PIDS+=($!)
+
+# Pause the service
+sleep 1
+kill -STOP $PID_SERVICE_TWO
+
+# reoffer the service
+./offer_test_service 3 &
+PID_SERVICE_THREE=$!
+
+# reoffer the service again to provoke rejecting as there is
+# already a pending offer
+./offer_test_service 4 &
+PID_SERVICE_FOUR=$!
+
+# Start another client
+./offer_test_client METHODCALL &
+CLIENT_PIDS+=($!)
+
+# Wait until all clients are finished
+for job in ${CLIENT_PIDS[*]}
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill -CONT $PID_SERVICE_TWO
+kill $PID_SERVICE_TWO
+kill $PID_SERVICE_THREE
+kill $PID_SERVICE_FOUR
+kill $PID_VSOMEIPD
+
+
+# Check if everything went well
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/offer_tests/offer_test_service.cpp b/test/offer_tests/offer_test_service.cpp
new file mode 100644
index 0000000..a734ed3
--- /dev/null
+++ b/test/offer_tests/offer_test_service.cpp
@@ -0,0 +1,165 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "offer_test_globals.hpp"
+
+static std::string service_number;
+
+class offer_test_service {
+public:
+ offer_test_service(struct offer_test::service_info _service_info) :
+ service_info_(_service_info),
+ // service with number 1 uses "vsomeipd" as application name
+ // this way the same json file can be reused for all local tests
+ // including the ones with vsomeipd
+ app_(vsomeip::runtime::get()->create_application(
+ (service_number == "1") ? "vsomeipd" :
+ "offer_test_service" + service_number)),
+ counter_(0),
+ wait_until_registered_(true),
+ offer_thread_(std::bind(&offer_test_service::run, this)),
+ shutdown_method_called_(false) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&offer_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, service_info_.instance_id,
+ service_info_.event_id, its_eventgroups, false);
+
+ inc_counter_and_notify();
+
+ app_->register_message_handler(service_info_.service_id,
+ service_info_.instance_id, service_info_.method_id,
+ std::bind(&offer_test_service::on_request, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(service_info_.service_id,
+ service_info_.instance_id, service_info_.shutdown_method_id,
+ std::bind(&offer_test_service::on_shutdown_method_called, this,
+ std::placeholders::_1));
+ app_->start();
+ }
+
+ ~offer_test_service() {
+ offer_thread_.join();
+ }
+
+ void offer() {
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ // this is allowed
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ // this is not allowed and will be rejected
+ app_->offer_service(service_info_.service_id, service_info_.instance_id, 33, 4711);
+ }
+
+ 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_request(const std::shared_ptr<vsomeip::message> &_message) {
+ app_->send(vsomeip::runtime::get()->create_response(_message));
+ }
+
+ void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ (void)_message;
+ shutdown_method_called_ = true;
+ // this is will trigger a warning
+ app_->stop_offer_service(service_info_.service_id, service_info_.instance_id, 44, 4711);
+ app_->stop_offer_service(service_info_.service_id, service_info_.instance_id);
+ app_->stop();
+ }
+
+ 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();
+
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Notifying";
+ while(!shutdown_method_called_) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ inc_counter_and_notify();
+ }
+ }
+
+ void inc_counter_and_notify() {
+ ++counter_;
+ // set value to field
+ const std::shared_ptr<vsomeip::payload> its_payload(vsomeip::runtime::get()->create_payload());
+ std::vector<vsomeip::byte_t> its_data;
+ its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF000000) >> 24));
+ its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF0000) >> 16));
+ its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF00) >> 8));
+ its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF)));
+ its_payload->set_data(its_data);
+ app_->notify(service_info_.service_id, service_info_.instance_id,
+ service_info_.event_id, its_payload);
+ }
+
+private:
+ struct offer_test::service_info service_info_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::uint32_t counter_;
+
+ bool wait_until_registered_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread offer_thread_;
+
+ bool shutdown_method_called_;
+};
+
+TEST(someip_offer_test, notify_increasing_counter)
+{
+ offer_test_service its_sample(offer_test::service);
+}
+
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl;
+ return 1;
+ }
+
+ service_number = std::string(argv[1]);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/offer_tests/offer_test_service_external.cpp b/test/offer_tests/offer_test_service_external.cpp
new file mode 100644
index 0000000..d14103f
--- /dev/null
+++ b/test/offer_tests/offer_test_service_external.cpp
@@ -0,0 +1,149 @@
+// Copyright (C) 2014-2016 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "offer_test_globals.hpp"
+
+static std::string service_number;
+
+class offer_test_service {
+public:
+ offer_test_service(struct offer_test::service_info _service_info) :
+ service_info_(_service_info),
+ // service with number 1 uses "vsomeipd" as application name
+ // this way the same json file can be reused for all local tests
+ // including the ones with vsomeipd
+ app_(vsomeip::runtime::get()->create_application(
+ (service_number == "1") ? "vsomeipd" :
+ "offer_test_service" + service_number)),
+ wait_until_registered_(true),
+ wait_until_service_available_(true),
+ offer_thread_(std::bind(&offer_test_service::run, this)) {
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&offer_test_service::on_state, this,
+ std::placeholders::_1));
+
+ app_->register_availability_handler(service_info_.service_id,
+ service_info_.instance_id,
+ std::bind(&offer_test_service::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ app_->request_service(service_info_.service_id,
+ service_info_.instance_id);
+ app_->start();
+ }
+
+ ~offer_test_service() {
+ offer_thread_.join();
+ }
+
+ void offer() {
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ // this is allowed
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ // this is not allowed and will be rejected
+ app_->offer_service(service_info_.service_id, service_info_.instance_id, 33, 4711);
+ }
+
+ 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_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ VSOMEIP_INFO << "Service [" << std::setw(4)
+ << std::setfill('0') << std::hex << _service << "." << _instance
+ << "] is " << (_is_available ? "available":"not available") << ".";
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ if(_is_available) {
+ wait_until_service_available_ = false;
+ condition_.notify_one();
+ } else {
+ wait_until_service_available_ = true;
+ condition_.notify_one();
+ }
+ }
+
+ 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_service_available_) {
+ condition_.wait(its_lock);
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Calling stop method";
+ std::shared_ptr<vsomeip::message> msg(vsomeip::runtime::get()->create_request());
+ msg->set_service(service_info_.service_id);
+ msg->set_instance(service_info_.instance_id);
+ msg->set_method(service_info_.shutdown_method_id);
+ msg->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN);
+ app_->send(msg);
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ app_->stop();
+ }
+
+private:
+ struct offer_test::service_info service_info_;
+ std::shared_ptr<vsomeip::application> app_;
+
+ bool wait_until_registered_;
+ bool wait_until_service_available_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread offer_thread_;
+};
+
+TEST(someip_offer_test, notify_increasing_counter)
+{
+ offer_test_service its_sample(offer_test::service);
+}
+
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 2) {
+ std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl;
+ return 1;
+ }
+
+ service_number = std::string(argv[1]);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/payload_tests/payload_test_client.cpp b/test/payload_tests/payload_test_client.cpp
index bea774e..60529fe 100644
--- a/test/payload_tests/payload_test_client.cpp
+++ b/test/payload_tests/payload_test_client.cpp
@@ -131,7 +131,6 @@ void payload_test_client::on_message(const std::shared_ptr<vsomeip::message>& _r
ASSERT_EQ(_response->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID);
ASSERT_EQ(_response->get_instance(), vsomeip_test::TEST_SERVICE_INSTANCE_ID);
- ASSERT_EQ(_response->get_client(), vsomeip_test::TEST_CLIENT_CLIENT_ID);
if(call_service_sync_)
{
@@ -217,10 +216,10 @@ void payload_test_client::run()
blocked_ = false;
stop();
- std::thread t1([](){ usleep(1000000 * 5);});
+ std::thread t1([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));});
t1.join();
app_->stop();
- std::thread t([](){ usleep(1000000 * 5);});
+ std::thread t([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));});
t.join();
}
diff --git a/test/payload_tests/payload_test_service.cpp b/test/payload_tests/payload_test_service.cpp
index 90fd476..6773743 100644
--- a/test/payload_tests/payload_test_service.cpp
+++ b/test/payload_tests/payload_test_service.cpp
@@ -115,9 +115,6 @@ void payload_test_service::on_message(const std::shared_ptr<vsomeip::message>& _
// TR_SOMEIP_00055
ASSERT_EQ(_request->get_message_type(), vsomeip::message_type_e::MT_REQUEST);
- // make sure the message was sent from the service
- ASSERT_EQ(_request->get_client(), vsomeip_test::TEST_CLIENT_CLIENT_ID);
-
if (check_payload) {
std::shared_ptr<vsomeip::payload> pl = _request->get_payload();
vsomeip::byte_t* pl_ptr = pl->get_data();
diff --git a/test/readme.txt b/test/readme.txt
index 2e8c240..9e127b4 100644
--- a/test/readme.txt
+++ b/test/readme.txt
@@ -390,3 +390,124 @@ complete system while doing 890 methodcalls.
Automatic start from the build directory (example):
ctest -V -R cpu_load_test
+
+
+Initial event tests
+----------------------
+This tests tests initial event mechanism over two nodes with multiple services
+on both nodes.
+
+The test setup is as followed:
+* There are six services offering one event each.
+* Three of the services run on node 1.
+* Three of the services run on node 2.
+* All of the services initially set their event to their service id and notify
+ once
+* On each node there are 20 client applications which subscribe to all of the
+ services events which are started at different times
+* Each client waits until it received one notification (the initial one) from
+ all services and then exits.
+* If all clients exited, the services are killed as well
+
+Automatic start from the build directory (example):
+
+ctest -V -R initial_event_test_diff_client_ids_diff_ports_udp
+
+Manual start from sub folder test of build directory:
+./initial_event_test_master_starter.sh UDP initial_event_test_diff_client_ids_diff_ports_master.json
+
+There are multiple versions of this test which differ in the used subscription
+method and port setup (use ctest -N to see all). For manual start the desired
+description method has to be passed to the starter script as first parameter.
+
+Offer tests
+-----------
+This tests test various cases of offering a service and error recovery
+after an application became unresponsive
+
+* Rejecting offer of service instance whose hosting application is
+ still alive.
+* Rejecting offer of service instance whose hosting application is
+ still alive with daemon
+* Accepting offer of service instance whose hosting application
+ crashed with (send SIGKILL)
+* Accepting offer of service instance whose hosting application became
+ unresponsive (SIGSTOP)
+* Rejecting offers for which there is already a pending offer
+* Rejecting remote offer for which there is already a local offer
+* Rejecting a local offer for which there is already a remote offer
+
+Automatic start from the build directory (example):
+
+ctest -V -R offer_tests
+
+Manual start from sub folder test of build directory:
+./offer_test_local_starter
+./offer_test_external_master_starter.sh
+
+Tests in detail:
+Rejecting offer of service instance whose hosting application is still
+alive:
+* start application which offers service
+* start client which continuously exchanges messages with the service
+* start application which offers the same service again -> should be
+ rejected and an error message should be printed.
+* Message exchange with client application should not be interrupted.
+
+Rejecting offer of service instance whose hosting application is still
+alive with daemon
+* start daemon (needed as he has to ping the offering client)
+* start application which offers service
+* start client which continuously exchanges messages with the service
+* start application which offers the same service again -> should be
+ rejected and an error message should be printed.
+* Message exchange with client application should not be interrupted.
+
+Accepting offer of service instance whose hosting application crashed
+with (send SIGKILL)
+* start daemon
+* start application which offers service
+* start client which exchanges messages with the service
+* kill application with SIGKILL
+* start application which offers the same service again -> should be
+ accepted.
+* start another client which exchanges messages with the service
+* Client should now communicate with new offerer.
+
+Accepting offer of service instance whose hosting application became
+unresponsive (SIGSTOP)
+* start daemon
+* start application which offers service
+* Send a SIGSTOP to the service to make it unresponsive
+* start application which offers the same service again -> should be
+ marked as PENDING_OFFER and a ping should be sent to the paused
+ application.
+* After the timeout passed the new offer should be accepted.
+* start client which exchanges messages with the service
+* Client should now communicate with new offerer.
+
+Rejecting offers for which there is already a pending offer
+* start daemon
+* start application which offers service
+* Send a SIGSTOP to the service to make it unresponsive
+* start application which offers the same service again -> should be
+ marked as PENDING_OFFER and a ping should be sent to the paused
+ application.
+* start application which offers the same service again -> should be
+ rejected as there is already a PENDING_OFFER pending.
+* After the timeout passed the new offer should be accepted.
+* start client which exchanges messages with the service
+* Client should now communicate with new offerer.
+
+Rejecting a local offer for which there is already a remote offer:
+* start daemon
+* start application which offers service
+* start daemon remotely
+* start same application which offers the same service again remotely
+ -> should be rejected as there is already a service instance
+ running in the network
+
+Rejecting remote offer for which there is already a local offer
+* start application which offers service
+* send SD message trying to offer the same service instance as already
+ offered locally from a remote host -> should be rejected
diff --git a/test/routing_tests/external_local_routing_test_service.cpp b/test/routing_tests/external_local_routing_test_service.cpp
index 745435f..e8d8891 100644
--- a/test/routing_tests/external_local_routing_test_service.cpp
+++ b/test/routing_tests/external_local_routing_test_service.cpp
@@ -159,7 +159,7 @@ void external_local_routing_test_service::run()
condition_.wait(its_lock);
}
- std::thread t2([](){ usleep(1000000 * 2);});
+ std::thread t2([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 2));});
t2.join();
app_->stop();
}
diff --git a/test/routing_tests/local_routing_test_client.json b/test/routing_tests/local_routing_test_client.json
index a5991c2..4509768 100644
--- a/test/routing_tests/local_routing_test_client.json
+++ b/test/routing_tests/local_routing_test_client.json
@@ -26,7 +26,7 @@
[
],
- "routing" : "local_routing_test_service",
+ "routing" : "vsomeipd",
"service-discovery" :
{
"enable" : "false",
diff --git a/test/routing_tests/local_routing_test_service.cpp b/test/routing_tests/local_routing_test_service.cpp
index 90e7eed..1f879dc 100644
--- a/test/routing_tests/local_routing_test_service.cpp
+++ b/test/routing_tests/local_routing_test_service.cpp
@@ -104,9 +104,6 @@ void local_routing_test_service::on_message(const std::shared_ptr<vsomeip::messa
// TR_SOMEIP_00055
ASSERT_EQ(_request->get_message_type(), vsomeip::message_type_e::MT_REQUEST);
- // make sure the message was sent from the service
- ASSERT_EQ(_request->get_client(), vsomeip_test::TEST_CLIENT_CLIENT_ID);
-
// check the session id.
ASSERT_EQ(_request->get_session(), static_cast<vsomeip::session_t>(number_of_received_messages_));
@@ -141,7 +138,7 @@ void local_routing_test_service::run()
while (!blocked_)
condition_.wait(its_lock);
- std::thread t2([](){ usleep(1000000 * 5);});
+ std::thread t2([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));});
t2.join();
app_->stop();
}
diff --git a/test/routing_tests/local_routing_test_service.json b/test/routing_tests/local_routing_test_service.json
index 528074f..edd9be6 100644
--- a/test/routing_tests/local_routing_test_service.json
+++ b/test/routing_tests/local_routing_test_service.json
@@ -29,7 +29,7 @@
}
],
- "routing" : "local_routing_test_service",
+ "routing" : "vsomeipd",
"service-discovery" :
{
"enable" : "false",
diff --git a/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp b/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp
index 744a322..9641690 100644
--- a/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp
+++ b/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp
@@ -34,7 +34,6 @@ public:
offer_thread_(std::bind(&subscribe_notify_one_test_service::run, this)),
wait_for_stop_(true),
stop_thread_(std::bind(&subscribe_notify_one_test_service::wait_for_stop, this)),
- //number_of_subscribers_(0),
wait_for_notify_(true),
notify_thread_(std::bind(&subscribe_notify_one_test_service::notify_one, this)) {
app_->init();
@@ -90,7 +89,6 @@ public:
~subscribe_notify_one_test_service() {
offer_thread_.join();
stop_thread_.join();
- notify_thread_.join();
}
void offer() {
@@ -120,7 +118,8 @@ public:
if(its_service != other_services_available_.end()) {
if(its_service->second != _is_available) {
its_service->second = true;
- VSOMEIP_INFO << "Service ["
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Service ["
<< std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
<< "] is available.";
@@ -140,11 +139,8 @@ public:
}
bool on_subscription(vsomeip::client_t _client, bool _subscribed) {
- (void)(_client);
- //_subscribed ? number_of_subscribers_++ : number_of_subscribers_--;
// check if all other services have subscribed:
- // -1 for placeholder in array
-
+ // -1 for placeholder in array and -1 for the service itself
if (subscribers_.size() == subscribe_notify_one_test::service_infos.size() - 2) {
return true;
}
@@ -160,10 +156,6 @@ public:
<< " subscribed, now have " << std::dec << subscribers_.size()
<< " subscribers" ;
- VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
- << service_info_.service_id << "] " << "Client: " << _client
- << " subscribed, now have " << std::dec << subscribers_.size()
- << " subscribers" ;
if(subscribers_.size() == subscribe_notify_one_test::service_infos.size() - 2)
{
// notify the notify thread to start sending out notifications
@@ -359,6 +351,9 @@ public:
<< service_info_.service_id
<< "] Received notifications from all other services, going down";
+ // wait until all notifications have been sent out
+ notify_thread_.join();
+
// let offer thread exit
{
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -389,7 +384,6 @@ private:
std::condition_variable stop_condition_;
std::thread stop_thread_;
- //std::uint32_t number_of_subscribers_;
bool wait_for_notify_;
std::mutex notify_mutex_;
std::condition_variable notify_condition_;
diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in
new file mode 100644
index 0000000..9c64a13
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in
@@ -0,0 +1,54 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30002",
+ "reliable":
+ {
+ "port":"40002",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3333",
+ "instance":"0x0001",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in
new file mode 100644
index 0000000..2d62dbe
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in
@@ -0,0 +1,54 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "services":
+ [
+ {
+ "service":"0x4444",
+ "instance":"0x0001",
+ "unreliable":"30004",
+ "reliable":
+ {
+ "port":"40004",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5555",
+ "instance":"0x0001",
+ "unreliable":"30005",
+ "reliable":
+ {
+ "port":"40005",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6666",
+ "instance":"0x0001",
+ "unreliable":"30006",
+ "reliable":
+ {
+ "port":"40006",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master.json.in
new file mode 100644
index 0000000..38dadb8
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master.json.in
@@ -0,0 +1,70 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"subscribe_notify_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"subscribe_notify_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"subscribe_notify_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40001",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x1111",
+ "instance":"0x0002",
+ "unreliable":"30002",
+ "reliable":
+ {
+ "port":"40002",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x1111",
+ "instance":"0x0003",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "routing":"subscribe_notify_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave.json.in
new file mode 100644
index 0000000..6abc1e3
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave.json.in
@@ -0,0 +1,70 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"subscribe_notify_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"subscribe_notify_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"subscribe_notify_test_service_six",
+ "id":"0x6666"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x2222",
+ "instance":"0x0001",
+ "unreliable":"30004",
+ "reliable":
+ {
+ "port":"40004",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0002",
+ "unreliable":"30005",
+ "reliable":
+ {
+ "port":"40005",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2222",
+ "instance":"0x0003",
+ "unreliable":"30006",
+ "reliable":
+ {
+ "port":"40006",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "routing":"subscribe_notify_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+} \ No newline at end of file
diff --git a/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp b/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp
index 0bf42d5..6e24a20 100644
--- a/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp
+++ b/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp
@@ -29,6 +29,19 @@ static constexpr std::array<service_info, 7> service_infos = {{
{ 0x6666, 0x1, 0x6666, 0x6666, 0x6000 }
}};
+static constexpr std::array<service_info, 7> service_infos_same_service_id = {{
+ // placeholder to be consistent w/ client ids, service ids, app names
+ { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
+ // node 1
+ { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 },
+ { 0x1111, 0x2, 0x2222, 0x2222, 0x2000 },
+ { 0x1111, 0x3, 0x3333, 0x3333, 0x3000 },
+ // node 2
+ { 0x2222, 0x1, 0x4444, 0x4444, 0x4000 },
+ { 0x2222, 0x2, 0x5555, 0x5555, 0x5000 },
+ { 0x2222, 0x3, 0x6666, 0x6666, 0x6000 }
+}};
+
static constexpr int notifications_to_send = 10;
}
diff --git a/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh b/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh
index 0d0f920..bbb48ea 100755
--- a/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh
+++ b/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh
@@ -18,6 +18,7 @@ then
echo " [TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]"
echo "Please pass a json file to this script."
echo "For example: $0 UDP subscribe_notify_test_diff_client_ids_diff_ports_master.json"
+ echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter"
exit 1
fi
@@ -50,15 +51,15 @@ FAIL=0
# Start the services
export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_one
export VSOMEIP_CONFIGURATION=$2
-./subscribe_notify_test_service 1 $1 &
+./subscribe_notify_test_service 1 $1 $3 &
export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_two
export VSOMEIP_CONFIGURATION=$2
-./subscribe_notify_test_service 2 $1 &
+./subscribe_notify_test_service 2 $1 $3 &
export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_three
export VSOMEIP_CONFIGURATION=$2
-./subscribe_notify_test_service 3 $1 &
+./subscribe_notify_test_service 3 $1 $3 &
sleep 1
@@ -66,7 +67,7 @@ cat <<End-of-message
*******************************************************************************
*******************************************************************************
** Please now run:
-** subscribe_notify_test_slave_starter.sh $1 $CLIENT_JSON_FILE
+** subscribe_notify_test_slave_starter.sh $1 $CLIENT_JSON_FILE $3
** from an external host to successfully complete this test.
**
** You probably will need to adapt the 'unicast' settings in
diff --git a/test/subscribe_notify_tests/subscribe_notify_test_service.cpp b/test/subscribe_notify_tests/subscribe_notify_test_service.cpp
index 9c967ef..a07f00c 100644
--- a/test/subscribe_notify_tests/subscribe_notify_test_service.cpp
+++ b/test/subscribe_notify_tests/subscribe_notify_test_service.cpp
@@ -23,8 +23,10 @@
class subscribe_notify_test_service {
public:
subscribe_notify_test_service(struct subscribe_notify_test::service_info _service_info,
- vsomeip::subscription_type_e _subscription_type) :
+ vsomeip::subscription_type_e _subscription_type,
+ std::array<subscribe_notify_test::service_info, 7> _service_infos) :
service_info_(_service_info),
+ service_infos_(_service_infos),
subscription_type_(_subscription_type),
app_(vsomeip::runtime::get()->create_application()),
wait_until_registered_(true),
@@ -33,7 +35,6 @@ public:
offer_thread_(std::bind(&subscribe_notify_test_service::run, this)),
wait_for_stop_(true),
stop_thread_(std::bind(&subscribe_notify_test_service::wait_for_stop, this)),
- number_of_subscribers_(0),
wait_for_notify_(true),
notify_thread_(std::bind(&subscribe_notify_test_service::notify, this)) {
app_->init();
@@ -45,7 +46,7 @@ public:
std::bind(&subscribe_notify_test_service::on_request, this,
std::placeholders::_1));
app_->register_message_handler(vsomeip::ANY_SERVICE,
- service_info_.instance_id, vsomeip::ANY_METHOD,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
std::bind(&subscribe_notify_test_service::on_message, this,
std::placeholders::_1));
@@ -57,12 +58,13 @@ public:
// register availability for all other services and request their event.
- for(const auto& i : subscribe_notify_test::service_infos) {
+ for(const auto& i : service_infos_) {
if ((i.service_id == service_info_.service_id
&& i.instance_id == service_info_.instance_id)
|| (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
continue;
}
+ app_->request_service(i.service_id, i.instance_id);
app_->register_availability_handler(i.service_id, i.instance_id,
std::bind(&subscribe_notify_test_service::on_availability, this,
std::placeholders::_1, std::placeholders::_2,
@@ -89,7 +91,6 @@ public:
~subscribe_notify_test_service() {
offer_thread_.join();
stop_thread_.join();
- notify_thread_.join();
}
void offer() {
@@ -140,22 +141,30 @@ public:
}
bool on_subscription(vsomeip::client_t _client, bool _subscribed) {
- (void)(_client);
- _subscribed ? number_of_subscribers_++ : number_of_subscribers_--;
+ static bool notified(false);
+ if (_subscribed) {
+ subscribers_.insert(_client);
+ } else {
+ subscribers_.erase(_client);
+ }
+
VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
- << service_info_.service_id << "] " << "Client: " << _client
- << " subscribed, now have " << std::dec << number_of_subscribers_
+ << service_info_.service_id << "] " << "Client: "
+ << std::setw(4) << std::setfill('0') << std::hex << _client
+ << (_subscribed ? " subscribed" : " unsubscribed")
+ << ", now have " << std::dec << subscribers_.size()
<< " subscribers" ;
// check if all other services have subscribed:
// -1 for placeholder in array
// divide by two because we only receive once subscription per remote node
// no matter how many clients subscribed to this eventgroup on the remote node
- if(number_of_subscribers_ == (subscribe_notify_test::service_infos.size() - 1) / 2 )
+ if(!notified && subscribers_.size() == (service_infos_.size() - 1) / 2 )
{
// notify the notify thread to start sending out notifications
std::lock_guard<std::mutex> its_lock(notify_mutex_);
wait_for_notify_ = false;
notify_condition_.notify_one();
+ notified = true;
}
return true;
}
@@ -238,8 +247,8 @@ public:
}
}
- if( received_twice == (subscribe_notify_test::service_infos.size() - 1) / 2
- && received_normal == (subscribe_notify_test::service_infos.size() - 1) / 2 - 1) {
+ if( received_twice == (service_infos_.size() - 1) / 2
+ && received_normal == (service_infos_.size() - 1) / 2 - 1) {
// routing manager stub receives the notification
// - twice from external nodes
// - and normal from all internal nodes
@@ -273,7 +282,7 @@ public:
VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
<< service_info_.service_id << "] Subscribing";
// subscribe to events of other services
- for(const subscribe_notify_test::service_info& i: subscribe_notify_test::service_infos) {
+ for(const subscribe_notify_test::service_info& i: service_infos_) {
if ((i.service_id == service_info_.service_id
&& i.instance_id == service_info_.instance_id)
|| (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
@@ -304,7 +313,7 @@ public:
// successfully subscribed as we only receive once subscription per
// remote node no matter how many clients subscribed to this eventgroup
// on the remote node
- std::this_thread::sleep_for(std::chrono::milliseconds(2000));
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
<< service_info_.service_id << "] Starting to notify";
@@ -322,7 +331,7 @@ public:
<< service_info_.service_id << "] Notifying: " << i+1;
app_->notify(service_info_.service_id, service_info_.instance_id,
service_info_.event_id, its_payload);
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
@@ -331,6 +340,10 @@ public:
while (wait_for_stop_) {
stop_condition_.wait(its_lock);
}
+
+ // wait until all notifications have been sent out
+ notify_thread_.join();
+
VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
<< service_info_.service_id
<< "] Received notifications from all other services, going down";
@@ -342,12 +355,13 @@ public:
condition_.notify_one();
}
- std::this_thread::sleep_for(std::chrono::seconds(6));
+ std::this_thread::sleep_for(std::chrono::seconds(1));
app_->stop();
}
private:
subscribe_notify_test::service_info service_info_;
+ std::array<subscribe_notify_test::service_info, 7> service_infos_;
vsomeip::subscription_type_e subscription_type_;
std::shared_ptr<vsomeip::application> app_;
std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_;
@@ -365,7 +379,7 @@ private:
std::condition_variable stop_condition_;
std::thread stop_thread_;
- std::uint32_t number_of_subscribers_;
+ std::set<vsomeip::client_t> subscribers_;
bool wait_for_notify_;
std::mutex notify_mutex_;
std::condition_variable notify_condition_;
@@ -374,11 +388,20 @@ private:
static int service_number;
static vsomeip::subscription_type_e subscription_type;
+static bool use_same_service_id;
TEST(someip_subscribe_notify_test, send_ten_notifications_to_service)
{
- subscribe_notify_test_service its_sample(
- subscribe_notify_test::service_infos[service_number], subscription_type);
+ if(use_same_service_id) {
+ subscribe_notify_test_service its_sample(
+ subscribe_notify_test::service_infos_same_service_id[service_number],
+ subscription_type,
+ subscribe_notify_test::service_infos_same_service_id);
+ } else {
+ subscribe_notify_test_service its_sample(
+ subscribe_notify_test::service_infos[service_number], subscription_type,
+ subscribe_notify_test::service_infos);
+ }
}
#ifndef WIN32
@@ -386,10 +409,11 @@ int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
if(argc < 3) {
- std::cerr << "Please specify a service number and subscription type, like: " << argv[0] << " 2 UDP" << std::endl;
+ std::cerr << "Please specify a service number and subscription type, like: " << argv[0] << " 2 UDP SAME_SERVICE_ID" << std::endl;
std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl;
std::cerr << "Valid subscription types include:" << std::endl;
std::cerr << "[TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]" << std::endl;
+ std::cerr << "If SAME_SERVICE_ID is specified as third parameter the test is run w/ multiple instances of the same service" << std::endl;
return 1;
}
@@ -411,6 +435,12 @@ int main(int argc, char** argv)
std::cerr << "[TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]" << std::endl;
return 1;
}
+
+ if (argc >= 4 && std::string("SAME_SERVICE_ID") == std::string(argv[3])) {
+ use_same_service_id = true;
+ } else {
+ use_same_service_id = false;
+ }
return RUN_ALL_TESTS();
}
#endif
diff --git a/test/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh b/test/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh
index 887e2e4..b37a781 100755
--- a/test/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh
+++ b/test/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh
@@ -18,6 +18,7 @@ then
echo " [TCP_AND_UDP, PREFER_UDP, PREFER_TCP, UDP, TCP]"
echo "Please pass a json file to this script."
echo "For example: $0 UDP subscribe_notify_test_diff_client_ids_diff_ports_slave.json"
+ echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter"
exit 1
fi
@@ -45,15 +46,15 @@ FAIL=0
# Start the services
export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_four
export VSOMEIP_CONFIGURATION=$2
-./subscribe_notify_test_service 4 $1 &
+./subscribe_notify_test_service 4 $1 $3 &
export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_five
export VSOMEIP_CONFIGURATION=$2
-./subscribe_notify_test_service 5 $1 &
+./subscribe_notify_test_service 5 $1 $3 &
export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_six
export VSOMEIP_CONFIGURATION=$2
-./subscribe_notify_test_service 6 $1 &
+./subscribe_notify_test_service 6 $1 $3 &
# Wait until all applications are finished
for job in $(jobs -p)
diff --git a/tools/vsomeip_ctrl.cpp b/tools/vsomeip_ctrl.cpp
index 84faf00..947caf8 100644
--- a/tools/vsomeip_ctrl.cpp
+++ b/tools/vsomeip_ctrl.cpp
@@ -5,7 +5,7 @@
#include <vsomeip/vsomeip.hpp>
#include "../implementation/configuration/include/internal.hpp"
-#include "../../implementation/logging/include/logger.hpp"
+#include "../implementation/logging/include/logger.hpp"
#include "../implementation/service_discovery/include/constants.hpp"
#include "../implementation/utility/include/byteorder.hpp"
@@ -91,7 +91,7 @@ public:
"registered." : "deregistered.");
if (_state == vsomeip::state_type_e::ST_REGISTERED) {
- app_->request_service(service_id_, vsomeip::ANY_INSTANCE);
+ app_->request_service(service_id_, instance_);
}
}
@@ -112,23 +112,25 @@ public:
<< "." << std::setw(4) << std::setfill('0') << std::hex
<< _response->get_instance() << "]:";
VSOMEIP_INFO << "########## begin message";
- VSOMEIP_INFO << std::setw(4) << std::setfill('0') << std::hex
- << _response->get_service() << std::setw(4) << std::setfill('0')
- << std::hex << _response->get_method()
+ VSOMEIP_INFO << std::hex << std::setw(4) << std::setfill('0')
+ << _response->get_service()
+ << std::hex << std::setw(4) << std::setfill('0')
+ << _response->get_method()
<< " # service id / instance id";
- VSOMEIP_INFO << std::setw(8) << std::setfill('0') << std::hex
+ VSOMEIP_INFO << std::hex << std::setw(8) << std::setfill('0')
<< _response->get_length() << " # length";
- VSOMEIP_INFO << std::setw(4) << std::setfill('0') << std::hex
- << _response->get_client() << std::setw(4) << std::setfill('0')
- << std::hex << _response->get_session()
+ VSOMEIP_INFO << std::hex << std::setw(4) << std::setfill('0')
+ << _response->get_client()
+ << std::hex << std::setw(4) << std::setfill('0')
+ << _response->get_session()
<< " # client id / session id";
- VSOMEIP_INFO << std::setw(2) << std::setfill('0') << std::hex
+ VSOMEIP_INFO << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<std::uint16_t>(_response->get_protocol_version())
- << std::setw(2) << std::setfill('0') << std::hex
+ << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<std::uint16_t>(_response->get_interface_version())
- << std::setw(2) << std::setfill('0') << std::hex
+ << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<std::uint16_t>(_response->get_message_type())
- << std::setw(2) << std::setfill('0') << std::hex
+ << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<std::uint16_t>(_response->get_return_code())
<< " # protocol version / interface version / "
<< "message type / return code";